赞
踩
在RTL代码编写结束后,需要对其编写testbench完成对待测设计的例化,测试代码的封装,生成输入激励,收集输出相应,决定对错和衡量进度。
如图模仿设计的整个运行环境,虚线框为testbench。testbench是对DUT进行测试的方案描述文件,因此模块没有输入输出,用到的语句也是不可综合的,主要包含激励发生器,DUT,参考模型,监视器,比较器等。
tb.v是封闭的,没有input/output
1)行激励
initial块中添加
2)预设输入向量
3)使用task
(3)检查确认验证结果
1)人工波形检查
2)通过系统函数打印
3)自动检查
本文介绍的testbench将以systemverilog和verilog语句为主,关于两种语言的具体语法参见:
systemverilog:IC验证——SystemVerilog学习_KGback的博客-CSDN博客_systemverilog验证
verilog:IC设计——Verilog HDL学习笔记_KGback的博客-CSDN博客
包含verilog语法中always的用法。
仿真时对变量初始化,过程语句块,对clk,reset等输入信号初始化
(1)#delay
(2)@(signal)
在signal信号发生反转后执行,在signal前添加posedge/negedge表明信号有效沿,可以使用or指定多个参数。
(3)wait(signal==1)
等待信号触发事务
重复操作语句块
无限循环,只能通过$finish退出
通过变量控制循环次数。
强制退出循环。
fork...join / join_any / join_none
fork引导的并行块,其特点:
(1)并行块中所有语句同时执行。join是当按时间时序排序在最后的语句执行完或者执行disable语句时,程序流程跳出程序块;join_any当任意语句执行完后,程序跳出;join_none是fork块和外部程序同时执行
(2)块内每条语句的执行时间是相对于程序流程进入到块内的仿真时间的
(3)延时时间是用来给赋值语句提供执行时序的
(4)若fork...join中存在begin...end语句,则begin...end内语句为顺序执行
- fork
- 块内声明语句 //块内声明语句可以是参数说明语句、 reg型变量声明语句、 integer型变量声明语句、
- //real型变量声明语句、time型变量声明语句、事件(event)说明语句。
- ......
- join
- wait_fork; //等待所有fork进程执行完毕
- disable_fork; //中断所有fork进程
task和function必须在module内定义和调用,其作用范围仅限于该模块;内定义的变量都是局部变量,不会与其他变量冲突,且都是寄存器变量
task可以调用function,但function不能调用task。
执行消耗时间的电路,测试文件中主要的测试任务内容。通常用在需要耗时的信号采样或驱动场景中。task是否可综合在不同的综合工具中支持不一样,一般用于testbench。
无返回值。
定义方式:
automatic
多次调用同一任务时,需要使用自动任务定义。
task一般是静态的,即所有调用者共享task的地址空间和变量;
当在一个模块中两次调用同一人物的间隔时间较短时,两次调用人物的时间重叠,会出现互斥问题,造成任务执行结果错误,使用automatic可解决该问题。
disable
可使task在执行完成之前就结束所有活动。
e.g.
disable <task_name>
函数功能,function和task都是描述功能块,但function无时序控制,即不消耗时间,通常做一些声明,创建或纯粹的数字和逻辑运算的操作。因此用于调试的子程序都用过被定义成function而不是任务。
能返回一个和函数名同名的寄存器值,即缺省的返回值是与函数名name同名的变量值;void无return
内不使用非阻塞赋值。
只有input类型,没有output类型
定义和调用
用于仿真、调试和验证,观察仿真执行的结果。该语句不可综合,在设计代码中不能存在,只能在调试阶段用。
打印信息,可以放在initial和always模块中。
$display("%d\n", 10); //以10进制打印10后换行,同理 h(同x,16进制),o(八进制),b(二进制),
//c(ASCII字符),s(字符串),t(时间格式)
//一些特殊字符:\n(换行),\t(相当于tab键),\\(反斜杠),%%(百分符号)
$display("@%0t a=%0d, b=%0d", $time, a, b); //输出当前仿真时间,变量数值,例:@10 a=2, b=9
$display会自动换行,即$display("")和¥display("\n")意义一样
与diaplay类似,区别是不会自动换行
一般是initial块的第一句,表示打开监控器,打印次数可以有很多次。
当信号a或b的值发生变化时,系统任务$monito显示当前仿真时间,信号a值(二进制), 信号b值(16进制)。
Verilog仿真中即使DUT的输入激励已经执行完毕,仿真也会一直执行下去。
$finish结束仿真;$stop暂停仿真
$time返回一个根据所在模块的时间精度要求进行舍入的64bit整数
$realtime返回一个带小数部分的完整实数
$stime返回一个32位整数时间值
Verilog允许同时打开30个文件。
$random
e.g.
rand1=$random; // 返回32bit的整数
rand2=$random(seed); //seed可以是reg、integer或time变量
rand3=$random %b;其中b>0,给出范围在(-b+1,b-1)的随机数
rand4={$random} %b;//加拼接符{ }后 生成正随机数(0~b-1)
event A, B; //声明
#10 ->A; //触发A
@(A); //等待A触发,触发信号为冲击信号,
wait( A.triggered ); //触发时会形成一小段电平信号
wait_order(A, B); //触发顺序A>B
描述时间单位和仿真精度(仿真器仿真步进),时间单位指tb中# xxx代表的时间长度,数字必须是1、10、100。只需在顶层模块中定义一次。
`timescale 10ns/1ns //模块test的时间单位为10ns、 时间精度为1ns
parameter d=1.55; //根据时间精度,参数d值被从1.55取整为1.6。
#10 creg = areg; //在两条赋值语句间延迟10个时间单位,即100ns
仿真器不同,结果可能不同
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。