2.2.6 VHDL语句
VHDL语言是描述硬件逻辑电路的语言,与其他软件语言有明显的区别。从描述的电路结构来看,VHDL有描述组合逻辑(Combinational Logic)电路的语句和描述时序逻辑(Sequential Logic)电路的语句;从语句执行顺序来看,VHDL有并发语句和顺序语句两种。组合逻辑电路指没有触发信号的电路,电路输出结果直接由输入信号决定,当输入信号变化时,输出信号即发生变化;时序逻辑电路指有触发信号的电路,电路有记忆功能,电路的输出结果不仅受输入信号的影响,同时还受触发信号的控制,只有当触发信号及输入信号均发生变化时,输出信号才发生变化。组合逻辑电路与时序逻辑电路的含义与常规数字电路相同。读者应该还记得,前文讲解VHDL程序结构时介绍过语句体并行执行的概念,VHDL中的并发语句即指同时执行的语句,在编写代码时,并发语句无先后顺序之分,并发语句是写在process(进程)之外的语句,这里的process也是VHDL的一个独特语句;顺序语句则是指按语句出现的先后顺序执行的语句,且顺序语句均需要写在process之内。组合逻辑电路通常写在process之外,也可以写在process之内;时序逻辑电路只能写在process之内。
上面介绍的组合逻辑电路、时序逻辑电路、顺序执行语句、并行执行语句、process语句等概念之间的关系听起来可能会有些混乱,因为它们是从不同角度来描述VHDL语句的功能或特点的。VHDL语言的语句虽然比C语言要少很多,但由于包含了完整的仿真、测试、建模语句,精通所有的语句仍然需要花费极大的精力。但常用的电路建模语句并不多,且语义明确,接下来仅介绍常用的部分VHDL语句,读者需要仔细体会各语句的特点及所描述的功能电路模型。随着编程经验的增加,相信读者会很快对这些概念有更准确的把握。
1.赋值语句
VHDL有3种对象的赋值语句:常量赋值、变量赋值、信号赋值。
常量赋值语句是并发执行语句,只能出现在结构体的声明区,声明的常量仅在结构体设计内部可以引用。其语法为
变量赋值语句是顺序执行语句,变量赋值语句只能综合成组合逻辑电路。变量可以先声明后赋值,也可以在声明时直接赋初值。变量的声明只能出现在process语句块中的保留字process与begin之间,变量赋值语句只能出现在process语句块之内,其作用域仅限于声明该变量的process之内。也就是说,一个VHDL设计文件中除了process之内有变量,其他地方是不能有变量存在的。当程序执行到变量赋值语句时,变量值立即改变成表达式的值。读者可能会觉得这种说法有些多余,难道还有不立即改变赋值对象值的语句吗?这正是信号赋值语句与变量赋值语句的最大区别,也是硬件描述语言不同于其他计算机编程语言的最大特点。我们先来看看变量赋值语法,等介绍完信号赋值语句后,再以一个实例讲述两者的差异。
信号可以先声明后赋值,也可以在声明时直接赋初值。信号只能在结构体的声明区声明,不能在process之内声明。信号赋值语句可以是顺序执行语句,也可以是并发执行语句。当信号赋值语句出现在process之外时,为并发执行语句,只能综合成组合逻辑电路;当出现在process之内时,为顺序执行语句,可以综合成组合逻辑电路或时序逻辑电路。当程序执行到信号赋值语句时,信号值在一定时间后才改变成表达式的值。先来看看信号赋值语法。
声明信号时赋初值以符号“:=”表示,此时程序执行当前语句时信号值立即改变;信号赋值符号为“<=”,即运算操作符中的“小于或等于”符号,当程序执行到当前语句时,信号值在一定时间后才改变。用户可以通过保留字after显示地指定信号值变化所需的延时,如果没有显示指定时间,则默认为delta time为无穷短。需要注意的是,delta time是比任何显示指定的时间都要短的时间。正是为了区分对象立即接受新值及延迟接收新值,VHDL用两种不同的符号(:=和<=)来表示赋值操作。
2.when-else语句
when-else语句是并发执行语句,只能写在process之外,综合成组合逻辑电路。首先来看语句的语法。
when-else语句的语法意义很明确,语句依次判断各条件表达式的值,当某条件表达式为真时,将指定逻辑值赋值给目标信号,同时语句终止执行,不再对后面的条件进行判断。所以,语句的条件表达式有优先级,条件表达式越靠前的优先级越高。
3.with-select-when语句。
with-select-when语句是并发执行语句,只能写在process之外,综合成组合逻辑电路。首先来看语句的语法。
with-select-when语句的语法意义很明确,语句依次判断各条件表达式的值,当某条件表达式值为真时,将指定的逻辑值指定给目标信号。与when-else语句不同的是,条件表达式之间没有优先级,也就是说,即使第一个条件表达式的值为真,语句也依然会继续往下执行,直到语句结束。值得注意的是,在使用这条语句时,最后的when others指所有条件均不满足时目标信号的逻辑值。从语句的语义上分析,这条语句非常适合用来描述译码器或不具有优先级的多路选择器电路。
4.process的语法结构
process(进程)是VHDL语言中最为重要的语法结构,所有时序逻辑电路均须使用process结构。本节前面介绍的几种语句也完全可以通过process的语法结构来实现。process的基本语法结构如下。
保留字process之前的进程标号可选,但如果设置了进程标号,则在process结束时也必须写上进程标号。进程标号只用来对process设置一个名称,本身不参与编译或仿真。敏感向量是指触发process内部语句动作的信号,只有当敏感向量列表中的信号逻辑状态发生改变时,才能触发process的内部语句执行。只有当进程设计区中出现wait语句时,才不需要设置敏感向量,否则必须设置至少一个敏感向量信号。wait语句本身就决定了process内部程序的触发条件,所以不设置敏感信号。wait语句将在稍后介绍。
5.if语句
if语句是顺序执行语句,只能写在process之内。if语句是VHDL语言中最重要使用最广泛的语句,其完整语法如下。
本书前面已多次使用到if语句,其语义十分明确,当相应条件成立时就执行条件下的语句。需要注意的一点是,if语句是有优先级的,这与并行执行语句when-else相似。
6.case语句
case语句是顺序执行语句,只能写在process之内。case语句也是条件判断语句,与if语句不同的是,语句中的条件判断没有优先级,类似并行语句with-select-when语句,所以用with-select-when语句编写的代码也完全可以在process中通过case语句实现。先来看看case语句的完整语法。
case语句中的成立信号值必须包含条件成立信号的所有取值,当要求when others后不必执行任何语句时,可用语句null代替。null表示没有任何操作,只能用在process语法结构中。
7.wait语句
wait语句是顺序执行语句,只能写在process之内。wait语句有3种形式:wait until、wait for、wait on。其中,只有wait until可以综合成电路,其他两种形式均无法综合成电路,只能在仿真测试文件中使用。它们的语法分别如下。
由于wait语句的优先级很高,wait语句必须是紧跟process后的第一条语句。如果process中有wait语句,则不能有敏感信号。
wait until语句表示当条件表达式成立时执行后面的语句,wait for表示程序在等待给定时间后再执行后面的语句,wait on表示当指定的信号状态发生变化时执行后面的语句。