第2章FPGA设计基础2.1VerilogHDL基础知识2.1.1概述硬件描述语言HDL(HardwareDescriptionLanguage)是一种用形式化方法来描述数字电路和数字逻辑系统的硬件描述语言,有两种类型:VHDL和VerilogHDL。举个例子,在传统的设计方法中,对2输入的与门,我们可能需要到标准器件库中调出一个74系列的器件,但在硬件描述语言中,“&”就是一个与门的形式描述,“C=A&B”就是一个2输入与门的描述,而“and”就是一个与门器件。VerilogHDL语言具有这样的描述能力:设计的行为特性、设计的数据流特性、设计的结构组成以及包含响应监控和设计验证方面的时延和波形产生机制。所有这些都使用同一种建模语言,可综合的Verilog模块可以构成一个可靠的复杂IP软核和固核模块。VerilogHDL语言不仅定义了语法,而且对每个语法结构都定义了清晰的模拟、仿真语义。因此,用这种语言编写的模型能够使用Verilog仿真器进行验证。VerilogHDL语言从C编程语言中继承了多种操作符和结构。VerilogHDL模型可以是实际电路的不同级别的抽象,主要指:(1)系统级(2)算法级(3)RTL级(4)门级(5)开关级,前三种属于行为级描述。VHDL侧重于系统级描述,从而更多的为系统级设计人员所采用;Verilog侧重于电路级描述,从而更多的为电路级设计人员所采用。Verilog非常容易掌握,只需有C语言编程基础,就可很快上手。2.1.2Verilog与C语言的比较虽然Verilog语言是从C语言过渡而来的,其某些语法与C语言接近,但存在如下几方面的本质区别:1.Verilog是一种硬件语言,最终是为了产生实际的硬件电路或对硬件电路进行仿真;C语言是一种软件语言,是控制硬件来实现某些功能;2.C语言只要是语法正确,都是可以编译执行的;而Verilog语言有可综合的限制,即在所有的verilog语句中,只有一部分可以被综合,而另外的部分则不能被综合,只能用来仿真;3.C语言是一种软件编程语言,其基本思想是语句的循序执行,而Verilog语言的基本思想是模块的并行执行;4.利用Verilog编程时,要时刻记得Verilog是硬件语言,要时刻将Verilog与硬件电路对应起来。Verilog语言是在C语言的基础之上发展起来的,他们有着类似的语意,C语言和Verilog的很多关键字和运算符都可以对应起来。表2-1中列出了常用的C与Verilog相对应的关键字与控制结构。表2-1常用的C与Verilog相对应的关键字与控制结构CVerilogsub-functionmodule,function,taskif-then-elseif-then-elseCaseCase{,}begin,endForForWhileWhileBreakDisableDefineDefineIntIntPrintfmonitor,display,strobe表2-2列出了C与Verilog相对应的运算符。表2-2常用的C与Verilog相对应的运算符CVerilog功能**乘//除++加--减%%取模!!反逻辑&&&&逻辑且||||逻辑或大于小于==大于等于==小于等于====等于!=!=不等于~~位反相&&按位逻辑与||按位逻辑或^^按位逻辑异或~^~^按位逻辑同或右移左移?:?:同等於if-else敘述2.1.3采用自顶向下的设计方法随着技术的发展,一个芯片上往往集成了几十万到几百万个器件,传统的自底向上的设计方法已不太现实。因此,一个设计往往从系统级设计开始,把系统划分成几个大的基本的功能模块,每个功能模块再按一定的规则分成下一个层次的基本单元,如此一直划分下去。自顶向下的设计方法可用图2-1所示的树状结构表示。图2-1TOP-DOWN设计思想系统级的顶层模块模块A模块B模块C模块B1模块B2模块C1通过自顶向下的设计方法,可实现设计的结构化,可使一个复杂的系统设计由多个设计者分工合作,还可以实现层次化的管理。2.1.4模块模块(module)是Verilog的基本描述单位,用于描述某个设计的功能或结构及与其他模块通信的外部端口。模块在概念上可等同于一个器件,尤如调用通用器件(与门、三态门等)或通用宏单元(计数器、ALU、CPU)等。因此,一个模块可在另一个模块中调用。一个设计是由一个个模块(module)构成的,模块是以module开始,endmodule结束,模块包括模块的端口定义部分和逻辑功能描述部分。模块的端口定义部分,即该模块的端口声明定义了该模块的管脚名,是该模块与其他模块通讯的外部接口,相当于器件的pin。模块的内容,包括I/O说明,内部信号、调用模块等的声明语句和功能定义语句。I/O说明定义了管脚信号的流向,信号的位宽(总线或单根信号线)。功能描述用来产生各种逻辑(主要是组合逻辑和时序逻辑),还可用来实例化一个器件。例如:3位加法器的形成语言为moduleaddr(a,b,cin,count,sum);//模块名及输入输出端口列表//input[2:0]a;//定义信号流向及位宽//input[2:0]b;inputcin;outputcount;output[2:0]sum;assign{count,sum}=a+b+cin;//功能描述//endmodule2.1.5VerilogHDL基本语法VerilogHDL的一些基本语法包括标识符、注释、格式、数字值集合、两种数据类型、运算符、表达式和一些基本的语句等。1.标识符(1)定义标识符(identifier)用于定义模块名、端口名、信号名等。VerilogHDL中的标识符可以是任意一组字母、数字、$符号和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线。另外,标识符是区分大小写的。以下是标识符的几个例子:CountCOUNT//与Count不同R56_68FIVE$(2)关键词VerilogHDL定义了一系列关键词,但要注意只有小写的关键词才是保留字。例如,标识符always(这是个关键词)与标识符ALWAYS(非关键词)是不同的。下面是常用的关键字:alwaysandassignbegincasedefaultdisableedgeelseendendcaseendmoduleendfunctionendprimitiveendspecifyendtableendtaskeventforforeverforkfunctionifinitialinoutinputintegerjoinlargemodulenegedgenornotoroutput等等。(3)书写规范建议以下是一些书写规范的要求:使用有意义的有效的名字如Sum、CPU_addr等;用下划线区分词;采用一些前缀或后缀,如时钟采用Clk前缀:Clk_50,Clk_CPU;低电平采用_n后缀:Enable_n;统一一定的缩写,如全局复位信号Rst;同一信号在不同层次保持一致性,如同一时钟信号必须在各模块保持一致;自定义的标识符不能与保留字同名;参数采用大写,如SIZE。2.注释VerilogHDL中有两种注释方式,一种是以“/*”符号开始,“*/”结束,在两个符号之间的语句都是注释语句,因此可扩展到多行。如:/*statement1,statement2,.....statementn*/以上n个语句都是注释语句。另一种是以//开头的语句,它表示以//开始到本行结束都属于注释语句。3.格式VerilogHDL是区分大小写的,即大小写不同的标识符是不同的。另外其书写格式自由,即一条语句可多行书写,一行可写多个语句。空白(新行、制表符、空格)没有特殊意义。如inputA;inputB;与inputA;inputB;是一样的。书写规范建议:一个语句一行。4.数字值集合下面介绍VerilogHDL的值集合、常量(整型、实型、字符型)和变量等。(1)值集合VerilogHDL中规定了四种基本的值类型,这四类基本值组成的VerilogHDL中的常量。0:逻辑0或“假”;1:逻辑1或“真”;X:未知值;Z:高阻。注意,这四种值的解释都内置于语言中。如一个为z的值总是意味着高阻抗,一个为0的值通常是指逻辑0;在门的输入或一个表达式中为“z”的值通常解释成“x”;此外,x值和z值都是不分大小写的,也就是说,值0x1z与值0X1Z相同。(2)常量VerilogHDL中有三种常量:整型、实型、字符串型。下划线符号(_)可以随意用在整数或实数中,它们就数量本身没有意义,可用来提高易读性,唯一的限制是下划线符号不能用作为首字符。下面主要介绍整型和字符串型。1)整型整型数可以按如下两种方式书写:A.简单的十进制格式这种形式的整数定义为带有一个可选的“+”(一元)或“-”(一元)操作符的数字序列。下面是这种简易十进制形式整数的例子。32十进制数32-15十进制数-15B.基数表示法这种形式的整数格式为:[size]'basevaluesize定义以位计的常量的位长;base为o或O(表示八进制),b或B(表示二进制),d或D(表示十进制),h或H(表示十六进制);value是基于base的值的数字序列,值x和z以及十六进制中的a到f不区分大小写。下面是一些具体实例。5'O375位八进制数(二进制11111)4'D24位十进制数(二进制0011)4'B1x_014位二进制数7'Hx7位x(扩展的x),即xxxxxxx4'hZ4位z(扩展的z),即zzzz4'd-4非法:数值不能为负8'h2A在位长和字符之间,以及基数和数值之间允许出现空格3'b001非法:`和基数b之间不允许出现空格(2+3)'b10非法:位长不能够为表达式注意:x(或z)在十六进制值中代表4位x(或z),在八进制中代表3位x(或z),在二进制中代表1位x(或z)。如果定义的长度比为常量指定的长度长,通常在左边填0补位。但是如果数最左边一位为x或z,就相应地用x或z在左边补位。例如:10'b10左边添0占位,000000001010'bx0x1左边添x占位,xxxxxxx0x1如果长度定义得更小,那么最左边的位相应地被截断。例如:3'b1001_0011与3'b011相等5'H0FFF与5'H1F相等2)字符串型字符串是双引号内的字符序列,字符串不能分成多行书写。例如:INTERNALERRORREACHED-HERE用8位ASCII值表示的字符可看作是无符号整数,因此字符串是8位ASCII值的序列。为存储字符串“INTERNALERROR”,变量需要8*14位。reg[1:8*14]Message;...Message=INTERNALERROR5.数据类型VerilogHDL主要包括两种数据类型:线网类型(nettype)和寄存器类型(regtype)。(1)线网类型1)wire和tri定义线网类型主要有wire和tri两种。线网类型用于对结构化器件之间的物理连线的建模,如器件的管脚,内部器件如与门的输出等。线网类型代表的是物理连接线,因此它不存贮逻辑值,必须由器件所驱动,通常由assign进行赋值。如assignA=B^C;当一个wire类型的信号没有被驱动时,缺省值为Z(高阻)。信号没有定义数据类型时,缺省为wire类型。2)两者区别tri主要用于定义三态的线网。(2)寄存器类型1)定义reg是最常用的寄存器类型,寄存器类型通常用于对存储单元的描述,如D型触发器、ROM等。必须注意的是,reg类型的变量,不一定是存储单元,如在always语句中进行描述的变量必须用reg类型的变量。reg范围定义是可选的,如果没有定义范围,缺省值为1位寄存器。例如:reg[3:0]Sat;//Sat为4位寄存器。regCnt;//1位寄存器。2)寄存器类型的存储单元建模举例用寄存器类型来构建两位D触发器如下:reg[1:0]Dout;.....always@(posedgeClk)Dout=Din;