1、奇偶分频
module fre_div
#(parameter DIV_NUM = 5)
(
input clk,
input rst_n,
output clk_div
);
reg [3:0] cnt_div;
wire clk_odd_div;
reg clk_even_div;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)
cnt_div <= 4'd0;
else if(cnt_div == DIV_NUM - 1)
cnt_div <= 4'd0;
else
cnt_div <= cnt_div + 4'd1;
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n)
clk_even_div <= 1'd0;
else if(cnt_div == DIV_NUM/2 - 1 | cnt_div == DIV_NUM - 1)
clk_even_div <= ~clk_even_div;
end
reg clk_odd_div0,clk_odd_div1;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)
clk_odd_div0 <= 1'd0;
else if(cnt_div == (DIV_NUM - 1)/2 | cnt_div == DIV_NUM - 1)
clk_odd_div0 <= ~clk_odd_div0;
else
clk_odd_div0 <= clk_odd_div0;
end
always @(negedge clk or negedge rst_n)begin
if(~rst_n)
clk_odd_div1 <= 1'd0;
else if(cnt_div == (DIV_NUM - 1)/2 | cnt_div == DIV_NUM - 1)
clk_odd_div1 <= ~clk_odd_div1;
else
clk_odd_div1 <= clk_odd_div1;
end
assign clk_odd_div = clk_odd_div0|clk_odd_div1;
assign clk_div = (DIV_NUM%2) ? clk_odd_div : clk_even_div;
endmodule
testbench
module clk_tb(
);
reg clk;
reg rst_n;
wire clk_div;
parameter DIV_NUM = 3;
fre_div
#(.DIV_NUM(DIV_NUM))
u_fre_div(
.clk (clk ),
.rst_n (rst_n ),
. clk_div( clk_div)
);
always #10 clk = ~clk;
initial begin
clk = 0;
rst_n = 0;
#100;
rst_n = 1;
end
endmodule
2、任意小数分频
如19/9分频,意味着在输入时钟clk_in的19个周期内,输出需产生9个脉冲,控制输出8个二分频时钟周期和1个三分频时钟周期即可。
// M/N小数分频,M为分子,N为分母
module Dec_Freq_Div_M_N(
input clk,
input rstn,
output clk_out
);
reg [5:0] cnt;
reg [3:0] cnt_a;
reg [3:0] cnt_b;
reg clk_out_reg;
assign clk_out = clk_out_reg;
// div_a和div_b分别为根据前述公式计算出来的基准分频系数
// change为2、3分频时钟的切换点
parameter M = 6'd19;
parameter change = 6'd16;
parameter div_a = 5'd2;
parameter div_b = 5'd3;
//总计数器
always @(posedge clk or negedge rstn) begin
if(!rstn)
cnt <= 6'b0;
else begin
if(cnt == M - 1'b1)
cnt <= 6'b0;
else
cnt <= cnt + 1'b1;
end
end
//产生2、3分频的计数器
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
cnt_a <= 4'b0;
cnt_b <= 4'b0;
end
else if(cnt<=change-1'b1) begin
cnt_b <= 4'd0;
if(cnt_a == div_a - 1'b1)
cnt_a <= 4'd0;
else
cnt_a <= cnt_a + 1'b1;
end
else if(cnt>change-1'b1) begin
cnt_a <= 4'd0;
if(cnt_b == div_b - 1'b1)
cnt_b <= 4'd0;
else
cnt_b <= cnt_b + 1'b1;
end
//输出时钟产生逻辑
always @(posedge clk or negedge rstn) begin
if(!rstn)
clk_out_reg <= 1'b0;
else if(cnt<change) begin
if(cnt_a == 4'd0 || cnt_a == div_a/2)
clk_out_reg <= ~clk_out_reg;
else
clk_out_reg <= clk_out_reg;
end
else if(cnt>=change) begin
if(cnt_b == 4'd0 || cnt_b == (div_b - 1'b1)/2)
clk_out_reg <= ~clk_out_reg;
else
clk_out_reg <= clk_out_reg;
end
end
endmodule