基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)

文章目录

  • 前言
  • 一、开源资料下载链接
  • 二、行波计数器
    • 2.1 行波计数器介绍
    • 2.2 设计实例
    • 2.3 总结
  • 三、计数分频器
    • 3.1 计数分频器介绍
    • 3.2 设计实例
    • 3.3 总结
  • 四、门控时钟设计
    • 4.1 门控时钟介绍
    • 4.2伪门控时钟
    • 4.3 基于锁存器的门控时钟
    • 4.3 基于锁存器的门控时钟设计实例
    • 4.4 总结
  • 五、奇数分频器
    • 5.1 奇数分频器简介
    • 5.2 设计实例
    • 5.3 另一种设计思路
    • 5.4 总结
  • 文献参考


前言

  在许多设计中,常常伴随着对时钟的各种需求,如需要进行偶数倍分频,奇数倍分频;对于时钟的处理也很重要,如何防止时钟截断,时钟毛刺,减少累计时钟偏移;在低功耗设计中,如何降低时钟网络和其中寄存器的功耗;
  进而衍生出各种技术,如行波计数器、计数分频器、门控时钟、锁存器门控时钟等待。
  在数字设计中,产生时钟信号的方法主要有两种,一种是通过PLL锁相环对时钟源进行分频或倍频,另一种是在设计的模块中用硬件描述语言描述分频逻辑。
  在本文中将对这些技术进行简要的介绍,并给出若干设计实例。


一、开源资料下载链接

  https://hihii11.github.io/verilog_clockmanager.html

二、行波计数器

2.1 行波计数器介绍

  图2.1给出了一个三级行波计数器,每个D触发器的反相输出端~Q与输入端D相连。正向输出端作为下一级触发器的时钟信号。
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第1张图片                图2.1 三级行波计数器

这样设计的行波计数器相对于其他分频器来说,其具有以下特点。
1.每级D触发器可对源时钟进行2n分频。
  如上图2.1中,
    clk1 = clk_source / 2;
     clk2 = clk_source / 4;
     clk3 = clk_source / 8;
   其各级时钟波形如图2.2所示。
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第2张图片
                图2.2 各级时钟波形
2.资源消耗少
  由于行波计数器仅通过若干个触发器级联产生时钟,所以其没有附加的组合逻辑,故消耗资源较少。
3.功耗低
  由于行波计数器消耗资源少,故在CLK发生反转时,所带动的处于活跃的组合逻辑部分也较少,因此由这部分逻辑产生的峰值功耗大大降低。
  在低功耗设计中常用行波计数器。

行波计数器也存在以下缺点:
1.行波计数器有较严重的级联效应
  由于行波计数器的级联结构,其每一级时钟都会产生一定的滞后。
如:
  clk1 相较于 clk_source 会产生由U1A所引入的触发器延时及布线延时(tU1A)。
  clk2 相较于 clk1 会产生由U2A所引入的触发器延时(tU2A)。
  clk3 同理。
  由此一来,延迟会不断积累,如图2.3所示。
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第3张图片
                图2.3 行波计数器的级联效应
  一方面这种延迟可能会引入毛刺,另一方面在同步电路设计中,有可能会违背数据的建立保持时间。
  因为行波计数器产生的时钟本质上是异步的,依赖其产生的时钟的模块,在进行数据交互时,属于跨时钟域。
2.会对STA工具和综合工具带来麻烦
  行波计数器在各阶段创建时钟所引入的级联效应导致的问题,会增加STA工具和综合工具的工作量。

2.2 设计实例

1.模块代码

module travel_wave_counter#(
       parameter integer LEVELs = 3
)
(
       input  wire                  CLK_IN,
       input  wire                    nRST,
       output wire [LEVELs-1:0]    CLK_OUT
    );
    
    genvar i;
    generate
        for(i = 0;i < LEVELs;i = i+1)
        begin
            if(i == 0)
            begin
                travel_wave_level travel_wave_level_inist0(
                   .CLK_IN(CLK_IN),.nRST(nRST),.DOUT(CLK_OUT[i]));
            end
            else
            begin
                travel_wave_level travel_wave_level_inist0(
                   .CLK_IN(CLK_OUT[i-1]),.nRST(nRST),.DOUT(CLK_OUT[i]));
            end
        end
    endgenerate    
