引言
本文简单介绍 System Verilog 语言的 TestBench。
前文链接:
我的 System Verilog 学习记录(1)
我的 System Verilog 学习记录(2)
testbench 的目的何在 ?
testbench 可以让我们通过仿真验证设计的功能。它就像一个盛放设计的容器,并且可以驱动很多不同的输入激励。
- 产生不同类型的输入激励;
- 用产生的激励驱动设计的输入;
- 可以让设计处理输入的激励,并且产生输出结果;
- 检查输出结果和期望结果,发现设计的功能缺陷;
- 如果发现bug,可以修改设计源码修改bug;
- 重复执行上述过程直至没有任何功能问题;
testbench 的组件有哪些 ?
各部分解释:
组件 | 描述 |
生成器 | 生成用以驱动 DUT 的各种不同的输入激励 |
接口 | 包含设计中可以被激励或者监测的信号 |
驱动器 | 将生成的激励驱动至设计中 |
监视器 | 监测设计的输入输出端口,以捕获设计的行为 |
计分板 | 检查输出和期望结果的一致性 |
环境 | 包括上述所有验证组件 |
测试 | 包括可以微调的不同配置设置项 |
啥是 DUT ?
DUT 表示的是 Design Under Test ,待测试的设计,设计用VHDL 或者 Verilog 描述的。DUT是个主要用在后验证阶段的术语。后验证阶段在硅芯片制造完成后进行。在前验证阶段,也称为Design Under Verification ,简写为 DUV。
这里网站给出了一个完全详细的示例:SystemVerilog Testbench Example 1
但是此处遇到一些问题,指出来和大家讨论:
Design 源程序:
什么是接口 ?
如果设计中包含成百上千的端口信号,那么接口信号的连接、维护、重用就会变得异常繁琐。然而,我们可以将设计中所有的输入输出端口放置在一个容器中,组成向DUT连接的接口。那么待测试的设计就可以通过这个接口给相应的驱动和激励。
什么是驱动器 ?
驱动器是通过接口中定义的任务来执行DUT引脚摆动的验证组件。当驱动器给设计的输入端口驱动一些数值时,其需要调用在接口中预定义的一些任务(task),不需要真正了解信号之间的时序关系。时序信息定义在由接口提供的任务里面。这种抽象级别使得testbench更加灵活可变。在未来,如果接口有变动,新的驱动器仍然可以调用相同的任务用不同的方式驱动信号。
驱动器怎么知道驱动什么 ?
生成器可以产生有效的数据事务并将它们送至驱动器的验证组件。驱动器就可以将由生成器提供的数据通过接口送至设计中。数据事务由类对象(class object)实现。上面组件图中蓝色正方形所示即是。驱动器的任务就是获取数据对象将其翻译成DUT可以理解的内容。
为啥需要监视器 ?
截至目前,已经讨论了数据如何驱动至DUT。但是那仅仅是一半的过程,我们主要的目的在验证设计的功能。DUT处理输入数据并且将计算结果送至输出引脚。此时监视器就负责获取已处理的数据,将其转化为数据对象将其送至计分板。
计分板存在的意义是啥 ?
计分板有一个和DUT有着相同行为方式的参考模型。该模型反映了对DUT期望的行为。输入到DUT的数据同样送至参考模型,所以当DUT存在功能问题时,其输出结果一定和参考模型的结果不一致。所以二者比较的结果就会告知我们设计中存在功能缺陷。这个过程一般都在计分板中完成。
为啥需要环境 ?
因为在未来的工程中更多的组件可以被加入相同的环境中,这样可以让验证变得更灵活可扩展。
测试是干嘛的 ?
确切地说测试会例化环境对象,配置测试的工作方式。注意,我们可能会有成千上万个测试,我们不可能为每一个测试做出直接的改变。因此,我们需要把环境中主要的开关项、参数等做一个微调,就可以用于其他测试。那样的话,测试将对激励生成有更高的控制力,并且也将变得更加有效。
此处我们讨论了简单的testbench的基本结构。在实际工程中,将会有很多类似的组件相互连接在更高抽象级完成各种任务。如果我们要验证一个不超过50行RTL代码的简易数字计数器,那么okay,这样做完全可以。但是随着复杂度的不断增加,将会需要处理更多的抽象级别。
啥叫抽象级 ?
上篇文章的示例中有用独立语句实现电平翻转。
这个是可以通过任务实现,这样不仅实现了相同的功能,并且可重用性更强。这样就将信号的时序细节隐藏,使用者不需要关心其内部逻辑和时序,只要知道如何使用就可以,增加了抽象等级。
还有另外一个示例:SystemVerilog Testbench Example 2