《Xilinx FPGA设计基础》课件第3章_第1页
《Xilinx FPGA设计基础》课件第3章_第2页
《Xilinx FPGA设计基础》课件第3章_第3页
《Xilinx FPGA设计基础》课件第3章_第4页
《Xilinx FPGA设计基础》课件第3章_第5页
已阅读5页,还剩326页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第3章VHDL硬件描述语言3.1VHDL的历史和概况

3.2VHDL基本设计思想

3.3VHDL语言设计的基本单元

3.4VHDL语言的对象和数据类型3.5VHDL语言运算操作符3.6VHDL语言的描述语句3.7VHDL的层次结构设计3.8有限状态机(FSM)

3.1VHDL的历史和概况

VHDL是VHSIC硬件描述语言(VHSICHardwareDescriptionLanguage)的缩写,而VHSIC又是超高速集成电路(VeryHigh-SpeedIntegratedCircuit)的缩写。从这个缩写我们大致可以看出VHDL语言的起源和目的。

VHDL是1980年在美国国防部的指导下开发的,于1983年完成。1987年被美国国防部和IEEE确定为标准的硬件描述语言,形成的标准为IEEE1076。当初开发这种语言是出于美国国防部采购电子设备的需要。美国军队的装备是向私人企业采购的,如果武器大量装备部队,而其中某个供应商在几年后倒闭了,那这种武器的维修保养和再生产就会出现大问题。而这些电子设备,尤其是超高速集成电路的内部结构很复杂,如果出现了这种问题要找其他公司生产代用品就非常困难。因此,美国国防部希望供应商能留下其产品的信息,以保证其一旦破产能由其他厂商迅速生产出代用品。由于涉及商业机密和知识产权的问题,供应商不会提供最初的设计文档,于是美国国防部就提出了一种折中的方法,即硬件描述语言,也就是VHDL。供应商要用VHDL把自己生产的集成电路芯片的行为描述出来,例如从芯片的哪个管脚输入什么样的信号,过多长时间能输出什么样的信号等。这样,如果需要其他厂商生产代用品,只需要按照VHDL文档,设计行为与其相同的芯片即可。

VHDL当初是为了描述芯片的行为,而并不是为了设计硬件而开发的,因此IEEE1076-1987标准在模型描述方面非常详尽,但在综合方面它只定义了一些很宽泛的参数,在工程实现中有很大的难度。1993年,IEEE修订了VHDL标准,新标准相对于87版本有了很大的改进。93版本的VHDL是目前应用最广泛的版本,很多厂商的综合工具都支持这一标准。IEEE规定其标准必须每五年修订一次,因此VHDL还有很多后续版本,如2000版,但这些版本并没有修订多少内容。 3.2VHDL基本设计思想

从VHDL的字面含义可以看出,VHDL语言着重于描述。通过描述芯片的输入/输出、结构和行为等,使工程师能从概念上对芯片有一个完整的了解。描述的目的是要传递信息,通常意义下的描述是一个非常灵活的过程,例如口述、打手势、书面陈述等,但每个人的表达方式和理解方式不同,这些方法都无法或很难准确无误地传递要表达的信息。因此,工程化的描述都采用规范的语言形式,用严格的语法结构限定描述的内容,VHDL也不例外。

VHDL只是给工程师提供了一个描述规范,用这种规范进行描述可以使众多工程师之间传递信息更加简洁、准确。学习VHDL就是学习如何利用这些规范进行描述,因此,我们在学习VHDL之前,要在思维中假想一个现成的芯片,学习的过程中,对照芯片不断完善对芯片的描述。

VHDL不仅可以对芯片的接口和行为参数做详尽的描述,而且可以作为一门编程语言对可编程逻辑器件进行编程配置。目前,可编程逻辑器件的EDA工具都支持以VHDL代码作为工程设计的输入。

VHDL语言语法简单,结构明晰,可以满足工程设计中的各种需求。

1)用编程的方式描述设计的功能

在2.2节的实验中,我们已经初步接触了VHDL语言程序。VHDL程序的设计方法与其他编程语言的设计方法很相似,工程师可以用编程的思想完成FPGA的电路设计。这对于熟悉Pascal或C语言的工程师来说相当方便。

2) VHDL支持工程设计的结构化描述

一般在硬件电路设计中,采用自底向上的设计方式,即先设计构成系统的各个组成模块,明确模块的端口和时序,然后设计模块之间的互联关系,组成整个系统。

VHDL不仅支持自底向上的设计方式,而且支持如图3.1所示的自顶向下的设计输入模式,这种输入模式更符合一般设计者对工程的认知过程。首先根据工程设计需要完成的功能、芯片的输入/输出信号的定义等信息,对设计的顶层模块进行描述。然后,将顶层模块的功能实现划分为几个二级功能模块,对二级模块的端口和互联关系进行描述。如此,由顶向下逐步将系统模块划分为底层的模块实现。图3.1自顶向下的设计输入方式

3) VHDL支持多层次抽象描述

FPGA电路设计一般抽象为四个层次,即行为层次(Behavioral)、寄存器传输层次(RTL,RegisterTransferLevel)、逻辑门层次(Logic)和布图层次(Layout),如图3.2所示。

行为层次主要关注模块的功能描述和仿真验证,寄存器传输层次要关注模块的可综合电路的实现,逻辑门层次考虑如何用门级电路实现给定功能,布图层次考虑如何将电路适配到FPGA的资源中。

抽象层次越高,设计和仿真用的时间越少,但对电路细节的描述也越少;抽象层次越低,与器件相关的细节描述越多,但设计和仿真难度越大,花费时间越长。图3.2FPGA设计的抽象层次通常做基于FPGA的工程设计,工程师只需要用VHDL语言设计RTL以上的层次实现,电路的FPGA底层实现通过综合工具和实现工具完成。

4)用仿真工具对设计进行仿真

仿真是验证工程设计的必要步骤,VHDL语言有专用的仿真工具,可以对FPGA设计的各个层次做仿真验证,包括行为层次和寄存器传输层次的功能仿真,逻辑门层次的综合后的仿真和布图层次的布局布线后的仿真。每个层次的仿真有其各自的特点,灵活使用各层次的仿真,可以使工程验证得心应手。

另外,需要注意,VHDL语言在建模方面有很多描述语句,但并不是所有的描述语句都是可以综合的,可综合语句只是VHDL建模语句的一个子集,它们的关系如图3.3所示。图3.3建模语句与可综合语句的关系行为层次的VHDL描述是用于仿真的,全部的建模语言都可以使用;寄存器传输层次的VHDL描述只能用可综合的语句。一般的工程设计文件都要用寄存器传输层次的描述,而测试平台文件则用行为级的描述。 3.3VHDL语言设计的基本单元

