IC基础:解决分频器

偶数分频(太简单不写了)

  1. D触发器级联并Q非连D,实现2的n次幂分频
  2. 计数器分频,0和n/2处反转

50%奇数分频

  1. 0,n/2处反转
  2. 将分频后的信号在原时钟negedge打一拍,将两个信号相或
  • Code:
module odd_divider#(
    parameter N,
    parameter N_2
)
(
    input clk,
    input rst_n,
    output clk_N
);
    //==============defination
    reg clk_N_p;
    reg clk_N_n;
    wire clk_N;
    reg [7 : 0] cnt;

    //==============output
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt <= 'd0;
        else if(cnt == N - 1) cnt <= 'd0;
        else cnt <= cnt + 1'b1;
    end


    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) clk_N_p <= 1'b0;
        else if(cnt == 0 || cnt == N_2) clk_N_p <= ~clk_N_p;
    end
    always@(negedge clk or negedge rst_n)begin
        if(!rst_n)  clk_N_n <= 1'b0;
        else clk_N_n <= clk_N_p;
    end
    assign clk_N = clk_N_p || clk_N_n;
endmodule
  • Testbench:
module tb_odd_divider();
    //===================parameter
    parameter PERIOD = 10 / 2;
    parameter N = 7;
    parameter N_2 = 3;

    //===================parameter
    reg clk, rst_n;
    wire clk_N;
    //===================parameter
    initial begin
        clk = 0;
        rst_n = 0;
        #200 rst_n = 1;
	    #1500 $finish;
    end
    always #PERIOD clk = ~clk;
    
    odd_divider#(
        .N (N),
        .N_2(N_2)
    )
    u_odd_divider
    (
        .clk (clk),
        .rst_n(rst_n),
        .clk_N(clk_N)
    );
`ifdef FSDB
initial begin
	$fsdbDumpfile("tb_odd_divider.fsdb");
	$fsdbDumpvars;
    $fsdbDumpMDA();
end
`endif

endmodule 
  • VCS+verdi仿真:

在这里插入图片描述

  • Schematic:
    在这里插入图片描述

任意小数分频

  • 说明:形如M/N分频,明白公式:M / N = Q…R(M个周期有N个脉冲,其中R个Q+1分频时钟,(N - R)个Q分频时钟)
  • Code:
module decimal_divider#(
    parameter M,
    parameter N,
    parameter Q,
    parameter Q_2,
    parameter R
)
(
    input clk,
    input rst_n,
    output o_clk
);
    //================defination
    reg clk_q;
    reg [7 : 0] cnt_q;
    wire add_cnt_q;
    wire end_cnt_q;

    reg clk_q1;
    reg [7 : 0] cnt_q1;
    wire add_cnt_q1;
    wire end_cnt_q1;

    reg [7 : 0] cnt;
    wire add_cnt;
    wire end_cnt;
    //================output
    assign add_cnt_q = (cnt < N - R);
    assign end_cnt_q = add_cnt_q && (cnt_q == Q - 1);
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt_q <= 'd0;
        else if(end_cnt_q) cnt_q <= 'd0;
        else if(add_cnt_q) cnt_q <= cnt_q + 1'b1;
    end
    
    assign add_cnt_q1 = (cnt >= N - R);
    assign end_cnt_q1 = add_cnt_q1 && (cnt_q1 == Q);
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt_q1 <= 'd0;
        else if(end_cnt_q1) cnt_q1 <= 'd0;
        else if(add_cnt_q1) cnt_q1 <= cnt_q1 + 1'b1;
    end
    
    assign add_cnt = end_cnt_q || end_cnt_q1;
    assign end_cnt = add_cnt && (cnt == N - 1);
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) cnt <= 'd0;
        else if(end_cnt) cnt <= 'd0;
        else if(add_cnt) cnt <= cnt + 1'b1;
    end

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) clk_q <= 'd0;
        else if(add_cnt_q && ((cnt_q == 0) || (cnt_q == Q_2))) clk_q <=  ~clk_q;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) clk_q1 <= 'd0;
        else if(add_cnt_q1 && ((cnt_q1 == 0) || (cnt_q1 == Q_2))) clk_q1 <=  ~clk_q1;
    end
    assign o_clk = clk_q || clk_q1;
endmodule 
  • Testbench
module tb_decimal_divider();
    //===================parameter
    parameter PERIOD = 10 / 2;
    parameter M = 21;
    parameter N = 5;
    parameter Q = 4;
    parameter Q_2 = 2;
    parameter R = 1;

    //===================defination
    reg clk, rst_n;
    wire o_clk;
    //===================output
    initial begin
        clk = 0;
        rst_n = 0;
        #200 rst_n = 1;
	    #1500 $finish;
    end
    always #PERIOD clk = ~clk;
    
    decimal_divider#(
        .M(M),
        .N(N),
        .Q(Q),
        .Q_2(Q_2),
        .R(R)
    )
    u_decimal_divider
    (
        .clk (clk),
        .rst_n(rst_n),
        .o_clk(o_clk)
    );
`ifdef FSDB
initial begin
	$fsdbDumpfile("tb_decimal_divider.fsdb");
	$fsdbDumpvars;
    $fsdbDumpMDA();
end
`endif

endmodule 
  • VCS+verdi:

在这里插入图片描述

  • Schematic:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值