今天学习了一下分频器及其Verilog实现
1.偶分频
实现一个NUM_DIV分频的分频器,下面代码中 NUM_DIV= 6,占空比50%
设计代码
module divider_even(
clk,
rst_n,
clk_div
);
input clk;
input rst_n;
output clk_div;
reg clk_div;
parameter NUM_DIV = 6;
reg [3:0] cnt;
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
cnt <= 4'd0;
clk_div <= 1'b0;
end
else if(cnt < NUM_DIV / 2 - 1) begin
cnt <= cnt + 1'b1;
clk_div <= clk_div;
end
else begin
cnt <= 4'd0;
clk_div <= ~clk_div;
end
endmodule
仿真代码
module divider_tb();
reg clk;
reg rst_n;
wire clk_div;
parameter DELY=100;
divider_even U_divider(
.clk (clk ),
.rst_n (rst_n ),
.clk_div(clk_div)
);
always #(DELY/2) clk=~clk;//??????
/*initial begin
$fsdbDumpfile("divider_even.fsdb");
$fsdbDumpvars(0,U_divider);
end
*/initial begin
clk=0;rst_n=0;
#DELY rst_n=1;
//#((DELY*20)) $finish;
end
endmodule
波形图
从波形图中可以看到,clk_div的时钟频率是clk的1/6;计数cnt = 3清零
2.奇分频
设计目标:实现一个占空比50%,5分频的分频器
遇到一个错误,寄存器变量不能使用连续赋值语句
assign clk_div = clk_div1 | clk_div2;
** Error: E:/questasim/examples/labs/divider/odd_divider.v(53): Register is illegal in left-hand side of continuous assignment
解决方案很简单,只需要加一个initial,把这个赋值语句放在过程块里面就好了;
设计代码
//rtl
module divider_odd(
clk,
rst_n,
clk_div
);
input clk;
input rst_n;
output clk_div;
reg clk_div;
parameter NUM_DIV = 5;
reg[2:0] cnt1;
reg[2:0] cnt2;
reg clk_div1, clk_div2;
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt1 <= 0;
else if(cnt1 < NUM_DIV - 1)
cnt1 <= cnt1 + 1'b1;
else
cnt1 <= 0;
always @(posedge clk or negedge rst_n)
if(!rst_n)
clk_div1 <= 1'b1;
else if(cnt1 < NUM_DIV / 2)
clk_div1 <= 1'b1;
else
clk_div1 <= 1'b0;
always @(negedge clk or negedge rst_n)
if(!rst_n)
cnt2 <= 0;
else if(cnt2 < NUM_DIV - 1)
cnt2 <= cnt2 + 1'b1;
else
cnt2 <= 0;
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
clk_div2 <= 1'b1;
else if(cnt2 < NUM_DIV / 2)
clk_div2 <= 1'b1;
else
clk_div2 <= 1'b0;
end
initial
assign clk_div = clk_div1 | clk_div2;
endmodule
仿真代码
//tb
module divider_tb();
reg clk;
reg rst_n;
wire clk_div;
parameter DELY=100;
divider_odd U_divider(
.clk (clk ),
.rst_n (rst_n ),
.clk_div(clk_div)
);
always #(DELY/2) clk=~clk;//??????
/*initial begin
// $fsdbDumpfile("divider_odd.fsdb");
// $fsdbDumpvars(0,U_divider);
//end
*/
initial begin
clk=0;rst_n=0;
#DELY rst_n=1;
//#((DELY*20)) $finish;
end
endmodule
波形图
从波形图可以看到,实现了5分频,占空比50%
3.任意占空比,任意分频
设计目标:时钟信号50M分频产生880Hz,而分频得到的信号的占空比为30%
设计代码
//rtl
module div_any(
clk,
rst_n,
clk_div,
counter
);
input clk,rst_n;
output clk_div;
reg clk_div;
output [15:0] counter;
reg [15:0] counter;
always @(posedge clk)
if(!rst_n)
counter <= 0;
else if(counter==56817)
counter <= 0;
else counter <= counter+1;
always @(posedge clk)
if(!rst_n)
clk_div <= 0;
else if(counter<17045)
clk_div <= 1;
else
clk_div <= 0;
endmodule
仿真代码
//tb
module div_tb();
reg clk;
reg rst_n;
wire clk_div;
wire [15:0] counter;
parameter DELY=100;
div_any U_div(
.clk (clk ),
.rst_n (rst_n ),
.counter(counter),
.clk_div(clk_div)
);
always #(DELY/2) clk=~clk;//??????
/*initial begin
$fsdbDumpfile("div_any.fsdb");
$fsdbDumpvars(0,U_div);
end*/
initial begin
clk=0;rst_n=0;
#DELY rst_n=1;
#((DELY*80000)) $finish;
end
endmodule
波形图
参考Verilog设计分频器(面试必看) - Zhangxianhe - 博客园
本文的波形都是自己仿真生成的