VHDL是由设计单元组成的,基本的设计单元包括:

●实体Entity;

●构造体Architecture;

●配置Configuration;

●包集合Package;

●库Library。

芯片中的一个模块可以是芯片的顶层模块,即芯片本身,也可以是芯片内的任意模块。读者在学习本节内容的过程中可以参照2.2节实验中的内容,以加深对VHDL设计单元的理解。3.3.1实体

设计一个模块,首先要给模块起一个名字作为这个模块的标识,称为实体名称。这个名字通常与模块的功能有密切关系,例如2.2节实验中的AND_OR。

模块命名后,就要确定这个模块的外部接口参数,即模块有哪些输入信号,有哪些输出信号,信号的名称和类型是什么,在确定了这些参数之后,我们就完成了对实体的描述。

实体描述了模块的外部接口和接口的相关参数。

在VHDL中实体描述的结构如图3.4所示。图3.4实体描述结构图中,“entity实体名称is”标识实体说明的开始,“end实体名称”标识实体说明的结束,“entity”是实体声明的关键字。

端口声明是实体说明的主要部分,用于说明模块实体与外部接口的信号传递关系。模块的端口声明与芯片的管脚说明类似,只有定义了端口,模块才能通过端口信号与外部互相传递信息。

实体中所有的端口信号都要在“port();”语句的括号内声明。端口的声明包含三个部分:端口名称、端口模式和数据类型。相同端口模式和数据类型的端口信号可以作为一组信号联合声明,信号之间用逗号“,”隔开,不同组的信号声明之间用分号“;”隔开,但是要注意声明最后一组信号后不需要再加分号,端口声明的结构如下:

1.端口名称

一般一个模块实体包含不止一个端口,为了区别不同的端口,给端口命名时通常不会采用上面例子中的方式,而会将端口的含义包含在名称中。例如,常用的端口名称“clk”表示时钟信号等。

2.端口模式

端口模式用于定义模块端口的数据传输模式。VHDL的端口模式有五种,如表3.1所示。表3.1端口模式说明

in模式的端口只能用作实体的输入端口,外部信号只能通过端口输入,而实体内部的信号不能通过端口输出,如图3.5(a)所示。

与此相反,out模式的端口只能用作实体的输出端口,实体内部的信号可以通过端口输出,但是外部信号不能通过端口输入,如图3.5(b)所示。图3.5实体端口类型(a) in端口;(b) out端口;(c) inout端口;(d) buffer端口

inout端口是双向端口,既可以用作内部信号的输出端口,也可以用作外部信号的输入端口,但是输入和输出是分时复用的,输入的信号值是外部信号驱动的值,而不是内部输出时驱动的值,如图3.5(c)所示。

buffer是缓冲输出端口,使用buffer输出的信号值在实体内部仍可以对其他信号进行赋值。buffer与inout有明显的不同,buffer不能用作信号的输入。当一个实体的端口用buffer模式时,只能与其他实体的buffer类型的端口相连。

linkage类型的端口不指定信号传输方向,可以与任意类型的端口相连。

3.数据类型

IEEE1706/93VHDL语言参考手册规定,EDA综合工具支持的端口数据类型为布尔型(boolean)、位型(bit)、位矢量型(bit_vector)和整数型(integer)。

由IEEEstd_logic_1164所约定的、并由EDA工具支持和提供的数据类型为标准逻辑类型(StandardLogic)。标准逻辑类型也分为布尔型、位型、位矢量型和整数型。为了使EDA工具的仿真、综合软件能够处理这些逻辑类型,这些库必须用USE语句声明。

我们会在后续内容中对数据类型做详细介绍。

一个典型的实体声明如图3.6所示。图3.6实体声明实例图3.6实例中,一开始将“IEEE”库包含进来,并声明用“IEEE.STD_LOGIC_1164”包中的全部内容。端口的类型选用了STD_LOGIC和STD_LOGIC_VECTOR,STD_LOGIC类似于位型,说明这些端口信号只能取逻辑“0”或逻辑“1”;STD_LOGIC_VECTOR类似于位矢量型,说明这些端口的信号值可以取一组二进制位值,位矢量的长度在后面的括号中说明,(7downto0)说明该端口是一个8位的端口,比特位由左至右为从高到低的次序。

4.参数声明

实体的声明过程中还可以加入参数声明,参数声明类似于C++语言中的类属参数声明,在实体内部可以将声明的参数作为常数使用。参数声明必须放在端口声明之前,声明的参数必须在generic();语句的括号内。参数声明包含三部分,参数名称、参数类型和参数默认值,其中参数的默认值是可选的。参数声明时,多个参数之间用分号“;”隔开。参数声明的结构如下:

包含参数声明的实体声明结构如图3.7所示。图3.7带参数的实体描述结构例如图3.8的实例中,SETVALUE和COUNTOUT的端口位矢量长度可以设置为参数。图3.8带参数的实体声明实例3.3.2构造体

通过实体声明可以了解模块的外部特征,但无法得知模块内部的功能实现。通常用构造体对实体的内部实现做更加详细的描述。构造体是一个从属单元,不能独立存在于模块中,必须与实体声明联合使用。而一个实体声明可以有多个构造体。

构造体描述了模块的内部功能、行为或结构实现。

在VHDL中构造体描述的结构如图3.9所示。图3.9构造体描述结构

1.实体名称

构造体中的实体名称必须与实体声明中的实体名称一致。

2.构造体名称

构造体名称是构造体的标识,在命名时通常与构造体的描述方式相关。构造体在描述模块的内部实现时通常有三种方式,行为描述、数据流描述和结构描述,不同的描述方式只在于其风格不同,而功能实现是统一的。在比较复杂的构造体描述中,通常不止用一种描述方式,而会灵活地搭配三种方式进行描述。

1)行为描述

行为描述是抽象层最高的描述。主要使用电路的行为特性来描述设计,通过EDA工具的综合和优化,实现实体的功能。采用这种描述方法设计的电路非常易于维护。在VHDL中通常用process的方式进行行为描述。

例如,2.2节实验1中的模块AND_OR,采用行为描述方式的代码如图3.10所示。图3.10AND_OR的行为描述代码

2)数据流描述

数据流的描述方式主要使用VHDL语言中的标准布尔函数,将信号之间的布尔代数关系用布尔方程式来表示。采用数据流描述方式的AND_OR模块代码如图3.11所示。图3.11AND_OR的数据流描述代码

3)结构描述

结构描述主要通过下层模块的声明和调用及端口映射将下层模块相连,构成电路的结构性描述。AND_OR模块的结构描述代码如图3.12所示。图3.12AND_OR的结构描述代码

