资源描述
单击此处编辑母版标题样式,第4章 VHDL语言介绍,4.1 VHDL语言概述,4.2 VHDL语言的特点,4.3 VHDL语言的数据类型,4.4 VHDL的数据对象,4.5 运算操作符,4.6 实训:设计2选1数据选择器,4.1 VHDL语言概述,VHDL(Very-high-speed Integrated Circuit Hardware Description Language)诞生于1982年,是美国国防部委托IBM和Texas Instruments联合开发的。该语言的设计目标有两个:一是使设计者可以用一种语言来描述他们希望描述的复杂电路;二是希望这种语言成为一种标准,使VHSIC计划中的每一个成员都能够按照标准格式向别的成员提供设计。,1986年,VHDL被建议作为IEEE标准,经过了多次修改后,到1987年12月,它被接纳为IEEE的标准。自IEEE公布了VHDL的标准版本IEEE 1076(简称87版)之后,各EDA公司相继推出了自己的VHDL设计环境,或宣布自己的设计工具可以和VHDL接口。此后,VHDL在电子设计领域得到了广泛应用,并逐步取代了原有的非标准硬件描述语言。1993年,IEEE对VHDL进行了修订,增加了文件类型与说明语句,增加了文件操作的功能,增加了操作符,并定义了共享变量,端口映射中可以采用常量等,从更高的抽象层次和系统描述能力上扩展了VHDL的内容。新版本的VHDL即IEEE-1076-1993版本(简称93版),读者可参阅相应的手册。,现在,VHDL和Verilog HDL作为IEEE的工业标准硬件描述语言,在电子工程领域已成为事实上的通用硬件描述语言。有专家认为,在新的世纪中,VHDL与Verilog HDL将承担起大部分的数字系统设计任务。本书主要是以87版为基础编写的,在用一些EDA工具软件进行编译时,要事先指定版本号,这一点请注意。,4.2 VHDL语言的特点,如今,大多数EDA工具软件都采用VHDL语言作为主要的硬件描述语言,这主要源于VHDL强大的自身功能与特点。VHDL语言有如下特点:,(1)VHDL是工业标准的文本格式语言。VHDL已成为一种工业标准,设计者、EDA工具供应商以及芯片生产厂家都要遵循这一标准。该语言是一种文本格式的语言,ASIC的设计者在设计电路时,就像编写其他高级语言一样,用文本来表达所要设计的电路,这样能比较直观地表达设计者的设计思想,并且易于修改。,(2)VHDL具有强大的描述能力。VHDL语言既可以描述系统级电路,也可以描述门级电路;既可以采用行为级描述、数据流描述或结构化描述,也可以采用三者混合的描述方式。VHDL还支持惯性延迟和传输延迟,可以方便地建立电子系统的模型,其强大的描述功能主要来自于强大的语法结构和丰富的数据类型。,(3)VHDL能同时支持仿真与综合。VHDL语言是一种能够支持系统仿真的语言。事实上,ASIC成功的关键在于生产前的设计,而保证设计正确性的主要手段就是系统仿真。目前大部分的EDA工具支持VHDL语言级仿真。这样,设计者在ASIC生产前就能够知道设计的正确与否、系统的性能如何等关键问题。VHDL不仅仅是一种仿真语言,它的大部分语句是可综合的,但也有一部分不支持综合,但其中的可综合语句足以描述一个大而完整的系统。目前所有的高层综合工具所支持的综合语句都是IEEE标准的一个子集。,(4)VHDL是一种并发执行的语句。几乎所有高级语言程序的执行都是顺序的,而VHDL语言执行在总体上是并行的,这种特性符合实际逻辑电路的工作过程。(5)VHDL支持结构化设计与top-down设计方法。VHDL语言是一种结构化的语言,它提供的语句可以完成多层结构的描述,因此VHDL语言支持结构化设计。结构化设计就是将一个系统划分为多个模块,而每个模块又可以继续划分为更多的子模块。EDA设计是自顶向下的,由于VHDL语言支持结构化设计,因而就可以采用top-down设计方法,从系统整体要求出发,自上而下地逐步将系统内容细化,最后完成系统设计。,(6)VHDL的描述与工艺无关。设计者在利用VHDL描述电路时并不需要关心电路最终将采用哪种工艺实现,EDA工具可以将VHDL源代码映射到不同的工艺库上,提高了设计的可重用性。VHDL语言还有共享与调用功能。利用VHDL设计的电路是文本格式的程序,易于保存与管理。,4.3.1 预定义(标准)数据类型,VHDL的预定义数据类型都是在VHDL标准的程序包STANDARD中定义的,在实际使用时,会自动包含到VHDL的源程序中,因此不必通过USE语句进行调用。,1位(BIT)与位矢量(BIT_VECTOR)数据类型,在数字系统中,信号通常用一个位来表示,取值只能是“1”或“0”。如果一个量一次可取多个位值,则在VHDL语言中把它定义为位矢量。位矢量其实是基于BIT数据类型的数组。使用位矢量必须注明位长,即数组中元素的个数和排列情况。,2整数(INTEGER)数据类型,整数数据类型与算术中的整数定义相同,其取值范围为-(231-1)+(231-1),可以进行加、减、乘、除等算术运算。整数的取值范围比较大,而VHDL语言是硬件描述语言,为了确定整数的存储空间,VHDL综合器要求用RANGE为所定义的整数限定范围,然后根据所限定的范围来决定表示此信号或变量的二进制数的位数。,【,例4-3,】SIGNALabus:INTEGER RANGE 0 TO15;说明:abus是一个整数,其取值为015。在应用时整数不能按位访问,并且对整数也不能用逻辑操作符。如果需要进行逻辑操作或按位访问操作,则可以运用类型转换函数将整数转换成BIT_VECTOR类型的数后再进行操作。综合器对abus综合时可用4位二进制数来表示,因此,abus将被综合成由4条信号线构成的信号。整数常量的书写方式见例4-4。【,例4-4,】3(十进制整数),10E4(十进制整数),16#D2#(十六进制整数),2#11011010#(二进制整数)。,4字符(CHARACTER)与字符串(STRING)数据类型,字符类型通常用单引号引起来,如A。一般情况下,VHDL语言对于字母的大小写不敏感,但是对于字符量中的大小写字符却认为是不一样的。字符串数据类型是字符数据类型的一个非约束型数组,或称为字符串数组。字符串必须用双引号标明。,【,例4-5,】SINGALSTRING_VAR:STRING(1 TO 7);STRING=a b c d;_空格也作为一个字符,5实数(REAL)数据类型,在进行算法研究或实验时,作为对硬件方案的抽象手段,常常用到实数的四则运算。通常情况下,实数仅能在VHDL仿真中使用,实数的取值范围为-1.0E38+1.0E38。实数常量的书写方式见例4-6。【,例4-6,】65971.333333(十进制浮点数),8#43.6#E+4(八进制浮点数),43.6E-4(十进制浮点数)。,6时间(TIME)数据类型,VHDL中唯一预定义的物理类型是时间。完整的时间类型包括整数和物理量单位两部分,整数和单位之间至少留一个空格,如50 ms、30 ns。时间类型仅在仿真中使用,使模型系统更逼近实际系统的运行情况。STANDARD程序包中也定义了时间,参见例4-7。,【例4-7】TYPE TIME IS RANGE -2 147 483 647 TO 2 147 483 647;UNITSfs:-飞秒,VHDL中最小的时间单位ps=1000 fs;-皮秒ns=1000 ps;-纳秒us=1000 ns;-微秒ms=1000 us;-毫秒sec=1000 ms;-秒min=60 sec;-分hr=60 min;-时END UNTIS;,8错误等级(SEVERITYLEVEL),在VHDL仿真器中,错误等级用来指示设计系统的工作状态,共有4种可能的状态值:NOTE(注意)、WARNING(警告)、ERROR(错误)、FAILURE(失败)。在仿真过程中,可输出这4种值来提示被仿真系统当前的工作情况。,4.3.2 IEEE预定义标准逻辑位与矢量1标准逻辑位STD_LOGIC数据类型,在数字系统设计中,信号值通常用一个位(BIT)来表示,事实上用BIT数据类型去描述信号状态是不够的,数字系统中状态的取值还有高阻、不定值等。为了更好地描述数字系统,在IEEE库的包集合STD_LOGIC和STD_LOGIC_1164中有如下的定义:TYPEstd_logic IS(U,X,1,0,Z,W,L,H,-);表示std_logic数值类型具有9种不同的值:U(未初始化的)、X(强未知的)、0(强0)、1(强1)、Z(高阻态)、W(弱未知的)、L(弱0)、H(弱1)、-(忽略)。把STD_LOGIC称为标准的逻辑位,其对应的矢量称为标准逻辑位矢量。在IEEE库的程序包STD_LOGIC_1164中,定义了两个非常重要的数据类型,即标准逻辑位STD_LOGIC和标准逻辑矢量STD_LOGIC_VECTOR。,在仿真和综合中,STD_LOGIC值是非常重要的,它可以使设计者精确模拟一些未知和高阻态的线路情况。对于综合器,高阻态和忽略态可用于三态的描述。但就综合而言,STD_LOGIC型数据能够在数字器件中实现的只有其中4种值,即“-”、“0”、“1”和“Z”。当然,这并不表明其余的5种值不存在。这9种值对于VHDL的行为仿真都有重要意义。,描述总线信号,使用STD_LOGIC_VECTOR是方便的,但需注意的是总线中的每一个信号都必须定义为同一种STD_LOGIC数据类型。,如果将信号或变量定义为这三种数据类型,就可以使用程序包STD_LOGIC_ARITH中定义的运算符。在使用之前,请注意必须加入下面的语句:LIBRARY IEEE;USE IEEE.STD_LOGIC_ARITH.ALL;UNSIGNED 类型和SIGNED类型是用来设计可综合的数学运算程序的重要类型,UNSIGNED用于无符号数的运算。在实际运用中,多数运算都需要用到它们。,在IEEE程序包中,NUMERIC_STD和NUMERIC_BIT程序包中也定义了UNSIGNED及SIGNED数据类型,NUMERIC_ STD是针对于STD_LOGIC型定义的,而NUMERIC_BIT是针对于BIT型定义的。此外,程序包中还定义了相应的运算符重载函数。有些综合器没有附带STD_LOGIC_ARITH程序包,此时只能使用NUMERIC_STD和NUMERIC_BIT程序包。在STANDARD程序包中没有定义STD_LOGIC_VECTOR的运算符,而整数类型一般只在仿真的时候用来描述算法,因此UNSIGNED和SIGNED的使用率是很高的。,(1)无符号数据类型(UNSIGNED TYPE)。UNSIGNED数据类型代表一个无符号的数值,在综合器中,这个数值被解释为一个二进制数,这个二进制数最左边是其最高位。例如,十进制的8可以表示如下:UNSIGNED(“1000”)如果要定义一个变量或信号的数据类型为UNSIGNED,则其位矢量长度越长,所能代表的数值就越大。不能用UNSIGNED定义负数。以下是两则无符号数据定义的示例:【,例4-10,】VARIABLE VAR:UNSIGNED(0 TO 10);SIGNAL SIG:UNSIGNED(5 DOWNTO 0);其中,变量VAR有11位数值,最高位是VAR(0),而非VAR(10);信号SIG有6位数值,最高位是SIG(5)。,(2)有符号数据类型(SIGNED TYPE)。SIGNED数据类型代表一个无符号的数值,综合器将其解释为补码,此数的最高位是符号位。例如:SIGNED(“1011”)代表+5,SIGNED(“1101”)代表-5。若将例4-10中的VAR定义为SIGNED数据类型,则数值意义就不同了。如:VARIABLEVAR:SIGNED(0TO 10):其中,变量VAR有11位,最左位VAR(0)是符号位。,4.3.3 用户定义的数据类型,VHDL允许用户自定义新的数据类型,如枚举类型(ENUMERATION TYPE)、整数类型(INTEGER TYPE)、数组类型(ARRAY TYPE)、记录类型(RECORD TYPE)、时间类型(TIME TYPE)、实数类型(REAL TYPE)等。用户自定义数据是用类型定义语句TYPE和子类型定义语句SUBTYPE实现的,以下将介绍这两种语句的使用方法。,1TYPE语句,TYPE语句的语法结构如下:TYPE 数据类型名IS数据类型定义 OF基本数据类型;其中,数据类型名由设计者自定;数据类型定义部分用来描述定义数据类型的表达方式和表达内容;关键词OF后的基本数据类型是指数据类型定义的元素的基本数据类型,一般都是取已有的预定义数据类型,如BIT、STD_LOGIC或INTEGER等。例如:TYPEST1ISARRAY(0 TO 15)OFSTD_LOGIC;该句定义的数据ST1是一个具有16个元素的数组型数据,数组中的每一个元素的数据类型都是STD_LOGIC型。,在VHDL中,任一数据对象(SIGNAL、VARIABLE、CONSTANT)都必须归属某一数据类型,只有同数据类型的数据对象才能进行相互作用。利用TYPE语句可以完成各种形式的自定义数据类型以供不同类型的数据对象间的相互作用和计算。,2SUBTYPE语句,子类型SUBTYPE只是由TYPE所定义的原数据类型的一个子集,它满足原始数据类型的所有约束条件,原数据类型称为基本数据类型。子类型SUPTYPE的语句格式如下:SUBTYPE子类型名 IS基本数据类型RANGE约束范围;子类型的定义只在基本数据类型上作一些约束,并没有定义新的数据类型。子类型定义中的基本数据类型必须是已经存在的数据类型。,【,例4-11,】SUBTYPEDIGITSIS INTEGERRANGE0 TO 9;其中,INTEGER是标准程序包中已定义过的数据类型,子类型DIGITS只是把INTEGER约束为只含10个值。由于子类型与其基本数据类型属同一数据类型,因此属于子类型的和属于基本数据类型的数据对象间的赋值和被赋值可以直接进行,不必进行数据类型的转换。利用子类型定义数据对象,可以提高程序的可读性和易处理性,还有利于提高综合的优化效率,这是因为综合器可以根据子类型所设的约束范围,有效地推知参与综合的寄存器最合适的数目。,3枚举类型,枚举类型是TYPE的特殊用法,VHDL中的枚举数据类型用文字符号来表示一组实际的二进制的类型(若直接用数值来定义,则必须使用单引号)。例如状态机的每一状态在实际电路中虽然是以一组触发器的当前二进制数位的组合来表示的,但设计者在状态机的设计中,为了便于阅读和编译,往往将表征每一状态的二进制数组用文字符号来表示。,【,例4-12,】TYPEM_STATEIS(STATE1,STATE2,STATE3,STATE4,STATE5);SIGNALCURRENT_STATE,NEXT_STATE:M_STATE;TYPE WEEK IS(SUN,MON,TUE,WED,THU,FRI,SAT);在这里,信号CURRENT_STATE和NEXT_STATE的数据类型定义为M_STATE,它们的取值范围是可枚举的,即从STATE1STATE5共5种,代表5组惟一的二进制数值。“WEEK”也是一个枚举类型,定义了7种取值,表示周日至周六。,在综合过程中,枚举类型文字元素的编码通常是自动的,编码顺序是默认的,一般将第一个枚举量(最左边的量)编码为0,以后的依次加1。综合器在编码过程中自动将第一枚举元素转变成位矢量,位矢量的长度取所需表达的所有枚举元素的最小值。如例4-12中设用于表达5个状态的矢位长度为3,编码默认值如下:STATE1000;STATE2001;STATE3010;STATE4011;STATE5=100 它们的数值顺序为STATE1STATE2STATE3STATE4STATE5。一般而言,编码方法因综合器不同而不同。为了某些特殊的需要,编码顺序也可以人为设置。,4整数自定义类型和实数自定义类型,整数和实数的数据类型在标准的程序包中已作定义,但在实际应用中,特别在综合中,由于这两种非枚举数据类型的取值定义范围太大,综合器无法进行综合,因而定义为整数或实数的数据对象的具体数据类型必须由用户根据实际需要重新定义,并限定其取值范围,以便能为综合器所接受,从而提高芯片资源的利用率。这种定义其实也是SUBTYPE的特殊用法。,实际应用中,VHDL仿真器通常将整数或实数类型的数据作为有用符号数处理。VHDL综合器对整数或实数的编码方法是:(1)对用户已定义的数据和子类型中的负数,编码为二进制补码;(2)对用户已定义的数据和子类型中的正数,编码为二进制原码。编码的位数即综合后信号线的数目只取决于用户定义的数值的最大值。在综合中,以浮点数表示的实数将首先转换成相应数值大小的整数。因此在使用整数时,VHDL综合器要求使用数值限定关键词RANGE,对整数的使用范围作明确的限制。,5数组类型,数组类型属复合型数据类型,是指将一组具有相同数据类型的元素集合在一起,作为一个数据对象来处理。数组可以是一维(每个元素只有一个下标)数组或多维数组(每个元素有多个下标)。VHDL仿真器支持多维数组,但综合器只支持一维数组。数组的元素可以是任何一种数据类型,用以定义数组元素下标范围的子句决定了数组中元素的个数以及元素的排序方向,如子句“0 TO 7”是由低到高排序的8个元素,“15 DOWNTO 0”是由高到低排序的16个元素。,VHDL允许定义两种不同类型的数组,即限定性数组和非限定性数组。它们的区别是,限定性数组下标的取值范围在数组定义时就被确认了,而非限定性数组下标的取值范围需留待随后根据具体数据对象再确定。,(1)限定性数组的定义语句格式如下:TYPE 数组名IS ARRAY(数组范围)OF数据类型;其中,数组名是新定义的限定性数组类型的名称,可以是任何标识符,其类型与数组元素相同;数组范围明确指出数组元素的数量和排序方式,以整数来表示其下标;数据类型即指数组各元素的数据类型。【,例4-14,】TYPESTBISARRAY(7 DOWNTO 0)OFSTD_LOGIC;这个数组类型的名称是STB,它有8个元素,其下标排序为70,各元素的排序是STB(7)STB(0)。,(2)非限定性数组的定义语句格式如下:TYPE 数组名 IS ARRAY(数组下标名 RANCE)OF 数据类型;其中,数组名是定义的非限定性数组类型的名称;数组下标名是以整数类型设定的一个数组下标名称;符号“”是下标范围待定符号,用到该数组类型时,再填入具体的数值范围;数据类型是数组中每一元素的数据类型。比如STD_LOGIC_ VECTOR的定义语句为“TPYE STD_LOGIC_VECTOR IS ARRAY(NATURAL RANGE)OF STD_LOGIC”,这其实也是非限定性数组的定义语句。,6记录类型由已定义的、数据类型不同的对象元素构成的数组称为记录类型的对象。定义记录类型的语句格式如下:TYPE记录类型名 IS RECORD 元素名:元素数据类型;元素名:元素数据类型;END RECORD 记录类型名;,对记录类型的数据对象进行赋值,可以整体赋值,也可以对其中的单个元素进行赋值。在使用整体赋值方式时,有位置关联方式和名字关联方式两种表达方式。如果使用位置关联方式,则默认为元素赋值的顺序与记录类型声明的顺序相同。如果使用了OTHERS选项,则至少应有一个元素被赋值;如果有两个或更多的元素由OTHERS选项来赋值,则这些元素必须具有相同的类型。此外,如果有两个或两个以上的元素具有相同的元素和相同的子类型,就可以将其以记录类型的方式放在一起定义。,本例中定义的记录OPERATION共有五个元素:一个是加法指令码的字符串OPSTR,一个是4位操作码OPCODE,另三个是枚举型数据OP1、OP2、RES(其中OP1和OP2是操作数,RES是目标码)。例中定义的变量INSTR1的数据类型是记录型OPERATION,它的第一个元素是加法指令字符串“ADD,AX BX”;第二个元素是此指令的4位命令代码“0001”;第三、第四个元素为AX和BX;AX和BX相加后的结果送入第五个元素AX,因此这里的AX是目标码。,语句“INSTR3,OPSTR:=”MUL AX,BX“;”赋给INSTR3中的元素OPSTR。一般来说,对于记录类型的数据对象进行赋值时,就在记录类型对象名后加“.”,再加赋值元素的名称。若记录类型中的每一个元素仅为标量型数据类型,则称为线性记录类型,否则为非线性记录类型。只有线性记录类型的数据对象都是可综合的。,7数据类型转换,VHDL是一种强类型语言,因此不同数据类型的数据对象在相互操作时,需要进行数据类型转换。(1)类型转换函数方式。类型转换函数的作用就是将一种属于某种数据类型的数据对象转换成属于另一种数据类型的数据对象。,此例中利用了DATAIO库中的程序包STD_LOGIC_OPS 中的两个数据类型转换函数:TO_VECTOR(将INTEGER转换成STD_LOGIC_VECTOR)和TO_INTEGER(将STD_LOGIC _ VECTOR转换成INTEGER)。通过这两个转换函数,就可以使用“+”运算符进行直接加1操作了,同时又能保证最后的加法结果是STD_LOGIC_VECTOR数据类型。利用类型转换函数来进行类型转换需定义一个函数,使其参数类型为被转换的类型,返回值为转换后的类型。在实际运用中经常使用类型转换函数,VHDL的标准程序包中提供了一些常用的转换函数,见表4-1。,(2)直接类型转换方式。直接类型转换的一般语句格式是:数据类型标识符(表达式)一般情况下,直接类型转换仅限于非常关联(数据类型相互间的关联性非常大)的数据类型之间,且必须遵守以下规则:所有的抽象数字类型是非常关联的类型(如整型、浮点型),如果浮点数转换为整数,则转换结果是最近的一个整型数。如果两个数组有相同的维数,两个数组的元素是同一类型,并且在各处的下标范围内索引是同一类型或非常接近的类型,那么这两个数组是非常关联类型。,枚举型不能被转换。如果类型标识符所指的是非限定数组,则结果会将被转换的数组的下标范围去掉,即成为非限定数组。如果类型标识符所指的是限定性数组,则转换后的数组的下标范围与类型标识符所指的下标范围相同。转换结束后,数组中元素的值等价于原数组中的元素值。【,例,4-18,】VARIABLE DATAC,PARAMC:INTEGER RANGE 0 TO 255,DATAC:=INTEGER(74.94*REAL(PARAMC);,4.4 VHDL,的数据对象,在,VHDL,语言中,数据对象,(Data Objects),也叫做,VHDL,语言的客体,它类似于一种容器,接收不同数据类型的赋值。,VHDL,语言是一种硬件描述语言,它描述硬件电路的工作情况。硬件电路的工作过程实际上是信号变化及传输的过程,所以,VHDL,语言的基本数据对象就是信号,(SIGNAL),。除了信号外,VHDL语言还有三种数据对象,分别为常量(CONSTANT)、变量(VARIABLE)和文件(FILE)。在电子电路中,这四类数据对象都具有一定的含义。信号对应地代表物理设计中的一条硬件连线;常量代表数字电路中的电源和地等;变量一般用来表示进行数据暂时存储的载体;文件是传输大量数据的一种特殊的数据对象,这是在VHDL 93标准中新通过的,它在TEXTIO描述语句中详细说明。,4.4.1 常量,常量是指在VHDL程序中一经定义后就不再发生变化的值,它可以在很多区域中进行说明。在编写VHDL程序的过程中,设计人员经常把在VHDL程序中多处使用的数值设计为一个常量,以后如果需要修改这个数值,仅修改这个常量就可以了。常量在使用之前必须进行说明,其描述格式如下:CONSTANT常量名,常量名,:数据类型约束条件:=初始值;其中,表示可选项。,【,例4-19,】CONSTANTfbus:BIT_VECTOR:=“010115”;-位矢量数据类型CONSTANTvcc:REAL:=5.0;-实数数据类型CONSTANTdelay:TIME:=15 ns;-时间数据类型,常量定义说明语句所允许的设计单元有实体、结构体、程序包、块、进程和子程序等。常量在程序包中进行定义后,所有调用该程序包的VHDL程序都可以使用该常量,常量具有最大的全局化特征。在程序包中进行定义时,常量的数值在包首中可以先不进行定义,而把该数值在包体中进行定义,也可以在包首中定义完整的常量语句,具体应用请参考程序包的章节。如果在实体中进行定义,则常量在该实体所对应的所有结构体中都有效;如果在结构体中定义,则常量仅在该结构体中有效;如果在进程与子程序中定义常量,则其仅在该进程与子程序中有效。,4.4.2 信号,信号是描述硬件系统的基本数据对象,它类似于硬件的连接线。信号可以作为设计实体中并行语句模块间的信息交流通道。在多个进程、多个子程序之间及进程、子程序与外部设备间进行通信时要进行信号传递。信号通常在结构体、程序包和实体中进行定义。信号具有全局量的性质。信号定义的格式如下:SIGNAL 信号名,信号名,:数据类型约束条件:=初始值;,【,例4-20,】SIGNAL a:INTEGER RANGE 0 TO 15;SIGNAL flaga,flagb:BIT;SIGNAL data:STD_LOGIC_VECTOR(7 DOWNTO 0):=“11000110”;在程序中给信号赋的初始值仅在仿真时有效,不能用于综合,因为电路在上电后并不能保证它的初始状态是什么。信号值的代入使用符号“=”,信号代入时可以产生附加延时。,【,例,4-21,】,a=10;flag=1;data=“10110110”AFTER 10 ns;事实上,除了没有方向说明以外,信号与实体的端口(PORT)概念是一致的。信号可以看成是实体内部的端口,用于描述一部分电路与另一部分电路的信号连接情况。在VHDL程序中,实体中所定义的端口都可以作为信号来处理,但要注意它的方向。信号的使用和定义范围包括实体、结构体和程序包。在进程和子程序中不允许定义信号。信号可以有多个驱动源,或者说赋值信号源。,在进程中,只能将信号列入敏感表,而不能将变量列入敏感表,可见进程只对信号敏感,而对变量不敏感。当信号定义了数据类型和表达方式后,在VHDL设计中就能对信号进行赋值了。信号的赋值语句表达式如下:目标信号名=表达式;赋值语句的详细用法见后续章节。,4.4.3 变量,变量(VARIABLE)是一个局部量,只能在进程、子程序中进行定义和使用,可以进行多次赋值。在仿真过程中,变量不像信号那样到了规定的时间才能赋值,变量的赋值是立即生效的,所以变量赋值时不能附加延时语句。变量定义的格式如下:VARIABLE 变量名,变量名,:数据类型约束条件:=初始值;,【例4-22】VARIABLEx,y:STD_LOGIC_VECTOR(7 DOWNTO 0);VARIABLE count:INTEGER RANGE 0 TO 255:=10;变量作为局部量,其适用范围仅限于定义了变量的进程或子程序中。在仿真过程中变量的初始值仅在仿真时有效,综合时将略去所有的初始值。变量赋值格式如下:目标变量名:=表达式;,变量数值的改变是通过变量赋值来实现的,赋值语句右方的表达式必须是一个与目标具有相同数据类型的数值,这个表达式可以是一个运算表达式,也可以是一个数值。通过赋值操作,变量的值立即改变。变量赋值语句左边的目标变量可以是单值变量,也可以是一个变量的集合,即数组型变量。下面是一个变量赋值的例子,请注意变量赋值时数据类型的一致性。,4.4.4 信号与变量的区别,信号与变量是经常使用的两种数据对象,两者有很大的区别,归纳起来主要有:(1)赋值语句不同,信号赋值的符号为“=”,而变量为“:=”。(2)通常变量的值可以给信号赋值,但信号的值却不能给变量赋值。(3)信号是全局量,是一个实体内各部分之间以及实体之间进行通信的载体;而变量是一个局部量,只允许定义并作用在进程和子程序中,如果要把变量的值从它定义的区间传输出去,必须先把该变量赋值给一个信号,通过信号把值传输出去。,(4)信号可以作为进程的敏感信号,但是变量却不可以作为进程的敏感信号,让进程启动,至少要有一个敏感信号发生变化。(5)操作过程不相同。在变量的赋值语句中,该语句一旦执行,变量立刻被赋予新值,在执行下一条语句时,该变量的值就用新赋的值参与运算;而在信号赋值语句中,该语句虽然已经被执行,但信号值并没有立即改变,因此下一条语句执行时,仍然使用原来的信号值。在结构体的并行语句中,不允许信号被赋值一次以上。在进程中,若对同一个信号赋值超过两次,则编译将会给出警告,指出只有最后一次赋值有效。,图4-1 例4-24仿真的波形,图4-2 例4-24信号改为变量后仿真的波形,4.5 运算操作符,在VHDL中共有4类运算操作符,即逻辑操作符(Logical Operator)、关系操作符(Relational Operator)、算术操作符(Arithmetic Operator)和并置操作符(Concatenation Operator),如表4-2所示。在VHDL语言中,操作数的类型应该和操作符所要求的类型相一致,并且基本操作符间的操作数必须是同类型的。表4-2右栏已大致列出了各种操作符所要求的数据类型。,操作符是有优先级的,其优先级如表4-3所示,在编程时要注意各操作符的优先级,为了保险起见可多用括号。,4.5.1 逻辑操作符,由表4-3知,逻辑操作符可以对位、标准逻辑位和布尔类型的数据进行操作,要求运算符左右的数据类型必须相同。当一个语句中存在两个以上的逻辑表达式时,在一般的高级语言中运算按自左至右的顺序进行,而在VHDL语言中,如果逻辑关系不能确定,必须要加上括号确定各运算的优先顺序。,【,例4-25,】x=(a AND b)OR(NOT c AND d);-NOT优先级最高,所以在NOT c处可以不加括号x=b AND a AND d AND e;-不会引起逻辑关系变化,可以不加括号x=b OR c OR d OR e;-不会引起逻辑关系变化,可以不加括号x=a XOR d XOR e;-不会引起逻辑关系变化,可以不加括号a=(x1 AND x2)OR(y1 AND y2);-不加括号会引起逻辑关系变化,一定要加括号,4.5.2 关系操作符,应该注意小于等于(=)和代入运算符(=)的不同(从上下文区别)。两个对象进行比较时,数据类型一定要相同。=(等于)和/=(不等于)适用于所有数据类型对象之间的比较;大于、小于、大于等于、小于等于适用于整数、实数、位矢量及数组类型的比较;两个位矢量对象比较时,类型一定要一致,但长度可以不相同,在比较时,某些低版本的EDA工具的编译器从最左的位开始,自左至右按位进行比较从而得出最终比较结果。,上例中,a值为10,而b值为7,a应该比b大,但是因为某些低版本的EDA工具的编译器比较是自左至右进行的,最左边的位都是1,所以比较次左边的值时发现b对应的位为1,而a对应的位为0,所以最终得出ab的结论。目前,大多数EDA工具的编译器在比较不同长度的位矢量时,会自动在位数少的数据左边补上零,从而使长度一致,得出正确的结果。,4.5.3 算术操作符,在算术运算符中,赋值语句两边的数据位长应一致,否则编译时将会出错。比如在对STD_LOGIC_VECTOR进行加、减运算时,要求操作数两边的操作数和运算结果的位长相同,否则编译时将会给出语法出错信息。,正常情况下,标准逻辑位是不允许进行算术运算的,但是在设计电路时经常会对标准逻辑位矢量进行加、减运算,为了使设计变得方便快捷,为了方便各种不同数据类型间的运算,VHDL还允许用户对原有的基本操作符重新定义,赋予新的含义和功能,从而建立一种新的操作符,即重载操作符(Overloading Operator)。定义这种重载操作符的函数称为重载函数。事实上,在程序包STD_LOGIC_UNSIGNED中已定义了多种可供不同数据类型间操作的算符重载函数,其中STD_ LOGIC_SIGNED包集合定义了有符号数的操作符,而程序包STD_LOGIC_UNSIGNED包集合定义了无符号数的操作符。,Synopsys的程序包STD_LOGIC_ARITH、STD_LOGIC_ UNSIGNED和STD_LOGIC_SIGNED中已经为许多类型的运算重载了算术操作符和关系操作符,只要引用这些程序包,即可在SIGNED、UNSIGNED、STA_LOGIC和INTEGER之间进行混合运算,在INTEGER、STD_LOGIC和STD_LOGIC _ VECTOR之间也可以进行混合运算。,在算术操作符中,乘与除的数据类型是整数和实数(包括浮点数)。在一定条件下还可对物理类型的数据对象进行运算操作。虽然在一定条件下,乘法和除法运算是可以综合的,但从优化综合、节省芯片资源的角度出发,最好不要轻易使用乘、除操作符,可以用其它变通的方法来实现乘、除运算。操作符MOD和REM的本质与除法操作符是一样的,可综合的取模和取余的操作数必须是以2为底数的幂。MOD和REM的操作数数据类型只能是整数,运算结果也是整数。,符号操作符“+”和“-”的操作数只有一个,操作数的数据类型是整数。操作符“+”对操作数不作任何改变;操作符“-”作用于操作数的返回值是对原操作数取负。在实际使用中,取负操作数需加括号,如Z=X*(-Y)。VHDL规定,乘方操作符“*”和取绝对值操作符“ABS”的操作数数据类型一般为整数类型。乘方(*)运算的左边可以是整数或浮点数,但右边必须为整数,而且只有在左边为浮点时其右边才可以为负数。一般地,VHDL综合器要求乘方操作符作用的操作数的底数必须是2。,六种移位操作符号SLL、SRL、SLA、SRA、ROL和ROR都是VHDL93标准新增的运算符。VHDL93标准规定移位操作符作用的操作数的数据类型应是一组数组,并要求数组中的元素必须是BIT或BOOLEAN数据类型,移位的位数为整数。在EDA工具所附的程序包中重载了移位操作符以支持STD_ LOGIC _VECTOR及INTEGER等类型。移位操作符左边可以是其所支持的各类型数据,右边则必定是INTEGER型数据。如果操作符右边是INTEGER型常数,则移位操作符实现起来比较节省硬件资源。,SLL的功能是将矢量向左移,右边跟进的位补零;SRL的功能恰好与SLL相反。ROL和ROR移位方式稍有不同,它们移出的位将依次填补移空的位,执行的是自循环式移位方式。SLA和SRA是算术移位操作符,其移空位用最初的首位即符号位来填补。移位操作符的语句格式是:标识符号 移位操作符号 移位位数;,【,例4-27,】VARIABLE a:STD_LOGIC_VECTOR(6 DOWNTO 0):=“1001001”;a SLL 1;-a=“0010010”a SRL 1;-a=“0100100”a SLA 1;-a=“0010011”a SRA 1;-a=“1100100”a ROL 1;-a=“0010011”a ROR 1;-a=“1100100”,4.6 实训:设计2选1数据选择器,一、实训内容,运用VHDL语言设计2选1数据选择器。,二、实训目的,(1)学会运用Quartus软件的VHDL语言设计数字电路。,(2)初步掌握运用VHDL语言设计数字电路的方法。,(3)掌握Quartus软件的使用步骤。,(4)掌握信号与变量的使用。,三、实训原理,2选1数据选择器有2个信号输入端和1个选择信号控制端、1个选择信号输出端,其真值表如表4-4所示。当sel=1时,输出为d1;当sel=0时,输出为d0。,四、实训内容,(1)用VHDL语言设计2选1数据选择器。(2)检查编译,直到没有错误。(3)运用Quartus软件进行仿真,
展开阅读全文