在数字系统设计中,我们传统上都认为,应该对所有的触发器设置一个主复位,这样将大大方便后续的测试工作。所以,在所有的程序中,我往往都在端口定义中使用同一个reset信号(其实好多时候根本就没有用到)。所以,当看到文档中提到,“不建议在FPGA设计中使用全局复位,或者说应该努力避免这种设计方式”时,许多设计人员(包括我)都会觉得非常难以理解,这种设计思想跟我们通常的认识是相冲突的!
继续读下去,不知不觉发现这个白皮书讲的还真是在理。接下来把我的个人理解讲述一下。
1.全局复位是不是关键时序?
全局复位信号一般由以下三种途径获得:
1. 第一种,最常见的,就是用一个复位按钮产生一个复位信号接到FPGA的全局复位管脚上。它的速度显然是非常慢的(因为是机械结构),而且存在抖动的问题。
2. 第二种是上电的时候由电源芯片产生的,如TI的TPS76x系列的电源系统一般都可以产生复位信号,供主芯片上电复位使用。
3. 第三种是由控制芯片产生的复位脉冲,这个是我们设计人员可以方便使用程序控制的。
在这些情况下,复位信号的变化与FGPA芯片内部信号相比看起来是及其缓慢的,例如,复位按钮产生的复位信号的周期至少是在毫秒级别的,而我们FPGA内部信号往往是纳米或者微秒级别的。复位信号的频率是如此之低,以至于我们任务它不属于关键时序(not timing-critical)。即使是对此类信号进行时序约束,约束的周期也是非常长的。全局复位脉冲的周期远大于时钟周期,所以传统意义上假设FPGA芯片中所有的触发器都能够得到有效的复位。
然而,随着FPGA性能和工作频率的快速提高,这种假设开始不再成立。此时,全局复位信号的产生开始成为时序关键的问题。
在Xilinx 的FPGA器件中,全局的复位/置位信号(Global Set/Reset (GSR))(可以通过全局复位管脚引入)是几乎绝对可靠的,因为它是芯片内部的信号。如果所有的触发器都使用这一全局复位信号,则GSR信号将形成一个高扇出的网络(有兴趣的朋友可以在综合工具中查看)。虽然在启动顺序中,它可以与一个用户自定义的时钟进行同步,但是想让它与设计中的所有时钟信号进行同步是不可能的;比如,一个Xilinx FPGA中可能含有多个DLL/DCM/PLL时钟处理模块,每个模块又可以产生多个时钟信号,在各个模块内部进行时钟信号的同步是可行的,然而想让所有时钟信号同步是完全不可行的——从DCM的分布上就可以看出来:中间相隔的长距离布线对高频时钟信号的延时显著增大,进行同步自然无法做到。于是,在时钟信号频率越来越高的情况下,全局复位信号便开始成为时序关键。解释如下:
图1被两个时钟信号的边沿截断的复位信号的时序图
图1 给出了被两个时钟信号的边沿截断的复位信号的时序图,第一行是时钟信号,第二行是器件复位管脚上的信号,第三行是到达触发器复位端的复位信号。为了使触发器进行有效的复位,在有效的时钟边沿到来之前,复位信号应该被保持至少一个建立时间(时钟信号的简历时间)。可以看出,时钟信号的频率越高,用来分配复位信号的可用时间就越少。而且考虑到全局复位信号往往是高扇出的的网络,想在这个庞大的网络中满足苛刻的时序要求是非常困难的。在经常使用的异步复位的设计中,更没有办法来保证所有的触发器都可以在同一个时钟边沿被释放,即使存在用来分配复位信号的可用时间。这一点从图2中可以看出。
图2 异步设计中复位信号的时序图
图2给出了异步设计中复位信号的时序图。可以看出,在A时刻产生的复位信号,将在第一个时钟信号的有效边沿产生,而在C时刻产生的复位信号将在第二个有效的时钟信号边沿产生。在B时刻,触发器很难有效定义哪一个复位信号是有效的,这将导致亚稳态的产生。
随着时钟信号频率的增高和器件规模增大带来的潜在的时钟偏移,在同一个时钟边沿对所有的触发器进行是否已经几乎是不可能的了。图3显示了高时钟频率下的复位时序图。
图3 高时钟频率下的复位时序
全局复位对时序的要求真的很关键吗?
好消息是,在绝大多数设计中(白皮书说是超过99.99%?应该是老外写文档的习惯吧),复位信号的时序是无关紧要的——通常情况下,大部分电路都能够正常工作。然而,只要你曾经遇到过复位信号不正常导致电路无法正确工作的情况,那么可以说你“幸运”地遇到了那0.01%的复位信号异常的情况。图4给出了一个流水线复位的情况。
图4 流水线的复位
在流水线中,假如数据都是完全顺序处理的(即不存在反馈、环路等情况),则主复位信号是何时产生的是完全无关紧要的。经过几个周期的流水线操作,任何不正常的数据状态都将被从系统中“冲出”流水线,这是很容易理解的。事实上,在正常的流水线操作中,我们也很少会用到复位操作的,因为这是完全没有必要的。即使是在仿真环境中,我们也往往会在测试程序中对初始状态进行配置,从而将所有的未知状态从系统中清除出去,使得系统中的所有输入都变为有效的数据。
然而,在图5所示的独热码状态机的情况下,复位信号的时序却的的确确成为了系统正常工作的关键因素之一。
图5 独热码状态机的复位
图5 的例子中演示了一个简单的的独热码状态机的复位示意图。图中清晰地显示了复位失败的潜在可能性。如果第一个含有独热码的触发器比第二个触发器提前释放一个时钟周期,则其含有的独热码将丢失,整个状态机将永远进入无效状态(cold)。减小这种情况发生的概率往往可以通过使用相邻的触发器构成状态机来解决(使用本地复位网络,则信号的失真度较低),但前提是时序约束中的建立时间必须满足。此外,如果所有的触发器无法在同一个时钟信号的有效边沿被释放,,则一个已经编码的状态机可能会调变进入未知状态,包括非法状态,造成电路无法正确工作。所以,在包含反馈通路的电路设计者,需要对复位信号的时序要求进行仔细考虑。
事实上,不存在反馈通路的电路是完全不需要使用复位信号的。例如,在数字信号处理应用中,有限脉冲响应滤波器(FIR)就不存在反馈通路:只有在有效数据填满所有节拍时,滤波器才会输出采样值,否则不输出任何数据;所以对节拍寄存器进行复位是毫无意义的。然而,在有限脉冲响应滤波器(IIR)中,存在反馈通路,如果在一个不可靠的复位信号下对节拍寄存器进行复位并产生一个伪信号输出,则滤波器输出会受到显著的影响。最坏的情况下,伪信号带来的不稳定将导致整个滤波器陷入崩溃状态。
如何自动覆盖99.99%的情况
图6 FPGA配置
当一个Xilinx的FPGA芯片被重新配置时,每一个单元都将被初始化,如图6所示。在某种意义上讲,这是一个上电之后的“终极的”全局复位操作,因为它不仅仅是对所有的触发器进行了复位操作,还初始化了所有的RAM单元。随着Xilinx FPGA芯片内部的嵌入式RAM资源越来越多,这种“终极的”全局复位操作越来越有意义。对所有的RAM单元进行预定义,在软件仿真和实际操作中都是非常有帮助的,因为这样避免了在上电时采用复杂的启动顺序来清除存储单元内容的操作。
随着Xilinx的FPGA芯片越来越多的嵌入处理器内核,比如MicroBlaze软核、ARM和PowerPC硬核等,这种特性使得所有的程序和数据空间在处理器内核执行第一条指令之前都已经被预定义,则原来那种靠烧写昂贵的可编程资源来仅仅复位触发器的操作变得毫无意义了。开发过程中所使用的仿真工具也应当具有模拟此操作的能力(即我们通常所说的“上电复位”),这样在后续的设计中就可以避免使用可有可无的复位操作了。
其余0.01% 情况的设计准则
最重要的事情是使用某些准则来处理设计中的复位操作,并且这些准则在设计审查阶段就应该被完全考虑到。可以使用一个局部的高性能的复位网络来控制仅仅需要局部复位的触发器。图7给出了一个这种局部复位的示意图。这种电路的优点在于,它所提供的复位效果与外接全局复位信号的效果是一致的。
图7 局部复位示意图
在器件配置或者异步复位时,链中的所有触发器都被预设为1。几乎在这同时,链中的最后一个触发器驱动局部复位网络并向其发送一个有效复位信号。随着全局复位/置位信号或异步复位信号的释放,整个移位寄存器链开始在每个时钟周期被填充为0。
链中触发器的数目决定了局部复位网络所需要的复位脉冲的最小宽度。最后的结果是,链中最后一个触发器从高跳变到低,而局部复位信号的释放与时钟周期同步。被复位的触发器可以采用同步置位(synchronous set (FDS))或者同步复位(synchronous reset (FDR)),即构成了完整的同步设计,而接下来的时序规范和分析也将容易得多。
复位操作消耗的资源远比你想象的要多
在FPGA设计中,我们往往习惯在HDL文件的端口声明中加入一个reset信号,却忽略了它所带来的资源消耗。仔细分析一下,竟会有如此之多的影响:
• 复位网络需要占用布线资源
♦ 导致其余信号的布线信号受到影响,降低了它们布线的自由度。
♦ 增加的布线网络往往需要使用更高速率的芯片。
♦ 复位网络占用大量布线资源,使得Place&Route的时间大大增加,如果电脑是老爷机则让人十分痛苦。
• 复位信号需要占用大量的逻辑资源
♦ 复位信号需要使用触发器的专用复位管脚。
♦ 可操作的复位信号往往导致D触发器的输入前增加额外的门操作或专用的复位信号输入。
♦ 增大整个设计 的尺寸。
♦ 额外的逻辑消耗降低了系统的性能。
• 阻止了使用高效特征,如Xilinx FPGA特有的SRL16E 移位寄存器。
♦ SRL16E可以在一个LUT中实现多达16个触发器。
♦ SRL16E 实现的虚拟触发器不支持复位操作,这使得HDL设计中带有复位操作时,综合工具无法有效利用SRL16E 资源。有可能增加多达16倍的资源消耗。
在Xilinx网站的白皮书 WP275 .pdf:《Get your Priorities Right - Make your Design Up to 50% Smaller》中提到了复位信号是如何影响FPGA资源利用率的,有兴趣的朋友可以去读一下。
总结一下,Xilinx FPGA设计中一般不需要插入全局复位网络,这样我们在写程序的时候就不必每个模块都加入reset端口了,既方便了程序书写,又减小了编译时间,还减少了资源占用。绝大多数情况下,重配置或者上电过程中,所有的触发器和RAM等都可以被预设初始状态,所以全局复位是完全没有必要的,因为所有的信号都已经具有明确的初值!Xilinx FPGA都已经经过充分验证,所以扫描逻辑和运行测试向量都不再是必须的操作,全局复位作为这些操作的一部分自然也不再需要。
复位操作还会影响到器件的资源占用、布局布线和实现效果,所以及时非得使用复位操作,也可以在局部仔细地设计复位网络。FPGA的设计真是博大精深,好多感觉上是约定俗成的东西,在实际实现中竟然有时候是完全不合理的。欢迎大家一起讨论。