3.声明语句

声明语句在构造体的关键字“begin”之前,可用于声明下列描述语句:

● “use”语句;

● 子程序(subprogram)声明;

● 子程序体(subprogrambody);

● 类型(type)声明;

● 子类型(subtype)声明;

● 常量(constant)声明;

● 信号(signal)声明;

● 元件(component)声明;

● 并发(concurrent)语句。最典型的声明语句如AND_OR的三种描述中都用到的SIG1和SIG2信号的声明。在这里只将全部的声明语句提出,后续的章节中将详细介绍每一种声明语句。

4.并发语句

构造体中的每一个并发语句都定义了一个运算单元,这个单元包括三个部分:

●读取信号值;

●用读取的信号值进行运算;

●将运算的结果赋值给另外一个信号。构造体中的所有并发语句都是同时进行运算的,与语句的书写顺序没有任何关系。并发语句有五种类型:

●块(block)语句;

●元件(component)例化;

●过程(procedure)调用;

●进程(process);

●信号(signal)赋值。

我们可以在AND_OR的结构体描述实例中找到用到的并发语句,这里也只将全部的并发语句提出,在后续的章节中将详细介绍这些并发语句。3.3.3配置

上述构造体内容中提到,一个实体声明可以有多个构造体,但这个实体被上层模块调用,并在最终形成电路时,只能使用一种结构体作为实体功能实现的描述。这时就需要使用配置结构将实体与对应的结构体连接起来。配置不是所有VHDL代码必备的一部分,它不是从属单元,可以独立存在。通常在使用时都会将配置单独写入一个文件中。

注意:虽然使用配置可以使VHDL代码更加灵活,但目前很多综合工具都不支持配置。

配置用于描述设计的层次之间的互联关系,以及实体与结构体之间的连接关系。

在VHDL中配置描述的结构如图3.13所示。图3.13配置描述结构配置描述以“configuration配置名称of实体名称is”开始,以“end配置名称”结束,“configuration”是构造体声明的关键字。

1.实体名称

配置中的实体名称必须与实体声明中的实体名称一致。

2.配置名称

配置名称是配置的标识。一个实体的配置可以在这个实体被上层模块调用时,作为上层模块中的配置语句使用。

3.配置语句

根据使用情况不同,配置语句有简有繁。最简单的配置语句的结构如下:库包含3.3.4包集合

VHDL工程设计包含很多元素,不仅包含之前所涉及的实体、结构体以及配置,还包含一些常量定义、数据类型定义、子类型定义、子程序和函数等元素,这些元素会在源文件设计中反复用到。

类似于C语言中,我们经常将用户定义的类型、常量、函数声明等单独写入一个头文件中,然后在C源文件中用include语句包含进来一样。VHDL语言中,也将这些内容组织在一起,但不形成文件,而形成包集合。

包集合用于存储在工程设计中需要反复用到的常量定义、数据类型定义、子类型定义、子程序和函数声明等。在上述的代码中,都会以“libraryIEEE”和“use……”开头,其中“use……”部分代码的含义就是对用到的包集合进行声明。

包集合由包集合声明和包集合体两部分构成,包集合的描述结构如图3.14所示。图3.14包集合描述结构

1.包集合名称

包集合名称是包集合的标识,在使用包集合时,可以作为参数使用。

2.包集合声明语句

包集合声明语句中包含了工程设计中常用的信息,这些信息包括数据类型声明、信号声明、子程序声明和元件声明。在声明语句中,对子程序和元件只做声明,具体的实现在包集合体描述语句中进行描述。包集合声明语句中声明的这些定义对外界是可见的。

注意,包集合中声明的信号在不同的实体中是不能共享的,如果多个实体都使用了包集合中的同一个信号,则每个实体内都会有一个独立的该信号的复制信号。

3.包集合体描述语句

包集合体描述语句包含了子函数(Function)和过程(Prodecure)等的具体实现,这些子函数或过程是在包集合声明语句中已经声明的。

一个简单的包集合实例如下:3.3.5库

所有的VHDL设计元素经过编译后最终都会包含在库中,库和包集合构成了VHDL工程数据的管理结构,这个管理结构类似于操作系统中文件夹和子文件夹的结构,如图3.15所示。图3.15库和包集合构成的管理结构库中包含了编译后的数据的集合,这些数据包括实体定义、构造体定义、配置定义和包集合定义。

我们在之前的示例代码中经常以“libraryIEEE;”开头,这个语句的含义就是将IEEE库包含到设计文件中。库的描述结构为:

library库名称;

将库文件包含到设计文件中后,设计单元内的语句就可以使用库中的数据,这一点和C语言中库的概念是一致的。

VHDL设计中可以存在多个不同的库,这些库大致可以归为5类:IEEE库、STD库、ASIC库、WORK库和用户自定义库。● IEEE库:包含了“STD_LOGIC_1164”、“STD_LOGIC_ARITH”和“STD_LOGIC_UNSIGNED”等包集合,这些包集合定义了一些工程设计中常用的数据类型等的定义。

● STD库:VHDL的标准库,库中有标准的“STANDARD”包集合。

● ASIC库:各公司为了使用VHDL语言进行门级仿真而提供的ASIC逻辑门库。

● WORK库:类似于项目管理文件夹,项目中设计的所有单元都存放于这个库中。

●  用户自定义库:用户自行开发的库,用于包含多个实体中共用的包集合和实体等。

VHDL语言中,库与库之间是相互独立的,不能互相嵌套。其中WORK库和STD库是工程设计中的每个设计单元都要用到的库,因此设计过程中可以不用标准格式说明。

通常在工程设计中库和包集合是联合使用的,如在之前的VHDL代码实例中经常用到的开头:

libraryIEEE;

useIEEE.STD_LOGIC_1164.all;

这个开头中“libraryIEEE”声明将IEEE库包含进来,“useIEEE.STD_LOGIC_1164.all”表示使用IEEE库中STD_LOGIC_1164包集合的所有(all)定义。另外一个简单的实例如图3.16所示。图3.16library和package使用实例

3.4VHDL语言的对象和数据类型

3.4.1VHDL语言的对象类型

在VHDL语言中,可以被赋值的都称为对象(Object)。对象有很多种,常用的有端口(Port)、常量(Constant)、信号(Signal)、变量(Variable)。

这里,首先给出一个简单的例子,读者可以对照例子中的代码理解这些对象。

1.端口(Port)

端口定义了实体的信号传递接口,在3.3.1节介绍实体的定义时,已经对端口做了介绍。在端口的定义中,数据类型是必不可少的一部分。

