Verilog RTL 级低功耗设计(下)

1. 门控时钟

通常情况下,时钟树由大量的缓冲器和反相器组成。而时钟信号为设计中翻转率最高的信号,时钟树的功耗可高达整个设计功耗 30%。加入门控时钟(clock gating)电路,可减少时钟树的开关行为,能节省开关功耗。同时,时钟引脚开关行为的减少,寄存器的内部功耗也会减少。所以,采用门控时钟,可以有效地降低功耗。

实现原理

通俗来讲,当模块或触发器不工作时,将时钟关闭而不影响正常功能的逻辑,可以称之为门控时钟逻辑。此时时钟并不是一直存在的,所以可以形象的称之为门控时钟。

实现门控时钟的方法主要有以下 3 种。

1、使用与逻辑

最简单的方法,是直接将时钟使能控制(门控)信号与时钟做"与"逻辑。

例如对一块 ram 的时钟进行该操作,代码如下:

// use and-logic
module  clkgate_basic
    (
        input           clk ,
        input           clken ,
        input           rstn ,
        input           wr_en ,
        input [3:0]     addr ,
        input [7:0]     data ,
        output [7:0]    q
     );

   //clk gate
  wire                 clk_gate = clk & clken ;
   ram #(4, 8)
      u1_ram16x8
        (
         .CLK   (clk_gate),
         .A     (addr),
         .D     (data),
         .EN    (clken),
         .WR    (wr_en),
         .Q     (q));

endmodule

ram 模型如下:

module  ram
    #(  parameter       AW = 2 ,
        parameter       DW = 3 )
    (
        input                   CLK ,
        input [AW-1:0]          A ,
        input [DW-1:0]          D ,
        input                   EN ,
        input                   WR ,    //1 for write and 0 for read
        output reg [DW-1:0]     Q
     );

   parameter            MASK = 3 ;

   reg [DW-1:0]         mem [0:(1<<AW)-1] ;
   always @(posedge CLK) begin
      if (EN && WR) begin
         mem[A]  <= D ;
      end
      else if (EN && !WR) begin
         Q       <= mem[A] ;
      end
   end

endmodule

testbench 代码如下:

