知识点(分频器)
1、奇偶数分频(经典)
module div_fre#(
parameter DIV_N = 'd4
);
(
input clk,
input rst_n,
output clk_div
);
reg [$clog2(DIV)-1:0]cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(add_cnt)
begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = 1;
assign end_cnt = add_cnt&&(cnt == DIV_N -1);
always@(negedge clk or negedge rst_n)begin
if(!rst)
clk1 <= 0;
else if(cnt == (DIV_N-1)/2)
clk1 <= 1;
else if(cnt == DIV_N-1)
clk1 <= 0;
else
clk1 <= clk1;
end
always@(posedge clk or negedge rst_n)begin
if(rst_n)
clk2 <= 0;
else if(cnt == (DIV_N-1)/2)
clk2 <= 1;
else if(cnt == DIV_N-1)
clk2 <= 0;
else
clk2 <= clk2;
end
assign clk_even = clk2;
assign clk_odd = clk1|clk2;
assign clk_out = (DIV_N%2)?clk_odd:clk_even;
2、N+0.5分频
对于常规的非50%分频,可以是在N+0.5的情况下,上升沿计数应到2N清零,并且在0与N+1时翻转。
下降沿计数应到2N清零,并且在0与N时翻转。
对于改进的接近50%分频比,可以是在N+0.5的情况下,上升沿计数应到2N清零,在0与2N+1/2时翻转,
下降沿计数应在N/2与N时翻转。
`timescale 1ns / 1ps
module divider_point5 #(parameter CLK_N = 2)
(
input clk_in,
input rst_n,
output reg clk_2in, // 2N倍频时钟
output reg clk_2in_2, // 下降沿2N倍频时钟
//output clk_en,
output clk_N_point5,
output reg clk_out
);
reg [7:0] cnt_2N; // 2N倍频时钟计数
reg [7:0] cnt_2N_2; // 下降沿2N倍频时钟计数
reg clk_out_g1;
assign clk_N_point5 = clk_2in && clk_2in_2;
// 上升沿生成2N分频时钟电路
always@(posedge clk_in or negedge rst_n) begin
if(!rst_n)
cnt_2N <= 8'b0;
else if(cnt_2N == 2*CLK_N)
cnt_2N <= 8'b0;
else
cnt_2N <= cnt_2N + 1'b1;
end
always@(posedge clk_in or negedge rst_n) begin
if(!rst_n)
clk_2in <= 1'b0;
//else if((cnt_2N == CLK_N+1) ||( cnt_2N ==0 )) begin // 这个是占空比为1:2N+1,未改进
else if((cnt_2N == CLK_N+1+CLK_N/2) ||( cnt_2N ==0 )) begin // 这个是占空比尽量靠近0.5的方式
clk_2in <= ~clk_2in;
end
else
clk_2in <= clk_2in;
end
// 下降沿生成2N分频时钟电路
always@(negedge clk_in or negedge rst_n) begin
if(!rst_n)
cnt_2N_2 <= 8'b0;
else if(cnt_2N_2 == 2*CLK_N)
cnt_2N_2 <= 8'b0;
else
cnt_2N_2 <= cnt_2N_2 + 1'b1;
end
always@(negedge clk_in or negedge rst_n) begin
if(!rst_n)
clk_2in_2 <= 1'b1;
//else if((cnt_2N_2 == CLK_N) ||( cnt_2N_2 == 0 )) begin // 这个是占空比为1:2N+1,未改进
else if((cnt_2N_2 == CLK_N) ||( cnt_2N_2 == CLK_N/2 )) begin // 这个是占空比尽量靠近0.5的方式
clk_2in_2 <= ~clk_2in_2;
end
else
clk_2in_2 <= clk_2in_2;
end
endmodule
3、任意小数分频(两种方法)
(1)脉冲删除法
module point_clk(
output reg clkout,
input rstn,
input refclk,
input [31:0] fenzi,//fenzi/fenmu must equal or more than 2
input [31:0] fenmu, //fenzi/fenmu must equal or more than 2
output reg [31:0] cnt
);
reg [2:0] rstn_syn;
always @(posedge refclk) begin
rstn_syn[0] <= rstn;
rstn_syn[1] <= rstn_syn[0];
rstn_syn[2] <= rstn_syn[1];
end
always @(posedge refclk or negedge rstn_syn[2]) begin
if(!rstn_syn[2]) cnt <= 0;
else begin
if(cnt < fenzi) cnt <= cnt + fenmu;
else cnt <= cnt + fenmu - fenzi;
end
end
always @(posedge refclk or negedge rstn_syn[2]) begin
if(!rstn_syn[2]) clkout <= 0;
else begin
if(((cnt > (fenzi>>1)) || (cnt == (fenzi>>1))) && (cnt < fenzi)) clkout <= 1;
else clkout <= 0;
end
end
endmodule
(2)双模置数法
以8.7分频为例,小数分频不可能50%
module DIV_M_N#(
parameter M_N = 'd87,
parameter ceo = 'd24,
parameter DIV_E = 'd8,
parameter DIV_O = 'd9
)
(
input clk,
input rst_n,
output clk_out
);
reg[$clog2(M_N)-1:0] cnt;
reg[$clog2(DIV_E)-1:0]cnt2;
reg[$clog2(DIV_O)-1:0]cnt1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(cnt == M_N-1)
cnt <= 0;
else
cnt <= cnt + 1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
cnt1 <= 0;
cnt2 <= 0;
end
else if(cnt <= ceo - 1)
begin
cnt1 <= 0;
if(cnt2 == DIV_E)
cnt2 <= 0;
else
cnt2 <= cnt2 + 1;
end
else if(cnt > ceo)
begin
cnt2 <= 0;
if(cnt1 == DIV_O)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
clk_M_N <= 0;
else begin
if(cnt < ceo)
begin
if(cnt2 ==0||cnt2==DIV_E/2)
clk_M_N <= ~clk_M_N;
end
else if(cnt>=ceo)
begin
if(cnt1 == 0||cnt1 == (DIV_O-1)/2)
clk_M_N <= ~clk_M_N;
end
end
end