文章目录
Verilog HDL语句
块语句
块语句分为两种:
- begin-end语句:顺序快;
- fork-join语句:并行快。
可以给块语句取名字,含名块的特点有:
- 有名块可以在快内定义局部变量;
- 有名块允许被其他语句调用;
- 有名块会降低仿真效率。
顺序块begin-end
- 顺序执行;
- 每条语句的延迟时间是相对于前一条语句的仿真时间的;
- 直到最后一句语句执行完,程序流程控制才跳出该语句块;
- 块内声明可以是parameter、reg、integer、real。
并行块fork-join
- 同时执行;
- 每条语句的延迟时间是相对于程序流程控制进入到块内的仿真时间的;
- 当时间顺序排在最后的语句执行完,或者一个disable语句执行时,结束;
- 块内声明可以定义为parameter、reg、integer、real、time、event。
赋值语句
阻塞赋值
- 语句执行完后块才结束;
- b的值在赋值语句执行完后立刻就改变;
- 边沿触发的always块中使用阻塞赋值可能产生意想不到的结果。
非阻塞赋值
- 块结束后才进行赋值操作;
- b的值不是立刻改变的;
- 时序逻辑常用的赋值方法。
体现了上一时刻状态在这一时刻起作用后得到这一时刻状态。
条件语句
if-else语句
if (...)
begin
end
else
begin
end
if (...)
begin
end
else if (...)
begin
end
else // else总是和上面最近的if配对,如果较为复杂的话,可以用begin-end来彰显配对关系
begin
end
case语句
- case括号内的表达式称为控制表达式,通常表示控制信号的某些位;case分支项的表达式称为分支表达式,常用控制信号的具体状态值表示,又称为常量表达式。
- 控制表达式和分支表达式值相等时就执行分支表达式后面的语句,若所有分支表达式值都不匹配,则执行default后面的语句;
- 控制表达式及分支表达式可不为常数表达式,可以在运行时计算;
- 可以没有default项,一个case里面只可以有一个default项;
- 每个case分支项的分支表达式的值需要互不相同,否则会矛盾;
- 执行完case分支项之后就跳出去了;
- case表达式进行比较时,x、z与0、1一样精确匹配,这与===是一样的;
- case语句所有表达式的值位宽应该一样;
- casex和casez是用于处理控制表达式和分支表达式含有x、z位的情况;casez用于处理不考虑高阻z的比较过程;casex用于处理x和z都不必考虑的过程。前者就是控制表达式中z可以是万能匹配的,常量表达式中的也同理。
循环语句
循环语句通常并不单独存在,一般在initial或者always中。
forever语句
常用于产生周期波形,作为仿真测试信号。与always语句不同之处在于它不能独立写在程序中,必须存在在initial块中(只执行一次)。
forever 语句;
forever
begin
语句;
end
repeat语句
repeat(表达式)语句;
repeat(表达式)
begin
语句;
end
表达式通常为常量表达式;
表达式表示的是循环的次数。
用repeat循环和加法和移位操作实现乘法器。
while语句
while(表达式) 语句;
while(表达式)
begin
语句;
end
用while循环语句对8位二进制数rega中的"1"进行计算。
for循环语句
结构说明语句
initial语句
initial语句和always语句是行为级建模的两种基本语句,其他的行为语句基本只能出现在这两种语句里面。
initial
begin
end
initial常用于测试文件和虚拟模块的编写。
所有的initial语句内的语句构成了一个initial块,initial块从仿真0时刻开始执行,在整个仿真过程中只执行一次。
如果一个模块中包括了若干个initial块,那么这些initial块从仿真0时刻开始并发执行。
always语句
always <时序控制> <语句>
always具有不断重复执行的特性,在构建时钟信号时,需要和一定的时序控制结合。这是一种仿真死锁的情形always areg = ~areg
,正确的写法是always #PERIOD areg = ~areg
。
initial和always的比较
- 一个程序模块可以有多个initial和always,它们是并发的;
- initial只执行一次,但always可以重复执行,直到仿真结束;
- always一直在检测触发条件。
task语句
task<任务名>;
<端口及数据类型说明语句>
<语句>
endtask
调用时
<任务名>(端口1,端口2,...)
- 任务完成后,控制就传回启动过程,若任务内部有定时控制,则启动的时间和任务返回的时间不同;
- 任务可以启动其他任务,任务数量没有限制,其他任务完成后,控制才能返回。
function语句
function <返回值类型或范围>(函数名)
<端口说明语句>
<变量类型说明语句>
begin
<语句>
end
endfunction
函数定义了蕴含由<返回值类型或范围>定义的、与函数同名的、函数内部的寄存器。
返回值类型默认为1位寄存器类型。
使用规则:
- 不能包含任何时间控制语句,即用#/@/wait标识的语句;
- 函数不能启动任务;
- 定义函数时至少需要有一个输入变量;
- 函数定义中必须有一条赋值语句给与函数同名的内部变量赋以结果值作为返回值。
function与task的区别
- 函数只能与主模块共用一个仿真时间单位,而任务可以定义自己的仿真时间单位;
- 函数不能启动任务,但任务可以启动其他任务或者函数;
- 函数至少有一个输入,任务可以没有;
- 函数需要返回一个值,任务是不返回值的,有点像指针;
系统任务
标准输出任务
$display和$write,前者输出后自动换行,后者不自动换行。
- 总是用表达式的最大可能占的位数来显示当前的值;
- 十进制输出时结果前面的0用空格代替,其他的进制结果的0仍然正常显示;
- 在格式控制字符的百分号和表示进制的字符之间插0可使输出数据宽度子动态哦中;
- 若表达式的所有位都是不定值或高阻,则输出结果为小写的x或z;如果只有部分的话,输出结果为大写的X或Z;
就是说,如果我一整个输出都是高阻或者未定的话,会给出StX,如果只是部分的话,会在那个位置给出X.
仿真结束任务
$finish:退出仿真器,回主操作系统;
$finish(n):n=0 不输出任何信息;n=1 输出当前仿真时刻和位置;n=2 输出当前仿真时刻,耗费内存和CPU时间。
$stop:暂停仿真,进入用户交互;
$stop(n);
可通过输入其他命令继续仿真状态
随机函数
$random; 给出有符号32位随机整数;
$random %b; 给出[-(b-1):(b-1)]有符号整数;
{$random}%b; 给出[0:(b-1)]有符号整数;
编译预处理
时间标定命令
`timescale<仿真时间单位>/<时间精度>
时间单位用于定义模块仿真时间和延迟时间基准单位,有效数字只能取1、10、100,时间单位有s、ms、us、ps、fs;
时间精度参数用于对延迟时间进行取整操作。
时间精度数值应该小于或等于时间单位值。