1、1 1第4章 VHDL语言要素 第4章 VHDL语言要素 4.1 VHDL文字规则 4.2 数据对象 4.3 VHDL的数据类型 4.4 VHDL操作符 4.5 属性 2 2第4章 VHDL语言要素 4.1 VHDL文字规则文字规则VHDL文字主要包括数值型文字和标识符。数值型文字主要有数字型、字符串型。4.1.1 数值型文字数值型文字1数字型数字型数字型文字有多种表达方式,列举如下:(1) 整数(Integer)。整数是十进制数,与算数整数相似,包括正整数、负整数和零,表示范围是-(231-1)(231-1),即-21474836472147483647。整数的表达方式举例:1,234,56
2、7E2(=56700),12_345_678(=12345678)3 3第4章 VHDL语言要素 其中,数字间的下划线仅仅是为了提高文字的可读性,相当于一个空的间隔符,没有其他意义,也不影响文字本身的数值。(2) 实数(Real)。实数也是十进制的数,但必须带有小数点。它类似于数学上的实数,或称浮点数,表示范围是-1.0E381.0E38。实数的表达方式举例:0.0,123.45,6.0,78.99E-2(=0.7899),12_345.678_999(=12345.678999)4 4第4章 VHDL语言要素 (3) 以数制基数表示的格式。用这种方式表示的数由五部分组成:第一部分,基数,用十
3、进制数表明所用数制;第二部分,数制隔离符号“#”;第三部分,所要表达的数;第四部分,指数隔离符号“#”;第五部分,用十进制数表示的指数,如果这一部分为0可以省去不写。以数制基数表示的文字表达方式举例:10#235#(十进制数表示,等于235)2#1110_1011#(二进制数表示,等于235)8#353#(八进制数表示,等于235)16#EB#(十六进制数表示,等于235)16#E#E1(十六进制数表示,等于16#E0#,等于2#11100000#,等于224)16#F.01#E2(十六进制数表示,等于16#F01#,等于3841.00)5 5第4章 VHDL语言要素 (4) 物理文字量。物理
4、文字量包括时间、电阻、电流等,但此类文字综合器不能接受,多用于仿真。物理文字量的表达方式举例:55 ns,177 A,23 m它一般由整数和单位两部分组成,整数与单位间至少留一个空格。6 6第4章 VHDL语言要素 2. 字符串型字符串型字符是用单引号引起来的ASCII字符,可以是数值,也可以是符号或字母,如A、 8、 a、 -。字符串是字符的一维数组,必须使用双引号引起来。VHDL中有两种字符串:文字字符串和数位字符串。(1) 文字字符串。文字字符串即用双引号引起来的一串文字,举例:“STRING”,“Both A and B equal to 0“(2) 数位字符串。数位字符串即位矢量,用
5、双引号引起来的一维位(BIT,VHDL预定义数据类型)数据,采用基数符加字符串的表达形式,举例: 7 7第4章 VHDL语言要素 B“1_1101_0010”(二进制数组,位矢量长度是9)O“34”(八进制数组,位矢量长度是6,相当于B“011100”)X“1AB”(十六进制数组,位矢量长度是12)其中,B代表二进制基数符号,表示二进制数位0或者1,字符串中的每一位表示一个BIT;O代表八进制基数符号,字符串中的每一位代表一个八进制数,即3位BIT的二进制数;X代表十六进制基数符号,字符串中的每一位代表一个十六进制数,即一个4位的二进制数。8 8第4章 VHDL语言要素 分析下面表达方式的正确
6、性:B“1000_1110”-二进制数组,数组长度8,表达正确B“10001110” -二进制数组,数组长度8,表达正确“1000_1110”-表达错误,如果省去B,则不能加下划线“10001110” -表达正确1AB -表述错误,除二进制外,八进制和十六进制不能省去基数符9 9第4章 VHDL语言要素 4.1.2 标识符标识符VHDL中的标识符可以是常量、变量、信号、端口、子程序或参数的名称。使用标识符要遵守一定的法则,这不仅是对电子系统设计工程师的一个约束,同时也为各种EDA工具提供标准的书写规范,使之在综合仿真过程中不产生歧义,易于仿真。VHDL中的标识符分为基本标识符和扩展标识符两种。
7、基本标识符的规则如下:(1) 标识符由字母(AZ,az)、数字(09)和下划线(_)组成。(2) 任何标识符必须以英文字母开头。10 10第4章 VHDL语言要素 (3) 不允许出现多个连续的下划线,只能是单一下划线,且不能以下划线结束。(4) 标识符不区分英文字母大小写。(5) VHDL定义的保留字或关键词,不能用作标识符。(6) VHDL中的注释文字一律由两个连续的连接线“-”开始,可以出现在任一语句后面,也可以出现在独立行。分析下面标识符的合法性:_decoder -非法标识符,起始不能是非英文字母3dop -非法标识符,起始不能是非英文字母largenumber 非法标识符,“”不能成
8、为标识符的构成11 11第4章 VHDL语言要素 sig_N -合法标识符state0 -合法标识符NOT-ACK -非法标识符,“-”不能成为标识符的构成Data_ _bus -非法标识符,不能含有多个下划线Copper_ _ -非法标识符,不能以下划线结束Return -非法标识符,关键字不能用作标识符tx_clk -合法标识符12 12第4章 VHDL语言要素 VHDL93标准还支持扩展标识符,以反斜杠来界定,免去了87标准中基本标识符的一些限制,如:可以以数字打头,允许包含图形符号,允许使用VHDL保留字,区分字母大小写等。扩展标识符举例:entity、2chip、EDA、eda、aa
9、bb。但目前仍有较多VHDL工具不支持扩展标识符,所以本书仍以87标准为准。由于VHDL语言不区分大小写,在书写时一定要养成良好的书写习惯。一般而言,应用关键词时应大写,自行定义的标识符应小写。13 13第4章 VHDL语言要素 4.2 数数 据据 对对 象象在VHDL中,凡是可以赋予一个值的客体称为数据对象。数据对象是数据类型的载体,可以把它看做一个容器,能够接收不同数据类型的赋值。常用的数据对象有:常量(CONSTANT)、变量(VARIABLE)和信号(SIGNAL)。14 14第4章 VHDL语言要素 4.2.1 常量常量常量是指在设计描述中不会变化的值。常量的使用主要是为了使代码更容
10、易阅读和修改。在VHDL描述中,一般用常量名代替数值。常量是一个恒定不变的值,一旦作了数据类型和赋值定义后,在代码中就不能再改变,因而具有全局意义。常量声明的格式如下:CONSTANT 常量名 :数据类型 := 取值;15 15第4章 VHDL语言要素 【例4-1】CONSTANT width_s : INTEGER := 8; -声明常量width_s,数据类型为整型,值为8CONSTANT delay : TIME := 25ns; -声明常量dealy作为延时时间25 nsCONSTANT fbus: BIT_VECTOR := “010100”; -声明常量fbus为位矢量类型常量的使
11、用注意以下几个要点:(1) 常量的赋值必须符合声明的数据类型。(2) 常量一旦赋值就不能再改变。若要改变常量值,必须要改变设计,改变常量的声明。16 16第4章 VHDL语言要素 (3) 常量声明所允许的范围有实体、结构体、进程、子程序、块和程序包。(4) 常量具有可视性规则,即常量的声明位置决定它的使用范围。如果常量是在程序包中声明的,则调用此程序包的所有设计实体都可以使用,此时具有最大的全局化特征;常量如果声明在设计实体中,则这个实体定义的所有结构体都可以使用;常量如果声明在结构体内,则只能用于该结构体;如果声明在某进程中,则只能在该进程中使用。17 17第4章 VHDL语言要素 4.2.
12、2 变量变量变量用于对数据的暂时存储。变量是一个局部量,只能在进程和子程序中使用。变量声明的格式如下:VARIABLE 变量名 :数据类型 :=初始值;【例4-2】VARIABLE count: INTEGER RANGE 0 TO 99 := 0; -声明变量count,数据类型为整型,初值为0VARIABLE result : STD_LOGIC := 1; -变量result为标准逻辑位数据类型,初值为1VARIABLE x,y,z : STD_LOGIC_VECTOR(7 DOWNTO 0); -声明变量x、y、z为标准逻辑矢量数据类型,没有定义初值18 18第4章 VHDL语言要素
13、虽然变量可以在声明时赋予初始值,但综合器并不支持初始值的设置,使用时将忽略。初始值仅对仿真器有效。当变量在声明语句中没有赋予初值时,可以通过变量赋值语句在使用时对其赋值。变量赋值语句的格式如下:目标变量名 := 表达式;19 19第4章 VHDL语言要素 【例4-3】VARIABLE x,y,z : STD_LOGIC_VECTOR(7 DOWNTO 0); -声明变量x、y、zx := “01001010”;y := “00010001”;z := x(0 TO 3) & y(4 TO 7); 需要注意的是,赋值语句中的表达式必须与目标变量具有相同的数据类型。变量在使用时还需注意以下几个要点
14、:(1) 变量是一个局部量,只用于进程和子程序。变量不能将信息带出对它作定义的设计单元。(2) 变量的赋值是立即发生的,不存在任何延时的行为。2020第4章 VHDL语言要素 (3) VHDL语言规则不支持变量附加延时语句。(4) 变量常用在实现某种运算的赋值语句中。变量赋值和初始化赋值都使用符号“:=”。(5) 变量不能用于硬件连线。在VHDL 93标准中对变量的类型作了增加,引入了全程变量,可以把值传送到进程外部,参见例4-4。从分析可知,定义了一个全程变量v,用于在进程P0和P1间传递信息。需要注意的是,全程变量也不能作为进程的敏感参数,并且可能导致一些不确定性,使用全程变量必须小心。2
15、1 21第4章 VHDL语言要素 【例4-4】 2222第4章 VHDL语言要素 4.2.3 信号信号信号是电路内部硬件实体相互连接的抽象表示,可以实现进程之间的通信。信号声明的格式如下:SIGNAL 信号名 : 数据类型 :=初始值;【例4-5】SIGNAL sys_clk:BIT := 0; -声明位型的信号sys_clk,初始值为低电平SIGNAL temp:STD_LOGIC_VECTOR(7 DOWNTO 0); -信号temp,数据类型为标准逻辑矢量,没有设置初始值SIGNAL s1,s2 :STD_LOGIC; -声明了两个STD_LOGIC类型的信号s1和s22323第4章 V
16、HDL语言要素 与变量相同,对信号初始值的设置也不是必须的,并且仅在仿真中有效。一般在设计中对信号进行赋值,信号赋值语句的格式如下:目标信号名=表达式;【例4-6】SIGNAL a,b,c,d : STD_LOGIC_VECTOR(7 DOWNTO 0);a = “10101010”; -以二进制形式将8个比特一次赋值完毕b = X“AA”; -以十六进制形式赋值,在VHDL 97标准中定义c(7 DOWNTO 4) = “1100”; -比特分割,信号c的高4位被赋值“1100”d(7) = 1; -单比特赋值2424第4章 VHDL语言要素 信号的使用需要注意以下几个要点:(1) 信号的声
17、明范围是程序包、实体和结构体。信号不能在进程和子程序中声明,但可以使用。(2) 与常量相似,信号也具有可视性规则。在程序包中声明的信号,对于所有调用此程序包的设计实体都可见;在实体中声明的信号,在其对应的所有结构体中都可见;在结构体中声明的信号,此结构体内部都可见。(3) 实体中定义的输入、输出端口也是信号,只是附加了数据流动的方向。2525第4章 VHDL语言要素 (4) 符号“:=”用于对信号赋初始值,符号“=”用于信号的代入赋值。代入赋值可以设置延时,如:a= “10101010 ”AFTER 5ns。(5) 信号包括I/O引脚信号和IC内部缓冲信号,有硬件电路与之对应,所以即使没有设置
18、延时,信号之间的传递也有实际的附加延时。(6) 信号能够实现进程间的通信,即把进程外的信息带入进程内部,把进程内部的信息带出进程。所以,信号能够列入进程的敏感列表,而变量不能列入。2626第4章 VHDL语言要素 (7) 信号的赋值可以出现在进程中,也可以直接出现在结构体的并行语句中,但它们的运行含义不同。前者属于顺序信号赋值,允许同一信号有多个驱动源(赋值源),但只有最后的赋值语句进行有效的赋值操作,如例4-7中的y被赋值为c;后者属于并行信号赋值,赋值操作是各自独立并行发生的,不允许对同一信号多次赋值,如例4-8中的y被赋值为a+b,z被赋值为c,不允许对y多次赋值。同样地,也不允许在不同
19、的进程中对同一信号进行赋值操作。2727第4章 VHDL语言要素 【例4-7】 ARCHITECTURE bhv OF adder IS SIGNAL a,b,c,y, z :INTEGER;BEGIN PROCESS(a,b,c) BEGIN y = a+b; y = c;END PROCESS;END bhv;2828第4章 VHDL语言要素 【例4-8】ARCHITECTURE bhv OF adder ISSIGNAL a,b,c,y,z:INTEGER; BEGINy = a+b;z = c;END bhv;2929第4章 VHDL语言要素 (8) 在使用信号赋值语句时,可以一个信号
20、定义几个值,见例4-9。这些值应一一枚举,中间使用逗号分开,AFTER后的延时值必须为升序。但需要特别注意的是,综合工具不支持这种描述方法,该描述更多地使用在仿真测试中。更多的例子可以参见第8章。【例4-9】 时刻 输出信号c值c = 0, 0 01 AFTER 5ns, 5 1a AFTER 10ns, 10 ab AFTER 15ns; 15 b3030第4章 VHDL语言要素 4.2.4 变量与信号的比较变量与信号的比较在VHDL语言中,变量和信号是常用的数据对象,在形式上非常相似,但本质上却有很大的差别。变量赋值语句用来给变量赋值或改变变量值,使用赋值符号“:=”,且只能在VHDL的顺
21、序语句部分(进程和子程序)声明和使用。当给变量赋值时,赋值操作立即执行,该变量一直保留所赋值,直到下次赋值操作发生为止。变量一般用作局部数据的临时存储单元。31 31第4章 VHDL语言要素 信号赋值语句可以改变当前进程中信号的驱动值,使用赋值符号“=”。信号只能在VHDL并行语句部分声明,但既可以用在并行语句部分,也可以用在顺序语句部分。当给信号赋值时,赋值操作并没有立即生效,必须要等待一个延时,在每个进程结束时才完成赋值。信号一般用作电路单元的互联。当然,变量类型和信号类型如果完全一致,数据类型也完全相同,允许二者相互赋值。例4-10和例4-11显示了信号和变量在进程中赋值的区别。由于实体
22、定义部分完全与例4-10相同,所以例4-11只显示了结构体部分。两个例子的区别仅在于例4-10使用的是信号a和b,而例4-11使用的是变量a和b。3232第4章 VHDL语言要素 【例4-10】3333第4章 VHDL语言要素 3434第4章 VHDL语言要素 【例4-11】3535第4章 VHDL语言要素 图4-1和图4-2分别是例4-10和例4-11综合后的RTL电路图,可以看出其结果有了较大的差别,这是由信号和变量不同的赋值特性所引起的。变量的赋值是立即执行没有延时的,所以a:=x和b:=a这两条语句能够立即执行。3636第4章 VHDL语言要素 图4-1 例4-10的RTL电路图 37
23、37第4章 VHDL语言要素 图4-2 例4-11的RTL电路图 3838第4章 VHDL语言要素 信号的赋值是有延时的,当进程启动后,进程有固定的运行时间,在进程内的语句是顺序执行的。所有进程内的信号赋值语句均顺序启动各自的延时定时器(顺序启动的间隔几乎为0),准备在定时结束后执行赋值操作。可以发现,只有执行到END PROCESS语句时,延时才结束,模拟器的时钟才能向前推进。因此,进程中所有信号的赋值操作几乎是在同时完成赋值的。所以,对于例4-9来说(仿真结果见图4-3),当第2个时钟上升沿到来后,启动一次进程,信号a能够在延时后获得新的输入信号x的值1,信号b也能在延时后完成赋值语句b=
24、a-1操作,但此时对赋值语句b而言,a值仍然是原有的a值0,而不是新的a值1,这是因为新的a值是基本与b的赋值同时完成得到的,所以完成赋值操作后b值仍然为-1。同样地,对于输出信号y,也在延时后完成赋值语句y=b-2,得到y值为-3。对于两个例子赋值更新的数据可参见图4-3和图4-4。可以看到,采用信号的例4-10比采用变量的例4-11慢了两个时钟周期,与RTL电路图的结构相符。3939第4章 VHDL语言要素 图4-3 例4-10的波形仿真结果 4040第4章 VHDL语言要素 图4-4 例4-11的波形仿真结果 41 41第4章 VHDL语言要素 分析例4-12代码片段,说明信号s_v的最
25、后赋值结果。从例4-12的注释中可以看出,由于变量是立即赋值的,所以s_v(0)和s_v(1)得到了变量x和y第一次赋值,为“1”,随后变量x和y进行了第二次赋值,并将值传递给了s_v(4)和s_v(5),使得s_v(4)和s_v(5)为“0”。虽然信号s1和s2也分别有两次赋值操作,但按照在同一进程中执行最后一条赋值语句的规则,s1和s2的值都是“0”,所以s_v(2)、s_v(3)、s_v(6)、s_v(7)均为“0”。所以完成赋值后,信号s_v应等于“00000011”。4242第4章 VHDL语言要素 【例4-12】4343第4章 VHDL语言要素 4444第4章 VHDL语言要素 为
26、便于读者分析,下面再列举两个实例进行比较。例4-13和例4-14的目的是完成一个移位寄存器,例4-14的实体部分与例4-13相同,这里略去。比较两个例子,可以发现信号和变量的基本区别:声明、使用的范围不同。这也是例4-14中的语句“q = reg”必须放在进程内的原因。观察两个例子的仿真结果,例4-13仿真结果正确,在第一个时钟上升沿到来时,置入数据“10010010”,然后从第2个时钟上升沿开始,每经过一次时钟的上升沿,数据从低位向高位移位一次,最低位移入“1”。例4-14的仿真结果不正确,究其原因是因为变量立即赋值的特性。从例4-14的L10行可知,先进行reg(0)的赋值,再进行移位操作
27、,这样就使得移位时的reg(0)已经是得到赋值“1”后的新值了。可以看出,信号赋值的书写顺序不影响最后的结果;而变量由于具有立即赋值的特性,赋值的书写顺序就十分重要。当然,可以通过更改两条赋值语句的前后顺序来更正例4-14。4545第4章 VHDL语言要素 例4-13和例4-14都使用了IF语句的嵌套。IF语句首先判断是否有时钟信号clk的上升沿到来(例4-13中的L16),如有,则执行嵌套在内的IF语句(例4-13中的L17L19),判断控制置数信号ctl是否为高电平“1”。这意味着,赋值语句“reg b THEN y = a;ELSE y b成立时,关系运算表达式的结果是布尔量TRUE,执
28、行y = a;反之为FALSE,执行y = b。5454第4章 VHDL语言要素 (2) BIT数据类型。位数据类型也是一个二值的枚举数据类型,取值只能是“1”或者“0”。位数据类型的数据对象,可以参与逻辑运算,结果仍然是位数据类型。VHDL综合器使用一位二进制数表示位数据类型,如:SIGNAL s1 : BIT := 1; SIGNAL s2 : BIT := 0 ;(3) BIT_VECTOR数据类型。位矢量是基于位数据类型的数组,使用位矢量必须注明位宽,即数组中的元素个数和排列情况,如:5555第4章 VHDL语言要素 SIGNAL s1 : BIT_VECTOR(7 DOWNTO 0)
29、; -信号s1被定义为一个8位位宽的位矢量,数组元素排列指示关键词DOWNTO,表示最左位是s1(7),下标名按照降序排列,最右位是s1(0)SIGNAL s2 : BIT_VECTOR(0 TO 7); -信号s2被定义为一个8位位宽的位矢量,数组元素排列指示关键词TO,表示最左位是s2(0),下标名按照升序排列,最右位是s2(7)5656第4章 VHDL语言要素 一般而言,DOWNTO更适合于硬件设计者通常的思维方法,即最左边是权值最高的位(MSB,Most Significant Bit)。下面进一步理解数组排列指示关键词以及数组的赋值和运算。例4-16完成了对信号x、y、z的赋值,其中
30、符号“&”表示串联,即把操作数或数组合并连接起来组成新的数组,如“0”&“1”&“0”结果为“010”,“001”&“100”结果为“001100”,“100”&“001”结果为“100001”,“VH”&“DL”结果为“VHDL”。例4-17显示的是对数组进行逻辑运算,需要注意的是,如果对位矢量进行逻辑操作,其结果仍为位操作,如位与。另外,逻辑操作符要求两个矢量具有相同的长度,并要求被赋值的矢量也是相同的长度。5757第4章 VHDL语言要素 【例4-16】SIGNAL x : BIT_VECTOR(1 DOWNTO 0);SIGNAL y : BIT_VECTOR(0 TO 1);SIGN
31、AL z : BIT_VECTOR(3 DOWNTO 0);SIGNAL t : BIT_VECTOR(7 DOWNTO 0);x = a & b; - x(1) = a ,x(0) = by = a & b; - y(0) = a , y(1) = bz = 1 & x(1) & y(0); - z = “1aa”t(7 DOWNTO 4) = 0001; - 对数组的片的赋值,注意赋值时片的下标方向要与声明时一致5858第4章 VHDL语言要素 【例4-17】SIGNAL a , b , c ,d : BIT_VECTOR(0 TO 3);a = “1010”;b = “1000”;c =
32、 a AND b; - c = “1000”d = a OR b; - d = “1010”(4) CHARACTER数据类型。字符数据类型枚举了ASCII字符集,用单引号引起来。字符类型区分大小写,如:“A”、“a”不同。(5) STRING数据类型。字符串数据类型是字符类型的一个非限定数组。字符串类型必须用双引号引起来,如:“bule”、“abcd”。5959第4章 VHDL语言要素 (6) INTEGER数据类型。整数数据类型包括正整数、负整数和零。VHDL语言中,整数使用32位的有符号的二进制数表示,即整数的取值范围是-231+231(-2 147 483 647+2 147 483
33、647)。在实际应用时,综合器一般将整型作为无符号数处理,仿真器一般将整型作为有符号数处理。使用整数时,需要利用RANGE子句为所声明的数限定范围,然后根据所限定的范围来决定表示此信号或变量的二进制数的位数。如果在声明时没有限定取值范围,则综合器会自动采用32位二进制数来表示,假设实际中的整数只需4位二进制数即可,就会造成较大的资源浪费。整数数据类型的声明如下:SIGNAL s1 : INTEGER RANGE 0 TO 15 ; -声明信号s1,数据类型是整型,取值范围015共16个值,可用4位二进制数来表示6060第4章 VHDL语言要素 (7) NATURAL数据类型。自然数数据类型是整
34、数类型的子类型,用来表示自然数(即非负的整数)。(8) POSITIVE数据类型。正整数数据类型也是整数类型的子类型,包含整数中非零和非负的数值。(9) REAL数据类型。实数的取值范围是-1.0E38+1.0E38。实数必须带有小数点。通常情况下,实数类型仅能在仿真器中使用,综合器不支持实数类型。实数的书写格式可参见4.1.1节。(10) TIME数据类型。VHDL中唯一的预定物理类型是时间。时间类型包括整数和物理量单位两个部分,且整数和单位之间至少留一个空格,如2 ns、10 ms。综合器也不支持时间类型。61 61第4章 VHDL语言要素 2. IEEE预定义数据类型预定义数据类型IEE
35、E库是VHDL设计中最为常用的库,包含IEEE标准的程序包和其他一些支持工业标准的程序包,如std_logic_1164、numeric_std、numeric_bit、std_logic_arith、std_logic_unsigned、std_logic_signed等。在这些程序包内还定义了一些常用的数据类型,但由于这些程序包并非符合VHDL标准,所以在使用相应的数据类型前,需要在设计的最前面以显式的形式表达出来。6262第4章 VHDL语言要素 IEEE库中的std_logic_1164这个程序包是IEEE的标准程序包,定义了两个重要且常用的数据类型:标准逻辑位STD_LOGIC和标准
36、逻辑矢量STD_LOGIC_VECTOR。从前面的内容分析可知,如果要使用这两个数据类型,必须先通过LIBRARY语句打开IEEE库,然后通过USE语句显式调用std_logic_1164这个程序包。程序包std_logic_arith是由美国Synopsys公司加入IEEE库的,虽然并非IEEE标准,但已成为事实上的工业标准。该程序包在std_logic_1164程序包的基础上扩展了三个数据类型:无符号(UNSIGNED)数据类型、有符号(SIGNED)数据类型以及小整型(SMALL_INT)数据类型,并定义了相关的算数运算符和转换函数。6363第4章 VHDL语言要素 在IEEE库中,nu
37、meric_std标准程序包和numeric_bit程序包也定义了UNSIGNED型和SIGNED型数据类型,其中,numeric_std程序包是针对STD_LOGIC数据类型的无符号数和有符号数,而numeric_bit程序包是针对BIT数据类型的。当综合器中没有附带std_logic_arith程序包时,可以使用这两个程序包。6464第4章 VHDL语言要素 (1) STD_LOGIC数据类型。STD_LOGIC数据类型共定义了九种取值,分别是:“U”未初始化;“X”强未知的;“0”强0;“1”强1;“Z”高阻态;“W”弱未知的;“L”弱0;“H”弱1;“-”忽略。这就意味着STD_LOG
38、IC数据类型能够比BIT数据类型描述更多的线路情况,如:“Z”和“-”常用于三态的描述,“L”和“H”可用于描述下拉和上拉。但就综合而言,STD_LOGIC数据类型在数字器件中实现的只有其中的四种取值(“0”、“1”、“-”、“Z”)。当然,这九种值对于仿真都有重要的意义。6565第4章 VHDL语言要素 (2) STD_LOGIC_VECTOR数据类型。STD_LOGIV_VECTOR数据类型是基于STD_LOGIC的一维数组,即数组中每个元素的数据类型都是STD_LOGIC,采用双引号引起来。需要注意的是,位宽相同、数据类型相同才能进行赋值或运算操作。STD_LOGIC_VECTOR数据类
39、型的相关操作与BIT_VECTOR数据类型类似,这里不再赘述。6666第4章 VHDL语言要素 (3) STD_ULOGIC和STD_ULOGIC_VECTOR数据类型。STD_ULOGIC数据类型也是在std_logic_1164程序包中定义的,也定义了九种取值,它与STD_LOGIC数据类型的区别在于:STD_LOGIC数据类型是STD_ULOGIC数据类型的一个子集,是一个决断类型。所谓决断是指:如果一个信号由多个驱动源驱动,则需要调用预先定义的决断函数以解决冲突并确定赋予信号哪个值。由于STD_ULOGIC不是决断类型,如果一个这样的信号由两个以上的驱动源驱动,将导致错误。由于STD_
40、ULOGIC的限制,使用STD_LGOIC数据类型更为方便。具体决断的相关知识请参见7.2.3节。同样地,STD_ULOGIC_VECTOR数据类型是基于STD_ULOGIC数据类型的一维数组。6767第4章 VHDL语言要素 (4) UNSIGNED数据类型。UNSIGNED数据类型代表一个无符号的数。在综合器中,这个数值被解释为一个二进制数,最左位是最高位。如果声明一个变量或信号为UNSIGNED数据类型,则其位矢长度越长,所能代表的数值就越大,如:位矢长度为8位,最大值为255。不能使用UNSIGNED声明负数。例4-18是UNSIGNED数据类型的示例。【例4-18】VARIABLE
41、v1 : UNSIGNED(0 TO 7); -声明变量v1,8位二进制数,最高位为v1(0)SIGNAL s1 : UNSIGNED(7 DOWNTO 0); -声明变量s1,最高位为s1(7)6868第4章 VHDL语言要素 (5) SIGNED数据类型。SIGNED数据类型表示一个有符号的数,最高位是符号位,一般用“0”表示正,“1”表示负,综合器将其解释为补码。例4-19是SIGNED数据类型的示例。【例4-19】ARCHITECTURE bhv OF ex ISSIGNAL s1 : SIGNED(3 TO 0); -声明信号s1为有符号数BEGINPROCESS(c)VARIABL
42、E v1 : SIGNED(0 TO 3); -声明变量v1为有符号数6969第4章 VHDL语言要素 BEGIN v1 := “0101”; -最高位v1(0)是符号位,v1=+5 s1 = “1011”; -最高位s1(3)是符号位,s1=-5 (6) SMALL_INT数据类型。SMALL_INT数据类型是INTEGER数据类型的子类型,按照在std_logic_arith程序包中定义的源代码,它将INTEGER约束到只含有2个值。程序包std_logic_arith中声明SMALL_INT的源代码如下:SUBTYPE SMALL_INT IS INTEGER RANGE 0 TO 1;
43、7070第4章 VHDL语言要素 4.3.2 用户自定义数据类型用户自定义数据类型除了上述预定义数据类型外,用户还可以定义自己所需的数据类型。一般采用类型定义语句TYPE和子类型定义语句SUBTYPE来实现。1TYPE语句语句TYPE语句能够定义一种全新的数据类型,其语法格式如下:TYPE 数据类型名 IS 数据类型定义 OF 基本数据类型;其中,数据类型名由用户自行定义,可有多个,采用逗号分开;数据类型定义部分用来描述所定义的数据类型的表达方式和表达内容;关键词OF后的基本数据类型是指数据类型定义中所定义的元素的基本数据类型,一般是已有的预定义数据类型,如:BIT、STD_LOGIC等。例4
44、-20是使用TYPE定义新数据类型并声明数据对象的示例。71 71第4章 VHDL语言要素 【例4-20】TYPE btype IS ARRAY (7 DOWNTO 0) OF BIT; -定义数据类型btype,具有8个元素的数组型,每一个元素的数据类型都是BITTYPE color IS (blue, green, red, yellow); -定义数据类型color,共有4个元素,属于枚举类型SIGNAL s1 : btype; -声明信号s1为btype型VARIABLE v1 : color; -声明变量v1为color型.s1 = “10001000”; -对s1赋值v1 := g
45、reen; -对v1赋值7272第4章 VHDL语言要素 2SUBTYPE语句语句SUBTYPE语句定义子类型,即已有数据类型的子集,它满足原数据类型(称为基本数据类型)的所有约束条件。子类型定义的语法格式如下:SUBTYPE 子类型名 IS 基本数据类型 范围;子类型的定义只是在基本数据类型的基础上作一些约束,它并没有定义新的数据类型。上述的POSITIVE和NATURAL就是INTEGER数据类型的子类型。只要值在合适的子类型范围内,这些子类型都可以完成相加、乘、比较、赋值等操作。例4-21给出了POSITIVE和NATURAL之间的有效和无效的赋值示例。例4-22是子类型定义示例。737
46、3第4章 VHDL语言要素 【例4-21】VARIABLE v_n : NATURAL; -声明变量v_n为NATURAL类型VARIABLE v_p : POSITIVE; -声明变量v_p为POSITIVE类型. v_n := 0; -对v_n赋值0v_p := v_n; -把v_n赋值给v_p,此处错误,0超过了POSITIVE数据类型的取值范围.v_p :=5; -对v_p赋值5v_n :=v_p+1; -把v_p+1赋值给v_n,赋值有效7474第4章 VHDL语言要素 【例4-22】SUBTYPE my_int IS INTEGER RANGE 0 TO 1023; -定义子类型m
47、y_int,取值范围01023SUBTYPE my_std IS STD_LOGIC_VECTOR(15 DOWNTO 0); -定义子类型my_type,16位数组TYPE btype IS ARRAY (NATURAL RANGE ) OF BIT; -定义btype为非限定BIT数组SUBTYPE my_type IS btype (0 TO 15); -定义my_type为btype数据类型的子类型下面以一个实例进一步说明TYPE语句和SUBTYPE语句定义的数据类型的区别。7575第4章 VHDL语言要素 【例4-23】7676第4章 VHDL语言要素 7777第4章 VHDL语言要
48、素 编译例4-23,软件会报错,具体错误原因如图4-7所示,即输入信号d并不符合btype数据类型。从例4-23的L12行可以看到,定义了一个数据类型btype,是一个有4个元素的数组,每个元素的数据类型都是STD_LOGIC;输入信号d的数据类型为标准逻辑矢量。虽然从表面来看,二者的形式完全一致,但它们不是一种数据类型,所以不能完成赋值操作。再次强调,使用TYPE语句定义的类型是一个全新的数据类型,VHDL不允许不同的数据类型直接进行操作运算,必须进行数据类型的转换。如果将L12行改为“SUBTYPE btype IS STD_LOGIC_VECTOR(3 DOWNTO 0);”,即使用子类
49、型定义语句,该例将能通过编译。子类型与其基本数据类型属于同一种数据类型,所以属于子类型的和属于基本数据类型的数据对象间的相互赋值可以直接进行,而不必进行数据类型的转换。7878第4章 VHDL语言要素 图4-7 例4-23编译出错信息 7979第4章 VHDL语言要素 3常用用户自定义类型常用用户自定义类型VHDL常用的用户自定义数据类型有:枚举类型、整数类型、数组类型、记录类型等。(1) 枚举类型。顾名思义,枚举类型即为通过枚举该类型的所有可能值来定义。枚举类型的示例如例4-24所示。【例4-24】TYPE color IS (blue, green, red, yellow); -定义数据
50、类型color,共有4个元素TYPE my_std_logic IS (0 ,1, Z, -); -定义数据类型my_std_logic,包含4个元素8080第4章 VHDL语言要素 在使用状态机进行VHDL设计时,一般采用枚举类型来枚举所有的状态。具体状态机的设计方法参见第6章。在综合时,会把用文字符号表示的枚举值用一组二进制数来表示,称为枚举编码。编码比特向量的长度由枚举值的个数所决定,一般确定为所需表达的最少比特数。例4-24中的枚举类型color,需要2 bit的编码向量就能完成对所有值的表示。如果一个枚举类型有5个值,则需要3 bit的编码向量。默认的编码方式是顺序编码,如:blue