[sv] region & timeslot

本文探讨了SystemVerilog中的事件调度机制、EventRegions,以及如何应对并行仿真中的Nondeterminism问题。作者结合IEEE标准和实践案例,解析了关键编码指南,包括非阻塞赋值、timescale对仿真时间的影响,以及编程块在代码组织中的作用。

文章内容主要来自于以下文档,然后对自己平时遇到的一些现象作出了思考。

1、IEEE systemverilog.std.1800-2012

2、SystemVerilog Event Regions & Race Avoidance & Guidelines

===================================悲伤的分割线===================================

零、前言
我们设计的硬件、仿真环境抽象意义上是可以并行运行的。但是在实际仿真时,不过是运行在cpu上的串行执行的程序而已(先不讨论多核)。systemverilog专门为这种并行到串行的转换定义了调度机制。但IEEE在制定规范时,并未规定一部分并行的事件执行的先后顺序,这点会引入不确定性(Nondeterminism),这种不确定性往往会体现在不同厂家的仿真器上(因为不同的厂家采用的调度算法是不一样的),最严重的后果就是在不同仿真器上看到的最终结果是不一样的。所以作为一名合格的工程师,应该对sv仿真器的调度机制、确定性与不确定性有基础的了解。

一、event与time slot的介绍
systemverilog是为离散事件执行模型(discrete event execution)所定义的一种语言。怎么理解呢?离散指的是仿真时间(simulation time)上的离散性,仿真基于时间片(time slot)进行,只对有效的时刻点进行仿真。事件执行模型指的是仿真基于事件进行建模和整体的调度。

下面先介绍几个概念:

进程(Processes)是sv中并发调度的单元,比如:原语(Primitives)、initial过程块、always过程块、连续赋值(continuous assign)、异步任务(asynchronous tasks)、过程赋值(procedural assignment)等。进程是可以被执行的,有相应的状态标志(state,比如挂起)。进程会响应输入的变化并产生对应的输出。sv的描述的对象也正是这些进程。

更新事件(update event):仿真中,net或者variable上每次的变化被认为是一次更新事件。

求值事件(evaluation event):进程对更新事件敏感!当一个更新事件被执行时,所有对该更新事件敏感的进程都会被求值,但是顺序是任意的。进程的求值本身也被认为是一种事件,即求值事件(evaluation event)。更新事件和求值事件的相互交替执行,推动了仿真时间的前移。

时间片(time slot):这个真的没啥好解释的,知道仿真是基于离散的时刻点来进行的就可以了。只有在每个时间片上的仿真活动全部完成,仿真器才会进行下一个时间片,也就是说仿真时间是不可逆的。在早期的IEEE描述里面,time slot也叫做timestep,只不过现在不这么叫了。每个时间片都会被划分成很多个区域,下面会详细介绍。划分的目的是为了保证仿真执行的正确性和清晰性。

二、systemverilog中的Events Regions
再看sv的Event Regions之前,我们先看下verilog-2001里面定义的Event Regions。

嗯,看上去还不是很复杂。总共也就定义了4个regions(Active、Inactive、NBA、Postponed),而且一般对于我们而言,Inactive域是不会用到的(后面会解释)。

Active Region:

阻塞赋值。
计算非阻塞赋值的右侧表达式(RHS即Right-Hand-Side)。并且把相应的更新事件调度至NBA Region(NBA即nonblocking assignment,非阻塞赋值)。
连续赋值。
调用$display系统函数。
primitive计算。
Inactive Region:

#0延迟下的阻塞赋值。
NBA Region:

更新非阻塞赋值的左侧表达式。
Postponed Region:

调用$monitor和$strobe系统函数。
这里有两个有趣的东西:

1、非阻塞赋值其实是分成了两个步骤,先计算RHS,再更新LHS,中间会去完成其它事件的调度和计算。而阻塞赋值两步同时执行,不存在中间插入其它事件的情况。

2、有一些工程师喜欢用#0延迟去消除对同一变量赋值所引起的竞争,但是其实按照编码规范来,你就不应该在多个always对同一个变量进行阻塞赋值,所以理论上就不应该用到#0的阻塞赋值,所以也就用不到Inavtive Region了。

我们再来看看systemverilog-2005里面定义的Event Regions。

