怎么在fsdb波形中构造一个0ps的毛刺

写在前面:

1、按照大家通常的思维,其实题目应该取“怎么分析一个0ps的毛刺”,即从结果分析原因。但是0ps的毛刺产生的原因实在太多了,我们不如反其道行之,自己尝试去构造一个0ps的毛刺,以一种正向的思维去理解,当你能够自己构造出一个0ps的毛刺时,基本上也能够分析其它0ps毛刺产生的原因了。

2、看本文之前需要先去了解verilog/systemverilog的调度机制,可以参考我以前写的一篇文章SystemVerilog调度机制与一些现象的思考

3、我发现大家都喜欢白嫖啊,看完如果觉得文章对自己有帮助,一定要一键三连啊!!!

4、郫县犀浦这边有家王宝器椒麻鱼味道很不错,附近的同学可以尝试下。

正文:

Verdi相关知识补充

1、vcs编译完成的simv,在运行时是通过调用Verdi的相关函数来达到dump波形的效果的。如果想控制dump的过程,可以将相关参数附加在simv后面。比如:

+fsdb+glitch=num    控制glitch(毛刺)的dump,num取值0~254,0代表将所有的毛刺dump下来。

+fsdb+sequential     记录同一时刻下,信号变化的先后顺序。

+fsdb+region           Enable region mode dumping。也就是记录信号的Event Regions(Active、Inactive、NBA...)信息。

2、为什么有些人使用的参数是+fsdb+delta,而不是+fsdb+glitch=num?

3、Verdi里面glich的调试方法

首先鼠标左键选择需要展开的时间点,然后按下图所示的选项展开这个时间点,可以看到在这个时间点上,信号变化的先后顺序。

Expand Delta

如果你还关注信号的Region信息,那么在此基础上点击Region Mode,就可以看到信号是在哪个区域发生变化的。

Expand Delta (Region Mode)

第一次尝试构造,直接连续两次赋值

dut.v

module dut();

logic a = 0;
logic b = 0;

initial begin
    #10;
    a = 1; b = 1;
    a = 0;
    #10;
end

endmodule

Expand Delta

写完代码还没跑仿真之前,我已经凭直觉知道这样肯定是失败的。果不其然,Verdi里面a的取值恒为0。可以看到,在10ns这个时间点上,a的取值是没有发生变化的。也就是说a的变化并没有被记录下来。联想到以前看到的文章说“begin...end之间的语句一定是按照先后顺序执行的”,难道因为这个原因,a的变化被仿真器优化掉了?所以我考虑换一种方式来生成0ps脉冲。

第二次尝试构造,利用竞争和冒险来产生毛刺

先复习下数字电路,当输入信号经过不同路径到达输出时,电路就会存在竞争,有发生冒险的可能,此时就会产生毛刺。

一个比较典型的竞争冒险电路如下,我尝试参考这种方式去生成0ps的毛刺。

dut.v

module dut();

logic a = 0;
logic a_inv;
logic b;

initial begin
    #10 a = 1;
    #10 a = 0;
end

assign a_inv = ~a;
assign b = a & a_inv;

endmodule

Expand Delta

Expand Delta (Region Mode)

然鹅,输出b还是一条水平的直线,到底是哪里不对呢?

难道是由于调度的先后顺序不对?先调度了assign a_inv = ~a;后调度assign b = a & a_inv;导致的?为此我也展开了部分许多实验,排除了这个可能,这里就不再展开了。

为什么?到底是为什么?难道出不出毛刺看人品?正当我苦思冥想之时,突然灵光一闪,我知道为什么了,是的,我知道为什么了。

因为vcs波形的dump本质上是通过PLI调用Verdi的相关函数来实现的,如果信号先发生变化,再调用dump函数,那么自然这些变化信息不能被及时的记录下来。如下图所示,在我们的例子中,信号的变化全部集中在Active Region,当Active Region执行完成后,再去调用PLI,这些变化信息自然被丢弃了。那么为了构建一个0ps的脉冲,我们就需要在NBA区域引入信号的变化,从而保证信号的变化完全地被PLI记录下来。(其实该思路存在误区)

第三次尝试构造,利用Active-NBA区域后的PLI来记录毛刺信息

dut.v

module dut();

logic a = 0;
logic a_inv;
logic b;

initial begin
    #10 a = 1;
    #10 a = 0;
end

//assign a_inv = ~a;

always @(*) begin
    a_inv <= ~a;
end

assign b = a & a_inv;

endmodule

Expand Delta

Expand Delta (Region Mode)

果不其然,这样的确生成了一个0ps的毛刺。

可以看到,a的取值在Active区域发生变化后,会先让b的取值变为1;a_inv的取值在NBA区域发生变化后,会让b的取值变为0。二者的效果叠加,最终在b上输出的就是一个0ps的脉冲。

第四次尝试构造,利用双initial的生成glitch(2020/04/16添加,修正部分观点)

这里先感谢Holden_Liu同学在留言中指出了文中的一些问题。

这里贴出他的文章链接:

dump glitch 毛刺分析 及 异步复位同步释放

在前文中,我们可以通过Active-NBA区域的交互构造出glitch,导致我一度认为glitch必须由不同Region交互来生成。在Holden_Liu同学的文中,展示了使用双initial来生成glitch的例子。这里不妨借鉴一下。

dut.v

module dut();

logic a;

initial begin
        a = 0;
    #10 a = 1;
end

initial begin
    #10 a = 0;
    #10 a = 1;
end

endmodule

Expand Delta

Expand Delta (Region Mode)

可以看到,其实单在Active区域内的变化就可以生成glitch了,因此修正观点如下。

1、vcs仿真器应该是以调度单元process来存储信号变化的,process内部每个Region的变化不对外呈现。

2、verdi的PLI只提供了Dump波形的函数接口,具体要Dump什么样的数据,并存储到波形中,还是由vcs仿真器自己决定的。

再次感谢指出错误!

写在最后

1、在项目过程中,很多0ps的脉冲也可以通过以上介绍的方法来进行分析。

2、遇到0ps的毛刺,千万不要觉得这个不重要,在前仿中出现的0ps毛刺必须要全部解释清楚。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值