Verilog RTL 级低功耗设计


下表显示了在数字设计的各个层次上可减少功耗的百分比。RTL 级之后,功耗的减少量已经非常有限。
在这里插入图片描述
作为一个编写 Verilog 的伪码农,系统级减少功耗的工作也可参与一些,但重点应该放在 RTL 级来减少功耗。


《Verilog 教程》章节中 《6.7 Verilog 流水线》一节。


并行和流水线这两种方法都是用资源换速度。在一定的场合下灵活的使用这两种方法,都可以降低功耗。


三、资源共享

当设计中一些相同的运算逻辑在多处使用时,就可以使用资源共享的方法避免多个运算逻辑的重复出现,减少资源的消耗。

例如一个比较逻辑,没有使用资源共享的代码描述如下:

 always @(*) begin
        case (mode) :
            3'b000:         result  = 1'b1 ;
            3'b001:         result  = 1'b0 ;
            3'b010:         result  = value1 == value2 ;
            3'b011:         result  = value1 != value2 ;
            3'b100:         result  = value1 > value2 ;
            3'b101:         result  = value1 < value2 ;
            3'b110:         result  = value1 >= value2 ;
            3'b111:         result  = value1 <= value2 ;
        endcase
    end
对上述代码进行优化,描述如下:
    wire equal_con       = value1 == value2 ;
    wire great_con       = value1 > value2 ;
    always @(*) begin
        case (mode) :
            3'b000:         result  = 1'b1 ;
            3'b001:         result  = 1'b0 ;
            3'b010:         result  = equal_con ;
            3'b011:         result  = equal_con ;
            3'b100:         result  = great_con ;
            3'b101:         result  = !great_con && !equal_con ;
            3'b110:         result  = great_con && equal_con ;
            3'b111:         result  = !great_con ;
        endcase
    end

第一种方法综合实现时,如果编译器优化做的不好,可能需要 6 个比较器。第二种资源共享的方法只需要 2 个比较器即可完成相同的逻辑功能,因此在一定程度会减少功耗。

四、状态编码

对于一些变化频繁的信号,翻转率相对较高,功耗相对较大。可以利用状态编码的方式来降低开关活动,减少功耗。

例如高速计数器工作时,使用格雷码代替二进制编码时,每一时刻只有 1bit 的数据翻转,翻转率降低,功耗随之降低。

例如进行状态机设计时,状态机切换前后的状态编码如果只有 1bit 的差异,也会减少翻转率。

五、操作数隔离

操作数隔离原理:如果在某一段时间内,数据通路的输出是无用的,将输入置成固定值,数据通路部分没有翻转,功耗就会降低。

一个乘法器电路图如下所示。

当 sel0 = 0 或 sel1 = 1 时,乘法器 Multiplier 的输出结果并不能通过两个 Mux 到达寄存器的输入端。即寄存器并不能保存当前乘法器的结果,此次乘法运算是没有必要的。在此种条件下,采用操作数隔离,使乘法器不工作保持静态,也可以节省功耗。

对上述电路进行一个优化,如下图所示。

操作数隔离之后,当 sel0 = 0 或 sel1 = 1 时,乘法器输入端始终为 0,没有信号翻转,乘法器没有进行额外的无效工作,所以功耗会降低。

一般来说,操作数隔离的操作发生在代码综合的时候。这个过程往往是人为可设置、编译器可自动识别的。当然,良好的代码风格,在编写 RTL 电路时就考虑周全,更加有助于实现操作数隔离,从而降低功耗。

乘法器没有使用操作数隔离时,Verilog 代码描述如下:

//no isolation
module  oper_isolation1
    (
     input                clk ,           //100MHz
     input [1:0]          sel ,
     input [3:0]          din1 ,          //data in
     input [3:0]          din2 ,          //data in
     output reg [7:0]     dout
     );

    reg [7:0]       res ;
    always @(*) begin
        res       = din1 * din2 ;
    end

    always @(posedge clk) begin
        if (sel == 2'b01) begin
            dout   <= res ;
        end
    end
endmodule

乘法器使用操作数隔离时,Verilog 代码描述如下:

//using isolation
module  oper_isolation2
    (
    input                clk ,           //100MHz
    input [1:0]          sel ,
    input [3:0]          din1 ,          //data in
    input [3:0]          din2 ,          //data in
    output reg [7:0]     dout
    );

    wire [3:0]           mul1 = sel == 2'b01 ? din1 : 0 ;
    wire [3:0]           mul2 = sel == 2'b01 ? din2 : 0 ;
    reg [7:0]            res ;
    always @(*) begin
        res       = mul1 * mul2 ;
    end

    always @(posedge clk) begin
        if (sel == 2'b01) begin
            dout   <= res ;
        end
    end
endmodule

相关