参考书籍:《Verilog HDL 数字设计与综合》第二版,本文档为第9章的学习笔记。
本章将探讨Verilog语言的另外一些增强特性
过程赋值将值赋给寄存器,值一直在寄存器中保存,知道另一个赋值语句存放该寄存器。
过程连续赋值允许有限时间段内将表达式的值连续地加(驱动)到寄存器或线网。
第一类过程连续赋值语句,在过程连续赋值语句的左边只能是一个寄存器或一个拼接的寄存器组,不可以是线网类型变量的部分 位选择、位选择或寄存器组。
过程连续赋值语句可以改写(覆盖)常用的过程赋值的结果。且一般只用于受控的一端时间内。
建议不要使用该种赋值语句。
assign q=1'b0; //代码运行过程中会一直给寄存器型变量q赋值。
deassign q; //取消给q一直赋值
第二类过程连续赋值语句,既可以改写(覆盖)寄存器上的赋值也可以改写(覆盖)线网上的赋值。多用于交互式调试过程,建议不要在设计模块的内部使用force和release语句,它们应只出现在激励中,或仅作为调试语句。
force q = 1'b1;
release q;
参数可以在模块定义内定义。但是,在Verilog模块编译过程中,参数值可以针对每个模块调用单独改变。
两种改变方式:通过defparam语句、通过模块调用参数赋值。
在设计中,可以通过关键字defparam在任意模块中改变参数,且可以通过层次名称引用来改变。
//实例
module hello_world;
parameter id_num = 0;
initial
$display("hello_world id number = %d", id_num);
endmodule
module top;
hello_world w1();
hello_world w2();
defparam w1.id_num = 1;
defparam w1.id_num = 2;
endmodule
ANSI C风格的参数声明
module hello_world
#(parameter id_num = 0)();
endmodule
module top
#(.id_num(5))();
endmodule
module bus;
parameter delay1 = 2;
parameter delay2 = 3;
parameter delay3 = 7;
...
endmodule
module top;
bus #(4,5,6) b1(); //b1:delay1=4,delay2=5,delay3=6
bus #(9,4) b2(); //b2:delay1=9,delay2=4,delay3=7(默认)
bus #(.delay1(4),delay2(7)) b3(); //b2:delay1=4,delay2=4,delay3=7(默认)
endmodule
可以在不同环境下编译不同的代码
`ifdef:满足条件时编译
`ifndef:没有定义时进行编译
`elsif:其他满足条件编译
`else:其他情况进行编译,与`ifdef搭配使用
`endif:用来结束条件编译
所有语句都可以被编译,但是有条件控制其执行。且仅仅能用于行为语句
关键字$test$plusargs用于条件执行,只有设置了标志DISPLAY_VAR才执行变量
if($test$plusargs("DISPLAY_VAR"))
$display("hello_world");
else
$display("END");
系统任务关键字$value$plusargs来进一步控制条件执行。该系统任务用于测试调用选项的参数值。如果没有找到匹配的调用选项,那么$value$plusargs返回0。如果找到了调用选项,那么返回非0值。
用法:`timescale
`timescale 10us / 1ns ; //参考时间单位:10us;时间精度:1ns。
只有1、10、100才是合法的说明时间单位和时间精度的整数
在第3节基本概念的博客中有简单说明
Verilog的结果通常输出到标准输出和文件verilog.log中。可以将Verilog的输出重新定向到选择的文件。
文件可以用系统任务$fopen打开
用法:$fopen("
用法:
任务$返回一个被称为多通道描述符的32位值,多通道描述符中只有1位被设置成1。标准输出有一个多通道描述符,其最低位(第0位)被设置成1,标准输出也成为通道0。标准输出一直是开放的,当每次调用$fopen则必有一位被设置成1,最多可以设置到第30位,第31位为保留位。通道号与设置的位号相对应。
系统任务$fdisplay , $fmonitoe , $fwrite , $fstrobe都用于写文件。
用法:$fdisplay(
用法:$fclose(
//文件写入操作
//打开相应的文件名的文件,并设置多通道描述符
integer handle1, handle2; //整形数为32位
//标准输出是打开的; descriptor = 32'h0000_0001(第0位置1)
initial begin
handle1 = $fopen("file1.out"); //handle1 = 32'h0000_0002(第1位置1)
handle2 = $fopen("file2.out"); //handle1 = 32'h0000_0004(第2位置1)
end
//写到文件中
integer des1, des2; //文件描述符
initial begin
des1 = handle1 | 1; //按位或,des1 = 32'h0000_0003
$fdisplay(des1,"Diaplay 1"); //将Diaplay 1写道文件file1.out中
des2 = handle1 | handle2;
$fdisplay(des2,"Diaplay 2"); //将Diaplay 2写道文件file2.out中
end
//关闭文件
$fclose(handle1);
在系统显示任务中$display , $write , $monitor , $strobe中使用%m选项,可以显示任何级别的层次。
//功能模块
module M;
...
...
initial $display("display in %m");
endmodule
//调用功能模块
module top;
...
M m1();
endmodule
仿真结果为:display in top.m1
因此通过上面例子可以显示完整层次路径名,如模块、任务、函数和命名块。
选通显示由关键字 $strobe来完成。该任务与$display类似,都用于显示。但是 $strobe是在同一时刻的其他赋值语句执行完才执行。如在同一上升沿既有赋值语句,又有显示语句。在该上升沿$display会调用赋值语句未执行的变量值,而$strobe会调用赋值语句执行结束的变量值。
用法:$random; //返回一个32位整数
$random(
$random % 60; //返回一个 -59 : +59的随机数
{$random} % 60; //返回一个 0 : +59的随机数
用法:$readmemb("
$redmemh语法与之相同
reg [7:0] memory [0:7]; //8个8位寄存器型变量
$readmemb("init.dat", memory); //把数据文件init.dat读入memory中
值变转储文件(VCD)是一个ASCII文件,包含仿真时间、范围与信号的定义以及仿真运行过程信号值的变化等信息。
这一部分并未深入学习,用到VCD时,会回来补充。