大家好,我是数字小熊饼干,一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结,并通过汇总成文章的形式进行输出,相信无论你是在职的还是已经还准备入行,看过之后都会有有一些收获,如果看完后喜欢的话就请关注我吧~谢谢~
本篇文章我们来探讨一下低功耗设计的重要方法——门控时钟clock gating。由于时钟在不断的翻转会产生大量的功耗,例如:
-在时钟沿变化的组合逻辑所产生的功耗(由于触发器驱动这些组合逻辑)。
-由触发器产生的功耗,即使触发器的输入和内部状态没有发生变化,该功耗依然存在。
-设计中时钟树产生的功耗。在同步时钟驱动的电路中,为了减少时钟偏移,会生成大面积的时钟树,其上分布着大量的时钟缓冲器(buffer),时钟树会产生大量的功耗。
既然时钟的不断翻转引起了这么多的功耗,那么直接把时钟关掉就成为了降低芯片功耗的一个不错的主意~
一、组合逻辑的门控时钟电路
在思考如何关断时钟时,我们自然会想到可以由组合逻辑中的与门和或门组成门控时钟,如下图所示:
但是组合逻辑的缺点就是容易产生毛刺,如下图所示,如果使能EN未在时钟为高时,保持稳定,就会产生毛刺:
这种毛刺是我们需要避免的,因为其对后续受该时钟驱动的电路造成不可预料的影响,例如产生亚稳态等等。
二、基于锁存器的门控时钟电路
由于组合逻辑的易产生毛刺的缺点,我们需要依靠那些对时钟敏感的器件来关断时钟,例如我们可以使用低电平敏感的锁存器latch来锁存使能信号,使之在时钟有效沿(通常为上升沿)和非有效沿(通常为下降沿)之间保持不变,即可解决产生出现毛刺的问题。
上述电路使用verilog描述为:
module clk_gate
(
input wire clk_in,
input wire en ,
output wire clk_gated
);
reg en_latch;
always @(*) begin //生成latch
if (!clk_in) begin
en_latch = en;
end
end
assign clk_gated = en_latch & clk_in;
endmodule
在实际项目中,通常为了保证较高的生产缺陷覆盖率,还会在clock gating中加入scan信号(即scan信号和使能信号en在进入锁存器前进行“或”), 以保证在进行scan测试时,芯片中的所有触发器,无论使能信号是多少都能被时钟驱动,进而使得扫描链按照正常方式移动扫描数据。
因此,最终的clock gating电路如下所示:
三、latch的生成和避免
既然提到了latch,我们就对latch进行一下介绍,在verilog中使用组合逻辑的always块时,如果出现以下情况会生成latch:
-if结构不完整,没有覆盖全所有情况,即没有else且不带if的这条分支就会生成latch;
-case结构不完整,case 选项列表不全且没有加 default 关键字,或有多个赋值语句不完整时,也会产生 latch;
-在组合逻辑中,使用原信号来赋值其本身,或者判断条件中也有其本身,这种情况会产生组合逻辑回路(combinational loop)也会生成latch;
-always的敏感列表不完整,即不是使用always@(*)的这种方式,而是使用信号例如always@(a),那么当该触发的时候没有触发,那么相关寄存器还是会保存之前的输出结果,因而会生成锁存器。
而在我们平常写的代码中,通常是不允许出现latch的,因为latch的出现会使得静态时序分析STA无法正确分析时序,且会容易产生毛刺,增加后续电路出现风险的可能性。
所以为了避免生成latch,通常合理的做法是:
- if或case写完整,或者在进入if或case之前,先对信号进行赋值,例如:
always @( *) begin
e = a; //避免生成latch
case(a)
2'b00: e = a;
2'b01: e = b
2'b10: e = c;
default: e = d;
end
- 组合逻辑always块中的敏感列表使用*
- 不要将赋值信号放在赋值源头,或条件判断中
四、总结
以上就是时钟门控及latch的相关内容了,顺便一提,在我们的实际项目中,工艺库一般都会提供这种时钟门控模块,其中已经写好了时序约束,可以直接调用,不需要自己手动的搭建。不过身为一个合格的设计师对于这类模块的原理还是需要掌握的~
如果你喜欢这篇文章的话,请关注我的公众号-熊熊的ic车间,里面还有ic设计和ic验证的学习资料和书籍等着你呢~欢迎您的关注