endmodule

module travel_wave_level(
       input  wire  CLK_IN,
       input  wire    nRST,
       output wire    DOUT
);
    reg dout;
    assign DOUT = dout;
    always@(posedge CLK_IN,negedge nRST)
    begin
        if(~nRST)
        begin
            dout <= 1'b0;
        end
        else
        begin
            dout <= ~dout;
        end
    end
endmodule

2.综合电路框图
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第4张图片

2.3 总结

  行波计数器产生时钟属于异步,同步应当避免。
  在低功耗设计等情况下,可以尝试使用行波计数器,但需要严格控制。


三、计数分频器

3.1 计数分频器介绍

  针对上述行波计数器的缺点,在同步电路设计中,可以采用计数器或状态机来产生分频时钟。
  利用计数器产生分频器需要注意:
  1.应由寄存器直接产生时钟信号,永远不要对计数器或状态机输出进行译码。
  原因是状态改变时信号会产生竞争冒险,从而导致逻辑错误,产生的时钟信号出现毛刺,会导致电路逻辑错误。
  2.对主频进行分频时,应使用同步计数器或状态机。

3.2 设计实例

  典型的计数分频器设计:(注意本小节计数器均为偶数分频)
1.使用两个同步always逻辑块

module div_counter#(
        parameter integer DIV_NUM = 2
)(
        input  wire  CLK_IN,
        input  wire    nRST,
        output wire CLK_OUT
    );
    
    reg [15:0] clk_cnt;
    reg clk_out;
    assign CLK_OUT = clk_out;
    always@(posedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_cnt <= 16'd0;
        end
        else
        begin
            if(clk_cnt != DIV_NUM - 1)
                clk_cnt <= clk_cnt + 16'd1;
            else
                clk_cnt <= 16'd0;
        end
    end
    
    always@(posedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_out <= 1'b0;
        end
        else
        begin
            if(clk_cnt < DIV_NUM/2)
                clk_out <= 1'b1;
            else
                clk_out <= 1'b0;
        end
    end
endmodule

综合后电路:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第5张图片2.一个always逻辑块,一个组合逻辑

module div_counter#(
        parameter integer DIV_NUM = 2
)(
        input  wire  CLK_IN,
        input  wire    nRST,
        output wire CLK_OUT
    );
    
    reg [15:0] clk_cnt;
    reg clk_out;
    assign CLK_OUT = (clk_cnt < DIV_NUM/2)?1'b1:1'b0;
    always@(posedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_cnt <= 16'd0;
        end
        else
        begin
            if(clk_cnt != DIV_NUM - 1)
                clk_cnt <= clk_cnt + 16'd1;
            else
                clk_cnt <= 16'd0;
        end
    end
endmodule

综合后电路:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第6张图片  两种设计方式的区别在于,第一种设计时钟信号是通过时序逻辑驱动产生的,而第二种是直接通过组合逻辑产生。
  第二种设计对于信号毛刺的抗干扰性较差,第一种可以很好地滤除毛刺。

3.3 总结

  对于行波计数器的缺点,可采取计数器的方法进行时钟分频。
  完全同步的设计,时钟偏移现象相对行波计数器较轻。
  消耗的资源较行波计数器较多,且功耗较大。


四、门控时钟设计

4.1 门控时钟介绍

  门控时钟是减少功耗的有力手段,在时钟被门控关闭后,该时钟网络和其中的寄存器都会停止翻转,因此功耗会显著减低。
  但门控时钟也会带来一些问题:
  1.门控时钟属于非同步设计,会增加设计时间和验证工作量。
  2.门控时钟会在时钟链路上增加额外的时钟偏移。
  3.门控时钟对毛刺敏感,可能导致设计失败。

传统的门控时钟设计如图3.1所示:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第7张图片
                图4.1 典型门控时钟电路
  对于时钟源clk_source经过一个额外的与门U2A,当clk_en为高时,clk_source能过通过到达U1A触发器,当clk_en为低时clk_source无法到达触发器。
  当clk_en为低时,触发器及其时钟网络中的所有组合逻辑停止翻转,out端保持不变。
  由于clk_source经过了U2A与门,所有会产生一定的时钟偏移。

4.2伪门控时钟

  上述问题可以通过同步设计来解决。
  使用MUX的同步设计方案:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第8张图片
                图4.2 伪门控时钟电路
  可以通过clk_en来控制触发器输入端口D的数据,若此时选择的数据为out端口,则触发器输出将保持不变。
  但由于并未切断时钟树,所以触发器内部包括组合逻辑都处于活跃状态,功耗并未得到实质性降低。

4.3 基于锁存器的门控时钟

传统的门控时钟仅有一级与门进行门控控制,其会产生时钟截断情况:
在这里插入图片描述
                图4.3 传统门控时钟的时钟截断现象
  在6时刻,因为clk_en由高变低,所以其输出clk_out被截断,同理在8时刻,由于clk_en变高,clk_out同样被截断。
  这样的截断会产生以下一些问题:
  1.时钟占空比不平衡。
  2.产生的脉冲尖峰(干扰)会引起保持建立时间的问题。

  故在设计中可采用锁存器来避免时钟截断。

4.3 基于锁存器的门控时钟设计实例

基于锁存器门控时钟的verilog描述:

module gata_clock(
        input  wire     CLK_IN,
        input  wire    CLK_ENI,
        output wire    CLK_OUT
    );
    reg clk_eno;
    
    assign CLK_OUT = clk_eno & CLK_IN;
    
    always@(~CLK_IN)
    begin
        clk_eno <= CLK_ENI;
    end    
endmodule

时钟截断仿真:
在这里插入图片描述
由于在FPGA设计中,板上资源有时没有锁存器;
此时可以将锁存器换为触发器;

module gata_clock(
        input  wire     CLK_IN,
        input  wire    CLK_ENI,
        output wire    CLK_OUT
    );
    (*KEEP="true"*)reg clk_eno;
    
    assign CLK_OUT = clk_eno & CLK_IN;
    
    always@(posedge CLK_IN)
    begin
        clk_eno <= CLK_ENI;
    end    
endmodule

综合后电路:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第9张图片

4.4 总结

  合理使用门控时钟可以降低模块功耗。
  在FPGA设计中,可以使用带触发器的门控时钟来消除时钟截断现象。


五、奇数分频器

5.1 奇数分频器简介

  对于偶数倍的分频,可以使用行波计数器或计数器等方式实现;
  但对于占空比要求为百分之50的奇数分频,上述几种设计就难以实现了;
  对于奇数倍的分频,可以采取以下设计方法:
  1.创建一个模N计数器,计数值为0-(N-1)
  2.创建两个T触发器,用于产生时钟产生逻辑LOGIC0,LOGIC1
     需要注意产生LOGIC0的T触发器需在输入时钟的上升沿采样
     产生LOGIC1的T触发器在输入时钟的下降沿采样
  3.创建两个T触发器使能信号TFF_EN0,TFF_EN1
    TFF_EN0在第1步中,计数值为1的时候置位
    TFF_EN1在第1步中,计数值为(N+1)/2时置位
  4.创建产生时钟逻辑,CLK_OUT = LOGIC0 ^ LOGIC1

5.2 设计实例

奇数分频器设计代码:

module odd_clk_div#(
        parameter integer DIV_NUM = 3
)(
       input  wire  CLK_IN,
       input  wire    nRST,
       output wire  TFF_EN0,
       output wire  TFF_EN1,
       output wire   LOGIC0,
       output wire   LOGIC1,
       output wire   [15:0] CLK_CNT,
       output wire CLK_OUT
    );
    
    reg [15:0] clk_cnt;//clock counter
    wire tff_en0,tff_en1;
    assign CLK_CNT = clk_cnt;
    assign tff_en0 = (clk_cnt == 'd0)?1'b1:1'b0;
    assign tff_en1 = (clk_cnt == (DIV_NUM+1)/2)?1'b1:1'b0;
    assign TFF_EN0 = tff_en0;
    assign TFF_EN1 = tff_en1;
    //counter
    always@(posedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_cnt <= 16'd0;
        end
        else
        begin
            if(clk_cnt != DIV_NUM - 1)
            begin
                clk_cnt <= clk_cnt + 16'd1;
            end 
            else clk_cnt <= 16'd0;
        end
    end
    
    //clock bulid logic
    reg clk_div0_lgic;//sample tff_en0 at clk posegde
    reg clk_div1_lgic;//sample tff_en1 at clk negedge
    assign CLK_OUT = clk_div0_lgic ^ clk_div1_lgic;
    assign LOGIC0 = clk_div0_lgic;
    assign LOGIC1 = clk_div1_lgic;
    //TFF 0
    always@(posedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_div0_lgic <= 1'b0;
        end
        else
        begin
            if(tff_en0)
                clk_div0_lgic <= ~clk_div0_lgic;
            else
                clk_div0_lgic <= clk_div0_lgic;
        end
    end
    //TFF 1
    always@(negedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_div1_lgic <= 1'b0;
        end
        else
        begin
             if(tff_en1)
                clk_div1_lgic <= ~clk_div1_lgic;
            else
                clk_div1_lgic <= clk_div1_lgic;
        end
    end

当DIV_NUM = 7时,仿真波形如下:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第10张图片上述设计综合:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第11张图片

5.3 另一种设计思路

  本质上来说,这种奇数倍分频产生了两个2N倍的偶数分频信号,只不过利用两个分频信号的相位差进行逻辑异或得到N分频的信号;
  因此也可以采用以下的设计思路:
  1.首先创建两个模2N的计数器
    第一个计数器在clk上升沿采样,初值为0
    第二个计数器在clk下降沿采样,初值为(DIV_NUM+1)/2 - 1
  2.根据两个计数器的值产生两个2N倍偶数分频信号
  3.将产生的偶数分频信号进行异或产生时钟

module odd_clk_div#(
        parameter integer DIV_NUM = 3
)(
       input  wire  CLK_IN,
       input  wire    nRST,
       output wire   LOGIC0,
       output wire   LOGIC1,
       output wire   [15:0] CLK_CNT0,
       output wire   [15:0] CLK_CNT1,
       output wire CLK_OUT
    );
    
    reg [15:0] clk_cnt0;//clock counter
    reg [15:0] clk_cnt1;//clock counter
    wire logic0,logic1;
    assign LOGIC0 = logic0;    
    assign LOGIC1 = logic1;    
    assign CLK_CNT0 = clk_cnt0;
    assign CLK_CNT1 = clk_cnt1;
    
    
    
    assign CLK_OUT = logic0 ^ logic1;
    assign logic0 = (clk_cnt0 < DIV_NUM ) ? 1'b1:1'b0;
    assign logic1 = (clk_cnt1 < DIV_NUM ) ? 1'b1:1'b0;
    //counter
    always@(posedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_cnt0 <= 16'd0;
        end
        else
        begin
            if(clk_cnt0 != 2*DIV_NUM - 1)
            begin
                clk_cnt0 <= clk_cnt0 + 16'd1;
            end 
            else clk_cnt0 <= 16'd0;
        end
    end
    always@(negedge CLK_IN)
    begin
        if(~nRST)
        begin
            clk_cnt1 <= (DIV_NUM+1)/2 - 1;
        end
        else
        begin
            if(clk_cnt1 != 2*DIV_NUM - 1)
            begin
                clk_cnt1 <= clk_cnt1 + 16'd1;
            end 
            else clk_cnt1 <= 16'd0;
        end
    end
   
endmodule

仿真:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第12张图片
设计综合:
基于verilog的时钟管理电路设计(奇数/偶数分频、门控时钟等)_第13张图片

5.4 总结

  奇数分频可通过产生两个相位不同的2N倍分频,异或产生


文献参考

1.《硬件架构的艺术-数字电路的设计方法与技术》

你可能感兴趣的:(基于Vivado的硬件设计,fpga开发,硬件工程,硬件架构)