verilog 学习笔记Word文档格式.docx
- 文档编号:17525663
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:31
- 大小:198.25KB
verilog 学习笔记Word文档格式.docx
《verilog 学习笔记Word文档格式.docx》由会员分享,可在线阅读,更多相关《verilog 学习笔记Word文档格式.docx(31页珍藏版)》请在冰豆网上搜索。
而Verilog的仿真软件也是顺序执行的,在时间关系上同实际的硬件是有差异的,可能会出现一些无法发现的问题。
Verilog可用的输出输入函数很少。
C语言的花样则很多,转换过程中会遇到一些困难。
C语言的函数调用与Verilog中模块的调用也有区别。
C程序调用函数是没有延时特性的,一个函数是唯一确定的,对同一个函数的不同调用是一样的。
而Verilog中对模块的不同调用是不同的,即使调用的是同一个模块,必须用不同的名字来指定。
Verilog的语法规则很死,限制很多,能用的判断语句有限。
仿真速度较慢,查错功能差,错误信息不完整。
仿真软件通常也很昂贵,而且不一定可靠。
C语言没有时间关系,转换后的Verilog程序必须要能做到没有任何外加的人工延时信号,也就是必须表达为有限状态机,即RTL级的Verilog,否则将无法使用综合工具把Verilog源代码转化为门级逻辑。
3)如何利用C语言来加快硬件的设计和查错
下表中列出了常用的C与Verilog相对应的关键字与控制结构
下表中,列出了C与Verilog相对应的运算符
从上面的讨论我们可以总结如下:
C语言与Verilog硬件描述语言可以配合使用,辅助设计硬件
C语言与Verilog硬件描述语言很象,只要稍加限制,C语言的程序很容易转成Verilog
的程序
1.2VerilogHDL与VHDL
VerilogHDL和VHDL都是用于逻辑设计的硬件描述语言,并且都已成为IEEE标准。
VHDL是在1987年成为IEEE标准,VerilogHDL则在1995年才正式成为IEEE标准。
之所以VHDL比VerilogHDL早成为IEEE标准,这是因为VHDL是美国军方组织开发的,而VerilogHDL则是从一个普通的民间公司的私有财产转化而来,基于VerilogHDL的优越性,才成为的IEEE标准,因而有更强的生命力。
VHDL其英文全名为VHSICHardwareDescriptionLanguage,而VHSIC则是VeryHighSpeedIntegeratedCircuit的缩写词,意为甚高速集成电路,故VHDL其准确的中文译名为甚高速集成电路的硬件描述语言。
VerilogHDL和VHDL作为描述硬件电路设计的语言,其共同的特点在于:
能形式化地抽象表示电路的结构和行为、支持逻辑设计中层次与领域的描述、可借用高级语言的精巧结构来简化电路的描述、具有电路仿真与验证机制以保证设计的正确性、支持电路描述由高层到低层的综合转换、硬件描述与实现工艺无关(有关工艺参数可通过语言提供的属性包括进去)、便于文档管理、易于理解和设计重用。
但是VerilogHDL和VHDL又各有其自己的特点。
由于VerilogHDL早在1983年就已推出,至今已有十三年的应用历史,因而VerilogHDL拥有更广泛的设计群体,成熟的资源也远比VHDL丰富。
与VHDL相比VerilogHDL的最大优点是:
它是一种非常容易掌握的硬件描述语言,只要有C语言的编程基础,通过二十学时的学习,再加上一段实际操作,一般同学可在二至三个月内掌握这种设计技术。
而掌握VHDL设计技术就比较困难。
这是
因为VHDL不很直观,需要有Ada编程基础,一般认为至少需要半年以上的专业培训,才能掌握VHDL的基本设计技术。
目前版本的VerilogHDL和VHDL在行为级抽象建模的覆盖范围方面也有所不同。
一般认为VerilogHDL在系统级抽象方面比VHDL略差一些,而在门级开关电路描述方面比VHDL强得多。
下面图1-3是VerilogHDL和VHDL建模能力的比较图示供读者参考:
VerilogHDL较为适合系统级(System)、算法级(Alogrithem)、寄存器传输级(RTL)、逻辑级(Logic)、门级(Gate)、电路开关级(Switch)设计,而对于特大型(几百万门级以上)的系统级(System)设计,则VHDL更为适合,由于这两种HDL语言还在不断地发展过程中,它们都会逐步地完善自己。
美国和中国台湾地区逻辑电路设计和制造厂家大都以VerilogHDL为主,中国大陆地区目前学习使用VHDL的较多。
到底选用VHDL或是VerilogHDL來配合C一起用,就留給各位
自行去決定。
但从学习的角度来看,VerilogHDL比較簡單,也與C语言较接近,容易掌握。
从使用的角度,支持Verilog硬件描述语言的半导体厂家也较支持VHDL的多。
2有关Verilog中的一些语法
2.1运算符
位运算符
1)~//取反
2)&
//按位与
3)|//按位或
4)^//按位异或
5)^~//按位同或(异或非)
逻辑运算符
在VerilogHDL语言中存在三种逻辑运算符:
1)&
&
逻辑与
2)||逻辑或
3)!
逻辑非
等式运算符
在VerilogHDL语言中存在四种等式运算符:
1)==(等于)
2)!
=(不等于)
3)===(等于)
4)!
==(不等于)
"
=="
和"
!
="
又称为逻辑等式运算符。
其结果由两个操作数的值决定。
由于操作数中某些位可能是不定值x和高阻值z,结果可能为不定值x。
而"
==="
运算符则不同,它在对操作数进行比较时对某些位的不定值x和高阻值z也进行比较,两个操作数必需完全一致,其结果才是1,否则为0。
运算符常用于case表达式的判别,所以又称为"
case等式运算符"
。
位移运算符
左移:
右边的添0
右移:
左边的添0,移除的位舍去
举例:
4’b1001<
<
1=5’b10010;
4’b1001<
2=6’b100100;
1<
6=32’b1000000;
4’b1001>
>
1=4’b0100;
4=4’b0000;
位拼接运算符
1.{a,b[3:
0],w,3’b101}也可以写成为{a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1}
2.{4{w}}//这等同于{w,w,w,w}
3.{b,{3{a,b}}}//这等同于{b,a,b,a,b,a,b}
负数:
一个数字可以被定义为负数,只需在位宽表达式前加一个减号,减号必须写在数字定义表达式的最前面。
注意减号不可以放在位宽和进制之间也不可以放在进制和具体的数之间。
见下例:
-8'
d5//这个表达式代表5的补数(用八位二进制数表示)
2.2Wire、reg、tri、memory型
wire型变量通常是用来表示单个门驱动或连续赋值语句驱动的网络型数据,tri型变量则用来表示多驱动器驱动的网络型数据。
如果wire型或tri型变量没有定义逻辑强度(logicstrength),在多驱动源的情况下,逻辑值会发生冲突从而产生不确定值。
wire型数据常用来表示用于以assign关键字指定的组合逻辑信号。
Verilog程序模块中输入输出信号类型缺省时自动定义为wire型。
寄存器是数据储存单元的抽象。
寄存器数据类型的关键字是reg,通过赋值语句可以改变寄存器储存的值,其作用与改变触发器储存的值相当。
reg类型数据的缺省初始值为不定值x。
reg型数据常用来表示用于“always”模块内的指定信号,常代表触发器。
通常,在设计中要由“always”块通过使用行为描述语句来表达逻辑关系。
在“always”块内被赋值的每一个信号都必须定义成reg,reg型只表示被定义的信号将用在“always”块内,理解这一点很重要。
并不是说reg型信号一定是寄存器或触发器的输出。
虽然reg型信号常常是寄存器或触发器的输出,但并不一定总是这样。
VerilogHDL通过对reg型变量建立数组来对存储器建模,可以描述RAM型存储器,ROM存储器和reg文件。
数组中的每一个单元通过一个数组索引进行寻址。
在Verilog语言中没有多维数组存在。
memory型数据是通过扩展reg型数据的地址范围来生成的。
reg[7:
0]mema[255:
0];
这个例子定义了一个名为mema的存储器,该存储器有256个8位的存储器。
该存储器的地址范围是0到255。
尽管memory型数据和reg型数据的定义格式很相似,但要注意其不同之处。
如一个由n个1位寄存器构成的存储器组是不同于一个n位的寄存器的。
见下例:
reg[n-1:
0]rega;
//一个n位的寄存器
regmema[n-1:
//一个由n个1位寄存器构成的存储器组
一个n位的寄存器可以在一条赋值语句里进行赋值,而一个完整的存储器则不行。
rega=0;
//合法赋值语句
mema=0;
//非法赋值语句
如果想对memory中的存储单元进行读写操作,必须指定该单元在存储器中的地址。
下面的写法是正确的。
mema[3]=0;
//给memory中的第3个存储单元赋值为0。
2.3assign和always语句
模块中最重要的部分是逻辑功能定义部分。
有三种方法可在模块中产生逻辑。
1).用“assign”声明语句
采用“assign”语句是描述组合逻辑最常用的方法之一。
如:
assigna=b&
c;
2).用实例元件
andand_inst(q,a,b);
采用实例元件的方法象在电路图输入方式下,调入库元件一样。
键入元件的名字和相连的引脚即可,表示在设计中用到一个跟与门(and)一样的名为and_inst的与门,其输入端为a,b,输出为q。
要求每个实例元件的名字必须是唯一的,以避免与其他调用与门(and)的实例混淆。
3).用“always”块
“always”块既可用于描述组合逻辑也可描述时序逻辑。
如果用Verilog模块实现一定的功能,首先应该清楚哪些是同时发生的,哪些是顺序发生的。
上面三个例子分别采用了“assign”语句、实例元件和“always”块。
这三个例子描述的逻辑功能是同时执行的。
也就是说,如果把这三项写到一个VeriIog模块文件中去,它们的次序不会影响逻辑实现的功能。
这三项是同时执行的,也就是并发的。
然而,在“always”模块内,逻辑是按照指定的顺序执行的。
“always”块中的语句称为“顺序语句”,因为它们是顺序执行的。
请注意,两个或更多的“always”模块也是同时执行的,但是模块内部的语句是顺序执行的。
always块的语法原则:
1)每个always块只能有一个事件控制"
@(event-expression)"
而且要紧跟在always关键字后面。
2)always块可以表示时序逻辑或者组合逻辑,也可以用always块既表示电平敏感的透明锁存器又同时表示组合逻辑。
但是不推荐使用这种描述方法,因为这容易产生错误和多余的电平敏感的透明锁存器。
3)带有posedge或negedge关键字的事件表达式表示沿触发的时序逻辑,没有posedge或negedge关键字的表示组合逻辑或电平敏感的锁存器,或者两种都表示。
在表示时序和组合逻辑的事件控制表达式中如有多个沿和多个电平,其间必须用关键字“or”连接。
4)每个表示时序always块只能由一个时钟跳变沿触发,置位或复位最好也由该时钟跳变沿触发。
5)每个在always块中赋值的信号都必需定义成reg型或整型。
整型变量缺省为32bit,使用Verilog操作符可对其进行二进制求补的算术运算。
综合器还支持整型量的范围说明,这样就允许产生不是32位的整型量。
句法结构:
integer[<
msb>
:
lsb>
]<
identifier>
6)always块中应该避免组合反馈回路。
每次执行always块时,在生成组合逻辑的always块中赋值的所有信号必需都有明确的值;
否则,需要设计者在设计中加入电平敏感的锁存器来保持赋值前的最后一个值,只有这样综合器才能正常生成电路。
如果不这样做综合器会发出警告提示设计中插入了锁存器。
如果在设计中存在综合器认为不是电平敏感锁存器的组合回路时,综合器会发出错误信息(例如设计中有异步状态机时)。
上面这一段不太好理解,让我们再解释一下,这也就是说,用always块设计纯组合逻辑电路时,在生成组合逻辑的always块中参与赋值的所有信号都必需有明确的值[即在赋值表达式右端参与赋值的信号都必需在always@(敏感电平列表)中列出],如果在赋值表达式右端引用了敏感电平列表中没有列出的信号,那么在综合时,将会为该没有列出信号隐含地产生一个透明锁存器,这是因为该信号的变化不会立刻引起所赋值的变化,而必须等到敏感电平列表中某一个信号变化时,它的作用才显现出来,也就是相当于存在着一个透明锁存器把该信号的变化暂存起来,待敏感电平列表中某一个信号变化时再起作用,纯组合逻辑电路不可能做到这一点。
这样,综合后所得电路已经不是纯组合逻辑电路了,这时综合器会发出警告提示设计中插入了锁存器。
见下例。
例:
inputa,b,c;
rege,d;
always@(aorborc)
begin
e=d&
a&
b;
/*因为d没有在敏感电平列表中,所以d变化时,e不能立刻变化,要等到a或b或c变化时才体现出来,这就是说实际上相当于存在一个电平敏感的透明锁存器在起作用,把d信号的变化锁存其中*/
d=e|c;
end
边沿触发的always块常常描述时序逻辑,如果符合可综合风格要求可用综合工具自动转换为表示时序逻辑的寄存器组和门级逻辑,而电平触发的always块常常用来描述组合逻辑和带锁存器的组合逻辑,如果符合可综合风格要求可转换为表示组合逻辑的门级逻辑或带锁存器的组合逻辑。
一个模块中可以有多个always块,它们都是并行运行的。
2.4阻塞赋值和非阻塞赋值
1.非阻塞(Non_Blocking)赋值方式(如b<
=a;
),在描述时序逻辑的always块中用非阻塞赋值,则综合成时序逻辑的电路结构。
1)块结束后才完成赋值操作。
2)b的值并不是立刻就改变的。
3)这是一种比较常用的赋值方法。
(特别在编写可综合模块时)
2.阻塞(Blocking)赋值方式(如b=a;
),在描述组合逻辑的always块中用阻塞赋值,则综合成组合逻辑的电路结构。
1)赋值语句执行完后,块才结束。
2)b的值在赋值语句执行完后立刻就改变的
3)可能会产生意想不到的结果。
到目前为止,前面所举的例子中的"
always"
模块内的reg型信号都是采用
下面的这种赋值方式:
b<
这种方式的赋值并不是马上执行的,也就是说"
块内的下一条语句执行后,b并不等于a,而是保持原来的值。
块结束后,才进行赋值。
而另一种赋值方式阻塞赋值方式,b=a;
这种赋值方式是马上执行的。
也就是说执行下一条语句时,b已等于a。
[例1]:
always@(posedgeclk)
b<
=a;
c<
=b;
[例1]中的"
块中用了非阻塞赋值方式,定义了两个reg型信号b和c,clk信号的上升沿到来时,b就等于a,c就等于b,这里应该用到了两个触发器。
请注意:
赋值是在"
块结束后执行的,c应为原来b的值。
这个"
块实际描述的电路功能如下图所示:
[例2]:
always@(posedgeclk)
b=a;
c=b;
[例2]中的"
块用了阻塞赋值方式。
clk信号的上升沿到来时,将发生如下的变化:
b马上取a的值,c马上取b的值(即等于a),生成的电路图如下所示只用了一个触发器来寄存器a的值,又输出给b和c。
这大概不是设计者的初衷,如果采用[例1]所示的非阻塞赋值方式就可以避免这种错误
关于赋值语句的编写规则:
1)时序电路建模时,用非阻塞赋值。
2)锁存器电路建模时,用非阻塞赋值。
3)用always块建立组合逻辑模型时,用阻塞赋值。
4)在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。
5)在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
6)不要在一个以上的always块中为同一个变量赋值。
7)用$strobe系统任务来显示用非阻塞赋值的变量值
8)在赋值时不要使用#0延迟
2.5Verilog中使用的一些关键字
always,and,assign,begin,buf,bufif0,bufif1,case,casex,casez,cmos,deassign,
default,defparam,disable,edge,else,end,endcase,endmodule,endfunction,endprimitive,endspecify,endtable,endtask,event,for,force,forever,fork,function,highz0,highz1,if,initial,inout,input,integer,join,large,macromodule,medium,module,nand,negedge,nmos,nor,not,notif0,notifl,or,output,parameter,pmos,posedge,primitive,pull0,pull1,pullup,pulldown,rcmos,reg,releses,repeat,mmos,rpmos,rtran,rtranif0,rtranif1,scalared,small,specify,specparam,strength,strong0,strong1,supply0,supply1,table,task,time,tran,tranif0,tranif1,tri,tri0,tri1,triand,trior,trireg,vectored,wait,wand,weak0,weak1,while,wire,wor,xnor,xor
所以,在对变量进行命名的时候,避免使用以上的名字,以免造成混乱而使系统无法进行争取识别。
下面主要介绍几种常用的。
1.Repeat语句
在repeat语句中,其表达式通常为常量表达式。
下面的例子中使用repeat循环语句及加法和移位操作来实现一个乘法器。
parametersize=8,longsize=16;
reg[size:
1]opa,opb;
reg[longsize:
1]result;
begin:
mult
1]shift_opa,shift_opb;
shift_opa=opa;
shift_opb=opb;
result=0;
repeat(size)
if(shift_opb[1])
result=result+shift_opa;
shift_opa=shift_opa<
1;
shift_opb=shift_opb>
也可以用for语句来实现:
for(bindex=1;
bindex<
=size;
bindex=bindex+1)
if(opb[bindex])
result=result+(opa<
(bindex-1));
2.task和function说明语句的不同点
task和function说明语句分别用来定义任务和函数。
利用任务和函数可以把一个很大的程序模块分解成许多较小的任务和函数便于理解和调试。
输入、输出和总线信号的值可以传入、传出任务和函数。
任务和函数往往还是大的程序模块中在不同地点多次用到的相同的程序段。
学会使用task和function语句可以简化程序的结构,使程序明白易懂,是编写较大型模块的基本功
任务和函数有些不同,主要的不同有以下四点:
1)函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位。
2)函数不能启动任务,而任务能启动其它任务和函数。
3)函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量。
4)函数返回一个值,而任务则不返回值。
函数的目的是通过返回一个值来响应输入信号的值。
任务却能支持多种目的,能计算多个结果值,这些结果值只能通过被调用的任务的输出或总线端口送出。
VerilogHDL模块使用函数时是把它当作表达式中的操作符,这个操作的结果值就是这个函数的返回值。
下面让我们用例子来说明:
例如,定义一任务或函数对一个16位的字进行操作让高字节
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- verilog 学习笔记 学习 笔记