Verilog学习之路(10)—仿真使用的系统任务
一、前言
在Verilog HDL集成电路设计过程中,设计者完成RTL级描述后需要对设计进行设计确认。设计确认是设计者检查设计中是否包含缺陷的过程。设计确认可以通过仿真和验证来完成。仿真和验证能确保设计的完整性、可靠性、时效性以及先进性。
二、display和write
$display
和$write
是Verilog中两种主要的标准输出任务,这两个系统函数都用于将特定信息输出到标准输出设备且语法格式相同。其中不同的是,$display
带有行结束字符,即自动在输出后进行换行;而$write
不自动行,可以用于在一行里输出多个信息。
其中格式化字符串常用的输出格式如下所示:
对其中的特殊字符输出如下所示
三、monitor
$monitor
提供了监控和输出参数参数列表中的表达式或变量值的功能,当参数列表中变量或表达式的值发生变化时,整个参数列表中变量或表达式的值都将输出显示。
编写代码如下所示
module monitor_tb;
integer a,b;
initial begin
a = 2;
b = 4;
forever begin
#5 a= a + b;
#5 b = a -1;
end
end
initial begin
$monitor($time, ": a=%3d, b=%3d", a, b);
end
initial begin
#40 $finish;
end
endmodule
仿真结果如下
另外与$monitor
相关的还提供了monitoron
和$monitoroff
两种系统任务,其描述如下所示
四、strobe
$strobe
系统任务用于某时刻所有语句都处理完后,在时间步的结尾输出一行格式化的文本。编写代码如下所示
module strobe_tb;
reg a, b;
initial begin
a = 0;
$display("a by display is %0d", a);
$strobe("a by strobe is %0d", a);
a =1;
end
initial begin
b <= 0;
$display("b by display is %d", b);
$strobe("b by strobe is %d", b);
#5;
$display("after #5, b by display is %d", b);
$strobe("after #5, b by strobe is %d", b);
b <= 1;
end
endmodule
仿真结果如下
五、time、realtime和timeformat
使用$time
和realtime
这两个时间系统函数可以得到当前的仿真时刻,不同的是,$time
返回一个64比特的当前仿真时刻值,而$realtime
以实型数据的形式返回仿真时间。
timeformat
是用来设置时间格式化输出时的格式的,其使用如下所示:
$timeformat(units_number, precision_number, suffix_string, minimum_field_wdith);
- units_number 是 0 到-15 之间的整数值,表示打印的时间值的单位:0 表示秒,-3 表示毫秒,-6 表示微秒,-9 表示纳秒, -12 表示皮秒, -15 表示飞秒;中间值也可以使用:例如-10表示以100ps为单位。其默认值为`timescalse所设置的仿真时间单位。
- precision_number 是在打印时间值时,小数点后保留的位数。其默认值为0。
- suffix_string 是在时间值后面打印的一个后缀字符串。其默认值为空字符串。
- MinFieldWidth 是时间值字符串与后缀字符串合起来的这部分字符串的最小长度,若这部分字符串不足这个长度,则在这部分字符串之前补空格。其默认值为20。
编写代码如下所示:
`timescale 1ns/1ps
module time_tb;
reg ts;
initial begin
$timeformat(-9, 3, "ns", 8);
#2.1 ts = 1;
$display("@$time: %0t, ts = %d", $time, ts);
$display("@$realtime: %0t, ts = %d", $realtime, ts);
#2.1 ts = 0;
$display("@$time: %0t, ts = %d", $time, ts);
$display("@$realtime: %0t, ts = %d", $realtime, ts);
#2.1 ts = 1;
$display("@$time: %0t, ts = %d", $time, ts);
$display("@$realtime: %0t, ts = %d", $realtime, ts);
#2.1 ts = 0;
$display("@$time: %0t, ts = %d", $time, ts);
$display("@$realtime: %0t, ts = %d", $realtime, ts);
end
endmodule
仿真结果如下
六、finish和stop
系统任务$finish
和$stop
用于对仿真过程的控制,分别表示结束仿真和中断仿真,其语法格式分别如下:
$finish;
$finish(n);
$stop;
$stop(n);
其中,n是参数,可以取0、1或2几个值,含义如下所示:
七、readmemh和readmemb
系统任务$readmemb
和$readmemh
用来从文件中读取数据到存储器中,这两个任务可以在仿真的任何时刻被执行使用,其语法格式如下所示:
$readmemb("<file_name>", <memory_name>);
$readmemb("<file_name>", <memory_name>, <start_addr>);
$readmemb("<file_name>", <memory_name>, <start_addr>, <finish_addr>);
$readmemh("<file_name>", <memory_name>);
$readmemh("<file_name>", <memory_name>, <start_addr>);
$readmemh("<file_name>", <memory_name>, <start_addr>, <finish_addr>);
在这两个系统任务中,被读取的数据文件的内容只能包含空白位置(空格、换行符、制表符(tab)和换页符(form-feeds)、注释行(//形式的和/* … */的都可以)、二进制或十六进制的数字。
编写代码如下所示
module readmem_tb;
reg [7:0] memory_b [0:7];
reg [31:0] memory_h [0:31];
integer i;
initial begin
// 把数据文件init_b.txt读入存储器中的给定地址
$readmemb("init_b.txt", memory_b);
// 把数据文件init_h.txt读入存储器中的给定地址
$readmemh("init_h.txt", memory_h);
// 显示初始化后的存储器内容
for(i=0; i<8; i=i+1) begin
$display("memory_b[%0d] = %b", i, memory_b[i]);
end
for(i=0; i<8; i=i+1) begin
$display("memory_h[%0h] = %h", i, memory_h[i]);
end
end
endmodule
任何编写init_b.txt
和init_h.txt
文件如下所示,可以用@<address
在数据文件中指定地址,
init_b.txt如下所示:
11111111 01010101
00000000 10101010
@006
1111zzzz 00001111
init_h.txt如下所示:
@001
0 11
0 111
0 1111
0 11111
仿真结果如下
八、random
$random
是产生随机数的系统函数,每次调用该函数将返回一个32位的带符号的整形随机数。$random
的一般用法如下所示:
$random % b
其中,b为一常数且要求大于零,这样即可得到一个范围在-b+1
到b-1
之间的随机数。
利用操作符{ }
可以将函数$random
返回的有符号整数变换为无符号数,其用法如下:
{$random} % b
其中,b为一常数且要求大于零,这样即可得到一个范围在0
到b-1
之间的随机数。
编写代码如下所示
module random_tb;
integer i;
initial begin
for(i=0; i < 8; i=i+1) begin
$display("@%0d times, $random %% 10 = %d", i, $random%10);
end
for(i=0; i < 8; i=i+1) begin
$display("@%0d times, {$random} %% 10 = %d", i, {$random}%10);
end
end
endmodule
仿真结果如下
九、附录
上一篇:Verilog学习之路(9)—计数器和移位寄存器
下一篇: