赞
踩
1)过程赋值将值付给寄存器并保存,过程连续赋值可以有限时间内将表达式的值连续地加到寄存器或线网。
关键字assign和deassign表示第一类过程连续赋值语句。其左边智能是寄存器或一个拼接的寄存器组,不能是线网。可以改写常用的过程赋值的结果,只用于受控制的一段时间。
例如
//具有异步复位端,由下降沿出发的D触发器
module edge_dff(q,qbar,d,clk,reset)
output q,bar;
inout d,clk,reset;
reg q,qbar;
always @(negedge clk) //基于事件的时序控制,clk负向跳变执行always
begin
q=d;
qbar = -d;
end
always @(reset) //当reset为高电平时,执行always,过程连续赋值
if(reset)
begin
assign q=1'b0;
assign qbar = 1'b1;
end
else
begin
deassign q;
deassign qbar;
end
endmodule
这个方法不实用
force和release表示过程连续赋值语句的第二种形式,改写寄存器上的赋值也可以改写线网的赋值。主要是交互调试中使用应当只出现在激励中或调试语句中。
module stimulus;
...
//调用(实例引用)该触发器
edge_dff dff(Q,Qbar,D,CLK,RESET);
...
initial
begin
#50 force dff.q = 1'b1; //在时间单位50时刻,q强制赋值为1
#50 release dff.q; //时间单位100时刻,释放q的赋值
end
...
endmodule
force改写任何连续赋值语句所赋的值,直到释放线网。线网被释放是将立即返回自己的正常驱动值。
module top;
...
assign out = a & b & c; //用连续赋值语句对线网变量out赋值
...
initial
#50 force out =a | b & c;
#50 release out;
end
...
endmodule
2)改写覆盖参数
通过defparam语句或模块调用参数赋值或通过调用参数赋值
defparam在人员模块调用中改变数值,模块调用的层次名称可以用在改写参数值的语句中。
//定义模块
module hello_world;
parameter id_num = 0;
initial
$display("Displaying hello_world id number = %d",id_num);
endmodule
module top
//defparam语句,改变引用的实例模块中的参数值
defparam w1.id._num =2;
hello_world w1();
hello_world w2();
endmodule
调用模块时可以改写其原来定义的参数值,使用关键字#
module top;
hello_world #(1) w1; //把1传递给w1
hello_world #(.id_num(2)) w2; //把参数值2传递给w2实例中id_num参数
endmodule
当模块里定义了多个参数,当调用模块时,可以按照模块中参数声明的顺序用指定 的新值改写它们。如果没有指定,则采用默认声明值。通过给参数名门和指定相应的值来改写相应参数。这种方法是参数按名赋值。
module bus_master;
patameter delay1 = 2;
parameter delay2 = 3;
parameter delay3 = 7;
...
endmodule
module
bus_master #(4,5,6) b1(); //新的参数赋值给b1中的delay1=4,delay2=5,delay3=6
bus_master #(9,4) b2(); //b2:delay1=9,delay2=4,delay3=7(采用默认的参数声明值)
//这种方式减少产生错误的机会
endmodule
3)条件编译和执行
Verilog代码中的一部分可能适用于某个编译环境,但不适用于另一个环境。如果设计者不想为两个环境创建不同版本的Verilog设计,另外的方法就是,设计者指定某一部分代码设置特定的标识才能被编译,这就是条件编译,也可以在运行中设置标识执行,就是条件执行。
编译指令‘ifdef,'ifdef,'else,'elsif,'endif
'ifdef TEST //如果设置TEST标识,就编译test模块
module test;
...
endmodule
’else //在默认情况下,编译stimulus
module stimulus
...
endmodule
‘endif //'ifdef语句的结束
module top;
bus_master b1();
'ifdef ADD_B2
bus_master b2(); //如果定义了ADD_B2文本标识,有条件的调用b2
'elsif ADD_B3
bus_master b3(); //如果定义了ADD_B3,就调用b3
'else
bus_master b4(); //默认情况下调用b4
'endif
'ifndef IGNORE_B5
bus_master b5(); //如果没有定义INGORE_B5,调用b5
'endif
endmodule
'ifdef,'ifndef可以出现任何地方,'else最多可以匹配一个’ifdef,‘ifndef。'endif作为结束,’一个‘ifdef,’ifndef可以匹配任意数量的‘elsif命令。
条件编译标识用'define语句设置,’ifdef不可以使用布尔表达式
条件执行,系统关键字$test$plusargs用于条件执行
module test;
..
initial
begin
if($test$plusargs("DISPLAY VAR"))
$display("Display = %b",(a,b,c)); //只有当标识设置时才能显示
else
$dispaly("No Display"); //其他情况不显示
end
endmodule
仅当在运行时标识DISPLAY_VAR时才显示变量。可以指定+DISPLAY_VAR选项在程序运行时设置标志
可以使用系统关键字$value$plusargs来进一步控制条件执行。该系统任务用于测试调用选项的参数值。如果没有找到匹配的调用选项,那么$value$plueargs返回0.如果找到了匹配的调用选项,那么$value$plusargs返回非0值。
4)时间尺度
'timescale编译指令为模块指定参考时间单位
'timescale <reference_time_unit> / <time_precision>
<reference_time_unit>(参考时间单位)指定时间和延迟的测量单位,<time_precision> (时间精度) 指定仿真过程中延迟值进位取整的精度。
//参考时间单位为100ns,精度为1ns
'module dummy1;
reg toggle;
//对toggle变量进行初始化
initial
toggle = 1'b0;
//每5个时间单位把toggle寄存器翻转一次
//本模块5个时间单位 = 500ns = 0.5us
always #5
begin
toggle =~tonggle;
$display("%d,In %m toggle =%b",$time,toggle);
end
endmodule
//为模块dummy2定义时间尺度
//参考时间单位为1us/10ns
module dummy2;
reg toggle;
//对toggle变量进行初始化
initial
toggle = 1'b0;
always #5
begin
toggle = ~toggle;
$display("%d,In %m toggle = %b",$time,toggle);
end
endmodule
5)常用系统任务
文件输出,显示层次,选通显示,随机数生成、内存初始化和值变转存储等的系统任务
文件输出
$fopen打开文件
$fopen("<name_of_file>");
<file_handle> = $fopen("<name_of_file>")
$fopen返回一个多通道描述符的32位值。多通道描述符中只有一位被设置成1.标注输出有一个多通道描述符,其最低位(第0位)被设置成1。标准输出也称为通道0.标准输出一直是开放的。
写文件
$display,$fmonltor,$fwrite,$fstrobe
$display(<file_descripr or>,p1,p2,...,pn);
$fmonitor(<file_descript_or>,p1,p2,...,pn);
关闭文件
$fclose
$fclose(<file_descriptor>);
文件一旦被关闭就不能再写入。多通道描述符中的相应位置被设置为0,$fopen调用可以重用这以为。
显示层次
利用任何显示任务,比如$display,$write,$monitor,$strobe任务中的%m选项,可以显示任何级别的层次。当一个模块的多个实例执行同一段代码时,%m选项会区分是哪个模块实例在进行输出。显示任务中的%m选项无需参数
选通显示
strobing由关键字$strong的系统任务完成。$strobe该语句总是在同一时刻的其他赋值语句执行完成之后执行。$strobe提供了一种同步机制,确保同一时钟沿赋值的其他语句在执行完毕之后才显示数据。
随机数生成
随机数生成功能满足了生成随机测试向量集的需求。随机测试非常重要。因为它经常发现设计中潜在的问题。随机向量生成也用于芯片体系结构的性能分析。系统任务$random用于生成随机数
//生成随机数,并把他们用到ROM的地址
module test;
integer r_seed;
reg [31:0] addr; //ROM地址
wire [31:0] data; //从ROM输出的数据
...
ROM rom1(data,addr);
initial
r_seed //随意定义随机数种子为2
always @(posedge clock)
addr = $random(r_seed); //产生随机数
...
<检查并核对ROM的输出是否符合预期的数值>
...
endmodule
用数据文件对存储器进行初始化
非常有用的系统任务来根据数据文件对存储器进行初始化。关键字$readmemb和$readmemh用于初始化存储器
$readmemb("<file_name>",<memory_name>);
$readmemb("<file_name>",<memory_name>,<start_addr>);
$readmemb("<file_name>",<memory_name>,<start_addr>,<finish_addr>);
$readmemh的语法与之相同
值变转储(VCD)是一个ASCII文件,包含仿真时间,范围与信号的定义以及仿真运行过程中的信号值的变化信息。设计中的所有信号或者选定的信号集合在仿真过程中都可以被写入VCD文件。后处理工具可以把VCD文件作为输入并把层次信息、信号值和信号波形显示出来。
对于大规模设计的仿真、设计者可以把选定的信号VCD文件中,并使用后处理调试、分析和验证仿真输出结果。对于大规模设计的仿真,设计者可以把选定的信号转储到VCD文件中,并使用后处理工具调试,分析和验证仿真输出结果。
模块实例或者模块实例信号($dumpvars),选择VCD文件的名称($dumpfile),选择转储过程的起点和终点($dumpon,$dumpoff),选择生成检测点($dumpall)。
//指定VCD文件名。若不指定VCD文件,则由仿真器指定一个默认文件名
initial
$dumpfile("myfile.dmp"); //仿真信息转储到myfile.dmp文件
initial
$dumpvars; //没有指定变量范围,把设计中的全部信号都转储
initial
$dumpvars(1,top); //转储模块实例top中的信号,1表示层次的等级只转储top下的第一层信号,即转储top模块中的变量,而不转储top中的调用模块的变量
initial
$dumpvars(2,top.m1); //转储top.m1模块一下两层的信号
initial
$dumpvars(0,top.m1); //0表示转储top.m1模块下面各个层的所有信号
//启动和停止转储过程
initial
begin
$dumpon //启动转储过程
#100000 $dumpoff; //过了1_000_000个时间单位后,停止转储
end
//生成一个检查点
initial
$dumpall;
总结
过程连续赋值语句用于改写(覆盖)寄存器和线网上的赋值。assign和deassign可以改写(覆盖)寄存器上的赋值。force和release可以改写(覆盖)寄存器和线网上的赋值。assign和deassign可以用在实际的设计中。force和release可以用在调试中
可以用在defparam语句或者在模块调用中传递新值来改写已在模块中定义的参数。在模块调用中,可以按参数列表的参数顺序或者名字关联的方式给参数赋值。推荐使用名字关联的方式给参数赋值
设计的某些代码可以通过使用'ifdef,'ifdef,'elsif,'else,‘endif等指令有条件的编译。编译时用'define语句定义编译标识。
Verilog仿真器中可以为写操作打开30个文件。在多通道描述符中为每个文件赋予1位。多通道描述符可用于写多个文件。
可以在任何显示语句中使用%m显示层次
选通显示是一种在某确定时刻或者由某件事出发的显示值的方式,其显示的执行安排在同时刻执行的其他语句都执行完毕之后进行。
使用系统任务$random生成随机数,用于生成随机测试向量。随机数可以是整数或负数。
存储器可以用数据文件的数据进行初始化,数据文件包含地址和数据,地址可以在存储器初始化指定。
值变转储文件是许多设计者处理工具中进行调试时使用的一种通用格式。Verilog可以将所有或者部分选定的模块变量转储到VCD文件中,多种系统任务可以用于此目的。
作业
1.使用assign和deassign语句,设计一个带异步clear(q = 0)和preset(q = 1)端口的由上升沿出发的D触发器
解:
module my_dff(q,d,clock,clear,preset);
output q;
input d,clock,clear,preset;
reg q;
always @(posedge clock)
begin
q=d;
end
always @(clear or preset)
if(clear)
assign q=1'b0;
else if(preset)
assign q=1'b1;
else
deassign q;
endmodule
然而Quartus II不支持报错,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。