11.3.1 VHDL中的描述语句
在VHDL中,将一个能够完成特定独立功能的设计称为设计实体(Design Entity)。一个基本的VHDL设计实体的结构模型如图11-21所示。一个有意义的设计实体中至少包含库(或程序包)、实体和结构体3个部分。
在描述电路功能的时候,仅有对象和运算操作符是不够的,还需要描述语句。结构体的描述语句可以分成并行描述语句(Concurrent Statement)和顺序描述语句(Sequential Statement)两种类型。
并行描述语句是指能够作为单独的语句直接出现在结构体中的描述语句,结构体中的所有语句都是并行执行的,与语句的前后次序无关。这是因为VHDL所描述的实际系统在工作时,许多操作都是并行执行的。顺序描述语句可以描述一些具有一定步骤或者按顺序执行的操作和行为。顺序描述语句的实现在硬件上依赖于具有次序性的结构,如状态机或者具有操作优先权的复杂组合逻辑。顺序描述语句只能出现在进程(Process)或者子程序(Sub Program)中。通常,过程(Procedure)和函数(Function)统称为子程序。

图11-21 VHDL设计实体的结构模型
1.并行描述语句
常用的并行描述语句包括进程(Process)语句、并行信号赋值(Concurrent Signal Assignment)语句、条件信号赋值(Conditional Signal Assignment)语句、选择信号赋值(Selected Signal Assignment)语句、过程调用(Procedure Call)语句、生成(Generate)语句、元件实例化(Component Instantiation)语句等。
1)进程语句。进程语句是最常用的并行语句,在一个结构体中,可以出现多个进程语句,各个进程语句并行执行。进程语句内部可以包含顺序描述语句。
进程语句的语法格式如下。

进程语句由多个部分构成。其中,“[]”内为可选部分;进程标号作为该进程的标识符号,以区别于其他进程;灵敏度参数列表(Sensitivity List)为信号列表,该列表内信号的变化将触发进程执行(所有触发进程变化的信号都应包含到该表中);变量声明项用来定义在该进程中需要用到的变量;顺序描述语句即一系列顺序执行的描述语句,具体语句将在下面的顺序描述语句中介绍。
为了启动进程,需要在进程结构中包含一个灵敏度参数列表,或者包含一个WAIT语句。要注意的是,灵敏度参数列表和WAIT语句是互斥的,只能出现一个。
2)简单信号赋值语句。简单信号赋值语句是最常用的简单并行语句,它确定了数字系统中不同信号间的逻辑关系。
简单信号赋值语句的语法格式如下。

其中,“<=”是信号赋值语句的标志符,它表示将表达式的值赋给目标信号。例如,下面这段程序采用简单信号赋值语句描述与非门电路。

3)条件信号赋值语句。条件信号赋值语句即根据条件的不同,将不同的表达式赋值给目标信号。条件信号赋值语句与普通软件编程语言中的If-Then-Else语句类似。
条件信号赋值语句的语法格式如下。

当“WHEN”后的赋值条件表达式为“真”时,即将其前面的表达式赋给目标信号,否则继续判断下一个条件表达式。当所有赋值条件均不成立时,将最后一个表达式赋值给目标信号。在使用条件信号赋值语句时要注意,赋值条件表达式要具备足够的覆盖范围,尽可能地包括所有可能的情况,避免因条件不全出现死锁现象。
例如,下面这段程序采用条件赋值语句描述多路选择器电路。

4)选择信号赋值语句。选择信号赋值语句是根据同一个选择表达式的不同取值,为目标信号赋予不同的表达式。选择信号赋值语句和条件信号赋值语句相似,所不同的是其赋值条件表达式之间没有先后关系,类似于C语言中的Case语句。在VHDL中也有顺序执行的CASE语句,功能与选择信号赋值语句类似。
选择信号赋值语句的语法格式如下。

例如,下面这段程序采用信号赋值语句描述多路选择器电路。

5)过程调用语句。过程调用语句是在并行区域内调用过程语句,与其他并行语句一起并行执行。过程语句本身是顺序执行的,但它可以作为一个整体出现在结构体的并行描述中。与进程语句相比,过程调用的好处是过程语句主体可以保存在其他区域内,如程序包内,并可以在整个设计中随时调用。在某些系统中可能不支持过程调用语句,须视条件使用。
过程调用语句的语法格式如下。

例如,下面是一个过程dff在结构体并行区域内调用的实例。

6)生成语句。在进行逻辑设计时,有时需要多次复制同一个子元件,并且将复制的元件按照一定规则连接起来,构成一个功能更强的元件。生成语句为执行上述逻辑操作提供了便捷的实现方式。生成语句有两种形式,即IF形式和FOR形式。IF形式的生成语句对其包含的并行语句进行条件性地一次生成,而FOR形式的生成语句对于它所包含的并行语句则采用循环生成。
FOR形式生成语句的语法格式如下。

