《Verilog语法简易教程.ppt》由会员分享,可在线阅读,更多相关《Verilog语法简易教程.ppt(61页珍藏版)》请在三一办公上搜索。
1、电子设计大赛 Verilog 与 FPGA,什么是Verilog HDL?,Verilog 是一种用于数字逻辑设计的硬件描述语言。在设计中常用于硬件电路的行为级描述就是告诉电路,你应该做什么,做什么,再做什么!,Verilog与C语言,Verilog的某些语法是与C相似的。但只是形似,神是不同的!Verilog只是Verilog而已,你可以参考C,但不能当做C!你必须了解Verilog的本质。,记住!,你编写的Verilog代码,是会生成实际硬件电路的。而电路,一般都不是串行执行的,很多时候都是并行工作的。所以在Verilog中,你一定要对电路的时序图与数据量图有深刻的认识!,不是所有的Ver
2、ilog代码都能够转换成实际电路的,学习语法时要分辨清楚。那些可以转换成实际电路的,我们称为“可综合”!另外,即使你使用的可综合的代码去编写,如果你描述的电路实际上无法实现,也是无法综合的!,也许在C语言中,代码越简洁越好。但是在Verilog中绝不是这样!衡量Verilog代码的唯一标准,就是在代码正确与清晰的前提下,可以生成结构尽可能简单、功能却非常强大的电路!,也许有用的Tips,多使用编译器附带RTL Viewr看看RTL级原理图,看清楚你写的代码到底生成了什么样的电路。多使用SignalTap II Logical Analyzer,看看你写的模块的时序图,看看你写的模块输出的数据的
3、值,尽量忘记C吧,C可以帮助你记住Verilog里面的关键字,但是请不要用C的思想来编写Verilog。要使用Verilog的思想来编写Verilog,多写多练吧,无论学习什么练习都是王道。当你初步掌握了Verilog之后,推荐你看看Verilog 那些事儿进行进一步的学习。什么是Verilog的思想?也许你可要在那里找到答案。,语法-符号,标识符:赋给对象的唯一名称,可以是字母、数字、下划线和符号“$”的组合,且首字符只能是字母或者下划线。区分大小写,如“if”为关键字,而“IF”不是关键字。注释:注释有两种:1,以“/*”开头,以“*/”结束。2,以“/”开头到本行结束。这些和C语言差不多
4、。,语法-数字量,逻辑数值:(1)0:逻辑0;(2)1:逻辑1;(3)x:未知,不定;(4)z:高阻态。,整数常量:基本表达格式为:长度进制 数值如:6b96位二进制数 5o55位八进制数 9d69位十进制数 8h1f8位十六进制数而没有“长度进制”声明时,默认为32位十进制数。如:40,-50。,参数:参数是特殊的常量,其语法结构是:parameter para1=const1,para2=const2 paraN=constN;如:parameter BIT=1,BYTE=8;,语法-变量定义,数据类型:数据类型用来表示数字电路硬件中的数据存储和传送元素,可以理解成变量。Verilog 中
5、总共有两大类数据类型:线网类型和寄存器类型。数据类型的总种类很多,这里只介绍两种最常用且可综合的类型:wire与reg。有兴趣的同学可以自行学习其他类型。wire是线网类型,可以理解成电路中的一根导线,在实际综合中一般也是生成连接线。reg是寄存器类型,就是电路中的寄存器、触发器或选择器。,语法-变量声明,命名规则:wire与reg变量的通用命名规则:wire/reg msb:lsb Varia1,Varia2;例如:reg3:0 Sat;/Sat为4位寄存器 wire7:0 Line;/Line为8位线网如果没有位宽声明,则默认为1位位宽。注意:reg和wire声明的都是无符号变量,若要声明
6、有符号变量,可以在reg和wire后加上关键字signed。如:reg signed 7:0 Sat;,语法-变量赋值,在Verilog中,变量是不能随意赋值的,必须使用赋值运算符才可以进行赋值。其中assign称为连续赋值,对应于线网类型变量wire;initial或always称为过程赋值,对应于寄存器类型变量reg。下面作具体讲解,语法-assign与wire,首先列个例子:wire a;assign a=1b1;可以看出,语法格式就是这么简单,如下:assign 线网型变量名=赋值表达式;需要理解的是,assign称为连续赋值的意思是,等号右端赋值表达式的值会持续对被赋值变量产生连续驱
7、动,而且只要等号右端赋值表达式的值改变,左端被赋值变量的值就会立即改变。对应到电路中去,就是导线。,语法-assign与wire,下面列举一些实际中常用的用法:(1)wire a,b;assign a=b;(2)wire 7:0 a,b;assign a=b;(3)wire 7:0 a,b;assign a3=b1;(4)wire 7:0 a,b;assign a3:0=b3:0;(5)wire a,b;wire 1:0 c;assign c=a,b;,语法-initial/always与reg,首先列举两个例子说明initial与always的区别,reg a,c;initial begin
8、 c=1b0;end,reg a,c;always(a)begin c=c+a;end,initial只会执行一次,即只执行一次把C赋零的行为;而always会不断执行,即每一次a的值改变时,c都会被重新赋值。,这两个例子也非常清楚的说明了initial/always 与reg如何配合使用。要注意的是,其中begin end是必须加入的,而也必须和always一起使用。具体在后面进行讲解。,语法阻塞与非阻塞,于连续赋值assign不同的是,过程赋值中的赋值操作符分为两种,分别是:“=”,称为阻塞赋值,指的在当前的赋值完成前阻塞其他类型的赋值任务;“=”,称为非阻塞赋值,指的从估计右端开始并不阻
9、碍执行其他的赋值操作。阻塞与非阻塞赋值的区别是Verilog中较为重要的一部分,将在后面进行详尽的讲解。,语法-算数运算符,算数运算符有5种:+,-,*,/,%,用于整型数据的数学运算。随着技术的发展,上述5种算术运算符都是可以直接综合的。需要注意的是,在进行加法和乘法运算时,要注意防止数据溢出造成运算错误。,语法-逻辑运算符与关系运算符,Verilog中的逻辑运算符与关系运算符同C语言中的用法相似,可以参考。逻辑运算符分为3种:逻辑与“逻辑不等!=。如果操作数直接的关系成立,则返回值为1;关系不成立,则返回值为0。,语法-条件运算符,条件运算符为“?:”,基本表达式为:y=x?a:b;与C语
10、言一样,x为真时返回前一个操作数a,否则返回操作数b。,语法-位运算符,Verilog用位运算符来描述硬件电路中的逻辑门,共有5种:(1):非;(2)&:与;(3)|:或;(4):异或;(5):同或。与逻辑运算符不同,位运算符是逐位操作。而逻辑运算符是对整体进行操作:101&100=100;101&100=1;,拼接运算符与重复操作符,拼接运算符是将两个或多个信号的某些位拼接起来成为一个整体数据的运算操作,其格式为:s1,s2,sn;举例如下:z3:0=a,b,c,d;shr15:0=shr14:1,b,c;重复操作符为,即双重花括号,提供复制一个常量或变量的简便记法,如:32b01=6b01
11、0101;,语法-移位运算符,移位运算符只有两种:(右移),其使用格式为:s1N,N为常数。某些情况下移位运算符的效果也可以通过拼接运算符实现,这个看个人喜好与具体电路要求。,语法-一元约简运算符,一元约简运算符是一种特殊的位运算符,它对单个操作数进行运算,最后返回一位数,具体运算过程为:首先将操作数的第一位和第二位进行位运算,然后将结果与第三位进行位运算,依次类推到最后一位,输出运算结果。示例如下:out1=一元约简运算符主要用于特殊操作中,如与约简可检测数据中是否包含位1,或约简课检测数据是否包含0。,语法-begin end,前面已经提到过beginend了。beginend在Veril
12、og中是非常基础但是十分重要的东西。那么什么是beginend?这里可以借助C来理解:“beginend就是C语言中的花括号,只不过在Verilog中有了别的用处了,所以用beginend来表示。”,语法-触发,“”,前面讲到了在过程赋值always中,必须加上。为什么?过程赋值是什么?就是如果发生了什么行为,才给你赋值。那发生的行为就要用“(行为)”来描述,我们称之为触发,完整格式为always(触发事件)begin end,语法-触发事件,触发事件有两种,这是由硬件电路决定的,在数电中已经学过:电平触发,边沿触发。,电平触发的格式为 always(a)begin end只要a的电平一改变,
13、内部的过程赋值就进行一次。电平触发不能直接选择触发的电平是高还是低,如果非要选择,可以在内部加入if语句进行判断:always(a)begin if(a=1b0)begin end end,与电平触发不同,边沿触发可以直接选择触发的边沿:posedge表示上升沿触发,negedge表示下降沿触发。如:always(posedge clk)begin end需要注意的是,边沿触发不可以选用某个信号的两个沿,即不能(posedge clk or negedge clk),注意事项!同一个always模块中只能使用一种触发方式,不可以边沿触发与电平触发混合使用。不同的触发事件中间用“or”隔开,也可
14、以用“,”隔开。,语法-条件语句if,Verilog中的if语句与C语言中十分相似,可以直接进行参考。需要注意的是,ifelse中,即使用不到else分支,语句中else分支也最好加上,否则电路有可能生成不稳定的电路,造成结果的错误。,if(a=1b1)c=1b0;应写成,if(a=1b1)c=1b0;else c=c;,语法-条件语句case,case与C语言中的switch比较类似,但是具体又有区别。其语法格式如下:,case(条件表达式)分支1:语句块1;分支2:语句块2;default:语句块n;endcase,reg 2:0 cnt;case(cnt)3b000:q=q+1;3b00
15、1:q=q+2;default:q=q;endcase,语法-条件语句case,当几个分支对应的操作相同时,可以将这些分支放在一起,如:reg 2:0 cnt;case(cnt)3b000,3b001,3b010:q=q+1;3b011,3b100:q=q+2;default:q=q;endcase,另外,同else一样,default一般不要缺省。,语法-条件语句if与case的区别,最大的区别是,if生成的电路是串行,是有优先级的编码逻辑;而case生成的电路是并行的,各种判定情况的优先级相同。因此,if生成的电路延时较大,占用硬件资源少;case生成的电路延时短,但占用硬件资源多。,语法
16、-循环语句,Verilog中也是有循环语句的,但是不推荐初学者使用。与C不同,Verilog的循环语句是依靠电路的重复生成实现的,而且并不是所有的循环语句都可以综合。感兴趣的同学可以在深入了解Verilog后自学循环语句。,语法-任务和函数,Verilog中还有两种特殊的语句:任务(task)和函数(function)。这两种语句一般用于组合电路的设计中,可以简化代码结构,但在时序电路的设计中无法使用。感兴趣的同学可以在深入了解Verilog后自行学习。,语法-模块的概念,模块(module)是Verilog中最基本的概念,也是最常用的基本单元。一个module就是一整块电路实体,一个系统就是
17、由许多个module组成的。需要注意的是,在Quartus中,一个Verilog HDL文件(*.v)中只能编写一个module,而且文件名必须与module的名字相同。,语法-module的结构,module的基本结构如下:module 模块名(端口列表)端口声明 其他声明 模块条目endmodule,端口声明有3钟:(1)input:输入端口,可以理解为输入脚;(2)output:输出端口,可以理解成输出脚;(3)inout:输入输出端口,可以理解成双向管脚。,语法-module实例:3-8译码器,module decoder3to8(din,dout);input 2:0 din;out
18、put 7:0 dout;reg 7:0 dout;always(din)begin case(din)3b000:dout=8b0000_0001;3b001:dout=8b0000_0010;3b111:dout=8b1000_0000;endcase endendmodule,语法*-阻塞与非阻塞的深入理解,前面说过,过程赋值有两种:阻塞赋值“=”和非阻塞赋值“=”。那么它们有什么区别呢?说的最简单的话,阻塞式赋值左边的变量在被赋予新值前,之后用到该变量的阻塞赋值式都无法执行,而非阻塞赋值则不会。在组合逻辑和时序逻辑电路中都可以这样理解。,语法*-阻塞与非阻塞的深入理解,首先看组合逻辑中
19、的区别,看下面两个例子,always(a,b,c,d)begin t1=aend,always(a,b,c,d)begin t1=aend,当a,b,c,d都从0变为1时,左边out输出1,右边out仍为0。因为t1的值由a,b决定,t2的值有c,d决定,在左边,由于阻塞,t1、t2被赋新值前不能给out赋值,out使用的t1,t2存储的是新的数值1;而在右边,由于 非阻塞,out赋值式立刻执行,out使用的t1,t2存储的是旧的数值0。,语法*-阻塞与非阻塞的深入理解,再来看时序逻辑中的区别,看下面两个例子,always(posedge clk)q1=d;q2=q1;q3=q2;end,al
20、ways(posedge clk)q1=d;q2=q1;q3=q2;end,可以看到,实际生产的电路是不同的。在左边,由于阻塞的关系,q3最后直接等于d,电路便被简化成左图了;在右边,由于非阻塞q2、q3分别对应着上一时钟沿的q1,q2,因此需要3级触发器来实现。,语法*-阻塞与非阻塞的深入理解,编码建议:(1)对组合逻辑建模采用阻塞式赋值;(2)对时序逻辑建模采用非阻塞式赋值;(3)同一个module中阻塞与非阻塞赋值放在不同的always块中。,语法*-模块调用,对于一个复杂的系统,是不可能把所有的功能都放在一个module中完成的。一般都是按照功能进行划分,分别封装成多个module,在
21、需要用到某个module时再去调用。被成为模块调用。下面举例说明:首先假设有一个乘法器,可以实现8位整型数乘法,其端口声明为:module mult8(a0,a1,b);input 7:0 a0,a1;output 15:0 b;endmodule,语法*-模块调用,然后在另一个module中调用它:module co(c1,c2,c3,c4,result);input 7:0 c1,c2,c3,c4;output reg result;reg15:0 temp1,temp2;mult8 inst_1(.a0(c1),.a1(c2),.b(temp1);,mult8 inst_2(.a0(c3
22、),.a1(c4),.b(temp2);result=(temp1temp2)?1:0;endmodule这样就实现了模块的调用,最终实现了将输入数据相乘后比较大小的结果输出。,语法*-模块调用,根据上面例子,可以给出模块调用的语法格式:模块名 例化后名(.端口1名(连接端口1信号名),.端口2名(连接端口2信号名),.端口3名(连接端口3信号名),);其中,掉用时端口的顺便可以改变,只要名字正确即可;例化后名不能为元模块名或关键字。,语法*-状态机,状态机并不是属于Verilog的范畴,但是通过Verilog实现状态机可以帮助我们简化很多设计,所以状态机一定要掌握!状态机可分为两种:Meal
23、y型和Moore型状态机。Mealy型状态机的输出同时依赖于当前状态和输入信号,输出可以在输入发生改变之后立刻改变,而与时钟信号无关,因此Mealy型状态机具有异步输出;Moore型状态机的输出仅仅依赖于当前状态,输出是通过组合逻辑块计算得到的,本质上是当前状态的函数。,语法*-状态机,Mealy型,Mealy型,语法*-状态机,状态机设计原则:1,给事件划分步骤,弄清楚先做什么,再做什么,做了这一步下一步应该怎么样做。2,状态化简与状态分配。检查下是否有冗余,重复的步骤。当状态划分到最简后,给每个状态进行编码分配。3,通过Verilog实现。这里有很多模板,后面进行讲解。4,观察编译结果的状
24、态流程图,检查状态机功能是否正确。,语法*-状态机,编码分配原则:状态的编码形式一般有三种,普通的二进制编码,格雷码编码,One Hot码编码(One Hot码对应关系:0,0000;1,0001;2,0010;3,0100;4,1000)。二进制码占用的数据位宽比较简单,但容易产生毛刺;格雷码一定程度减少了毛刺的产生;One Hot码不会产生毛刺,可以使状态机达到较高的工作频率,但是会增加触发器的占用。具体选用什么码根据实际需求,一般普通二进制编码即可。,语法*-状态机,“一段式”状态机Verilog模板:always(posedge clk)begin if(!rst_n)begin st
25、ate=out=end else begin case(state)s0:begin state=out=end,s1:begin state=out=end endcase endend 这种形式输出向量不会产生毛刺,但是不能实现异步Mealy有限状态机。,语法*-状态机,“二段式”状态机Verilog模板:/状态调转always(posedge clk)begin if(!rst_n)state=idle;else state=next_state;end/下一状态的计算以及输出逻辑always(state)begin case(state)s0:begin next_state=out=
26、,end s1:begin next_state=out=end endcaseend 这种形式具有最优的面积和时序性能,但输出组合逻辑,有可能产生毛刺。,语法*-状态机,飞“三段式”状态机Verilog模板:/状态调转always(posedge clk)begin if(!rst_n)state=idle;else state=next_state;end/下一状态的计算always(posedge clk)begin case(state)s0:next_state=s1:next_state=endcase,end/输出的逻辑处理always(posedge clk)begin cas
27、e(state)s0:out=s1:put=endcaseend 这种形式的输出同样无毛刺,是一些参考书上的推荐写法。,写在Verilog的最后,下面是一些我推荐的代码风格,同学们可以参考一下,希望对同学们学习Verilog有帮助;模块声明:module(/input a,b,/output c,d);在声明时就用注释将输入输出脚区别出来。,写在Verilog的最后,异步复位的always:always(posedge clk,negedge rst_n)begin if(!rst_n)begin/一堆复位的行为 end else begin endend模块带有异步复位的功能推荐都这样写,F
28、PGA的概述,Filed programmable gate array,现场可编程门阵列。FPGA的引脚分为电源脚,I/O脚,特殊功能脚。能给外设使用的只有I/O脚。FPGA的逻辑实现是通过查找表的方式实现的,就是通过RAM来实现逻辑函数。所以,FPGA内部没有真正的逻辑门。,FPGA使用注意,FPGA内部是RAM,RAM掉电丢失数据,所以与CPLD不同,FPGA普通下载的程序在掉电后是没有了的。FPGA内部没有真正的逻辑门,所以不要在内部使用带高阻态的输出相连,编译器不会报错,但是电路功能是无法实现的。如果非要把两个输出连一起,可以使用“:?”进行二选一。FPGA的I/O引脚电路是支持双向
29、高阻态的。,FPGA内部硬件,1.锁相环(PLL):可以将输入的晶振时钟信号分频或者倍频。注意:FPGA内部对时序有着严格的要求,而PLL的输入输出都是使用的特殊设计的时钟信号线。因此当工作在高频时,你们自己编写的FPGA模块一般都必须采用PLL的输出作为时钟信号。,FPGA内部硬件,基本逻辑单元:不同FPGA的基本逻辑单元的命名不同,但其内部都是由:查找表,缓冲器,选择器,触发器等构成的。硬件乘法器:好一点的FPGA内部都集成有硬件乘法器,可以一个时钟周期完成整型乘法。,FPGA内部硬件,RAM模块:FPGA内部都集成有RAM模块,Quartus生成的ROM,RAM,FIFO都是使用基本逻辑
30、单元加RAM模块综合的。DSP模块:高端的FPGA内部还集成有DSP模块,专用于一些DSP算法。(不过,我们的cyclone里面没有),Quartus工具推荐,这就是大名鼎鼎的逻辑分析仪,可以查看FPGA内部任何模块的任意端口的数值,支持硬件触发和软件触发。缺点是它是硬件实现的,会占用FPGA内部资源,而且对被观察的模块有影响,有时会造成“去掉逻辑分析仪功能就不对了”的结果。,Quartus工具推荐,这个工具可以查看FPGA内部RAM或ROM中存储的数值,甚至进行修改。只要在生成RAM(ROM)时将下面的勾上即可。注意:双口RAM内的值无法用这个工具查看!,Quartus工具推荐,这个工具可以
31、将tcl脚本文件导入到工程中。tcl脚本是很强大的,你可以在里面进行管脚的分频,管脚电压、方向的设定,各模块之间关系的说明。总之,很强大。,Quartus工具推荐,这个是用来查看编译生成的RTL级原理图的,也就是说你写的代码所生成的硬件电路。我强烈要求你们多看看RTL级原理图,从硬件角度理解你们写的东西是什么,便于你们形成Verilog编程思想。,Quartus工具推荐,这个工具是用来看状态机的状态流程图的。当你们编写了状态机后,可以通过这个工具来检查状态机的功能是否正确。,Quartus工具推荐,“F1”对,就是键盘的按键F1!如果你编译出错了,左键点击那个报错,然后用F1看看你为什么错了。Quartus提供强大的帮助系统,有疑问多查阅官方资料。,谢谢观赏,Make Presentation much more fun,