如果按照软件的思维理解硬件仿真,那么上面的三个模块首先是独立运行的线程(thread)在仿真伊始并行执行,除了每个线程会依照自身内部产生的事件触发进程模块之外,也同时依靠相邻模块间的信号变化。
Verilog设计竞争问题
为了避免在RTL仿真行为中发生的信号竞争问题,我们建议通过非阻塞赋值或者特定的信号延迟来解决同步的问题。例如,从下面的例子可以看到,采用阻塞赋值可能引起的竞争问题:
从仿真结果来看,寄存器a在每个时钟计数以后的值会被当前时钟内的b采集到,所以,每个时钟周期内a和b的数值是一致的。但是,这种仿真行为并不符合真实的硬件行为,因为b如果要对a的数值采样,那么必须有一个周期的延迟,而从软件角度理解,b不应该在当前时刻收集a变化后的数值,而应该是变化前的数值。
所以,我们可以通过非阻塞赋值的形式来避免这种情况。
输出结果:
非阻塞赋值和信号输出的延迟赋值都可以有效避免设计层面的竞争问题。那么当testbench与DUT连接时,这种方式还是否行之有效呢?在讨论之前,我们首先从SV的仿真调度入手。
SV的仿真调度
SV的仿真调度完全支持Verilog的仿真调度,同时又扩展出来支持新的SV的结构体例如program(程序)和断言(assertion)。充分理解SV的不同结构体在仿真中执行的先后顺序,有利于理解testbench中对DUT的驱动和采样的顺序,避免不合理的驱动采样方式。
由于仿真器一般基于event驱动方式来执行,所以如果对各个类型的event发生做出合理安排就可以保证设计与验证环境之间有清晰的发生顺序,进而避免这两者之间的竞争问题。
这里time-slot(时间片)是仿真时间中的一个抽象单位Ts,在该单位内所有的线程(always,initial,assertion等)和数据对象的赋值(阻塞赋值和非阻塞赋值)会被赋予相应的优先级,依次被执行。这种优先级即上图显示的scheduling regions(调度区域)。除了observed和reactive区域,其它区域均是继承于Verilog调度区域。preponed区域是从上一个Ts进入本时间单位的入口,而postponed区域则是所有event触发完毕所有数据也被赋值结束以后该Ts的出口。
从上述不同调度区域的功能来看,可以将其划分为: