第二一章、Verilog的部分语法_第1页
第二一章、Verilog的部分语法_第2页
第二一章、Verilog的部分语法_第3页
第二一章、Verilog的部分语法_第4页
第二一章、Verilog的部分语法_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、本节讲述部分的verilog 语法主要包括位拼接 ”的用法Parameter 用法Begin end 语句块同步与异步条件语句case , if 等阻塞赋值与非阻塞赋值边沿检测电路(双边沿触发的计数器)按键去抖动出路设计用法在C语言中,是复合语句,但是在 verilog 中,有着不同的含义-位拼接运算符。即, 将几个1位或者是多位的变量拼接成位更宽的量。假设 a=1' b0;b=3' b101;c=2' b11那么c,b,a二6 ' b11_101_0。下划线可以使结果看起来更加清晰,别无他意。又如c0,b2:1,c1 = 4' b1_10_1;实例:使

2、用 一位全加器的设计。全加器和半加器类似,只是在输入端还有一个进位输入端Ci ,电路符号如下:CiFullAdder1bitCo回顾前面的讲述,半加器中我们使用了2位的变量temp来保存运算结果,而实际上这个temp就是Co和S的拼接,即Co, S = temp 。这里三个1位的数相加结果最大仍然是 2位,使用Co, S 代替半加器中temp的代码如下:module FullAdder(A,B,Ci,Co,S);input A,B,Ci; wire A,B,Ci;output Co,S; wire Co,S;assign Co,S=A+B+Ci;/endmodule代码注释:A+B+Ci的和存

3、入 Co,S 拼接符中,Co为高位,S为低位。有时候还用作 复制运算符,例如:A=1' b1;o 一B=2A;则,B的值为A复制2次,即二进制的11 (2' bllO 注释:部分EDA工具可能不支持此复制运算符功能。Parameter 关键字Verilog 中使用parameter关键字来定义常量。例如:parameter W=5那么在任何时候W就代表5。通常在可变宽度的设计中很有用。为可变宽度变量的设计提供了方便。接下来以 4位全加器的设计演示 parameter关键字的使用。例:4位全加器的设计根据要求,全加器要有两个 4位的输入端,一个进位输入端Ci , 一个4位的和隼出

4、端 S和一个进位输出端 Co。模块图如下:CiFullAdder4bitCoA3.0B3.0S3.0这里使用parameter关键字定义一个常量 WIDTH为4 ,即parameter WIDTH=4 ;然后在位宽设计的时候采用这个符号WIDTH来定义,如:wire WIDTH-1:0 A ;则A为4位宽的连线。完整代码如下:module FullAdderNbit(A,B,Ci,Co,S);parameter WIDTH=4; /input WIDTH-1:0A,B;wire WIDTH-1:0A,B;input Ci;wire Ci;output WIDTH-1:0 S;wire WIDT

5、H-1:0 S;output Co;wire Co;assign Co,S=A+B+Ci;endmodule代码注释:可以在module和endmodule 之间的任何位置使用 parameter关键字定义常量。综合后的RTL视图如下,可以看出全加器的输入都是4位的。使用parameter 的关键字的好处之一是,当我们需要另外一个 8位的全加器的时候,我们 不需要修改很多代码,只需要将 parameter WIDTH=4 ;中的4换成8即可。然后重新综 合,查看一下是否变为了8位全加器。begin end 块语句begin end 的功能相当于c语言中的复合语句“。”的功能,即把好几条语句组合

6、在一 起作为一条语句执行。此处以模N计数器做实例讲解 begin end的用法。模N计数器,即计数器的技术个数为N个,如果计数器从0开始计数,当记到 N-1时候就开始下一轮的计数,即计数范围从0N-1。实例:模10计数器设计。假设该计数器有两个端口,时钟输入端clk,计数器输出端cntr ,技术范围从09。代码如下:module counter10(clk,cntr);input clk; output reg 3:0 cntr; /always(posedge clk)begin/(4)if(cntr = 4'b1001) -(2)cntr = 0;elsecntr = cntr +

7、 1; /-(3)end/(4)endmodule代码注释:(1) Verilog HDL中允许将端口和类型放在一起声明。output reg 3:0 cntr;相当于output 3:0 cntr;output reg 3:0 cntr;两条语句的功能。输入的类型如果不声明,则默认为wire 型。如:input clk;没有声明clk 类型,则表示 clk为wire 型。cntr 宽度为4位,因为9变为二进制是1001 ,占4(2)和(3) 这里判断的是 cntr 是否为9 (二进制1001 ),而不是10。要特别注意!这里 分析一下电路的动作,每个加 1动作的进行都需要 posedge c

8、lk才能进行,计数器是从 开始计数的,当cntr变到9时就已经用了 10个posedge clk 了。如果让电路再次动作, 就需要第11个posedge clk ,而这时的计数值应该为0 (模10已经完成了,下一个周期开始)。所以在第11个posedge clk到来之前计数值为 9。这和C语言中的运行方式完全不同,不是顺序执行的,切记! 另外,有的同学会问,为什么不这样写begincntr = cntr + 1;if(cntr = 4'b1001) cntr = 0;end这种写法里面,begin 和end之间有2条语句,原代码中是一条if语句。一定要记住硬件描述语言生成的硬件电路,这

9、两条语句都同时对 cntr进行赋值操作(只看语句本身,不要带入语句的含义去看),这在电路上是不允许的,也就是说不可能有个电路的输出有两种 同时给的驱动! 尽管有些EDA软件工具会智能化的理解并生成正确的电路,但在学习中一 定要避免这种方式的使用,切记!(4)这两个(4) 一定要成对使用。这个块还可以给起个名字,叫做块名。没有什么电气意 义,只是使代码看起来更清晰明了。用法如下:begin : aaaaif(cntr = 4'b1001)cntr = 0; elsecntr = cntr + 1; end:aaaa 就是begin end 块的块名 同步电路与异步电路从上一节的D触发器设

10、计的RTL视图中我们可以看出,D触发器本身的功能引脚较多,而我们使用的就 CP和D、Q三个。下面我们尝试着使用其他的引脚。D触发器设计实例2:具有同步复位功能的 D触发器设计。在最简单的D触发器基础上设计带复位端输入的D触发器。即使用RTL图中的CLRMyDff2Q脚。电路图如下。DCPCLR复位功能在数字电路中有 同步复位和异步复位 两类。所谓同步,指的是与时钟同步,也 就是D触发器的任何输出都需要有时钟的上升沿才能产生输出。所谓异步是指即使没有时 钟的上升沿也能够产生输出行为。这两种方式在Verilog HDL中都给予了支持。同步复位D触发器指当复位引脚端有效时(通常约定为高电平,也可以根

11、据需要设计成低电平),在时钟上升沿出现时,D触发器会输出(Q端)复位(即为0),否则,在时钟上升沿出现时,将 D端的值传递至Q端。同步复位D触发器设计:module MyDff2_sync(cp,d,q,clr);input cp;input d;input clr;output q;wire cp; reg q;wire d, clr; /(4)always(posedge cp)if(clr = 1'b1)/q=1'b0;/(2)else/(3)q=d;endmodule代码注释:(1)如果条件成立,即 clr为高电平时,进行(2)(2)q端口输出低电平,即复位(3)否则,

12、如果clr端口不为高电平,则进行 d触发器的正常工作行为。(4)语法,可以将相同类型的端口或者端口类型写在一个关键字的后面,中间用逗号隔 开,最后放一个分号。类似 c语言中的一次定义多个相同类型的变量方式。查看一下生成的 RTL视图此时RTL图发生了变化,图中多了一个2选1的模块。根据此图分析,当 clr为高电平 时,二选一的数据选择器会选择0至D触发器的输入端,故,当 D触发器的时钟上升沿出现时,会将0送至输出q端;如果clr为低电平,则将 d送至输出q端。这里,RTL视图中 没有使用D触发器本身的 CLR弓|脚,因此也可以推测 D触发器本身的CLR引脚不是同步 复位功能引脚,而是异步复位功

13、能。可以在接下来的D触发器设计实例3中得到验证。这里使用了 if else语句对clr的电平值进行判断,如果为高,就执行功能1,否则的话执行功能2。此if-else语句的功能和c语言中的if-else语句功能完全一致,不再详细论述。D触发器设计实例3:具有异步复位功能的D触发器设计。异步复位D触发器指当复位引脚端有效时(通常约定为高电平,也可以根据需要设计 成低电平),D触发器就会立刻输出(Q端)复位(即为 0),否则,将D端的值传递至 Q 端。这个动作的过程 没有时钟的参与!异步复位D触发器设计:module MyDff3_async(cp,d,q,clr);input cp;input d

14、;input clr;output q;wire cp; reg q;always(posedge cp , posedge clr) /if(clr = 1'b1)q=1'b0;else q=d;endmodule代码注释:(1)和同步复位D触发器的区别在于 always后面的括号中多了一个条件posedge clr。也就是说,这个 always模块的动作可以在时钟cp的上升沿来触发,也可以由clr的上升沿来触发。两个条件之间用逗号“,”隔开,表示 或的关系,也可以用关键字or代替。也就是说,或者posedge cp来触发电路动作,或者 posedge clr来触发电路动作。

15、这样,即使没有 cp的上升沿,也可以产生动作,这就是异步的由来。生成的RTL视图如下qreg0这是大家看到,clr的端口直接连接到了 D触发器的CLR端上,也充分说名了这个端是 异步端口,也可以从仿真的图上来说明。在25ns时刻,clr为低电平,这时候 d触发器正常工作,将 d端输出至q端,因d为高 电平,故q端这时候变高。在 60ns时刻,这个时刻,没有出现 cp的上升沿,但是输出端发 生了变化,很显然是由于 clr的变化导致的q端输出。因此,这个 D触发器是异步复位的 D 触发器。特别注意,在always块的 (触发信号)中,有 2个信号,为什么在生成电路的时候 将cp连接到了 D触发器的

16、时钟端,而将clr端口连接到了 D触发器的CLR端呢?为什么不 将cp连接到CLR端,clr连接到时钟输入上呢?难道是因为名称的缘故?答案是否定的。这里注意到,尽管 (触发信号)中有两个信号,但是其中一个信号clr在always块的内部做了判断if (clr = 1' bl),而另一个没有判断。 VerilogHDL综合器规定,在 always块语 句中被判断的量一定是复位或者是置位端口,always块中没有判断的量一定是时钟。 换句话说,时序电路的时钟在 always 块中是不允许进行电平高低的判定和读取等操作的。小测试,将上述代码修改成以下代码并综合module MyDff3_as

17、ync(cp,d,q,clr);input cp;input d;input clr;output q; wire cp; reg q;always(posedge cp , posedge clr)if(cp = 1'b1)/(1)q=1'b0; elseq=d;endmodule代码注释:(1)这里将if语句后面的clr换成了 cp,编译后查看 RTL视图如下:qreg0 PRE d > DQ 1>qclr >- ->ENA CLR cp 图中将cp连接到了 CLR端,而将clr连接到了 D触发器的时钟端,充分证明了上述观 点°D触发器设计

18、实例4:具有复位和置位功能的D触发器设计。 此处为了节约篇幅,只进行异步置位、异步复位(复位优先)的方式进行设计,其余方 式的D触发器请自行设计。module MyDff4(cp,d,q,clr,pre);input cp;input d;input clr;input pre;output q;wire cp; reg q;wire d,clr,pre;always(posedge cp , posedge clr , posedge pre)if(clr = 1'b1)q=1'b0;else if(pre = 1'b1)q = 1'b1;elseq = d;

19、endmodule生成RTL视图如下:条件语句case , if 等If语句和case语句是Verilog HDL的典型条件语句,其中 if 语句的用法和c语言中的用法完全一致,在此处,不在详细叙述。但注意,如果有多个if else 语句同时使用的话,else 总是和最近的if配对。以下以带有同步加载、同步清零的8位计数器为例示范if语句的使用。根据设计的要求,此模块图应该具有以下端口该计数器有5个端口,其中,clk为计数时钟,din为8为的数据置入端,dout为8位的 计数数据输出端,load为初值置入使能端,假设高电平有效,clr为计数清零端,假设高电平有效。当load和clr均为低电平时

20、,计数器正常计数。module counter8bit(clk,din,load,clr,dout);input clk;input 7:0 din;input load;input clr;output reg 7:0 dout;always(posedge clk)beginif(clr = 1)dout = 0;else if(load = 1)dout = din;elsedout = dout + 1;endendmodule在功能部分的语句中,先判断 clr是否有效(高电平),如果有效则给计数器清 0;否则检 查10ad是否有效,如果有效(高电平),则把初值din赋给计数器输出,如

21、果load无效, 则正常加1计数。读者试着使用if语句对该计数器进行增加功能,变为模 60的计数器。If语句示例2 :带有方向控制的加减法计数器设计。为了研究问题简便,这里不再采用清零端和初值加载功能,只有 clk时钟端、updown方 向控制端和计数输出端dout。模块图如下:updownCounterclkupdowndout7.0功能定义如下:当 updown为高电平时,dout对clk的上升沿进行加 1计数,否则进行减1计数。代码如下:module updownCounter(clk,updown,dout);input clk;input updown;output reg 7:0

22、dout;always(posedge clk)beginif(updown = 1)dout = dout + 1;elsedout = dout - 1;endendmodule功能比较简单,这里不在注释。功能的正确性可以从仿真图上进行验证出来b- 0 ”ii Rn电:欧委也涉要运宓迟巨叁定更醴啥目露'鹿空穿迎n'颐遛售更就回E汇g返亲空泛颁武_.J1D | mlf 巾 J. 11 ' I !;!: : : : :!:!;:;:;8 I I I I I I I I I I | | | | I I I I I I I I I I I I II I I I I I I

23、I I I I I I I I I I I I I I I I I I I I i I I I I I I I I I I I I Illi I I I I I I III从图中可以看出,当 updown为高电平时,计数器的结果从023进行了加1计数,当updown变为低电平时,从 23往下减计数,等等。VerilogHDL中的另一条件语句是 case ,它的语法格式如下:case (敏感信号表达式)值1: 语句1; /case分支值2: 语句2;值n: 语句n;default:语句 n+1; endcase其中case和endcase 为case语句的关键字。如果敏感信号表达式(通常是变量)

24、和值 n (分支值)相等,那么该分支值后面的语句就会执行,执行结束立刻退出case语句。它的语法非常类似于 c语言中的switch-case 语句,但是注意每个分支值后面没有 break ! 下面用示例进行说明 case语句的用法。七(八)段数码管是电路系统中常见的外设,通常用于模拟显示数字和个别字符。它的外形如下:标有abcdh的就是8个发光二极管,这 8个二极管又有两种形式的电路连接方法,分别 称共阴极接法和共阳极接法。共阴极的数码管内部电路如下图:a e A e f £ hgm将所有的二极管的阴极接到一起,通常连接到电路的GND上。共阳极的接法恰好相反,把所有二极管的阳极连接在

25、一起,如下图h。西 p ;ll! 一*f 3百# e > a a#/z btsl/X afFLvcc以,共阴极为例,通常电路设计的连接如下图(图中串联了限流电阻,通常270R左右)GND若要显示如下字符0、1、2、3、4、5、6、7、8、9见下图邛口数码首字那 由LED数码管字建 0只需要将a、b、c、d、e、f、g、h等端口输出相应的高低电平即可。代码示例:设计一个八段数码管显示译码电路,将 4为输入的二进制数在数码管上显示出来。模块图如下:din为二进制的输入,a、b、c、d、e、f、g、h为8个输出端口,分别通过限流电阻连 接到八段数码管相应的段上。代码如下:module bcd2

26、seg(din,a,b,c,d,e,f,g,h);output reg a,b,c,d,e,f,g,h;input3:0 din;always (din)/begincase(din)/(2)4'd0:a,b,c,d,e,f,g,h=8'b11111100; / (3)4'd1:a,b,c,d,e,f,g,h=8'b01100000;4'd2:a,b,c,d,e,f,g,h=8'b11011010;4'd3:a,b,c,d,e,f,g,h=8'b11110010;4'd4:a,b,c,d,e,f,g,h=8'b01

27、100110;4'd5:a,b,c,d,e,f,g,h=8'b10110110;4'd6:a,b,c,d,e,f,g,h=8'b10111110;4'd7:a,b,c,d,e,f,g,h=8'b11100000;4'd8:a,b,c,d,e,f,g,h=8'b11111110;4'd9:a,b,c,d,e,f,g,h=8'b11110110;default: a,b,c,d,e,f,g,h=8'b0000_0000; /(4)endcase/(5)endendmodule代码注释:always(din) 表

28、示当din发生值得变化的时候,always 块(从begin 到end之间的代码)动作一次。always(din) 也可以写成always(*),凡是括号中不是边沿信号的都可以写成*号,意义不变。(2)和(5) , case语句的格式,必须成对使用。(3)分支值中的4'd0也可以写成0 (缺省为10进制)或者4'b0000 ,在硬件上的含义的相同的。只是表现形式不同而已(十进制的和二进制的)。后面的分支同样适用。(4)default 是case 语句的缺省选项(和 c语言中的swich-case 一样),当输入的二 进制值不在09范围内的时候,数码管不显示。这是一个很实用的例程

29、,在很多数码管显示的系统中,可以直接使用。有兴趣的同学可以下载到带有数码管的 FPGA/CPLD硬件系统上尝试一下。还可以对此程序进行扩展,让它能够 显示十六进制的 AbCdE和F等,这里不再在赘述。小作业:设计一个加减法电路.2个4位数的加减法.结果用八段数码管显示出来阻塞赋值与非阻塞赋值在以往的设计中,都是用了 “=”这个赋值符号。通常称作阻塞赋值符号。那么它的意义和作用是什么呢?这里通过一个实例设计来进行“ 二”含义的诠释。欲设方f 2个D触发器级联的电路,如下图:My2Dffsq1根据电路的构成,使用非阻塞赋值符号“=”的代码如下:module My2Dffs(clk,d,q0,q1)

30、;input clk,d;output reg q0,q1;always(posedge clk)beginq0=d;q1=q0;endendmodule使用QuartusII综合后,发现生成的电路如下图:q1reg0PRE-D Q>ENACLRq0reg0PRE-D Q->ENACLR也就是说,实际上两个 Dff根本没有级联起来?这是为什么呢?在 Verilog 中,"=" 为非阻塞赋值,从 语义上讲,begin 和end之间使用了阻塞赋值语句,那么这些语句的赋 值是有先后顺序的(注意这里的说法,是语义上的先后顺序,实际硬件电路的动作都是在 clk的上升沿处进

31、行的)。也就是说,后一条语句的执行(q1=q0;)是在前一条语句q0=d; 赋值结束才进行,而第一条语句中已经将q0的值变成了 d,所以下一条语句中将 q0的值付给q1就是将d的值赋给q1 ,所以综合后电路中出现的两个d触发器输入端都是d。要想使生成的电路符合要求,必须在(q1=q0;)这条语句执行的时候,d的值还没有来得及赋给q0才可以。也就是说,让两条赋值语句同时执行就可以。这里就用到非阻塞赋值“<=”符号,非阻塞赋值的含义就是指begin 和end之间的各个语句执行时同时进行的,不必等上一条语句执行结束就立刻执行。在上面的实例中,将阻塞赋值符号变为非阻塞符号,代码如下:module

32、 My2Dffs(clk,d,q0,q1); input clk,d;output reg q0,q1;always(posedge clk)beginq0<=d;q1<=q0;endendmodule重新编译代码,查看 RTL电路图如下:q0reg0q1reg0这时候生成的电路就是最开始要设计的电路了。注意事项:阻塞非阻塞赋值只有在时序电路中才会出现,所以只能在 always语句中使用,换句话说,不可以在 assign 语句使用“ <二"符号,因为assign 电路生成的都是 组合电路。非阻塞赋值符号“ <=”和比较小于等于“ <=”是相同的,在 Ve

33、rilogHDL靠语句来识别,如果出现在条件语句if等后面,则是“小于等于”,如果出现在赋值语句中就是赋值符号,要注意识别。多数情况下,为了得到更为精确的逻辑,往往使用“<=”的场合比较多,“二” 一般会在算法中出现。接着上例,如果说我就想使用“=”符号来实现两个 D触发器的级联电路,可以吗?答 案是肯定的,只需要将begin和end之间的两条语句调换一下顺序就可以了,读者可以自己去验证并体会其中的含义。当然也可写2个always 块,每个always 块中各使用一条赋值语句,因为多个 always 是并行执行的,所以没有语句执行先后之说。边沿检测电路两个相互级联的 D触发器在实际的应用

34、中有着很巧妙的应用。 有如下电路在级联的2个d触发器后面分别接入了非门和与门或者是异或门,那么这些门的输出 端a、b、c会出现什么样的特点呢?首先分析一下a输出,因为两个d触发器是记忆电路,故假设q0和q1端都为低电平, d也是低电平,则a端当前t0时刻输出为低(即 0), t1时刻,d变为高电平,t2时刻, 时钟上升沿到来。q0端变为高电平,但 q1端仍然为低电平,q1的非则为高电平,所以 a 端输出高电平。t3时刻,又一个clk时钟沿来到,这是 q1输出也变为了高电平,故 a端 又变为低电平。t3时刻以后,例如t4 , q0和q1的输出一直为高,a端一直为低电平。clkdq0qiat0 t

35、112 t3t4由此图得出,当d输入端出现一个上升沿的时候,在clk的作用下,系统的a端会出现一个clk周期宽度的正脉中,这个特性可以在很多的应用中发挥关键的作用,这个电路 也叫做上升沿检测电路, 或者叫上升沿微分电路 (卢毅赖杰编著的VHDL与数字电路设计), 同理可以得出,当 d端出现下降沿的时候,b端会输出一个clk周期宽度的正脉中(下降 沿检测电路或下降沿微分电路);不论d端产生的是上升沿还是下降沿,c端都会输出一个clk周期宽度的正脉冲(双边沿检测电路或双边沿微分电路) 该电路的完整描述与如下:module EdgeDetect(clk,d,a,b,c);input clk,d;ou

36、tput a,b,c;reg q0,q1; always(posedge clk) beginq0<=d;q1<=q0;endassign a=q0&(!q1);assign b=(!q0)&q1;assign c=q0Aq1;/endmodule注释:(1) "A"为异或运算符,和 C语言中的异或运算一样 仿真波形如下图:*2J£ D5 oiTO. 9 niico ,o 收 mq p mVKf QIm p ns5M pUMC puTO O b9m.phlWU.,0 riBm pM£l<5. nx502: “可 ne J*=£13w 闩L> f:iil ni rr3而a1<K 0

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论