reg Q;
always @(negedge Clk) 在Clk的下降沿把D赋给Q
Q = D; always @(Clr) begin
if(!Clr)
assign Q = 0; 如果clr为0,assign赋值使Q被赋值为0,然后Q就始终为0, else
deassign Q;
end endmodule
上面这段程序中,第一个always会在Clk的下降沿把D赋给Q,但是第二个always内的过程性连续赋值语句会使第一个always的赋值失效。在第二个always中,如果clr为0,assign赋值使Q被赋值为0,然后Q就始终为0,而不管Clk如何变化,即Clk和D对Q无效;等到Clr变为1时,deassign被执行,对Q的过程性连续赋值被取消。之后Clk才能对Q产生影响。换句话说,在Clr为0是,Q一直被assign所霸占,只有Clr为1时,才会把Q释放掉,从而才会受到D的影响。
·force-release
当force语句应用于寄存器时,寄存器的当前值被force语句的值覆盖;当release语句应用于寄存器时,寄存器中的当前值将保持不变,直到被赋予新值。来看两段代码:
reg[2:0] Colt; Colt = 2;
force Colt = 1; //Colt被强制赋值为1
release Colt //对Colt的强制赋值被取消,从现在起Colt将保持值为1 assign Colt = 5;
force Colt = 3; //被强制赋值为3
release Colt; //对Colt的强制赋值被取消,assign Colt = 5重新生效,使得Colt的值变为5 用force语句对线网赋值时,将为线网替换所有驱动源,直到那个线网上执行release语句为止。 wire prt;
or #1 (prt, Std, Dzx); //定义一个或门,线网prt的驱动源 由或门的结构给出 initial begin
force prt = Dzx & Srd; #5;
release prt; end
上面的程序中,执行force语句将替换ptr原来的驱动源,ptr将一直保持这些驱动源,直到release把对prt的强制赋值取消之后,或门的prt驱动源才重新生效。
3.2.5 if语句
对于if语句,如果某个分支内的过程语句多于一条,就应该把它们放在begin-end块内。这里的begin-end相当于C中的{}。
3.2.6 case语句
注意:在比较条件表达式和分支表达式的值时,如果值的某些位出现了x或z,那么这些x和z和0、1一样有意义,所以只要在两个值的相同位置出现x或z,就认为这两个值相同。
·casex和casez
在casez语句中,出现在条件表达式和任意分支项表达式中的值z被认为是无关值,出现z的那个位在比较时被忽略。在casex语句中,值x和z都被认为是无关位。所谓无关位即在比较时可以忽略的位,只要其它的位相匹配即可。
3.2.7 循环语句
(1)forever是个永远循环执行的语句,不需要声明任何变量,其语法格式如下: Forever procedural_statement
其中,procedural_statement是过程语句,若过程语句多于一条,则应该放在begin-end块内。注意:forever语句中必须有某种形式的时序控制,否则forever会在0时延后 永远重复执行过程语句。forever的最主要用途是产生周期性的波形作为仿真测试信号。
(2)repeat循环语句
repeat循环是个重复执行若干次数的语句,带有一个控制循环次数的常量或者变量,其语法形式如下: repeat(loop_count) procedural_statement
其中loop_count是控制循环次数的常数或变量;如果控制循环次数的常数或变量的值不确定(为x或z)时,那么循环次数按0处理。
Sum = repeat(Count) @ (posedge Clk) Sum+1; //首先计算出Sum+1的值,然后等待Clk上升沿,最后为左端赋值
repeat(4) @(negedge Clockz); //等待Clockz上出现4次下降沿之后,才能继续执行repeat之后的语句 (3)while循环语句 (4)for循环语句
4.case 语句
case 语句是一个多路条件分支形式(相当于c语言的switch语句)用法如下: case(case_expr)
case_item_expr{ ,case_item_expr} : procedural_statement . . .
. . .
[default: procedural_statement]
endcase
case 语句首先对条件表达式case_expr 求值,第一个与条件表达式值相匹配的分支中的语句被执行。 case (HEX)
4'b0001 : LED = 7'b1111001; // 1 4'b0010 : LED = 7'b0100100; // 2 default :LED = 7'b1000000; // 0 endcase
case 的缺省项必须写,防止产生锁存器。
以$字符开始的标识符表示系统任务或系统函数。
系统任务提供了一种封装行为的机制。这种机制可在设计的不同部分被调用。任务可以返回0个或多个值。系统函数除只能返回一个值以外与任务相同。此外,函数在0时刻执行,即不允许延迟,而任务可以带有延迟。
系统任务和系统函数可以分成以下几类:
1.输出控制类系统函数:模拟过程的状态信息以及模拟结果的输出都必须按一定的格式进行表示,:$display,$write,$minitor等。
2.模拟时标类系统函数:比如$time和$realtime等。
3.进程控制类系统任务:对模拟进程控制,有$finish,$stop等。 4.文件读写类系统任务:用于控制对数据文件读写方式,如$readmem。 5.其他类:比如随机数产生系统函数$random。
$display(“格式控制输出和字符串”,输出变量名表); 输出结束后自动换行, $write(“格式控制输出和字符串”,输出变量名表); 后者不会。 系统任务$monitor
和$display与$write一样,同属于输出控制类,它的调用形式可以有以下三种: $monitor(“格式控制输出和字符串”,输出变量名表); $monitoron; $monitoroff;
以上第一种的格式和上面的$display完全一致,不同点是,$display每调用一次执行一次,$monitor则一旦被调用,就会随着对输出变量名表中的每一个变量检测,如果发现其中任何一个变量在模拟过程中发生了变化,就会按照$monitor中的格式,产生一次输出。
通常情况下$monitor的输出中会用到一个系统函数$time,如: $monitor($time,,“signal1=%b signal2=%b”,signal1,signal2);
对$time的返回值也可以进行格式控制,如: $monitor (“%d signal1=%b signal2=%b ”,$time, signal1,signal2);
由于$monitor一旦被调用后就会启动一个后台进程,因而不可能在有循环性质的表达中出现,如always过程块或者其他高级程序循环语句, $monitor通常位于initial过程块的最开始处,
格式说明符 %h 或 %H %d或 %D %o或%O %b或 %B %c或 %C %s或 %S 输出格式 以十六进制的格式输出 以十进制的格式输出 以八进制的格式输出 以二进制的格式输出 以ASCII字符形式输出 以字符串方式输出 %v或 %V %t或 %T %m 或 %M %e或 %E %f 或 %F %g 或 %G
3.4.3系统函数$time和$realtime
输出连线型数据的驱动强度 输出模拟系统所使用的时间单位 输出所在模块的分级名 将实型量以指数方式显示 将实型量以浮点方式显示 将实型量以上面两种种较短的方式显示 $time和$realtime属于模拟时标类系统函数,将返回从模拟程序开始执行到被调用时刻的时间,不同之处在于$time
返回的是64位整数,而$realtime返回的是一个实型数。
例 `timescale 10ns/1ns module time_demo; reg parameter initial begin
end
$display (“time value”); $monitor($time,,,“var=%b”,var); //$time换成$realtime,没有四舍五入误差的问题。 #delay #delay #1000
var=1; var=0; $finish; ar;
delay=1.6
endmodule
系统时间定标为10ns为计时单位,所以delay=1.6实际代表的时间是16ns,
输出时间应该是1.6和3.2,可是实际输出时2和3,这是因为$time在返回时间变量时进行了四舍五入。 显示结果如下: time value 0 var=x
2 var=1 3 var=0 4 .
3.4.4系统任务$finish和$stop
控制模拟进程。
$finish; $finish(n);
它的作用就是中止仿真器的运行,结束仿真过程。可以带上一个参数,参数n只能取以下三个值: 0:不输出任何信息。
1:输出结束仿真的时间和模拟文件的位置。
2:在1的基础上增加对CPU时间、机器内存占用情况等统计结果的输出。
如果$finish不指明参数时,默认为1。
$stop的调用方式相同和$finish相同, 参数也相同。不同的是,$stop的作用只相当于一个pause的暂停语句,,这是设计人员可以输入相应的命令,对模拟过程进行交互控制,比如用force/release语句,对某些信号实行强制性修改,在不退出仿真进程的前提下,进行模拟调试。
3.4.6系统任务$random产生一个随机数,
$random %b,b>0,它将产生一个范围在(-b+1)到(b-1)之间的随机数。
测试模块提供随机脉冲序列,如: reg[7:0] always
#(140+($random `)) ran_num=$random `
这样ran_num的值在-59~+59之间随机产生,且随机数产生的延时间隔在81~159之间变化。
以`(反引号)开始的某些标识符是编译器指令。在Verilog 语言编译时,特定的编译器指令在整个编译过程中有效
3.5.1 `define 和`undef
`define指令用于文本替换,它很像C语言中的#define 指令,如:
`define MAX_BUS_SIZE 32
. . .
reg [ `MAX_BUS_SIZE - 1:0 ] AddReg;
`undef 指令取消前面定义的宏。例如:
`define WORD 16 //建立一个文本宏替代。 . . .
wire [ `WORD : 1] Bus;
. . .
`undef WORD // 在`undef编译指令后, WORD的宏定义不再有效. 3.5.2 `ifdef、`else 和`endif 条件编译, `ifdef WINDOWS
parameter WORD_SIZE = 16 `else
parameter WORD_SIZE = 32
`endif
在编译过程中,如果已定义了名字为WINDOWS的文本宏,就选择第一种参数声明,否则选择第二种参数说明。`else 程序指令对于`ifdef 指令是可选的。
3.5.3 `default_nettype指定隐式线网类型,为那些没有被说明的连线定义线网类型。
`default_nettype wand 该实例定义的缺省的线网为线与类型。因此,如果在此指令后面的任何模块中没有说明的连线,那么该线网被假定为线与类型。
3.5.4 `include 嵌入内嵌文件的内容。
文件既可以用相对路径名定义,也可以用全路径名定义, 例如:
`include \
编译时,这一行由文件“../../primitives.v” 的内容替代。
`timescale time_unit / time_precision
time_unit 和time_precision 由值1、10、和100以及单位s、ms、us、ns、ps和fs组成。例如:
`timescale 1ns/100ps
表示时延单位为1ns, 时延精度为100ps。`timescale在模块说明外部出现, 并且影响后面所有的时延值。例如: and # (5.22, 6.17 ) Al (Z, A, B);
ran_num;