常用的端口类型有输入(Input)、输出(Output)、双向(Inout)和缓冲输出(Buffer)四种,其中Input、Inout和Buffer端口可以对其他对象赋值,Output、Inout和Buffer可以被其他对象赋值。

2.常量(Constant)

常量是一个固定的值。常量在被创建时就被赋值为一个固定的值,并且常量的值在使用过程中只能对其他对象赋值,不能被修改。常量使代码更容易阅读和维护。常量可以在结构体、包集合、实体、块语句、过程语句和子函数中声明,在结构体中声明的常量是本地常量,只能在结构体内部使用。

常量声明的结构为:

constant常量名称:数据类型:=常量表达式

例如:

constantCPU_ADDR_MSB:integer:=32;

constantMASK:std_logic_vector:="00001111"

3.变量(Variable)

变量是用于存储信息的一种对象。变量在被创建时也可以赋初始值,但与常量相反,变量在使用过程中既可以对其他对象赋值,也可以被修改。

变量是一个局部量,不能在结构体中声明,而只能在进程语句(Process)、函数语句(Function)和过程语句(Procedure)中声明。

变量声明的结构为:

variable变量名称:数据类型[:=初始值表达式]

例如:

variableCOUNT:INTEGER;

variableV:STD_LOGIC_VECTOR(3downto0):="0101";

variableW:INTEGER

range0to7:=7;在VHDL中,变量在综合后可以是一个连线(Wire),也可以是一个寄存器(register),综合的结果取决于变量在时序电路中是否用于保存信号值。这一灵活性也使得变量在使用过程中经常引发错误,例如功能仿真的结果与综合后的结果不一致的情况,所以在使用变量时要格外小心。

变量用“:=”符号进行赋值操作,例如:

V:="0111";

W:=5;

COUNT:=W+16;

另外,虽然变量可以赋初始值,但是在综合时,综合器会将初始值忽略掉,因此在使用过程中也要特别注意。

4.信号(Signal)

信号是电路底层硬件单元连接的抽象。在VHDL中,信号可以用于在结构体中的不同并发语句之间传递信息,也可以通过端口与其他实体传递信息。从某种意义上讲,端口也是信号的一种,但是被限定了输入/输出特性,因此也可以通过创建端口来创建一个信号,而端口的赋值方式也与信号相同。

信号可以在实体(Entity)、结构体(Architecture)和块语句(Block)中声明,不能在进程(Process)语句、函数语句(Function)和过程语句(Procedure)中声明,但可以在进程(Process)、函数(Function)和过程(Procedure)中使用。信号的声明结构与变量类似:

signal信号名称:数据类型[:=初始值表达式];

例如:

signalA,B:BIT;

signalLBUS:INTEGER: =

8;

与变量相同,信号在声明结构中被赋予的初始值,在综合时也会被忽略。

信号采用“<=”符号进行赋值操作,例如:

A<='0';

LBUS<=16;由于信号本身是底层硬件单元连接的抽象,因此,类似于信号在连线上有传输时延,信号在数值传递的过程中也可以加入延时,例如两个信号A和B,B的值经过5ns的延时后传递到A,赋值语句可以写为:

A<=Bafter5ns;

但必须明白,像“after5ns”这样的语句,在底层电路是根本无法实现的,因此,延时语句只在行为建模时起作用,而在综合时也会被完全忽略。

从变量和信号的声明和定义看,很容易将这两种对象混淆,但实际上,这两种对象有明显的区别,这些区别在以后的工程实践中可以慢慢体会。

1)声明和使用位置不同

变量只能在进程语句(Process)、函数语句(Function)和过程语句(Procedure)内声明,也只能在这些语句内部使用,因此是一个局部对象。

信号可以在实体(Entity)、结构体(Architecture)和块语句(Block)中声明,在进程(Process)、函数(Function)和过程(Procedure)中使用,因此可以在不同的进程之间传递信息,是一个全局对象。

2)赋值符号和延迟不同

变量用“:=”赋值,信号用“<=”赋值。

变量被赋值时,可以被看做是赋值符号右侧表达式的代名词,在使用变量时,可以直接用其所代的表达式替代。如果赋值的过程被分为获取数据值、数值计算、用计算的结

果进行赋值三个步骤,那么变量在赋值的过程中,第三步“用计算的结果进行赋值”这个操作是即时的,没有延时。而信号是物理单元的抽象,因此第三个步骤的操作是有时延的。3.4.2VHDL语言的数据类型

VHDL对类型的要求很严格,如上所述,所有的端口、常量、变量和信号在声明时都要显式地定义其对应的数据类型。不同类型之间的数据不能直接赋值,数据类型相同,而位长不同时也不能直接代入。因此,熟练掌握各种数据类型对于用VHDL语言编程至关重要。

VHDL中定义了很多种数据类型,这些数据类型大致可以分为五种:

●标量类型(ScalarType)

●复合类型(CompositeType)

●存取类型(AccessType)

●文件类型(FilesType)

●用户定义的子类型(SubTypes)

1.标量类型

标量类型是VHDL中最基本的类型,用于描述一个单值数据对象。属于标量类型的数据类型有以下几种:

●位型(BIT)

●布尔型(BOOLEAN)

●整型(INTEGER)

●实型(REAL)

●物理型

●符号型(CHARACTER)

●标准逻辑类型(STD_LOGIC)

●枚举类型(ENUMERATE)

●错误等级(SEVERITY_LEVEL)

1)位(BIT)

BIT型是数字逻辑中最基本的逻辑形式,BIT型在STD库中有明确定义,其定义如下:

typeBITis('0','1');

从上面的定义可以看出,BIT类型的数据只能取'0'和'1'两个值,是二值系统中的最基本单元,分别表示低电平和高电平。

一个位型数据的实例如下:

signalX,Y,Z:BIT;

X<='0';

Y<='1';

Z<=XandY;

2)布尔(BOOLEAN)

BOOLEAN型相对于BIT型抽象层次更高,BOOLEAN型的定义如下:

typeBOOLEANis(FALSE,TRUE);

从定义上看,BOOLEAN类型类似于BIT类型,一个BOOLEAN量也具有两种状态,FALSE或者TRUE。但它和位型不同,它没有数值的含义,也不能进行算术运算,只能作为关系运算的结果,在判断语句中判断使用,例如:

ifSEL='1'…

ifF>=G…

这些语句都将产生BOOLEAN型的结果。一个BOOLEAN型数据的实例如下:

signalCOND:BOOLEAN;

ifCONDthen

3)整型(INTEGER)

VHDL中的INTEGER数据与C语言中的整型数据定义相同。VHDL中INTEGER数据的表示范围为-(231-1)~231-1,即-2147483647~2147483647。INTEGER型的定义如下:

