FPGA硬件逻辑和数字IC中笔试面试常考的Verilog语言实现分频问题(包含偶数分频、计数分频、小数分频和任意整数分频)
由于2021秋招需要,我查找了很多奇偶分频的文章,将其中简单且便于理解的放出来,全部是经过Vivado仿真验证过的,请放心使用。
时钟信号的处理是FPGA的特色之一,因此分频器也是FPGA设计中使用频率非常高的基本设计之一。一般在FPGA中都有集成的锁相环可以实现各种时钟的分频和倍频设计,但是通过语言设计进行时钟分频是最基本的训练,在对时钟要求不高的设计时也能节省锁相环资源。
一、偶数分频
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: even_div
//Engineer: hewen
///
module even_div(clk_in,reset,clk_out);
parameter N = 4;
input clk_in;
input reset;
output clk_out;
reg clk_out;
reg[N-1:0] cnt;
always @(posedge clk_in)
begin
if(!reset)
begin
cnt<=0;
clk_out <= 0;
end
else
if(cnt==(N/2-1))
begin
cnt<=0;
clk_out=~clk_out;
end
else
begin
cnt<=cnt+1;
clk_out<=clk_out;
end
end
endmodule
对应的testbench测试程序
//testbench程序
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: even_div_tb
//Engineer: hewen
///
module even_div_tb;
reg clk_in;
reg reset;
wire clk_out;
even_div uut(
.clk_in(clk_in),
.reset(reset),
.clk_out(clk_out)
);
initial begin
clk_in = 0;
reset = 0;
#10 reset = 1;
end
always #5 clk_in = ~clk_in;
endmodule
举例–4分频的波形如下:
二、奇数分频
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: even_div
//Engineer: hewen
///
module odd_div(clk_in,reset,clk_out);
input clk_in;
input reset;
output clk_out;
integer cnt1,cnt2;
reg clk_divp;
reg clk_divn;
parameter N=5;
always @(posedge clk_in)
begin
if(!reset)
begin
clk_divp<=0;
cnt1<=0;
end
else
if(cnt1==(N-1))
cnt1<=0;
else
if(cnt1==0|cnt1==(N-1)/2)
begin
cnt1<=cnt1+1;
clk_divp<=~clk_divp;
end
else
cnt1<=cnt1+1;
end
always @(negedge clk_in)
begin
if(!reset)
begin
clk_divn<=0;
cnt2<=0;
end
else
if(cnt2==0|cnt2==(N-1)/2)
begin
cnt2<=cnt2+1;
clk_divn<=~clk_divn;
end
else
cnt2<=cnt2+1;
end
assign clk_out = clk_divp | clk_divn;
endmodule
对应的testbench测试程序
//testbench程序
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: odd_div_tb
//Engineer: hewen
///
module odd_div_tb;
reg clk_in;
reg reset;
wire clk_out;
odd_div uut(
.clk_in(clk_in),
.reset(reset),
.clk_out(clk_out)
);
initial
begin
clk_in = 0;
reset = 0;
#10 reset = 1;
end
always #2 clk_in = ~clk_in;
endmodule
举例–5分频的波形如下:
三、小数分频
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: half_integer_div
//Engineer: hewen
///
module half_integer_div(
input clk,
input rst_n,
output clk_out
);
parameter N = 3; //3.5分频
reg[31:0] cnt1;
reg clk_p;
reg clk_n;
always @(posedge clk or posedge rst_n)
begin
if(!rst_n)
cnt1<=0;
else if(cnt1 == 2*N)
cnt1<= 0;
else
cnt1<=cnt1+1;
end
always @(posedge clk or posedge rst_n)
begin
if(!rst_n)
clk_p<=0;
else if(cnt1 == 2*N)
clk_p<=1;
else if(cnt1 == N)
clk_p<=0;
end
always @(negedge clk or posedge rst_n)
begin
if(!rst_n)
clk_n <= 0;
else if (cnt1==0)
clk_n <= 0;
else if(cnt1 ==N)
clk_n<=1;
end
assign clk_out = clk_p & clk_n;
endmodule
对应的testbench测试程序
//testbench程序
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: half_integer_div_tb;
//Engineer: hewen
///
module half_integer_div_tb;
reg clk_in;
reg reset;
wire clk_out;
half_integer_div uut(
.clk(clk_in),
.rst_n(reset),
.clk_out(clk_out)
);
initial
begin
clk_in = 0;
reset = 0;
#10 reset = 1;
end
always #2 clk_in = ~clk_in;
endmodule
举例–3.5分频的波形如下:
四、任意整数分频
//参考链接:http://mp.weixin.qq.com/s/962d_hkVh3qxHrwz0v8eSg
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: divide
//Engineer: hewen
///
module divide #
(
parameter WIDTH = 24, //计数器的位数,计数的最大值为 2**(WIDTH-1)
parameter N = 12_000_000 //分频系数,请确保 N<2**(WIDTH-1),否则计数会溢出
)
(input clk, //clk连接到FPGA的C1脚,频率为12MHz
input rst_n, //复位信号,低有效,
output clkout //输出信号,可以连接到LED观察分频的时钟
);
reg [WIDTH-1:0] cnt_p,cnt_n;
reg clk_p,clk_n;
/**********上升沿触发部分************/
//上升沿触发时计数器的控制
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_p <= 1'b0;
else if(cnt_p == (N-1))
cnt_p <= 1'b0;
else
cnt_p <= cnt_p + 1'b1;
end
//上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
clk_p <= 1'b0;
else if(cnt_p < (N>>1))
clk_p <= 1'b0;
else
clk_p <= 1'b1;
end
/***********下降沿触发部分*************/
//下降沿触发时计数器的控制
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_n <= 1'b0;
else if(cnt_n == (N-1))
cnt_n <= 1'b0;
else
cnt_n <= cnt_n + 1'b1;
end
//下降沿触发的分频时钟输出,和clk_p相差半个clk时钟
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
clk_n <= 1'b0;
else if(cnt_n < (N>>1))
clk_n <= 1'b0;
else
clk_n <= 1'b1;
end
wire clk1 = clk; //当N=1时,直接输出clk
wire clk2 = clk_p; //当N为偶数也就是N[0]=0,输出clk_p
wire clk3 = clk_p & clk_n; //当N为奇数也就是N[0]=1,输出clk_p&clk_n。正周期多所以是相与
assign clkout = (N==1)? clk1:(N[0]? clk3:clk2);
endmodule
对应的testbench测试程序
//testbench程序
`timescale 1ns/1ps
///
//Create Date: 2020/03/05
//Module Name: divide_tb;
//Engineer: hewen
///
module divide_tb;
reg clk_in;
reg reset;
wire clk_out;
divide uut(
.clk(clk_in),
.rst_n(reset),
.clkout(clk_out)
);
initial
begin
clk_in = 0;
reset = 0;
#10 reset = 1;
end
always #2 clk_in = ~clk_in;
endmodule
举例–9分频的波形如下: