Menu Close

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

控制台输出:

%title插图%num

 

 

Posted in FPGA, FPGA, Verilog, Verilog, 开发语言, 教材与教案, 文章
0 0 投票数
Article Rating
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论

相关链接