even frequency division
You can adopt the idea of synchronous integer frequency division, and you can use Moore's state machine or counter (sequence machine) idea. Here is an implementation idea of synchronous 7-frequency Moore's state machine:
module clk_divide(
input wire clk ,
input wire rst_n ,
output wire clk_o
);
//==================1. 同步整数分频器====================//
//基于摩尔状态机实现7分频(一段式状态机) 同样可以实现偶数分频
localparam S0 = 7'b0000_001 , //S0状态:clk_o输出0
S1 = 7'b0000_010 , //S1状态:clk_o输出0
S2 = 7'b0000_100 , //S2状态:clk_o输出0
S3 = 7'b0001_000 , //S3状态:clk_o输出0
S4 = 7'b0010_000 , //S4状态:clk_o输出1
S5 = 7'b0100_000 , //S5状态:clk_o输出1
S6 = 7'b1000_000 ; //S1状态:clk_o输出1
reg [6:0] state ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= S0;
clk_o <= 1'b0;
end
else begin
case(state)
S0: begin state <= S1; clk_o <= 1'b0; end
S1: begin state <= S2; clk_o <= 1'b0; end
S2: begin state <= S3; clk_o <= 1'b0; end
S3: begin state <= S4; clk_o <= 1'b0; end
S4: begin state <= S5; clk_o <= 1'b1; end
S5: begin state <= S6; clk_o <= 1'b1; end
S6: begin state <= S0; clk_o <= 1'b1; end
default:begin state <= S0; clk_o <= 1'b1; end
endcase
end
end
The testbench looks like this:
`timescale 1ns/1ns
`define CLK_CYCLE 20
module tb_clk_divide;
reg clk ;
reg rst_n ;
wire clk_o ;
clk_divide u_clk_divide(
.clk (clk) ,
.rst_n (rst_n) ,
.clk_o (clk_o)
);
initial begin
clk = 1'b0;
rst_n = 1'b0;
#201;
rst_n = 1'b1;
end
always #(`CLK_CYCLE / 2) clk = ~clk;
endmodule
The simulation waveform is:
Odd frequency division
method one
The main idea is as follows:
First, two counters are constructed based on the rising edge of the clock and the falling edge of the clock. Both counters are set to 0 when the maximum value of the frequency division is set. Then two counters are given respectively and two variables are declared, clk_div1 and clk_div2. . If the two clock edges are less than half of the maximum count value, the signal will be pulled high. Otherwise, the signal will be lowered. Finally, the final divided clock can be obtained by ORing these two variable signals.
module clk_divide(
input wire clk ,
input wire rst_n ,
output wire clk_o
);
//==================2. 奇数分频器=======================//
//方法1
parameter CLK_DIV = 7 ; //奇数分频的频数
reg [3:0] cnt_pos ; //上升沿计数器
reg [3:0] cnt_neg ; //下降沿计数器
reg clk_div1 ; //分频信号1
reg clk_div2 ; //分频信号2
always @(posedge clk or negedge rst_n) begin //时钟上升沿触发
if(!rst_n) begin
cnt_pos <= 'd0;
end
else if(cnt_pos == CLK_DIV - 1'b1) begin //计数最大值置0
cnt_pos <= 'd0;
end
else
cnt_pos <= cnt_pos + 1'b1;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div1 <= 1'b0;
end
else if(cnt_pos < CLK_DIV / 2) begin //小于计数值的一半,拉高clk_div1
clk_div1 <= 1'b1;
end
else begin+
clk_div1 <= 1'b0;
end
end
always @(negedge clk or negedge rst_n) begin //时钟下降沿触发
if(!rst_n) begin
cnt_neg <= 'd0;
end
else if(cnt_neg == CLK_DIV - 1) begin //计数到最大值置0
cnt_neg <= 'd0;
end
else begin
cnt_neg <= cnt_neg + 1'b1;
end
end
always @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div2 <= 1'b0;
end
else if(cnt_neg < CLK_DIV / 2) begin //小于计数值的一半,拉高clk_div2
clk_div2 <= 1'b1;
end
else begin
clk_div2 <= 1'b0;
end
end
assign clk_o = clk_div1 | clk_div2; //将clk_div1和clk_div2或运算
Simulation screenshot:
Method Two
The second method is from "The Art of Hardware Architecture". Based on its ideas, the implementation code is as follows. There are detailed comments in the code, so I won't go into details.
module clk_divide(
input wire clk ,
input wire rst_n ,
output wire clk_o
);
//方法2(来自《硬件架构的艺术》)
//步骤1:创建由时钟上升沿触发的0-(N-1)的计数器,N为分频系数
parameter N = 5 ;
reg [3:0] cnt_up ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_up <= 'd0;
end
else if(cnt_up == N-1) begin
cnt_up <= 'd0;
end
else begin
cnt_up <= cnt_up + 1'b1;
end
end
//步骤2:使用两个触发器,按照如下方式产生使能信号
//tff1_en:在计数值为0时使能
//tff2_en:在计数值为(N+1)/2时使能
wire tff1_en ;
wire tff2_en ;
assign tff1_en = (cnt_up == 0) ? 1'b1 : 1'b0;
assign tff2_en = (cnt_up == (N+1)/2) ? 1'b1 : 1'b0;
//步骤三:产生以下信号
//div1:TFF1的输出--->由输入时钟的上升沿触发
//div2:TFF2的输出--->由输入时钟的下降沿触发
reg div1 ;
reg div2 ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div1 <= 1'b0;
end
else if(tff1_en) begin
div1 <= ~div1;
end
else begin
div1 <= div1;
end
end
always @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
div2 <= 1'b0;
end
else if(tff2_en) begin
div2 <=~div2;
end
else begin
div2 <= div2;
end
end
//步骤四:将div1和div2信号异或
assign clk_o = div1 ^ div2;
endmodule
The simulation is as follows:
All code
//时钟分频器
//2022/09/01
//======================================================//
//==================1. 同步整数分频器====================//
//==================2. 奇数分频器=======================//
module clk_divide(
input wire clk ,
input wire rst_n ,
output wire clk_o
);
/*
//==================1. 同步整数分频器====================//
//基于摩尔状态机实现7分频(一段式状态机) 同样可以实现偶数分频
localparam S0 = 7'b0000_001 , //S0状态:clk_o输出0
S1 = 7'b0000_010 , //S1状态:clk_o输出0
S2 = 7'b0000_100 , //S2状态:clk_o输出0
S3 = 7'b0001_000 , //S3状态:clk_o输出0
S4 = 7'b0010_000 , //S4状态:clk_o输出1
S5 = 7'b0100_000 , //S5状态:clk_o输出1
S6 = 7'b1000_000 ; //S1状态:clk_o输出1
reg [6:0] state ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= S0;
clk_o <= 1'b0;
end
else begin
case(state)
S0: begin state <= S1; clk_o <= 1'b0; end
S1: begin state <= S2; clk_o <= 1'b0; end
S2: begin state <= S3; clk_o <= 1'b0; end
S3: begin state <= S4; clk_o <= 1'b0; end
S4: begin state <= S5; clk_o <= 1'b1; end
S5: begin state <= S6; clk_o <= 1'b1; end
S6: begin state <= S0; clk_o <= 1'b1; end
default:begin state <= S0; clk_o <= 1'b1; end
endcase
end
end
*/
//==================2. 奇数分频器=======================//
/*
//方法1
parameter CLK_DIV = 7 ; //奇数分频的频数
reg [3:0] cnt_pos ; //上升沿计数器
reg [3:0] cnt_neg ; //下降沿计数器
reg clk_div1 ; //分频信号1
reg clk_div2 ; //分频信号2
always @(posedge clk or negedge rst_n) begin //时钟上升沿触发
if(!rst_n) begin
cnt_pos <= 'd0;
end
else if(cnt_pos == CLK_DIV - 1'b1) begin //计数最大值置0
cnt_pos <= 'd0;
end
else
cnt_pos <= cnt_pos + 1'b1;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div1 <= 1'b0;
end
else if(cnt_pos < CLK_DIV / 2) begin //小于计数值的一半,拉高clk_div1
clk_div1 <= 1'b1;
end
else begin+
clk_div1 <= 1'b0;
end
end
always @(negedge clk or negedge rst_n) begin //时钟下降沿触发
if(!rst_n) begin
cnt_neg <= 'd0;
end
else if(cnt_neg == CLK_DIV - 1) begin //计数到最大值置0
cnt_neg <= 'd0;
end
else begin
cnt_neg <= cnt_neg + 1'b1;
end
end
always @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_div2 <= 1'b0;
end
else if(cnt_neg < CLK_DIV / 2) begin //小于计数值的一半,拉高clk_div2
clk_div2 <= 1'b1;
end
else begin
clk_div2 <= 1'b0;
end
end
assign clk_o = clk_div1 | clk_div2; //将clk_div1和clk_div2或运算
*/
//方法2(来自《硬件架构的艺术》)
//步骤1:创建由时钟上升沿触发的0-(N-1)的计数器,N为分频系数
parameter N = 5 ;
reg [3:0] cnt_up ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_up <= 'd0;
end
else if(cnt_up == N-1) begin
cnt_up <= 'd0;
end
else begin
cnt_up <= cnt_up + 1'b1;
end
end
//步骤2:使用两个触发器,按照如下方式产生使能信号
//tff1_en:在计数值为0时使能
//tff2_en:在计数值为(N+1)/2时使能
wire tff1_en ;
wire tff2_en ;
assign tff1_en = (cnt_up == 0) ? 1'b1 : 1'b0;
assign tff2_en = (cnt_up == (N+1)/2) ? 1'b1 : 1'b0;
//步骤三:产生以下信号
//div1:TFF1的输出--->由输入时钟的上升沿触发
//div2:TFF2的输出--->由输入时钟的下降沿触发
reg div1 ;
reg div2 ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
div1 <= 1'b0;
end
else if(tff1_en) begin
div1 <= ~div1;
end
else begin
div1 <= div1;
end
end
always @(negedge clk or negedge rst_n) begin
if(!rst_n) begin
div2 <= 1'b0;
end
else if(tff2_en) begin
div2 <=~div2;
end
else begin
div2 <= div2;
end
end
//步骤四:将div1和div2信号异或
assign clk_o = div1 ^ div2;
endmodule