一、行波时钟
任意分频电路,相信很多人都听说过这个专业名词,好多视频上都说不建议使用计数器产生的分频时钟。其实在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
四、仿真时序图