![人工智能硬件电路设计基础及应用](https://wfqqreader-1252317822.image.myqcloud.com/cover/533/43738533/b_43738533.jpg)
3.1 顺序语句
顺序语句是用来描述算法的语句,仅存在于process、function和procedure代码段中。在这些代码段中,顺序语句是逐行顺序执行的。
VHDL中的顺序语句包括if语句、case语句、wait语句、loop语句、null语句、信号赋值语句(见第2.1.3节)和变量赋值语句(见第2.1.5节)。
3.1.1 if语句
if语句是VHDL顺序语句的一种。根据一个或者多个条件,if语句选择相应的语句进行执行。计语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_68_1.jpg?sign=1739511434-yoj3pi1zstd7KrhZFXM9G5NGwiNsc2vU-0-d93c590b5a3d13bef55fd60c60328766)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_69_1.jpg?sign=1739511434-4GeSfU2d3iikdac5pxPec8pj4347DZDx-0-cadc0bd36fc390ea94ec218aaebf010b)
其中,if_label是if语句的标签;condition是if语句选择执行代码段的判断条件;sequence_of_statements是与condition对应的执行语句。
例3.1 if语句示例
本例的代码嵌套使用4条if语句,实现异步复位的同步计数功能。
语句1的判断条件是判断低电平有效的复位信号rst_n是否有效。如果为真,将计数器的计数值和进位值清零;如果为假,进入后续操作。
语句2的判断条件是判断计数器时钟的上升沿是否到来。如果为真,进行后续操作。
语句3的判断条件是计数器使能信号是否有效。如果为真,计数器进行计数操作;如果为假,计数器的计数值保持不变。
语句4的判断条件是计数值是否达到最大值。如果为真,计数值清零,进位置高电平;如果为假,计数值自加一,进位置低电平。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_69_2.jpg?sign=1739511434-QTnDBt8WVjHsI2DaTPA7FR4cBBli5MAq-0-c642c608318a9acc3958b26f922dd973)
3.1.2 case语句
case语句是VHDL顺序语句的一种。根据指定表达式的值,case语句从可选分支的语句段中选择其中一个分支进行执行。case语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_70_1.jpg?sign=1739511434-A1NEHvdfN8uQWf6DlJpxnD18eeYHWviM-0-0f71422fff36ed57272fe1c26d2e9e1a)
其中,case_label是case语句的标签;expression是case语句进入分支的判断表达式;choices构成表达式的取值列表;sequence_of_statements是与选项列表中choices对应分支的执行语句。取值列表必须涵盖表达式所有可能的取值,并且每一种取值只能出现一次。
choices可由多个choice构成,choice可由常量表达式、范围或者others表示。case语句需要在取值列表列出表达式的可能取值,这就需要用到others来表示所有未列出的情况。使用others表示其他情况时,others必须是最后一个choice。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_70_2.jpg?sign=1739511434-rKagYYZrXcSiWstDIx69RYVVcBY89wTZ-0-5f84a24584ebb3616d2da5a3e227e827)
例3.2 case语句示例
示例一中,根据x和y的值,case语句C1和C2分别对out_1和out_2赋值0、1、2或3。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_70_3.jpg?sign=1739511434-FhQY4Z5mG4DrBC6CPk8mhW0PLSsxYTsY-0-79d5dae97fdb12e25a261766deabb103)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_71_1.jpg?sign=1739511434-evaBw7sqKtDt6KX8XQuUwN1bDzvKCyHw-0-badf8956bc0c2b88d2596e3667092036)
示例二中,case语句C3在ex的值为num或num+1时,将op赋值为0;在ex的值为num+2时,将op赋值为1;在ex的值为num+3、num+4、num+5或num+6时,将op赋值为2;在ex的值为其他情况时,将op赋值为3。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_71_2.jpg?sign=1739511434-6gbDUBIUf4IVIefQvF7FrxIlpHW17qkS-0-ba826c27f91a4e5498c8513b107f5274)
3.1.3 比较if语句和case语句
if语句和case都是分支语句,可以在不同的条件下执行不同的操作,但两者之间还是有很大区别的。case语句必须将所有可能的分支都列出,而if语句则可以通过多层嵌套更加灵活地实现功能。
例3.3 4位优先级编码器
示例一中,if语句通过嵌套的方式实现优先级编码器。首先,检测data_in最高位是否为低电平。如果为真,直接将输出赋值为“00”;如果为假,检测次高位是否为低电平。接下来的操作以此类推。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_71_3.jpg?sign=1739511434-BGKrNRT0UjsCx06IEHD1AzMfOxtFyeBY-0-3c025b629ecabbc0e662194bafe2c082)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_72_1.jpg?sign=1739511434-NrMztll5GAJMpdHkL3kr9rugFF5ZVDNv-0-27f7aa87fb1af49490897c6df1c0983c)
示例二中,case语句实现优先级编码器。case语句直接将data_in作为表达式,列出data_in的所有可能情况,在每种情况后对data_out赋值。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_72_2.jpg?sign=1739511434-cBS0JenERokfo3xBqCu7z8GEBaTgAKu2-0-fc0919689070e8c1621f17c31746870a)
示例一和示例二都实现了优先级编码器的功能,但采用if语句的示例一在代码量上要明显少于使用case语句的示例二。可以预见的是,如果分别使用if语句和case语句实现8位优先级编码器,两者的代码量将有很大的差别。
尽管if语句在代码展示上存在优先级,但是,在编写类似多路复用器的电路时,EDA工具在实际综合时会优化这部分电路设计。
例3.4 4选1多路复用器
示例一是通过if语句实现4选1多路复用器的代码。图0.1是示例一综合后的RTL电路。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_73_1.jpg?sign=1739511434-vJoKFoYd2LMLR8Ajz0xEaSqfStL5m0HX-0-15b50c0d5f802e685c7bd78e93ed0e0e)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_73_2.jpg?sign=1739511434-kVsQEO3d5KREN32GNednrOBjdbiSM8ve-0-c4f4fcc9fdaa6ee50572794b61527b1c)
图3.1 示例一综合后的RTL电路
示例一是通过case语句实现4选1多路复用器的代码。图3.2是示例二综合后的RTL电路。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_73_3.jpg?sign=1739511434-uMertp9t4CM9XnTCF8LJPPp8j82RBEY7-0-c115f4cf3afaef4aae528926ffd5165b)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_74_1.jpg?sign=1739511434-ncAObFsMdV736dC4cYjmrZljsmW119f7-0-354917d7a7c99f60f9c51d2ad069b3a0)
图3.2 示例二综合后的RTL电路
比较图3.1和图3.2,不难看出,这两张RTL电路图是完全相同的。示例一和示例二综合后都是一个多路复用器模块,即使是使用了嵌套if语句的示例一也会被综合工具优化为多路复用器模块。
3.1.4 wait语句
wait语句是用来暂停process或者procedure顺序语句的。wait语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_74_2.jpg?sign=1739511434-cY1S82LoLeiZcd5LzdMTgLoQxVQQAbiv-0-f66c5cf4a3af82ce5dbd58ba5bea4471)
其中,wait是wait语句的标签;signal_name是wait语句的敏感列表中的敏感信号,直到敏感列表中的其中一个信号发生变化,才开始执行后续操作;condition是wait语句需要满足的条件,指导满足condition的条件,才开始执行后续操作;time_expression是表示时间的表达式,直到等待time所确定的时间,才开始执行后续操作。
如果process中有wait语句,那么该process不可设置敏感列表。
例3.5 wait语句示例
示例一中,语句1在clk的上升沿时结束暂停,将a的值赋值给Q,进入语句2的暂停;语句2在10ns后结束暂停,将b的值赋值给Q,进入语句3的暂停;语句3在c发生变化时结束暂停,将c的值赋值给Q,进入语句4的暂停;语句4没有结束暂停的条件,该代码段进入永久暂停。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_74_3.jpg?sign=1739511434-elEMPTcVqOMejIHryCxxLRGkZTD4MRcD-0-f19fb0e27b5d159e05765c1baf9a0a33)
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_75_1.jpg?sign=1739511434-eSpSTyfoEPRz6ExpGCTKlugUffLPcq5n-0-8b0b56c625e42883f80a60aa4ba583e4)
示例二中,首先将x赋值为高电平,进入wait产生的暂停;等到a或者b发生变化,并且clk为高电平时,结束wait产生的暂停,将信号x取反。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_75_2.jpg?sign=1739511434-ZxbHQdLMPa3MvTmCeYeHWVfArQlrjRf4-0-9102c18ba1ae298c5d04a0e08a30493d)
示例三中,wait语句是当enable为高电平时结束暂停,其效果与注释中的loop语句功能相同。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_75_3.jpg?sign=1739511434-6kELUne0QH0xAvFuRPufGRjwDjXYqqM6-0-dc778036fedc43b6aa0f0cf59dfb99d6)
3.1.5 loop语句
loop语句是可以实现多次执行同一段语句的顺序语句。loop语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_75_4.jpg?sign=1739511434-WQ3ktEuFQquz21Udk4UwHze0dZicBmQB-0-a995ccfcd65f3bbf007aa75e11f2928b)
其中,loop_label是loop语句的标签;iteration_scheme是loop语句循环的迭代方案;sequence_of_statements是需要循环执行的语句段。iteration_scheme的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_75_5.jpg?sign=1739511434-d4SxnAmpldBQfyPOpISI22XAfxHtYghQ-0-58f43af83ded6fe88e6bd4f37dc598ab)
其中,iteration_scheme分为while和for两种结构。while结构中,condition是进入循环的前置条件,只有满足condition的条件,才能进入下一次循环;for结构中,identifier是循环参数的标识符,discrete_range是给定的离散范围,每一次循环结束时,该参数都会自加一,只有循环参数在离散范围内,才能进入下一次循环。在每一次循环中,循环参数可以看作常量,在循环过程中,不可以对循环参数进行赋值操作。
为了完善loop语句的功能,VHDL还定义了next和exit两个语句为loop语句进行补充。next语句实现跳出本次循环功能,如果还满足进入下一次循环的条件,循环会继续执行;exit语句实现结束循环的功能,无论是否满足进入下一次循环的条件,都会开始执行loop语句的下一条语句。
next语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_76_1.jpg?sign=1739511434-Qq2TdnpP0dbJ8hMYDvGEbaYxK0rC2IXp-0-9cd35619288314c400604b628bb2db1b)
其中,next_label是next语句的标签;loop_label是所跳出循环的标签;condition是next语句可选的执行条件。
exit语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_76_2.jpg?sign=1739511434-xu4aWJOulwAQxNZZAcDsNoHSvKRIRTgA-0-5f8f7659e5a08600f0277c4265131a70)
其中,exit_label是exit语句的标签;loop_label是所结束循环的标签;condition是exit语句可选的执行条件。
例3.6 loop语句示例
示例一中,loop语句没有迭代方案。循环内容是延迟5ns将clk取反,实现周期为10ns的时钟信号输出。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_76_3.jpg?sign=1739511434-crM1rTGt1uQ2RWi1s7ieNd4LEuQZgI7x-0-fcdc83c05346225d62fa10efafcdabcc)
示例二中,loop语句采用while格式的迭代方案。i是模拟的循环参数,与for格式的循环参数不同,此处的i可以进行赋值操作。一般来说,模拟的循环参数在每次循环过程中赋新的值,否则,该循环可能会永远无法结束循环,成为无限循环。此处,i在每次循环结束时自加一,当大于8时,不再进入下一次循环。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_76_4.jpg?sign=1739511434-amwVEnjpaTfZN134WabnRfEmrW9hboRc-0-05cbebc90c6ceb16bc5d929516f71f6c)
示例三中,loop语句采用for格式的迭代方案。循环参数i的初始值是1。当i在1至8的范围时,将不断进行循环;当i等于9时,将结束整个循环。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_77_1.jpg?sign=1739511434-nn8mZsmfRmOJz2pRXG9GO4UxHWz873oB-0-f1154b345275054f604efe1bc7c89d0a)
示例四中,语句1是结束整个L4的loop语句,不再进入下一次循环。语句2是在满足i与m相等时结束语句所在的loop语句,即L5的loop语句,结束后程序会进入L4的下一个循环。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_77_2.jpg?sign=1739511434-earrlum4UfQG7poh5G3a0gF8kAXSCOE6-0-2c963049890540a65276f8c6247a5c6c)
示例五中,语句1是在满足countvalue与n相等时跳出所在loop语句的本次循环,即L7的本次循环。跳出本次循环后,如果循环参数在自加一后仍然满足迭代方案的条件,则继续进入下一次循环;否则,结束L7的loop语句。语句2是跳出L6的loop语句的本次循环。跳出本次循环后,继续进入下一次L6循环。此处的L6没有设置循环条件,也没有在循环内部模拟循环参数,或使用exit语句,该循环是一个无限循环。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_77_3.jpg?sign=1739511434-8w8y7399pqL0CYegjSPXiwuJSyhpqFvG-0-65731927c908995a4ef282dc936dd47d)
3.1.6 null语句
null语句是执行空操作的语句,即语句不会对程序产生任何影响,直接跳转到下一条语句。null语句的语法结构如下。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_78_1.jpg?sign=1739511434-diZ95DISXvA5UfdXboXZZDBbESI3OyPG-0-78fb6fa227f411c2286cd73feaed498e)
其中,null_label是null语句的标签。
当程序对于某些分支中不需要执行任何操作时,可以使用null语句。case语句必须列出所有可能出现的分支,也就会出现不执行任何操作的分支,这时就可以使用null语句来作为分支执行的内容。
例3.7 null语句示例
示例中,当data_in为低电平时,不执行任何操作,即不修改data的值;当data_in为高电平时,将data赋值为“01”;当data_in为其他值时,将data赋值为“10”。
![](https://epubservercos.yuewen.com/B3251C/23020659009785406/epubprivate/OEBPS/Images/43035_78_2.jpg?sign=1739511434-IhnJhuMVuv2gcERf2Aeq8VecomCJ1bTy-0-878b11a62fd93ede551a0cef19d04271)