一、行波時鍾
任意分頻電路,相信很多人都聽說過這個專業名詞,好多視頻上都說不建議使用計數器產生的分頻時鍾。其實在FPGA領域當中,由寄存器分頻產生的時鍾還有一個學名叫做,行波時鍾。是由時序邏輯產生比如A寄存器的輸出作為B寄存的時鍾輸入(一般不建議使用),如下圖所示;驅動右邊那個觸發器的時鍾即為行波時鍾。之所以不建議使用在FPGA中使用行波時鍾,因為這樣會在FPGA設計中引入新的時鍾域,,增加時序分析的難度,並且由於行波時鍾的相位通常會滯后於原始時鍾,會導致后續觸發器的保持時間不一定能滿足。

事實上,采用行波時鍾的目的無非是為后續時序電路的處理速度進行降頻,而要實現降頻的功能,除了通過降低時鍾信號的頻率外,仍然可以通過控制后續時序電路存儲單元的使能端來實現,因此,上例中的電路完全可以修改如下:這樣一來,整個時序邏輯將只被一個時鍾信號所驅動。

二、任意分頻電路
雖然說比建議使用分屏電路。但是在一些對時序要求不高的情況下是完全可以用的。而且還可以節省PLL和DCM等資源。那么設計一個任意分頻的電路。這里的關鍵是偶數分頻和奇數分頻兩大塊。占空比一般都是50%。分頻電路的整體架構如下:

