任意整数倍分频器设计
2^n次方的分频器设计
对于一个占空比为50%的模8分频器
module mod8_divide
(
input clk,
input rst_n,
output clk_divide
);
reg [2:0] cnt;
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 3'b000;
else
cnt <= cnt +1'b1;
end
assign clk_divide=cnt[2];
endmodule
我们可以发现,cnt[2]的时序与输出的分频时钟时序完全一致,因此可以用cnt[2]来作为分频时钟的结果输出。进一步的,如果在设计中遇到模2^n次分频的情况,则可以通过这种方式实现,可以节约逻辑资源。
任意整数倍分频器设计
module div #(parameter N=5) ( input wire clk, input wire rst_n, output wire o_clk ); localparam WIDTH = log2(N); reg [WIDTH-1:0] cnt_p; reg [WIDTH-1:0] cnt_n; reg clk_p; reg clk_n; assign o_clk = (N==1) ? clk : (N[0]) ? (clk_p | clk_n) :clk_p; //上升沿计数 always @ (posedge clk,negedge rst_n) begin if(!rst_n) cnt_p <= {WIDTH{1'b0}}; else if (cnt_p == N-1) cnt_p <= {WIDTH{1'b0}}; else cnt_p <= cnt_p + 1'b1; end always @ (posedge clk,negedge rst_n) begin if(!rst_n) clk_p <= 1'b1; else if (cnt_p < (N>>1)) clk_p <= 1'b1; else clk_p <= 1'b0; end //下降沿计数 always @ (negedge clk,negedge rst_n) begin if(!rst_n) cnt_n <= {WIDTH{1'b0}}; else if (cnt_n == N-1) cnt_n <= {WIDTH{1'b0}}; else cnt_n <= cnt_n + 1'b1; end always @ (negedge clk,negedge rst_n) begin if(!rst_n) clk_n <= 1'b1; else if (cnt_n < (N>>1)) clk_n <= 1'b1; else clk_n <= 1'b0; end function integer log2(input integer n); integer i; begin log2 = 1; for (i=0;2**i<n;i=i+1) log2=i+1; end endfunction endmodule
`timescale 1ns/1ns module div_tb; reg clk,rst_n; wire o_clk; div #(.N(11)) div_tb ( .rst_n(rst_n), .clk(clk), .o_clk(o_clk) ); initial begin clk = 1'b1; rst_n = 1'b0; #20 rst_n =1'b1; #20000 $stop; end always #10 clk = ~clk; endmodule
N=10时的仿真结果(10分频)
N=11时的仿真结果(11分频)
代码优化修改如下:
module div #(parameter N=5) ( input wire clk, input wire rst_n, output wire o_clk ); localparam WIDTH = log2(N); reg [WIDTH-1:0] cnt_p; reg [WIDTH-1:0] cnt_n; reg clk_p; reg clk_n; assign o_clk = (N==1) ? clk : (N[0]) ? (clk_p | clk_n) :clk_p; //上升沿计数 always @ (posedge clk,negedge rst_n) begin if(!rst_n) cnt_p <= {WIDTH{1'b0}}; else if (cnt_p == N-1) cnt_p <= {WIDTH{1'b0}}; else cnt_p <= cnt_p + 1'b1; end always @ (posedge clk,negedge rst_n) begin if(!rst_n) clk_p <= 1'b1; else if (cnt_p < (N>>1)) clk_p <= 1'b1; else clk_p <= 1'b0; end //下降沿计数 /* always @ (negedge clk,negedge rst_n) begin if(!rst_n) cnt_n <= {WIDTH{1'b0}}; else if (cnt_n == N-1) cnt_n <= {WIDTH{1'b0}}; else cnt_n <= cnt_n + 1'b1; end always @ (negedge clk,negedge rst_n) begin if(!rst_n) clk_n <= 1'b1; else if (cnt_n < (N>>1)) clk_n <= 1'b1; else clk_n <= 1'b0; end */ always @ (negedge clk,negedge rst_n) begin if(!rst_n) clk_n <= 1'b1; else clk_n <= clk_p; end function integer log2(input integer n); integer i; begin log2 = 1; for (i=0;2**i<n;i=i+1) log2=i+1; end endfunction endmodule
路漫漫其修远兮,吾将上下而求索