typeINTEGERisrange-2147483647to2147483647虽然INTEGER类型的数据在底层电路中也是用一系列二进制位表示的,但是在使用INTEGER类型时,不能直接对数据的比特位进行操作,而必须使用转换函数将INTEGER数据转换为位矢量类型。不过,目前一些公司的综合器已经不受这个约束的限制。

一个INTEGER类型数据的实例如下:

signalINT_S:INTEGER;

signalA:INTEGERrange0to7;

signalB:INTEGERrange15downto0;

A<=5;

B<=12;通常INTEGER类型的数据在定义时,都要用“range”语句给出数据的取值范围,数据在后续使用过程中不能超出此范围。“range”定义的范围必须在-2147483647~2147483647范围内。

4)实型(REAL)

VHDL语言中,实型REAL也叫浮点型Floating,REAL数据是通常的数值运算中浮点型的抽象,它的数值范围为-1038~1038。在VHDL中没有定义REAL数据的精度,但这个精度至少可以达到6个比特位。使用REAL类型数据时要注意,很多公司的综合工具都不支持REAL类型的数据。在VHDL中,通常采用用户自定义的方式来定义一个REAL类型的数据,例如:

typeCAPACITYisrange-25.0to25.0;

signalSIG_1:CAPACITY:=3.0;

SIG_1<=5.6;

其中,CAPACITY是用户自定义的一种REAL型的数据类型。

5)物理型

物理型数据用于表示一些物理量,如重量、长度、时间或电压值等等,用户可以根据工程需要定义一些物理数据类型。完整的物理型数据包含数值和单位两部分,在定义一个物理型数据类型时,必须先给出一个基准单位,其他的单位也必须是基准单位的倍数。VHDL中只定义了一种物理类型TIME。TIME类型用于对延时等时间参数建模,VHDL中TIME类型的定义如下:

VHDL-93除了上述的字符外,还预定义了一些其他字符,共支持256个字符,这些字符中不能打印的字符用标识符给出。

7)标准逻辑类型(STD_LOGIC)

在IEEE标准库的STD_LOGIC_1164包集合中,定义了STD_LOGIC数据类型,与BIT类型相似,STD_LOGIC也是表示单个数字信号逻辑的。STD_LOGIC类型的定义如下:上述的定义中,首先定义了STD_ULOGIC类型,STD_LOGIC类型是经过RESOLVED函数处理过的STD_ULOGIC类型,但STD_LOGIC和STD_ULOGIC可以取值的数值集合是相同的,这里我们不对这两种类型做详细介绍,可以简单地认为两种类型是一致的。

从类型的定义可以看出,STD_LOGIC表现的状态就是实际的数字电路在输入/输出时所呈现的状态,它比BIT型所描述的逻辑状态更完整。不过,定义中的Don’tcare表示不重要的逻辑,是什么状态都无所谓,这在真实逻辑中是不存在的。

8)枚举类型(ENUMERATE)

在VHDL中,也支持类似于其他编程语言中常用的枚举类型。使用枚举类型可以使工程师在更高的抽象层次上进行建模,也可以使程序代码简便易懂,这一点在状态机和复杂系统的描述中尤其有用。

枚举类型的描述结构为:

type类型名称is(元素,元素,…);

事实上,在上述其他数据类型的介绍中已经多次使用的枚举类型,BIT型、BOOL型、CHARACTER型和STD_LOGIC型都是用这种结构定义的。

9)错误等级(SEVERITY_LEVEL)

错误等级用于表征系统的运行状态,有四种状态可用:NOTE(注意)、WARNING(警告)、ERROR(错误)和FAILURE(失败)。

错误等级的描述结构为:

type

SEVERITY_LEVEL

is(NOTE,WARNING,ERROR,FAILURE);

错误等级也是在标准库中用枚举类型的方式预定义的,在系统仿真过程中可以用这四种状态来提示系统当前的运行状态。

SEVERITY_LEVEL通常与ASSERT语句配合使用,读者可以参照图3.33的实例了解SEVERITY_LEVEL类型数据的使用方法。

2.复合类型

复合型的数据是指由多个单值数据组合而成的数据,复合型数据以向量、数组或记录的形式存在。属于复合类型的数据有以下几种:

●位矢量型(BIT_VECTOR)

●标准逻辑矢量型(STG_LOGIC_VECTOR)

●字符串型(STRING)

●数组型(ARRAY)

●记录型(RECORD)

1)位矢量型(BIT_VECTOR)

位矢量型是由多个位型数据组合起来的一组位数据,在VHDL的标准STD包集合中,BIT_VECTOR的定义如下:

typeBIT_VECTORisARRAY(NATURALrange<>)ofBIT;

这里我们不需要关心NATURALrange<>的含义。

位矢量在定义和使用时,用双引号括起来,例如:

signalA_WORD:bit_vector(7downto0):="01011100";

A_WORD<=X "AC";其中,X"A"的前缀X表示后面的数是十六进制数,"A"表示十六进制数的值。BIT_VECTOR可以用"_"符号来分隔数值位,例如上面例子中,A也可以这样赋值:

A_WORD<="0101_1100";

这种赋值方法与上例中的赋值方法得到的效果是相同的。

2)标准逻辑矢量型(STD_LOGIC_VECTOR)

标准逻辑矢量型是由多个标准逻辑数据组合起来的,在STD_LOGIC_1164包集合中,STD_LOGIC_VECTOR的定义如下:

type

STD_LOGIC_VECTOR

is

ARRAY(NATURAL

range<>)of

STD_LOGIC;

STD_LOGIC_VECTOR的定义和使用方式与BIT_VECTOR的方式相同,也要用双引号括起来,例如:

signalB_DATA:STD_LOGIC_VECTOR(3downto0):="0011";

B_DATA<="1100";

3)字符串型(STRING)

字符串类型是由多个字符类型的数据组合起来的,在VHDL的标准STD包集合中,STRING的定义如下:

type

STRING

is

ARRAY (POSITIVE

range<>)ofCHARACTER;

字符串型数据在定义和使用时也要用双引号括起来,例如:

variableMY_STRING:STRING (1to11);

MY_STRING:="Test_string"

字符串类型常用于程序的提示或说明,使用字符串时要注意,字符串类型的数据对大小写是敏感的,“xxxx”和“XXXX”是不同的。

4)数组型(ARRAY)

