现代的IC芯片包含丰富的触发器,不同电路的时钟驱动源存在频率和相位的差异,因而出现了跨不同时钟区域进行异步数据传输的要求。亚稳态问题是异步数据传输过程面临的主要问题,本文提出多种跨越异步时钟边界传输数据的方法,它们包括FIFO?法和脉冲展宽处理等同步方法。PeterAlfke应用工程主管ilinx公司mikem@isdmag.com数字电路设计工程师偏好稳定、易于设计及仿真的同步单一时钟系统,然而,有时也难免用到多时钟。在电信和数据通讯领域,将数据由一种时钟域传到另一种时钟域的情况很常见,这类设计要全面解决时序问题。两种不相关时钟并不一定会造成时序关系的混乱,虽然出现时序冲突的情况肯定不止一次,因此,在这种情形下,在异步边界之间准确地传输数据至关重要。采用经验证的设计技术可将存在问题的仲裁电路大幅减少,并且设计出可靠工作的电路。应遵循的设计原则尽管设计工程师偏好同步电路,但如果一个系统中存在多个时钟,要确保时钟边界的设计成功,设计工程师就必须遵循若干重要原则:1.不要同时对一个以上的并行触发器中的异步输入进行同步处理。由于在同步触发器窗口建立期间异步输入经常会改变,而且给定的两个触发器不可能完全一致(即便在同一芯片内的触发器)。这样迟早会出现这样的情况:当一个时钟沿来临时,一个触发器输入被当成“1”,而另一个触发器被当成“0”。这种反常的情形会引起很多麻烦,因而需要将设计改为只使用一个时钟同步触发器。然而,即使采用单个同步触发器也会出现逻辑异常现象,出现这种情形的可能性很小,但的确存在,因为当触发器的主锁存器接收的信号进入平稳状态前,异步输入在极短的建立时间窗口内发生改变,这样触发器就会进入亚稳态。触发器即使进入亚稳态状态,也会很快进入稳态。只要触发器有几纳秒的建立时间,设计工程师就能解决这个亚稳态问题。因为输入数据中时序不一致,所以采用何种方式让触发器稳定并不重要。亚稳态问题并非指输出结果数据的不确定性,而是指输出变化的时序不确定性。握手通信方式当并行数据通过时钟域边界时,采用什么办法能够解决稳定问题?传统的处理办法是生成一个标记,然后采用握手方式来处理(图1)。当发送电路要发送并行数据时,它会在READY信号上产生一个上升沿,即在触发器F上设立标记告诉接收电路发送数据已经准备就绪。接收电路将持续扫描触发器F,当检测到标记变为高电平时便接收稳定的并行数据,然后产生用于设置触发器A的ACK上升沿。它使触发器F复位,然后触发器F使触发器A复位。这种独特的设计不考虑传输和接收之间任意相位及频率的关系,这通常要求在两个触发器之间的设计采用合理的约束竞争条件。在触发器F和触发器A复位期间,可以把一个合理的环路延迟插入。在某些特殊设计中,这种延迟可在发送期间,也可以在接收期间插入。这种传统的握手通讯方式要求通讯双方检测标记F的状态。发送电路只能在F为低电平时才改变并行数据,而接收电路只能在F为高电平时接收数据,这种方式虽然安全但数据传输率低。然而,还能找到在异步时钟边界更快地传输数据的其它方法。当接收时钟比输入数据的变化快得多时,就要对带有接收时钟的异步字进行双倍缓存,并在两个寄存器中对数据进行识别校验(图2)。同样,如果在接收时钟之前或在接收时钟周期内,异步数据时序未发生变化,则两个寄存器里都保存相同的有效数据。识别比较器也可用作跳变检测器,因为在异步数据发生变化时它会停止工作。如果异步数据是二进制计数器,这种双倍缓存电路甚至可用来处理与读时钟周期速度同样快的计数器的变化。要修正识别比较器使其能接受识别数据。如前所述这种电路能拒收计数器跳变时可能俘获的错误数据,但允许读取电路在一个计数器时钟周期后开始读操作,此外,改变比较器窗口也能增加这种容错性。向FIFO输入数据当接收时钟偶尔要读取比读取时钟周期变化更快的异步数据时,就必须插入一个异步先进先出(FIFO)存贮器作为一个弹性缓存,该FIFO存贮器由配备独立的读、写地址计数器的双口RAM和数据端口组成。双口RAM和FIFO存贮器的专用IC很多,在FPGA(如Xilinx的Virtex)中也嵌入了双口RAM。FPGA双口RAM深度从16位(用查表逻辑实现)到256位甚至4096位(由片上BlockRAM实现),输入和输出的时钟频率远远大于100MHz。真正双端口存贮器的每个端口的工作相互独立。写入端采用连续的写入时钟并通过激活WRITEENABLE端来写入数据。读取端采用连续的读取时钟并通过激活READENABLE端来读取数据。为了避免出现解码差错,建议两个端口都采用格雷码寻址方式。在FIFO中,如果两个端口采用相同序列,那么地址代码序列是不相关的。因为在任意的跳变中只有一个位改变,格雷码特别适合于时钟域边界的数据传输。空状态运行在真实的双端口存贮器中,每个端口都在其各自的时钟域中同步工作。两个时钟域只有在FULL和EMPTY等极端状态下才进行相互通讯,因而需要特别注意这两种标记。更确切地说,因为前沿都是同步信号,难以控制的仅仅是这些信号的后沿。写操作时FULL有效,这样信号前沿就与写入端口同步,这是唯一要用到标记的端口。读操作时EMPTY有效,这样信号前沿就与读端口同步,这也是唯一要用到标记的端口。只有这两个标记的后沿需要跨过两个时钟域。幸运的是,即使是高速系统也允许FULL和EMPTY的后沿存在一定的同步延迟,这种延迟仅会减慢特殊情况出现后系统重启动的速度。通常,FULL和EMPTY的两种极端情形可通过相同的条件,即写入和读取地址的等价性来表示。区分两者的一个简单方法是通过比较两个计数器中最重要的两个地址位来设置或清零两者共用的一个锁存器。可以把地址计数顺序用环形图来表示,二进制及格雷码中的两个最大位(MSB)表明了每个计数器的地址象限。四个位解码构成两个查找表,根据两个计数器的两个MSB的16种不同的组合,可以确定两个计数器之间的象限距:1.四位码代表写入计数器紧邻读取计数器后面的象限,解码为“可能将变为FULL”,并设置DIRECTION锁存器为“1”;2.另外四位码代表写入计数器紧靠在读取计数器之前的象限,解码为“可能变为EMPTY”,将DIRECTION锁存器清零;3.其他四位码代表读取和写入计数器位于同一象限,最后四位码则表明它们位于相反的象限。这八个代码不能为DIRECTION锁存器提供有用的信息,因而可以忽略。脉冲前沿谁先出现?在真正的FULL和EMPTY条件发生前,DIRECTION锁存器就已经稳定,因而DIRECTION锁存器的输出可用于把地址识别比较器输出变为FULL输出信号或EMPTY输出信号。如前所述,这些信号的前沿与利用这些前沿的时钟域本身是同步的。在写入时钟建立期间,不能出现经读取时钟初始化的FULL信号后沿,最容易的办法是在时钟上升沿展宽FULL信号使其在写入时钟的低电平期间不进入无效状态。当锁存器在写入时钟的下降沿正好准备锁存时,如果FULL信号在极小时间窗口内终止,这时依然可能进入亚稳态。大部分情况下,亚稳态输出可在下一个写入时钟的上升沿来到之前变为稳态。如果用户仍然对这种混乱感到担心,FULL信号可展宽为大于整个写入时钟周期,从而完全消除亚稳态错误。也可以让触发器产生脉冲后沿与写入时钟同步的FULL信号(图3),EMPTY信号也是对称的,并且以类似的方式展宽或做同步处理。这些设计假定读取和写入时钟处于自由运行状态,由各自的使能信号触发。如果没有自由运行的读时钟,该设计会通过一个有效的EMPTY-STRETCHED输出来锁定,EMPTY-STRETCHED输出要在读取时钟的高电平上结束。如果时钟不能自由运行,EMPTY-STRETCHED输出就将中断外部决策逻辑电路以防止读取时钟变高。这样甚至在数据已写入到FIFO,EMPTY-STRETCHED仍保持有效状态,同样,如果没有自由运行的写入时钟,FULL-STRETCHED的行为也类似。由相应的使能信号激活的可自由运行的时钟就可以避免出现这些问题(图4)。小型FIFO可通过16位SelectRAM实现,更深的FIFO可用Virtex的BlockRAM实现。典型的深度为256位,n倍16位宽FIFO只需n+1个BlockRAM加上三个逻辑电路模块(CLB)。n个BlockRAM可作为具有独立的读、写端口的双口256×16的RAM,每个都配备自身的时钟和时钟使能信号。附加的一个BlockRAM作为双口ROM查找表用于格雷码地址序列的查找,因此,它可作为对数据BlockRAM直接寻址的标志输出的读、写地址计数器。与传统逻辑电路相比,在ROM中生成格雷码地址速度更快,方法也更简单。DIRECTION锁存器、地址识别比较器以及上述扩展电路可通过三个CLB来实现。FIFO可以跟时钟频率超过100MHz的两个异步端口协同工作。由于用作地址计数器的双口ROM每侧都还有另外8个输出可用,这些输出用做预查询地址,从而有可能提前一个时钟周期对FULL和EMPTY解码,并对它们进行管线操作,这种方法使工作频率接近固有的200MHzBlockROM时钟频率。本文总结无论什么时候钟控触发器或锁存器对异步输入进行同步,输出都有可能出现有意外的延迟。这种延迟不仅可以在异步跳变与建立时间内发生冲突,也可以在主锁存器正在被禁止的时间窗口内发生,因此,会锁定输入数据。在这种情况下,触发器会进入一种对称平衡的瞬态亚稳态,此时,即使向完全平衡状态有极小的偏离都会造成输出向某个稳定状态回归,本文提供的解决方案可以有效地解决亚稳态问题。