我第一次看到内心其实也是崩溃的,卧槽,数了下,总共有17个Event Regions。但是,如果把8个PLI(Programming Language Interface,用来调用其它语言的函数的接口,比如C/C++)的Event Regions剔除,看上去也还好。

Active Region、Inactive Region、NBA Region统称为Active Region set,这是专门为RTL代码执行所设立的区域集合(set),实际上就是上面介绍的verilog代码的区域,只不过在sv中需要限定一下事件是在module中定义的,而不是program中定义的(verilog不存在program)。在sv中,相对于为RTL代码设立的区域,还有专门为验证平台所设计的区域集合,Reactive Region set。包含了Reactive Region、Re-Inactive Region、Re-NBA Region。Observed Region则是专门为断言所设计的区域。

Preponed Region:

采样数据,为断言做准备。
Observed Region:

使用Preponed Region采样到的值来计算断言。
Reactive Region:

所有定义在program内的阻塞赋值。
执行断言pass/fail代码?(这个有点疑问)
所有定义在program内的非阻塞赋值RHS的计算,并将相应的更新事件调度至Re-NBA Region。
所有program内的连续赋值。
执行系统函数$exit及隐式的$exit命令。
其实仔细看下,和Active Region内执行事件是很类似的,只不过加了program的限定。

Re-Inactive Region:

program内#0延迟的进程。
虽然Inactive Region不推荐使用,但是Re-Inactive Region还是有一些独特的价值的,比如开一些后台fork时,你希望新开的子进程优先于父进程执行。

program test;
    initial begin
        fork
            process1;
            process2;
            process3;
        join_none
        #0;
        // parent process continues
    end
endprogram
Re-NBA Region:

执行Reactive Region调度过来的LHS更新事件。
Postponed Region:

调用$monitor和$strobe系统函数。
收集利用strobe采样的功能覆盖率。
比较一下,systemverilog的Postponed Region比verilog的Postponed Region多了功能覆盖率的收集功能。

三、编码Guideline的一些解释


Guideline #1:时序逻辑使用非阻塞赋值。这样才可以保证时序逻辑的代码在NBA Region执行,sv才能正确地建模。
Guideline #3:用always块写组合逻辑使用阻塞赋值。这样可以保证代码是在Active Region执行的,仿真时行为是组合逻辑的行为。
Guideline #6:不要在多个always块中对同一个变量赋值。显然,这样做会引起冲突,导致最终结果的不确定性。
Guideline #8:在过程赋值时不要使用#0的delay。这条在上面已经解释过了。
Guideline #7:使用$strobe函数观察非阻塞赋值的结果。参考前面函数调用的位置就知道为什么了,$display函数观察到的不是我们想要的结果。但是这里我有一个疑问,假如always内非阻塞赋值有`U_DLY,观察到的结果又是怎么样的?
四、关于#1step
#1step是systemverilog引入的一种新的能力,主要为了解决采样的问题。step时间单位其实就是我们定义的最小的时间精度,换句话说,这也是仿真器在时间上进行调度的最小单位,在#1step的delay时间内,是不存在事件的。

IEEE定义了#1step延迟会在当前time slot的Preponed Region进行采样,但这样实际上的效果和在上一个time slot的Postponed Region采样是一样的(有可能两个time slot之间差了无数个#1step)。所以个人猜测,很多EDA的厂家会对这里进行优化,但最终呈现的效果是在当前time slot的Preponed Region采样的就行。

在时钟块(clocking block)里面默认的input skew就是#1step,而output skew是0。

五、平时遇到的一些问题的思考
Q1:interface中应该怎么去定义`SETUP和`HOLD时间比较好?

A1:

可以参考我的另一篇文章:systemverilog中interface时钟块的时序控制
而且Guildline也明确建议我们在clocking block里面使用#1step的input skew。
 

Q2:整个仿真所消耗的CPU时间和定义的`timescale有没有关系?

A2:个人观点:如果改变`timescale能够减少我们的time slot数量或者总的事件量,那么对仿真时间就是有收益的。

Q3:为什么设计写代码时不建议采用always@(*)的方式赋常值,而是建议使用assign的方式给常值?always@(*)赋常值在仿真时的行为是什么样的?

A3:参考下图,sv标准里面写了,连续赋值语句会在0时刻进行触发,以便传递常值;而always的阻塞赋值没有这个效果。

