Intel FPGA数字信号处理设计(基础版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.2.3 数据类型

数据类型是已命名的一组值,对象的数据类型定义了该对象可以具有的值和可以对该对象进行的运算。VHDL语言是一种类型性很强的语言,不同类型之间的对象通常不能相互赋值或运算,如下面的语句是不合法的。

VHDL语言本身定义了一些基本的数据类型,如标量类型、复合类型、文件类型等,但在具体设计时,极少使用VHDL的基本数据类型,大多使用在基本数据类型基础上重新定义的各种数据类型。这些重新定义的数据类型大多已在封装好的程序包中定义,只要在程序文件中声明相应的程序包后即可直接使用。接下来只对几种最常用的数据类型进行介绍。

1.数值数据类型

定义数值数据类型的语法为

VHDL语言在标准程序包standard中预定义了两种枚举数据类型——INTEGER、REAL,以及INTEGER的两种子类型——NATURAL、POSITIVE。这几种数据类型的定义如下。

VHDL语言通过是否带小数点来区分INTEGER(整数)与REAL(实数)数据类型。比如,“10.0”为REAL数据,“10”为INTEGER数据。FPGA进行实数运算相当麻烦,逻辑综合的程序设计中也不支持实数类型的操作,只可以在仿真测试文件中使用。NATURAL为自然数类型,POSITIVE为正整数类型,这两种数据类型均是INTEGER的子类型。

2.数组数据类型

数组是指由相同数据类型的数据组合在一起而形成的数据类型,VHDL语言在标准程序包standard中预定义好了两种数组数据类型STRING和BIT_VECTOR。

STRING是指由多个CHARACTER组成的数组类型,BIT_VECTOR是指由多个BIT数据组成的数组类型,也称为位向量或位矢量。尖括号(<>)表示无范围限制,因此STRING的下标范围为正整数(不能为0),BIT_VECTOR的下标范围为自然数(可以为0)。如果定义数组类型时指明了下标为无限制,则在声明该类型数据时必须指明下标范围。下面是数组应用例子。

我们也可以定义自己的数组数据类型,如

3.STD_LOGIC_1164定义的数据类型

前面说过,虽然VHDL有多种基本的数据类型,用户也可以自定义各种类型的数据,但在实际设计中一般直接应用软件程序包中已定义好的数据类型。在设计源文件时,一般需要包含几条库及程序包声明语句。

STD_LOGIC_ARITH和STD_LOGIC_UNSIGNED程序包的内容在后文讨论。设计中用得最多的数据类型是在STD_LOGIC_1164程序包中定义的数据类型STD_LOGIC及其数组形式STD_LOGIC_VECTOR。现在来看STD_LOGIC_1164程序包中是如何来定义这两种数据类型的。

读者可能会感到奇怪,STD_LOGIC数据类型仅是STD_ULOGIC的一个子类型,在定义该类型时有一个关键字resolved。resolved是程序包中定义的一个函数,我们不必去过多关注resolved的细节,只需知道STD_LOGIC类型的信号因为有resolved函数的作用,可以由两个以上的信号来驱动。此外,STD_LOGIC的定义与STD_ULOGIC完全相同,STD_LOGIC_VECTOR是STD_LOGIC的数组形式。从STD_ULOGIC数据类型的定义来看,它是一种有9个值的枚举数据类型,每个值都代表着规定的含义,如X表示未知状态,U表示没有初始化,Z表示高阻状态。在这9个状态值中,我们只需记住1、0、Z分别代表数字电路中的1、0及高阻状态即可,其他值通常只在仿真建模时使用。

与VHDL标准程序包中定义的二值数据个BIT相比,STD_LOGIC的值明显丰富了许多。事实上,STD_LOGIC所定义的值可以完全表示数字电路中的信号逻辑。同时,加上IEEE库中提供的适合STD_LOGIC数据类型的各种运算、操作符功能及函数支持,在VHDL设计中几乎仅声明STD_LOGIC及STD_LOGIC_VECTOR这两种数据类型即可以完成全部设计。更形象地讲,在进行VHDL设计时,可以将每BIT的STD_LOGIC类型数据都当成一条实际的信号线来理解,而数字逻辑电路设计不过是各种数字信号之间的运算、控制等操作。

4.STD_LOGIC_ARITH定义的数据类型

STD_LOGIC_ARITH中主要定义了3种数据类型。

SMALL_INT为INTEGER的子类型,只有“0”和“1”两种取值,在VHDL设计中极少使用。有趣的是UNSIGNED和SIGNED两种数据类型的定义方式,你可能又觉得十分奇怪了,STD_LOGIC_ARITH中定义的两种数组类型UNSIGNED、SIGNED与STD_LOGIC_1164中的STD_LOGIC_VECTOR的定义完全相同!这样定义有什么特殊的用处吗?单单从字面上理解,STD_LOGIC_VECTOR数据类型是指一组STD_LOGIC类型的数据集合,SIGNED指有符号数据,UNSIGNED指无符号数据。对于一组二进制数据,我们有时要当成有符号数来运算,有时要当成无符号数来运算,UNSIGNED与SIGNED类型数据正是为解决这一问题而定义的。

在源文件设计中,我们通常会将成组的二进制信号声明成STD_LOGIC_VECTOR数据类型。这样,在设计中,操作数进行加、减、比较等操作时会被当成无符号数运算。如果需要在设计文件中把操作数当作有符号数运算,则只需将或STD_LOGIC_UNSIGNED程序包改成STD_LOGIC_SIGNED即可。读者可能要问了:如果在设计文件中要同时使用有符号数和无符号数操作,该怎么办呢?如果是这样,则首先要在源文件头声明程序包STD_LOGIC_UNSIGNED,然后在需要进行有符号数的操作时,用关键字SIGNED指明操作数为有符号数。

在STD_LOGIC_VECTOR数据的前面加类型名UNSIGNED或SIGNED可以看成数据类型转换,那么其他数据类型之间是否也可以进行这种方式的类型转换呢?答案是否定的。STD_LOGIC_VECTOR与UNSIGNED、SIGNED之间可以进行类型转换的主要原因是它们的定义相同。在VHDL设计中,还有一种大家在其他语言中最为熟悉的数据类型INTEGER,虽然我们不主张在设计中用这种数据类型,但并非不能使用。例如,在设计中同时使用INTEGER与STD_LOGIC_VECTOR两种数据类型,有时难免出现需要INTEGER与STD_LOGIC_VECTOR进行类型转换的情况。庆幸的是,IEEE已为我们编写好类型转换函数,使用起来相当方便,读者可以查看STD_LOGIC_UNSIGNED程序包源文件了解该函数的使用方法。