在RTL代码编写结束后,需要对其编写testbench完成对待测设计的例化,测试代码的封装,生成输入激励,收集输出相应,决定对错和衡量进度。
一、testbench架构
1.1 TB框架
如图模仿设计的整个运行环境,虚线框为testbench。testbench是对DUT进行测试的方案描述文件,因此模块没有输入输出,用到的语句也是不可综合的,主要包含激励发生器,DUT,参考模型,监视器,比较器等。
1.2 tb.v的写法
tb.v是封闭的,没有input/output
(1)时钟和复位
(2)测试激励
1)行激励
initial块中添加
2)预设输入向量
3)使用task
(3)检查确认验证结果
1)人工波形检查
2)通过系统函数打印
3)自动检查
二、Verilog 不可综合语法描述
本文介绍的testbench将以systemverilog和verilog语句为主,关于两种语言的具体语法参见:
systemverilog:IC验证——SystemVerilog学习_KGback的博客-CSDN博客_systemverilog验证
verilog:IC设计——Verilog HDL学习笔记_KGback的博客-CSDN博客
2.1 标识符
2.2 过程结构语句
always
包含verilog语法中always的用法。
initial
仿真时对变量初始化,过程语句块,对clk,reset等输入信号初始化
- 不需要触发条件,仿真开始即执行
- 一个initial块执行一次,多个initial块并行执行
时序控制方法
(1)#delay
(2)@(signal)
在signal信号发生反转后执行,在signal前添加posedge/negedge表明信号有效沿,可以使用or指定多个参数。
(3)wait(signal==1)
等待信号触发事务
2.3 循环语句
repeat
重复操作语句块
forever
无限循环,只能通过$finish退出
while
通过变量控制循环次数。
for
disable
强制退出循环。
2.4 并行块语句
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进程
2.5 任务和函数
task和function必须在module内定义和调用,其作用范围仅限于该模块;内定义的变量都是局部变量,不会与其他变量冲突,且都是寄存器变量
task可以调用function,但function不能调用task。
task
执行消耗时间的电路,测试文件中主要的测试任务内容。通常用在需要耗时的信号采样或驱动场景中。task是否可综合在不同的综合工具中支持不一样,一般用于testbench。
无返回值。
定义方式:
automatic
多次调用同一任务时,需要使用自动任务定义。
task一般是静态的,即所有调用者共享task的地址空间和变量;
当在一个模块中两次调用同一人物的间隔时间较短时,两次调用人物的时间重叠,会出现互斥问题,造成任务执行结果错误,使用automatic可解决该问题。
disable
可使task在执行完成之前就结束所有活动。
e.g.
disable <task_name>
function
函数功能,function和task都是描述功能块,但function无时序控制,即不消耗时间,通常做一些声明,创建或纯粹的数字和逻辑运算的操作。因此用于调试的子程序都用过被定义成function而不是任务。
能返回一个和函数名同名的寄存器值,即缺省的返回值是与函数名name同名的变量值;void无return
内不使用非阻塞赋值。
只有input类型,没有output类型
定义和调用
2.6 系统任务
用于仿真、调试和验证,观察仿真执行的结果。该语句不可综合,在设计代码中不能存在,只能在调试阶段用。
$display()
打印信息,可以放在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")意义一样
$write()
与diaplay类似,区别是不会自动换行
$monitor($time, “a = %b, b = %h”, a, b)
一般是initial块的第一句,表示打开监控器,打印次数可以有很多次。
当信号a或b的值发生变化时,系统任务$monito显示当前仿真时间,信号a值(二进制), 信号b值(16进制)。
$finish和$stop
Verilog仿真中即使DUT的输入激励已经执行完毕,仿真也会一直执行下去。
$finish结束仿真;$stop暂停仿真
$time和$realtime
$time返回一个根据所在模块的时间精度要求进行舍入的64bit整数
$realtime返回一个带小数部分的完整实数
$stime返回一个32位整数时间值
字符串操作
- $sformatf
字符串拼接
Systemverilog : $sscanf系统函数_ucanredo的博客-CSDN博客
文件操作
Verilog允许同时打开30个文件。
- $fopen和$fclose
打开文件,然后将原来文件清空
e.g.
integer descriptor;
descriptor = $fopen("switch.txt", "r"); //只读打开一个文件,只允许读数据
// 32bit的descriptor中的一位对应一个通道;标准输出占用32bit多通道描述符的最低位,且始终是打开的;最高位是保留位
Verilog 文件操作-$fgetc,$fgets,$fscanf,$fread - 芯片天地 -
$fdisplay, $fwrite, $fmonitor, $fstrobe
向指定文件输出字符
- $feof
判断文件是否结束,通常是通过$fread()和$fscanf()来识别 - $readmemh()和$readmemb()
将文件中的数据读到存储器中,h要求16进制,b要求2进制,文件中的数据按定义的位宽用空格间隔。
e.g.
reg [31:0] memory [1023:0]; //1K word字长的存储单元
$readmemh("file1", memory); //把file1中的内容读1K word到memory中去
详细使用可参考:
Verilog中的文件操作 - 与非网
verilog中$readmemb和$readmemh的使用_m0_38037810的博客-CSDN博客
随机函数
$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)
2.7 event 触发事件
event A, B; //声明
#10 ->A; //触发A
@(A); //等待A触发,触发信号为冲击信号,
wait( A.triggered ); //触发时会形成一小段电平信号
wait_order(A, B); //触发顺序A>B
2.8 不可综合的预编译命令
`timescale
描述时间单位和仿真精度(仿真器仿真步进),时间单位指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
3. testbench仿真特征
verilog仿真器
仿真器不同,结果可能不同
- Verilog-XL:
cadence开发的解释仿真器,“解释”即有一个运行时间的解释工具执行每一条Verilog指令并且与时间队列进行交流。该仿真器在cadence系统里是一个默认的verilog仿真器,但一直未被cadence更新,不具备verilog的新特点。 - NC-Verilog:
cadence的编译仿真器,把Verilog转换成该程序的定制仿真器,即先转换成C程序,再编译成仿真器。与Verilog-2001大部分兼容。 - VCS:
synopsys开发的编译仿真器,可以与该公司的其他工具集成在一起。兼容Verilog-2001
- Verilog综合成电路的方法
- behavioral(行为级RTL):
用高层次的Verilog描述所希望的系统行为,随后用综合工具综合成硬件电路。 - structural(结构级):
Verilog完全由一个标准单元库基本门的实例构成。该Verilog可以完全是文本的,或是采用标准库中逻辑门符号的层次化原理图。
- 编译综合过程
- 编译阶段
工具通过阅读目标代码,进行语法和语义分析,将每个模块分别编入库中 - 建模阶段
工具将各模块按照设计集成关系最终组成顶层模块,主要包括模块例化,接口例化,程序例化,层次集成,计算参数,解决层次信号引用,建立模块连接等。类似软件编译的link阶段。 - 仿真阶段
通过读取建模后的对象文件,建立硬件RTL模型和验证环境,以周期驱动或事件驱动进行仿真。