Q4:ucli中,按下ctrl-c后程序是停在了哪里?

A4:没有找到明显的答案,这里只是一些猜测。ucli交互时我们需要看到的是一个明确的结果,所以程序不应当处于设计代码的迭代的过程中,因此,可以排除是Active Regions。

Q5:systemverilog引入program块的意义?

A5:引入了Reactive Region set(Reactive、Re-Inactive、Re-NBA),将验证代码和设计代码区域区分,减少了竞争冒险。

Q6:有时候写代码时会加入#0的延迟,有什么作用吗?

A6:参考文章,设计中不要使用,验证时可以使用来对事件执行先后进行调度。

Q7:uvm的run_test()在应该在module里面例化,还是应该在program里面例化?

A7:两种例化方式都是可以的。在module中例化就相当于没有了program块,自然也就没有了program块相关的Regions,如果你的代码风格不是很诡异的话,当然是完全没有问题的。事实上cadence也是推荐我们在module中例化run_test(),而synopsys则建议我们在program块内例化run_test,利用program块来对设计代码和验证平台进行区分。曾经有人也说过program块完全是多余的垃圾,因为对于代码风格良好的设计而言,即使没有program块也是不会存在验证的竞争冒险。所以个人观点,萝卜青菜,各有所爱,你习惯用哪个就用哪个。

Q8:uvm中的函数uvm_wait_for_nba_region()有什么作用?

A8:顾名思义,这里需要等待NBA Region之前的进程被执行完。源代码有解释,如下:

===================================悲伤的分割线===================================

写在最后:

1、双11撸了一台腾讯云主机(真良心价!2C4G 3M 3年只要688),已经基于xfce+vnc装好图形界面,试了下vcs和verdi都可以正常运行。而且手机上的vnc viewer也挺好用的。开心。

2、其实搞验证搞了这么久,觉得最有用的资料还是IEEE的标准和软件的user guide,其它的知识点很多都是衍生出去的(有一种天下武功出少林的感觉),建议大家有空还是多看看。

3、TMD,周天还要让我去公司协助定位问题,真是够了,能不能给人留点私人时间啊。
————————————————
版权声明:本文为优快云博主「kevindas」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/kevindas/article/details/103449360

<think>我们正在讨论VCS选项中`+fsdb+glitch=0`的使用场景。根据引用内容,这个选项主要与波形文件中毛刺(glitch)的记录和显示有关。 首先,从引用[3]和[4]中我们可以看到: - `+fsdb+glitch=0`是VCS仿真时的一个选项,用于控制毛刺的记录。 - 在引用[3]中,用户提到在drv里面使用了`wait(interface.rdy === 1)`,这个条件会捕获time_slot里面的毛刺,导致非预期的驱动行为。为了解决这个问题,他们使用了`+fsdb+glitch=0`选项,这样可以在波形上直接看到毛刺。 - 引用[4]则说明`+fsdb+glitch=0`是用于查看glitch(毛刺)的,它是delta cycle调试的三种方式之一。 具体来说,`+fsdb+glitch`选项有三个设置: - `0`: 显示所有毛刺(默认) - `1`: 过滤短于单位延迟的毛刺 - `2`: 完全禁用毛刺检测 那么,`+fsdb+glitch=0`的使用场景是什么呢? 1. **需要详细分析信号毛刺的场景**:当设计中存在组合逻辑路径时,由于门级仿真中的延迟,可能会产生非常短暂的脉冲(即毛刺)。如果这些毛刺被后续电路(比如使用`===`的操作)捕获,可能会导致意外的行为。使用`+fsdb+glitch=0`可以确保这些毛刺被完整记录在FSDB波形中,便于在Verdi中调试。 2. **调试由于毛刺引发的逻辑错误**:如引用[3]所述,在验证环境中,如果测试平台使用了`===`操作符等待信号(例如`wait(interface.rdy === 1)`),那么当信号上出现毛刺(即使是一个delta cycle的脉冲)时,这样的等待语句可能会被触发,导致在非预期的时间点执行驱动操作。启用`+fsdb+glitch=0`后,可以在波形中看到这些毛刺,进而分析它们是否导致了错误。 3. **分析delta cycle行为**:引用[4]提到,`+fsdb+glitch=0`是调试delta cycle事件的一种方式。在波形查看器(如Verdi)中,可以通过展开delta cycle(View -> Expand Delta)来查看信号在同一个仿真时间点内不同事件区域(Active, NBA等)的变化。毛刺通常就是在一个仿真时间点内,信号在多个事件区域中变化的结果。例如,引用[2]中的例子,一个信号在Active区域变化导致另一个信号变化,然后在NBA区域又有一个变化,两者叠加产生了一个0宽度的脉冲(即毛刺)。 因此,使用`+fsdb+glitch=0`的场景主要包括: - 设计和验证中怀疑毛刺导致功能错误时。 - 需要详细观察信号在同一个时间点内多次变化(delta cycle)的情况。 - 组合逻辑较多且延迟模型较精确的门级仿真中。 注意:启用毛刺记录会增加仿真开销(因为需要记录更多的信号变化)和波形文件大小。因此,在不需要调试毛刺的情况下,可以考虑使用`+fsdb+glitch=1`(过滤掉非常短的毛刺)或`+fsdb+glitch=2`(完全禁用)来减少开销。 在Verdi中调试毛刺时,可以: 1. 使用`fsdbdebug -info`检查FSDB文件是否包含毛刺信息。 2. 使用`fsdbdebug -show_glitch`列出所有毛刺(如果Verdi版本支持)。 3. 在波形视图中,将光标定位到毛刺出现的时间点,然后使用`View -> Expand Delta`来展开查看事件序列(Event Sequence)和事件区域(Event Region)[^1][^4]。 最后,要使用这些选项,需要在Testbench中调用`$fsdbDumpvars`,并在仿真命令行中加上`+fsdb+glitch=0`。 </think>### VCS选项中`+fsdb+glitch=0`的使用场景详解 `+fsdb+glitch=0`是VCS仿真中用于**精确捕获和调试信号毛刺**的关键选项,在以下场景中具有重要作用: #### 1. **组合逻辑时序验证**(最核心场景) 当设计包含多级组合逻辑时,信号可能因门延迟差异产生短暂毛刺(<1个时钟周期)。使用`+fsdb+glitch=0`可: - 完整记录所有宽度脉冲(包括零延迟毛刺) - 暴露组合逻辑竞争冒险问题 - 尤其适用于异步电路和时钟门控设计验证 **案例**: > 引用[2]中的双initial块glitch生成实验,通过此选项可捕获`a_inv→b`路径产生的0ps脉冲[^2] #### 2. **验证平台敏感事件调试** 当Testbench使用`wait(signal === value)`或`@(signal)`等敏感事件时: ```systemverilog // 示例:易受毛刺影响的等待语句 initial begin wait(interface.rdy === 1); // 毛刺可能意外触发此等待 drive_data(); end ``` `+fsdb+glitch=0`可捕获接口信号上的瞬时跳变,防止验证平台被虚假事件误导[^3] #### 3. **Delta-Cycle级时序分析** 用于调试同一仿真时刻内的多区域事件: - **Active区**:阻塞赋值执行(绿色区域) - **NBA区**:非阻塞赋值生效(红色区域) 通过Verdi的`View > Expand Delta`可分析: $$ \Delta t = t_{active} - t_{nba} $$ 毛刺常因Active区与NBA区信号冲突产生[^4] #### 4. **低功耗设计验证** 在电源门控场景中: - 电源开关瞬态可能产生亚稳态毛刺 - 隔离单元失效可能导致信号瞬时连通 - 使用此选项可捕捉power-aware仿真中的非法电平跳变 #### 5. **混合信号仿真** 在数模混合仿真时: - ADC/DAC接口的数字毛刺可能被误判为模拟信号 - 特别需要捕获窄脉冲分析信号完整性 > **性能提示**:此选项会增加15-20%仿真开销,建议: > - 门级仿真默认开启 > - RTL仿真仅在调试时启用 > - 回归测试使用`+fsdb+glitch=1`过滤短脉冲 ### 操作示例 ```bash # 编译命令 vcs -debug_access+all design.v tb.sv # 仿真命令(启用毛刺捕获) simv +fsdb+file=glitch_debug.fsdb +fsdb+glitch=0 ``` 在Verdi中通过`fsdbdebug -show_glitch`列出所有毛刺点[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值