数组型是由多个相同类型的数据组成的集合,组成集合的数据类型可以是任意的。VHDL支持多维数组,但有一些综合器只支持一维数组。数组中的数据可以通过索引值获取,索引值是INTEGER类型的,它的范围取决于数组中元素的个数和顺序。图3.17数组赋值示意图数组也可以采用一种便捷的方式进行赋值,即联合赋值。联合赋值不仅在数组中可以使用,多个标量对象在赋值时也可以采用这种方式。下面举一个简单的例子说明这种赋值方式:

signalH_BYTE,L_BYTE:STD_LOGIC_VECTOR(0to7);

signalQ_OUT:STD_LOGIC_VECTOR(31downto0);

signalA,B,C,D:STD_LOGIC;

signalWORD:STD_LOGIC_VECTOR(3downto0);

(A,B,C,D)<=WORD;

WORD<=(2=>'1',3=>D,others=>'0');

Q_OUT<=(others=>'0');

WORD<=(A,B,C,D);

H_BYTE<=(7|6|0|1=>'1',2to5=>'0');

使用联合赋值时,出现在赋值符号左侧的联合体只能由标量类型组成,如上述例子中对A,B,C,D联合赋值的情况,赋值符号两侧的元素个数必须相等,上例中“others”表示对所有未赋值的位赋予给定的默认值。

在工程应用中,大型的数组(即索引值范围比较大的数组)一般用变量或常量定义,用信号定义时,会影响仿真速度。图3.18TX_PACKET的组成结构

3.文件类型(File)

VHDL中的文件类型是由某种类型的数据组成的数据流,可以在仿真中读入和写出,类似于C语言中的文件类型。目前常用的文件类型只有TEXT类型,IEEE的TEXTIO包集合中包含了TEXT文件常用的一些读写函数,方便设计者在开发时调用。

VHDL-87和VHDL-93中文件的描述结构不同,例如:

4.用户定义的子类型

除了上述VHDL中预定义的标准类型外,用户可以根据工程设计的需要,修改已定义数据类型的范围限定,形成新的数据类型,这种类型称为子类型(subtype)。子类型的定义结构如下:

subtype子类型名称is已定义类型名称;

例如:

subtypeMY_INTisintegerrange0to255;

subtypeSMALL_INTisMY_INTrange5to30;

再如:

typeMY_STATEis(

LOAD,JUMP,ADD,SUB,DIV,MULT,STORA,STORB);3.4.3不同数据类型之间的转换

以上给出了多种VHDL中常用的数据类型,用这些数据类型定义的对象在赋值时都必须遵守数据赋值的规范,不同类型之间的数据不能赋值,相同类型不同位长的数据之间也不能相互赋值。但这样会很不方便,因此IEEE的一些包集合中给出了一些数据类型之间的转换函数,不同类型之间的数据可以先经过转换函数转换为相同类型,然后进行赋值。

表3.2给出了一些常用的转换函数名称及其功能。表3.2VHDL中常用转换函数下面举几个简单的例子:

signalA:STD_LOGIC_VECTOR(7downto0);

signalB:INTEGERrange0to200;

signalMY_ADDRESS:STD_LOGIC_VECTOR(31downto0);

A<=CONV_STD_LOGIC_VECTOR(B,8);

B<=CONV_INTEGER(A)

MY_ADDRESS<=CONV_STD_LOGIC_VECTOR(X"000027AC");

注意:在使用这些函数的时候,一定要在文件开始将IEEE库和函数所在的包集合包含进来。 3.5VHDL语言运算操作符

VHDL中有5种运算操作符,分别为逻辑运算符(Logical)、关系运算符(Relational)、算术运算符(Arithmetic)、移位运算符(Shift)和并置运算符(Concatenation),其中移位运算符是VHDL-93中新加的运算符。在运算过程中将操作符作用于操作数,完成计算。操作符标识需要进行的计算,操作数标识用于计算的数据。使用操作符的过程中要注意,所有的操作符都是对应于确定的数据类型的,例如,VHDL内嵌的算术操作符就不能对BIT_VECTOR和STD_LOGIC_VECTOR类型的数据进行运算。IEEE的STD_LOGIC_ARITH包集合对这类情况进行了扩展,加入了相应的子程序,供设计者调用。因此,在程序中如果要对两个BIT_VECTOR或STD_LOGIC_VECTOR的数据进行算术运算,就需要将STD_LOGIC_ARITH包集合包含进来。

表3.3中列出了VHDL中支持的运算操作符,与C语言类似,运算操作符也有优先级。表3.3操作符及优先级

1.逻辑运算符

VHDL中共有7种逻辑运算符,其中xnor是在VHDL-93中新定义的,见表3.4。表3.4逻 辑 运 算 符逻辑运算符可对BOOLEAN、BIT、BIT_VECTOR、STD_LOGIC和STD_LOGIC_VECTOR的数据对象做运算。其中,not是单目运算符,其他为双目运算符。在计算时,运算符两侧的数据类型必须相同。

用逻辑运算符运算的实例如下:

signalA,B,C:BIT_VECTOR(3downto0);

signalD,E,F,G:STD_LOGIC_VECTOR(1downto0);

signalH,I,J,K:BIT;

signalL,M,N,O,P,Q:BOOLEAN;

A<=BandC;

D<=EorForG;

H<=(InandJ)nandK;

L<=(MxorN)and(OxorP);通常,在一个表达式中使用多个不同的操作符时,要用括号标明操作符的优先级。而如果多个操作符相同,则可以不用括号标明。上例中给出了对应的实例。

2.关系运算符

VHDL中有6种关系运算符,所有的关系运算符都返回BOOLEAN类型的结果,见表3.5。表3.5关 系 运 算 符关系运算符中,“=”和“/=”可以对所有类型的数据运算,而其他的操作符只能对枚举类型、整数类型、枚举类型的一维数组或整数等类型的数据做运算。在运算时,符号两边的数据类型必须相同,但数据的位数不一定相同。位数不同的两个数据作比较时需要注意,VHDL中的数组类型(包括BIT_VECTOR和STD_LOGIC_VECTOR)的比较是按照类似于字母排序的方式进行的,排序时从数组最左边的元素开始对比,直至发现第一个不同的元素,排在前面的数小于排在后面的数,举一个简单的例子,如“101011”和“1011”的比较,两个数的前3位都相同,因为“1011”的第四位为“1”而“101011”的第四位为“0”,因此“1011”>“101011”成立,如图3.19所示。图3.19不同位长数据的比较另外一种情况,如果短数组刚好是长数组的前面一部分,那么短数组在排序时排在长数组的前面,也就是短数组的值小于长数组的值,例如“101”就小于“101000”。

3.移位运算符