`timescale 1ns/1ns
module test ;
   //signals declaration
   reg          rstn ;
   reg          clk ;
   reg          clken ;
   reg          wr_en ;
   reg [3:0]    addr ;
   reg [7:0]    data ;
   wire [7:0]   q ;

   initial begin
      rstn      = 0 ;
      #7 rstn   = 0 ;
   end

   always begin
      #50 clk = 0 ;
      #50 clk = 1 ;
   end

   //data logic
   initial begin
      clken     = 0 ;
      wr_en     = 0 ;
      addr      = 4'h3 ;
      data      = 8'h31 ;
      # 53 ;
      //(1) normal write and read
      clken     = 1 ;
      wr_en     = 1 ;
      repeat(9) begin
         @(negedge clk) ;
         data   = data + 1 ;
         addr   = addr + 1 ;
      end
      @(negedge clk) ;
      clken     = 0 ;
      wr_en     = 0 ;

      //read
      #211;
      addr      = 4'h3 ;
      clken     = 1 ;
      repeat(9) begin
         @(negedge clk) ;
         addr   = addr + 1 ;
      end
      @(negedge clk) ;
      //end
      clken     = 0 ;
   end // initial begin

   clkgate_basic u_ram_clkgate
    (
        .clk    (clk),
        .clken  (clken),
        .rstn   (rstn),
        .wr_en  (wr_en),
        .addr   (addr),
        .data   (data),
        .q      (q)
     );

   //simulation finish
   always begin
      #100;
      if ($time >= 10000)  begin
         #1 ;
         $finish ;
      end
   end

endmodule

抓取 ram 端口信号,测试结果如下。

如图可知在读、写操作中间,ram 时钟有一段一直为 0 的时刻。时钟在 ram 没有工作的时候不会翻转,实际中也会减少很多的功耗。

该方法缺点也非常明显。由于时序或抖动的原因,时钟使能信号与时钟进行"与"逻辑后,容易产生毛刺,会对数字电路产生严重影响。

在 testbench 中对时钟使能信号进行非理想的模拟,加入如下仿真代码:

      //(2) jitter at the end of read
      #985;
      addr      = 4'h3 ;
      clken     = 1 ;
      repeat(9) begin
         @(negedge clk) ;
         addr   = addr + 1 ;
      end
      @(negedge clk) ;
      clken     = 0 ;
      #20 clken = 1 ;
      #21 clken = 0 ;
      #31 clken = 1 ;
      #13 clken = 0 ;

读 ram 的仿真结果如下。

由图可知,因为信号 clken 的异步或抖动问题,导致输入到 ram 的时钟已经出现了毛刺。地址为 0x3 的数据被遗漏(和使能信号时序有关),地址为 0xC 的数据读了 2 次。显然该门控时钟的逻辑设计非常的危险。

为解决此类问题,需要使用 latch 结构来消除毛刺。

2、使用 latch

在 《Verilog 教程》章节《6.5 Verilog 避免 Latch》中讲到,数字设计中应当避免 Latch 的产生,但 clock gating 是个例外。所以在进行时序分析时,不用关心 clock gating 部分产生的 Latch。

使用 latch 消除门控时钟毛刺的电路图如下所示。

在时钟下降沿对时钟使能信号进行锁存,并保持一个时钟周期内不变。锁存后的信号再与时钟进行"与"逻辑操作,可将门控时钟中的毛刺消除掉。

将仿真例程钟直接"与"操作的门控时钟逻辑部分,改写为使用 latch 逻辑,修改如下:

   //(2) using latch
   reg                  en_latch ;
   always @(*) begin
      if (!clk) begin
         en_latch       = clken ;
      end
   end
   wire clk_gate = clk & en_latch ;

仿真结果如下。

虽然地址为 0x3 的数据仍然被遗漏(和使能信号时序有关),但 ram 的时钟已经是正常时钟,不再出现毛刺(标黄的 CLK 信号)。

3、使用标准单元库

虽然使用 latch 可以解决门控时钟毛刺的出现,但是时序也需要严格的约束。

FPGA 或 IC 设计时,综合库中往往会有集成门控逻辑单元。此类门控逻辑单元经过了大量的更新迭代和验证,使用起来更加的方便、安全。

因此一般情况下,门控时钟的设计也都会直接调用专用的集成门控逻辑单元。调用方式和基本的与门、缓冲器等基本单元类似,直接例化即可。

2. 使用方式

合理的使用门控时钟逻辑,对电路时钟进行控制,也会有效的减少功耗。

1、手动 gating

增加时钟使能信号,人为的控制模块工作时钟的有无。

模块工作时,将使能信号有效,时钟打开;模块空闲时,将使能信号无效,时钟关闭,节省功耗。

上一节的仿真设计,就可以看做是手动 gating 的例子。ram 读写时,使能信号为高,ram 时钟打开,ram 开始工作;使能信号为低时,ram 不工作,此时无输入时钟。

2、自动 gating

模块在工作时,可以自动检测自己的工作状态,并输出一个 busy(忙碌) 信号。外部可以通过该指示信号,对模块内部的部分逻辑进行时钟门控,来减少时钟的翻转,达到自动 gating 的控制。

与手动 gating 不同的是,这些模块在工作时,会有短暂的空闲状态。自动 gating 就是要在这短暂的空闲状态时间内关闭掉无用的时钟,而不是像手动 gating 直接关闭掉整个模块的时钟,否则该模块就不能再正常工作。

例如 uart 在完成一次传输数据时会有一段空闲的状态,此时可将一些 fifo 逻辑、波特率产生逻辑等模块的时钟自动关闭。

例如在包含 cpu 的设计中,可加入检测 bus 总线空闲状态的逻辑,自动控制开关 bus 总线的时钟,以此降低功耗。

限于篇幅,这里先不再举例仿真。

3、自动插入 gating

当 RTL 设计完成之后进行逻辑综合时,编译器也会对代码的逻辑进行自动优化,这就包括将一些触发器的时钟端进行 gating。例如一个带使能端的同步 D 触发器的 RTL 描述如下:

   //(2) Flip-Flop with enable port
   always @(posedge CLK) begin
      if (EN) begin
         Q       = D ;
      end
   end

其 RTL 前级仿真如下图所示:

综合后的仿真波形往往会如下图所示:

对比可知,综合后已经没有了 EN 信号,时钟(CP 端)经过 clock gating 后也不是一直存在。既保证了逻辑的正确性,又减少了时钟翻转,降低了功耗。

下一章:Verilog 显示任务

Verilog 中主要用以下 4 种系统任务来显示(打印)调试信息:$display, $write, $strobe, $monitor。 1. $display$display 使用方法和 C 语言中 ...