热度 12| |||
clock tree上的动态功耗将会占整个芯片的数字部分的动态功耗的30~40%,所以clock gating技术是一种非常有效降低clock动态功耗的技术。
在实现的时候,大家都知道用clock gating来降低动态功耗,但是大部分的时候都是synthesis的工具来自动插入。不过工具插入clook gating是对代码的书写格式是有要求的,比如:
always@(posedge clock or negedge rst_n) if (~rst_n) q <= 10'b0; else if (en) q <= q + 1'b1;这种代码,工具如果把自动插入clock gating的选项打开,就会对10bit的q寄存器插入clock gating。clock gating的enable信号就是用的en信号(也就是 对q寄存器来说是局部信号)。
ODC(Observability Don't Care)技术是基于分析寄存器的输出来推导clock gating 的enable信号。比如通过分析寄存器的输出,发现后面的逻辑在某种条件下没有用前级的输出,这个时候可以用这个条件来做clock gating的enable信号。这个说起来比较抽象,下面看一个例子:
module top (in_I_bus, in_T_bus, in_S_bus, in_Q_bus, mux_sel_prev_cycle, clk, OUT) ; input [3:0] in_I_bus, in_T_bus, in_S_bus ; input [4:0] in_Q_bus ; input mux_sel_prev_cycle ; input clk ; output [4:0] OUT ; // datapath line reg [3:0] I_bus, T_bus, S_bus ; reg [4:0] Q_bus ; always @(posedge clk) begin I_bus <= in_I_bus ; T_bus <= in_T_bus ; S_bus <= in_S_bus ; Q_bus <= in_Q_bus ; end reg [4:0] R_bus ; reg [4:0] mult_out ; always @(*) begin R_bus = I_bus + T_bus ; mult_out = R_bus * S_bus ; end reg mux_sel ; always @(posedge clk) begin mux_sel <= mux_sel_prev_cycle ; end wire [4:0] OUT ; assign OUT = mux_sel ? mult_out : Q_bus ; endmodule转成schematic示意图如下:
如果直接综合,最后出来的netlist是不会有clock gating的。
但是从功能上来看,其实是可以用mux_sel_prev_cycle来做in_I_bus ,in_T_bus,in_S_bus的寄存器的clock gating 的enable信号,用~mux_sel_prev_cycle来做in_Q_bus的寄存器clock gating的enable信号。
Joules 工具就提供了分析ODC的功能,首先分析代码结构,找到候选的ODC 寄存器,然后读入激励文件(波形文件),基于clock cycle来识别无用的翻转,分析浪费的功耗。如果通过激励文件,发现没有任何无用的翻转,那说明这个候选的ODC寄存器就不是真正的ODC寄存器,无法通过插入clock gating来节省功耗。同时,joules还提供解决办法(产生clock gating 的enable信号,或者其他需要前期准备的逻辑电路)。
通过joules的ODC分析后得到的RTL如下:
module top (in_I_bus, in_T_bus, in_S_bus, in_Q_bus, mux_sel_prev_cycle, clk, OUT) ; input [3:0] in_I_bus, in_T_bus, in_S_bus ; input [4:0] in_Q_bus ; input mux_sel_prev_cycle ; input clk ; output [4:0] OUT ; // datapath line reg [0:3] I_bus, T_bus, S_bus ; reg [0:4] Q_bus ; always @(posedge clk) begin if (mux_sel_prev_cycle) begin // Added ODC enable flagged by Joules I_bus <= in_I_bus ; T_bus <= in_T_bus ; S_bus <= in_S_bus ; end if(~mux_sel_prev_cycle) // Added ODC enable flagged by Joules Q_bus <= in_Q_bus ; end reg [4:0] R_bus ; reg [4:0] mult_out ; always @(*) begin R_bus = I_bus + T_bus ; mult_out = R_bus * S_bus ; end // enable line reg mux_sel ; always @(posedge clk) begin mux_sel <= mux_sel_prev_cycle ; end // select logic ... unobservability point wire [4:0] OUT ; assign OUT = mux_sel ? mult_out : Q_bus ; endmoduleschematic的示意图如下:
其中红色部分就是joules修改的。