![人工智能硬件电路设计基础及应用](https://wfqqreader-1252317822.image.myqcloud.com/cover/533/43738533/b_43738533.jpg)
3.2 并行语句
并行语句是用来描述互相连接的块和进程的语句。这些块和进程共同描述了一个电路设计的行为和结构。从本质上来说,VHDL程序是由许多并行语句组成的,是并行语句的集合。并行语句相互之间是异步执行的,是相互独立的。并行语句互相补充,组成一个完整的电路设计,又是相互联系的。
VHDL的并行语句包括process语句、when语句、block语句、component语句、generate语句和信号赋值语句(见第2.1.3节)。
3.2.1 process语句
VHDL中,进程(process)是并行语句,但其内部的语句是顺序描述语句,代表了整体设计中的一部分功能。进程的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_79_1.jpg?sign=1739325675-34LKkVQkEzHp8anYZMJDRA4b9n77LJWX-0-34126c83a05938b54a9504697546618e)
其中,process_label是进程的标签;process_sensitivity_list是进程的敏感列表;process_declarative_part是进程的声明部分;process_statement_part是进程的语句部分。
process一般都会添加敏感列表或wait语句对process的执行条件进行判断。敏感列表本质上是隐性的wait语句。具有敏感列表的process和将wait语句放在最后的process是完全相同的,即下面的两段代码是等价的。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_79_2.jpg?sign=1739325675-RL79zJRkM7tj4mKgvbz9YF0soLe0y5dU-0-79d49540035ef0a65c8b7f38f2c63d20)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_79_3.jpg?sign=1739325675-doX8ToXmqxAlSefKOkgvsnWOOai55NlG-0-06e1ac4e1987373c999306ae22f19bd3)
另外,需要特别注意的是,process并不是在敏感列表发生变化时才开始执行,而是在敏感列表发生变化时继续执行下一次。为了验证这一点,可以通过例3.8进行测试。
例3.8 process执行过程测试
本示例是process执行过程的测试程序。第一个process中,首先将共享变量b赋值为高电平,将临时信号tmp_re1取反,然后等待信号a变化;等到信号a变化后,将临时信号tmp_re2取反。第二个process中,设置时钟信号clk为敏感列表,在共享变量b为高电平时,将临时变量tmp_re3取反。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_79_4.jpg?sign=1739325675-YX9h4PaWqFs1hajS81fQk9ybw6RXokYQ-0-9ba0c008f390b6309c2a03a133833168)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_80_1.jpg?sign=1739325675-Phb3LhMHsXuwZn3kAFU8qmcXlvROjgEh-0-10b9766d15116e3bd478b44bfdc78a52)
本示例的仿真结果如图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的执行过程。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_81_1.jpg?sign=1739325675-ks71z54WE9jl0I6IVhQ7CZmiOaXb9Tul-0-f6de41ba269816f330402a2e1cabae36)
图3.3 process执行过程仿真结果
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_81_2.jpg?sign=1739325675-pvdrUj0EcKdIkW6baQhPIbRyrqa9bald-0-78d14d5ce2e672a7e91deebb5619eeb9)
图3.4 process执行过程仿真结果
3.2.2 block语句
block语句是将结构体中并行语句分组的语句,实现设计的模块化。block语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_81_3.jpg?sign=1739325675-neCgu4yIonrf6HhMfiMS0GjXMUkb16bi-0-1ba353d0d621c8e247674079f901e571)
其中,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条赋值语句分割为两部分,每条语句都会同时执行。综合工具综合后,其实际功能与示例最后的注释部分是完全相同的。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_82_1.jpg?sign=1739325675-Da0UehyAp66uzKdd2W6qRsRnLKU8pjRk-0-adb876b916cb24e42a81877f7ed2624b)
示例二中,block语句B3和B4实现了block语句的嵌套。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_82_2.jpg?sign=1739325675-sx20qwJ7A6mnpLV4d913jzHW0orfnj7L-0-1e411d25d5de3e410ec2016ad5bc4d46)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_83_1.jpg?sign=1739325675-3isOXm83gPXDC8IQTQzHDoiaGdtlRkJt-0-f5f1ecabf35751064027faff38519131)
保护块是一种特殊的block语句,比简单块多了保护块条件。只有当保护块条件为真时,保护块内带有guarded关键词的语句才会被执行。保护块是不可综合的。
例3.10 保护块示例
本示例通过保护块实现了同步复位上升沿触发的D触发器。只有在保护块条件为真且rst为高电平时,q会被赋值为高电平。否则,q被赋值为d的值。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_83_2.jpg?sign=1739325675-yJW0DZygRUD7a2kdAiYZDJu7Mpv8ux11-0-e5efc8e88f3e6043ec1dbc8f10012bcc)
3.2.3 generate语句
generate语句是为并行语句提供迭代循环和条件分支机制语句。generate根据实现的功能可以分为for/generate、if/generate和case/generate。在功能和语法结构上,与顺序语句中的for/loop语句、if语句和case语句大致相同。
for/generate语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_83_3.jpg?sign=1739325675-femCgD9zitLcEwZDyzEHGu5QJOY1yYtm-0-7a21a561f8edcdcd3e7b6b2a2a10122a)
其中,generate_label是generate语句的标签;identifier是generate语句进行迭代循环的生成参数;discrete_range是生成参数的离散范围;generate_statement_body是进行循环的并行语句段。
if/generate语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_83_4.jpg?sign=1739325675-ck2rJViLIIdsc1HCQX5NJwb3rihyWGEd-0-1f854efba4a874ea8ebb8973c6ad9350)
其中,generate_label是generate语句的标签;alternative_label是分支的标签;condition是if/generate进入分支的条件;generate_statement_body是每个分支对应的并行语句段。
case/generate语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_84_1.jpg?sign=1739325675-vY4aj4FfZjtIgu1KLc8GhfaKKfPhVHJP-0-e0a1e92356d4664fe677afbb24a9c353)
其中,generate_label是generate语句的标签;expression是进入分支的判断表达式;alternative_label是分支的标签;generate_statement_body是每个分支对应的并行语句段。
例3.11 generate语句示例
示例一实现了多输入与门的电路。通过for/generate语句,将输入信号的每一位都进行逻辑与操作。port_num是通用属性定义的输入端口数量,端口定义了相应数量的输入。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_84_2.jpg?sign=1739325675-I7JRcXy4cMYBGu0tOEiT9frxASCTns9u-0-0b12c1726c18f330b01b56f19d536109)
示例二实现逻辑与/或门的电路。通过case/generate语句,判断通用属性gate_type的值,实现逻辑与门或逻辑或门的功能。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_84_3.jpg?sign=1739325675-SbsoiU8NlzuJw3vcrbWDgC43l07T4UW5-0-e5a9c19405b2904e0a9662dc2f9021fd)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_85_1.jpg?sign=1739325675-kWS4bWuozoNIbDC5cupBP8fdpSgpl0JA-0-b3e01242524ca2070a03cbac8318b7c7)
示例三实现了通用触发器的电路。通过case/generate语句,判断ff_type的值,实现D触发器、JK触发器或T触发器的功能。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_85_2.jpg?sign=1739325675-yAiX6o76P6qMpEchZ48aS8SshS27Dr2A-0-4b0eba90d22a33d7588d6f1d29002403)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_86_1.jpg?sign=1739325675-F9m42qKSNmRiUWMVcHkO2P6LDNDyS0vC-0-6e55c19e4ea493e0deb1910c5d1f8076)
3.2.4 component实例化语句
component(元件)是一段结构完整的代码段。使用component时,需要component声明和component实例化两部分。component声明是为一个设计实体创建一个虚拟接口供实例化语句使用的。component实例化语句是关联component的端口,重新配置component的通用属性,将一个设计实体实例化为当前设计实体的子元件。
component声明的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_86_2.jpg?sign=1739325675-iocUs5pLkwJ2C7aSaG3gPGIB13lSbTF9-0-f7410b9341499c038a47910be39ce9eb)
其中,component_name是元件的名称;generic_list是元件的通用属性列表;port_list是元件的端口列表。
component实例化语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_86_3.jpg?sign=1739325675-ajF09uqntyqZdwodVF1ZkmATQV8K1CFn-0-b0efa390ab9235192f2d9ef1ee49170d)
其中,component_name是component声明中的元件名称;generic_association_list是重新配置通用属性的列表,即通用属性映射列表;port_association_list是关联端口的列表,即端口映射列表。映射列表的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_86_4.jpg?sign=1739325675-q7SrLsUh2R8X9UOY62eLFs0yOdnoKjbZ-0-87d6b9d00bc9297091a8763782e7cf5e)
其中,映射列表可以包含多个通用属性或者端口的映射,也可以省略不需要修改的通用属性和不需要连接的端口。
例3.12 component示例
通用触发器flip_flop是通过通用属性实现多种触发器功能的设计实体。示例在结构体的声明部分声明了元件flip_flop,在实现部分将flip_flop实例化为D触发器,实现同步模10的8421BCD码计数器电路。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_87_1.jpg?sign=1739325675-ryvVXanQb9woTuuEF8u1FfaYerWvWLwV-0-0f90e68975c8f70370313f8f8f246fd8)
通用触发器flip_flop的RTL原理图如图3.5所示。使用D触发器实现同步模10的8421BCD码计数器的原理图如图3.6所示。依据计数器原理图,将实际的连接在下述代码中实现。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_87_2.jpg?sign=1739325675-oBd4iE16ulk4ospL0E7pozrT2Yy5ktLW-0-25a33283fbc2865963b299ca9098488d)
图3.5 通用触发器flip_flop的RTL原理图
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_88_1.jpg?sign=1739325675-0Oianm9kqKC4hFa6QGlSQmr1KCsUhzW3-0-587f5a034e416de652240e750ba1205f)
图3.6 使用D触发器实现同步模10的8421BCD码计数器的原理图
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_88_2.jpg?sign=1739325675-VHUwHMhXITMJc1zjGJEPPG0a2KW5KMsF-0-ff53e076058af43372d13afbc3cfdcf1)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_89_1.jpg?sign=1739325675-hqL4PUkmDnhBUv9cliKFMd5Zrdipk0Fb-0-40787755ecdd651e8658144d22ce2266)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_90_1.jpg?sign=1739325675-0Ngj0SlT6Po8el0fpByIKw6KTbIYxVDl-0-f9dda0f7c8a9fab8853d1d982b4be1fe)
对计数器设计实体进行仿真,仿真结果如图3.7所示。在时钟信号clk上升沿时,计数状态q会自加一;当状态q达到“1001”时,进位co变为高电平;当计数器重新开始新一轮计数时,进位co变为低电平。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_90_2.jpg?sign=1739325675-6XATBoXWIbuM3BUgNAGY0u47W12TIls5-0-cb113fbe566d32578daaceb4a648b858)
图3.7 同步模10的8421BCD码计数器的仿真结果