在前面的几节课程中, 我们介绍了$display,$monitor 系统任务,本文介绍的$strobe任务也是激励文件中经常使用的系统任务,它可以很好的帮助我们观察运行结果,定位运行中出现的问题。需要注意的是$strobe任务只能用在仿真程序中,是不可综合的任务,因此不能在实体程序中使用。$strobe 任务的使用方法和$display非常类似,但是他们之间还是有些不同的。两者的区别在于:$strobe命令会在当前时间结束时执行;而$display是只要仿真器看到就会立即执行。
1.$strobe
$strobe系统任务和$display 系统任务的语法基本上是相同的。$strobe 也是在控制台窗口下,打印输出。 它是在当前的时间点结束时执行,而不是解析到当前的$strobe 立即执行。
$strobe(“字符区” ,表达式1,表达式2,...);
例1:首先,我们使用$display 做一个仿真程序
`timescale 1ns / 1ps module tb_dis (); reg [3:0] a,b; wire [4:0] y = a + b; initial begin a = 3; b = 2; $display("$display: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 4; $display("$display: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); b = 5; $display("$display: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 3; b = 7; $display("$display: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 2; b = 6; $display("$display: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); end endmodule
在modelsim transcript 窗口列表显示如下:
# $display: time = 0, a= 3, b= 2, y= x
# $display: time = 10, a= 4, b= 2, y= 5
# $display: time = 10, a= 4, b= 5, y= 5
# $display: time = 20, a= 3, b= 7, y= 9
# $display: time = 30, a= 2, b= 6, y= 10
我们会发现,仿真程序中在10ns 的位置使用$display 打印输出了两次,第一次时,a = 4,b的值保持0ns 的值; 第二次时,a = 4,b = 5值;这说明$display 对已经执行过的赋值都能正确打印出来,但对于 y = a+b 并没有将其计算的结果输出出来 。
例2:使用$strobe 测试阻塞赋值
`timescale 1ns / 1ps module tb_dis (); reg [3:0] a,b; wire [4:0] y = a + b; initial begin a = 3; b = 2; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 4; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); b = 5; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 3; b = 7; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 2; b = 6; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); end endmodule
测试结果如下:
# $strobe: time = 0, a= 3, b= 2, y= 5
# $strobe: time = 10, a= 4, b= 5, y= 9
# $strobe: time = 10, a= 4, b= 5, y= 9
# $strobe: time = 20, a= 3, b= 7, y= 10
# $strobe: time = 30, a= 2, b= 6, y= 8
同样,我们只是改造上面的仿真程序, 将$display 替换为 $strobe 任务, 发现在10ns 位置也是打印两次, 这两次打印的结果相同。表明 当10ns结束时,$strobe 才进行的打印,这时: a = 4, b =5 ,同时将 y = a + b 的值也是计算完后,才打印输出的。
例2:使用$strobe 任务测试非阻塞赋值
`timescale 1ns / 1ps module tb_dis (); reg [3:0] a,b; wire [4:0] y = a + b; initial begin a <= 3; b <= 2; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a <= 4; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); b <= 5; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a <= 3; b <= 7; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a <= 2; b <= 6; $strobe("$strobe: time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); end endmodule
控制台输出结果:
# $strobe: time = 0, a= 3, b= 2, y= 5 # $strobe: time = 10, a= 4, b= 5, y= 9 # $strobe: time = 10, a= 4, b= 5, y= 9 # $strobe: time = 20, a= 3, b= 7, y= 10 # $strobe: time = 30, a= 2, b= 6, y= 8
同样, 我们会发现: 不论是阻塞赋值还是非阻塞赋值, $strobe 都是在当前时间点结束时,打印输出结果。
从上面演示的例子可以看出,当打印输出连续赋值语句或module例化的输出结果时,在当前的时间点内,$display无法输出当前运算结果,但 $strobe却可以显示组合逻辑结果。因此, 如果希望在当前时间点内打印连续赋值语句或module例化的输出结果推荐使用$strobe, 而其他情况下使用$display可以显示更多的细节。
2.$write
$write系统任务和$display 系统任务的语法基本上是相同的。$write和$display 的区别是$write 在打印输出时,没有换行的操作。
$write(“字符区” ,表达式1,表达式2,...);
例4:将例1 改造为$write 打印输出:
`timescale 1ns / 1ps module tb_dis (); reg [3:0] a,b; wire [4:0] y = a + b; initial begin a = 3; b = 2; $write ("$write : time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 4; $write ("$write : time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); b = 5; $write ("$write : time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 3; b = 7; $write ("$write : time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); #10 a = 2; b = 6; $write ("$write : time =%05d, a= %d, b=%d, y= %d ",$time ,a, b, y); end endmodule
控制台输出的结果为:
$write: time = 0, a= 3, b= 2, y= x $write: time = 10, a= 4, b= 2, y= 5 $write: time = 10, a= 4, b= 5, y= 5 $write: time = 20, a= 3, b= 7, y= 9 $write: time = 30, a= 2, b= 6, y= 10
这里我们看到使用$write 任务打印输出时,没有回车,换行的操作,在同一行内打印所有输出结果。
例5:将例1 改造为$write 任务 (手工添加换行)打印输出:
`timescale 1ns / 1ps module tb_dis (); reg [3:0] a,b; wire [4:0] y = a + b; initial begin a = 3; b = 2; $write ("$write : time =%05d, a= %d, b=%d, y= %d \n",$time ,a, b, y); #10 a = 4; $write ("$write : time =%05d, a= %d, b=%d, y= %d \n",$time ,a, b, y); b = 5; $write ("$write : time =%05d, a= %d, b=%d, y= %d \n",$time ,a, b, y); #10 a = 3; b = 7; $write ("$write : time =%05d, a= %d, b=%d, y= %d \n",$time ,a, b, y); #10 a = 2; b = 6; $write ("$write : time =%05d, a= %d, b=%d, y= %d \n",$time ,a, b, y); end endmodule
控制台输出的结果为:
# $write: time = 0, a= 3, b= 2, y= x # $write: time = 10, a= 4, b= 2, y= 5 # $write: time = 10, a= 4, b= 5, y= 5 # $write: time = 20, a= 3, b= 7, y= 9 # $write: time = 30, a= 2, b= 6, y= 10
当手工添加\n后, 打印输出的结果和$display相同了。
3.格式化输出列表
%h或%H | 以十六进制的形式输出 |
%d或%D | 以十进制的形式输出 |
%o或%O | 以八进制的形式输出 |
%b或%B | 以二进制的形式输出 |
%c或%C | 以ASCII码字符的形式输出 |
%s或%S | 以字符串的形式输出 |
%t或%T | 以当前的时间格式的形式输出 |
%e或%E | 以指数的形式输出实型数 |
%f或%F | 以十进制的形式输出实型数 |
%g或%G | 以指数或者十进制的形式输出实型数,无论何种格式都以较短的结果输出 |
%x | 十六进制 |
%u | 十六进制 |
\n | 换行 |
\t | 相当于按一个Tab键 |
\\ | 反斜杠字符\ |
\” | 双引号字符” |
%% | 百分符号% |
1、格式说明,由”%”和格式字符组成。它的作用是将输出的数据转换成指定的格式输出。格式说明总是由”%”字符开始的。
2、普通字符,即需要原样输出的字符。其中包括一些转义字符,下面的字符形式用于格式字符串参数中,用来显示特殊的字符。
在 Verilog 中, 转义符 一定是使用在双引号括起来的字符串中!
举例:
`timescale 1ns / 1ps //`define VIVADO_ONLY module tb_dis (); localparam WIDTH = 8; real r; integer i; reg [WIDTH - 1:0] a,b,c; wire [WIDTH:0] y = a + b; initial begin a = 2; b = 5; c = 9; $display("===> display print format testing.... <==="); #10; $strobe ("$strobe: time =%05d, a= %h, b=%d, c=%o, y= %b ",$time ,a, b, c, y); #10; $strobe ("$strobe: time =%05d, a= %H, b=%D, c=%O, y= %B ",$time ,a, b, c, y); #10; $strobe ("$strobe: time =%05d, char = %c, char = %C ",$time ,"M", "q"); #10; $strobe ("$strobe: time =%05d, %s, %S ",$time , "Hello World !", "Hello World !"); #10; $strobe ("$strobe: time =%t, %T ",$time ,$time); #10; r = 31415.926; $strobe ("$strobe: time =%05d, r = %e, r = %E ",$time ,r, r); #10; r = 31415.926; $strobe ("$strobe: time =%05d, r = %f, r = %F ",$time ,r, r); #10; r = 31415.926; $strobe ("$strobe: time =%05d, r = %g, r = %G ",$time ,r, r); #10; $strobe ("$strobe: time =%05d, a = %x",$time , r); #10; a = 33; b = 'o47; c = 8'hfe; i = -56; $strobe ("$strobe: time =%05d, a = %u, b = %u, c = %u",$time , a, i, c); #10; $strobe ("$strobe: time =%05d, Hello \n World !", $time); #10; $strobe ("$strobe: time =%05d, \t\t\tHello World !", $time); #10; $strobe ("$strobe: time =%05d, \\Hello World !\\", $time); #10; $strobe ("$strobe: time =%05d, \"Hello World !\"", $time); #10; $strobe ("$strobe: time =%05d, Hello World ! 100%%", $time); #10; $display("===> display print format test finished. <==="); #10; end /* addab #(.WIDTH (WIDTH)) addab_inst ( .a (a), .b (b), .y (y) ); */ endmodule
控制台输出: