桂林旅游网站制作夫唯seo怎么样
VHDL代码结构
一段完整的VHDL代码的3个基本组成部分:库(LIBRARY)声明、实体(ENTITY)和构造体(ARCHITECTURE)。
VHDL代码基本单元
-
LIBRARY(库)声明:列出当前设计中需要用到的所有库文件,如ieee,std和work等。
-
ENTITY(实体):定义了电路的输入/输出引脚;给出了电路外部连接端口(PORTS)的定义;定义电路模块的外部属性。
-
ARCHITECTURE(构造体):所包含的代码描述了电路要实现的功能;内部的语句描述了电路所实现的功能。
库是一些常用代码的集合,将电路设计中经常使用的一些代码存放到库中有利于设计的重用和代码共享。下图给出了库的典型结构。代码通常以FUNCTION(函数)、PROCEDURE(过程)或COMPONENT(元件)等标准形式存放在PACKAGE(包集)中,用户可以根据需要对其进行编译和使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FbP05kJN-1668149634177)(.\VHDL代码的基本组成.png)]
2.2库声明
-
IEEE(标准库)、STD(语言定义库),IEEE扩展库、VITAL(主要ASIC设计提供的一些仿真模型)、Work(临时库),存放用户设计所有相关的文件。
-
LIBRARY(库)的建立和使用有利于设计重用和代码共享,同时可以使代码结构更加清晰。
-
work 库是当前工作库,当前设计的所有代码都存放在work中,使用work库不需要进行任何声明。
包:
定义公共属性(函数、常量、自定义数据类型、子类型),和C语言的头文件类似。
package package_name is常量;自定义数据类型;子类型;函数;
end package_name ;
VHDL 允许用户在定义函数的时候,将函数的声明与函数的实现进行分离。
package body package_name is函数实现;
end package_name ;
函数声明在
package
中,实现在package body
,当然可以将函数直接在package
中实现。
自己定义的包存放在work
库中;
预定义包:
- STD_LOGIC_1164
它是IEEE库中使用率较高的一个包,其中STD_LOGIC,STD_LOGIC_VECTER数据类型是设计中必须用到的数据类型。该包主要定义了一些数据类型,子类型以及函数。
- STD_LOGIC_ARITH
数学相关的运算符号、数据类型等定义在这个包中(+、-、*、/……),
- STD_LOGIC_SIGNED
- STD_LOGIC_USIGNED
这两个包主要是为了丰富
STD_LOGIC_ARITH
包,定义了这两个包,就可以不用定义STD_LOGIC_ARITH
包了。
实体
entity add_m is-- 参数声明Generic(constant a_WIDTH:STD_LOGIC_VECTOR:=7; -- 定义一个常量);-- 端口声明port (clk :in std_logic; -- 逻辑类型的a, b:in std_logic_vector(7 downto 0) ;s,cout:out std_logic_vector(8 downto 0));
end add_m;
信号模式
-
signal_mode(端口信号)的模式有四种:IN,OUT,INOUT或者BUFFER。
-
IN,OUT :是单向引脚
-
INOUT:是双向引脚
-
OUT类型的端口是不能供电路内部使用的。
-
信号的类型包括:BIT、STD_LOGIC、INTEGER
-
BUFFER:该模式的引脚首先是一个输出引脚,但该输出信号可以供电路内部使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwuhdZuS-1668149634178)(.\信号模式.png)]
结构体
描述电路模块的内部结构
architecture dataflow of add_m is-- 定义信号-- 定义函数-- 定义自定义数据类型-- 调用某个模块的时候,先要例化元件,再在begin end 模块中调用
begin-- 例化模块s <= a xor b xor cin;cout <= (a and b) or (a and cin) or (b and cin);
end dataflow;
电路语句
进程语句
Verilog 的进程语句为 always 和 initial。VHDL中只有一条进程语句为
process
- process内部的代码是顺序执行的,每当敏感信号列表中的信号发生变化时,process 就执行一次
Process:
Process (敏感信号列表)-- 定义变量,VHDL比Verilog多了一个变量,变量只能在单个的进程语句中进行描述 ;-- 大部分情况下,变量都是可以用信号进行代替的, 但不能将变量当作信号使用,-- 变量相当于信号传递过程中的中间量-- architecture 的声明部分没有信号模式说明(信号模式说明在ENTITY中才会出现)
begin-- 和always语句一样-- if ;case……;end process;
- 操作符“ <= ”用来给信号(SIGNAL)赋值,“:=”用来给变量(VARIABLE)赋值,默认情况下,ENTITY中所有的端口都是信号
- VHDL的整体框架:库、包、实体、结构体
library ieee;
use IEEE.std_logic_1164.all;entity test_one isport (clk : in bit; -- 这里的端口信号是BIT类型的,BIT类型在std库中定义。-- 本例不需要进行声明,因为std库和work库是默认可见的。a, b : in bit;q : out bit);
end entity;architecture rtl of test_one issignal temp : bit; -- architecture 的声明部分没有信号模式说明(信号模式说明在ENTITY中才会出现)
begintemp <= a nand b;process (clk) -- 尽管process 内部的语句是顺序执行的,--但是process作为一个整体 和 process外部的其他语句是并发执行的begin-- if clk'event and clk = '1' thenif rising_edge(clk) thenq <= temp;end if;end process;
end architecture rtl;
基本语法
数学表示:
数学类型(数据类型为数学类型)
10#170# -- 表示十进制数170
2#1111_1110# -- 表示二进制数354
16#a#E2 -- 表示 10*16^2
2#1010#E2 -- 表示 10*2^2
10#10#E2 -- 表示 10*10^2
逻辑类型(数据类型为逻辑类型)
逻辑位串,VHDL 中的逻辑变量没有十进制
B"1010" -- 表示二进制逻辑值 10
X"a" -- 表示16进制逻辑值 10
O"3" -- 表示8进制逻辑值 10
位的表示
7 downto 0 -- [7:0]
0 to 7 -- [0:7]
上升沿下降沿的表示
-- 使用语句表示上升沿
clk'event and clk = '1' -- “clk'event”表示“clk”发生变化,“clk == 1”表示上升沿-- 使用函数表示上升沿
rising_edge(clk); -- 调用的系统函数----------------------------------------------------------
-- 使用语句表示下降沿
clk'event and clk = '0' -- “clk'event”表示“clk”发生变化,“clk == 1”表示下降沿-- 使用函数表示上升沿
fulling_edge(clk); -- 调用的系统函数
VHDL 中的等号是 “ = ”
运算符
算术运算符
-
+、-、*、/
-
‘+’、‘-’:正负数的表示(+5:表示正5,-5:表示负5)。
-
&:位拼接;
Verilog中是:{a,b}
VHDL中是:a&b
关系运算符
关系运算符左右两边操作数的数据类型必须相同。
- =:等于
- =:不等于
- <、<= 、>、>=:小于、小于等于、大于、大于等于
逻辑运算符
- 在Verilog中有逻辑运算符(&&、||、!……)和位运算符(&、|、~……);
- 在VHDL中没有位运算符,只有逻辑运算(语法规定的): and(与) 、or(或) 、not(非、取反)、nand(与非)、nor(或非)、xor(异或) 、xnor(同或)
关联运算符
- => :表示符号的左边与符号的右边有关联;不能单独使用,只能在
case
等特定语句下才能使用,否则就是没有意义的。
移位运算符
移位操作符用来对数据进行移位操作,他们是在VHDL93中引入的。
移位操作符的语法结构为:<左操作数><移位操作符><右操作符>
,其中,左操作数必须是BIT_VRCTOR
类型的,右操作数必须是INTEGER
类型(前面可以加正负号)的。
-
sll 逻辑左移 – 数据左移,右端空出来的位置填充 ‘ 0 ’
-
srl 逻辑右移 – 数据右移,左端空出来的位置填充 ‘ 0 ’
-
sla 算术左移 – 数据左移,同时复制最右端的位,在数据左移操作后填充在右端空出的位置上
-
sra 算术右移 – 数据右移,同时复制最左端的位,在数据右移操作后填充在左端空出的位置上
-
rol 循环逻辑左移 – 数据左移,同时从左端溢出的位依次填充到右端空出的位置上
-
ror 循环逻辑右移 – 数据右移,同时从右端溢出的位依次填充到左端空出的位置上
数据类型
数学类型
- Integer:整数类型
- Real:实数类型
- Boolean:布尔量,true\false
- Character:字符类型
- String:字符串类型
- Time:时间类型
- Nature:自然数类型
逻辑类型
- Bit、Bit_verctor:逻辑类型,对应verilog里面的
reg、wire、tri
等类型
数组
数组(Array)是将相同数据类型的数据集合在一起形成的一种新的数据类型。它可以是一维(1D)的,也可以是二维的(2D)的或者1x1维(1Dx1D)的。更高维数的数组通常是不可综合的。
数组的结构如图3.1所示。图中(a)是一个标量,(b)是一个矢量,也是一个一维数组,(c)是一个矢量数组,也是一个1x1维的数组,(d)是一个二维标量数组。
为什么(c)是一个1x1维的呢?该数组包含3个矢量,每个矢量的位宽为5;
事实上可以认为,VHDL预定义的数据类型仅包括标量类型(单个位)和矢量类型(一维数组)两类。这两类中只有下列数据类型是可以综合的:
标量:BIT , STD_LOGIC , STD_ULOGIC 和 BOOLEAN。
矢量:BIT_VECTOR , STD_LOGIC_VECTOR , STD_ULOGIC_VECTOR , INTEGER , SIGNED 和UNSIGNED。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LxcXXbsI-1668149634178)(.\数组.png)]
我们注意到,没有预定义二维和1x1维的数组,用户可以根据需要自己进行定义。为此,我们先要用TYPE
命令定义一种新的数据类型,进而可以用这种新的数据类型对信号、变量或常量进行声明。定义新的数组类型采用如下语法结构:
-- 定义新的数组类型采用如下语法结构:
type type_name is array (specification) of data_type;-- 使用新的数组类型对信号、变量和常数进行声明,可以采用如下语法结构:
type signal_name : type_name[ := initial_value]; -- 这里的初值是可选的-- 在上面的语法结构中,定义了一个新的数组类型的信号。采用同样的方法,可以定义
-- 数组类型的常量(constant)和变量(variable)。
例:数组
要求建立一个数组,它包含4个矢量,每个矢量位宽为8。这实际上是一个1x1维的数组,参见上图的(c)。我们称每个矢量为“行”,称整个数组为“矩阵”。此外,称每个矢量最左边的位为MSB,最上面的一行为“第0行”。那么数组可以这样实现(注意例子中的信号x是阵列类型的):
-- 例 1x1维的数组
type row is array (7 downto 0) of std_logic; -- 1维数组
type matrix is array (0 to 3) of row; -- 1x1维数组
signal x : matrix; -- 1x1维数组-- 例 可以用另一种方法来构造上例中的 1x1 维数组
type matrix is array (0 to 3) of std_logic_vector (7 downto 0) of std_logic;
-- 从数据兼容性的角度来看,后一种方法比前一种更具有优势(参见例3.1)-- 例 二维数组
-- 下面给出了一个二维数组,它并不是由矢量构成的,而是由标量构成的。
type matrix2D is array (0 to 3,7 downto 0) of std_logic; -- 二维数组-- 例 数组的初始化
-- 在上面给出的语法结构中,对信号和变量赋初始值的操作是可选的。可以按如下方式对信号和变量
-- 赋初始值。
... := "0001"; -- 对一维数组初始化
... := ('0','0','0','1'); -- 对一维数组初始化
... := (('0','1','1','1'),('1','1','1','1')); -- 对1x1维数组或二维数组初始化
例 合法和非法的数组赋值
type row is array (7 downto 0) of std_logic; -- 1维数组
type array1 is array (0 to 3) of row; -- 1x1维数组
type array2 is array (0 to 3) of std_logic_vector(7 downto 0); -- 1x1维数组
type array3 is array (0 to 3, 7 downto 0) of std_logic; -- 二维数组signal x : row;
signal y : array1;
signal v : array2;
signal w : array3;-- 下面的数组赋值操作是基于上面定义的数据类型和信号声明的。
-----------------------------合法的标量值赋值--------------------------
-- 因为所有信号(x、y、v 和 w)都源于std_logic类型,所以下面的标量(单个位)赋值都是合法的。
x(0) <= y(1)(2); -- 注意有两个圆括号(y是1x1维数组)
x(1) <= v(2)(3); -- 注意有两个圆括号(v是1x1维数组)
x(2) <= w(2, 1); -- 注意只有一个圆括号(w是二维数组)
y(1)(1) <= x(6);
y(2)(0) <= v(0)(0);
y(0)(0) <= w(3, 3);
w(1, 1) <= x(7);
w(3, 0) <= v(0)(3);
-----------------------------矢量赋值--------------------------
x <= y(0); -- 合法(同是ROW类型的)
x <= v(1); -- 非法,类型不匹配(x 和 v(1) 分别是ROW和STD_LOGIC_VECTOR类型的)
x <= w(2); -- 非法(w必须带有两个索引值)
x <= w(2, 2 downto 0); -- 非法(x是row类型的,而右侧是STD_LOGIC类型的)
v(0) <= w(2, 2 downto 0); -- 非法(V(0)是STD_LOGIC_VECTOR类型的,而右侧是STD_LOGIC类型的,数据类型不匹配)
v(0) <= w(2); -- 非法(w必须带有两个索引值,数据类型也不同)
y(1) <= v(3); -- 非法(y(1)和v(3)分别是ROW和STD_LOGIC_VECTOR类型的)y(1)(7 downto 3) <= x(4 downto 0); -- 合法(同类型,同宽度)
v(1)(7 downto 3) <= v(2)(4 downto 0); -- 合法(同类型,同宽度)
w(1, 5 downto 1) <= v(2)(4 downto 0); -- 非法(数据类型不匹配)
端口数组
在定义电路的输入/输出端口时,有时需要把端口定义为矢量阵列。由于在ENTITY中不允许使用TYPE进行类型定义,所以必须在包集中根据端口的具体信号特征建立用户自定义的数据类型,该数据类型可以供包括ENITY在内的整个设计使用。下面给出一个例子:
--------------------package---------------------
library ieee;
use ieee.std_logic_1164.all;
------------------------------
package my_data_types_package istype vector_arry is array (natural range <>) ofstd_logic_vector(7 downto 0);end my_datamy_data_types_package;--------------------main---------------------library ieee;
use ieee.std_logic_1164.all;
use work.my_datamy_data_types_package.all; -- 用户定义的包集entity mux isport (……;);end entity;……;
---------------------------------------------
记录类型
记录类型和数组类型有些相似,两者唯一的区别在于RECORD类型内部可以包含不同类型的数据,而ARRAY只能包含相同类型的数据。
-- RECORD数据的类型
type birthday is recordday : integer range 1 to 31;month:month_name;
end record
有符号数和无符号数
在IEEE库中有一个名为
std_logic_arith
的包集,其中包括有符号数(SIGNED)和无符号数(UNSIGNED)两种数据类型。
SIGNAL X : SIGNED (7 downto 0);
SIGNAL Y : SIGNED (0 to 3);
只有在代码开始部分声明ieee
库中的包集std_logic_arith
,才能使用有符号数和无符号数。事实上,使用有符号数和无符号数主要是为了进行算术运算,但有/无符号数不支持逻辑运算。
-- 有符号数和无符号数的合法与非法操作
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all; -- 必须声明这个包集才能使用 SIGNED 和 UNSIGNED
-- 或者声明下面这两个包
-- STD_LOGIC_SIGNED
-- STD_LOGIC_USIGNED
........signal a : in signed (7 downto 0);
signal b : in signed (7 downto 0);
signal c : out signed (7 downto 0);........x <= a + b; --合法(支持算术运算)
x <= a and b; --非法(不支持逻辑运算)
std_logic_vector
类型的数据不能直接进行算术运算。为了解决这个问题,ieee库提供STD_LOGIC_SIGNED
、STD_LOGIC_USIGNED
。两个包集。声明了这两个包集以后,STD_LOGIC_VECTOR
类型的数据可以像SINGED
和UNSIGNED
类型的数据一样进行算术运算。
-- 例:STD_LOGIC_VECTOR类型数据的算术运算操作
library ieee;
use ieee.std_logic_1164.all;
use ieee.STD_LOGIC_USIGNED.all;
use ieee.STD_LOGIC_SIGNED.all;-- ....................
signed a:in std_logic_vector (7 downto 0);
signed b:in std_logic_vector (7 downto 0);
signed x:out std_logic_vector (7 downto 0);-- .....................x <= a + b; -- 合法 (支持算术运算)
x <= a and b; -- 合法 (支持逻辑运算)
数据类型转换
在VHDL中,不同类型的数据类型不能直接进行算术或逻辑运算。因此有必要进行数据类型转换操作。有两种常见的方法可以实现数据类型转换:一种方法是写一段专门用于数据类型转换的VHDL代码;另一种方法是调用包集中预定义的数据类型转换函数。在包集std_logic_1164
中有一些数据类型转换函数,可以直接使用。
-- 例:不同类型数据的合法与非法操作
type long is integer range -100 to +100;
type short is integer range 10 to +10;
signal x: short;
signal y: long;
...
y <= 2*x+5; --非法(数据类型不匹配)
y <= long(2*x+5); --合法(运算结果已经强制转换成long类型)
在ieee
库的包集std_logic_arith
中提供了许多数据类型转换函数,如下所示:
-
conv_integer(p)
:将数据类型为INTEGER
,UNSIFGNED
,SIGNED
,STD_ULOGIC
或STD_LOGIC
的操作数p转换成INTEGER
类型。注意,这里不包含STD_LOGIC_VECTOR
。 -
conv_unsigned(p,b)
:将数据类型为INTEGER
,UNSIGNED
,SIGNED
或STD_ULOGIC
的操作数转换成位宽为b的UNSIGNED
类型的数据。 -
conv_signed(p,b)
:将数据类型为INTEGER
,UNSIGNED
,SIGNED
或STD_ULOGIC
的操作数p转换成位宽为b的SIGNED
类型的操作数。 -
conv_std_logic_vector(p,b)
:将数据类型为INTEGER
,UNSIGNED
,SIGNED
或STD_LOGIC
的操作数p转换成位宽为b的STD_LOGIC_VECTOR
。
-- 例:数据类型转换
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
...
signal a:in UNSIGNED(7 downto 0);
signal b:in UNSIGNED(7 downto 0);
...
y <= conv_std_logic_vector((a+b),8);
-- 合法,(a+b)被转换成位宽为8的STD_LOGIC_VECTOR值,然后赋给y。
VHDL中基本的可综合的数据类型
-- VHDL中基本的可综合的数据类型
-- BIT,BIT_VECTOR '0','1'
-- STD_LOGIC , STD_LOGIC_VECTOR 'x','0','1','z'
-- STD_ULOGIC , STD_ULOGIC_VECTOR 'x','0','1','z'
-- BOOLEAN true ,false
-- NATURAL 0 到 +2147483647
-- INTEGER -2147483647 到 +2147483647
-- SIGNED -2147483647 到 +2147483647
-- USIGNED 0 到 +2147483647
-- 用户自定义整形 INTEGER的子集
-- 用户自定义枚举类型 根据用户定义进行编码得到
-- SUBTYPE 任何预定义或用户自定义类型的子集
-- ARRAY 任意上述单一类型数据的集合
-- RECORD 任意上述多种类型数据的集合
例3.1 数据类型用法举例
-- 在给出数据类型定义和信号声明的基础上,下面列出了一些合法和非法的赋值操作:type byte1 is array (7 downto 0) of std_logic; -- 一维数组
type mem1 is array (0 to 3, 7 downto 0) of std_logic; -- 二维数组
type mem2 is array (0 to 3) of byte1; -- 1x1维数组
type mem3 is array (0 to 3) of std_logic_vector(0 to 7); -- 1x1维数组
signal a : std_logic; -- 标量信号
signal b : bit; -- 标量信号
signal x : byte1; -- 一维信号
signal y : std_logic_vector(7 to 0); -- 一维信号
signal v : BIT_VECTOR(3 downto 0); -- 一维信号
signal z : std_logic_vector(x'high downto 0); -- 一维信号
signal w1 : mem1; -- 二维信号
signal w2 : mem2; -- 1x1维信号
signal w3 : mem3; -- 1x1维信号----------------------------------合法的标量赋值-----------------------------x(2) <= a; -- 同类型(std_logic),使用正确
y(0) <= x(0); -- 同类型(std_logic), 使用正确
z(7) <= x(5); -- 同类型(std_logic), 使用正确
b <= v(3); -- 同类型(BIT), 使用正确
w1(0, 0) <= x(3); -- 同类型(std_logic), 使用正确
w1(2, 5) <= y(7); -- 同类型(std_logic), 使用正确
w2(2)(5) <= y(7); -- 同类型(std_logic), 使用正确
w1(2,5) <= w2(3)(7); -- 同类型(std_logic), 使用正确----------------------------------非法的标量赋值-----------------------------
b <= a; -- BIT和STD_LOGIC数据类型不匹配
w1(0)(2) <= x(2); -- w1的索引必须是二维的
w2(2,0) <= a; -- w2的索引必须是1x1维的----------------------------------合法的矢量赋值-----------------------------
x <= "1111_1110";
y <= ('1','1','1','1','1','1','0','z');
z <= "11111"&"000"; -- "&"是拼接符号
x <= (others => '1');
y <= (7 => '0',1 => '0',(others => '1') );
z <= y;y(2 downto 0) <= z(6 downto 4);
w2(0)(7 downto 0) <= "1111_0000";
w3(2) <= y;
z <= w3(1);
z(5 downto 0) <= w3(1)(2 to 7);
w3(1) <= "0000_0000";
w3(1) <= (others => '0');
w2 <= ((others => '0'),(others => '0'),(others => '0'),(others => '0'));
w3 <= ("1111_1110",('0','0','0','0','z','z','z','z'),(others => '0'),(others => '0') );----------------------------------合法的数组赋值-----------------------------
x <= y; --数据类型匹配
y(5 to 7) <= z(6 downto 0); -- y的索引方向(5 to 7)错误
w1 <= ((others => '1')); -- w1是二维数组
w1(0,7 downto 0) <= "1111_1111"; -- w1是二维数组
w2 <= (others => 'z'); -- w2是1x1维数组
w2 (0,7 downto 0) <= "1111_0000"; -- w2指数必须是1x1----------------------------------对数组进行初始化的一个实例-----------------
for i in 0 to 3 loopfor j in 7 downto 0 loopx(j) <= '0';y(j) <= '0';z(j) <= '0';w1(i,j) <= '0';w2(i)(j) <= '0';w3(i)(j) <= '0';end loop;
end loop;
例3.2 单个位和位矢量
这个例子说明了对单个位赋值和对位赋值的区别(也就是说,对BIT和对BIT_VECTOR,STD_LOGIC和STD_LOGIC_VECTOR,STD_ULOGIC 和 STD_ULOGIC_VECTOR的差别进行了对比)。
在下面给出的两段VHDL代码中,都对输入信号进行”与“运算,然后将运算结果赋给输出信号。他们之间的唯一区别是输入和输出的位宽不一样(第一段代码中输入和输出的位宽是1,第二段代码中输入和输出的位宽是4)。图3.2给出了域代码相对应的电路结构。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8HyVSUH-1668149634178)(.\单个位和位矢量.png)]
4.2属性
VHDL语言中的属性(ATTRIBUTE)语句可以从指定的客体或对象中获得关心的数据或信息,因此可以使VHDL代码更灵活。VHDL中的预定义属性可以划分为两大类:数值类属性和信号类属性。
数值类属性
数值类属性用来得到数组、块或一般数据的相关信息,例如可用来获取数组的长度和数值范围等。
VHDL中预定义的可综合的数值类属性如下:
d'LOW
返回数组索引的下限值d'HIGH
返回数组索引的上限值d'LEFT
返回数组索引的左边界值d'RIGHT
返回数组索引的右边界值d'LENGTH
返回矢量的长度值d'RANGE
返回矢量的位宽范围d'REVERSE_RANGE
按相反的次序,返回矢量的位宽范围
例:定义信号
SIGNAL d:STD_LOGIC_VECTOR(7 DOWNTO 0);
-- 则有:
d'LOW = 0; --数组索引的下限值
d'HIGH = 7; --数组索引的上限值
d'LEFT = 7; --数组索引的左边界值
d'RIGHT = 0; --数组索引的右边界值
d'LENGTH = 8; --矢量的长度值
d'RANGE = (7 downto 0); --矢量的位宽范围
d'REVERSE_RANGE = (0 to 7); --按相反的次序,返回矢量的位宽范围
例:定义信号
SIGNAL signal_name:STD_LOGIC_VECTOR(0 to 7);
-- 则下列4个LOOP语句都是可综合的,并且是等效的:
for i in range(0 to 7)loop……for i in signal_name'range(0 to 7)loop……for i in range(signal_name'LOW to x'HIGH)loop……for i in range(0 to signal_name'LENGTH - 1)loop……
枚举类型
对于枚举类型的信号,VHDL中定义了如下属性:
d'VAL(pos)
–返回指定位置(pos)的值d'POS(value)
–给出数值(value),返回其位置序号d'LEFTOF(value)
–给出数值(value),返回其左侧的值d'VAL(row,column)
–返回给定行、列位置对应的值
通常,枚举数据类型的属性是不可综合的。
信号类属性
对于信号 s
,有以下预定义的属性:
-
s'EVENT
如果s的值发生了变化,则返回值为布尔量TRUE,否则返回FALSE。 -
s'STABLE
如果s保持稳定,没有发生变化,则返回值为布尔量TRUE,否则返回值FALSE。 -
s‘ACTIVE
如果当前 s = ’1‘,则返回TRUE,否则返回FALSE。 -
s'QUIET<time>
如果在指定的时间内s没有发生变化,则返回TRUE,否则返回FALSE。 -
s'LAST_EVENT
计算上一次事件发生到现在所经历的时间,并返回这个时间按值。 -
s'LAST_ACTIVE
返回最后一次 s = ‘1’ 到现在所经历的时间长度。 -
s'LAST_VALUE
返回最后一次变化前s的值。
大部分信号类型属性仅用于仿真。但上面给出的前两个信号类属性(s'EVENT 和 s'STABLE
)是可以综合的,其中s'EVENT
最常用。
例:
下面给出的4个赋值语句都是可综合的,并且是等效的。如果信号clk
出现了上升沿,那么将返回TRUE,及括号中的返回值为TRUE。
if (clk'EVENT and clk = '1')…… -- EVENT 搭配if使用if (not clk'STABLE and clk = '1')…… -- STABLE搭配if使用wait until (clk'EVENT and clk = '1')…… -- EVENT搭配wait使用if rising_edge(clk)…… -- 调用一个函数
用户自定义属性
上述给出的诸如HIGH
,RANGE
,EVENT
等都是在VHDL87中预定义的属性,此外VHDL也允许用户自定义属性。使用用户自定义属性首先要进行属性声明,其语法格式为:
ATTRIBUTE attribute_name :attribute_type;
其中,attribute_type可以是任何数据类型,包括BIT、INTEGER、STD_LOGIC和STD_LOGIC_VECTOR等。此后就可以进行属性描述了,具体语法格式如下:
ATTRIBUTE attribute_name of target_name : class is value;
其中,class可以是数据类型、信号、变量、函数、实体或构造体等。
例
ATTRIBUTE number_of_inputs:INTEGER; --属性声明
ATTRIBUTE number_of_inputs of nand3:SIGNAL is 3 --属性描述
……
inputs <= nand3'number_of_inputs; --属性调用,返回值为3
例 枚举类型编码
在一般情况下,对枚举类型数据采用顺序编码的方式。下面是我们定义的枚举类型color:
type color is(red,green,blue,white);
编码后,red = “ 00 ”,green = “ 01 ”,blue = “ 10 ”,white = " 11 "。使用用户自定义属性后,可以改变这种默认的编码次序,具体方式如下:
ATTRIBUTE enum_encoding of color: