由于Verilog只能在时钟的上升沿或者下降沿改变电路的状态,因此精确的小数分频是无法通过Verilog实现的,我们只能实现平均意义上的小数分频,即某段时间内,该时钟的周期平均为T(T为小数)。
我们以8.6分频为例,来阐述小数分频的实现方法。
T=8.6 对应于M.N(即M=8|N = 6),T也可以表示为 T = M + b/(a+b)
将M通分至分母(a+b),则T = ( Ma+(M+1)b )/( a+b),这里我们发现组成小数分频使用了a个M分频和b个M+1分频的整数分频电路。
这个方法被称作”双模前置小数分频“,其最重要的核心是M分频和M+1分频这个相近频率
因此,对于8.6分频,整数部分为8,我们选用8分频和9分频来进行合成,列出二元方程组如下
8a+9b=43
a+b=5
得出来a和b的解为2和3,也就是说,在五个周期内,有两个8分频和3个9分频时钟,从而在这五个周期内,平均周期为(2x8+3x9)/(3+2)=8.6。
以下是RTL代码实现:
module clkdiv(
input logic clk,
input logic rst,
output logic clkout
);
//8.6=43/5
//a*8+b*9=43
//a+b=5
//-->a=2,b=3
//16+27=43
logic [4:0] cnt8;
logic [4:0] cnt9;
logic [4:0] cnt;
//cnt
always_ff@(posedge clk,posedge rst)
if(rst)
cnt<=0;
else if(cnt==0||cnt==2) //9 clkdiv when cnt=0,2,4
begin
if(cnt9==9-1)
cnt<=cnt+1;
else
cnt<=cnt;
end
else if(cnt==4)
begin
if(cnt9==9-1)
cnt<=0;
else
cnt<=cnt;
end
else if(cnt==1||cnt==3) //8 clkdiv when cnt=1,3
begin
if(cnt8==8-1)
cnt<=cnt+1;
else
cnt<=cnt;
end
//cnt9
always_ff@(posedge clk,posedge rst)
if(rst)
cnt9<=0;
else if(cnt==0||cnt==2||cnt==4)
if(cnt9==9-1)
cnt9<=0;
else
cnt9<=cnt9+1;
else
cnt9<=0;
//cnt8
always_ff@(posedge clk,posedge rst)
if(rst)
cnt8<=0;
else if(cnt==1||cnt==3)
if(cnt8==8-1)
cnt8<=0;
else
cnt8<=cnt8+1;
else
cnt8<=0;
//clkout
always_comb
begin
case(cnt)
0,2,4:if(cnt9==9-1)
clkout=1;
else
clkout=0;
1,3:if(cnt8==8-1)
clkout=1;
else
clkout=0;
default:clkout=0;
endcase
end
endmodule
|