IF形式生成语句的语法格式如下。

其中,生成标号是生成语句所必需的,条件表达式是一个结果为布尔值的表达式。下面举例说明它们的使用方式。
例如,下面这段程序采用生成语句描述由8个1位的ALU构成的8位ALU模块。(https://www.daowen.com)


7)元件实例化语句。元件实例化是层次设计方法的一种具体实现。元件实例化语句使用户可以在当前工程设计中调用低一级的元件,实质上是在当前工程设计中生成一个特殊的元件副本。元件实例化时,被调用的元件首先要在该结构体的声明区域或外部程序包内进行声明,使其对于当前工程设计的结构体可见。
元件实例化语句的语法格式如下。

其中,实例化名为本次实例化的标号;元件名为底层模板元件的名称;类属映射(GENERIC MAP)用于给底层元件实体声明中的类属参数常量赋予实际参数值,如果底层实体没有类属声明,那么元件声明中也就不需要类属声明一项,此处的类属映射可以省略;端口映射(PORT MAP)用于将底层元件的端口与顶层元件的端口对应起来,“=>”左侧为底层元件端口名称,“=>”右侧为顶层端口名称。
上述的端口映射方式称为名称关联,即根据名称将相应的端口对应起来,此时,端口排列的前后位置不会影响映射的正确性;还有一种映射方式称为位置关联,即当顶层元件和底层元件的端口、信号或参数排列顺序完全一致时,可以省略底层元件的端口、信号、参数名称,即将“=>”左边的部分省略。其语法格式可简化成如下格式。

2.顺序描述语句
常用的顺序描述语句包括信号和变量赋值(Signal and variable assignments)语句、IF- THEN-ELSE语句、CASE语句、LOOP语句等。
1)信号和变量赋值语句。前面讲述的信号赋值语句也可以出现在进程或子程序中,其语法格式不变;而变量赋值语句只能出现在进程或子程序中。需要注意的是,进程内的信号赋值语句与变量赋值语句有所不同。进程内,信号赋值语句一般都会隐藏一个时间延迟△,因此紧随其后的顺序语句并不能得到该信号的新值;变量赋值时无时间延迟,在执行了变量赋值语句之后,变量就获得了新值。了解信号和变量赋值的区别,有助于在设计中正确选择数据类型。
变量赋值语句的语法格式如下。
变量名:=表达式;
2)IF-THEN-ELSE语句。IF-THEN-ELSE语句是VHDL语言中最常用的控制语句,它根据条件表达式的值决定执行哪一个分支语句。
IF-THEN-ELSE语句的语法结构如下。

其中,“{}”内是可选并可重复的结构;“[]”内的内容是可选的;条件表达式的结果必须为布尔值;顺序语句部分可以是任意的顺序执行语句,包括IF-THEN-ELSE语句,即可以嵌套执行该语句。
例如,下面这段程序采用IF-THEN-ELSE语句描述四选一多路选择器。

3)CASE语句。CASE语句也是通过条件判断进行选择执行的语句。
CASE语句的语法格式如下。

其中,“{}”内是可选并可重复的结构,条件选择值必须是互斥的,即不能有两个相同的选择值出现,并且选择值必须覆盖控制表达式所有的值域范围,必要时可以用OTHERS代替其他可能值。
在CASE语句中,各个选择值之间的关系是并列的,没有优先权之分。而在IF语句中,总是先处理写在前面的条件,前面的条件不满足时,才处理下一个条件,即各个条件间在执行顺序上是有优先级的。
例如,下面这段程序采用CASE语句描述四选一多路选择器。

4)LOOP语句。使用LOOP(循环)语句可以实现重复操作和循环的迭代操作。LOOP语句有3种基本形式,即FOR LOOP、WHILE LOOP和INFINITE LOOP。
LOOP语句的语法格式如下。

FOR循环是指定执行次数的循环方式,其循环变量不需要预先声明,且变量值能够自动递增,IN后的离散值范围说明了循环变量的取值范围,离散值范围的取值不一定为整数值,可以是其他类型的范围值。WHILE循环是以判别表达式值的真伪作为循环与否的依据,当表达式值为真时,继续循环,否则退出循环。Infinite循环不包含FOR或WHILE关键字,但在循环语句中加入了停止条件,其语法格式如下。

例如,下面这段程序介绍了LOOP语句的应用。

3.NEXT语句
NEXT语句用于LOOP语句中的循环控制,它可以跳出本次循环操作,继续下一次的循环。
NEXT语句的语法格式如下。
NEXT[标号][WHEN条件表达式];
4.RETURN语句
RETURN语句用在函数内部,用于返回函数的输出值。例如:

在了解VHDL的基本语法结构以后,就可以进行一些基础的VHDL设计了。