【数字IC手撕代码】Verilog小数分频|题目|原理|设计|仿真

Verilog小数分频

    • 前言
    • 小数/分数分频题目
    • 小数分数分频的原理
    • RTL设计
    • 小数分频电路的testbench
    • 仿真结果

前言

本系列旨在提供100%准确的数字IC设计/验证手撕代码环节的题目,原理,RTL设计,Testbench和参考仿真波形,每篇文章的内容都经过仿真核对。快速导航链接如下:

奇数分频
偶数分频
半整数分批
小数/分数分频
序列检测器
模三检测器
饮料机
异步复位,同步释放
边沿检测(上升沿,下降沿,双边沿)
全加器,半加器
格雷码转二进制
单bit跨时钟域(打两拍,边沿同步,脉冲同步)
同步FIFO

应当说,手撕代码环节是面试流程中既重要又简单的一个环节,跟软件类的岗位相比起来,数字IC的手撕代码题目固定,数量有限,属于整个面试中必得分的一个环节,在这个系列以外,笔者同样推荐数字IC求职者使用“HdlBits”进行硬件描述语言的训练
链接如下
HDLBits — Verilog Practice

小数/分数分频题目

1.用verilog实现”43/5“ in other words 8.6分频的电路
2.用verilog实现 ”a/b“ 的分频电路

小数分数分频的原理

在【数字IC手撕代码】的第一篇和第二篇,我们已经详细介绍了奇数分频电路和偶数分频电路的设计方法,对于小数分频来说,我们应用了第一篇和第二篇文章中的有关思想.先得到两个整数分频的电路,控制整数分频出现的次数,以此来得到小数分频电路。

因为Verilog作为HDL语言对应的硬件电路没有办法对小数计时,因此假如输入时钟周期T=10ns,我们在这里得到的分频电路并非对应于每个周期都是86ns(即不可能有任何两个上升沿之间的时间差为86ns

与之相对应的,我们在这里提出的8.6分频,实际上是指输出的分频信号5个时钟周期内持续的时间信号为430ns(即一段时间内的平均值概念

以题目一8.6分频为例,我们需要用哪两个整数分频来处理出上述的平均值概念呢?
这里对应的数学推导过程如下:

T=8.6 对应于M.N(即M=8|N = 6)
T也可以表示为 T = M + b/(a+b) 这里的a+b就是值”输出的分频信号5个时钟周期这一平均概念“
将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.6的小数分频,比如:使用1个11分频和4个8分频,我们也可以合成出8.6分频的信号
这种方法也是可行的,但是相较于双模前置小数分频法来说,这种方法的突出缺点是clock信号的质量很差(即分频信号的5个时钟周期长短不一,相差较大)

为了得到质量更好的分频时钟信号,我们还需要做出什么努力呢?

以 8.6 倍分频为例,按照双模前置小数分频法得到合成所需2个8分频和3个9分频
这些整数分频的实现顺序一般有以下 4 种:
(1) 先进行 2 次 8 分频,再进行 3 次 9 分频;
(2) 先进行 3 次 9 分频,再进行 2 次 8 分频;
(3) 将 2 次 8 分频平均的插入到 3 次 9 分频中;
可以发现前两种方法时钟频率不均匀,相位抖动较大,所以一般会采用后两种平均插入的方法进行小数分频操作。实际的时序图如下所示

在这里插入图片描述
怎么把这种设计抽象为硬件描述语言呢

实际上很多种抽象方法,这里给出一个思路,即用一个大的计数器count(从0计到4,即代表了5个周期)当count=0,2,4的时候,执行9分频,当count=1,3的时候,执行8分频,偶数分频电路和奇数分频电路的实现可以参考第一篇和第二篇文章中的有关思想进行设计。

RTL设计

module fraction_divide(clk,rst_n,clk_out);
input clk;
input rst_n;
output reg clk_out; 

reg [2:0] count;
reg [3:0] count_odd;
reg [3:0] count_even;

always@(posedge clk or negedge rst_n)
begin
 if(!rst_n)begin //reset
count <= 3'd0;
count_odd  <= 3'd0;
count_even <= 3'd0;
 end

 else if (count == 3'd0 || count == 3'd2)begin //count = 0/2执行九分频
 if(count_odd < 4'd8)begin
 count_even <= 4'd0;
 count_odd <= count_odd +1'b1;
 end
 else  begin
 count_odd <= 4'd0;
 count <= count + 1'b1;
 end
 end

 else if (count ==3'd4)begin // count = 4 也执行九分频
 if(count_odd < 4'd8)begin
 count_even <= 4'd0;
 count_odd <= count_odd +1'b1;
 end
 else  begin
 count_odd <= 4'd0;
 count <= 4'd0;
 end
 end

 else if (count == 3'd1 || count == 3'd3)begin //count = 1/3执行八分频
 if(count_even < 4'd7) begin
 count_odd <= 4'd0;
 count_even <= count_even +1'b1;
 end
 else  begin
 count_even <= 4'd0;
 count <= count +1'b1;
 end
 end

 
 else begin 
 count <= 3'd0;
 count_odd  <= 3'd0;
 count_even <= 3'd0;
 end 

end

always@(*)
if(count_odd == 4'd8 || count_even == 4'd7)
clk_out = 1'b1;
else 
clk_out = 1'b0;

endmodule

小数分频电路的testbench

`timescale 1ns/1ps
module fraction_divide_tb();
reg clk;
reg rst_n;
wire clk_out;

fraction_divide u1 (.clk(clk),.rst_n(rst_n),.clk_out(clk_out));

always #5 clk =~clk;

initial
begin
clk = 0;
rst_n = 1;
#15
rst_n = 0;
#25
rst_n = 1;
#4000
$stop;
end

endmodule

仿真结果

【数字IC手撕代码】Verilog小数分频|题目|原理|设计|仿真_第1张图片

复位后所有的计数器都为0
两个白线之间的距离是895000-465000=430000ps
即430ns,输入的clock周期为10ns
因此满足了43个周期出现5个高周期的设计预期

你可能感兴趣的:(数字IC手撕代码,fpga开发,verilog,芯片,硬件架构,fpga)