參考自《硬體架構的藝術》。 思路:產生具有50%占空比的奇數分頻時鐘,最簡單的方式是以期望輸出頻率的一半(即輸出周期的兩倍)生成兩個正交相位時鐘,這兩個正交時鐘之間有90°的相位差(即相差四分之一個周期),然後將這兩個時鐘異或,就得到了奇數的50%占空比時鐘。 本次內容針對的是3分頻。具體的思路按照 ...
參考自《硬體架構的藝術》。
思路:產生具有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)” 這種的來寫,很直觀。