用于验证的Verilog语法
DUT (Design Under Test, 被测电路)
initial语句
对变量初始化,只执行一次
系统任务
$finish
仿真结束
$stop
停止仿真,但不退出,输入.后可以继续进行
$display
打印信息到屏幕,如调试信息,错误或者异常等,可以在testbench中使用“.”支出信号在DUT中的路径信号来判断输出打印信息。
$monitor
和display类似,但是仅在监视的信号数值发生变化才输出打印信息。
`timescale
`timescale 仿真时间单位/时间精度
//单位和精度的数字只能是1、10、100
$time
任务返回仿真器当前仿真时间。在testbench中需要使用`timescale指出仿真时间单位(通常为1ns)。当前仿真时间是一个64位整数乘以timescale的单位后四舍五入取整的结果,不包含小数部分。
$realtime
以实数的方式返回当前仿真时间,包含小数部分。使用delay的方式会出现小数的时间精度。
$random
返回32为带符号的随机整数。将$random放入{}内,可得到非负整数。\$ramdom(seed)中的seed是一个正整数,可以设定随机数的取值范围。
$save
$save("file name")可以将仿真器当前仿真状态保存早指定文件中。后续可以加载继续仿真。
$readmemh/\$writememh
$readmemh从文本读取数据。
$fopen/\$fclose
integer j, file;
reg [31:0] mem_addr;
initial begin
mem_addr = 0;
file = $fopen("results_file.dat");
for (j = 0; j < 10; j++) begin
$fdisplay(file, "the compute result is %d", mem_addr);
mem_addr += 1;
end
$fclose(file);
end
任务
与Verilog函数非常类似,可以将一段代码定义为一个任务,然后在不同的地方多次调用。
与函数的差异是:任务可以自定义输出输出端口,任务也可以进行定时控制,如@posedge clk、none-zerotimings和#10等时间控制语句。
任务是按顺序执行的,内部的定时控制语句,仿真器会等到条件满足才执行后续语句。任务既可以是可综合的也可以是不可综合的,一般用作testbench中。
储存器建模
在Verilog中可以通过定义二维寄存器数据的方式定义存储器,在综合的时候采用寄存器阵列加以实际实现。在实际芯片中通常通过定制设计的SRAM(Static Random Access Memory,静态随机存取储存器)来实现的,不是通过综合生成的。Verilog中定义的存储器模型主要用于验证。
其他Verilog语法结构
while循环
当括号内条件为真是循环,为假时退出。循环内部建议加入与定时控制有关的语句,如@posedge clk或#5,以避免形成定时环路,造成死循环。
for循环、repeat
for循环语句可以用于testbench或者可综合的RTL中。
force/release
force用于讲一个固定值(1,0)强制赋予一个reg或者wire类型的变量。在release命令被执行之前,不论reg或者wire类型的变量被怎样驱动,变量的只都不会发生改变。release命令被执行后,变量值由其具体驱动决定。
fork/join
fork/join内部的语句是并发执行的,当其内部的多条语句都执行完后,才继续执行其后面的其他语句。
在fork-join内部通常并发地的执行多个仿真任务,主要用于testbench中,用于模拟正式的电路工作情况。
task memread;
begin
#100 $display("mem read task time", $time);
end
endtask
task memcomp;
begin
#500 $display("mem comp task time", $time);
end
endtask
initial begin
fork
begin
memread();
memread();
memread();
end
begin
memcomp();
memcomp();
memcomp();
end
join
$display("time after memread, memcomp task executed", $time);
end