众所周知,后仿真主要是仿真timing问题,所谓timing问题即是当出现timing违例时,DFF的Q端出现不定态,一旦该不定态级联到后续组合逻辑中,将有可能导致系统瘫痪。因此,如果后仿真出现了timing违例,一定要引起足够的重视,分析具体原因是什么?
通常情况下,有一些原因是由于同步器的第一级输出不定态导致的,正常来说,对于异步时钟域信号,我们设计中应该不会直接使用第一级同步器输出,因此第一次同步器我们也不需要进行timing check。除此之外,其他的DFF都需要进行timing check。
下面是几种常见的timing check:
$setup ( negedge D , posedge CP, 4, notifier ); //触发器的setup检查
$hold ( posedge CP, negedge CD, 3, notifier ); //触发器的hold检查
$setuphold ( posedge CP, negedge D , 4, 3, notifier ); //setup hold检查
$recovery ( negedge CD, posedge CP, 2, notifier ); //时钟复位的timing检查
$removal ( posedge CD, posedge CP, 1, notifier ); //时钟复位的timing检查
$recrem ( negedge CD, posedge CP, 2, 1, notifier ); //时钟复位的timing检查
$width ( posedge CP, 5, 0, notifier ); //最小脉宽的检查
$period ( posedge CP, 10, notifier ); //周期的检查
notifier是一个reg型的变量,它位于DFF的 model内,并且不会被初始化,因此它的初始default值是x。

对于timing检查项:任意一条timing check语句检测到timing violation发生时,对应的timing check语句就会把notifier的值做一次toggle。
第1次timing violation时,notifier的值会从x变为0或1。后续每发生一次timing violation,notifier的值也会被做一次toggle。如果旧值为0,则新值为1。如果旧值为1,则新值为0。但不会再回到x。
| notifier在volition之前 | notifier在volition之后 |
| x | 要么0,要么1,随机的 |
| 0 | 1 |
| 1 | 0 |
| z | z |
而notifier的toggle,会导致寄存器的Q端变为x,如下图底部的红箭头指向的那个星号。
DFF的源语如下:
primitive smic_dff(q, d, cp, cdn, sdn, notifier);
output q;
input d, cp, cdn, sdn, notifier;
reg q;
table
? ? ? ? * : ? : x; //一旦notifier发生变化,寄存器输出必为x-state
......
endtable
endprimitive
在不想check timing的地方如何避免x的产生
第1种是把对应的寄存器内的notifier force为x。由于notifier被force为x,它不再toggle,不会影响primitive语句,寄存器的Q端就不再会出现x了。
force xxx.async_reg_0_.NOTIFIER = 1'bx;
以下两种方法,来自网上,我这边并未使用过,仅供参考:
第2种做法是使用vcs的option:+optconfigfile+no_timing_check.cfg,
并在no_timing_check.cfg文件中增加下面语句
instance {tb.a} {noTiming};
第3种做法则是使用vcs的ucli的接口输入进去一个config文件,文件内容如下:
tcheck {tb.a} SETUPHOLD -msg -disable
我个人认为第3种是最好的做法,因为前2种会把所有的timing check都停掉,
而CDC时其实只需要不检查setup和hold就够了,其他的width/period/recovery/removal
之类还是需要检查的(当然了,会有别的寄存器那里继续检查period/width)。
对于异步复位同步释放逻辑的第1级,只有recovery和removal不需要检查,
使用第3种方法也能更加精确地指定不检查这2种timing类型,而不是一刀切地不检查所有timing类型。
513

被折叠的 条评论
为什么被折叠?



