完整的VHDL语言程序包含实体(Entity)、构造体(Architercture)、配置(Configuration)、包集合(Package)和库(Library)五部分。其中,实体是用来描述设计系统的外部接口;构造体用于描述系统内部的结构和行为;包集合存放共享的数据类型、常数和子程序等;配置用于从库中选取所需单元来组成系统设计的不同版本;库存放已经编译的实体、构造体、包集合和配置。
实体是用来描述设计单元接口的语句,该部分规定了设计单元的的输入、输出接口或引脚。
ENTITY 实体名 IS
[类属参数说明];
[端口说明];
END ENTITY 实体名;
类属参数说明必须放在端口说明之前,用于指定参数。例如:
GENERIC(m: TIME:=1ns);
该句指定了构造体内m的值为1ns。
tmp1:=d0 AND sel after m;
表示d0和sel两个输入信号相与后,经1ns延迟才送到tmp1。
端口说明是对基本设计实体(单元)与外部接口的描述,也可以说是对外部引脚信号的名称、数据类型,以及输入、输出方向的描述。书写形式如下:
PORT( 端口名: 方向 数据类型名;
端口名: 方向 数据类型名);
端口名是赋予每个外部引脚的名称。端口方向是用来定义外部引脚的信号方向是输入还是输出,输入用IN表示,输出用OUT表示, 双向端口用INOUT表示,还有一种特殊情况BUFFER表示输出(这种情况构造体内部可以再使用改变量)。
构造体是一个基本设计单元的功能描述体,具体指明该基本设计单元的行为、元件及内部的连接关系,总的说就是定义了设计单元的具体功能。构造体的描述语句分为行为描述(基本设计单元的数学模型描述)、寄存器描述(数据流描述通俗来讲就是用基本元件描述)和结构描述(逻辑元件连接描述)三种。
ARCHITECTURE 构造体名 OF 实体名 IS
[定义语句] 内部信号,常数,数据类型,函数等的定义;
BEGIN
[并行处理语句];
END ARCHITECTURE 构造体名;
构造体的名称是对本构造体的命名,它是该构造体的唯一名称。OF后面紧跟的实体名表明了该构造体所对应的是哪一实体,用IS结束构造体命名。
在设计规模比较大的电路结构时,全电路都用唯一的模块描述很不方面。为此,设计者们希望将整个电路分成若干相对独立的模块来进行电路的描述。VHDL语言有三种形式的子结构描述语句:
块结构名:
BLOCK
BEGIN
...
END BLOCK 块结构名
在对程序进行仿真时,BLOCK语句中所描述的各个语句是可以并行执行的,与书写的顺序无关。构造体内部直接书写的语句也是并发的。VHDL当中将可以并发执行的语句称为并发语句(Concurrent Statement)。
BLOCK [卫式布尔表达式]
[进程名]: PROCESS(信号1,信号2,信号......) IS
BEGIN
...
END PROCESS [进程名];
注意这里的进程名可以有,也可以不写。
[进程名]: PROCESS(信号1,信号2,信号......) IS
这里面中的信号1、信号2、信号3在VHDL当中成为敏感量,只要其中有一个信号发生呢过变化,都将启动执行PROCESS语句。一旦启动,就会从上到下将PROCESS中的语句执行一遍,执行完一遍会重新进入等待执行状态。
非重入的程序。我理解非重入程序就是会改变程序其他全局变量的程序
。过程
函数
PROCEDURE 过程名(参数1; 参数2; ...)IS
[定义语句];(变量等的定义)
BEGIN
[顺序处理语句];
END PROCEDURE 过程名;
注意这里的参数是有完成的定义。参数可以是 输入、输出
。可以表示为:
[变量名]: IN/OUT/INOUT [数据类型]
在过程调用过程中,IN类型是作为常量,OUT/INOUT是作为变量;在过程运行结束之后OUT、INOUT参数都将拷贝到调用者的信号或变量中去。
FUNCTION 函数名(参数1; 参数2; ...)
RETURN 数据类型名 IS
[定义语句];(变量等的定义)
BEGIN
[顺序处理语句];
RETURN [返回变量名]
END FUNCTION 过程名;
在函数当中所有参数必须是输入,所以在参数定义时可以将IN省略。函数中的输入值由调用者拷贝到输入参数中,如果没有特别指定,则在函数语句中按常数处理。
通常函数都是存放在各种包集合或者库里面。以下我们将做详细介绍哦。
库(Library)是经编译后的数据的集合,它存放包集合定义、实体定义、构造体定义和配置定义。在VHDL当中,库的说明总是放在设计单元的最前面,即
LIBRARY 库名;
这样,在设计单元内的语句就可以使用库中的数据。库的好处是使设计者共享已经编译过的设计结果。VHDL当中可以存在多个不同的库,但是库和库之间是独立的,不能相互嵌套。
VHDL当中,库分为五种:IEEE库、STD库、面向ASIC的库、用户自定义库和WORK库。
LIBRARY STD;
USE STD.STD_LOGIC_1164.ALL;
STD库貌似也可以不进行说明
LIBRARY [库名];
第二句要说明设计者要使用的是库中哪一个包集合以及包集合中的项目名(如过程名、函数名等)。第二句的格式如下:
USE LIBARARY_name.packge_name.ITEM.name
包集合只是单纯用来罗列VHDL语言中所要用到的信号定义、常数定义、元件语句、函数定义和过程定义等,它是一个可编译的设计单元,也是库结构当中的一个层次。要使用包集合时,可以用USE语句说明。
PACKAGE 包集合名 IS
[说明语句];
END PACKAGE 包集合名;--包集合标题
PACKAGE BODY 包集合名 IS
[说明语句];
END PACKAGE BODY 包集合名;--包集合体
一个包集合有标题(Header)和包集合体(Package Body)构成。包集合体只是一个可选项。这是因为包集合标题允许使用数据赋值和有实质性的操作语句。一般来说,包集合标题列出所有项目的名称,而包集合体给出具体的细节。
包集合体和包集合标题分开描述好处是:当函数的功能需要作某些调整或数据赋值需要变化时,只需要改变包集合体的相关语句能够减小编译的单元。
配置(Configuration)语句描述层与层之间的连接关系以及实体与结构之间的联系关系。比如:在实体中,可以通过配置语句选择不同的构造体。
配置语句的基本书写格式如下:
CONFIGURATION [配置名] OF 实体名 IS
[语句说明];
END CONFIGURATION [配置名]
CONFIGURATION [配置名] OF 实体名 IS
FOR 选配构造体名
END FOR;
END CONFIGURATION [配置名]
缺省配置用于不包含块(BLOCK)和元件(COMPONENTS)的构造体。
在VHDL语言中,凡是可以赋予一个值的对象称为客体。客体主要包括以下四种:信号(Signal)、变量(Variable)、常数(Constant)、文件(File)。
客体类别 | 含义 | 说明场合 |
---|---|---|
信号 | 信号是全局量 | ARCHITECTURE, PACKAGE, ENTITY |
变量 | 共享变量是全局量,局部变量是局部量 | PROCESS, FUNCTION, PROCEDURE |
常数 | 常数是全局量 | 上下两种场合均存在 |
文件 | 文件是全局量 | ARCHITECTURE, PACKAGE, ENTITY |
常数是一个固定的值,所谓常数就是对某一常数名赋予一个固定的值。赋值通常在程序开始前进行。其一般格式如下:
CONSTANT 常数名: 数据类型:=表达式;
例子:
CONSTANT VCC : REAL=5.0;
CONSTANT DALY : TIME=100ns;
CONSTANT FBUS : BIT_VECTOR=“0101”;
在93版的协议中,变量引入了共享变量(Shared Variable),但是请注意共享变量应该谨慎使用
。
SHARED VARIABLE [变量名]: [子类型名] :=初始值; --初始值可以没有
并且共享变量不能在进程和子程序的说明域不能使用。
局部变量的赋值是立即生效的。并不像信号那样到了规定的仿真时间才进行赋值。
VARIABLE 变量名: 数据类型 约束条件:=表达式;
信号(Signal)是电子电路内部硬件连接的抽象。与端口的概念很像,在构造体、包集合和实体中进行说明。
信号的定义语句如下:
SIGNAL 变量名: 数据类型 约束条件:=表达式; --注意这里赋值的方式
在VHDL中,提供一个预先定义的包集合——文本输入/输出包集合(TEXTIO),在该TEXTIO中包含有对文本文件进行读/写的过程和函数。这些文本文件都是ASCII码文件,其格式可根据编程人员的需要设定。TEXTIO按行对文件进行处理,一行为一个字符串,并以回车符、换行符作为行结束符。
TYPE 类型名 IS FILE OF 类型/子类型名;
例如,
TYPE index IS RANGE 0 TO 15;
FILE_OPEN(文件名, "外部文件名", 文件读写类型)
FILE_CLOSE(文件名)
READ
WRITE
ENDFILE(文件名)
TEXTIO还包含行读和行写两个子过程:
READLINE(目的行变量,源行变量)
WRITELINE(目的行变量,源行变量)
在VHDL中,信号、变量、常数都要指定数据类型,因此VHDL提供了多种多样标准的数据类型。另外,为使用户设计方便,还可以由用户自定义数据类型。尽管听起来,VHDL语言对数据类型要求不严,但实际上VHDL对数据类型的定义相当严格。
数据类型 | 含义 |
---|---|
整数 | 32位,-(231-1)~(231-1) |
实数 | 浮点数,-1.0E+38~+1.0E_38 |
位 | 逻辑"0"或"1" |
位矢量 | 位矢量 |
布尔量 | 逻辑"真"或逻辑"假" |
字符 | ASCII码 |
时间 | 时间单位fs, ps, ns, us, ms, sec, min, hr |
错误等级 | NOTE, WARNING, ERROR, FAILURE |
自然数, 正整数 | 整数的子集(自然数:大于等于0的整数;正整数:大于0的整数) |
字符串 | 字符矢量 |
赋值语句当中的数据类型必须匹配
。尽管整数值在电子系统中,可能是用一系列的二进制位值来表示,但是整数不能看做位矢量,也不能按位来访问,对整数不能用逻辑操作符
。实在要进行位操作时,可以用转换函数将整数转化为位矢量。在电子系统中,整数也可以作为对信号总线状态的一种抽象手段,用来准确地表示总线的某一中状态。
实数有正负,书写时一定要有小数点
例如:-1.0
+2.5
-1.0E+38
有些数可以用整数表示,也可以用实数表示;但是整数和实数的意义是不一样的,主要是因为数据类型不一样。
BIT('1')
B"001_101_010"--9位二进制位串
X"A_F0_FC"--20位十六进制位串
O"3701"--12位八进制位串
X" "--空位串
虽然布尔量也是二值枚举量,但它和位不同,没有数值的含义,不能进行算术运算。
例如,它可以在IF语句中被测试,测试结果产生一个布尔量TRUE或者FALSE。CHARACTER('1');
"iteger range"
而且整数和单位之间应该至少留有1个空格的位置
,例如:20 us, 100ns, 3sec
在系统仿真时,时间数据特别有用,用它表示信号延时,从而使模型系统更逼近实际的运行环境。
VHDL当中,用户可以根据自己的需求来定义数据,定义格式如下:
TYPE 数据类型名 {,数据类型名} IS 数据类型定义;
不完整的用户定义的数据类型的书写格式:
TYPE 数据类型名 {,数据类型名};
以下将介绍几种可由用户定义的数据类型
TYPE Week IS(sun, mon, tue, wed, thu, fri, sat);
由上述定义可知,凡是用于代表星期二的日子都可以用tue代替,这比用代码"010"表示星期二直观多了,使用也不容易出错。
枚举类型数据定义如下:
TYPE 数据类型名 IS (元素, 元素, 元素 , ......);
TYPE digit IS INTEGER RANGE 0 TO 9;
定义格式如下:
TYPE 数据类型名 IS 数据类型定义约束范围;
TYPE current IS INTEGER RANGE -1.0E4 TO 1.0E4;
定义格式如下:
TYPE 数据类型名 IS 数据类型定义约束范围;
TYPE 数据类型名 IS ARRAY 范围 OF 原数据类型名;--范围默认是整数类型
例子,
TYPE STD_LOGIC_VECTOR IS ARRAY (NATRUAL RANGE<>) OF STD_LOGIC;
这里的范围由RANGE<>指定,这是一个没有范围限定的数组。这时候应该由信号的说明语句来限定范围。例如:
SIGNAL aaa: STD_LOGIC_VECTOR(3 DOWNTO 0);
二维数组需要用两个范围来限定,例如
TYPE memarray IS ARRAY (0 TO 5, 7 DOWNTO 0) OF STD_LOGIC;
存取(Access)类型
文件(File)类型
记录(Recode)类型
记录是将不同数据类型的数据和数据名组织在一起形成的新客体。定义格式如下:
TYPE 数据类型名 IS RECORD
元素名: 数据类型名;
元素名: 数据类型名;
...
END RECORD
在提取数据时应当使用“.”,格式如下:
数据名.元素名
TYPE 数据类型名 IS 范围;
UNITS 基本单位;
单位;
END UNITS;
用户定义的子类型是用户对已定义的数据类型进行一些范围限而形成的一种新的数据类型。格式一般如下:
SUBTYPE 子类型名 IS 数据类型名;
注意:
"STD_LOGIC_VECTOR"的值只能是二进制值。BIT_VECTOR的值除2进制值外,可以是八进制,十六进制。
这个例子好像不对,但是思想就是这样
这里地数据类型的限定类似于C语言当中的强转。
具体问题如下:
CASE (a&b&c) IS
WHEN "001"=>Y<="01111111";
WHEN "010"=>Y<="10111111";
...
END CASE;
在该例中,a&b&c的数据类型不定,那么会发生错误。此时需要对数据进行类型限定。类型限定的实现方式是在数据前加上“类型名”。例如:
a<=STD_LOGIC_VECTORN ("01101010");
SUBTYPE STD3BIT STD_LOGIC_VECTOR(0 TO 2);
CASE STD3BIT (a&b&c) IS
WHEN "000"=>Y<="01111111";
WHEN "001"=>Y<="10111111";
...
END CASE;
VHDL基本数据类型当中的bit是一个逻辑型的变量,这类数据只能是“0”或者“1”。这种数据类型有一些缺陷,比如没有高阻态,不能很好地仿真,也很难描述双向数据总线。
为此,1993年制定出新的标准(IEEE STD1164),使得“STD_LOGIC”型数据可以具有如下9种不同的取值:
U--初始值
X--不定
0--0
1--1
Z--高阻态
W--弱信号不定
L--弱信号O
H-- 弱信号1
- --不可能情况
VHDL当中共有四类操作符,分为是逻辑(Logic)运算符、关系(Relational)运算符、算术(Arithmetic)运算符和并置(Concatenation)运算符。请注意操作数的类型应该和操作符的要求一致,并且操作符是有优先级的
优先级顺序 | 操作运算符类型 | 操作符 | 功能 |
---|---|---|---|
优 | 逻辑运算符 | AND | 逻辑与 |
先 | 逻辑运算符 | OR | 逻辑或 |
级 | 逻辑运算符 | NAND | 逻辑与非 |
从 | 逻辑运算符 | NOR | 逻辑或非 |
上 | 逻辑运算符 | SLL | 逻辑左移 |
到 | 逻辑运算符 | SRL | 逻辑右移 |
下 | 逻辑运算符 | SLA | 算术左移 |
递 | 逻辑运算符 | SRA | 算术右移 |
增 | 逻辑运算符 | ROL | 逻辑循环左移 |
逻辑运算符 | ROR | 逻辑循环右移 | |
关系运算符 | = | 等于 | |
关系运算符 | /= | 不等于 | |
关系运算符 | < | 小于 | |
关系运算符 | > | 大于 | |
关系运算符 | <= | 小于等于 | |
关系运算符 | >= | 大于等于 | |
算术运算符 | + | 加 | |
算术运算符 | - | 减 | |
并置运算符 | & | 并置 | |
正、负运算符 | + | 正 | |
正、负运算符 | - | 负 | |
算术运算符 | * | 乘 | |
算术运算符 | / | 除 | |
算术运算符 | MOD | 求模 | |
算术运算符 | REM | 取余 | |
算术运算符 | ** | 指数 | |
算术运算符 | ABS | 取绝对值 | |
逻辑运算符 | NOT | 取反 |
93版中逻辑运算符共有12种,分别是
NOT--取反
使用例子:
a<=not b;
AND--yu与
OR--或
NAND--与非
NOR--或非
XOR--异或
使用例子
a<=b[运算符]c;
SLL--逻辑左移
SRL--逻辑右移
SLA--算术左移
SRA--算术右移
ROL--逻辑循环左移
ROR--逻辑循环右移
移位运算符使用时,应该调用ieee.numeric_std库。一般是使用连接符实现移位,并且这样更接近底层。
使用例子
a<=a [移位运算符] [位数];
逻辑运算符可以对“STD_LOGIC”和“BIT”等逻辑型数据、“STD_LOGIC_VECTOR”逻辑型数组及布尔型数据进行逻辑运算。请注意逻辑运算符的左边和右边,以及代入信号的数据类型必须相同
当一个语句中存在两个以上相同逻辑表达式时,在C语言中有自左向右的优先级顺序,但是在VHDL中,左右没有优先级差别。
简单说一下,逻辑运算符和算术运算符的区别。逻辑移位不考虑符号位,算术移位考虑符号位
VHDL中有10种算术运算符。
+ --加
- --减
* -- 乘
/ --除
MOD --求模
REM --取余
+ --正(一元运算符)
- --负(一元运算符)
** --指数
ABS --取绝对值
VHDL当中有6中关系运算符:
= --等于
/= --不等于
< --小于
<= --小于等于
> --大于
>= --大于等于
为了能使位矢量进行关系运算,在包集合“STD_LOGIC_UNSIGNED”中对“STD_LOGIC_VECTOR”关系运算重新作了定义。在利用关系运算符对位矢量数据进行比较时,比较过程是从最左边的位开始,向右按位开始比较。
并置运算符就是连接符
&
下面直接用例子说明并置运算符的使用。
tmp_b<=b AND (en&en&en&en) ; --这里en是1 bit数据,b是4 bit数据。
tmp_b<=b AND (en, en, en, en); --这两句是等效的
``但是上述第二句这种方法不适用于位矢量的连接``
tmp_b<=b AND (3=>en, 2=>en, 1=>en, 0=>en); --这两数字1是指将en赋给变量的第几位
tmp_b<=b AND (3 DOWNTO 0=>EN); --这种方法与前一种方法类似
tmp_b<=b AND (OTHERS=>en); --这种方法与前两种方法达到的目的是一样的
--但是注意,OTHERS要放在集合体的最后。假若b位矢量的脚标b(2)的选择信号为'0',其他信号均为en,则表表达式为:
tmp_b<=(2=>'0', others=>en);
VHDL有三种不同风格的描述方式,即行为描述、寄存器描述(或数据流描述)、结构描述。一般来说,后两种描述方式能够直接综合成电路,而第一种描述方式在大多数时候是用来进行系统仿真,少数时候能够逻辑综合成电路。
不同语言对行为描述的定义不同,但是有一点是确定的,行为描述方式是对系统数学模型的描述,其抽象程度比寄存器传输描述更高。不能综合的原因是在行为描述中有大量采用算术运算、关系运算、惯性延时、传输延时等难以进行逻辑综合和不能进行逻辑综合的VHDL语句。一般来说行为描述语句主要用于系统数学模型的仿真或者系统工作原理的仿真
。
代入语句格式如下:
信号量 <= 敏感信号量表达式;
例如,
a<=b;
该语句是a得到b的值。这时候,b就是一个敏感信号量,只要b的值发生变化时,该语句就会被执行。
具有延时时间的代入语句如下:
a<=b AFTER 5ns; --``注意这里语句只能用来仿真``
下面以一个例子展示代入语句:
ENTITY and2 IS
PORT (a,b : IN BIT;
c : OUT BIT;
END ENTITY and2;
ARCHITECTURE and2_behav OF and2 IS
BEGIN
c<=a AND b AFTER 5ns;
END ARCHITECTURE and2_behav;
VHDL当中,延时语句有两证类型:惯性延时和传输延时。
在惯性模型中,系统或器件输出信号要发生变化必须有一段时间的延迟,这段延时时间称为系统或器件的惯性。注意这里的惯性延时是指物理器件在物理特性上的延迟,不可改变。
当一个系统或器件的输入信号变化周期小于系统或器件的惯性延迟时,其输出将保持不变。几乎所有的器件都会有惯性延迟,因此为了仿真逼近实际,设计人员在代入语句中几乎都会加上惯性延时时间的说明。例如:
b<=a AFTER 20 ns;
在VHDL当中,惯性延时是缺省的,级在语句中不作特别说明,产生的延时一定是惯性延时,这是因为大多数器件在行为仿真时都会呈现这种惯性延时。
惯性延迟说明只在行为仿真时有意义,在逻辑综合时将被忽略,或者在逻辑综合前必须去掉
VHDL中传输延迟不可缺省,传输延时常用来描述总线延时、连接线的延时及ASIC芯片中的路径延时。
具有传输延迟的代入语句如下:
b<=TRANSPORT a AFTER 20ns;
TRANSPORT是专门用于说明传输延迟的前置词。
在93版中,信号延时可指定脉冲宽度限制,在信号延迟表达式中REIECT用来限制脉冲宽度。例如:
dout1<=a AND b AFTER 5ns;
dout2<=REJECT 3ns INTENAL a AND b;
VHD中,创建一个驱动器可以有一条信号代入语句实现。当有多个代入语句时,就有可能出现多个驱动器连接到同一信号线上的情况。
ARCHITECTURE sample OF sample IS
BEGIN
a<=b AFTER 5ns;
a<=d AFTER 5ns;
END ARCHITECTURE sample;
这时候就存在多个驱动器驱动同一信号的情况,就存在一个问题:怎样选择输出。在VHDL中,为解决这一问题,在包集合STD_LOGIC_1164中专门定义了一种描述判决函数的数据类型,称为判决子类型。判决函数解决的问题就是在多个驱动器同时驱动一个信号时,定义输出哪一个值的函数。判决函数如下:
FUNCTION resolved (s: STD_ULOGIC_VECTOR) RETURN STD_ULOGIC;
--STD_ULOGIC_VECTO是专门定义的一种数据类型
--resolved函数是判决函数
GENERIC语句常用于不同层次的信息传递。可以传递的信息包括但不仅限于位矢量的常数,数组的长度以及器件的延时时间。该语句所涉及的数据除整数类型外,如涉及其他类型的数据,则不能进行逻辑综合。
使用GENRIC语句易于使器件模块化和通用化。例如,要描述二输入与门的行为。二输入与门的逻辑关系是明确的,但是由于工艺、材料的不同会有不同的延时时间。为实现通用化,需要开发一个通用的而输入与门的程序模块。如下:
ENTITY and2 IS
GENERIC (rise, fall: TIME);
PORT( a,b: IN BIT;
c: OUT BIT);
END ENTITY and2;
ARCHITECTURE behav OF and2 IS
SIGNAL internal: BIT;
BEGIN
internal<=a AND b;
c<= internal AFTER (rise) WHEN internal='1' ELSE
internal AFTER (fall);
END ARCHITECTURE behav;
下面是调用这个模块。
ENTITY sample IS
GENERIC (rise,fall: TIME);
PORT(ina,inb,inc,ind: IN BIT
q: OUT BIT);
END ENTITY sample;
ARCHITECTURE behav OF sample IS
COMPONENT and2 IS
GENERIC (rise,fall: TIME);
PORT( a,b: IN BIT;
c: OUT BIT);
END COMPONENT and2;
SIGNAL U0_C, U1_C: BIT;
BEGIN
U0: and2 GENRIC MAP(5ns, 5ns);
PORT MAP(ina, inb, U0_C);
U1: and2 GENRIC MAP(8ns, 10ns);
PORT MAP(inc, ind, U1_C);
U2: and2 GENRIC MAP(9ns, 11ns);
PORT MAP(U0_C, U1_C, c);
END ARCHITECTURE behav;
在这里可以看出VHDL语言GENERIC语句的灵活性,在元件调用时,可以代入不同参数,完成灵活的配置。
RTL描述是真正可以进行逻辑综合的描述方式。RTL描述也被称为数据流描述。
VHDL中的语句有一些限制:要么采用寄存器硬件一一对应的直接描述,要么采用寄存器之间的功能描述。
功能描述的RTL描述方式例子如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY mux2 IS
PORT (input: IN STD_LOGIC_VECTOR(1 DOWMTO 0);
sel: IN STD_LOGIC;
y: OUT STD_LOGIC);
END ENTITY mux2;
ARCHITECTURE rtl OF mux2 IS
BEGIN
y<=input(0) WHEN sel='1' ELSE
input(1);
END ARCHETECTURE rtl;
硬件一一对应的RTL描述方式例子如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY mux2 IS
PORT (input: IN STD_LOGIC_VECTOR(1 DOWMTO 0);
sel: IN STD_LOGIC;
y: OUT STD_LOGIC);
END ENTITY mux2;
ARCHITECTURE rtl OF mux2 IS
SIGNAL tmp1, tmp2, tmp3: STD_LOGIC;
BEGIN
tmp1<=in0 AND sel;
tmp2<=in1 AND (NOT sel);
tmp3<=tmp1 OR tmp2;
y<=tmp3;
END ARCHETECTURE rtl;
寄存器之间的功能描述是一种逻辑描述,只要知道外部特性和功能就行。寄存器硬件一一对应的描述是一种具体的描述,需要了解电路的构成,内部采用了哪些门电路。
PROCESS (sel) IS
BEGIN
IF(sel='1') THEN
y<='0';
ELSE
y<='1';
END IF;
END PROCESS;
改变书写顺序,
PROCESS (sel) IS
BEGIN
IF(sel='1') THEN
y<='1';
ELSE
y<='0';
END IF;
END PROCESS;
这两个例子只是书写顺序不一致,当sel='X’时,却会有不同的输出。为防止这种不合理的结果,增加一项,
PROCESS (sel) IS
BEGIN
IF(sel='1') THEN
y<='1';
ELSE IF(sel='0')
y<='0';
ELSE
y<='X';
END IF;
END PROCESS;
1、禁止一个进程中存在两个寄存器描述。RTL规定:一个进程中只能描述一个寄存器。
2、禁止IF语句中的ELSE项。在用IF语句描述寄存器功能时,禁止采用ELSE项
3、寄存器描述中必须代入信号值。
结构描述方式就是在多层次的设计中,高层次的设计模块调用低层次的设计模块,或者直接调用门电路设计单元来构成一个复杂逻辑电路的描述方法。结构描述方式最能提高设计效率,同时灵活性也是最高的。
结构描述是用COMPONENT语句(类似于C语言的声明)指明了在该电路中所使用的已生成模块,供本构造体调用。用PORT MAP语句将生成模块的端口与设计的各模块的端口联系起来,并定义相应的信号,来表示所设计的各模块的连接关系。
COMPONENT语句是基本的描述语句。该语句指定了本构造体中所调用的是哪一现成的逻辑描述模块。其格式如下:
COMPONENT 元件名 IS
GENERIC 说明; --参数说明
PORT 说明; --端口说明
END COMPONENT 元件名;
COMPONENT语句可以在ARCHITECTURE、PACKAGE及BLOCK的说明部分中使用。COMPONENT语句当中有GENERIC语句和PORT语句。GENERIC语句通常用于该元件的可变参数的代入或赋值。PORT语句用于说明该元件的输入、输出端口的信号规定。
COMPONENT_INSTANT语句是结构化描述中不可缺少的一个基本语句(类似于C语言当中的调用语句)。其格式如下:
标号名 : 元件名 PORT MAP(信号,...);
例如:
u2: and2 PORT MAP(nsel, d1, ab);
标号架子啊元件名的前面,在该构造体的说明汇总该标号名一定是唯一的。下一层元件的端口信号与实际连接的信号用PORT MAP的映射关系联系起来。映射的方法有两种:位置映射和名称映射。
PORT(a, b: IN BIT;
c: OUT BIT);
u2: and2 PORT MAP(nsel, d1,ab);
--这里nsel和a对应,b和d1对应,c和ab对应。
u2:and2 PORT MAP(a=>nsel, b=>d1, c=>ab);
在输出信号没有连接的情况下,对应端口的描述可以省略。
在用VHDL语言描述系统硬件行为时,按语句执行顺序对其进行分类,可以分为顺序(Sequential)描述语句和并发(Concurrent)描述语言。
顺序描述语言只能出现在进程或子程序中,由它定义进程或子程序所执行的算法。顺序描述语句中所涉及到的系统行为有时序流、控制、条件和迭代等。顺序描述语句的功能操作有算术、逻辑运算,信号和变量的赋值,子程序调用等。顺序描述语句主要由有:
NULL(空)语句表示只占位置的一种空处理操作,但是它可以用来为所对应信号赋一个空值,表示该驱动器被关闭
进程在仿真运行中总是处于下述两种状态之一:执行或挂起。进程状态的变化受等待语句的控制,当进程执行到等到语句时,会被挂起,并设置好再次执行的条件。等待语句可以设置4种不同的条件:无限等待、时间到、条件满足以及敏感信号量变化。这几种条件可以混用。其书写格式如下:
WAIT --无线等待
WAIT ON --敏感信号量的变化
WAIT UNTIL --条件满足
WAIT FOR --时间到
WAIT ON 信号 [,信号];
WAIT ON a, b; ---这是WAIT ON 后面接着多个信号量的语句
--上语句表明:它等待信号量a或者b发生变化。只要a或者b中有一个信号量发生变化,进程就结束挂起状态,而继续执行WAIT ON语句后续语句。
下面以两个例子直接来说明WAIT ON语句在实际使用的作用。实际上,两个例子的作用是一样的。并且如果PROCESS语句已经有了敏感信号量,在PROCESS语句中便不能再使用WAIT ON语句。
PROCESS(a,b) IS
BEGIN
y<=a AND b;
END PROCESS;
**************
PROCESS
BEGIN
y<=a AND b;
WAIT ON a,b;
END PROCESS;
WAIT UNTIL 表达式; --这里的表达式是布尔表达式,当进程执行到该语句时将被挂起,直至表达式返回一个“真”值。
实际上,表示式是一个隐式的敏感信号量表。当表中的任何一个信号量发生变化时,立即对表达式进行一次评估。
实例如下:
WAIT UNTIL((x*10)<100); --当信号量的值大于或者10时,进程执行到该语句时将被挂起;反之,进程将被挂起。
WAIT FOR 时间表达式; --进程执行到该语句时将被挂起,直到指定的等待时间到时,进程再开始执行WAIT FOR语句后续的语句。
实例如下:
WAIT FOR 20ns;
WAIT FOR (a*(b+c));--注意WAIT FOR的语句一定是时间量
WAIT ON nmi, interrupt UNTIL((nmi=TRUE)OR(interrupt=TRUE)) FOR 5us;
上述语句有三个等待的结束条件:
(1)信号量nmi和interrupt中任何一个有一次新的变化;
(2)信号量nmi和interrupt中任何一个取值为“真”;
(3)该语句已等待5us。
注意在多条件WAIT语句表达式的值至少应该至少包含一个信号量的值
WAIT UNTIL (sedB='1') FOR 1us;
ASSERT(sendB='1')
REPORT"sendB timed out at '1' "
SEVERIRT ERROR;
上例中,每个等待语句的超时表达式用1us说明。如果等待语句的等待时间超过了1us,则进程执行下一条ASSERT语句。ASSERT语句的判断条件为“假”,就向操作人员提供错误输出信息输出,帮助操作人员了解在进程中发生了超时等待。
断言(ASSERT)语句主要用于程序仿真、调试的人机对话,它可以给出一个文字串作为警告和错误信息,其给程序调试带来极大好处。其书写格式如下:
ASSERT 条件 [REPORT 输出信息] [SEVERITY 级别];
当执行ASSERT语句时就会对条件进行判决。如果条件为“真”,则向下执行另一个语句;如果条件为“假”,则输出错误信息和错误严重程度的级别。REPORT后面跟的是设计者所写字符串,通常是说明错误原因,文件串应该用" "括起来。SEVERITY后面跟的是错误严重程度的级别。VHDL中错误有四个级别:FAILURE, ERROR, WARNING, NOTE。
例子:
ASSERT(sendB='1')
REPORT"sendB timed out at '1' "
SEVERIRT ERROR
信号代入语句的书写格式如下:
目的信号量<=信号量表达式;
该语句表明:将右边信号量表达式的值赋予左边的目的信号量。注意:代入符号两边信号量的类型和位长度应该一致
另外,代入语句的符号“<=”和关系操作的小于等于符号“<=”是相同的,在使用时应该正确判别不同的操作关系。
变量赋值语句的书写格式如下:
目的变量:=表达式;
该语句表明:目的变量的值将由表达式所表达的新值代替。注意:赋值符号左右两边的变量的数据类型必须相同
目的变量的类型、范围及初值在实现应已给出过。右边表达式可以是变量、信号或字符。
IF语句是根据所指定的条件来确定执行哪些语句,有三种书写格式:门闩控制、二选择控制、多选择控制。
``注意IF语句的条件判断输出是布尔量,即是“真( TRUE)”或“假“FALSE”。因此IF语句的条件表达式中只能使用关系运算操作符。
IF 条件 THEN
顺序处理语句
END IF;
当程序执行到IF语句时,判断IF语句所指定的条件是否成立。如果成立,则IF语句所包含的顺序处理语句将被执行;反之,程序将跳过IF语句所包含的顺序处理语句,向下执行后续语句。
实例:
IF(a='1') THEN
c<=b;
END IF;
这是门闩控制的一个实例,该语句会被综合为一个D触发器。
IF 条件 THEN
顺序处理语句;
ELSE
顺序处理语句;
END IF;
这种语句是一个非此即彼的语句,用条件来选择两条不同程序执行的路径。
典型实例二选一电路如下:
ARCHITECTURE rtl OF mux2 IS
BEGIN
PROCESS(a, b, sel) IS
BEGIN
IF(sel='1') THEN
c<=a;
ELSE
c<=b;
END IF;
END PROCESS;
END ARCHITETUREL rtl;
IF 条件 THEN
顺序处理语句;
ELSEIF 条件 THEN
顺序处理语句;
···
ELSEIF 条件 THEN
顺序处理语句;
ELSE
顺序处理语句;
END IF;
典型的多选择语句是多选一电路。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY mux4 IS
PORT(input: IN STD_LOGIC_VECTOR (3 DOWNTO 0);
sel: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
y: OUT STD_LOGIC);
END ENTITY mux4;
ARCHITECTURE rtl OF mux4 IS
BEGIN
PROCESS(input, sel) IS
BEGIN
IF(sel="00") THEN
y<=input(0);
ELSEIF(sel="01") THEN
y<=input(1);
ELSEIF(sel="10") THEN
y<=input(2);
ELSE
y<=input(3);
ENS IF;
END PROCESS;
END ARCHITECTURE;
CASE语句用来描述总线或编码、译码的行为,从许多不同语句的序列中选择其中之一来执行。CASE语句的书写格式如下:
CASE 表达式 IS
WHEN 条件表达式=>顺序处理语句;
END CASE;
CASE语句的条件表达式可以有如下4种不同的表达形式:
WHEN 值 =>顺序处理语句;
WHEN 值|值|值|···|值 =>顺序处理语句;
WHEN 值 TO 值 =>顺序处理语句;
WHEN OTHERS =>顺序处理语句; --这里的OTHERS表示其他所有值的缺省。
实例:
LIBARRY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY mux4 IS
PORT(a,b,i0,i1,i2,i3: IN STD_LOGIC;
q: OUT STD_LOGIC);
END ENEITY mux4;
ARCHITECTURE mux4_behave of mux4 IS
SIGNAL sel: INTEGER ranger 0 TO 3;
BEGIN
B: PROCESS(a,b,i0,i1,i2,i3) IS
BEGIN
sel<='0';
IF(a='1')THEN
sel<=sel+1;
END IF;
IF(b='1')THEN
sel<=sel+2;
END IF;
CASE sel IS
WHEN 0=> q<=i0;
WHEN 1=> q<=i1;
WHEN 2=> q<=i2;
WHEN 3=> q<=i3;
END CASE;
END PROCESS;
END ARCHITECTURE;
CASE语句和IF语句的对比:CASE语句是一种并行处理语句,IF语句是串行处理语句。在CASE语句中,WHEH的条件是相互独立并且应该将所有的取值一一列举出来。'U'、'X'、'Z'等状态尽管在逻辑电路综合时没有用,但是在CASE语句中必须将所有情况罗列。
如果在CASE语句中的OTHERS之前将所有的所有有意义的输入项(可以逻辑综合的项)都罗列出来,在逻辑综合前就不会有什么不利影响。
下面讨论当OTHERS<="XXX···XXX"时,如果未罗列完所有意义的输入项(可以逻辑综合的项),在综合时,可以认为未罗列的项不可能出现,这会大大简化逻辑电路的设计。但此时如果OTHERS<=“XXX···XXX”(可以逻辑综合),则会使得逻辑综合时,电路规模大大增加。目前VHDL语言的标准中还没有能对输入任意项进行处理的方法。
下面介绍VHDL中,优先项的描述。
WHEN "XXXXXXX0"=> y<="111";
WHEN "XXXXXX01"=> y<="110";
但是这种描述语句在VHDL还未制定出来,因此不能使用这正非法语句。
不晓得这个对不对
这时可以利用IF语句描述优先级编码器。
LOOP语句语句与其他高级语句中的循环语句一样,使程序能进行有规则的循环,循环次数受迭代算法控制。VHDL中,LOPP语句常用来描述位片逻辑及迭代电路的行为。一般有两种书写格式:FOR循环变量、WHILE条件。
[标号]: FOR 循环变量 IN 离散范围 LOOP -- 标号不是必须的
顺序处理语句;
END LOOP [标号];
具体例子如下:
ASUM: FOR i IN 1 TO 9 LOOP
sum:=i+sum; --sum初始值为0;
END LOOP ASUM;
下面看一个完整的例子。
LIBRARY IEEE
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY parity_check IS
PORT(a: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
y: OUT STD_LOGIC);
END ENTITY parity_check;
ARCHITECTURE rtl OF parity_check IS
BEGIN
PROCESS(a) IS
VARIABLE tmp: STD_LOGIC;
BEGIN
tmp:='0';
FOR i IN 0 TO 7 LOOP
tmp:=tmp XOR a(i);
END LOOP;
y<=tmp;
END PROCESS;
END ARCHITECTURE;
--tmp是变量,它只能在进程内部说明,因为他是一个局部量。
--FOR-LOOP中的i在信号说明和变量说明中都未涉及,它是一个循环变量(整数类型的)。信号和变量都不能1代入此循环变量中。
--tmp是进程内部的变量,如想带出进程,必须将其代入信号量中。
[标号] : WHILE 条件 LOOP
顺序处理语句;
END LOOP [标号];
实例如下:
LIBRARY IEEE
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY parity_check IS
PORT(a: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
y: OUT STD_LOGIC);
END ENTITY parity_check;
ARCHITECTURE rtl OF parity_check IS
BEGIN
PROCESS(a) IS
VARIABLE tmp: STD_LOGIC;
BEGIN
tmp:='0';
i:=0;
WHILE(i<8) LOOP
tmp:=tmp XOR a(i);
i:=i+1;
END LOOP;
y<=tmp;
END PROCESS;
END ARCHITECTURE;
在VHDL当中一般不使用WHILE-LOOP语句进行RTL描述。
在LOOP语句中,NEXT语句用来跳出本次循环, 其书写格式如下:
NEXT [标号] [WHEN 条件]
NEXT语句执行时将停止本次迭代,而转入下一次新的迭代。NEXT后跟的“标号”表示下一次迭代的起始位置,WHEN条件表明NEXT语句执行的条件。如果NEXT后面既无“标号”,也无“WHEN条件”,那么只要执行到该语句就立即无条件跳出本次循环,并从LOOP的起始位置开始下一次循环。
例子如下:
L1: WHILE i<10 LOOP
L2: WHEN j<20 LOOP
···
NEXT L1 WHEN i=j;
···
END LOOP L2;
END LOOP L1;
EXIT语句也是LOOP语句当中的控制语句。但是与NEXT语句不同,EXIT语句是直接将LOOP语句结束。其书写格式如下:
EXIT [标号] [WHEN 条件]
如果EXIT后面没有跟“标号”和“WHEN条件”,则程序执行到该语句时无条件地从LOOP语句中跳出,结束循环状态。EXIT语句实例:
PROCESS(a) IS
VARIABLE int_a: INTEGER;
BEGIN
int_a:=a;
FOR i IN 0 to max_limit LOOP
IF(int_a<=0) THEN
EXIT;
ELSE
int_a:=int_a-1;
q(i)<=3.1416/REAL(a*i);
END IF;
END LOOP;
END PROCESS;
EXIT有四种具体的情况。
第一、EXIT语句有“循环标号”和“WHEN条件”。这时,应该进行判断跳转到“循环标号”位置处。
第二、EXIT语句有“WHEN条件”但无“循环标号”。这时,应该进行判断,然后结束本LOOP循环。执行下面的语句。
第三、EXIT语句有“循环标号”但无“WHEN条件”。此时直接跳转到“循环标号”处。
第四、EXIT语句既无“循环标号”也无“WHEN条件。此时立即结束本LOOP循环。
EXIT语据是一条很有用的控制语句。当程序需要处理保护、出错和警告状态时,它能提供一个快捷、简便的方法。
在VHDL中,能够进行并发处理的语句有:进程(PROCESS)语句、并发信号代入(Concurrent Signal Assignment)语句、条件信号代入(Conditional Signal Assignment)语句、选择信号代入(Selective Signal Assignment)语句、并发过程调用(Concurrent Procedure Call)语句和块(Block)语句。并发语句既可以是结构性的,也可以是行为性的。并且在并发语句中最关键的就是进程语句。
进程语句(PROCESS)是一种并发语句,在一个构造体中多个PROCESS语句可以同时并发运行。PROCESS语句有以下几个特点:
1、进程之间是并行的,进程可以存取构造体或实体名中定义的信号; 2、进程内部所有语句顺序执行; 3、进程结构中必须包含一个显式的敏感信号量或者包含一个WAIT语句; 4、进程之间的通信是通过信号量传递来实现。
并发代入语句实际就是一种在构造体内部但是在进程外部的代入语句。并发信号代入语句实际上就是一个进程的缩写。下面举一个例子说明并发信号代入语句。
ARCHITECTURE behav OF a_var IS
BEGIN
OUTPUT<=a(i);
END ARCHITECTURE behav;
–可以等效为:
ARCHITECTURE behav OF a_var IS
BEGIN
PROCESS(a(i)) IS;
BEGIN
output<=a(i);
END PROCESS;
END ARCHITECTURE behav;
上述两种方式实际上就是一样的效果。
条件代入语句也是并发描述语句,它可以根据不同条件将不同的多个表达式之一的值代入信号量,其书写格式如下:
目的信号量<=表达式1 WHEN条件1 ELSE
表达式2 WHEN条件2 ELSE
表达式3 WHEN条件3 ELSE
···
ELSE
表达式n;
具体例子如下:
ENTITY mux4 IS
PORT(i0,i1,i2,i3,a,b: IN STD_LOGIC;
q: OUT STDLOGIC);
END ENTITY mux4;
ARCHITECTURE rtl OF mux4 IS
SIGNAL sel: STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN
sel<=b&a;
q<=i0 WHEN sel="00" ELSE
i1 WHEN sel="01" ELSE
i2 WHEN sel="10" ELSE
i3 WHEN sel="11" ELSE
'X';
END ARCHITECTURE;
条件代入语句中ELSE语句一定要有。条件代入语句不能进行嵌套。受制于没有自身值代入的描述,不能生成锁存电路。
选择信号代入语句类似于CASE语句,它对表达式进行测试,当表达式取值不同时,将使不同的值代入目的信号量。其书写格式如下:
WITH 表达式 SELECT
目的信号量<=表达式1 WHEN 条件1
表达式2 WHEN 条件2
···
表达式n WHEN 条件n;
具体表达式如下:
ENTITY mux4 IS
PORT(i0,i1,i2,i3,a,b: IN STD_LOGIC;
q: OUT STDLOGIC);
END ENTITY mux4;
ARCHITECTURE behav OF mux4 IS
SIGNAL sel: INTEGER;
BEGIN
q<=i0 WHEN 0;
i1 WHEN 1;
i2 WHEN 2;
i3 WHEN 3;
‘X’ WHEN OTHERS;
sel<=0 WHEN a='0' AND b='0' ELSE
1 WHEN a='1' AND b='0' ELSE
2 WHEN a='0' AND b='1' ELSE
3 WHEN a='1' AND b='1' ELSE
4;
END ARCHITECTURE behav;
并发过程调用语句,这里对过程调用时需要注意的几个问题作以下说明。
1、并发过程调用语句是一个完整的语句,在其前面可以加标号;
2、并发过程调用语句应该有IN/OUT或者INOUT参数,它们应列于过程名后跟的括号内;
3、并发过程调用可以有多个返回值,但这些返回值应该通过过程定义的输出参数带回。
在构造体中采用并发过程调用语句的实例如下:
ARCHITECTURE···
BEGIN
Vector_to_int(z,x_flag);
···
END ARCHITECTURE;
上例中的Vector_to_int兵法过程调用时对位矢量z进行数制转换,使之变成十进制的整数q;x_flag是标志位,当标志位为“真”时表明转换失败,当为“假”时表明转换成功。
实际上这种并发调用语句就是一个进程调用过程的简写,其效果等效于在进程当中调用一个过程
块语句的书写格式如下:
标号: BLOCK
块头
{说明语句};
BEGIN
{并发处理语句};
END BLOCK 标号名;
“块头”主要用于信号的映射及参数的定义,通常通过GENRIC语句、GENERIC_MAP语句、PORT语句和PORT_MAP语据来实现。
“说明语句”主要是对块使用的客体进行说明。说明的项目包括:USE语句、子程序说明及子程序体、类型说明、常数说明、信号说明和元件说明。
块是可以嵌套并且重复调用的。
本节主要说明说明语句、定义语句和一些具体的规定。
VHDL语句有属性预定义功能,该功能有很多重要的应用,例如检测时钟边沿、完成定时检查、获得未约束的数据类型的范围等。
预定义的类型有:数值类、函数类、信号类、数据类型类、数据区间类和用户自定义的属性。
数值类属性用来得到数值、块或者一般数据的有关值。
T'LEFT --得到数据类或子类区间的最左端的值
T'RIGHT --得到数据类或子类区间的最右端的值
T'HIGH --得到数据类或子类区间的高端值和出现的次序相关出现早的次序低
T'LOW --得到数据类或子类区间的低端值和出现的次序相关出现早的次序低
T'LENGTH --数组的长度值
T'STRUCTURE --如果块和构造体中只有COMPONENT语句,则会得到“TRUE”。
T'BEHAVIOR --块或构造体有标号名,并且块和构造体中不存在COMPONENT语句,得到“TRUE”。
所谓函数类属性是指属性以函数的形式,让设计人员得到有关数据类型、数组、信号的某些信息。
函数类属性有以下三种:数组类型属性函数、数组属性函数、信号属性函数。
T'POS(x) --得到输入值x的位置序号
T'VAL(X) --得到输入位置序号x的值
T'SUCC(x) --得到输入x值的下一个值
T'PRED(x) --得到输入x值的前一个值
T'LEFTOF(X) --得到邻近输入x值左边的值
T'RIGHTOF(x) --得到临接输入x值右边的值
对于递增区间有:
T’SUCC(x)=T’RIGHTOF(x)
T’PRED(x)=T’LEFTOF(X)
对递减区间有:
T’SUCC(x)=T’LEFTOF(X)
T’PRED(x)=T’RIGHTOF(x)
T'LEFT(n) --得到索引号为n的区间的左端位置号。这里的n实际上是多维数组中所定义的多维区间的序号。当n缺省时,代表对一维区间进行操作。
T'RIGHT(n) --得到索引号为n的区间的右端位置号
T'HIGH(n) --得到索引号为n的区间的高端位置号
T'LOW(n) --得到索引号为n的区间的低端位置号
对于递增区间有:
T’HIGH(x)=T’RIGHTOF(x)
T’LOW(x)=T’LEFTOF(X)
对递减区间有:
T’HIGH(x)=T’LEFTOF(X)
T’LOW(x)=T’RIGHTOF(x)
S'EVENT --如果在当前一个相当小的时间间隔内时间发生,那么函数将返回一个为“真”的布尔量,否则返回“假”
S'ACTIVE --如果在当前一个相当小的时间间隔内信号发生变化,函数返回“真”;反之,返回“假”
S'LAST_EVENT --返回一个时间值,即从信号前一个事件发生到现在所经历的时间
S'LAST_VALUE --返回一个值,即从信号最后一次发生改变以前的值
S'LAST_ACTIVE --返回一个时间值,即从信号前一次改变到现在的时间
S’EVENT常用来作边沿检测。
信号类属性用于产生一种特别的信号,该信号是以所加属性信号为基础而形成的。信号类属性得到的相关信息类似于用函数类属性得到的信息。但是,信号类属性可以用于任何一般的信号,也包括敏感信号量表中指示的信号。信号类属性有以下四种:
S'DELAYED[(time)] --产生一个延时的信号,信号类型与该属性所加的信号相同。即是以属性所加信号为参考信号,经括号内的时间表达式所确定的时间延时后得到的延迟信号。
S'STABLE[(time)] --该属性可建立一个布尔信号,在括号内的·时间表达式所说明的时间内,若参考信号没有发生转换或其他时间,则得到一个“真”的结果。
S'QUIET[(time)] --该属性可以建立一个布尔信号,在括号内的时间表达式所说明的时间内,若参考信号没有发生转换或其他时间,其属性可以得到“真”的结果。
S'TRANSACTION --该属性可以建立一个BIT类型的信号,当属性所加信号发生转换或者其他事件时,其值将改变。
S’DELAYED[(time)] 可以建立一个所加信号的延迟版本。其实,该功能也可以使用传送延时赋值语句(Transport delay)实现。但是,后者要求编程人员用传送延时赋值的方式记入程序中,而且带有传送延时赋值的信号是一个新的信号。
利用该属性可以得到数据类型的一个值。它仅仅是一个类型属性,而且必须使用数值类或函数类属性的值来表示。例如:
t'BASE;
用该属性可以的带数据t的类型或者子类型,它仅仅作为其他属性的前缀来使用。例如:
a:=color_gun'BASE'RIGHT; --a=BLACK
VHDL中仅有两类数据区间类属性,这两类属性仅用于受约束的数据类型数据,并且可返回所选择输入参数的索引区间。这两个属性如下:
a'RANGE[(n)]; --返回一个由参数n所指出的第n个数据区间
a'REVERSE_RANGE[(n)]; --返回一个次序颠倒的数据区间
自定义属性的书写格式如下:
ATTRIBUTE 属性名: 数据子类型名;
ATTRIBUTE 属性名: OF 目标名: 目标集合 IS 公式;
在对要使用的属性进行说明以后就可以对数据类型、信号、变量、实体、构造体、配置、子程序、元件、标号进行具体的描述。
用户自定义属性的值在仿真中是不能改变的,也不能用于逻辑综合。用户自定义的属性主要用于从VHDL逻辑综合及ASIC的设计工具、动态解析工具的数据的过渡。
GENERATE语句用来产生多个相同的结构,由FOR-GENERATE和IF-GENERATE两种使用形式:
标号: FOR 变量 IN 不连续区间 GENERATE
<并发处理语句>;
END GENERATE [标号名];
标号: IF 条件 GENERATE
<并发处理语句>;
END GENERATE [标号名];