1、偶數分頻:可以不用介紹,計數到N/2翻轉就可以。
2、奇數分頻 第一步:上升沿觸發進行模N計數,從0開始計數,計數到0+(n-1)/2,進行翻轉,即為clk_odd= ~clk_odd
第二步:還是在上升沿的條件下,從接着第一步計數,在其基礎上再計數(n-1)/2,再次翻轉;clk_odd= ~clk_odd
第三步:在下降沿的條件下,采集clk_odd,即:clk_odd_r = clk_odd
第四步;輸出clk_odd_out = clk_odd_r |clk_odd;即為所求‘。
三、實現
1 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 // Project Name : 3 // Website : https://home.cnblogs.com/lgy-gdeu/ 4 // Author : LGY GUET Uiversity 5 // Weixin : li15226499835 6 // Email : 15277385992@163.com 7 // File : 8 // Create : 2020-07-01 9 // Revise : 10 // Editor : sublime text{SUBLIME_VERSION}, tab size ({TABS}) 11 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 // Modification History: 13 // Date By Version Change Description 14 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 // {DATE} {TIME} LGY 1.0 ++++++++++++++++ 16 // ********************************************************************************* 17 `timescale 1ns/1ns 18 module mux_cnt( 19 input wire sclk , 20 input wire s_rst_n , 21 input wire[3:0] div , 22 output wire clk_out 23 ); 24 25 //========================================================================\ 26 // ################ Define Parameter and Internal signals ################ 27 //========================================================================/ 28 localparam DIV1 = 1 ; 29 localparam DIV2 = 2 ; 30 localparam DIV3 = 3 ; 31 localparam DIV4 = 4 ; 32 localparam DIV5 = 5 ; 33 localparam DIV6 = 6 ; 34 localparam DIV7 = 7 ; 35 localparam DIV8 = 8 ; 36 reg [7:0] fre_en ; 37 //============================================================================= 38 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++ 39 //============================================================================= 40 //分頻模式的使能,一共是8種模式 41 always @(posedge sclk or negedge s_rst_n)begin 42 if(!s_rst_n)begin 43 fre_en <= 0; 44 end 45 else begin 46 case(div ) 47 DIV1 : fre_en <= 8'b0000_0001 ; 48 DIV2 : fre_en <= 8'b0000_0010 ; 49 DIV3 : fre_en <= 8'b0000_0100 ; 50 DIV4 : fre_en <= 8'b0000_1000 ; 51 DIV5 : fre_en <= 8'b0001_0000 ; 52 DIV6 : fre_en <= 8'b0010_0000 ; 53 DIV7 : fre_en <= 8'b0100_0000 ; 54 DIV8 : fre_en <= 8'b1000_0000 ; 55 endcase 56 end 57 end 58 59 //計數模塊 60 reg [3:0] fre_cnt ; 61 always @(posedge sclk or negedge s_rst_n)begin 62 if(!s_rst_n)begin 63 fre_cnt <= 0 ; 64 end 65 else begin 66 case (1'b1) 67 fre_en[0] : begin 68 ; 69 end 70 fre_en[1] : begin 71 ; 72 end 73 fre_en[2] : begin 74 if(fre_cnt < 2) 75 fre_cnt <= fre_cnt + 1'b1 ; 76 else 77 fre_cnt <= 0 ; 78 end 79 fre_en[3] : begin 80 if(fre_cnt<3) 81 fre_cnt <= fre_cnt + 1'b1 ; 82 else 83 fre_cnt <= 0; 84 end 85 fre_en[4] : begin 86 if(fre_cnt<4) 87 fre_cnt <= fre_cnt + 1'b1 ; 88 else 89 fre_cnt <= 0; 90 end 91 fre_en[5] : begin 92 if(fre_cnt<5) 93 fre_cnt <= fre_cnt + 1'b1 ; 94 else 95 fre_cnt <= 0; 96 end 97 fre_en[6] : begin 98 if(fre_cnt<6) 99 fre_cnt <= fre_cnt + 1'b1 ; 100 else 101 fre_cnt <= 0; 102 end 103 fre_en[7] : begin 104 if(fre_cnt<7) 105 fre_cnt <= fre_cnt + 1'b1 ; 106 else 107 fre_cnt <= 0; 108 end 109 110 endcase 111 end 112 end 113 //分頻模塊 114 reg clk_out_odd_r ; //奇數分頻,中間變量 115 reg clk_out_even ; //偶數分頻,直接輸出 116 always @ (posedge sclk or negedge s_rst_n) begin 117 if(s_rst_n == 1'b0)begin 118 clk_out_even <= 0; 119 clk_out_odd_r <= 0; 120 end 121 else begin 122 case (1'b1) 123 fre_en[0] : begin 124 ; 125 end 126 fre_en[1] : begin 127 clk_out_even <= ~clk_out_even ; 128 end 129 fre_en[2] : begin// 3 div 130 if (fre_cnt==1) 131 clk_out_odd_r <= ~clk_out_odd_r; 132 else if(fre_cnt==2) 133 clk_out_odd_r <= ~clk_out_odd_r; 134 else 135 clk_out_odd_r <= clk_out_odd_r; 136 end 137 fre_en[3] : begin//4 div 138 if(fre_cnt == 1) 139 clk_out_even <= ~clk_out_even ; 140 else if(fre_cnt ==3) 141 clk_out_even <= ~clk_out_even ; 142 else 143 clk_out_even <= clk_out_even ; 144 end 145 fre_en[4] : begin//5 div 146 if(fre_cnt == 2) 147 clk_out_odd_r <= ~clk_out_odd_r; 148 else if(fre_cnt == 4) 149 clk_out_odd_r <= ~clk_out_odd_r; 150 else 151 clk_out_odd_r <= clk_out_odd_r ; 152 153 end 154 fre_en[5] : begin// 6 div 155 if (fre_cnt == 2) 156 clk_out_even <= ~clk_out_even ; 157 else if(fre_cnt == 5) 158 clk_out_even <= ~clk_out_even ; 159 else 160 clk_out_even <= clk_out_even; 161 end 162 fre_en[6] : begin //7div 163 if(fre_cnt == 3) 164 clk_out_odd_r <= ~clk_out_odd_r ; 165 else if(fre_cnt ==6) 166 clk_out_odd_r <= ~clk_out_odd_r ; 167 else 168 clk_out_odd_r <= clk_out_odd_r ; 169 end 170 fre_en[7] : begin // 8 div 171 if(fre_cnt == 3) 172 clk_out_even <= ~clk_out_even ; 173 else if(fre_cnt ==7) 174 clk_out_even <= ~clk_out_even ; 175 else 176 clk_out_even <= clk_out_even ; 177 end 178 179 endcase 180 end 181 182 end 183 184 //中間輸出模塊 185 reg clk_out_odd_r1 ;//用來存放下降沿采集的數據 186 always @(negedge sclk or negedge s_rst_n)begin 187 if(!s_rst_n) 188 clk_out_odd_r1 <= 0; 189 else begin 190 case (1'b1 ) 191 fre_en[0] : begin 192 ; 193 end 194 fre_en[1] : begin 195 ; 196 end 197 fre_en[2] : begin 198 clk_out_odd_r1 <= clk_out_odd_r ; 199 end 200 fre_en[3] : begin 201 ; 202 end 203 fre_en[4] : begin 204 clk_out_odd_r1 <= clk_out_odd_r ; 205 end 206 fre_en[5] : begin 207 ; 208 end 209 fre_en[6] : begin 210 clk_out_odd_r1 <= clk_out_odd_r ; 211 end 212 fre_en[7] : begin 213 ; 214 end 215 endcase 216 end 217 end 218 219 //最后的輸出 220 //assign clk_out = ( fre_en[0] | fre_en[1] | fre_en[3] | fre_en[5] | fre_en[7] )?clk_out_even:clk_out_odd_r|clk_out_odd_r1; 221 assign clk_out = fre_en[0]? sclk :(( fre_en[1] | fre_en[3] | fre_en[5] | fre_en[7])?clk_out_even:clk_out_odd_r|clk_out_odd_r1); 222 223 endmodule
激勵文件
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 2020/07/01 14:59:38 7 // Design Name: 8 // Module Name: mux_cnt_tb 9 // Project Name: 10 // Target Devices: 11 // Tool Versions: 12 // Description: 13 // 14 // Dependencies: 15 // 16 // Revision: 17 // Revision 0.01 - File Created 18 // Additional Comments: 19 // 20 ////////////////////////////////////////////////////////////////////////////////// 21 22 23 module mux_cnt_tb(); 24 reg sclk ; 25 reg s_rst_n ; 26 reg [3:0] div ; 27 wire clk_out ; 28 29 //============================================================================= 30 //+++++++++++++++++++++++++ Main Code +++++++++++++++++++++++++++++++里 31 //============================================================================= 32 33 //initial begin 34 // sclk = 0 ; 35 // forever begin 36 // #2 sclk = ~sclk ; 37 // end 38 //end 39 40 41 42 43 initial begin 44 sclk = 0; 45 s_rst_n = 0; 46 div = 3 ; 47 #20 48 s_rst_n = 1; 49 #400 50 div = 1; 51 #600 52 s_rst_n = 1; 53 div = 5; 54 #1200 55 div = 2; 56 #600 57 58 $finish; 59 60 end 61 always #10 sclk = ~sclk ; 62 63 64 mux_cnt inst_mux_cnt (.sclk(sclk), .s_rst_n(s_rst_n), .div(div), .clk_out(clk_out)); 65 66 67 endmodule
四、仿真時序圖