VHDL-93中新定义了6种移位运算符,运算符的含义及示意图如表3.5所示。表3.5移 位 运 算 符算术向左移位时,填入的位值为最后一个位值;算术向右移位时,填入的位值为第一个位值;逻辑向左和逻辑向右移位时,默认新填入的位值都为0;向左旋转时,填入的位值为第一个位值;向右旋转时,填入的位值为最后一个位值。

举一个简单的例子,如果A = "10010101",则

Asll2

为 "01010100"

Asrl3

为 "00010010"

Asla3

为 "10101111"

Asra2为 "11100101"

Arol3

为 "10101100"

Aror5为 "10101100"移位运算符在使用时要注意,虽然运算符在VHDL-93中已经定义,但在IEEE的包集合中,只定义了SIGNED和UNSIGNED类型的移位运算操作符,对于其他数据类型,目前还没有定义。如果在综合器或仿真器中要对其他类型的数据使用移位操作符,可以尝试换一种写法描述移位,例如:

Asll2

描述为A<=A(5downto0)&"00";

Asrl3描述为A<=“000”&A(7downto3);

Asla3描述为A<=A(4downto0)&A(0)&A(0)A(0);

Asra2描述为A<=A(7)&A(7)&A(7downto2);

Arol3描述为A<=A(4downto0)&A(7downto5);

Aror5描述为A<=A(4downto0)&A(7downto5);

4.算术运算符

VHDL中有10种算术运算符,如表3.6。表3.6算 术 运 算 符算术运算符中正“+”和负“-”是单目运算符,操作数可以为整数、实数和物理量等类型。

加法和减法操作符两边必须是相同类型的数据,操作数也可以为整数、实数和物理量。乘除法的操作数可以同为整数或实数,物理量可以被整数或实数相乘或相除,结果仍为一个物理量。物理量除以同一类型的物理量结果为一个整数量。求模和取余的操作数必须都为整数类型。指数运算符的左侧操作数可以是任意整数或实数,右侧操作数应为整数。我们之前提到过,VHDL并没有预定义STD_LOGIC_VECTOR和BIT_VECTOR类型的加减法运算操作符,而IEEE在STD_LOGIC_ARITH包集合中对数组的加减法运算等操作符做了重载。因此,要在代码中对这些数组类型的数据做加减运算,必须声明使用STD_LOGIC_ARITH包集合。而且在使用时,运算符两端的数组位长必须相等。

算术运算符中真正能够综合的运算符只有“+”、“-”和“*”,对于“/”、“mod”、“rem”,在分母为2的乘方次常数时,可以将这些操作用位运算实现,因此是可以综合的。

5.并置运算符

并置运算符“&”用于标量和复合类型数据的并置连接,使用并置运算符可以很灵活地将标量或数组组织在一起,形成更大的数组。例如:

signalA_VEC,B_VEC:STD_LOGIC_VECTOR(7downto0);

signalZ_VEC:STD_LOGIC_VECTOR(15downto0);

signalA_BIT,B_BIT,C_BIT,D_BIT:STD_LOGIC;

signalX_VEC:STD_LOGIC_VECTOR(2downto0);

signalY_VEC:STD_LOGIC_VECTOR(8downto0);

Z_VEC<=A_VEC&B_VEC;

--A_VEC作为Z_VEC的高8位,B_VEC作为Z_VEC的低8位

X_VEC<=A_BIT&B_BIT&C_BIT;

--X_VEC从高到低的3个位的值分别用A_BIT、B_BIT和C_BIT赋值

Y_VEC<=B_VEC&D_BIT;

--B_VEC作为Y_VEC的高8位,D_BIT作为Y_VEC的最低位

在前面数组类型的介绍中曾提及,数组的赋值可以采用联合赋值的方式,这种方式其实也可以认为是并置运算的另一种形式。 3.6VHDL语言的描述语句

为了能够对硬件的行为做高效地建模,VHDL采用两类描述语句,一类称为并发描述语句(Concurrent),另一类称为顺序描述语句(Sequential)。

并发描述语句具有共时性,一个模块的结构体描述中,所有的并发语句都是同时进行的,与语句在程序中的位置无关。而顺序语句具有顺序性,它是按照语句在程序中的前后位置顺序执行的。下面举一个简单的例子说明结构体描述中的并发描述语句与顺序描述语句,如图3.20所示。图3.20并发语句与顺序语句3.6.1有关规则和基本语句

1.VHDL命名规则

VHDL中使用的名称,在命名时都需要符合VHDL的标识符命名规范,如实体名称、端口名称、结构体名称、变量名称和信号名称。

VHDL-87的短标识符命名规范为:

●标识符可以由英文字母、数字及下划线组成;

●标识符必须以英文字母开头;

●标识符不允许连续出现两个下划线;

●标识符最后一个字符不能是下划线;

●标识符中英文字母不区分大小写;

● VHDL中的保留关键字不能作为标识符来使用。

VHDL的标识符中,英文字母不区分大小写,例如CURRENT_STATE、current_state和CURRENT_state等是相同的,表示同一个对象。但VHDL中的常量字符不属于标识符,因此大小写是不同的。例如对STD_LOGIC类型或STD_LOGIC_VECTOR类型的信号代入高阻值“Z”时需要注意:

signalSIG_A:STD_LOGIC;

signalSIG_B:STD_LOGIC_VECTOR(2downto0);

SIG_A<='Z'; --正确

SIG_A<='z'; --错误,小写z没有定义;

SIG_B<="ZZZ"; --正确

SIG_B<="zzz"; --错误,小写z没有定义;

2.注释标记方法

VHDL的注释标记符为“--”,注释的内容为从“--”符号开始,一直到当前行的结束。在之前的示例代码中,我们已经多次使用这一符号进行注释,这里不再举例说明。

需要注意,“--”对于VHDL程序是注释符号,但一些其他工具经常使用这个符号作为参数传递的接口。如我们经常看到的“--synopsystranslate_on”和“--synopsystranslate_off”等。

3.信号代入语句

信号代入的语法结构为:

目标信号名称<=信号量表达式;信号的代入不是即时的。也就是说,即使信号量表达式发生了变化,最终赋予目标信号的值也不一定就是信号量的值。分为三种情况:

(1)如果信号只在一个进程中被赋值,而且在顺序执行一次Process中的语句时,只被赋值一次,那么信号的值就是被执行语句中信号量表达式计算的结果值。

(2)如果信号只在一个进程中被赋值,但在进程内部被多次赋值,那么只有最后一条赋值语句是起作用的。即使这个信号在进程中先被赋值,又被读出,然后又被赋值,那么被读出的信号的值仍是最后一次的赋值结果。

