[Verilog combat] Design and functional verification of an integer parity divider with adjustable duty cycle (with source code)


Virtual machine: VMware -14.0.0.24051
Environment: ubuntu 18.04.1 Script
: makefile ( click to go )
Utility: vcs and verdi



1. Demand

  The module can realize frequency division by 2-15 times any number, and the duty cycle of the clock obtained after frequency division can be adjusted in integer cycles.
  Even frequency division takes FDC = 8 frequency division as an example ( FDC分频系数), using the rising edge of the clock to count, the maximum count value is 8 (0~8, the counter needs 4 bits, 0 means that there is no clock edge coming, 8 means that there are already 8 The clock edge is coming), the adjustable duty cycle is 1/8x100%, 2/8x100%...;
  Odd frequency division adopts double edge detection, taking FDC = 3 frequency division as an example, the maximum count value is 6, adjustable The duty cycle is 1/6, 2/6….


2. Timing

insert image description here


三、Design and Functional Verification

(1)RTL

//-- modified by xlinxdu, 2022/04/26
module div
#(
  parameter FDC     = 10,
  parameter TOG_CNT = 5
)(
  input      clk    ,
  input      rst_n  ,
  output reg clk_div
);
  
reg [3:0] cnt;
reg [4:0] cnt_odd;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt <= 4'b0;
    end
    else if((FDC%2 == 0) && (cnt < FDC))begin
        cnt <= cnt + 1'b1;
    end
    else if(FDC%2 == 0) begin
        cnt <= 4'b1;
    end
end

always @(*) begin
    if((FDC%2 == 0)  && (cnt <= TOG_CNT))begin
        clk_div = 1'b1;
    end
    else if((FDC%2 == 0) && (cnt > TOG_CNT))begin
        clk_div = 1'b0;
    end
end

always @(posedge clk or negedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_odd <= 5'b0;
    end
    else if((FDC%2 ) && (cnt_odd < 2*FDC))begin
        cnt_odd <= cnt_odd + 1'b1;
    end
    else if(FDC%2 ) begin
        cnt_odd <= 5'b1;
    end
end

always @(*) begin
    if((FDC%2) && (cnt_odd <= TOG_CNT))begin
        clk_div = 1'b1;
    end
    else if((FDC%2) && (cnt_odd > TOG_CNT))begin
        clk_div = 1'b0;
    end
end

endmodule

(2)Test Bench

//-- modified by xlinxdu, 2022/04/26
`timescale 1ns/1ns
module tb_div;
 
    reg clk;
    reg rst_n;
    wire clk_div;

initial begin
        clk   = 0;
        rst_n = 1;
 
        #10 rst_n = 0;
        #10 rst_n = 1;

end

always #100 clk = ~clk;

div #(8,4) tb_div (
                    .clk(clk), 
                    .rst_n(rst_n), 
                    .clk_div(clk_div)
                   );

initial begin
  $fsdbDumpfile("div.fsdb");
  $fsdbDumpvars              ;
  $fsdbDumpMDA               ;
  #10000 $finish             ;
end 
 
      
endmodule

4. Result

  The following test takes 8 frequency division, 50% duty cycle; 3 frequency division, 50% duty cycle as an example. Change the division factor and duty cycle by passing parameters through the test case.

(1) Divide by 8 (50%, #(8,4))

insert image description here

(2) Divide by 3 (50%, #(3,3))

insert image description here

  • Result: The test waveform is the same as the timing, the data path is correct, and the functional verification is passed.

Notice: Pay attention to the calculation of the transfer value of the duty cycle when the frequency is oddly divided.


Author: xlinxdu
Copyright: This article is the original author, and the copyright belongs to the author.
Reprinting: Reprinting is prohibited without the permission of the author. Reprinting must retain this statement, and a link to the original text must be given in the article.

Guess you like

Origin blog.csdn.net/qq_43244515/article/details/124436263