在Verilog 语言进行仿真中,通常会使用$display, $strobe, $monitor,$write等系统函数向屏幕上输出一些信息, 帮助验证者 跟踪设计流程, 发现错误等。 在Verilog语言进行仿真时,缺省的设置是以`timescale的时间精度 为单位的(通常是 1ps, `timescale 1ns/1ps)。在通常的RTL 设计中,往往仿真单位是以ns 为单位(例如 `timescale 1ns/1ps),当然,一些超高速的设计,也会使用ps为单位。总体来说,使用仿真单位为ns系统打印输出为ps时,阅读起来不是非常方便。
举例:
`timescale 1ns / 1ps
module tb(
);
reg a = 0;
reg rst = 1;
initial
begin
#200;
rst = 1;
#10;
rst = 0;
$display("==== init a = 0, time = %t ====", $time);
end
endmodule
这时我们会发现$display 输出到屏幕上的信息时间单位都是ps级别的。虽然ps可以换算为ns,但总是和程序中的 #200; #10; 不一致。阅读起来不是非常方便。Verilog 语言中提供一种改变缺省显示输出的函数,是的屏幕显示函数输出结果和程序代码一致。 使得阅读变得更加方便。
1 $timeformat 任务格式
$timeformat ( units_number, precision_number, suffix_string, minimum_field_width) ;
这个系统任务并不改变程序时间精度(不改变`timescale 的内容),只是更改了$display, $strobe, $monitor, $write, $fdisplay, $fstrobe, $fmonitor, $fwrite 等系统任务中使用 %t 时的缺省时间单位, 方便开发者阅读代码。
参数描述:
- units_number: 是 0 到-15 之间的整数值,表示格式化输出的时间值的单位:0 表示秒,-3 表示毫秒,-6 表示微秒,-9 表示纳秒;它是以10(units_number)幂秒表示当前输出的时间单位。例如 -3 :代表%t 输出是以ms 为时间单位输出的,即 10-3 s = 1ms。具体数字所代表的含义,见表1
表1
| Unit number | Time unit | Unit number | Time unit |
| 0 | 1 s | -8 | 10 ns |
| -1 | 100 ms | -9 | 1 ns |
| -2 | 10 ms | -10 | 100 ps |
| -3 | 1 ms | -11 | 10 ps |
| -4 | 100 us | -12 | 1 ps |
| -5 | 10 us | -13 | 100 fs |
| -6 | 1 us | -14 | 10 fs |
| -7 | 100 ns | -15 | 1 fs |
- precision_number: 是指打印输出时, 小数点后保留多少位10进制数
- suffix_string: 后缀字符串, 可以增加 打印输出的时间单位。 例如 ” ps” ” ns” ” us” ” ms” 等。这样就不需要在 向 $display 等函数中额外添加时间单位了。
- minimum_field_width: 是指打印输出的时间值字符串+suffix_string 字符串的最小长度,如果时间值字符串+suffix_string 字符串 小于 minimum_field_width,则在时间值字符串+suffix_string字符串之前补空格。注:这个功能只对%t有效, 对于 %0t 无效。 它的作用是格式化输出, 使得上下行输出的结果都在同一列位置上。
2 举例说明
例1:时间单位设置: units_number
`timescale 1ns / 1ps
module timeformat_sim();
reg a = 0;
reg rst = 1;
initial
begin
#1;
$display("==== 1: simulation time = %t ====", $time);
$timeformat(-9,5," ns",10);
$display("==== 2: simulation time = %t ====", $time);
#10;
$timeformat(-6,5," us",10);
$display("==== 3: simulation time = %t ====", $time);
#30;
$timeformat(-3,5," ms",10);
$display("==== 4: simulation time = %t ====", $time);
#400;
$stop;
end
endmodule
仿真结果:
图1
根据图1 所示:
- 在没有使用$timeformat 之前打印 1 ,time = 1000 ,缺省的时间单位为 ps。原因: `timescale 1ns / 1ps
- 在设置$timeformat 时间精度为-9时, 打印2, time = 1.00000 ns 。 即10-9 秒
- 在设置$timeformat 时间精度为-6时, 打印3, time = 0.01100 us 。 即10-6 秒
- 在设置$timeformat 时间精度为-3时, 打印4, time = 0.00004 ms 。 即10-3 秒
例2:时间精度设置: precision_number
`timescale 1ns / 1ps
module timeformat_sim();
reg a = 0;
reg rst = 1;
initial
begin
#123456.789012;
$timeformat(-9,0," ns",10);
$display("==== 1: simulation time = %t ====", $time);
$timeformat(-6,3," us",10);
$display("==== 2: simulation time = %t ====", $time);
$timeformat(-3,6," ms",10);
$display("==== 3: simulation time = %t ====", $time);
$timeformat(-9,6," ns",10);
$display("==== 4: simulation time = %t ====", $time);
$timeformat(-9,6," ns",10);
$display("==== 5: simulation time = %t ====", $realtime);
#400;
$stop;
end
endmodule
仿真结果:
图2
从图2中可以看出:当时间精度为:
- 0:打印1;只有整数部分被输出。时间单位是ns
- 3:打印2;整数部分+小数点3位被输出。时间单位是us
- 6:打印3;小说部分输出6位。时间单位是ms
- 6:打印4;#123456.789012; 小数部分输出6位,但是小数部分全部为0,时间单位是ns, 使用$time 系统函数输出。
- 6:打印5;#123456.789012; 小数部分输出6位,但是小数部分全部为.789000,时间单位是ns,使用$realtime 系统函数输出。$realtime 可以根据当前仿真工程中的时间精度输出时间信息。
从打印4,5 可以看出 $time 系统函数只是输出当前仿真程序中的时间单位的整数部分;即:`timescale 1ns / 1ps。 使用系统函数 $realtime 可以输出当前时间单位的小数部分。
为什么打印5只显示123456.789000 而不是 123456.789012 呢? 可以使用新的`timescale 1ns / 1fs试试。主要看程序是否有必要使用更高的时间精度了。
例3:显示后缀设置:suffix_string
`timescale 1ns / 1ps
module timeformat_sim();
reg a = 0;
reg rst = 1;
initial
begin
#10;
$timeformat(-9,0,"",10);
$display("==== 1: simulation time = %t ====", $time);
$timeformat(-9,0,"abc",10);
$display("==== 2: simulation time = %t ====", $time);
$timeformat(-9,0,"KKK",10);
$display("==== 3: simulation time = %t ====", $time);
$timeformat(-9,0," ns",10);
$display("==== 4: simulation time = %t ====", $time);
#400;
$stop;
end
endmodule
仿真结果:
图3
从图3中可以看出:
- 打印1:可以没有后缀字符串。
- 打印2,3:可以是任意添加的字符串。
- 打印4:添加空格+有意义的字符串。帮助开发者理解当前的程序。
从这个例子,可以看出当使用$timeformat 设置好后缀字符串,就不必为每一个$display , $monitor 等等系统函数 单独添加时间单位后缀了。
例4:最小打印宽度设置minimum_field_width
`timescale 1ns / 1ps
module timeformat_sim();
reg a = 0;
reg rst = 1;
initial
begin
#10;
$timeformat(-9,3," ns",9);
$display("==== 1: simulation time = %t ====", $time);
$timeformat(-9,3," ns",10);
$display("==== 2: simulation time = %t ====", $time);
$timeformat(-9,3," ns",11);
$display("==== 3: simulation time = %t ====", $time);
$timeformat(-9,3," ns",12);
$display("==== 4: simulation time = %t ====", $time);
#400;
$stop;
end
endmodule
仿真结果:
图4
从图4中可以看出,当输出结果为10.000 ns 时,字符串一共含有9个字符(10 + . + 000 + 空格 + ns)。当使用minimum_field_width为:
- 9:$display 函数中 time = %t 等号之后没有额外添加空格。
- 10:$display 函数中 time = %t 等号之后没有额外添加1个空格。
- 11:$display 函数中 time = %t 等号之后没有额外添加2个空格。
- 12:$display 函数中 time = %t 等号之后没有额外添加3个空格。
注意:minimum_field_width这个参数在使用格式化输出为 %0t 时无效。
举例:$display(“==== 1: simulation time = %0t ====”, $time);
总体来说, 最小打印宽度参数主要是用来格式化打印输出的,防止
time = 1.000 ns time = 1000.000 ns time = 10.000 ns time = 100.000 ns
等数据在纵向上不对齐。使用较大的最小打印宽度设置,可以实现:
time = 1.000 ns time = 1000.000 ns time = 10.000 ns time = 100.000 ns
$timeformat 是Verilog 语言仿真中一个比较好用的工具函数, 没有使用这个系统任务, 也能完成相应的打印输出,但是在阅读的时候不是非常方便,使用$timeformat 系统任务,使得打印更加清晰,同时这个系统任务不会更改仿真时间单位和时间精度