那些年,我们一起踩过的后仿真的坑

19 篇文章 25 订阅
9 篇文章 18 订阅

转载自芯司机微信公众号
一、简介
  后仿真,是对经过综合/布局布线后的门级网表进行仿真,与前仿真对rtl代码进行仿真,找出功能上的缺陷相比,后仿真主要检查时序上的问题。
  相比较理想状况下的rtl仿真(功能仿真、前仿真),后仿消耗时间更多,在可读性差的cell里穿梭行走,debug的难度大大增强了,而一般我们在做后仿的时候,往往也意味着离tapeout的时间很急迫了。
  那么,时间紧,任务重的情况下,后仿经验的积累就尤为重要了,除了打怪升级多练手外,我们还可以从彼此的踩过的坑中快速攥经验值。
二、没有复位的寄存器
  一般情况下,设计里面的寄存器都要有复位端。但是,别忘了,后仿不仅仅包括设计的网表,还有各种model,比如analog model,这些model可能因为种种原因,存在没有初值没有复位的寄存器信号。这些寄存器在后仿时候往往给我们造成很大的麻烦。

reg rg_a, rg_b;
always @(posedge clk) begin
  rg_b <= rg_a;
end

解决方案:
  我们在testbench中通过force-release的方式对寄存器赋初值,因为变量是reg类型的,所以只要赋初值后,在没有其他条件触发时,会一直保持force进去的值。

initial begin
	force TOP.rg_b = 0;
	#0; // any delay time
	release TOP.rg_b;
end

三、信号取反
  当我们用网表进行后仿时,在testbench中驱动或者监测的DUT中的信号很可能是一个取反的信号。特别是端口上的信号,名字都没变,明明叫rstb的那货,行为上却像个rst。并不是设计人员粗心大意,而是DC和ICC这样的工具捣的鬼。
  特别可恨地是,一个多比特数据信号,某个比特被悄悄取了反,稍不留神想和前仿对比调试时,连数据位置都定位不准~往往也是让验证工程师哑巴吃黄连了。

i_dut_if.mon_data = Top.hwdata;

这里的Top层的hwdata信号并不是你以为的hwdata,事实上,hwdata的第0位被悄悄插了个反相器。所以,正确的做法是:

i_dut_if.mon_data = {Top.hwdata[31:1], ~Top.hwdata[0]};

四、没有驱动的Pad口的高阻信号传递到设计内部
  一般设计的顶层会有不少三态门的io口,当我们在bench中例化设计时,一定要注意这些三态门,除了只能使用wire类型的信号进行连接外,还要考虑没有驱动情况下的上拉/下拉。
  如果忽略了上拉/下拉,在功能仿真时一般不会遇到问题,但是后仿时’z的状态传入设计,便悄悄埋下个雷,某个门的输出就会变成x,并最终导致仿真停下来。
  解决方法呢,很简单,在bench中连接设计时,将三态门连接的信号加个上拉/下拉就好了。

wire scl;
dut i_dut(.scl(scl));
pullup(scl);

如果其他地方已经占用了pullup怎么办呢?没关系,pullup还有不同强度,选个强度弱的,这样即便其他地方也会有上拉/下拉,也不影响了。
  上面的上拉语句加上强度等级,即:pullup(weak1) p0 (scl)。
五、两级同步器
  不知道有多少次debug一根根变红的信号线,一遍遍艰难地追根溯源,最后,这个罪魁祸首就是看着无辜的两级同步器的第一级输出。
  两级同步器的引入不就是为了解决跨时钟域信号的亚稳态问题嘛?那么同步器的第一级输出必然是充斥着时序违例的原罪,但是对于时序检查的约束而言,它并不知道这是跨时钟的两级同步器,更不知道这一级输出的时序违例并不要紧,因为这个输出会再经过一个寄存器才会被使用。
  芯片后仿一般都是系统级验证,一个SOC系统上跨时钟域的时钟还真是不少,用到的同步器没个千啊,也有百啊。逢山开路,遇水搭桥,除了这样硬着头皮追源头,还有更好的办法么?
  要是说有什么好办法,那必然是,在仿真之前,我们能把这些符合条件的Q0提前挑出来。如何能从网表茫茫寄存器中把这些同步器第一级输出给甄别出来呢?这还真不是验证工程师自己能决定的。一方面取决于代码风格,试想,如果同步器都调用共同的lib cell,问题是不是会变得简单起来呢?
  如下所示,当所有同步模块都使用定义好的同步单元syncff。

module syncff(
	input clk,
	input rstb,
	input d,
	output reg q
);
	reg d_meta;
	always @(posedge clk or negedge rstb)begin
		if(!rstb) d_meta <= 1'b0;
		else d_meta <=d;
	end
	always @(posedge clk or negedge rstb)begin
		if(!rstb) q <= 1'b0;
		else q <=d_meta;
	end
endmodule
syncff i_syncff(
	.clk(clk),
	.rstb(rstb),
	.d(d),
	.q(q)
);

这样我们就很容易找到第一级同步器的输出d_meta。再统一加入到waive list中。这样就可以提前避免后仿中不要的x传递。

instance{top.xxx.i_syncff.d_meta}{noTiming};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值