偶数分频(太简单不写了)
- D触发器级联并Q非连D,实现2的n次幂分频
- 计数器分频,0和n/2处反转
50%奇数分频
- 0,n/2处反转
- 将分频后的信号在原时钟negedge打一拍,将两个信号相或
module odd_divider#(
parameter N,
parameter N_2
)
(
input clk,
input rst_n,
output clk_N
);
//==============defination
reg clk_N_p;
reg clk_N_n;
wire clk_N;
reg [7 : 0] cnt;
//==============output
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt <= 'd0;
else if(cnt == N - 1) cnt <= 'd0;
else cnt <= cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) clk_N_p <= 1'b0;
else if(cnt == 0 || cnt == N_2) clk_N_p <= ~clk_N_p;
end
always@(negedge clk or negedge rst_n)begin
if(!rst_n) clk_N_n <= 1'b0;
else clk_N_n <= clk_N_p;
end
assign clk_N = clk_N_p || clk_N_n;
endmodule
module tb_odd_divider();
//===================parameter
parameter PERIOD = 10 / 2;
parameter N = 7;
parameter N_2 = 3;
//===================parameter
reg clk, rst_n;
wire clk_N;
//===================parameter
initial begin
clk = 0;
rst_n = 0;
#200 rst_n = 1;
#1500 $finish;
end
always #PERIOD clk = ~clk;
odd_divider#(
.N (N),
.N_2(N_2)
)
u_odd_divider
(
.clk (clk),
.rst_n(rst_n),
.clk_N(clk_N)
);
`ifdef FSDB
initial begin
$fsdbDumpfile("tb_odd_divider.fsdb");
$fsdbDumpvars;
$fsdbDumpMDA();
end
`endif
endmodule
- Schematic:
任意小数分频
- 说明:形如M/N分频,明白公式:M / N = Q…R(M个周期有N个脉冲,其中R个Q+1分频时钟,(N - R)个Q分频时钟)
- Code:
module decimal_divider#(
parameter M,
parameter N,
parameter Q,
parameter Q_2,
parameter R
)
(
input clk,
input rst_n,
output o_clk
);
//================defination
reg clk_q;
reg [7 : 0] cnt_q;
wire add_cnt_q;
wire end_cnt_q;
reg clk_q1;
reg [7 : 0] cnt_q1;
wire add_cnt_q1;
wire end_cnt_q1;
reg [7 : 0] cnt;
wire add_cnt;
wire end_cnt;
//================output
assign add_cnt_q = (cnt < N - R);
assign end_cnt_q = add_cnt_q && (cnt_q == Q - 1);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt_q <= 'd0;
else if(end_cnt_q) cnt_q <= 'd0;
else if(add_cnt_q) cnt_q <= cnt_q + 1'b1;
end
assign add_cnt_q1 = (cnt >= N - R);
assign end_cnt_q1 = add_cnt_q1 && (cnt_q1 == Q);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt_q1 <= 'd0;
else if(end_cnt_q1) cnt_q1 <= 'd0;
else if(add_cnt_q1) cnt_q1 <= cnt_q1 + 1'b1;
end
assign add_cnt = end_cnt_q || end_cnt_q1;
assign end_cnt = add_cnt && (cnt == N - 1);
always@(posedge clk or negedge rst_n)begin
if(!rst_n) cnt <= 'd0;
else if(end_cnt) cnt <= 'd0;
else if(add_cnt) cnt <= cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) clk_q <= 'd0;
else if(add_cnt_q && ((cnt_q == 0) || (cnt_q == Q_2))) clk_q <= ~clk_q;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n) clk_q1 <= 'd0;
else if(add_cnt_q1 && ((cnt_q1 == 0) || (cnt_q1 == Q_2))) clk_q1 <= ~clk_q1;
end
assign o_clk = clk_q || clk_q1;
endmodule
module tb_decimal_divider();
//===================parameter
parameter PERIOD = 10 / 2;
parameter M = 21;
parameter N = 5;
parameter Q = 4;
parameter Q_2 = 2;
parameter R = 1;
//===================defination
reg clk, rst_n;
wire o_clk;
//===================output
initial begin
clk = 0;
rst_n = 0;
#200 rst_n = 1;
#1500 $finish;
end
always #PERIOD clk = ~clk;
decimal_divider#(
.M(M),
.N(N),
.Q(Q),
.Q_2(Q_2),
.R(R)
)
u_decimal_divider
(
.clk (clk),
.rst_n(rst_n),
.o_clk(o_clk)
);
`ifdef FSDB
initial begin
$fsdbDumpfile("tb_decimal_divider.fsdb");
$fsdbDumpvars;
$fsdbDumpMDA();
end
`endif
endmodule
- Schematic: