任意整数倍分频器设计

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 

posted on 2010-12-17 17:45  齐威王  阅读(2418)  评论(0编辑  收藏  举报

导航