Verilog -- 奇数分频器
偶数分频的原理就是计数到N/2-1后对分频输出取反。而如果分频数N为基数,则需要:
clk_out1 在clk 上升沿计数到 (N-1)/2-1后取反, 计数到N-1以后再取反
clk_out2 在clk 下降沿计数到 (N-1)/2-1后取反, 计数到N-1以后再取反
clk_out 取clk_out1 和 clk_out2的或。
代码:
module clk_div
#(
parameter DIV = 3
)
(
input clk_in,
input rst_n,
output clk_out
);
parameter WIDTH = $clog2(DIV);
parameter HALF_DIV = (DIV-1)/2;
reg [WIDTH-1:0] cnt;
reg clk_div1;
reg clk_div2;
assign clk_out = clk_div1 | clk_div2;
always@(posedge clk_in or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
end else begin
if(cnt == DIV-1) cnt <= 0;
else cnt <= cnt + 1;
end
end
always@(posedge clk_in or negedge rst_n) begin
if (!rst_n) begin
clk_div1 <= 0;
end else begin
if(cnt==HALF_DIV-1) begin
clk_div1 <= 0;
end
else if(cnt == DIV-1)begin
clk_div1 <= 1;
end
else begin
clk_div1 <= clk_div1;
end
end
end
always@(negedge clk_in or negedge rst_n) begin
if (!rst_n) begin
clk_div2 <= 0;
end else begin
if(cnt==HALF_DIV-1) begin
clk_div2 <= 0;
end
else if(cnt == DIV-1)begin
clk_div2 <= 1;
end
else begin
clk_div2 <= clk_div2;
end
end
end
endmodule
testbench:
`timescale 1ns/1ps
module clk_div_tb(/*autoarg*/);
reg clk_in;
reg rst_n;
wire clk_out;
always #1 clk_in = ~clk_in;
initial begin
clk_in = 1;
rst_n = 1;
#2 rst_n = 0;
#2 rst_n = 1;
end
initial begin
$fsdbDumpvars();
$fsdbDumpMDA();
$dumpvars();
#100 $finish;
end
clk_div #(
.DIV ( 3 ))
U_CLK_DIV_0(
.clk_in ( clk_in ),
.rst_n ( rst_n ),
.clk_out ( clk_out )
);
endmodule
仿真波形: