参考自《硬件架构的艺术》。
思路:产生具有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
下面是波形图。
总结:if else语句中,begin和end的书写十分重要,我在这上面吃了很多亏,一定要加!
另外,如果想写 “ ? : ” 这个组合逻辑符号的,尽量换成always@(*)块和if else配合着写,不然很容易出问题。
tb文件的话,这个很简单,就驱动个clk,碰到别的复杂的,也尽量不要加#号写时间,别把自己绕晕了,就用 “repeat() @(posedge clk)” 这种的来写,很直观。