系统任务
1.系统任务$monitor
$monitor提供了监控和输出参数列表中表达式或变量值的功能。其参数列表中输出格式规则与$display一样。与$display的区别是,$display只运行一次,而$monitor每当参数列表中的变量或者表达式的值发生变化时,$monitor语句都会执行一遍,如果同一时刻,两个或更多的参数值发生变化,则在该时刻只输出显示一次。
$monitoron和$monitoroff任务的作用是通过打开和关闭监控标志来控制监控任务$monitor的启动和停止。通常在通过调用$monitoron来启动$monitor时,不管$monitor参数列表中的值是否发生变化,总是立刻输出显示当前时刻参数列表中的值,这用于在监控的初始时刻设定初始比较值。
如:
$monitor(“led status is %d”,led);//每当led的状态发生变化时,就会输出一次led的值
2.时间度量系统函数$time
系统时间函数通常有 t i m e 和 time和 time和realtime,通过这两个函数可以得到当前的仿真时刻。
2.1 系统函数$time
$time返回一个64位整数,表示当前仿真时刻值。该时刻是以模块的仿真时间尺度为基准的。
如:
`timescale 10ns/1ns
module test;
reg set;
parameter p = 1.6;
initial
begin
$monitor($time,,"set=",set);
#p set=0;//$time总是输出整数,1.6取整后值为2;实际执行时间为16ns=-1.6*10ns,因为时间尺度单位为10ns
#p set=1;//3.2取整后值为3,实际执行时间为32ns=3.2*10ns
end
endmodule
输出结果为:
0 set=x
2 set=0
3 set=1
2.2 系统函数$realtime
r
e
a
l
t
i
m
e
和
realtime和
realtime和time的作用是一样的,只是$realtime返回的时间数字是一个实型数,该数字也是以时间尺度为基准的。
如:
`timescale 10ns/1ns
module test;
reg set;
parameter p = 1.6;
initial
begin
$monitor($realtime,,"set=",set);
#p set=0;//$time总是输出整数,1.6取整后值为2;实际执行时间为16ns=-1.6*10ns,因为时间尺度单位为10ns
#p set=1;//3.2取整后值为3,实际执行时间为32ns=3.2*10ns
end
endmodule
输出结果为:
0 set=x
1.6 set=0
3.2 set=1
3.系统任务$finish
格式:
$finish;
$finish(n);
系统任务$finish的作用是退出仿真器,返回主操作系统,即结束仿真过程。$finish可以带参数,根据参数的值输出不同的特征信息。不带参数的情况下,默认$finish的参数值为1。
$finish的参数值有以下几种:
- 0:不输出任何信息;
- 1:输出当前仿真时刻和位置;
- 2:输出当前仿真时刻、位置和仿真过程中所用memory及CPU时间的统计。
4.系统任务$stop
格式:
$stop;
$stop(n);
$stop任务的作用是把仿真器置成暂停模式,在仿真环境下,给出一个交互式的命令提示符,将控制权交给用户。这个任务可以带有参数表达式。根据参数值(0,1,2)的不同,输出不同的信息。参数值越大,输出的信息越多。
5.系统任务$readmemb和$readmemh
系统任务 r e a d m e m b 和 readmemb和 readmemb和readmemh用来从文件中读取数据到存储器中。这两个系统任务可以在仿真的任何时刻被执行使用,其格式如下:
- $readmemb(“数据文件名”,存储器名);
- $readmemb(“数据文件名”,存储器名,起始地址);
- $readmemb(“数据文件名”,存储器名,起始地址,结束地址);
- $readmemh(“数据文件名”,存储器名);
- $readmemh(“数据文件名”,存储器名,起始地址);
-
r
e
a
d
m
e
m
h
(
"
数据文件名
"
,
存储器名
,
起始地址
,
结束地址
)
;
在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置,注释行,二进制或十六进制的数字。对于
readmemh("数据文件名",存储器名,起始地址,结束地址); 在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置,注释行,二进制或十六进制的数字。 对于
readmemh("数据文件名",存储器名,起始地址,结束地址);在这两个系统任务中,被读取的数据文件的内容只能包含:空白位置,注释行,二进制或十六进制的数字。对于readmemb系统任务,每个数字必须是二进制数字;
对于$readmemh系统任务,每个数字必须是十六进制数字;
另外,数字必须用空白位置或注释行来分隔开。
当数据文件被读取时,每一个被读取的数字都被存放到连续的存储器单元中去。存储器单元的存放地址范围由系统任务声明语句中的起始地址和结束地址来说明,每个数据的存放地址在数据文件中进行说明。当地址出现在数据文件中,其格式为字符“@”+十六进制数。如:
@hh…h
对于@后面的十六进制数,可以是大写或小写的数字。在@与数字之间不允许存在空白位置。在数据文件中可以出现多个地址。当系统任务遇到一个地址说明时,系统任务将该地址后的数据存放到存储器中相应的地址单元中去。
如:
module test;
reg [7:0] memory[7:0];//声明有8个8位的存储单元
integer i;
initial
begin
$readmemb("init.dat",memory);//读取存储器文件init.dat的内容到memory中
//显示初始化后的存储器内容
for(i=0;i<8;i=i+1)
$display("memory[%d]=%b",i,memory[i]);
end
endmodule
文件init.dat包含初始化数据。用“@+地址”在数据文件中制定地址,地址以十六进制数说明。数据用空格符隔开,数据可以包含x或z,未初始化的位置默认值为x,init.dat的样本文件内容如下所示:
@002
11010000 01011101
00000001 10100001
@006
1111zzzz 0000xxx1
仿真测试模块结束后,输出如下:
memory[0]=xxxxxxxx
memory[1]=xxxxxxxx
memory[2]=11010000
memory[3]=01011101
memory[4]=00000001
memory[5]=10100001
memory[6]=1111zzzz
memory[7]=0000xxx1
- tips:
- 若系统任务声明语句中和数据文件中都没有进行地址说明,则默认的存放起始地址为该存储器定义语句中的起始地址。数据文件中的数据被连续存放到该存储器中,直到该存储器单元存满为止或数据文件中的数据存完。
- 若系统任务中仅说明了存放的起始地址,那么数据从起始地址开始存放,存放到该存储器定义语句中的结束地址为止。
- 若系统任务声明语句中,说明了存放的起始地址和结束地址,则数据文件中的数据按该起始地址开始存放,直至该结束地址,而不考虑该存储器中定义语句的起始地址和结束地址。
- 若地址信息在系统任务和数据文件中都进行了说明,则数据文件里的地址必须在系统任务中地址参数声明的范围之内。否则将提示错误信息,并且装载数据到存储器中的操作被中断。
- 若数据文件里的数据个数和系统任务中起始地址及结束地址范围内的数据个数不同的话,也会提示错误信息。
如:
reg [7:0] mem[1:256];
initial $readmemh(“mem.data”,mem);//装载数据以地址为1的存储器单元开始存放数据
initial $readmemh(“mem.data”,mem,16);//装载数据以地址为16的存储器单元开始存放数据
initial $readmemh(“mem.data”,mem,128,1);//从地址128单元开始装在数据,直到地址为1的单元,装在完毕,系统要检查数据文件中是否有128个数据,如果没有,系统将提示错误信息。
6.系统任务$random
$random用于产生一个随机数,当函数被调用时返回一个32位的随机数,是一个带符号的整形数。
用法为:
$random %b;
其中,b>0,随机数的范围为(-b+1)-(b-1)。
如(1):
reg[23:0] rand;
rand = KaTeX parse error: Expected '}', got 'EOF' at end of input: … rand; rand = {random} % 60;//rand的取值为0~59。
7.编译预处理
verilog中预处理命令以符号“`”开头。
(1)宏定义`define
用一个指定的标识符来代表一个字符串,用法如下:
`define 标志符(宏名) 字符串(宏内容)
如:
`define SIGNAL string
作用是指定用标志符SIGNAL来替换string字符串,在编译预处理时,会把程序中所有的SINGNAL都替换为string。
如:
`define WORDSIZE 8
module
reg [1:WORDSIZE] data;//等价于reg[1:8] data;
关于宏定义的特点:
- 宏名一般用大写字母表示,与变量名相区别。
- `define命令可以出现在模块定义里面,也可以在模块定义外面,宏名的有效范围为定义命令之后到原文件结束。
- 在引用已定义的宏名时,必须在宏名前面加上符号`。
- 使用宏名代替一个字符串,可以减少程序中重复书写字符串的工作量。
- 宏定义是用宏名代替一个字符串,只做简单的置换,不做语法检查。
- 宏定义不是verilog HDL语句,不必再行末加分号。
- 宏名和宏内容必须在同一行中进行声明。
如:
module test;
reg a,b,c,d,e,out;
`define expression a+b+c+d
assign out = `expression + e;
...
endmodule
8.“文件包含”处理`include"
“文件包含”指的是将一个源文件的全部内容包含进另一个文件中。
verilog HDL提供了`include命令来实现“文件包含”的操作,形式为:
`include “文件名”
如:
(1)文件aaa.v
module aaa(a,b,out);
input a,b;
output out;
wire out;
assign out = a^b;
endmodule
(2)文件bbb.v
`include "aaa.v"
module bbb(c,d,e,out);
input c,d,e;
output out;
wire out_a;
wire out;
aaa aaa(.a(c),.b(d),.out(out_a));
assign out = e & out_a;//等价与out=e&(c^d);
endmodule
9.时间尺度`timescale
`timescale命令用来说明模块内部所使用的时间单位和时间精度。
格式如下:
`timescale 时间单位/时间精度
其中,时间单位用来定义模块中仿真时间和延迟时间的基准单位,时间精度用来声明该模块的仿真时间的精确程度,该参量被用来对延迟时间值进行取整操作,因此该参量又被称为取整精度。
如果在同一个程序设计里,存在多个`timescale命令,则用最小的时间精度值来决定仿真的时间单位。另外,时间精度值不能大于时间单位值。
在`timescale命令中,用于说明时间单位和时间精度的参量值必须是整数,其有效数字为1,10,100,单位为秒(s)、毫秒(ms)、微秒(μs)、纳秒(ns)、皮秒(ps)、飞秒(fs)。这几种单位的关系如下:
时间单位 | 定义 |
---|---|
s | 秒(1s=1000ms) |
ms | 毫秒(1ms=1000μs) |
μs | 微秒(1μs=1000ns) |
ns | 纳秒(1ns=1000ps) |
ps | 皮秒(1ps=1000fs) |
fs | 飞秒(1fs) |
如: |
`timescale 10ns/1ns
module test;
reg set;
parameter d =1.55;
initial
begin
#d set =0;//延迟时间为1.6*10=16ns,注:精度为1ns,1.55*10ns=15.5ns,故向上取整为16ns
#d set = 1;//延迟时间为32ns
end
endmodule
10.条件编译命令`ifdef、`else、`endif
一般情况下,verilog HDL源程序中所有行都将参加编译,但有时希望对其中一部分内容只有在满足条件时才进行编译,这就是“条件编译”。即当满足一定条件时,对一组语句进行编译,否则编译另一组语句。
格式如下:
`ifdef 标志符(宏名)
程序段1
`else
程序段2
`endif
此代码作用是当宏名已经被定义过(使用`define命令定义),则对程序段1进行编译,否则编译程序段2,其中`else部分可以没有,即:
`ifdef 标志符(宏名)
程序段1
`endif
如:
`ifdef TEST
module test;
initial
$display("module %m is complied");
`else
module stimulus;
initial
$display("module %m is complied");
endmodule
`endif
11.条件执行
条件执行标志允许设计者在运行时控制语句执行的流程,所有语句都被编译,但是有条件地执行它们。条件执行标志仅能用于行为语句,系统任务关键字
t
e
s
t
test
testplusargs用于条件执行。
如:
module test;
reg a,b,c;
initial
begin
a=1'b1;b=1'b0;c=1'b1;
if($test$plusargs("DISPLAY_VAR"))//仅当运行时设置了标志DISPLAY_VAR时才显示变量
$display("display=%b",{a,b,c});//其他情况下不显示
else
$display("no display");
end
endmodule