人工智能硬件电路设计基础及应用
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.2 并行语句

并行语句是用来描述互相连接的块和进程的语句。这些块和进程共同描述了一个电路设计的行为和结构。从本质上来说,VHDL程序是由许多并行语句组成的,是并行语句的集合。并行语句相互之间是异步执行的,是相互独立的。并行语句互相补充,组成一个完整的电路设计,又是相互联系的。

VHDL的并行语句包括process语句、when语句、block语句、component语句、generate语句和信号赋值语句(见第2.1.3节)。

3.2.1 process语句

VHDL中,进程(process)是并行语句,但其内部的语句是顺序描述语句,代表了整体设计中的一部分功能。进程的语法结构如下。

其中,process_label是进程的标签;process_sensitivity_list是进程的敏感列表;process_declarative_part是进程的声明部分;process_statement_part是进程的语句部分。

process一般都会添加敏感列表或wait语句对process的执行条件进行判断。敏感列表本质上是隐性的wait语句。具有敏感列表的process和将wait语句放在最后的process是完全相同的,即下面的两段代码是等价的。

另外,需要特别注意的是,process并不是在敏感列表发生变化时才开始执行,而是在敏感列表发生变化时继续执行下一次。为了验证这一点,可以通过例3.8进行测试。

例3.8 process执行过程测试

本示例是process执行过程的测试程序。第一个process中,首先将共享变量b赋值为高电平,将临时信号tmp_re1取反,然后等待信号a变化;等到信号a变化后,将临时信号tmp_re2取反。第二个process中,设置时钟信号clk为敏感列表,在共享变量b为高电平时,将临时变量tmp_re3取反。

本示例的仿真结果如图3.3和图3.4所示。图3.3中,输出端口re3一直在跟随时钟信号clk变化。当clk变化时,re3也在这个时刻取反。由此不难看出,从0ns开始,共享变量b就已经被赋值为高电平了。那么,第一个process在输入端口a变化之前就已经开始执行了。另外,在0ns时,共享变量b被赋值后,临时变量tmp_re1也改变了,但由于临时变量tmp_re1是信号,需要等到process结束时才能将值传递给输出端口re1。

图3.4是将仿真时间范围放大到50ns的波形图。临时变量tmp_re3的初始值是低电平,而re3在0ns时的值是高电平,说明第二个process在0ns时就执行了tmp_re3取反的操作。但clk在0ns时并没有发生改变,也就不会触发敏感列表,process在clk变化之前就已经执行了一次。这里的现象再次验证了process的执行过程。

图3.3 process执行过程仿真结果

图3.4 process执行过程仿真结果

3.2.2 block语句

block语句是将结构体中并行语句分组的语句,实现设计的模块化。block语句的语法结构如下。

其中,block_label是block语句的标签;guard_condition是保护块的条件;block_header是block头部,包含generic、port等语句;block_declarative_part是block声明部分,包含在block内部使用的常量、信号等声明;block_statement_part是block语句的主题,包含待执行的并行语句。

block语句按照是否具有保护块条件,分为简单块和保护块。简单块可以理解为对原有代码的区域分割,将结构体模块化,增强结构体内部的层次性和可维护性。

例3.9 简单块示例

示例一中,block语句B1和B2将3条赋值语句分割为两部分,每条语句都会同时执行。综合工具综合后,其实际功能与示例最后的注释部分是完全相同的。

示例二中,block语句B3和B4实现了block语句的嵌套。

保护块是一种特殊的block语句,比简单块多了保护块条件。只有当保护块条件为真时,保护块内带有guarded关键词的语句才会被执行。保护块是不可综合的。

例3.10 保护块示例

本示例通过保护块实现了同步复位上升沿触发的D触发器。只有在保护块条件为真且rst为高电平时,q会被赋值为高电平。否则,q被赋值为d的值。

3.2.3 generate语句

generate语句是为并行语句提供迭代循环和条件分支机制语句。generate根据实现的功能可以分为for/generate、if/generate和case/generate。在功能和语法结构上,与顺序语句中的for/loop语句、if语句和case语句大致相同。

for/generate语句的语法结构如下。

其中,generate_label是generate语句的标签;identifier是generate语句进行迭代循环的生成参数;discrete_range是生成参数的离散范围;generate_statement_body是进行循环的并行语句段。

if/generate语句的语法结构如下。

其中,generate_label是generate语句的标签;alternative_label是分支的标签;condition是if/generate进入分支的条件;generate_statement_body是每个分支对应的并行语句段。

case/generate语句的语法结构如下。

其中,generate_label是generate语句的标签;expression是进入分支的判断表达式;alternative_label是分支的标签;generate_statement_body是每个分支对应的并行语句段。

例3.11 generate语句示例

示例一实现了多输入与门的电路。通过for/generate语句,将输入信号的每一位都进行逻辑与操作。port_num是通用属性定义的输入端口数量,端口定义了相应数量的输入。

示例二实现逻辑与/或门的电路。通过case/generate语句,判断通用属性gate_type的值,实现逻辑与门或逻辑或门的功能。

示例三实现了通用触发器的电路。通过case/generate语句,判断ff_type的值,实现D触发器、JK触发器或T触发器的功能。

3.2.4 component实例化语句

component(元件)是一段结构完整的代码段。使用component时,需要component声明和component实例化两部分。component声明是为一个设计实体创建一个虚拟接口供实例化语句使用的。component实例化语句是关联component的端口,重新配置component的通用属性,将一个设计实体实例化为当前设计实体的子元件。

component声明的语法结构如下。

其中,component_name是元件的名称;generic_list是元件的通用属性列表;port_list是元件的端口列表。

component实例化语句的语法结构如下。

其中,component_name是component声明中的元件名称;generic_association_list是重新配置通用属性的列表,即通用属性映射列表;port_association_list是关联端口的列表,即端口映射列表。映射列表的语法结构如下。

其中,映射列表可以包含多个通用属性或者端口的映射,也可以省略不需要修改的通用属性和不需要连接的端口。

例3.12 component示例

通用触发器flip_flop是通过通用属性实现多种触发器功能的设计实体。示例在结构体的声明部分声明了元件flip_flop,在实现部分将flip_flop实例化为D触发器,实现同步模10的8421BCD码计数器电路。

通用触发器flip_flop的RTL原理图如图3.5所示。使用D触发器实现同步模10的8421BCD码计数器的原理图如图3.6所示。依据计数器原理图,将实际的连接在下述代码中实现。

图3.5 通用触发器flip_flop的RTL原理图

图3.6 使用D触发器实现同步模10的8421BCD码计数器的原理图

对计数器设计实体进行仿真,仿真结果如图3.7所示。在时钟信号clk上升沿时,计数状态q会自加一;当状态q达到“1001”时,进位co变为高电平;当计数器重新开始新一轮计数时,进位co变为低电平。

图3.7 同步模10的8421BCD码计数器的仿真结果