系统任务

$display和$write

$display系统任务输出信息到标准输出设备,并带有行结束字符;$write系统任务输出信息到标准输出设备,不带行结束字符。

可以用类似C语言格式化输出的方式打印文本。

格式化输出 特殊字符

例1

1
2
3
4
5
6
module disp;
initial
begin
$display("\\\t%%\n\"\123") ;
end
endmodule
答案
1
2
\	%
"S

\123的意思是123代表的八进制数对应的ASCII码代表的字符

例2

1
2
3
4
5
6
module disp;
initial begin
$display("\\%%\123\n\456");
end
endmodule

答案
1
2
\%S
.

$display输出列表中数据的显示宽度是自动按照输出格式进行调整的。总是用表达式的最大可能值所占的位数来显示表达式的当前值。可以通过在%和表示进制的字符中间插入一个0,来自动调整显示输出数据宽度的方式。

冷门点,多看看。

对于不定态和高阻态:

  • 十进制格式下
    • 全部为X值,则显示小写的x字符
    • 全部为高阻,则显示小写的z字符
    • 部分为X值,显示大写的X字符
    • 部分为高阻,显示大写的Z字符
  • 十六进制格式下(或者8进制下)
    • 一个值全部为X,则显示小写x,一个值对应4位(3位,8进制)
    • 一个值全为高阻,则显示小写的z
    • 一个值部分位为不定态,则显示大写X字符
    • 一个值部分为高阻,则显示大写Z字符
  • 二进制格式,每一位都以0,1,x,z显示
1
2
3
4
5
6
7
8
$display(“%d”, 1’bx);
$display(“%h”, 14’bx01010);
$display(“%h %o”, 12’b001xxx101x01, 12’b001xxx101x01);
/* 输出
x
xxXa
XXX 1x5X
*/

$strobe:时序电路的好帮手

选通显示(Strobing )由关键字为 $strobe的系统任务完成。这个任务与 $display任务除了一点小差异外,其他非常相似。

如果许多其他语句与 $display任务在同一个时间单位执行,那么这些语句与$display任务的执行顺序是不确定的。

如果使用 $strobe,该语句总是在同时刻的其他赋值语句执行完成之后才执行。因此, $strobe提供了一种同步机制,它可以确保所有在同一时钟沿赋值的其他语句在执行完毕之后才显示数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
`timescale 1ns / 1ns
module test;
reg clk;
reg [2:0] d;

initial begin
clk = 0;
d = 0;
forever #10 clk = ~clk;
#100 $finish;
end

always @(posedge clk) begin
d <= d + 1;
end

always @(posedge clk) begin
$strobe(" Strobe\tDisplaying d = %d", d);
$display(" Display\tDisplaying d = %d", d);
$monitor(" Monitor\tDisplaying d = %d\n", d);
end

endmodule
1
2
3
4
5
6
7
8
9
10
11
12
Display	Displaying d = 0
Strobe Displaying d = 1
Monitor Displaying d = 1

Display Displaying d = 1
Strobe Displaying d = 2
Monitor Displaying d = 2

Display Displaying d = 2
Strobe Displaying d = 3
Monitor Displaying d = 3
...

为什么会这样?

和Verilog中的事件队列有关。

有关事件队列的内容,请查看后续笔记:

数字系统设计复习笔记:第九篇

$strobe和$monitor

  • $strobe和$monitor监测的相关变量的值,都是这些变量在当前时间槽中的最终稳定值
  • $strobe只有在被调用时才会对其中的参数进行监测,而$monitor只要监测的参数发生变化,$monitor就会执行
  • 代码中可以存在多个$strobe,并且多个$strobe的调用相互之间不影响
  • 在$strobe和$monitorr中,如果监测的参数是$time、$stime和$realtime这些系统函数的返回值,$strobe和$monitor对这些时间参数的变化并不敏感
  • 在任意仿真时刻,只有一个$monitor系统任务处于激活执行状态,至于多个$monitor执行的顺序,一般则取决于哪一个$monitor最近一次被调用
  • 可以通过$monitoroff和$monitoron对$monitor的执行进行监测

$dumpfile和$dumpvars

没啥好说的,生成vcd文件。

$dumpvars (1,top)

1表示层次等级,只转储top下第一层信号,即转储top模块中的变量,而不转储在top中调用模块中的变量。

$monitor

任务$monitor提供了监控和输出参数列表中的表达式或变量值的功能。

当启动一个带有一个或多个参数的$monitor任务时,仿真器则建立一个处理机制,使得每当参数列表中变量或表达式的值发生变化时,整个参数列表中变量或表达式的值都将输出显示。

在时序电路中,效果和$strobe应该是一样的。

$time和$realtime

用这两个时间系统函数可以得到当前的仿真时刻。

$realtime$time的作用是一样的,只是$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的。

$finish和$stop

总有人把$stop当成$finish用然后问老师为什么命令行卡在>>退出不了仿真😇

$finish的作用是退出仿真器,返回主操作系统,也就是结束仿真过程;$stop的作用是把 EDA 工具(例如仿真器)置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户。这个任务可以带有参数表达式。

题外话

有个傻子忘写$finish结果开了一堆仿真把CPU卡到98%
我不说是谁

$random

$random一般的用法是: $random %b,其中 b>0 。它给出了一个范围在( -b+1 ):(b-1 )中的随机数。

下面给出一个产生随机数的例子:

[ 23 : 0 ] rand ;
1
2
reg [23:0] rand ;
rand = $random %60 ;

上面的例子给出了一个范围在 -59~59 之间的随机数。

那要是想生成一个正数该怎么办?

1
2
reg [23:0] rand ;
rand = {$random} %60 ;

预编译处理

感觉看看宏定义就行了,这个调试的时候很方便。

timescale应该会考吧

`timescale

timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用timescale命令可以在同一个设计里包含采用了不同的时间单位的模块。例如,一个设计中包含了两个模块,其中一个模块的时间延迟单位为纳秒(ns ),另一个模块的时间延迟单位为皮秒(ps)。EDA 工具仍然可以对这个设计进行仿真测试。

timescale <时间单位> / <时间精度>

时间精度必须小于等于时间单位,否则会报错。

请仔细阐述timescale编译预处理的作用?不同timescale定义的多模块仿真测试时需要注意什么?

答案

timescale是一个编译预处理指令,用于定义时间单位和时间精度。

不同模块仿真测试,要注意每个模块内的timescale定义是否一致。若不一致,在传递信号时,可能会让信号长度发生变化。因此应当在一开始就确定所有模块的时间单位和精度,并在设计过程中保持一致。

条件编译

1
2
`ifdef
`endif

这些命令可以出现在源程序的任何地方。