Verilog HDL.docx
- 文档编号:1766005
- 上传时间:2023-05-01
- 格式:DOCX
- 页数:61
- 大小:491.31KB
Verilog HDL.docx
《Verilog HDL.docx》由会员分享,可在线阅读,更多相关《Verilog HDL.docx(61页珍藏版)》请在冰点文库上搜索。
VerilogHDL
第七章VerilogHDL基础知识
7.1硬件描述语言(HDL)概述
硬件描述语言(HardwareDescriptionLanguage)是硬件设计人员和电子设计自动化(EDA)工具之间的界面。
其主要目的是用来编写设计文件,建立电子系统行为级的仿真模型。
即利用计算机的巨大能力对用VerilogHDL或VHDL建模的复杂数字逻辑进行仿真,然后再自动综合以生成符合要求且在电路结构上可以实现的数字逻辑网表(Netlist),根据网表和某种工艺的器件自动生成具体电路,然后生成该工艺条件下这种具体电路的延时模型。
仿真验证无误后用于制造ASIC芯片或写入CPLD和FPGA器件中。
7.1.1使用硬件描述语言的必要性
传统的用原理图设计电路的方法具有直观形象的优点,但如果所设计系统的规模比较大,或设计软件不能提供设计者所需的库单元时,这种方法就显得很受限制了。
而且用原理图表示的设计,通用性、可移植性也较弱。
所以在现代的设计中,越来越多地采用了基于硬件描述语言的设计方式。
利用硬件描述语言来设计电路,使探测各种设计方案变成一件很容易很便利的事情,因为只需要对描述语言进行修改,这比更改电路原理图原型要容易实现得多。
7.1.2VerilogHDL硬件描述语言的发展历程
VerilogHDL语言最初是于1983年由GatewayDesignAutomation公司为其模拟器产品开发的硬件建模语言。
那时它只是一种专用语言。
由于他们的模拟、仿真器产品的广泛使用,VerilogHDL作为一种便于使用且实用的语言逐渐为众多设计者所接受。
在一次努力增加语言普及性的活动中,VerilogHDL语言于1990年被推向公众领域。
OpenVerilogInternational(OVI)是促进Verilog发展的国际性组织。
1992年,OVI决定致力于推广VerilogOVI标准成为IEEE标准。
这一努力最后获得成功,Verilog语言于1995年成为IEEE标准,称为IEEEStd.1364-1995。
后来又推出了IEEEStd.1364-2001,它在前者的基础上对Verilog语言做了若干改进和扩充,使其功能更强,使用更方便。
7.1.3VerilogHDL语言的主要能力
从语法结构上看,VerilogHDL语言与C语言有许多相似之处,并继承和借鉴了C语言的多种操作符和语法结构。
它可以用于从算法级、门级到开关级的多种抽象设计层次的数字系统建模。
被建模的数字系统对象的复杂性可以介于简单的门和完整的电子数字系统之间。
数字系统能够按层次描述,并可在相同描述中显式地进行时序建模。
VerilogHDL语言具有下述描述能力:
设计的行为特性、设计的数据流特性、设计的结构组成以及包含响应监控和设计验证方面的时延和波形产生机制。
所有这些都使用同一种建模语言。
此外,VerilogHDL语言提供了编程语言接口,通过该接口可以在模拟、验证期间从设计外部访问设计,包括模拟的具体控制和运行。
7.2程序基本结构
7.2.1模块
Verilog语言的基本描述单位是模块,以模块集合的形式来描述数字系统。
其中每一个模块都有接口部分,用来描述与其它模块之间的连接。
模块代表硬件上的逻辑实体,其范围可以从简单的门到整个大的系统。
一个模块的基本语法如下:
module<顶层模块名>(<输入输出端口列表>);
output输出端口列表;//输出端口声明
input输入端口列表;//输入端口声明
//定义数据、信号的类型,任务、函数声明
wire信号名;
reg信号名;
//逻辑功能定义
assign<结果信号名>=<表达式>;//使用assign语句定义逻辑功能
//用always块描述逻辑功能
always@(<敏感信号表达式>)
begin
//过程赋值
//if_else
//case语句
//while,repeat,for循环语句
//task,function调用
end
//调用其它模块
<调用模块名module_name><例化模块名>(<端口列表port_list>);
//门元件例化
门元件关键字<例化门元件名>(<端口列表portlist>);
endmodule
说明部分和逻辑功能描述语句可以放在模块的任何地方,但是变量、寄存器、线网和参数等的说明部分必须在使用前出现。
一般为了使模块描述清晰以及具有良好的可读性,最好将说明部分放在语句前。
下面看两个简单的VerilogHDL程序。
【例7.1】二选一数据选择器
modulemux2_1(out,a,b,sel);//模块名为mux2_1(端口列表out,a,b,sel)
outputout;//模块的输出端口为out
inputa,b,sel;//模块的输入端口为a,b,sel
assignout=sel?
a:
b;//逻辑功能描述
endmodule
【例7.2】八位计数器
modulecounter8(out,cout,data,load,cin,clk);/*模块名为counter8(端口列表out,cout,data,load,cin,clk)*/
output[7:
0]out;//定义out为输出端口,位宽为8位
outputcout;//定义cout为输出端口
input[7:
0]data;//定义data为输入端口,位宽为8位
inputcin,load,clk;//定义cin,load,clk为输入端口
reg[7:
0]out;//定义out为8位宽的reg型向量
always@(posedgeclk)//逻辑功能描述
begin
if(load)
out=data;
else
out=out+cin;
end
assigncout=&out&cin;//逻辑功能描述
endmodule
可以看出,Verilog模块的内容都嵌在module和endmodule两个语句之间,每个Verilog模块包括4个主要部分:
模块声明、端口定义、信号类型说明和逻辑功能描述。
(a)模块声明
模块声明包括模块名字和模块输入、输出端口列表。
格式如下:
module端口名(端口1,端口2,端口3,……)
模块结束的关键字为:
endmodule。
(b)端口定义
端口是模块与外界或其它模块连接和通信的信号线,对模块的输入、输出端口要明确说明,格式为:
output端口名1,端口名2,……端口名N;//输出端口
input端口名1,端口名2,……端口名N;//输入端口
inout端口名1,端口名2,……端口名N;//输入/输出端口
(c)信号类型声明
对模块中所用到的所有信号(包括端口信号、节点信号等)都必须进行数据类型的定义。
语言提供了各种信号类型,分别模拟实际电路中的各种物理连接和物理实体。
如:
wirea,b,c;//定义信号a,b,c为wire型
regout;//定义信号out为reg型
reg[7:
0]out;//定义信号out的数据类型为8位reg型
如果信号的数据类型没有定义,则综合器将其默认为wire型。
其中还应注意:
输入和双向端口不能定义为寄存器型;在测试模块中不需要定义端口。
(d)逻辑功能描述
模块中最核心的部分是逻辑功能的描述。
有多中方法可以在模块中描述和定义逻辑功能,还可以调用函数(function)和任务(task)来描述逻辑功能。
7.2.2逻辑功能的几种基本描述方法
1.数据流描述(用“assign”连续赋值语句)
数据流描述方式类似于布尔方程,既含有逻辑单元的结构信息,又隐含地表示某种行为。
“assign”语句一般用于组合逻辑的赋值,称为持续赋值方式。
这种方法简单,只需将逻辑表达式放在关键字“assign”后即可。
如:
assignF=~((A&B)|(C&D));
2.结构描述
结构描述是通过实例进行描述的。
将Verilog预定义的基元实例嵌入到语言中,监控实例的输入,一旦其中任何一个发生变化,便重新运算并输出。
在Verilog语言中,可通过调用如下元件的方式来描述电路的结构:
(1)调用Verilog内置门元件(门级结构描述);
(2)调用开关级元件(开关级结构描述);
(3)用户定义元件UDP(门级结构描述);
(4)模块实例(创建层次结构)。
调用元件的方法类似于在电路图输入方式下调入库元件一样,键入元件的名字和引脚的名字即可。
要求每个实例元件的名字必须是唯一的。
如:
andmyand4(f,a,b,c,d);//调用门元件,定义了一个四输入与门
andc3(out,a,b,c)//三输入与门,名字为c3
3.行为描述
行为描述方式是一种使用高级语言的方法。
它和用软件编程语言描述没有什么不同,具有很强的通用性和有效性。
它是通过行为实例来实现的。
(1)initial语句:
一般用于仿真中的初始化,仅执行一次。
(2)always语句:
语句不断重复执行,其含义是一旦赋值给定,仿真器便等待变量的下一次变化,有无限循环之意。
如例7.2的计数器模块中:
always@(posedgeclk)//每当clk上升沿到来时执行一遍begin-end块内的语句
begin
if(load)
out=data;
else
out=out+cin;
end
这种方法多用于描述时序逻辑。
4.混合描述
在模块中,上述逻辑功能的描述方法可以混合使用。
即模块描述中可以包含实例化的门、模块实例化语句、连续赋值语句以及always语句和initial语句的混合。
它们之间可以相互包含。
来自always语句和initial语句的值能够驱动门或开关,而来自于门或连续赋值语句的值能够反过来用于触发always语句和initial语句。
下面是混合设计方式的1位全加器实例(电路示意图如图7-1):
图7-1一位全加器电路
[例7.3]1位全加器
moduleAdd1(A,B,Cin,Sum,Cout);
inputA,B,Cin;
outputSum,Cout;
regCout;
regT1,T2,T3;
wireS1;
xorX1(S1,A,B);//门实例语句。
always@(AorBorCin)//always语句
begin
T1=A&Cin;
T2=B&Cin;
T3=A&B;
Cout=(T1|T2)|T3;
end
assignSum=S1^Cin;//连续赋值语句。
endmodule
只要A或B上有事件发生,门实例语句即被执行。
只要A、B或Cin上有事件发生,就执行always语句,并且只要S1或Cin上有事件发生,就执行连续赋值语句。
7.3VerilogHDL语言要素
VerilogHDL的基本要素,包括标识符、空白符、注释、数值和字符串、数据类型及运算符等。
7.3.1标识符
VerilogHDL中的标识符(identifier)可以是任意一组字母、数字、$符号和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。
另外,标识符是区分大小写的。
以下是标识符的几个例子:
Count
COUNT//与Count不同。
_R1_D2
R56_68
FIVE$
另外还有转义标识符(escapedidentifier),可以在一条标识符中包含任何可打印字符。
转义标识符以\(反斜线)符号开头,以空白结尾(空白可以是一个空格、一个制表字符或换行符)。
下面列举了几个转义标识符:
\7400
\.*.$
\{******}
\~Q
\OutGate与OutGate相同。
最后这个例子解释了在一条转义标识符中,反斜线和结束空格并不是转义标识符的一部分。
也就是说,标识符\OutGate和标识符OutGate恒等。
7.3.2关键字
VerilogHDL定义了一系列保留字,叫做关键词,它仅用于某些上下文中。
附录A列出了VerilogHDL语言中的所有保留字。
注意只有小写的关键词才是保留字。
例如,标识符always(这是个关键词)与标识符ALWAYS(非关键词)是不同的。
另外,转义标识符与关键词并不完全相同。
标识符\initial与标识符initial(这是个关键词)不同。
注意这一约定与那些转义标识符不同。
7.3.3格式
VerilogHDL区分大小写,也就是说大小写不同的标识符是不同的。
此外,VerilogHDL是自由格式的,即结构可以跨越多行编写,也可以在一行内编写。
空白符(空格、tab、换行和换页)没有特殊意义,只是使代码错落有致,阅读起来更方便。
在综合时,空白符被忽略。
例如:
initialbeginina=3'b001;inb=3’b0l0;end
和下面的指令一样:
initial
begin
ina=3’b001;
inb=3’b010;
end
7.3.4注释
在VerilogHDL中有两种形式的注释。
/*第一种形式:
可以扩展至
多行*/
//第二种形式:
在本行结束。
7.3.5数字与字符串
VerilogHDL有下列四种基本的值:
·0:
逻辑0或“假”、低电平;
·1:
逻辑1或“真”、高电平;
·x:
未知或者不确定的状态;
·z:
高阻态;
这四种值的解释都内置于语言中。
一个为z的如值总是意味着高阻抗,一个为0的值通常是指逻辑0。
此外,x值和z值都是不分大小写的,即值0x1z与值0X1Z相同。
而且在门的输入或一个表达式中为“z”的值通常解释成“x”。
VerilogHDL中的常量是由以上这四类基本值组成的。
VerilogHDL中有三类常量:
·整型
·实数型
·字符串型
1.整数
整数的书写格式为:
<位宽>’<进制><数字>
位宽为对应二进制数的宽度,数字是基于进制的数字序列。
常用的进制有:
·二进制(b或B);
·十进制整数(d或D);
·十六进制整数(h或H);
·八进制整数(o或O);
下面是一些合法的例子:
8’b11000101//位宽为8位的二进制数11000101
3’o6//位宽为3位的八进制数6
8’ha3//位宽为8位的十六进制数a3
4’D3//4位十进制数3
108//代表十进制数108,十进制的数可以缺省位宽和进制说明
4’b1x_10//位宽为4位的二进制数1x10
5’hx//4位十六进制数x,即xxxxx
4’h1a//在位宽和和字符之间,以及进制和数值之间允许出现空格
下面是一些不正确的书写例子:
4’o-4//非法:
数值不能为负,有负号应放在最左边
4’b1x//非法:
’和进制之间不允许出现空格
(1+2)’b10//非法:
位宽不能为表达式
在书写和使用数字中还要注意以下问题:
·每一个x或z字符代表的宽度取决于所用的进制,如:
8’b1001xxxx;//等价于8’h9x;
8’b1010zzzz;//等价于8’haz;
在case语句中使用x进行匹配,可增强程序的可读性。
·在较长的数之间可用下划线分开,如16’b1010-1101-0010-1001。
下划线符号“_”可以随意用在整数或实数中,它们就数量本身没有意义。
它们能用来提高易读性;唯一的限制是下划线符号不能用作为首字符。
·当数字不说明位宽,默认值为32位。
·如果没有定义一个整数的位宽,其宽度为相应值中定义的位数。
如:
’o47//6位八进制数
’ha3//8位十六进制数
·如果定义的长度比为常量指定的长度长,通常在左边填0补位。
但是如果数最左边一位为x或z,就相应地用x或z在左边补位。
如:
8’b10左边添0补位00000010
8’bx0x1左边添x补位xxxxxox1
·如果定义的位宽比实际的位数小,则最左边的位相应地被截断。
如:
3'b1001_0011与3'b011相等
5'H0FFF与5'H1F相等
此外,"?
"是高阻态z的另一种表示符号。
2.实数
实数可以用以下两种形式定义
(1)十进制计数法
例如:
2.0//合法表示
5.678//合法表示
11572.12//合法表示
0.1//合法表示
2.//非法:
小数点两侧必须有1位数字
(2)科学计数法;
这种形式的实数举例如下:
23_5.1e2//其值为23510.0;忽略下划线
3.6E2//360.0(e与E相同)
5E-4//0.0005
Verilog语言定义了实数如何隐式地转换为整数。
实数通过四舍五入被转换为最相近的整数。
例如:
42.446,42.45转换为整数42;
92.5,92.699转换为整数93;
-15.62转换为整数-16;
-26.22转换为整数-26。
3.字符串
字符串是双引号内的字符序列。
字符串不能分成多行书写。
例如:
"INTERNALERROR"
"REACHED->HERE"
"thisisanexampleforVerilogHDL"
字符串中的特殊字符必须用字符“\”来说明,例如:
\n换行符
\tTab键
\\字符“\”本身
\’’双引号’’
\206八进制数206对应的ASCII值
7.3.6数据类型
VerilogHDL有两大类数据类型:
·线网类型。
netstype表示Verilog结构化元件间的物理连线。
它的值由驱动元件的值决定,例如连续赋值或门的输出。
如果没有驱动元件连接到线网,线网的缺省值为z。
·寄存器类型。
registertype表示一个抽象的数据存储单元,它只能在always语句和initial语句中被赋值,并且它的值从一个赋值到另一个赋值被保存下来。
寄存器类型的变量具有x的缺省值。
1.线网类型(netstype)
线网类型包含下列不同种类的线网子类型:
•wire
•tri
•wor
•trior
•wand
•triand
•trireg
•tri1
•tri0
•supply0
•supply1
其中wire是最常用的连线型变量,这里主要对其进行介绍。
wire型数据常量用来表示以assign语句赋值的组合逻辑信号。
VerilongHDL模块中的输入/输出信号类型缺省时自动定义为wire型。
Wire型信号可以用作任何方程式的输入,也可以用做"assign"语句和实例元件的输出。
对于综合而言,其取值为0,1,X,Z。
wire型变量的定义格式如下:
wire数据名1,数据名2,数据名3……数据名n;
例如:
wirea,b;//定义了两个wire型变量a,b
上面两个变量a,b的宽度都是1位,若定义一个向量(vectors),可以按以下方式:
wire[n-1:
0]数据名1,数据名2,……数据名n
wire[n:
1]数据名1,数据名2,……数据名n
他们定义了数据的宽度为n位。
如下面定义了8位宽的数据总线,20位宽的地址总线:
wire[7:
0]databus;
wire[19:
0]addrbus;
或wire[8:
1]databus;
wire[20:
1]addrbus;
wire型向量可按以下方式使用:
wire[7:
0]in,out;//定义了两个8位wire型向量in,out
assignout=in;
若只使用其中某几位,可直接指明,但应注意宽度要一致。
如:
wire[7:
0]out;
wire[3:
0]in
assignout[5:
2]=in;//out向量的第2到第5位与in向量相等
既等效于:
assignout[5]=in[3]
Assignout[4]=in[2];
Assignout[3]=in[1];
Assignout[2]=in[0];
2.寄存器类型(registertype)
有5种不同的寄存器类型。
•reg
•integer
•time
•real
•realtime
寄存器数据类型reg是最常见的数据类型。
reg类型使用保留字reg加以说明,形式如下:
Reg数据名1,数据名2,……数据名n;
例如:
rega,b;//定义了两个reg型变量a,b
上面两个变量a,b的宽度都是1位,若定义一个向量,可按以下方式:
reg[n-1:
0]数据名1,数据名2,……数据名n
reg[n:
1]数据名1,数据名2,数据名2,……数据名n
他们定义了数据的宽度为n位。
如下面的语句定义了8位宽的数据:
reg[7:
0]data;//定义data为8位宽的reg型向量
或reg[8:
1]data;
3.存储器
存储器是一个寄存器数组,若干个相同宽度的向量构成数组,reg型数组变量即为memory型变量,既可定义存储器型数据。
如:
reg[7:
0]mymem[1023:
0]
上面的依据定义了一个1024个字节,每个字节宽度为8位的存储器。
通常,存储器采用如下方式定义:
parameterwordwidth=8,memsize=1024;
reg[wordwidth-1:
0]mymem[memsize-1:
0];
上面的语句定义了一个宽度为8位、1024个存储单元的存储器,该存储器的名字是mymem,
注意存储器属于寄存器数组类型,线网数据类型没有相应的存储器类型。
单个寄存器说明既能够用于说明寄存器类型,也可以用于说明存储器类型。
如:
parameterADDR_SIZE=16,WORD_SIZE=8;
reg[1:
WORD_SIZE]Rampar[ADDR_SIZE-1:
0],DataReg;
Rampar是存储器,是16个8位寄存器数组,而DataReg是8位寄存器。
在赋值语句中需要注意如下区别:
存储器赋值不能在一条赋值语句中完成,但是寄存器可以。
如:
reg[1:
5]Dig;//Dig为5位寄存器
…
Dig=5’b11011
上述赋值都是正确的,但下述赋值不正确:
regBog[1:
5];//Bog为5个1位寄存器的存储器
…
Bog=5’b11011;
对存储器赋值可以采用分别对存储器中的每个单元进行赋值。
如:
reg[0:
3]Xrom[1:
4];
…
Xrom[1]=4’ha;
Xrom[2]=4’hb;
Xrom[3]=4’hc;
Xrom[4]=4’hd;
7.3.7参数
在verilongHDL中,用parameter来定义常量,即用parameter来定义一个标志符,代表一个常量,称为符号常量。
其定义格式如下:
parameter参数名1=表达式,参数名2=表达式,参数名3=表达式……
例如:
parameterse1=8,code=8’ha3;
//分别定义参数sel为常数8(十进制),参数code为常数a3(十六进制)
又如:
parameterdatawidth=8,addwidth=datawidth*2;
在上句中,是用常数表达式进行赋值的。
参数值也可以在编译时被改变。
改变参数值可以使用参数定义语句
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Verilog HDL