1
Verilog HDL 设计基础
1 概述 1.1 硬件描述语言(HDL)的发展历史
硬件描述语言(HDL,Hardware Description Languag)是电子设计自动化
(EDA,Electronic Design Automation)的主要输入方式,在可编程逻辑器件和
专用集成电路设计中有着广泛的应用。
早期集成电路的规模是小,电路复杂度也低,设计主要依靠手工作业和个体
劳动。四、五十年后的今天,超大规模集成电路(VLSI )规模都在百万门乃至
数千万门量级,为适应集成电路大规模、高密度、功能复杂的需求,EDA 迅速
发展,并发挥越来越关键的作用,它也给传统的设计
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
带来了全面的革新。
EDA 专业公司的软件独立于半导体器件厂商,其 EDA 工具具有较好的
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
化和兼容性,追求技术上的先进性;半导体器件厂商开发的软件针对其产品工艺
特点进行了优化设计,可尽量高效地发挥产品的性能。实际上,二者经常有紧密
的合作,乃至结成战略联盟。
HDL 是硬件设计人员和电子设计自动化 (EDA)工具之间的界面,它可以
用来编写设计文件,建立电子系统行为级的仿真模型。
HDL 设计的主要优势:
采用一种高级语言表达和描述复杂的系统功能更易于人的理解,具体的
物理实现可以留给逻辑综合工具去完成。
支持自顶向下、分层次的设计模式,对于复杂系统设计尤为重要。
引入“库”的概念,设计可重复利用,也易于修改和完善。
提供强大的系统建模和电路仿真功能,可以大大减少设计中的错误数目,
缩短开发周期。
当前应用最为广泛的 HDL 有两种:Verilog HDL 和 VHDL,均已成为 IEEE
的标准。
Verilog HDL 是 1983 年由 GDA(Gateway Design Automation)公司的 Phil
Moorby 首创的。Moorby 在发布了 Verilog 语言后,于 1985 年设计出第一个
Verilog-XL 仿真器,用于快速门级仿真。随着 Verilog-XL 的成功,Verilog HDL
Re
f
r
e
n
ce
2
语言得到迅速发展。1989 年 Cadence 公司收购了 GDA 公司,1990 年 Cadence
公司公开了 Verilog HDL 语言,成立 OVI(Open Verilog Intemational)组织来负
责 Verilog HDL 的发展。 IEEE 于 1995 年制定了 Verilog HDL 的 IEEE 标准,即
Verilog HDL 1364-1995。目前最新的 Verilog 语言版本是 2000 年 IEEE 公布的
Verilog 2001 标准,该标准提高了系统级和可综合性能。
VHDL(VHSIC Hardware Description Language)的发展始于 1981 年,在美
国国防部的指导下开发完成。VHSIC 是超高速集成电路(Very High-Speed
Integrated Circuit)的缩写。1987 年 VHDL 被美国国防部和 IEEE 确定为标准的
硬件描述语言,形成的标准为 IEEE 1076。当初开发这种语言是出于美国国防部
采购电子设备的需要。美国军队的装备是向私人企业采购的,出于武器的维修保
养和再生产的考虑,美国国防部要求供应商用 VHDL 把自己生产的的集成电路
芯片的行为描述出来,例如从芯片的哪个管脚输入什么样的信号,过多长时间能
输出什么样的信号等。这样,如果需要其它厂商生产替代品,只需要按照 VHDL
文档,设计行为与其相同的芯片即可。VHDL 当初是为了描述芯片的行为,而并
非为了设计硬件而开发的,因此 IEEE 1076-1987标准在模型描述方面非常详尽,
但在综合方面它只定义了些很宽泛的参数,在工程实现中有很大的难度。1993
年 IEEE 进行了修订,定为 ANSI/IEEE1076-93 标准,该版本是目前应用最广泛
的 VHDL 版本,很多 EDA 公司和半导体厂商都提供对这一标准的支持。 1.2 Verilog HDL的特点
Verilog HDL 语言既是一种行为描述语言,也是一种结构描述语言。按照一
定规则和风格编写代码,可以将功能行为模块通过工具自动转化为门级互连的结
构模块。利用 Verilog 语言,可通过层次清晰的模块结构来描述复杂的大型设计,
并对所需的逻辑电路进行严格的设计。
Verilog HDL 语言的特点:
采用编程的方式描述设计的功能
支持工程设计的结构化描述
支持多层次的抽象描述
实现工艺无关,便于管理和设计重用
支持电路描述由高层到底层的综合转换(可综合)
Re
f
r
e
n
ce
3
具有电路仿真和验证机制(可验证)
Verilog HD 一个鲜明的特点是:语言风格类似“C”,简洁、 可读性强。而
VHDL 则不同于,VHDL 基于 ADA 语言,较为复杂、晦涩。
数字电路系统设计一般抽象为两类(行为模型和结构模型)、五个层次,即:
行为模型(Behavioral models)
• Algorithmic
• Architectural
结构模型(Structural models)
• Register transfer level (RTL)
• Gate level
• Switch level
行为模型层次最高,主要关注模块的功能描述和仿真验证,寄存器传输模型
关注模块的可综合电路的实现,逻辑门模型考虑如何用门级电路实现给定功能,
开关模型层次最底层,描述具体的晶体管和连线。
抽象层次越高,设计和仿真用的时间越少,但对电路细节的描述也越少;抽
象层次越低,与器件相关的细节描述越多,但设计和仿真难度越大,花费时间越
长。通常做基于 FPGA 的工程设计,工程师只需采用 HDL 语言设计 RTL 以上的
层次模型,电路的底层实现由逻辑综合、布局布线等工具完成。
Verilog HDL 最初主要用于结构层次的模型,很好地支持 RTL、Gate 和 Switch
级的设计,并能一定程度支持行为级模型的构建。
Re
f
r
e
n
ce
4
事实上,Verilog HDL 和 VHDL 在功能上的差异已越来越小,其应用范围更
多地取决于使用者的习惯。 1.3 自顶向下(Top-Down)的设计模式
随着微电了技术的快速发展,深亚微米的工艺可以使一个芯片上集成数以千
万乃至上亿只的晶体管,单片上就可以实现复杂系统,即所谓的片上系统。在这
种情况下,传统的自底向上(Bottom-Up)的设计方法学已经不可能适应现在的
设计要求,而自顶向下(Top-Down)的设计方法学已经成为设计界的主流设计
方法学。
在 EDA 工具出现以前,人们采用自底向上的设计方法设计集成电路。这种
设计方法缺少对整体功能的把握,工作耦合度高、效率较低,适用于小规模电路
设计。
自顶向下的设计方法是和 EDA 工具同步发展起来的。该设计方法是从最高
级功能定义(制订系统的
规范
编程规范下载gsp规范下载钢格栅规范下载警徽规范下载建设厅规范下载
)开始,将其不断分解为下一层次更具体的模块实
现,形成一个层次结构树,借助于 EDA 工具可以实现从高层次到低层次的转换。
自顶向下的设计如下图的示意,框中数字代表设计中模块定义的顺序。
Re
f
r
e
n
ce
5
图 自顶向下的 FPGA 设计层次构成图
自顶向下的设计方法学的主要优点有:
该方法可以采用硬件描述语言作为设计输入,改变了传统电路设计方法,
有利于提高设计效率。
设计从制定系统规范开始,进行逐层的模块分解,有利于系统要求和规
范的及时更新完善。该方法方便了项目管理,使得复杂数字电路设计成
为可能。
根据设计层次图可容易地进行设计任务划分,更有效地分配设计资源。
可较为灵活地对不同设计
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
进行比较试验,有利于设计方案的优化。
可重用以前的设计,提高设计工作效率。
提高了验证能力,并可减少用于验证的工作量。在设计过程中借助 EDA
仿真工具可及时发现每个设计层次的错误并修正,最大限度地不把错误
带到下一层次的设计中。设计层次越高,仿真验证所需的时间和工作量
越少,因此可缩短产品验证周期。
Re
f
r
e
n
ce
6
2 Verilog程序结构和语言要素 2.1 Verilog的程序结构
作为高级语言的一种,Verilog 语言以模块集合的形式来描述数字系统,其
中每一个模块都有接口部分,用来描述与其它模块之间的连接。通常一个文件代
表一个模块,但这并不是强制性的要求。
模块代表硬件上的逻辑实体,其范围可以从简单的门大到整个数字系统。在
Verilog HDL 中,模块就是封装在“module … endmodule”的一段程序代码。其
结构形式如下。
module
();
endmodule
其中是模块唯一性的标识符;是外部接口信号列
表,模块通过这些端口用来与其它模块进行连接。
模块端口定义分为三种类型:输入(input)、输出(output)和双向(inout)。
如下例所示。
module MUX2_1 (out, a, b, sel);
// 端口定义
output out;
input a, b, sel; // 输入输出列表
…
…
endmodule
模块中的其它定义包括:参数定义、内部信号量定义等。
模块描述可以采用行为型或结构型(或者是二者的组合)的描述方式。
• 行为型描述通过传统的编程语言结构定义数字模块的功能和状态,如使
用 if 条件语句、赋值语句等。
Re
f
r
e
n
ce
7
• 结构型描述将模块表达为具有层次概念的互相连接的子模块,其最底层
的元件是基元或已定义过的行为型模块。
一个 Verilog HDL 模块的完整结构如下所示:
module mod_name (in1, in2, out1, io1);
//定义
input in1; //输入信号
output out1; //输出信号
inout io1; //双向信号
reg rg1; //寄存器变量
wire wr1; //线型变量
parameter ; // 参数定义
function ; //
函数
excel方差函数excelsd函数已知函数 2 f x m x mx m 2 1 4 2拉格朗日函数pdf函数公式下载
task ; // 任务
// 程序代码
// 行为型描述
// 行为型描述
// 行为型(数据流)描述
// 结构型描述
endmodule
2.2 语言词法
Verilog HDL 源文本由一串词法符号构成。一个词法符号包含一个或若干个
字符,源文件中这些词法符号的排放格式很自由,也就是说,在句法上间隔和换
行只是将这些标识符分隔开来,并不具有重要意义。转意(escaped)标识符除
外。
Verilog 语言中词法符号的类型有以下几种:
• 间隔符
• 注释符
• 算子
• 数值
• 字符串
• 关键词
Re
f
r
e
n
ce
8
(一)间隔符
间隔符包括:空格字符、制表符、换行以及换页符,这些字符除了起到与其
它词法标识符相分隔的作用外可以被忽略,但是在字符串中空白和制表符会被认
为是有意义的字符。
(二)注释
Verilog HDL 有两种注释形式,单行注释和段注释(多行)。单行注释以两个
字符“//”起始,以新的一行作为结束;而段注释则是以“/*”起始,以“*/”
结束,段注释不允许嵌套,在段注释中单行注释标识符“//”没有任何特殊意义。
(三)运算子
算子是由单个、两个或三个字符组成的序列串,它用在表达式中。一元算子
放在操作数的左侧;二元算子的位置在两个操作数之间;条件算子有两个算子字
符分隔三个操作数。
(四)数值
Verilog HDL 的数值由以下四个基本的位值组成
• 0,代表逻辑 0 或假状态
• 1,代表逻辑 1 或真状态
• X,代表逻辑不定态
• Z,代表高阻态
常数按照其数值类型可以划分为整数和实数两种。
Verilog HDL 的整数可以是十进制、十六进制、八进制或二进制的、格式为
<位宽>' <基数> <数值>
位宽:描述常量所含位数的十进制整数,是可选项,如果没有这一项,可以
从常量的值推断出
基数:可选项,可以是 b,B(二进制),d,D(十进制),o,O(八进制),
h 或 H(十六进制),基数缺省默认为十进制数。
数值:是由基数所决定的表示常量真实值的一串 ASCII 码。如果基数定义
为 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,
Re
f
r
e
n
ce
9
d,D,e,E,f,F。对于基数为 d 或 D 的情况,数值字符可以是任何的十进制
数 0 到 9,但不可以是 X 或 Z。
举例如下
15 =〉十进制 15
'h15 =〉十六进制 15,十进制 21
12'h01F =〉十六进制 01F,十进制 31
5'b10011=〉 二进制 10011,十进制 19
注:
数值常量中的下划线"_"是为了增加可读性,可以忽略。如 8'b1100_0001
是 8 位二进制数。
数值常量中的"?"表示高阻状态,如 2'B1?表示 2 位的二进制数,其中的
低位是高阻状态。
Verilog 中实数用双精度浮点型数据来描述。实数既可以用小数(如:12.79)
也可以用科学计数法的方式(如:24e7)来表达。带小数点的实数在小数点两侧
都必须至少有一位数字。例如
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
Re
f
r
e
n
ce
10
实数可以转化为整数,根据四舍五入的原则,而不是截断原则。当将实数赋
给一个整数时,这种转化会自行发生。例如,在转化成整数时,实数 25.5 和 25.8
都变成 26,而 25.2 则变成 25。
(五)字符串
字符串常量是一行上写在双引号之间的字符序列串,在表达式和赋值语句中
字符串用作算子,且要转换成无符号整型常量,用一串 8 位二进制 ASCII 码的
形式表示,每一个 8 位二进制 ASCII 码代表一个字符,例如:字符串“ab”等价
于 16'h5758。
字符串变量是寄存器型变量,它具有与字符串的字符数乘以 8 相等的位宽。
例如:存储 12 个字符的字符串“Hello China!”需要 8*12,即 96 位宽的寄存
器。
使用 Verilog HDL 的操作符可以对字符串进行处理,被操作符处理的数据是
8 位 ASCII 码的顺序。
Verilog 支持 C 语言中的转意符,如\t, \n, \\, \"和%%等。
(六)标识符、关键字和系统名称
对象标识符是赋给对象的唯一的名字,用这个标识符来提及相应的对象,标
识符可以是:字母、数字、$符和下划线_字符的任意组合序列。但它必须以字母
大小写或下划线开头,不能是数字或$符,标识符是区分大小写的。
合法的标识符,例如:atack_del,clk_in1,_shift3,o$284 等。
非法命名如下:34net,a*b_net。
逃逸标识符 Escaped identifiers 以反斜杠"\"开始,以空格结束,这种命名可
以包含任何可印刷的 ASCII 字符,反斜杠和空格不属于名称的一部分。如:
\?#@sel ,\{A,B} ,\busa+index 等。
关键字是预先定义的非逃逸标识符,用来定义语言结构,所有的关键字都用
小写定义。
系统任务标识符 $ ,其中$表示引入一个语言结构,其后所跟的
标识符是系统任务或系统函数的名称。
Re
f
r
e
n
ce
11
系统功能可以执行各种的操作,例如
• 实时显示当前仿真时间$time
• 显示/监视信号的值$display,$monitor
• 暂停仿真$stop
• 结束仿真$finish
例:$monitor($time, "a = %b, b = %h", a, b);
每次 a 或 b 信号的值发生变化,这一系统任务的调用负责显示当前仿真时
间、二进制格式的 a 信号和十六进制格式的 b 信号。 2.3 数据类型
Verilog HDL 的数据类型表示在数字电路中数据进行存储和传输的元素。
Verilog 语言支持物理数据类型,可代表真实的硬件;同时也支持抽象数据
类型,如:整型、实型等。
(一)按物理数据类型分
Verilog HDL 中变量的物理数据类型分为:线型和寄存器型两种。
寄存器型数据与线型数据的区别在于:寄存器型数据保持最后一次的赋值;
而线型数据需要有持续的驱动,在被一个以上激励源驱动时,不同的线型数据有
各自决定其最终值的办法。
物理数据类型的通用说明形式为
, , …;
为数据类型,线型数据类型包括:wire、wand、wor 等;寄存器
数据类型为 reg。定义数据的位宽,格式为“[m:n]”,类似电路图中
的总线描述方式。可以省略,此时定义变量的位宽为缺省的 1 位。
具体实例如下。
wire [7:0] data; // 定义 8 位线型数据,数据位为 data[7]~data[0]
reg [16:31] addr; // 定义 16 位寄存器型数据,数据位为 addr[16]~addr[31]
变量的每一位可以是 0、1、X 或 Z。X 代表一个未被预置初始状态的变量
或是由于两个或更多个驱动装置试图将之设定为不同的值而引起的冲突型变量,
Z 代表高阻状态或浮空量。
Re
f
r
e
n
ce
12
注:使用 assign语句被连续赋值的变量必须是线型的;在 always或 initial 程
序块行为模块中用“=”赋值的变量必须是寄存器型的。
(二)按抽象数据类型分
按抽象数据类型,分以下几种
• integer 整型
在算术运算中整型数据被视为二进制补码形式的有符号数,而寄存器型数据
当作无符号数来处理。除此以外整型数据与 32 位寄存器型数据在实际意义上相
同。
• time 时间型
时间型变量与整型相类似,只是它是 64 位的无符号数。
• real 实型
实型数据在机器码表示法中是浮点型数值,Verilog 提供了将实型数据转换
成位矢量以及相反过程的系统功能
• event 事件型
它是一种特殊的变量类型,不具有任何值,作用是使模块不同部分的事件在
时间上同步。
• parameter 参数型
参数型数据是被命名的常量,在仿真开始前对其赋值,在整个仿真过程中保
持其值不变。数据的具体类型是由所赋的值来决定的,可以用它来定义变量的位
宽以及延迟时间等。 2.4 运算符和表达式
Verilog 语言参考了 C 语言中大多数算符的语义和句法。 一个例外是
Verilog 中没有增 1(++)和减 1(- -)运算符
(一)赋值运算符
赋值运算分为连续赋值和过程赋值。
连续赋值语句和过程块一样是一种行为描述语句,有时将其称为数据流描述
形式。连续赋值语句用来驱动线型变量,不能驱动寄存器变量。连续赋值语句采
用关键词 assign。
Re
f
r
e
n
ce
13
过程赋值用于行为描述结构块(initial 模块和 always 模块)中,分为阻塞和
无阻塞过程赋值两种类型。
阻塞赋值的符号为“=”,它代表要等到当前赋值完成后才能执行下一条
语句。
无阻塞赋值用“<=”代替了阻塞赋值的“=”,代表在赋值过程的同时控
制下一条语句的继续执行。
(二)算术运算符
在 Verilog HDL 语言中,算术运算符又称为二进制运算符,共有下面几种
+ 加法
- 减法
* 乘法
/ 除法
% 取模
在进行整数除法运算时,结果值要略去小数部分,只取整数部分。而进行取
模运算时,结果的符号位采用模运算式里第一个操作数的符号位。
注意: 在进行算术运算操作时,如果某一操作数有不确定的值 X,则运算
结果也是不定值 X。
下面是算术运算符应用的一个例子
module arithmetic(a, b, out1, out2, out3, out4, out5)
input [2:0] a, b;
output [3:0] out1;
output [4:0] out3;
output [2:0] out2, out4, out5;
reg [3:0] out1;
reg [4:0] out3;
reg [2:0] out2, out4, out5;
always @(a or b)
begin
out1 = a+b;
out2 = a-b;
out3 = a*b;
out4 = a/b;
out5 = a%b;
end
Re
f
r
e
n
ce
14
endmodule
(三)关系运算符
关系运算符共有以下几种
> 大于
>= 大于等于
< 小于
<= 小于等于
= = 逻辑相等
!= 逻辑不相等
= = = 实例相等
!= = 实例不相等
在进行关系运算时,如果操作数之间的关系成立,返回值为 1;反之,关系
不成立,则返回值为 0。若某一个操作数的值不定,则关系是模糊的,返回值是
不定值 X。
关系运算符的使用方法见下例。
module relation(a, b, out1, out2, out3, out4);
input [2:0] a, b;
output out1, out2, out3, out4;
reg out1, out2, out3, out4;
always @ (a or b)
begin
out1 = a < b;
out2 = a <= b;
out3 = a > b;
if (a >= b) out4 = 1;
else out4 = 0;
end
endmodule
在 Verilog 语言中,有两种类型的等式运算符,一种为逻辑等式运算符,另
一种为实例等式运算符。二者区别在于:若操作数含有一位 X 或 Z,逻辑算子
置位为 X,而实例算子可以比较含有 X 和 Z 的操作数。 举例如下
Re
f
r
e
n
ce
15
module equequ;
initial begin
$display ('bx == 'bx is %b ,'bx == 'bx);
$display ('bx === 'bx is %b,'bx === 'bx);
$display ('bz != 'bx is %b,'bz != 'bx);
$display ('bz !== 'bx is %b,'bz !== 'bx);
end
endmodule
模块 equequ 的执行会产生如下结果
'bx == 'bx is x
'bx === 'bx is 1
'bz != 'bx is x
'bz !== 'bx is 1
所有的关系运算符有着相同的优先级别,关系运算符的优先级别低于算术运
算符的优先级别。
(四)逻辑运算符
在 Verilog HDL 语言中有 3 种逻辑运算符
&& 逻辑与
| | 逻辑或
! 逻辑非
&& 和 ||是二目运算符,要求有两个操作数。如(a > b)&&(b > c),(a
< b)||(b < c)。而“!”是单目运算符,只要求一个操作数,如!(a > b)。
逻辑运算符中“&&”和“| |”的优先级别低于关系运算符,“!”高于算术运
算符。逻辑运算符与其它高级语言的用法基本相似。
(五)位逻辑运算符
在 Verilog 语言中有 7 种位逻辑运算符
~ 非
& 与
| 或
^ 异或
^~ 同或
~& 与非
Re
f
r
e
n
ce
16
~| 或非
位逻辑运算符对其自变量的每一位进行操作。例如,表达式 A & B 的结果
是 A 和 B 的对应位相与的值。对具有不定值的位进行操作,视情况而定会得到
不同的结果。例如:x 和 FALSE 相或得结果 x;x 和 TRUE 相或得结果 TURE。
如果操作数的长度不相等,较短的操作数将用 0 来补位,逐位运算将返回一个
与两个操作数中位宽较大的一个等宽的值。
在此需要注意的是:不要将逻辑运算符和位运算符相混淆。比如! 是逻辑非,
而~是位操作的非,即按位取反。例如,对于前者 !( 5 = = 6)结果是 TRUE;而
位操作~{1, 0, 1, 1} = 0100。
(六)一元约简运算符
约简运算符是单目运算符,也有与、或、非运算。其与、或、非运算规则
类似于位运算符的与、或、非运算规则,但其运算过程不同,位运算是对操作数
的相应位进行与、或、非运算,操作数是几位数则运算结果也是几位数。而约简
运算不同,约简运算是对单个操作数进行与、或、非递推运算,最后的运算结果
是 1 位的二进制数。
约简运算的具体运算过程是:先将操作数的第 1 位与第 2 位进行与、或、
非运算;然后将运算结果与第 3 位进行与、或、非运算,依次类推,直至最后一
位。例如
reg [3:0] B;
reg C;
C = &B;
相当于
C = ( (B[0]&B[1]) & B[2] ) & B[3];
完整的模块举例如下
module reduction(a, out1, out2, out3, out4, out5, out6);
input [3:0] a;
Re
f
r
e
n
ce
17
output out1, out2, out3, out4, out5, out6;
reg out1, out2, out3, out4, out5, out6;
always @ (a)
begin
out1 = & a;
out2 = | a;
out3 = ~& a;
out4 = ~| a;
out5 = ^ a;
out6 = ~^ a;
end
endmodule
(七)移位运算符
在 Verilog HDL 语言中有两种移位运算符“<<”(左移位运算符)和“>>”
(右移位运算符)。运算符有两个操作数,第一个操作数是移位操作的对象,第
二个操作数是移动的位数。这两种移位运算都用 0 来填补移出的空位。举例如下
module shift;
reg[3: 0] a, b;
initial begin
a = 1;
b = (a<<2);
end
endmodule
此例中,b 在移过两位后,用 0 来填补空出的位,进行移位运算时应注意移
位前后变量的位数。
(八)条件运算符
条件运算符(? :)有三个操作数,第一个操作数为 TRUE 时,算子返回第
二个操作数;否则返回第三个操作数。
条件算子可以用来实现一个选择器。例如
module conditional(time, y);
input [2:0] time;
output [ 2: 0] y;
reg [2: 0] y;
Re
f
r
e
n
ce
18
parameter zero = 3'b000;
parameter timeout = 3'b111;
always @(time)
y = (time != timeout) ? time +1: zero;
endmodule
嵌套的条件算子可用来实现多路选择。 如
wire [1: 0] absval;
assign absval = (a>0) ? 1 : (a<0) ? 2: 0;
(九)并接运算符
Verilog HDL 语言中有一个特殊的运算符——并接运算符{},这一运算符可
以将两个或更多个信号的某些位并接起来进行运算操作。其使用方法是把某些信
号的某些位详细地列出来,中间用逗号分开,最后用大括号括起来表示一个整体
信号。即{信号 1 的某几位,信号 2 的某几位,.. 信号 n 的某几位}。
例如:
{a[3],b,c[2: 0],4'b0100};
{2'b1x,4'h7} = = = 6'b1x0111
此外,在 Verilog 语言中还有一种重复操作符{{}},即将一个表达式放入双
重花括号中,复制因子放在第一层括号中,它为复制一个常量或变量提供一种简
便记法。例如:{3{2'b01}}=== 6'b010101
(七)运算符优先级排序
运算符优先级顺序如下所示
Re
f
r
e
n
ce
19
将操作数和算子通过正常的优先级规则组合起来便生成表达式,该结构将会
产生一个结果,这一结果是操作数的值和算子的语法含义的函数。一个合法的操
作数不加任何运算符也可以被认为是一个表达式,例如一个线型的位选操作数
表达式用来计算数值,但不仅仅单独用来求值,而是构成语句或其它结构的一部
分。表达式中的操作数可以是变量名(a)、变量的某一位(a[i])、变量的连续数
位(a[3:0])或者是功能块调用。
Re
f
r
e
n
ce
20
3 Verilog HDL的描述方法
Verilog HDL 的描述形式有三种:结构型描述、数据流描述(某种意义上也
可看作行为型描述)、行为型描述。 3.1 结构型描述
是通过实例进行描述的方法,将 Verilog 预定义基元或已定义的子模块以实
例调用的方式嵌入到语言中,将模块分解为互相连接的各子模块的集合。
调用实例的一般形式为
()
为被调用模块的名字,是传输到模块实例的
参数值,参数传递的典型应用是定义门级延迟。若模块中没有定义参数,或采用
缺省模块参数,该项可省略。为该模块实例的名字,
将模块中定义的输入输出端口和实例化后的信号线连接起来。
模块例化的端口连接有两种方式:位置映射法和信号名映射法。
位置映射法:严格按照模块定义的端口顺序来连接,不用注明原模块定
义时规定的端口名称。
(, , … );
信号名称映射法:利用“.”符号,表明原模块定义时的端口名,采用该
方法可以不必按照端口顺序排列。
(.(), .(), … );
下例为一与门模块的结构型描述,这一与门是通过将一个 NAND 的输出连
到另一 NAND 的两个输入上得到的。这个模块含有两个 NAND 模块实例,分
别是 gate_1 和 gate_2,通过内部连线 w1 连接起来。
In2
In1 w1
out
Re
f
r
e
n
ce
21
//由两个 NAND 生成的与门的结构型描述
module NAND(a, b, c);
input a, b;
output c;
endmodule
module AND(in1, in2, out);
input in1, in2;
output out;
wire w1;
//两个 NAND 模块实例,端口位置映射法
NAND gate_1(in1, in2, w1);
NAND gate_2 (w1, w1, out);
//两个 NAND 模块实例,端口名称映射法
NAND gate_1(.a(in1), .b(in2), .c(w1));
NAND gate_2(.a(w1), .b(w1), .c(out));
endmodule
3.2 数据流描述
数据流描述是一种描述组合逻辑功能的方法,用连续赋值语句来实现。连续
赋值语句形式如下:
assign = ;
连续赋值语句完成如下功能:等式右边的所有变量受持续监控,每当这些变
量中有任何一个发生变化,整个表达式被重新赋值并送给等式左端。
连续赋值语句用来驱动线型变量,这一线型变量必须已经事先定义过,只要
输入端操作数的值发生变,该语句就重新计算并刷新赋值结果。采用连续赋值语
句来描述组合逻辑不需要用门电路和互连线。
下例将线型端口 in1 和 in2 相与,并用这一结果去驱动 out 信号。
module AND(in1, in2, out);
input in1, in2;
output out;
//数据流描述
wire out;
assign out= in1 & in2;
endmodule
Re
f
r
e
n
ce
22
Verilog 语言允许在一次定义中进行多路赋值,下面是延迟为 5 的多路连续
赋值语句。
assign #5 c = a[0], d = {r1, r2, r3}, f[3:2] = {r3, r4};
还可以在连续赋值语句的左端设置并接操作。
assign {carry_out, sum} = ina + inb + carry_in;
数据流描述方法只能用来实现组合逻辑功能。从某种概念上说,数据流型描
述可以归入行为型描述一类。 3.3 行为型描述
行为型描述是一种使用高级语言的方法,它和用软件编程语言描述相似,具
有很强的通用性和有效性。
行为型描述是通过由关键词标识的过程结构块来描述。包含 4 种过程类型
initial 结构块
always 结构块
任务(task)结构块
函数(function)结构块
一个程序可以有多个 intial 结构块、always 结构块、task 结构块和 function
结构块。所有 intial 结构块和 always 结构块都是同时并行执行的。
(一)initial 结构块
initial 结构块只在仿真开始时执行一次结构体内的语句,执行完毕后便挂起,
再也不会被触发。initial 结构块是面向仿真的,是不可综合的。通常用于仿真时
测试模块的初始化、测试激励波形生成等功能。
(二)always 结构块
always 结构块和 initial 结构块不同,它是不断重复执行的。always 结构块工
作流程是:一旦有事件触发便执行结构体内的语句,执行完毕后便重新开始,等
待触发事件的下一次来临,有无限循环之意。
always 结构块既可面向综合,也可用于仿真。always 结构块通常都是可综合
的。
Re
f
r
e
n
ce
23
在过程结构块中,关键字(initial 或 always)之后跟随描述语句或语句块。
语句即为一条 Verilog HDL 代码;语句块为封装在“begin … end”/“fork… join”
中的一段行为语句,类似于 C 语言中“{}”大括号内的内容。
语句块可以有独立的名字,写在块定义语句第一个关键字(begin 或 fork)
之后,名字前用“:”标识。如
always@(a or b)
begin : adder // addr 为语句块的名字
c= a + b;
end
语句块按其内部语句执行的顺序方式分为串行和并行语句块两种类型。
(一)串行(begin…end)语句块
begin…end 语句块用来组合需要顺序执行的语句,称为串行语句块,其内的
各条语句是按照它们在块内的次序逐条执行的,当前语句执行完成后才能执行下
一条语句。
(二)并行(fork…join)语句块
fork…join 语句块用来组合需要并行执行的语句,称为并行语句块,其内的
各条语句的执行都以程序流程进入该语句块的时刻为时间起点。
并行语句块是不可综合的,更多地用于仿真验证代码中。
采用行为型描述一个与门的实例如下。
module AND(in1, in2, out);
input in1, in2;
output out;
//行为型描述
reg out;
always@(in1 or in2)
begin
out= in1 & in2;
end
endmodule
下面介绍行为型描述中的主要功能语句。
Re
f
r
e
n
ce
24
3.3.1 过程赋值语句
简单的阻塞过程赋值语句有如下三种形式:
• = < expression>;
• = #delay ;
• = @;
lhs(左端)可以是一个变量名、变量的某一特定位、变量的指定几位或是
对变量的并置。形式 1 中,仿真器先对右端表达式进行计算然后立即将结果赋给
左端;形式 2 中,仿真器计算右端表达式后要等待 delay 延迟时间,再将值赋到
左端;形式 3 下,仿真器要等到 event 事件发生才把右端的值赋给左端,这三种
赋值形式都要等到赋值操作后才能执行下一条语句。
无阻塞 Unblock 过程赋值语句在句法上与阻塞 block 过程赋值语句相似,只
是 用“<=”代替了“=”。
<= ;
<= #delay ;
<= @;
二者的差别在于无阻塞赋值语句右端计算好后并不立即赋给左端,在要赋值
的同时控制下一条语句的继续执行,无阻塞赋值语句对描述数据流很简便。例如
要模拟一个移位 寄存器,语句的顺序很重要。
stage1 = (#1) stage2;
stage2 = (#1) stage3;
stage3 = (#1) stage4;
stage4 = (#1) stage5;
而如下的编写方法便可以不考虑其顺序
stage1 <= (#1) stage2;
stage2 <= (#1) stage3;
stage3 <= (#1) stage4;
stage4 <= (#1) stage5;
Re
f
r
e
n
ce
25
3.3.2 触发事件控制语句
(一)信号电平事件语句
电平敏感事件是指信号的电平发生变化时发生触发的行为。有两种情形
• @() ;
• @( or …) ;
例子如下,只要 clk 的信号电平发生变化,cnt 信号输出的值就会加 1。
module counter1(clk, reset, cnt);
input clk, reset;
output [4:0] cnt;
reg [4:0] cnt;
always @(reset or clk) begin
if(reset) cnt= 0;
else cnt= cnt+1;
end
endmodule
(二)信号跳变沿事件
信号跳变沿事件是指信号的边沿发生跳变时触发的行为,分为信号上升沿和
下降沿控制,分别用 posedge 和 negedge 关键字来描述。语法格式为
• @() ;
• @( or …) ;
下例中只要 clk 的下降沿来临,cnt 信号输出的值就会加 1。
Module counter1(clk, reset, cnt);
input clk, reset;
output [4:0] cnt;
reg [4:0] cnt;
always @(negedge clk) begin
if(reset) cnt <= 0;
Re
f
r
e
n
ce
26
else cnt <= cnt+1;
end
endmodule
3.3.3 选择语句结构
Verilog HDL 语言含有丰富的控制语句,可以选择不同的控制语句生成程序
代码的过程块,比如在 initial 和 always 结构块中。大部分控制语句与传统的
编程语言“C”语言相似。Verilog HDL 语言与 C 语言之间的区别在于:C 语言
中的括弧{},在 Verilog 中用 begin 和 end 代替;而在 Verilog 中括弧{}用来完成
字符的位并接功能。由于大部分使用者对 C 语言都很熟悉, 接下来的各小结对
每一种结构进行举例介绍。
选择结构包括 if 和 case 语句
(一) if 语句
Verilog HDL 语言中的 if 语句与 C 语言的十分相似,使用起来也很简单。
• if() ;
• if() ;
else
• if() ;
else if() ;
else if …
else
通过下例进行说明。
if (a<0) b = 1;
else b = 0;
(二)case 语句
与 C 语言的 switch- case 语句不同,Verilog 语言中,选择第一个与<表达式>
的值相匹配的<数值>,并执行相关的语句,然后控制指针将转移到 endcase 语句
之后。也就是说,与 C 语言不同的是,它不需要 break 语句。其形式如下
case ()
Re
f
r
e
n
ce
27
:
< pattern2>:
default :
endcase
下面的例子检查了 1 位信号的值
case (sig)
1'bz:$display("Signal is floating");
1'bx:$display("Signal is unknown");
default:$display("Signal is %b", sig);
endcase
另举例如下
module case_statement;
integer i;
initial i = 0;
always begin
$display(i = %d, i );
case (i)
0 : i = i + 2;
1: i = i + 7;
2: i = i - 1;
Default: $stop;
endcase
end
endmodule
该模块的运行结果如下
i = 0
i = 2
i = 1
i = 8
选择表达式要与 case 表达式逐位相对照,若没有事件相匹配则执行 default
事件,若 default 事件不存在,便执行 case 语句后的下一条语句。
Re
f
r
e
n
ce
28
3.3.4 重复语句结构
重复结构包括 repeat 重复语句、while 循环语句、for 循环语句和 forever
循环语句。
(一)rep