文章目录
1. VHDL语言的标识符
VHDL中的标识符可以是常数、变量、信号、端口、子程序或参
数的名字。使用标识符要遵守如下规则:
- 标识符由字母(A…Z,a…Z)、数字和下划线字符组成
- 任何标识符必须以英文字母开头
- 末字符不能为下划线
- 不允许出现两个连续下划线
- 标识符中不区分大小写字母
- VHDL定义的保留字或称关键字,不能用作标识符
- VHDL中的注释由两个连续的虚线
--
开始,直到行尾
2. VHDL的文字
2.1 数字型文字
数字型文字的值有多种表达方式,现列举如下:
-
整数文字:整数文字都是十进制的数,如:
5,678,0,156E2(=15600 =156*102)
45_234_287 = 45234287
下划线可以连接数字
-
实数文字:实数文字也都是十进制的数,但必
须带有小数点,如:188.993,88_670.459_909(=88670.459909)
44.99E-2(=0.4499)
数字前可以加0,数字中间不能有空格
2.2 以数制基数表示的文字
基数#数字文字#E[指数]
指数为0可不写
10#170# --(十进制数表示,等于170=170*100>)
2#1111_1110# --(二进制数表示,等于254=254*20)
16#E#E1 --(十六进制数表示,=2#1110_0000#=224)
--(=14*161)
16#F.01#E+2 --(十六进制数表示,等于3841.00=F.01*162)
2.3 字符串型文字
字符是用单引号引起来的ASCI字符,可以是数值,也可以是符号或字母,如:‘A’,‘*’,‘Z’
字符串则是一维的字符数组,须放在双引号中。VHDL中有两种类型的字符串:文字字符串和数位字符串。
- 文字字符串
文字字符串是用双引号引起来的一串文字
如:“ERROR”,“BB$CC”
- 数位字符串
也称数值字符串、位矢量,是预定义的数据类型BIT的一维数组,它们所代表的是二进制、八进制或十六进制的数组,其位矢 量的长度即为等值的二进制数的位数。
进制基数符号:
B : 二进制基数符号(0~1)
O : 八进制基数符号(0~7)
X : 十六进制基数符号(0~F)
例如:
B"1_1101_1110" --二进制数数组,位矢量数组长度是9
X"AD0" --十六进制数数组,位矢量数组长度是12
2.4 下标名及下标段名
- 下标名:用于指示数组型变量或信号的某一元素,
如:a(2),b(n)
- 下标段名:则用于指示数组型变量或信号的某一段元素,其语句格式示例如下:
SIGNAL A,B,C:BIT_VECTOR(0 TO 7);
SIGNAL M:INTEGER RANGE 0 DOWNTO 3;
SIGNAL Y, Z : BIT;
Y <= A(M); --M是不可计算型下标表示
Z <= B(3); --3是可计算型下标表示
C(0 TO 3) <= (4 TO 7); --以段的方式进行赋值
C(4 TO 7) <= (0 TO 3); --以段的方式进行赋值
3. VHDL语言的数据对象
3.1 常量
常数是一个固定的值,主要是为了使设计实体中的常数更容
易阅读和修改。常数一旦被赋值就不能再改变。
一般格式:
CONSTANT 常数名 : 数据类型 := 表达式;
例子:
CONSTANT fbus:BIT_VECTOR := "01011001";
CONSTANT delay : TIME := 25 ns;
CONSTANT arg1 : BIT := '1'; --所赋值应与数据类型保持一致
常量的使用范围取决于它被定义的位置:
(1)程序包中定义的常量具有最大的全局化特性,可以用在调
用此程序包的所有设计实体中;
(2)设计实体中定义的常量,其有效范围为这个实体定义的所
有的结构体;
(3)设计实体中某一结构体中定义的常量只能用于此结构体;
(4)结构体中某一单元定义的常量,如一个进程中,这个常量
只能用在这一进程中
3.2 变量
变量是一个局部变量,它只能在进程语句、函数语句和过程
语句结构中使用,用作局部数据存储。变量常用在实现某种算
法的赋值语句中。
一般格式:
VARIABLE 变量名 : 数据类型 约束条件 :=表达式;
- 变量只能在process(进程)和子程序中定义和使用
例子:
VARIABLE x, y : INTEGER; --定义x,y为整数变量
VARIABLE count : INTEGER RANGE 0 TO 255 := 10; --定义计数变量范围
变量赋值语句的语法格式如下:
目标变量 := 表达式;
(1)赋值语句右方的表达式必须是一个与目标变量有相同
数据类型的数值
(2)变量不能用于硬件连线和存储元件
(3)变量的适用范围仅限于定义了变量的进程或子程序中。
(4)若将变量用于进程之外,必须将该值赋给一个相同的
类型的信号,即进程之间传递数据靠的是信号
例子:
VARIABLE x,y : REAL;
VARIABLE a,b : BIT_VECTOR(0 TO 7);
x := 100.0; --实数赋值,x是实数变量
y := 1.5 + x; --运算表达式赋值,y也是实数变量
a := "1010101" --位矢量赋值,a的数据类型是位矢量
a(3 TO 6) := ('1','1','0','1'); --段赋值
a(0 TO 5) := b(2 TO 7);
a(7) := '0'; --位赋值
3.3 信号
信号是描述硬件系统的基本数据对象,它类似于连接线。它除了没有数据流动方向说明以外,其他性质与实体的端口(Port)概念一致。
信号说明格式为:
SIGNAL 信号名 : 数据类型 约束条件 := 初始值;
-
信号初始值的设置不是必需的,而且初始值仅在VHDL的行
为仿真中有效。 -
信号是一个全局量,它可以用来进行进程之间的通信。
-
信号的使用和定义范围是实体、结构体和程序包
例子:
SIGNAL temp : STD_LOGIC := '0';
SIGNAL flaga,flagb : BIT;
SIGNAL date : STD_LOGIC_VECTOR(15 DOWNTO 0);
在程序中:
(1)信号值的代入采用 <=
代入符,而且信号代入时可以附加延时。
(2)变量赋值时用 :=
,不可附加延时。
(3)信号的初始赋值符号仍是 :=
在仿真过程中,信号到了规定的仿真时间才进行赋值,变量的赋值是立即生效的。
例子:
X <= Y AFTER 10 ns; --Y的值10ns后才被带入X
信号与变量的区别
-
声明的形式与位置不同
信号在结构体中声明;变量在进程中声明。
signal count : std_logic_vector(7 downto 0); variable temp : std_logic_vector(3 downto 0);
-
赋值符不同
count <= "00000000" , count <= "ZZZZZZZZ" count <= temp; temp := "0000";
-
赋值生效时间不同
信号:进程结束时
变量:立即生效
-
进程对信号敏感,对变量不敏感。
-
作用域不同
信号可以是多个进程的全局信号
变量只在定义后的顺序域可见
4. VHDL中的数据类型
-
标量型(SCALAR TYPE):属于单元素的最基本的数据类型,通常用于描述一个单值数据对象,它包括实数类型、整数类型、枚举类型和时间类型
-
复合类型(COMPOSITE TYPE):可以由细小的数据类型复合而成,如可由标量复合而成。复合类型主要有数组型(ARRAY)和记录型(RECORD).
-
存取类型(ACCESS TYPE):为给定的数据类型的数据对象提供存取方式。
-
文件类型(FILES TYPE):用于提供多值存取类型
数据类型名 | 类型符号 | 说明和取值举例 |
---|---|---|
标准逻辑 | STD_LOGIC | 逻辑’0’或逻辑’1’、‘Z’ |
标准逻辑向量 | STD_LOGIC_VECTOR | “0011ZZ”,X"00BB" |
位 | BIT | ‘0’,‘1’ |
位矢量 | BIT_VECTOR | “001100”,X"00BB" |
整数 | INTEGER | 整数32位 -(231-1) ~ (231-1) |
实数 | REAL | 浮点数 -1.0*1038 ~ 1.0*1038 |
布尔量 | BOOLEAN | TRUE,FALSE |
字符 | CHARACTER | 用单引号括起来, ‘a’,‘A’ |
字符串 | STRING | 用双引号括起来,“My God” |
时间 | TIME | 单位用fs,ps,ns,us,ms,sec,min,hr |
错误等级 | SEVERITY LEVEL | 表征系统的状态:NOTE、WARNING、ERROR、FAILURE |
自然数 | NATURAL | 大于或等于0的整数 |
正整数 | POSITIVE | 大于0的整数 |
4.1 VHDL预定义的数据类型
VHDL的预定义数据类型都是在VHDL标准程序包STANDARD中定义的,在实际使用中,已自动包含进VHDL的源文件中,因而不必通过USE语句以显式调用。
预定义的数据类型包括:
- **布尔(BOOLEAN)**数据类型
- 位(BIT) 数据类型
- 位矢量(BIT_VECTOR) 数据类型
- 字符(CHARACTER) 数据类型
- 整数(INTEGER) 数据类型
- 实数(REAL) 数据类型
- 字符串(STRING) 数据类型
- 时间(TIME) 数据类型
- 错误等级(SEVERITY_LEVEL)
4.1.1 布尔(BOOLEAN)数据类型
程序包STANDARD中定义布尔数据类型的源代码如下:
TYPE BOOLEAN IS (FALSE,TRUE);
布尔数据类型实际上是一个二值枚举型数据类型,它的取值有FALSE和TRUE两种。
4.1.2 位(BIT)数据类型
位数据类型也属于枚举型取值只能是1或0。位数据类型的数据对象,如变量、信号等,可以参与逻辑运算,运算结果仍是位的数据类型。VHDL综合器用一个二进制位表示BIT。在程序包STANDARD中定义的源代码是:
TYPE BIT IS (O',1);
4.1.3 位矢量(BIT_VECTOR)数据类型
位矢量只是基于BIT数据类型的数组,在程序包STANDARD中定义的源代码是:
TYPE BIT VECTOR IS ARRAY (NATURAL RANGE<>) OF BIT;
4.1.4 字符(CHARACTER)数据类型
字符类型通常用单引号引起来,如’A’。字符类型区分大小写,如 ‘B’ 不同于 ‘b’ 。字符类型已在STANDARD程序包中作了定义。
4.1.5 字符串
字符串数据类型是字符数据类型的一个非约束型数组,或称为字符串数组。字符串必须用双引号标明。如:
VARIABLE string_var STRING (1 TO 7);
string_var :"a b c d";
4.1.6 整数(INTEGER)
整数类型的数代表正整数、负整数和零。
常用的整数常量书写方式示例如下:
2 --十进制整数
10E4 --十进制整数
16#D2# --十六进制整数
2#11011010# --二进制整数
自然数(NATUAL)和正整数(POSITIVE)数据类型
自然数和正整数是整数的一个子类型。在STANDARD程序包中定义的源代码如下:
SUBTYPE NATURAL IS INTEGER RANGE O TO INTEGER 'HIGH;
SUBTYPE POSITIVE IS INTEGER RANGE 1 TO INTEGER 'HIGH;
4.1.7 实数(REAL)
VHDL的实数类型类似于数学上的实数,或称浮点数。实数的取值范围为 -1.0E38~+1.0E38 。通常情况下,实数类型仅能在VHDL仿真器中使用,VHDL综合器不支持实数,因为实数类型的实现相当复杂,目前在电路规模上难以承受。
实数常量的书写方式举例如下:
65971.33333 --十进制浮点数
8#43.6#E+4 --八进制浮点数
- 6E-4 --十六进制浮点数
4.1.8 时间(TIME)数据类型
VHDL中唯一的预定义物理类型是时间。完整的时间类型包括整数和物理量单位两部分,整数和单位之间至少留一个空格,如55 ms,20 ns.
STANDARD程序包中定义时间如下:
TYPE time IS RANGE -2147483647 TO 2147483647
units
fs ; --飞秒,VHDL中的最小时间单位
ps = 1000 fs ; --皮秒
ns = 1000 ps ; --纳秒
us = 1000 ns ; --微秒
ms = 1000 us ; --毫秒
sec = 1000 ms ; --秒
min = 1000 sec ; --分
hr = 1000 min ; --时
end units ;
4.1.9 错误等级(SECERITY_LEVEL)
在VHDL仿真器中,错误等级用来指示设计系统的工作状态,共有四种可能的状态值:NOTE(注意)、WARNING(警告)、ERROR(出错)、FAILURE(失败)。在仿真过程中,可输出这四种值来提示被仿真系统当前的工作情况。
STANDARD程序包中定义如下:
TYPE SEVERITY LEVEL IS (NOTE,WARNING,ERROR,FAILURE);
4.2 IEEE预定义的数据类型
在IEEE库的程序包STD_LOGIC_1164中,定义了两个非常重要的数据类型,即:
标准逻辑位STD_LOGIC
标准逻辑矢量STD_LOGIC_VECTOR
4.2.1 标准逻辑位STD_LOGIC数据类型
在IEEE库程序包STD_LOGIC_1164中的数据类型STD_LOGIC的定义如下所示:
TYPE STD_LOGIC IS ('U','X','0','1','Z','W','L','H','-');
逻辑值 | 说明 |
---|---|
‘0’ | 逻辑0,这和bit类型相同 |
‘1’ | 逻辑1,这和bit类型相同 |
‘X’ | 强信号不定(赋值时使用) |
‘U’ | 不定(初始值) |
‘Z’ | 高阻 |
‘W’ | 弱信号不定 |
‘L’ | 弱信号0 |
‘H’ | 弱信号1 |
‘_’ | 不可能情况 |
注意:在使用该类型数据时,在程序中必须写出库说明语句和使用包集合的说明语句。
LIBRARY IEEE; --库说明
USE IEEE.STD_LOGIC_1164.ALL; --使用包说明
4.2.2 标准逻辑向量(STD_LOGIC_VECTOR)
STD_LOGIC_VECTOR类型定义如下:
TYPE STD_LOGIC_VECTOR IS ARRAY (NATURAL RANGE<>) OF STD_LOGIC;
4.2.3 其他预定义标准数据类型
VHDL综合工具配带的扩展程序包中,定义了一些有用的类型。如Synopsys公司在IEEE库中加入的程序包STD_LOGIC_ARITH中定义了如下的数据类型:
- 无符号型(UNSIGNED)
- 有符号型(SIGNED)
- 小整型(SMALL_INT)
TYPE UNSIGNED IS ARRAY (NATURAL RANGE<>) OF STD_LOGIC;
TYPE SIGNED IS ARRAY (NATURAL RANGE<>) OF STD LOGIC;
SUBTYPE SMALL_INT IS INTEGER RANGE 0 TO 1;
无符号数据类型(UNSIGNED TYPE)
UNSIGNED数据类型代表一个无符号的数值,在综合器中,这个数值被解释为一个二进制数,这个二进制数的最左位是其最高位。
有符号数据类型(SIGNED TYPE)
SIGNED数据类型表示一个有符号的数值,综合器将其解释为补码,此数的最高位是符号位,例如:SIGNED(“0101”)代表+5,5;SIGNED(“1101”)代表-5。
4.3 用户自定义的数据类型
VHDL允许用户自行定义新的数据类型,他们可以有多种。
可由用户定义的常见的8种数据类型:
-
枚举(Enumerated)
-
实数(REAL),浮点数(FLOATING)
-
存取(ACCESS)
-
记录(RECORD)
-
整数(INTEGER)
-
数组(ARRAY)
-
文件(FILE)
-
时间(TIME)
4.3.1 TYPE语句用法
TYPE 数据类型名 IS 数据类型定义 [OF 基本数据类型];
TYPE 数据类型名 IS 数据类型定义 [OF 基本数据类型] [约束范围];
例子:
TYPE current IS REAL RANGE -1E4 TO 1E4;
TYPE digit IS INTEGER;
TYPE digit1 IS INTEGER RANGE 0 TO 9;
数据类型如果没有被指定,则默认为整数类型。
4.3.2 SUBTYPE语句的用法
子类型SUBTYPE只是由TYPE所定义的原数据类型的一个子集。
子类型SUBTYPE的语句格式如下:
SUBTYPE 子类型名 IS 基本数据类型 RANGE 约束范围;
例如:
SUBTYPE N1 IS INTEGER RANGE 10 TO 100;
4.3.3 枚举类型
VHDL中的枚举数据类型是用文字符号来表示一组实际的二进制数的类型(若直接用数值来定义,则必须使用单引号)。
例子:
TYPE M_STATE IS(STATE1, STATE2, STATE3, STATE4, STATE5);
4.3.4 数组类型
数组类型属复合类型,它是将一组具有相同数据类型的元素集合在一起,作为一个数据对象来处理的数据类型。数组可以是一维数组(每个元素只有一个下标)或多维数组(每个元素有多个下标)。
VHDL仿真器支持多维数组,但VHDL综合器只支持一维数组
数组的元素可以是任何一种数据类型,用以定义数组元素的下标范围子句决定了数组中元素的个数以及元素的排序方向,即下标数是由低到高,或是由高到低
限定性数组定义
TYPE 数组名 IS ARRAY (数组范围) OF 数据类型;
例子:
TYPE STB IS ARRAY (7 DOWNTO 0) OF STD_LOGIC;
TYPE X IS (LOW, HIGH);
TYPE DATA_BUS IS ARRAY (0 TO 7, X) OF BIT;
--首先定义X为两元素的枚举数据类型,然后将DATA_BUS定义为一个数组类型,其中每一元素的数据类型是BIT。
非限制性数组定义
TYPE 数组名 IS ARRAY (数组下标名 RANGE<>) OF 数据类型;
其中,数组名是定义的非限制性数组类型的取名;数组下标名是以整数类型设定的一个数组下标名称;符号“<>”是下标范围待定符号,用到该数组类型时,再填入具体的数值范围;数据类型是数组中每一元素的数据类型。
例子:
TYPE BIT_VECTOR IS ARRAY (NATURAL RANGE<>) OF BIT;
VARIABLE VA : BIT_VECTOR(1 TO 6); --将数组取值范围定在1~6
TYPE LOGIC_VECTOR IS ARRAY(NATURAL RANGE<>, POSITIVE RANGE<>) OF LOGIC;
VARIABLE L16_OBJECT : LOGIC_VECTOR(0 TO 7, 1 TO 2);
4.3.5 记录类型
由已定义的、数据类型不同的对象元素构成的数组称为记录类型的对象。定义记示类型的语句格式如下:
TYPE 记录类型名 IS RECORD
元素名 : 元素数据类型;
元素名 : 元素数据类型;
END RECORD[记录类型名];
例子:
TYPE RECDATA IS RECORD
element1 : TIME;
element2 : TIME;
element3 : STD_LOGIC;
END RECORD RECDATA;
TYPE REGNAME IS (AX, BX, CX, DX);
TYPE OPERATION IS RECORD
OPSTR : STRING(1 TO 10);
OPCODE : BIT_VECTOR(3 DOWNTO 0);
OP1, OP2, RES : REGNAME;
END RECORD OPERATION;
4.4 数据类型转换
由于VHDL是一种强类型语言,这就意味着即使对于非常接近的数据类型的数据对象,在相互操作时,也需要进行数据类型转换。
4.4.1 类型转换函数方式
类型转换函数的作用就是将一种属于某种数据类型的数据对象转换成属于另一种数据类型的数据对象。
DATAIO库中的程序包STD_LOGIC_OPS中的两个数据类型转换函数:
TO_VECTOR --将INTEGER转换成STD_LOGIC_VECTOR
TO_INTEGER --将STD_LOGIC_VECTOR转换成INTEGER
4.4.2 直接类型转换方式
直接类型转换的一般语句格式是:
数据类型标识符(表达式);
一般情况下,直接类型转换仅限于非常关联(数据类型相互间的关联性非常大)的数据类型之间,必须遵循以下规则:
(1)所有的抽象数字类型是非常关联的类型(如整型、浮点型),如果浮点数转换为整数,则转换结果是最接近的一个整型数。
(2)如果两个数组有相同的维数,且两个数组的元素是同一类型,并且在各处的下标范围内索引是同一类型或非常接近的类型那么这两个数组是非常关联类型。
(3)枚举型不能被转换。如果类型标识符所指的是非限定数组,则结果会将被转换的数组的下标范围去掉,即成为非限定数组。
例子:
VARIABLE DATAC, PARAMC : INTEGER;
DATAC := INTEGER(74.94 * REAL(PARAMC));
- 在类型与其子类型之间无需类型转换即使两个数组的下标索引方向不同,这两个数组仍有可能是非常关联类型的。
4.4.3 整数和实数说明
整数和实数的数据类型在标准的程序包中已作了定义,但在实际应用中,特别在综合中,由于这两种非枚举型的数据类型的取值定义范围太大,综合器无法进行综合。
实际应用中,VHDL仿真器通常将整数或实数类型作为有符号数处理,VHDL综合器对整数或实数的编码方法是:
对用户已定义的数据类型和子类型中的负数,编码为二进制补码;
对用户已定义的数据类型和子类型中的正数,编
码为二进制原码。
5. VHDL语言的运算符
-
逻辑运算(Logic)
-
关系运算(Relational)
-
算术运算(Arithmetic)
-
移位运算(Shift)
5.1 逻辑运算符
逻辑运算符可以对 bit 和 boolean 类型的值进行运算,也可对这些类型的一维数组进行运算。对数组型的运算,运算施加于数组中的每个元素,结果与原来数组长度相同。
逻辑判断的运算为“短路运算”,也就是说,条件表达式的左边成立时,就不再进行右边的判断。比如,IF (a=0) AND (b/a>2) THEN…这个判断运算,当 a=0 时,后面的判断不再继续,避免出现除数为 0 的运算。
操作符 | 功能 | 操作数据类型 |
---|---|---|
AND | 与 | BIT, BOOLEAN, STD_LOGIC |
OR | 或 | BIT, BOOLEAN, STD_LOGIC |
NOT | 非 | BIT, BOOLEAN, STD_LOGIC |
NAND | 与非 | BIT, BOOLEAN, STD_LOGIC |
NOR | 或非 | BIT, BOOLEAN, STD_LOGIC |
XOR | 异或 | BIT, BOOLEAN, STD_LOGIC |
XNOR | 同或 | BIT, BOOLEAN, STD_LOGIC |
5.2 关系运算符
关系运算符两边必须为相同的类型,其结果为 boolean 类型。
等号(=)和不等号(/=)两边可以为任意类型的运算对象。其他关系运算符的运算对象必须为标量类型或离散类型的一维数组。对于复杂的运算对象,如数组,两个值相等意味着两个值的所有对应元素相等。VHDL 的关系运算符如下表所示。
操作符 | 功能 | 操作数据类型 |
---|---|---|
= | 相等 | 任何数据类型 |
/= | 不等 | 任何数据类型 |
< | 小于 | 枚举与整数,及对应的一维数组 |
> | 大于 | 枚举与整数,及对应的一维数组 |
<= | 小于或等于 | 枚举与整数,及对应的一维数组 |
>= | 大于或等于 | 枚举与整数,及对应的一维数组 |
5.3 算数运算符
算术运算符包括一些基本的算术运算,使用算术运算符需要注意的是乘方(**)运算的右边必须为整数。
操作符 | 功能 | 操作数据类型 |
---|---|---|
+ | 加 | 整数 |
- | 减 | 整数 |
* | 乘 | 整数和实数(包括浮点数) |
/ | 除 | 整数和实数(包括浮点数) |
** | 乘方 | 整数 |
ABS | 取绝对值 | 整数 |
MOD | 取模 | 整数 |
REM | 取余 | 整数 |
5.4 移位运算符
移位运算符为二元运算符,左边必须为一维数组,且元素类型为 bit 或 boolean 类型。右边运算数为整数,可以为负数,相当于反方向移位。一位移位与循环移位的语义示意如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fkZXdxjR-1649257311912)(P:\WriteDown\VHDL笔记.assets\image-20220405174242589.png)]
操作符 | 功能 | 操作数据类型 |
---|---|---|
SLL | 逻辑左移 | BIT或布尔型一维数组 |
SRL | 逻辑右移 | BIT或布尔型一维数组 |
SLA | 算术左移 | BIT或布尔型一维数组 |
SRA | 算术右移 | BIT或布尔型一维数组 |
ROL | 逻辑循环左移 | BIT或布尔型一维数组 |
ROR | 逻辑循环右移 | BIT或布尔型一维数组 |
5.5 运算符的优先顺序
符号 | 优先级 |
---|---|
** ABS NOT | 最高优先级 |
* / MOD REM | ↑ |
+(正号) -(负号) | ↑ |
+ - & | ↑ |
SLL SLA SRL SRA ROL ROR | ↑ |
= /= < <= > >= | ↑ |
AND OR NAND NOR XOR XNOR | 最低优先级 |
6. VHDL语言的描述语句
-
WAIT 语句
-
断言语句
-
IF 语句
-
CASE 语句
-
LOOP 语句
-
NEXT 语句
-
过程调用语句
-
NULL 语句
6.1 VHDL顺序语句
6.1.1 WAIT语句
WAIT 语句允许把一个顺序执行的进程或子程序挂起,挂起的进程或子程序恢复的条件由 3种不同的方法指定。WAIT 语句可以有不同的格式,分别有不同的作用,例如
-
WAIT ON 表示等待到信号变化,
-
WAIT UNTIL 表示等到一个表达式为真,
-
WAIT FOR 表示等待一个固定的事件,
-
如果仅仅写一个 WAIT 的话就表示无限期的等待。
WAIT 语句能用于多种不同的目的,常用于为综合工具指定时钟输入。另一用途是将进程的执行延时一段时间或者是为了动态地修改进程敏感表。
为了避免无休止的等待可以加一个超时付句,不管进行到哪儿或是条件有没有满足都允许执行超时处理。下面的代码就演示了 WAIT UNTIL 语句的使用方法和超时处理的方法:
WAIT UNTIL (sendB = '1') FOR 1 ns;
ASSERT (sendB = '1')
REPORT "sendB timed out at '1'"
SEVERITY ERROR;
6.1.2 断言语句
断言语句的功能是为设计者报告一个文本字符串。断言语句包含一个布尔表达式,表达式为真,该语句不做任何事;反之,它将输出一用户规定的字符串到标准输出终端。
断言语句规定输出字符串的严重程度为 4 个级别(NOTE、WARNING、ERROR 和 FAILURE),它们的意思分别是注意、警告、错误和失败,严重层次递增。
断言语句的格式如下:
ASSERT_STATEMENT ::=
ASSERT CONDITION
[REPORT EXPRESSION]
[SEVERITY EXPRESSION];
其中,关键字 ASSERT 后跟 CONDITION 布尔值表达式,它的条件决定 REPORT 付句规定的文字表达式输出不输出,如果是假,文字表达式输出,如果是真,该文字表达式不输出。
此外还有两个可选的付句,REPORT 付句允许设计者指定输出文字表达式的值,如果不指定 REPORT 语句,默认值是 ASSERTION VIOLATION,SEVERITY 付句允许设计者指定断言语句的严重级别,如果没指定 SEVERITY 付句,其默认值是 ERROR。
下面是一个断言语句的使用实例,它表示对输入时钟进行检查,如果其建立时间小于20ns,则输出 ERROR 信号:
IF (clk = '1') THEN
-- 断言语句
ASSERT (NOW - last_d_change >= 20 ns)
REPORT "setup violation"
SEVERITY WARNING;
END IF;
6.1.3 IF语句
IF 语句是根据所指定的条件来确定执行哪些语句,其格式如下:
IF condition THEN
sequence_of_statements
ELSIF condition THEN
sequence_of_statements
ELSE
sequence_of_statement
END IF;
IF 语句用关键字 IF 开头和用关键字 END IF 结尾,END IF 分开拼写。有两个可选付句(ELSIF付句和 ELSE 付句),ELSIF 付句可重复并允许有多个 ELSIF 付句,可选 ELSE 付句但只允许有一个 ELSE 付句。付句中的条件是一布尔表达式,如条件为真值,则下一语句被执行;如果条件不为真,那么接着执行跟在 ELSE 付句后的顺序语句。
下面举一个 IF 语句的使用例子,如下:
IF (day = sunday) THEN
weekend := TRUE;
ELSIF (day = saturday) THEN
weekend := TRUE;
ELSE
weekday := TRUE;
END IF;
6.1.4 CASE语句
当单个表达式的值在多个起作用的项中选择时用 CASE 语句。CASE 语句的格式如下:
CASE expression IS
WHEN choice1 =>
sequence_of_statements
WHEN choice2 | choice3 =>
sequence_of_statements
…
WHEN OTHERS =>
sequence_of_statements
END CASE;
下面是一个使用 CASE 语句执行处理器指令的例子:
CASE instruction IS
WHEN load_accum =>
accum <= data;
WHEN store_out =>
data_out <= accum;
WHEN load|store =>
process_IO(addr);
WHEN OTHERS =>
process_error(instruction);
END CASE
6.1.5循环语句
当需要重复操作时用循环语句,或者实现的模块需要很强的迭代能力时用循环语句:
[循环标示 :] [循环条件] LOOP
顺序处理语句
END LOOP[LOOP_label];
其中循环条件可以用 WHILE 语句或者 FOR 语句来描述。WHLIE 语句有一个循环控制的条件 condition,只要条件表达式为真,WHILE 循环语句就一直执行下去,除非要退出循环。例如:
WHILE (day = weekday) LOOP
day := get_next_day(day);
END LOOP
FOR 循环是根据预先的设定进行迭代,所指定的范围并不一定必须为整数值,也可以表示成一个子类型的指示或者一个范围语句,例如:
PROCESS (clk)
TYPE day_of_week IS (sun,mon,tue,wed,thur,fri,sat);
BEGIN
FOR i IN day_of_week LOOP
IF i = sat THEN
son <= mow_lawn;
ELSEIF i = sun THEN
church <= family;
ELSE
dad <= go_to_work;
END IF;
END LOOP;
END PROCESS;
FOR LOOP 语句的指数值 i
由 FOR 语句局部地说明,这和进程、函数和过程中变量 i
不是一会事,它不需要显式地说明,由于 FOR LOOP 语句的虚拟性,循环指数要局部说明之。这样在进程、函数或过程中存在同名变量时,它们会被分别处理并由它们的内含寻址。
此外,关于循环需要特别注意的是,在某些编程语言中循环指数的值可由赋予内部循环值来改变,但是 VHDL 中是不允许对循环指数的任何赋值,这排除了在任何函数返回值中或在过程的输出与双向参量中存在循环指数。
6.1.6 NEXT 语句
如果必须在这次迭代或循环中停下正在执行的语句,而转向下一个迭代时,用 NEXT 语句。执行 NEXT 语句时,模块处理停在当前点并转到循环语句的开始。随着循环的第一个语句执行,循环变量增加一个迭代值,直到迭代的限制值,循环停止。
下面是一个 NEXT 语句使用的例子:
PROCESS(A,B)
CONSTANT max_limit :INTEGER := 255;
TYPE d_type IS ARRAY (0 to max_limit) OF BOOLEAN ;
VARIABLE done : d_type;
BEGIN
FOR i IN 0 TO max_limit LOOP
IF (done(i) = TRUE ) THEN
NEXT;
ELSE
done (i) := TRUE;
END IF;
q(i) <= a(i) AND b(i);
END LOOP;
END PROCESS;
6.1.7 EXIT语句
EXIT 语句提供完全停下循环执行的能力。执行期间发生了明显的错误或者所有的进程已执行完毕就跳出循环,EXIT 语句允许退出或跳出循环语句。执行 EXIT 语句后 EXIT 语句后面的语句暂停执行,去执行循环语句后面的语句。
EXIT 语句的基本书写格式如下:
EXIT [循环标号][WHEN 条件]
循环标号一般在多重循环中用于标明循环层次,如果 EXIT 语句后面添加循环标号,它将会退出循环标号指定的循环。“WHEN 条件”项用于表明 EXIT 语句执行的条件,此条件为真时才推出循环。
EXIT 语句的使用实例如下:
PROCESS (a)
BEGIN
first_loop:FOR i IN 0 TO 100 LOOP
second_loop:FOR j IN 1 TO 10 LOOP
......
EXIT second_loop;
......
EXIT first_loop;
END LOOP;
END LOOP;
END PROCESS;
6.2 VHDL并行语句
VHDL 不仅仅提供了一系列的顺序语句,同样也提供了很多并行语句。在 VHDL 中,并行语句主要包括以下几种:
-
进程(PROCESS)语句;
-
块(BLOCK)语句;
-
并发信号赋值;
-
条件信号赋值;
-
选择信号赋值。
6.2.1 PROCESS语句结构
进程语句是一种并发处理语句,在一个结构体中多个 PROCESS 语句可以同时并行运行(相当于多个 CPU 同时运作)。PROCESS 语句是 VHDL 语言中描述硬件系统并发行为的最基本语句。
PROCESS 语句归纳起来有如下几个特点:
-
它可以与其他进程并发运行,并可存取结构体或实体号中所定义的信号,进程结构中的所有语句都是按顺序执行的
-
为启动进程,在进行结构中必须包含一个显式的敏感信号量表或包含一个 WAIT 语句
-
进程之间的通信是通过信号量传递来实现的
PROCESS 语句的格式如下:
[进程名]:PROCESS(信号 1,信号 2,…)
BEGIN
…
END PROCESS;
一般情况下进程名可以被省略。进程申明关键字 PROCESS 后面括号内的信号是此进程的敏感信号,这些信号的变化会激活过程的执行。例如下面的代码就表示过程 main_proc 在信号clk 和 reset 变化时执行:
ARCHITECTURE arch of counter is
BEGIN
main_proc:
PROCESS(clk, reset)
BEGIN
if (reset = '1') then
…
end if;
END PROCESS;
END
在进程中也可以定义一些变量,这些变量是局部量,只能在进程内部使用,它们的赋值是立即生效的。局部变量定义的格式如下:
VARIABLE 变量名:数据类型 [约束条件] [:=表达式];
下面的代码演示了定义一个局部变量并且使用它的方法:
ARCHITECTURE arch of counter is
BEGIN
main_proc:
PROCESS(a)
VARIABLE item:array0(7 downto 0); --定义一个变量 item
BEGIN
item(7):=a;
c<=item(7);
END PROCESS;
END
6.2.2 BLOCK语句结构
BLOCK 语句的格式如下:
块名:BLOCK(条件)
[参数 GENERIC 说明; [参数映射;] ]
[端口说明; [端口映射;] ]
[块说明语句]
BEGIN
并发语句组;
END BLOCK 块名;
BLOCK 放在结构体的并行语句组中,每一个 BLOCK 相当于一个子电路原理图。和 PROCESS语句不同,BLOCK 内的语句是并发执行的。只要 BLOCK 右边的条件满足,BLOCK 内的语句就被执行。如果省略条件,表示本 BLOCK 被无条件执行。下面是一个 BLOCK 语句的例子:
ARCHITECTURE arch of test is
BEGIN
block_demo: BLOCK(clk='1')
BEGIN
s<=a xor b;
c<=a and b;
END BLOCK block_demo;
END;
上面的程序表示当 clk 信号变为 1 时,并行执行 BLOCK 语句内的程序,即将 a 和 b 两个信号的异或结果赋给 s 信号,同时将 a 和 b 信号的与结果赋给 c 信号。
6.2.3 并发信号赋值
信号赋值就是使用信号赋值操作符“<=”修改一个信号的状态,如果此语句是在一个进程中,那么它是一个顺序语句,反之如果它是在进程外面(和进程并列关系),那么它就是一个并行赋值的语句。
下面是一个信号赋值的例子,其中 c1、c2 是顺序赋值的,c2 在 c1 之后赋值;d1 和 d2是并行赋值的,它们同时被赋值:
ARCHITECTURE arch of demo is
BEGIN
-- 并行赋值
d1 <= din
d2 <= din
-- 进程
PROCESS(din)
BEGIN
-- 顺序赋值
c1 <= din
c2 <= din
END PROCESS;
END arch;
6.2.4 条件赋值语句
条件信号赋值的格式如下:
目的信号 <= 表达式 1 WHEN 条件 1 ELSE
表达式 2 WHEN 条件 2 ELSE
表达式 3 WHEN 条件 3 ELSE
…
表达式 n;
最后一个表达式 n 表示以上 n-1 个条件都不满足时自动选用此表达式,如果有条件满足,则条件对应的表达式会计算赋值给目的信号量。条件信号代入语句也是并发描述语句,它可以根据不同条件将不同的多个表达式之一的值代入信号量。
下面通过一个四选一选择器的实现方法来介绍条件信号代入语句的使用方法:
ENTITY mux4 IS
PORT (
din0, din1, din2, din3,sel0,sel1: in bit;
dout: out bit );
END mux4;
ARCHITECTURE arch of mux4 is
SIGNAL sel : bit_vector(1 downto 0);
BEGIN
sel <= sel1 & sel0;
dout <= din0 WHEN sel = “00” ELSE
din1 WHEN sel = “01” ELSE
din2 WHEN sel = “10” ELSE
din3 WHEN sel = “11” ELSE
‘X’;
END mux4;
6.2.5 选择信号赋值
选择信号赋值类似于 CASE 语句,它的格式如下:
WITH 表达式 SELECT
目的信号量 <= 表达式 1 WHEN 条件 1;
表达式 2 WHEN 条件 2;
表达式 3 WHEN 条件 3;
…
表达式 n WHEN 条件 n;
如果使用选择信号赋值实现上面的四选一选择器,代码如下:
ENTITY mux4 IS
PORT (
din0, din1, din2, din3,sel0,sel1: in bit;
dout: out bit );
END mux4;
ARCHITECTURE arch of mux4 is
SIGNAL sel : bit_vector(1 downto 0);
BEGIN
sel <= sel1 & sel0;
WITH sel SELECT
dout <= din1 when “00”,
dout <= din1 when “01”,
dout <= din2 when “10”,
dout <= din3 when “11”,
‘X” WHEN OTHERS;
END mux4;
7. VHDL语言的预定义属性
在 VHDL 中,属性是指关于设计实体、结构体、类型、信号等项目的制定特征,利用属性可以使得 VHDL 代码更加简明扼要、易于理解。
VHDL 提供了下面 5 类预定义属性:值类属性、函数类属性、信号类属性、数据类型类属性和数据范围类属性。
7.1 值类预定义属性
值类属性返回有关数组类型、块和常用数据类型的特定值,值类属性还用于返回数组的长度或者类型的最低边界,值类属性分成 3 个子类。
7.1.1 值类型属性:返回类型的边界
值类型属性用来返回类型的边界,有 4 种预定义属性:
-
T’LEFT 用于返回类型或者子类型的左边界;
-
T’RIGHT 用于返回类型或者子类型的右边界;
-
T’High 用于返回类型或者子类型的上限值;
-
T’Low 用于返回类型或者子类型的下限值。
用字符“ '
指定属性并后跟属性名, '
前的对象是所附属性的对象,字首大写 T
指所附属性的对象是类(TYPE),''
字符标点符号(tick)是 VHDL 特有的标号。
7.1.2 值类数组属性:返回数组长度
值类数组属性只有一个,即 LENGTH,该属性返回指定数组范围的总长度,它用于带某种标量类型的数组范围和带标量类型范围的多维数组。
7.1.3 值类块属性:返回块的信息
用属性 'STRUCTURE
和 'BEHAVIOR
返回有关在块和结构体中块是如何建模的信息。在块和结构体中如不含元件具体装配语句,则属性 'BEHAVIOR
将返回真值,如果块或者结构体中只含元件具体装配语句或被动进程,则属性 'STRUCTUTE
将返回真值。
7.2 函数类预定义属性
函数类属性为设计者返回类型、数组和信号信息。用函数类属性时,函数调用由输入变元的值返回一个值,返回值为可枚举值的位置号码、在一个△时间内信号是否改变的指示或者一个数组的边界。函数类属性可细分为 3 个常见的类别。
7.2.1 函数类型属性:返回类型值
函数类型属性返回类型内部值的位置号码、返回特定类型输入值的左和右边的值,函数类型属性分为 6 种:
-
'POS(value)返回传入值的位置号码;
-
'VAL(value)返回从该位置号码传入的值;
-
'SUCC(value)返回输入值后类型中的下一个值;
-
'PRED(value)返回输入值前类型中的原先的值;
-
'LEFTOF(value)表示立即返回一个值到输入值的左边;
-
'RIGHTOF(value)表示立即返回一值到输入值的右边。函数类型属性主要用于从可枚举数或物理类型的数转换到整数类型。
7.2.2 函数数组属性:返回数组的边界
函数数组类属性返回数组类型的边界,分4类:
-
数组’LEFT(n)返回指数范围 n 的左边界;
-
数组’RIGHT(n)返回指数范围 n 的右边界;
-
数组’HIGH(n)返回指数范围 n 的上限值;
-
数组’LOW(n)返回指数范围 n 的下限值。值类数组属性只有一个即 LENGTH,该属性返回指定数组范围的总长度,它用于带某种标量类型的数组范围和带标量类型范围的多维数组。
7.2.3 函数信号属性:返回信号历史信息
函数信号属性用来返回有关信号行为功能的信息,例如报告究竟一个信号是否正好有值的变化,报告从上次事件中跳变过了多少时间以及该信号原来的值是什么。
函数信号属性有如下 5 类:
-
S’EVENT,如果当前的△时间期间发生了事件返回真,否则返回假(信号是否有值的变化);
-
S’ACTIVE,如果在当前的△时间期间做了事项处理返回真,否则返回假;
-
S’LAST_EVENT,返回从信号原先事件的跳变至今所经历的时间;
-
S’LAST_VALUE,返回在上一次事件之前 S 的原先值;
-
S’LAST_ACTIVE,返回自信号原先一次的事项处理至今所经历的时间。
7.3 信号类预定义属性
信号类属性用于根据另一个信号创建一些专用的信号,由类专用信号为设计者返回有关所附属性的信号信息(在一指定时间范围内该信号是否已经稳定的信息、在信号上有无事项处理的信息和建立的信号的延迟形式)。
对这类信号是不能在子程序内部使用的,返回的信息和由某种函数属性所提供的功能非常类似,区别是这类专用信号用于正常信号能用的任何场合,包括在敏感表中。有如下的 4 类属性:
-
S’DELAYED[(time)] 建立和参考信号同类型的信号,该信号后跟参考信号和延时可选时间表示式的时间。'DELAYED 属性为信号建立延迟的版本并附在该信号上,它和传输延时信号赋值的功能相同,但简单。
-
S’STABLE[(time)] 在选择时间表达式指定的时间内参考信号无事件发生时,属性建立为真值的布尔信号。
-
S’QUIET[(time)] 参考信号或所选时间表达式指定时间内没事项处理时,属性建立一个为真值的布尔信号。
-
S’TRANSACTION 信号上有事件发生或为每个事项处理而翻转它的值时,该属性建立一个 BIT 类型的信号。
7.4 数据类型类预定义属性
数据类型类的属性只有一个 T’BASE 类型属性,它必须由另一个值或函数类型属性用该属性。这个属性将返回类型或者子类型的基本类型,这个属性只能作另一属性的前缀。
7.5 数据范围类预定义属性
数据范围类属性返回数组类型的范围值,并由所选的输入参数返回指定的指数范围,这种属性标记如下:
-
a’RANGE[(n)]; 属性 RANGE 将返回由参数 n 值指明的第 n 个范围和按指定排序的范围,'REVERSE_RANGE将返回按逆序的范围,属性’RANGE 和’REVERSE_RANGE 也用于控制循环语句的循环次数。
-
a’REVERSE_RANGE[(n)]REVERSE_RANGE 属性的用法和 RANGE 属性相类似,只是它按逆序返回一范围而已。 比如假设’RANGE 属性是返回 0 到 15,那么’REVERSE_RANGE 属性返回 15 下降到 0。
学校这学期开始讲VHDL语言,所以记录了笔记方便自己查找,现在分享给大家,本人只是一个小白,有不对的地方还请大家指正。笔记记录了几个大佬的内容,有从ppt上面摘录下来的,也有从大佬文章中copy出来的,下面放着md格式的文件,大家可以下载并自己作出修改。
链接: https://typora-1257112019.cos.ap-beijing.myqcloud.com/markdown/VHDL笔记.md