第1节组合逻辑和时序逻辑来源:通过前面各章的学习可知,VerilogHDL语言分为面向综合和面向仿真两大类语句,且可综合语句远少于仿真语句,读者可能会有可综合设计相对简单的感觉。然而事实刚好与此相反,这是因为:首先,可综合设计是用来构建硬件平台的,因此对设计的指标要求很高,包括资源、频率和功耗,这都需要通过代码来体现;其次,在实际开发中要利用基本VerilogHDL语句完成种类繁多的硬件开发,给设计人员带来了很大的挑战。所有的仿真语句只是为了可综合设计的验证而存在。为了让读者深入地理解可综合设计、灵活运用已学内容,本章将可综合设计中的基本知识点和难点提取出来,融入VerilogHDL语法以及开发工具等诸多方面,以深入浅出的方式向读者说明设计中的难点本质。8.1组合逻辑和时序逻辑数字电路根据逻辑功能的不同特点,可以分成两大类,一类叫组合逻辑电路(简称组合电路),另一类叫做时序逻辑电路(简称时序电路)。掌握组合逻辑和时序逻辑的区分手段与实现方法是数字系统设计的基本要求。8.1.1组合逻辑设计1.组合逻辑概念组合逻辑是VerilogHDL设计中的一个重要组成部分。从电路本质上讲,组合逻辑电路的特点是输出信号只是当前时刻输入信号的函数,与其他时刻的输入状态无关。无存储电路,也没有反馈电路,其典型结构如图8-1所示。从电路行为上看,其特征就是输出信号的变化仅仅与输入信号的电平有关,不涉及对信号跳变沿的处理。尽管组合电路在功能上千差万别,可是其分析方法却有很多相似之处。给定逻辑电路后,得到其输入与输出的直接表达式,将输入组合全部带入表达式中计算得到输出结果,并以真值表的形式表达出来,最后根据真值表说明电路功能。组合逻辑电路的设计就是在给定逻辑功能的前提下,通过某种设计渠道,得到满足功能要求且最简单的逻辑电路。基于HDL语言和EDA工具的组合逻辑电路的设计流程如图8-2所示。其中逻辑抽象和HDL编程是重点环节。在很多情况下,逻辑问题都是通过文字描述的,逻辑抽象就是对设计对象的输入与输出信号间的因果关系,用逻辑函数的方法表示出来。HDL语言编程就是直接通过语句来实现抽象结果。2.组合逻辑的VerilogHDL描述根据组合逻辑的电路行为,可以得到两种常用的RTL级描述方式。第一种是always模块的触发事件为电平敏感信号列表;第二种就是用assign关键字描述的数据流赋值语句。(1)always模块的敏感表为电平敏感信号的电路这种方式的组合电路应用非常广泛,几乎可以完成对所有组合逻辑电路的建模。always模块的敏感列表为所有判断条件信号和输入信号,但一定要注意敏感列表的完整性。在always模块中可以使用if、case和for等各种RTL关键字结构。由于赋值语句有阻塞赋值和非阻塞赋值两类,建议读者使用阻塞赋值语句“=”,详细原因将在8.3.1节进行说明。always模块中的信号必须定义为reg型,不过最终的实现结果中并没有寄存器。这是由于在组合逻辑电路描述中,将信号定义为reg型,只是为了满足语法要求。下面给出一个组合逻辑实例。【例8-1】通过VerilogHDL语言实现一个2输入比较器,输入分别为d1、d2,输出分别为f1(d1d2时为高电平)、f2(d1=d2时为高电平)、f3(d1d2时为高电平)。可以看出,组合逻辑就对应着电平触发事件电路。上述程序在ISE中综合后的RTL级结构图如图8-3所示,可以看出,虽然将输出信号f1、f2以及f3声明为寄存器变量,并且在always模块中进行赋值操作,但在组合逻辑设计中,并没有综合成D触发器。上述程序在ISESimulator中的仿真结果如图8-4所示,只要敏感信号电平发生变化,always语句块中所有语句都会被重新执行一次。(2)assign语句描述的电路利用条件符“?”可以描述一些相对简单的组合逻辑电路,信号只能被定义为wire型。当组合逻辑比较复杂时,需要很多条assign语句或者多重嵌套“?”,使得代码可读性极差,因此此时推荐第一种组合逻辑建模方式。下面给出一个由assign关键字描述的组合逻辑实例。【例8-2】通过assign语句实现例8-1的比较器。在ISE中查看其综合后的RTL级结构示意图,可以发现和图8-3一样,其仿真结果也和例8-1的一致。3.组合逻辑电路的注意事项(1)敏感信号列表在组合逻辑设计中,读者必须重点对待敏感信号列表。敏感信号列表出现在always块中,其典型行为级的含义为:只要敏感信号列表内的信号发生电平变化,则always模块中的语句就执行一次,因此设计人员必须将所有的输入信号和条件判断信号都列在信号列表中。有时,不完整的信号列表会造成不同的仿真和综合结果,因此需要保证敏感信号的完备性。在实际的PLD器件开发中,EDA工具都会默认将所有的输入信号和条件判断语句作为触发信号,增减敏感信号列表中的信号不会对最终的执行结果产生影响,因此读者如果期望在设计中通过修改敏感信号来得到不同的逻辑,那就大错特错了。当敏感信号不完备时,会使得仿真结果不一样,这是因为仿真器在工作时不会自动补充敏感信号表。如果缺少信号,则无法触发和该信号相关的仿真进程,也就得不到正确的仿真结果。因此,为了确保仿真和最终实现结果一致,必须要保证组合逻辑电路always敏感信号列表的完备性。如果设计人员在设计中,认为列举信号麻烦,则采用下面的语句。此时,综合工具和仿真工具会自动将所有的敏感信号自动加入敏感信号列表。ISE也支持这一用法。(2)不要在组合逻辑中引入环路在组合逻辑中引入环路会导致电路产生振荡、毛刺以及冲突等问题,从而降低设计的稳定性和可靠性,因此要彻底避免环路。图8-5给出一个简单的环路设计,把一个寄存器输出通过组合逻辑后,再次通过两级组合逻辑处理反馈给该组合逻辑的引脚时,就会产生组合环路,要避免该组合环路,可以采用图8-6所示的逻辑设计示意图,不仅功能结构一致,还取消了组合逻辑环路。之所以称逻辑环路是一种高风险设计,其原因如下:首先,环回逻辑的延时完全依靠组合逻辑门延迟和布线延迟。一旦这些传播时延有所变化,则环路的整体逻辑将彻底失效。其次,环路的时序分析是个死循环过程。目前的EDA开发工具为了计算环路的时序逻辑都会主动割断时序路径,引入许多不确定的因素。目前的综合工具都会给出逻辑环路的警告(CombinationalLoops),因此设计人员必须对软件工具的此类报告特别在意。如果一定要实现环路,则需要通过时序逻辑的寄存器来完成。8.1.2时序逻辑设计1.时序逻辑电路的基本知识时序逻辑是VerilogHDL设计中另一类重要应用。从电路特征上看来,其特点为任意时刻的输出不仅取决于该时刻的输入,而且还和电路原来的状态有关。电路里面有存储元件(各类触发器,在FPGA芯片结构中只有D触发器)用于记忆信息,如图8-7所示。从电路行为上讲,不管输入如何变化,仅当时钟的沿(上升沿或下降沿)到达时,才有可能使输出发生变化。从图8-7可以看出,时序逻辑电路由组合逻辑电路和存储电路这两部分组成,其中存储电路由各类触发器(JK触发器、D触发器以及T触发器等类型)构成,并将组合逻辑的部分输出反馈到输入逻辑的输入端口。时序电路可通过表达式(电路输出端的输出逻辑表达式、存储电路触发器输出端的驱动或激励表达式,以及表示触发器状态的状态方程)、状态转移表、状态转移图、时序图以及HDL行为描述语言等来描述。若将输入变量和各级触发器状态的全部组合列出,分别代入各级触发器的状态方程和电路的输出方程,则可以计算出各级触发器的次态值和当前输出值,把相应的计算结果列成真值表就可得到状态转移表。对于读者最关心的HDL行为描述代码,可在时序图的基础上快速得到。分析一个时序电路,就是要找出给定时序电路的逻辑功能。具体地说,就是要求找出电路的状态和输出状态(一般指进位输出、借位输出等)在输入变量和时钟信号作用下的变化规律。为了直观地说明上述方法,下面给出一个简单的时序逻辑电路,通过分析得到其常用的描述形式。【例8-3】完成图8-8所示的简单时序逻辑电路的分析。(1)首先,列出输出方程、驱动方程,即由于电路采用T型触发器,因此其特征方程为:将驱动方程代入特征方程,可以得到式(8-4)所示的状态方程。(2)计算并列出状态转移表图示电路有一个输入X和1级触发器,因此输入与触发器初态的取值组合只有4组,即00、01、10和11。把这些取值带入式(8-4)和式(8-1),可计算出触发器的次态和电路的输出值,其相应的状态转移表如表8-1所列。(3)画出状态转移图和时序图状态转移图直观、形象地显示出了时序逻辑电路的特点和逻辑功能,本例的状态转移图如图8-9所示。其中,圆圈内的数字表示电路的状态,箭头表示状态转换的方向,箭头旁注明了状态转换的输入条件和输出结果,输入条件位为斜线上方,而输出结果位于斜线下方。时序图就是通过数字信号波形直观表示时序逻辑电路的特点和逻辑功能,可根据状态方程、状态转移表等多方面得到,用于判断设计结果的正确性。图8-10(a)、(b)分别给出了触发器初始状态为0和1的时序图。从图8-10中可以看出以下两点:首先,时序电路的输出信号不仅取决于电路当时的输入,还取决于电路原来的状态,体现了“记忆”特性。其次,在同步时序逻辑电路中,触发器由时钟信号CP来触发,控制其翻转时刻,而对触发器翻转到何种状态并无影响。2.时序逻辑的VerilogHDL描述时序电路的行为决定了其只能通过always块语句实现,通过关键词“posedge”和“negedge”来捕获时钟信号的上升沿和下降沿。在always语句块中可以使用任何可综合的标志符。下面首先以D触发器为例,给出基本单元触发器的VerilogHDL实例,读者可自行完成其余常用触发器(RS触发器、JK触发器以及T触发器等)的VerilogHDL实现。【例8-4】通过VerilogHDL实现D触发器。同步D触发器的功能为:输入D只能在时序信号clk的沿变化时才能被写入到存储器中,替换以前的值,常用于数据延迟以及数据存储模块中。由于D触发器只有一个输入端,在许多情况下,可使触发器之间的连接变得非常简单,因此使用十分广泛。上述程序在ISE中综合后的RTL级结构图如图8-11所示。上述程序的仿真结果如图8-12所示。从中可以看出,在时钟上升沿,D触发器都将输入数据接收并寄存。在给出时序逻辑设计最基本的电路后,下面给出图8-8所示电路的VerilogHDL实现,和例8-3的描述方法进行比较。【例8-5】通过VerilogHDL语言实现例8-3所示电路。程序在ISE综合后的RTL级结构图如图8-13所示,可以看出,其和图8-8是一致的,达到了设计的目的。上述程序的仿真结果如图8-14所示,验证了程序的正确性。在利用VerilogHDL描述时序电路时有以下几个问题需要注意。(1)在描述时序电路的always块中的reg型信号都会被综合成寄存器,这是和组合逻辑电路所不同的。(2)时序逻辑中推荐使用非阻塞赋值“=”,原因将在8.3节详细说明。(3)时序逻辑的敏感信号列表只需要加入所用的时钟触发沿即可,其余所有的输入和条件判断信号都不用加入,这是因为时序逻辑是通过时钟信号的跳变沿来控制的。8.1.3组合逻辑电路中的竞争与冒险1.什么是竞争与冒险信号在组合逻辑电路内部通过连线和逻辑单元时,都有一定的延时。延时的大小与连线的长短和逻辑单元的数目有关,同时还受器件的制造工艺、工作电压、温度等条件的影响。此外,信号的高低电平转换也需要一定的过渡时间。由于存在这两方面因素,多路信号的电平值发生变化时,在信号变化的瞬间,组合逻辑的输出有先后顺序,并不是同时变化,往往会出现一些不正确的尖峰信号,这些尖峰信号称为“毛刺”,如图8-15所示。如果一个组合逻辑电路中有“毛刺”出现,就说明该电路存在“冒险”。需要注意的是,冒险信号的脉冲宽度很小,常常只有数纳秒或数十纳秒,其频带带宽可达数百兆赫兹或更宽。在板级调试时,