参考自《硬件架构的艺术》。

思路:产生具有50%占空比的奇数分频时钟,最简单的方式是以期望输出频率的一半(即输出周期的两倍)生成两个正交相位时钟,这两个正交时钟之间有90°的相位差(即相差四分之一个周期),然后将这两个时钟异或,就得到了奇数的50%占空比时钟。

本次内容针对的是3分频。具体的思路按照第一行写的书籍内容P84~85,以下是我自己写的代码及产生的波形。

 1 module clk_div_3 (
 2     input    clk    ,
 3     input    rstn  ,
 4      
 5     output   clkout
 6 );
 7 
 8 parameter    N = 'd3 ;
 9 
10 reg  [1:0]  cnt;
11 always @(posedge clk or negedge rstn) begin
12     if(!rstn || (cnt == (N-'d1)))
13         cnt  <=  'b0  ;
14     else 
15         cnt  <=  cnt   +  1  ;
16 end
17 
18 reg     ff1_en;
19 reg     ff2_en;
20 
21 always @(*) begin
22     ff1_en=0;ff2_en=0;
23     if(cnt == 0)begin
24         ff1_en  =  1'b1  ;
25     end
26     else if(cnt == ((N+1)/2)) begin
27         ff2_en  =  1'b1  ;
28     end
29     else begin 
30         ff1_en  =  0  ;
31         ff2_en  =  0  ;
32     end
33 end
34 
35 reg    clk_div_1  ;
36 reg    clk_div_2  ;
37 always @(posedge clk or negedge rstn) begin
38     if(!rstn) begin
39         clk_div_1   <=  'b0  ;
40     end
41     else if(ff1_en) begin
42         clk_div_1   <=  ~clk_div_1 ;
43     end
44     else begin 
45         clk_div_1   <=  clk_div_1 ;
46     end
47 end
48 
49 always @(negedge clk,rstn) begin
50     if(!rstn) begin
51         clk_div_2   <=  'b0  ;
52     end
53     else if(ff2_en) begin
54         clk_div_2   <=  ~clk_div_2 ;
55     end
56     else begin 
57         clk_div_2   <=  clk_div_2 ;
58     end
59 end
60 
61 assign  clkout  =  clk_div_1  ^  clk_div_2  ;
62 
63 endmodule

下面是很简单的tb文件。

 1 `timescale  1ns/10ps
 2 
 3 module tb ();
 4     reg    clk    ;
 5     reg    rstn   ;
 6     wire   clkout ;
 7 
 8 parameter    M = 'd3  ;
 9 
10 clk_div_3 #(
11     .N      (M      )
12 )   u0(
13     .clk    (clk    )    ,
14     .rstn   (rstn   )    ,
15     .clkout (clkout )    
16 );
17 
18 always #5  clk  =  ~clk  ;
19 
20 initial begin
21     clk  = 0;
22     rstn = 0;
23     repeat(5) @(posedge clk);
24     rstn = 1;
25     repeat(100) @(posedge clk);
26     $stop();
27 end
28 
29 endmodule

下面是波形图。

具有50%占空比的奇数整数分频

总结:if else语句中,begin和end的书写十分重要,我在这上面吃了很多亏,一定要加!

另外,如果想写 “ ? : ” 这个组合逻辑符号的,尽量换成always@(*)块和if else配合着写,不然很容易出问题。

tb文件的话,这个很简单,就驱动个clk,碰到别的复杂的,也尽量不要加#号写时间,别把自己绕晕了,就用 “repeat() @(posedge clk)” 这种的来写,很直观。