在此,<参数列表>是传输到模块实例的参数值。参数传递的典型应用是定义门级延迟,在1.7.1小节将有详细的说明。
下面是一个高层模块的例子,在这一模块中设置了测试数据并对变量进行监测。
//测试以上两个模块的高层模块
module test_AND;
reg a, b;
wire out1, out2;
initial begin //测试数据
a = 0; b = 0;
#1 a = 1;
#1 b = 1;
#1 a = 0;
end
initial begin //设置监测功能
$monitor (“Time=%0d a=%b b=%b out1=%b out2=%b”, $time, a, b, out1, out2);
end
//模块AND和NAND实例
AND gate1(a, b, out2);
NAND gate2(a, b, out1);
endmodule
应注意的是a和b的值要保持一定的时间,因此,使用了1位的寄存器。寄存器型变量存储过程赋值的最终结果(同传统的命令式编程语言相类似)。线型变量则没有存储能力,它们需要被持续驱动,比如用连续赋值语句或由一个模块的输出进行驱动,若线型输入的左端悬空,其值为未知的x。
连续赋值使用关键词assign,而过程赋值的形式是<寄存器变量> = <表达式>,其中<寄存器变量>必须是寄存器型或存储器型变量。过程赋值只允许出现在initial和always结构块中。
前者initial结构块中的语句顺序执行,一些语句设定了延迟#1,表示一个仿真时间单位的延迟。always结构块与initial结构块功能相同,但它是无限循环的过程(直到仿真停止)。initial和always结构多用来描述时序逻辑(即有限状态自动控制)
Verilog语言中,过程赋值和assign连续赋值之间区别很大。过程赋值改变一个寄存器的状态,即时序逻辑;而连续赋值用来描述组合逻辑。连续赋值语句驱动线型变量,输入操作数的值一发生变化,就重新计算并更新它所驱动的变量。掌握这一区别很有必要。
将这三个模块放到一个文件中,仿真后将产生如下的结果:
Time=0 a=0 b=0 out1=1 out2=0
Time=1 a=1 b=0 out1=1 out2=0
Time=2 a=1 b=1 out1=0 out2=1
Time=3 a=0 b=1 out1=1 out2=0
在此无循环操作,仿真器执行所有的事件后自行停止,因此不需要指定仿真结束时间。
Verilog语言的三种描述方法
● 结构型描述
是通过实例进行描述的方法。将Verilog预定义的基元实例嵌入到语言中,监控实例的输入,一旦其中任何一个发生变化,便重新运算并输出。
● 数据流型描述
是一种描述组合功能的方法,用assign连续赋值语句来实现。连续赋值语句完成如下的组合功能:等式右边的所有变量受持续监控,每当这些变量中有任何一个发生变化,整个表达式被重新赋值并送给等式左端。这种描述方法只能用来实现组合功能。
● 行为型描述
是一种使用高级语言的方法,它和用软件编程语言描述没有什么不同。具有很强的通用性和有效性。它是通过行为实例来实现的,关键词是always,其含义是,一旦赋值给定,仿真器便等待变量的下一次变化,有无限循环之意。
使用Verilog进行简单设计的实例
程序如下:
module MUX2_1 (out, a, b, sel); //端口定义
output out;
input a, b, sel; //输入输出列表
not (sel_, sel);
and (a1, a, sel_);
and (b1, b, sel);
or (out, a1, b1); //结构描述
endmodule
|
sel sel_
b b1 |
对应硬件电路如图2所示。
图2:MUX2_1模块电路示意图
a, b和sel是设备的输入端口,out是输出端口,所有信号都从这些端口流入和输出。and,or,not是Verilog中预定义好的基元实例,在结构型描述中使用。关键词module和endmodule之间包含完整的二选一多路选择器的设计实现。当在其它模块中用到这一多路选择器的模块时只需使用其模块名和所定义的端口名,不需要知道其内部的具体实现。这是至上而下设计方法的一个主要特征,因为一个模块的实现方法可以从行为级转换到门级,而对使用它的高层模块不产生任何影响。
1. 3 词法习俗
Verilog HDL的源文本文件是由一串词法标识符构成的,一个词法标识符包含一个或若干个字符。源文件中这些标识符的排放格式很自由,也就是说,在句法上间隔和换行只是将这些标识符分隔开来,并不具有重要意义,转意(escaped)标识符(见后面的详细说明)除外。
Verilog语言中词法标识符的类型有以下几种:
——间隔符
——注释符
——算子
——数值
——字符串
——标识符
——关键词
接下来对这些标识符一一进行说明。
1、 间隔符
间隔符包括空格字符、制表符、换行以及换页符,这些字符除了起到与其它词法标识符相分隔的作用外可以被忽略,但是在字符串中空白和制表符会被认为是有意义的字符。
2、 注释
Verilog HDL有两种注释形式,单行注释和段注释(多行)。单行注释以两个字符“//”起始,以新的一行作为结束;而段注释则是以/*起始,以*/结束。段注释不允许嵌套。在段注释中单行注释标识符//没有任何特殊意义。
3、 算子
算子是由单个、两个或三个字符组成的序列串,它用在表达式中,在第节讲述了表达式中算子的使用。
一元算子放在操作数的左侧,二元算子的位置在两个操作数之间,条件算子有两个算子字符分隔三个操作数。
4、 数值
Verilog HDL的数值集合由以下四个基本的值组成:
0—代表逻辑0或假状态
1—代表逻辑1或真状态
x—逻辑不定态
z—高阻态
常数按照其数值类型可以划分为整数和实数两种。
Verilog HDL的整数可以是十进制、十六进制、八进制或二进制的,格式为:
<位宽>' <基数> <数值>
● 位宽 :描述常量所含位数的十进制整数,是可选项,如果没有这一项,可以从常量的值推断出
● 基数 :可选项,可以是b,B,d,D,o,O,h或H,分别表示二进制、八进制、十进制和十六进制。基数缺省默认为十进制数。
● 数值: 是由基数所决定的表示常量真实值的一串ASCⅡ码。如果基数定义为b或B,数值可以是0,1,x,X,z或Z。若基数是o或O,数值还可以是2,3,4,5,6,7;若基数是h或H,数值还可以是8,9,a,A,b,B,c,C,d,D,e,E,f,F。对于基数为d或D的情况,数值符可以是任何的十进制数,0到9,但不可以是X或Z。举例如下:
15 (十进制15)
'h15 (十进制21,十六进制15)
5'b10011 (十进制19,二进制10011)
12'h01F (十进制31,十六进制01F)
'b01x (无十进制值,二进制01x)
注:
a、数值常量中的下划线"_"是为了增加可读性,可以忽略,如:8'b1100_0001是8位二进制数。
b、在给寄存器型数据赋值时,有大小的负数并不使用符号扩展的方法生成。
c、数值常量中的“?”表示高阻状态,如:2'B1?表示2位的二进制数,其中的一位是高阻状态。
Verilog中实数用双精度浮点型数据来描述。实数既可以用小数(如12.79)也可以用科学计数法的方式(如24e7,表示24乘以10的7次方)来表达。带小数点的实数在小数点两侧都必须至少有一位数字。例如:
1.2
0.5
128.7496
1.7E8(指数符号可以是e或E)
57.6e-3
0.1e-0
123.374_286_e-9 (下划线忽略)
下面的几个例子是无效的格式:
.25
3.
7.E3
.8e-2
实数可以转化为整数,根据四舍五入的原则,而不是截断原则。当将实数赋给一个整数时,这种转化会自行发生。例如,在转化成整数时,实数25.5和25.8都变成26,而25.2则变成25。
5、 字符串
字符串常量是一行上写在双引号之间的字符序列串,在表达式和赋值语句中字符串用作算子,且要转换成无符号整型常量,用一串8位二进制ASCⅡ码的形式表示,每一个8位二进制ASCⅡ码代表一个字符。例如:字符串“ab”等价于16'h5758。
字符串变量是寄存器型变量,它具有与字符串的字符数乘以8相等的位宽。
例如:
存储12个字符的字符串“Hello China!”需要8*12,即96位宽的寄存器。
reg [8*12:1] str1;
initial begin
str = “Hello
end
使用Verilog HDL的操作符可以对字符串进行处理,被操作符处理的数据是8位ASCⅡ码的顺序。
Verilog支持C语言中的转意符,如t, n, , "和%%等。
6、 标识符、关键字和系统名称
标识符是赋给对象的唯一的名字,用这个标识符来提及相应的对象。标识符可以是字母、数字、$符和下划线(_)字符的任意组合序列,但它必须以字母(大小写)或下划线开头,不能是数字或$符。标识符是区分大小写的。例如:atack_del,clk_in1,_shift3,o$284等。非法命名如下:34net,a*b_net。
逃逸标识符(Escaped identifiers)以反斜杠""开始,以空格结束,这种命名可以包含任何可印刷的ASCⅡ字符,反斜杠和空格不属于名称的一部分。如:~#@sel ,{A,B} ,busa+index 等。
关键字是预先定义的非逃逸标识符,用来定义语言结构,所有的关键字都是用小写方式定义的,附录A给出了所有已定义的关键字列表。
系统任务标识符:$<identifier>,其中$表示引入一个语言结构,其后所跟的标识符是系统任务或系统函数的名称。$<identifier>系统任务或系统函数标识符可以在三处进行定义:
——$<identifier>系统任务和函数的标准集合
——使用PLI(Programming Language Interface)定义附加的<identifier>系统任务 和函数
——通过软件工具定义附加的<identifier>系统任务和函数
系统功能可以执行不同的操作:
——实时显示当前仿真时间($time)
——显示/监视信号的值($display, $monitor)
——暂停仿真($stop)
——结束仿真($finish)
例:$monitor($time, "a = %b, b = %h", a, b);
每次a或b信号的值发生变化,这一系统任务的调用负责显示当前仿真时间、二进制格式的a信号和十六进制格式的b信号。
1. 4 数据类型
Verilog HDL的数据类型集合表示在硬件数字电路中数据进行存储和传输的要素。
Verilog语言支持抽象数据类型,如整型、实型等;同时也支持物理数据类型,可代表真实的硬件。
1.4.1 按物理数据类型分
Verilog中变量的物理数据类型分为线型和寄存器型两种。这两种类型的变量在定义时要设置位宽,缺省值为一位。变量的每一位可以是0,1,X或Z。X代表一个未被预置初始状态的变量或是由于两个或更多个驱动装置试图将之设定为不同的值而引起的冲突型线型变量,Z代表高阻状态或浮空量。
线型数据包括:wire,wand,wor等几种类型。在被一个以上激励源驱动时,不同的线型数据有各自决定其最终值的分辨办法。