(3)如果信号在多个进程中被赋值,这些驱动器的结果将会被连接在一起,而形成多驱动的情况。有一些综合器在遇到这种情况时将会报错。信号在这种情况下的赋值情况与底层电路的实现方法有关。VHDL中给出了一种判决函数,用于解决这种问题。我们将在并发描述语句的内容中介绍这种判决函数。

所有在“ifCLK'eventandCLK='1'then…”或“ifrising_edge(CLK)then…”后描述的信号代入语句,在综合后都会生成一个寄存器。上面例子综合后的结果如图3.21所示。图3.21时序电路中信号代入的综合结果前面讲过,实体的端口在结构体描述时被默认为信号,只是对信号的输入/输出属性做了限定。这里举一个例子,说明信号的赋值方法与最终综合的电路之间的关系。

假设要实现的电路图如图3.22所示。图3.22综合后的目标电路通过分析可以得知,方法B的代码与图3.22中的电路是对应的,方法A的实现明显是错误的,Q为输出端口,不能用“Q<=Q+1”对Q进行赋值。

那么方法C和方法D得到的综合电路应该是什么样的?读者可以对照图3.23所示的电路图对代码进行分析。图3.23综合电路(a)方法C;(b)方法D

4.wait语句

wait语句是等待语句, 在进程(Process)的顺序描述语句中用于控制进程状态的变化。wait语句设定一定的条件,当进程执行到wait语句时,进程就挂起,直到设定的条件满足时再继续执行。

wait语句可以设定4种不同的条件,分别为:

● waiton:等待敏感信号变化;

● waituntil:等待条件满足;

● waitfor:等待限定的时间;

● wait:无限等待。

1) waiton

waiton语句的语法结构为:

waiton敏感信号[,敏感信号];

当进程(Process)中的顺序描述语句执行到waiton语句时将会挂起,直到敏感信号中的任一信号发生变化,进程将结束挂起,继续执行waiton后的语句。

2) waituntil

waituntil语句的语法结构为:

waituntil条件表达式;

语法结构中,条件表达式的结果为布尔量,表达式满足条件时,返回“true”;不满足时,返回“false”。进程在运行到waituntil语句时将会挂起,当表达式中任何一个信号发生变化时,表达式的结果会被重新计算。如果计算结果为“true”,则继续执行后续语句;如果计算结果为“false”,则保持挂起状态。

3) waitfor

waitfor语句表示等待固定的时间,它的语法结构为:

waitfor时间表达式;

时间表达式的含义是,表达式的运算结果为一个时间值。如果时间表达式是一个常量,则waitfor语句将等待固定的时间;如果时间表达式是一个计算式,那么计算的结果应该是一个时间值。进程执行到wait for语句时将挂起,等待时间表达式所指示的时间长度,然后继续执行后续语句。

4) wait

单独地使用wait语句表示无限等待。最后依据wait表示进程将一直等待下去。

实际使用wait语句时,可以将上述的wait语句混合使用,混合使用的语法结构为:

wait[on敏感信号列表][until条件表达式][for时间表达式];

当on语句的敏感信号列表中的任一信号发生变化时,until语句的条件表达式将被重新计算。如果结果为“true”,则进程继续执行wait后的语句;如果结果为“false”,则进程保持挂起。

for语句相对比较独立,只要wait语句已经等待了时间表达式所指示的时间,则进程结束挂起,继续执行wait后的语句。在使用wait语句进行建模时需要注意,waiton、waitfor和wait语句是不可综合的。waituntil语句只有在条件表达式为时钟的边缘时,如waituntilCLOCK='1'时,是可综合的,否则也是不可综合的。可综合的语句在行为层次建模和RTL建模时都可以使用,不可综合的语句只有在行为层次建模时可以使用。但是有一些综合器,例如ISE中的XST,不支持对所有wait语句的综合。

5.变量赋值语句

变量赋值语句用于改变一个变量的值,其语法结构为:

变量名称:=表达式;

变量赋值符号两侧的数据类型必须相同,赋值符号右侧的表达式可以是常量、变量或信号。例如:根据变量在程序中使用情况的不同,变量综合后的结果可能是连线(Wire)、锁存器(Latch)或寄存器(Register)。在时序电路的顺序描述语句中,如果变量在被赋值之前被读取,那么综合后将会产生一个寄存器;如果这种情况发生在组合逻辑电路中,那么综合后将会产生一个锁存器。

例如,下面的代码:图3.24变量综合后的电路图图3.25另一种变量综合后的电路图3.6.2并发描述语句

1.进程语句(Process)

进程表示一个处理过程,在一个结构体中可以包含多个进程。进程与进程之间是并行的,进程内部包含一组顺序描述语句,进程内部的语句是按先后次序顺序执行的。

我们在之前的例程中曾多次用到进程语句,它的语法结构如下:敏感变量列表中列出将会触发进程执行的所有信号,这些信号可以包含实体的接口信号,进程的敏感变量列表用括号括起来,如果进程有多个敏感信号;则信号之间用逗号隔开。如果process描述的是时序电路,则敏感列表中必须包含时钟信号,而如果process描述的是组合逻辑,则敏感变量列表中应包含全部的敏感信号,否则会引起行为仿真结果和综合后结果不同的现象。

process的敏感信号列表与wait语句中的敏感信号是等价的, process在执行之前也要等待敏感信号的变化,因此process中对敏感信号的等待成为隐式等待,而wait语句的等待称为显式等待。VHDL中规定,如果进程中使用了wait语句,则process后不允许使用敏感变量列表。进程的声明语句用于声明在process内部使用的函数、过程、类型定义、常量和变量。

顺序描述语句是对进程行为功能的描述,进程每被触发一次,进程内的顺序描述语句顺序执行一次。

这里再举一个简单的例子说明进程的用法:一个结构体的多个进程之间是通过信号来传递信息的,而且进程之间只能用信号传递信息,因此通过信号连接的多个进程通常也被称为VHDL的连接模型。

进程语句是可综合VHDL语句中最有用的一条,但是并不是每个进程语句都是可以综合的,为了使代码有较高的性能,通常process语句用以下限定的模板进行编写,设计者在工程设计中可以参考:

2.直接信号代入语句

直接信号代入语句即指信号代入语句。信号代入语句既可以在process语句中使用,作为顺序描述语句的构成部分,也可以在process外部使用,作为并发语句。例如:

3.条件式信号代入语句

条件式信号代入语句是if/else顺序描述语句的并发表示形式。条件式信号代入语句的语法结构为:●如果条件1满足,则给目标信号赋值为表达式1;

●如果条件1不满足,而条件2满足,则给目标信号赋值为表达式2;

●如果条件1、2都不满足,而条件3满足,则给目标信号赋值为表达式3;

●如果条件1、2、…、n都不满足,则给目标信号赋值

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论