2.3 并行语句
VHDL内部的语句分为两大类:并行语句和顺序语句。并行语句是VHDL语言与传统软件描述语言最大的不同,所谓并行,是指这些语句相互之间是并行运行的,其执行方式与书写的顺序无关。并行语句放在结构体中,在执行中,并行语句之间可以有信息往来,也可以是互为独立、互不相关、异步运行的(如多时钟情况)。每一并行语句内部的语句运行方式可以有两种不同的方式,即并行执行方式(如块语句)和顺序执行方式(如进程语句)。
常用的并行语句有信号赋值语句、进程语句(process)、块语句(block)、元件例化语句(component)、生成语句(generate)和并行过程调用语句。
1. 信号赋值语句
信号赋值语句分为简单信号赋值语句(Simple Signal Assignment)、条件信号赋值语句(Conditional Signal Assignment)、选择信号赋值语句(Select Signal Assignment)等。
1)简单信号赋值语句
简单信号赋值语句的格式为:
目的信号<=信号表达式;
赋值时,需要注意数据对象必须是信号,左右两边数据类型一致。例如:
应当注意的是,信号赋值语句在进程外部使用时,是并行语句;在进程内部使用则是顺序语句,具体可参见下面进程讲解部分。
在位数较多的矢量信号赋值操作时,经常使用缺省赋值操作符(others=>x)作省略化的赋值。例如:
赋值后,d1的取值为10010。
2)条件信号赋值语句
条件信号赋值语句的格式为
当when后面的条件成立时,则对应表达式的值代入目的信号,最后一个else子句隐含了所有未列出的条件,每一子句的结尾没有标点,只有最后一句有分号。例如例2.1中使用的信号赋值语句
每一赋值条件是按书写的先后顺序逐项测定,一旦发现赋值条件为TRUE,立即将表达式的值赋给目的信号,条件出现的先后次序隐含优先权。
3)选择信号赋值语句
选择信号赋值语句格式如下:
当when后面的条件成立时,则对应表达式的值代入目的信号。若例2.1中信号y和s的数据类型为std_logic时,我们可以将上面的条件信号赋值语句改为如下的选择信号赋值语句。
也可以写成如下形式:
两种描述方法稍有不同,主要体现在当s为0、1之外的其他取值时,y的取值不同。
使用选择信号赋值语句时,需要注意所有的“when”子句必须是互斥的,且每个when子句可以包含多个条件,用“when others”来处理未考虑到的情况,不允许有条件重叠或条件涵盖不全的情况。每一子句结尾是逗号,最后一句是分号。
4)延时赋值语句
VHDL还支持两种特殊的延时赋值语句:惯性延时(inertial)和传输延时(transport)。
VHDL中惯性延时是缺省的,又称为固有延时,用于建立开关电路的模型。惯性延时的主要物理机制是分布电容效应,分布电容具有吸收脉冲能量的作用,当输入信号的脉冲宽度小于器件输入端分布电容对应的时间常数时,或者说小于器件的惯性延时宽度时,即使脉冲有足够高的电平,也无法突破数字器件的阈值电平,从而导致此脉冲信号无法被采集到。若惯性延迟时间是10ns,输入信号电平维持时间若小于10ns,则此输入信号的变化将被忽略。
惯性延时的一般格式如下:
目的信号<=[[REJECT 时间表达式]inertial ]信号
例如:
b <=reject 10 ns inertial a;
表示若信号a的电平维持时间小于10ns,则变化将被忽略,a仍保持为原来的电平值。惯性延时可以用于过滤掉过快的输入信号变化,小于或等于reject子句中时间表达式值的脉冲将被忽略。缺省时,如:“b<=a;”,仿真阶段附加的惯性延时为仿真的最小分辨时间δ。
又如:
b <=a after 20 ns; b <=inertial a after 20 ns;
这两条语句的功能是一样的,都表示把a的值延迟20ns后赋给信号b。
传输延时常代表总线、连接线的延迟时间,无论输入脉冲多窄,都能进行传输。传输延时时间必须专门说明,该延时只对信号起纯延时作用。
例如:
b <=transport a after 20 ns;
注意:带有延时的赋值语句只能在仿真时的testbench文件中出现,综合器是不支持此类带时间常数的语句的。
2. process语句
进程(process)语句是VHDL中最重要的语句,具有并行和顺序行为的双重性。进程本身属于并行语句,结构体中可以有多个进程,进程和进程语句之间是并行关系,多个进程语句可以同时并发执行,但是进程内部是一组连续执行的顺序语句。进程语句与结构体中的其余部分,包括进程之间的通信都是通过信号传递实现的。process语句的格式如下:
[进程标号: ]process [ (敏感信号表)] [进程说明部分]; begin [顺序语句]; end process[进程标号];
进程的启动取决于敏感信号表中的信号,只要有一个信号发生变化,进程就启动,执行一遍顺序语句定义的行为。因此进程只有两种运行状态:执行状态和等待状态,进程相当于一个条件无限循环的程序结构,循环条件为敏感信号。一些VHDL综合器在对程序综合后,会将该进程的所有输入信号均认为是对该进程对应的硬件电路敏感,而不论源程序中是否把该输入信号列入敏感信号表。因此为了使软件仿真与综合后的硬件仿真对应起来,应当将进程中的所有输入信号都列入敏感信号表中。
进程说明部分主要定义一些局部量,可包括数据类型、常数、枚举、变量、属性、子程序等,不允许定义信号和共享变量。
例如:
此进程的敏感信号是a和b,当a或b变化时,进程内部的赋值语句执行,注意这时的信号赋值语句为顺序信号赋值语句。
在结构体中,不允许同一信号有多个驱动源(驱动源为赋值符号右端的表达式所代表的电路),但是在进程中,同一信号可以有多个驱动源,结果只有最后的赋值被启动,并进行赋值。例如:
该进程执行的结果是:y的取值为b,x的取值为c-b。
当进程的敏感信号列表中有时钟信号,且内部的顺序语句的执行取决于时钟变化时,此进程综合后的电路为时序逻辑电路。注意一个进程中只允许描述对应于一个时钟信号的同步时序逻辑。
3. block语句
块(block)是VHDL程序中常用的子结构形式,有两种block:简单block(simple block)和卫式block(guarded block)。简单block仅仅是对原有代码进行区域分割,增强整个代码的可读性和可维护性;卫式block多了一个条件表达式,又称卫式表达式,只有当条件为真时才能执行卫式语句(guarded语句)。block语句的格式如下:
其中,类属子句和端口子句部分又称为块头,主要用于信号的映射及参数的定义,通过generic、generic_map、port和port_map语句实现。块说明语句与结构体的说明语句相同。
块有如下特点:块内的语句是并发执行的,运行结果与语句的书写顺序无关;在结构体内,可以有多个块结构,块在结构体内是并发运行的;块内可以再有块结构,形成块的嵌套,组成复杂系统的层次化结构。
【例2.3】简单block和卫式block使用示例。
综合生成的RTL电路图和仿真波形如图2-8所示,其中x_block为guarded block,当a为低电平时,其中的卫式语句不执行。
图2-8 含卫式block的RTL综合电路图和仿真波形图
如果把上例中的卫式block改为简单block:
综合生成的RTL电路图和仿真波形如图2-9所示。
图2-9 简单block的RTL综合电路图和仿真波形图
虽然用block语句可以形成层次化的电路结构,但是对于电路中功能的划分,更多的是采用进程或下面将要介绍的元件例化的方式来完成。
4. component语句
除了常规的门电路,标准化后作为一个元件放在库中调用,用户自己定义的特殊功能的元件,也可以放在库中,方便调用。这个过程称为标准化,也可以称为例化。任何一个用户设计的实体,无论功能多么复杂,都可以例化成一个元件或模块。
元件(component)语句分为元件说明语句和元件例化语句,元件说明和元件例化语句的使用是构成层次化设计的重要途径。元件说明语句将预先设计好的实体定义为一个底层元件,元件例化语句将该元件与另一设计实体中的端口相连接,为该设计实体引入一个底层设计元件,从而形成层次化设计。
元件说明语句的格式如下:
元件说明语句可以放在architecture、package和block的说明部分。元件例化语句的格式如下:
其中关联表即端口或类属参数的映射关系,分为位置映射和名称映射两种映射方式。位置映射就是把实际信号与底层元件的信号书写位置一一对应,只写调用底层元件部分的实际信号,不用写底层元件的信号。名称映射的格式为:形式参数=>实际参数。其中符号“=>”为关联运算符,形式参数指的是底层元件的信号名称,实际参数指的是调用底层元件部分的信号名称。另外要注意,元件标号名在结构体中必须是唯一的。
【例2.4】已有与非门nd2的设计实体,如下所示:
图2-10 含有3个ND2门的电路
要求用元件例化语句设计如图2-10所示电路。
上述两段程序应当放在同一个目录下,进行调用和管理。
5. generate语句
生成语句主要用于产生多个相同的结构和描述规则结构,有些实际电路往往会由许多重复的基本结构组成,生成语句可以简化这类电路的VHDL描述。生成语句有两种格式,如下所述:
或者
其中for-generate格式的生成语句主要用于描述结构相同的多重模式,内部为并发处理语句,不能使用exit语句和next语句。其中的循环变量是局部变量,自动产生,并且根据取值范围自动递增或递减,在逻辑综合时无意义,也不能在程序中引用。if-generate格式的生成语句主要描述结构的例外(在某种条件下)情况。
【例2.5】利用已有的D触发器构成4位移位寄存器,其组成框图如图2-11所示。利用生成语句,循环调用D触发器构成4位移位寄存器,VHDL程序如下所述。
图2-11 4位移位寄存器组成框图
使用生成语句时应当注意的是,移位寄存器的输入信号和输出信号的连接无法用for_generate语句实现,只能用信号赋值语句完成。