原文网站: Verilog testbench编写进阶(3)–$strobe,$write – 芯片天地
在前面的几节课程中, 我们介绍了$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
控制台输出: