SV环境构建二(软件环境细节-时间片,程序,模块,测试的始终 )

本文详细介绍了SystemVerilog中的仿真调度机制,重点讲解了时间片(Time Slot)的概念,包括Active、Inactive、NBA等六个调度区域。此外,还讨论了程序(program)在验证中的作用,提出了程序设计与测试采样区域的划分建议,并解释了program的隐式和显式结束方式,为理解SystemVerilog仿真提供了深入的见解。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、程序与模块

模块(module)作为SV从verilog继承来的概念,保持了它原有的特点,除了作为RTL模型的外壳包装和实现硬件行为,在更高的继承层面,模块之间也需要通信和同步。

1.SV的仿真调度机制 - 时间片(Time Slot)

SV的仿真调度在verilog的基础上,扩展出来新的sv结构体,如程序(program)和断言(assertion)。充分理解sv的不同结构体在仿真中的先后执行顺序,有利于理解testbench中对DUT驱动和采样的顺序,进而避免不合理的驱动、采样方式以及两者间的竞争问题。

在这里,非常有必要介绍仿真时间中的一个抽象单位Ts--时间片(time-slot),该单位内所有线程(always,initial,assertion等)和数据对象的赋值(阻塞与非阻塞)被赋予了相应优先级,依次被执行,优先级体现在调度区域(scheduling regions)中,如下图所示。

接下来,对这些调度区域做简单介绍。

Active区域:执行该阶段线程:always,assign,initial等。其中,与非阻塞赋值有关操作执行完毕后,对应线程进入NBA,带有零延时的线程(#0)直接进入inactive区域。

Inactive区域:有零延时操作的线程在inactive区域被激活,被执行前迁往active区域。所以,零延时操作会延缓线程的执行时间。

NBA区域:所有active和inactive区域均没有其他线程之后所到达的调度区,到达该区域后,之前active区域的非阻塞赋值生效,,如果非阻塞赋值触发了其他线程,被触发的线程要挪到active区域。

observe区域:当之前的active/inactive/NBA区域均执行完毕后,表示设计部分的线程已经执行完毕。接下来的区域是sv为验证一侧准备的。进入observe区域后,这一区域是为了属性断言准备的,方便监测设计中的变量确定值。该区域同样适用于接口和程序块中的采样操作,使得采集到的数据是该Ts的最终值。

reactive区域:经历了数据采样工作,断言语句需要进行属性判断,在该区域进行,同时处于testbench区域中的线程也在该区域执行。

postpone区域:分别经历了与设计、testbench相关的区域之后,当前Ts进入postponed区域。该区域内的值保持稳定,且与下一Ts preponed的值保持一致。同时,该区域也作为sv PLI/DPI的回调函数(callback)点,使得在sv外部的调用语言(如C)在使用sv变量时,仍然可以用到最新的数值。 

在了解上述6个区域之后,结合阻塞赋值与非阻塞赋值例子进行分析:

阻塞赋值:

a = a + 1; // a在Ts的active区域被赋值,且赋值立即生效
b = a;      // b在相同区域被赋值,同时使用被立即赋值的a = a + 1

非阻塞赋值:可以避免一些设计中的竞争情况

a <= a + 1;   // a在Ts的active区域被赋值,而在NBA区域生效
b <= a;       // b在同一个Ts区域被赋值,且使用被赋值前的a值

接下来,结合TB与DUT在时间片中的执行顺序,来分析一个例子的输出结果:

module counter(input clk);
    bit [3:0] cnt;
    always @(posedge clk) begin
        cnt <= cnt + 1;
        $display("@%0t DUT cnt = %0d", $time, cnt);
    end
endmodule

program dsample(input clk);
    initial begin
        forever begin
            @(posedge clk)
            $display("@%0t TB cnt = %0d", $time, dut.cnt);
        end
    end
endprogram

module tb;
    bit clk1;
    bit [3:0] cnt;
        initial begin
            forever begin 
                #5ns clk1 <= !clk1
            end
        end
        counter dut(clk1);
        dsample spl(clk1);
endmodule
仿真结果:
# @5 DUT cnt = 0
# @5 TB cnt = 1
# @15 DUT cnt = 1
# @15 TB cnt = 2
# @25 DUT cnt = 2
# @25 TB cnt = 3

分析:dut中cnt <= cnt + 1在active区域触发,同时该区域DUT完成采样,采到赋值前的值,到NBA区域,cnt完成+1的赋值,而TB的行动在后面的reactive区域进行,该区域,TB完成采样,采到赋值后的值。

 

由此看来,sv介绍的程序(program)就是为了将设计和验证调度区域显示的分割开来安排,因此建议将设计部分放到module块,测试采样部分放到program块,下面关于program有些要求与建议:

1. program可视为软件的”领地“,故其中不可出现硬件行为相关的过程语句与实例,如:always,module,interface,也不能出现其他program例化语句。

2. program内部可定义变量,以及发起多个initial块

3. program内部赋值方式应为阻塞赋值(软件方式)

4. program内部在驱动外部的硬件信号时应使用非阻塞赋值(硬件方式)

5. program内部initial块在reactive区域执行,外部initial块在active区域执行。

program的出现,解决了硬件信号采样可能出现的竞争风险,我们可以通过合适的连接和采样方式将验证组件和DUT进行连接。连接后,一旦有了激励,如何结束仿真,以何种方式结束将在下文为各位介绍。

二、测试的始终

        设计自身可以作为一个大的线程,内部包含并行线程,模块间通信主要依靠信号的变化。对于一个设计,在仿真开始阶段,如果不加入任何激励(如时钟和复位),则仿真不具备执行的条件,可以认为结束了。因为设计内部不产生任何新的事件,也不存在这些事件触发组合逻辑和时序逻辑。故,在仿真开始提供时钟复位是必要的。

        在verilog测试方式中,如果灌入的时钟信号不停止,仿真会一直跑下去,不会主动结束,这时就需要verilog系统函数调用来结束仿真了($finish(), $stop())。

1.program 隐式结束

        sv的program讲设计与验证部分隔开,且每个program都作为一个独立的测试,如果TB中只存在一个program,当program最后一个initial执行完毕后,仿真结束;若存在多个program,需要等待所有program的initial块全部执行完,结束仿真。

2.program 显式结束

       有时候。initial块中包含无限循环语句,隐式方式就无法实现结束仿真的功能了,这就需要调用函数$exit来强制结束当前program。等待所有program都执行完毕,仿真停止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值