SystemVerilog LRM 学习笔记 — SV Scheduler仿真调度

1. 为什么要理解scheduler?

SystemVerilog是HDVL语言,相较与Verilog,除了面向HW design应用,也为了提高verif的效率。所以其仿真调度算法在向下兼容Verilog的同时,增加了不少新的‘Time region’,以便更好的支持program块等针对验证需求的新特性。

SV不同于C/C++等软件语言,为了对硬件进行仿真建模,所以有很多并行的process,而仿真器作为运行在CPU上的软件,只是按照SV LRM的仿真调度算法,开始仿真后,将仿真时间串行的一步步的向前推进。由于SV LRM并没有完全详细的规定并行的process以具体什么样的顺序来执行,这就引进许多不确定性(Nondeterminism), 不同厂家的仿真器可能有不同的仿真结果。

为了在coding时就消除这种不确定性,更好理解常见的design rule,需要对Verilog/SV的仿真调度算法进行深刻理解,并且涉及到VHDL的混合仿真,也要理解VHDL和Verilog/SV之间的差异。

常见的Design Rules:

  1. 时序逻辑中应使用非阻塞赋值(<=)
  2. 锁存器建模应使用非阻塞赋值(<=)
  3. 用always对组合逻辑建模,应使用阻塞赋值(=)
  4. 当需要在同一always中对组合逻辑和时序逻辑建模时,可以使用<=,不要使用=
  5. 不要在同一always块中混合使用<=和=
  6. 要避免在不同的always块中对同一变量进行赋值
  7. 使用$strobe来打印同一时刻下的非阻塞赋值
  8. 千万,千万不要使用0延时(#0)

2. Simulation模型

SV是基于离散事件执行驱动的仿真模型,event-driven仿真的基本概念:1)simulation time, 2)simulation regions,3 event processing。

2.1 事件(event)

模型中数值的变化,功能仿真是一种事件驱动的仿真,整个仿真过程都是围绕事件来组织的。具体地说,由于仿真器在cpu是串行执行,其需要将各个event放进事件队列中(event queue),这就叫scheduling an enent.

更新事件(update event):在被仿真的电路中,线网或寄存器的值在任何进程中的任何改变都被认为是一个更新事件。

求值事件(evaluation event):由于更新事件产生的,进程的计算,计算事件。另外也包含PLI调用。

计算事件和更新事件之间循环往复的互相触发,推动仿真时间的前进。

process: 进程是Verilog中的独立执行单元,包括:原语(Primitives), 模块(Moules), initial过程块, always过程块, 连续赋值语句(assign), 异步任务(task)。在仿真时,所有的进程都是仿真器按Verilog的语义来顺序执行的,效果是各个进程并行执行的效果,在未执行完当前所有的进程时,仿真时间不会向前推进。

//下面例子会hang在仿真时刻0,因为更新时间一直触发求值事件,计算事件一直触发更新事件。
initial begin
    clk = 0;  
    forever clk = ~clk;
end

2.2 仿真时间(simulation time)

当然是指波形中看到的时间,不是仿真软件在host PC中运行的时间。是仿真时间维护的时间值,用来对仿真电路的真实时间进行建模,当仿真时间推进到某一个时间点时,该时间点就被称为当前仿真时间(current time),而以后的任何时间都被称为将来仿真时间(future time)。

2.3 仿真域(simulation region)

2.3.1 层次化事件队列(The stratified event queue)

一个timeslot下的事件队列可以划分为不同层次的域(region),这些域按照特定的优先级顺序执行,只有所有在优先级高的region内的事件执行完,才执行低优先级域的事件。仿真器首先按照仿真时间对事件进行排序,然后再在当前仿真时间里按照这些域的优先级顺序进行排序。在同一域里的事件,执行顺序是不确定的。

2.3.2 Verilog的事件调度器

Verilog的timeslot划分5个域:
Active region : 执行process语句,阻塞赋值,连续赋值,及非阻塞赋值的右侧求值事件,阻塞赋值和连续赋值会触发在该时刻的新事件。$display是在该region执行。
Inactive region : 执行 #0的阻塞赋值;
NBA region : 更新非阻塞赋值的LHS;
Monitor region : 执行$monitor 和 $strobe等,不会出发任何其他事件的read-only region

2.3.3 System Verilog的事件调度器

SystemVerilog增加到17个域,为assertion,design code和testbench code间交互作用减少race发生,其中9个顺序的域为了SV statement的执行,8个顺序的域为了PLI代码的执行。下图是略去了PLI region的SV scheduler。

Preponed region : 在timeslot开始时进行信号采样, assertion使用的signal也是在这个region进行采样。
observed region : 执行assertion evaluation.
Re-Active and Re-Inactive regions : 执行assertion action blocks 和 testbench programs

2.4 SV引入了新的代码块: program, final, clocking

program: 为了清晰的区分design和TB,SV引入program块,它可以包含TB的环境,目的是减少竞争冒险。program在Re-Active域执行。

final:final块用来在仿真末尾时打印summary info,它是在仿真隐式或显式的调用$finish后立即执行,没有delay,如:

program asic_with_ankit;
  int error, warning;
  initial begin
  //Main program activities…..
  end
  final begin
  $display (“Test is done with %d errors and %d warnings”, error, warning);
  end
endprogram

clocking:  SV引入clocking用以解决TB和design间的timing及sychronisation的需求.

3. 确定性(Determinism)和不确定性(Nondeterminism)

3.1 确定性(Determinism)

SV标准规定了下面两种确定的scheduling顺序:

1. 在begin…end块中的语句要按其代码出现的先后顺序执行,为了支持模型中的其他过程,可以挂起特定的begin-end块中语句的执行。不管怎样,不允许begin-end块中的语句不按照代码中的顺序以任意顺序执行。

2.NBAs必须按照语句的顺序来执行。

3.2 不确定性(Nondeterminism)

SV并没有规定多个processes执行时的顺序,如果多个processes在同一时刻下触发,这些processes以什么样的先后顺序来执行,由于SV标准并没有规定,不同厂商的仿真器不一定相同。如下例,q在d变化后是变成d还是~d,其结果都符合SV规定,但不同的仿真器可能会得到不同的结果。

always @(d)
  q=d;

assign q=~d;

4. 阻塞/非阻塞赋值(blocking/nonboclking assignment)

4.1 阻塞赋值

1、RHS的表达式计算和LHS的赋值更新,这两个动作之间不能插入其他动作,即所谓计算完毕,立即更新。

2、所谓阻塞赋值就是在一个”begin…end”块中的多个阻塞赋值语句,只有上一句完全执行完毕后,才会执行下一语句。
阻塞赋值属于active event,会立刻执行,这就是阻塞赋值“计算完毕,立即更新”的原因。此外,由于在分层事件队列中,只有将活跃事件中排在前面的事件调出,并执行完毕后,才能够执行下面的事件,这就可以解释阻塞赋值的第二个特点。

4.2 非阻塞赋值

非阻塞赋值分两个step执行:RHS的计算表达式和LHS的赋值更新。首先,应该是RHS表达式计算,得到新值后并不立即赋值,而是放在事件队列中等待,直到当前仿真时刻的后期才执行。


参考文献:

1. Verilog篇(三)仿真原理

2. SystemVerilog Simulation

3. Verilog and SV Event Scheduler

4. Verilog的分层事件队列

5. IEEE 1800-2017 – IEEE Standard for SystemVerilog

6. SystemVerilog Event Regions, Race Avoidance & Guidelines

阅读:153

发表评论

电子邮件地址不会被公开。 必填项已用*标注