一个简单的时钟分频器模块

A simple clock divider module

我被要求为不同类型的输入设计简单的时钟分频器电路。

我有一个 enabler [1:0] 输入和一个输入 clock,以及一个名为 clk_enable 的输出。

如果 enabler=01 那么我的输入时钟应该每 2 个时钟启用一次 signals.If enabler=10 那么我的输入应该除以 4 等等

我设法使用 case 关键字将我的输入时钟划分为不同的情况,但是对于 enabler=00 我的输入时钟应该等于我的输出 clk_enable 我无法做到这一点。

这是我试过的。我正在为 enabler=00 的情况寻求帮助。

module project(input [1:0] enabler,
                            input clock,
                            output reg clk_enable);

reg  [3:0] count,c;
initial begin
count=4'b0000;
c=4'b0000;
end

always @( posedge clock)
    case(enabler)
    2'b00:clk_enable<=clock;
    2'b01:clk_enable<=~clk_enable;
    2'b10:begin
            if (count >= 4'b0100-1)      
                count<=4'b0000;
            else begin 
            count<=count + 4'b0001;
            clk_enable<=(count<(4'b0100 / 2));
            end
            end
    2'b11: begin
            if (count >= 4'b1000-1)      
                count<=4'b0000;
            else begin 
            count<=count + 4'b0001;
            clk_enable<=(count<(4'b1000 / 2));
            end
            end
    endcase                                             
endmodule

这看起来你有很强的软件开发背景? :)

我的建议是你总是在组合逻辑和顺序逻辑之间划清界线。这包括关于设计的哪些部分实际上必须是顺序的,哪些可以是组合的一些想法。

对于你的情况,时钟分频显然必须是顺序的,因为你想在输入的 CLK 信号的每个上升沿反转生成的 CLK 信号(频率 f/2,情况 0'b01)(频率 f,案例 0'b00)。同样适用于 f/4(案例 0'b10)。 这部分需要是顺序的,因为你想反转之前的 CLK 状态......如果在组合逻辑中实现,这将导致 cmobinational 循环。因此,这里确实需要在 CLK 边沿上触发。 然而,正确的 CLK 输出信号的实际选择可以是组合的。您只想将正确的 CLK 信号分配给输出 CLK。

顺序部分的实现可能如下所示:

// frequency division from input CLK --> frequency: f/2
always @(posedge clk  or  negedge rst_neg) begin
    if (rst_neg = 1'b0) begin
        clk_2  <= 1'b0;
    end else begin
        clk_2  <= ~clk_2;
    end
end

// frequency division from first divided CLK --> frequency: f/4
always @(posedge clk_2  or  negedge rst_neg) begin
    if (rst_neg = 1'b0) begin
        clk_ 4 <= 1'b0;
    end else begin
        clk_4  <= ~clk_4;
    end
end

// frequency division from first divided CLK --> frequency: f/8
always @(posedge clk_4  or  negedge rst_neg) begin
    if (rst_neg = 1'b0) begin
        clk_ 8 <= 1'b0;
    end else begin
        clk_8  <= ~clk_8;
    end
end

所以这个简单的时序逻辑负责生成您需要的 f/2 和 f/4 的分频 CLK 信号。我还在下降沿包含了复位信号,这是您通常需要的。并且您保留了计数器逻辑(增量和比较)。

现在我们用简单的组合逻辑来处理正确的选择:

always @(*) begin
    case(enabler)
        2'b00:  clk_enable = clk;
        2'b01:  clk_enable = clk_2;
        2'b10:  clk_enable = clk_4;
        2'b11:  clk_enable = clk_8;
    endcase
end

这与您的硬件描述非常接近(clk_enable 需要在此处注册)。

但是,组合部分的另一种方法如下(将 clk_enable 声明为电线):

assign clk_enable = (enabler == 2'b00)  ?  clk
                      : (enabler == 2'b01)  ?  clk_2
                          : (enabler == 2'b10)  ?  clk_4
                              : (enabler == 2'b11)  ?  clk_8;

这将生成上升速率与 div_ratio 输入相匹配的门控脉冲时钟。 div_ratio 输出 0 div1 时钟(clk 原样) 1 div2(每 2 个 clk 脉冲脉冲一次) 2格3 3 div4

当不需要在分频时钟的负边沿采样时,这通常更可取 如果你需要 50% 的占空比我可以给你另一个片段

module clk_div_gated (
    input [1:0] div_ratio,
    input       clk,
    input       rst_n,    // async reset - a must for clock divider
    output      clk_div
);

reg [1:0] cnt;
reg clk_en;

always @(posedge clk or negedge rst_n)
    if (~rst_n)
        cnt    <= 2'h0;
    else
        cnt    <= (cnt == div_ratio)? 2'h0 : cnt + 1'b1;

// clk_en toggled at negedge to prevent glitches on output clock
// This is ok for FPGA, synthesizeable ASIC design must use latch + AND method
always @(negedge clk)
    clk_en <= (cnt == div_ratio);

assign clk_div <= clk & clk_en;

endmodule