1.2 可编程逻辑常用设计思想与技巧
本节将讨论可编程逻辑设计中常用的4种设计思想与技巧,它们分别是乒乓操作、串并转换、流水线操作和数据接口同步。
FPGA的设计思想和技巧多种多样,篇幅所限,我们不可能将日常工作中涉及的所有设计思想和技巧都一一讨论,在此仅仅挑选了4个有代表性的方法加以简要介绍,希望读者能够通过日常工作实践,总结出更多的设计思想与技巧。
1.2.1 乒乓操作
“乒乓操作”是一个常常应用于数据流控制的处理技巧,典型的乒乓操作方法如图1-8所示。
图1-8 乒乓操作示意图
乒乓操作的处理流程描述如下。输入数据流通过“输入数据流选择单元”,等时地将数据流分配到两个数据缓冲模块。数据缓冲模块可以是任何存储模块,比较常用的存储单元为双口RAM(DPRAM)、单口RAM(SPRAM)和FIFO等。在第1个缓冲周期,将输入的数据流缓存到“数据缓冲模块1”。在第2个缓冲周期,通过“输入数据流选择单元”的切换,将输入的数据流缓存到“数据缓冲模块2”,与此同时,将“数据缓冲模块1”缓存的第1个周期的数据通过“输出数据流选择单元”的选择,送到“数据流运算处理模块”被运算处理。在第3个缓冲周期,通过“输入数据流选择单元”的再次切换,将输入的数据流缓存到“数据缓冲模块1”,与此同时,将“数据缓冲模块2”缓存的第2个周期的数据通过“输出数据流选择单元”的切换,送到“数据流运算处理模块”被运算处理。如此循环,周而复始。
乒乓操作的最大特点是,通过“输入数据流选择单元”和“输出数据流选择单元”按节拍、相互配合地切换,将经过缓冲的数据流没有时间停顿地送到“数据流运算处理模块”,被运算与处理。把乒乓操作模块当做一个整体,站在这个模块的两端看数据,输入数据流和输出数据流都是连续不断的,没有任何停顿,非常适合对数据流进行流水线式处理,所以乒乓操作常常应用于流水线式算法,完成数据的无缝缓冲与处理。
乒乓操作的另一个优点是可以节约缓冲区空间。比如在WCDMA基带应用中,1帧(Frame)是由15个时隙(Slot)组成的,有时需要将1整帧的数据延时一个时隙后处理,比较直接的办法是将这帧数据缓存起来,然后延时1个时隙进行处理。这时缓冲区的长度是1整帧数据长,假设数据速率是3.84Mbit/s,1帧长10ms,则此时需要缓冲区长度是38400bit。如果采用乒乓操作,只需定义两个能缓冲1个Slot数据的RAM(单口RAM即可),当向一块RAM写数据时,从另一块RAM读数据,然后送到处理单元处理,此时,每块RAM的容量仅需2560bit即可,两块RAM加起来也只有5120bit的容量。
另外,巧妙地运用乒乓操作,还可以达到用低速模块处理高速数据流的效果。如图1-9所示,数据缓冲模块采用了双口RAM,并在DPRAM后引入了一级数据预处理模块,这个数据预处理可根据需要是各种数据运算,比如在WCDMA设计中,对输入数据流的解扩、解扰、去旋转等。假设端口A的输入数据流的速率为100Mbit/s,乒乓操作的缓冲周期是10ms,下面分析一下各个节点端口的数据速率。
输入数据流A端口处数据速率为100Mbit/s,在第1个缓冲周期10ms内,通过“输入数据流选择单元”,从B1到达DPRAM1。B1的数据速率也是100Mbit/s,在10ms内,DPRAM1要写入1Mbit数据。同理在第2个10ms,数据流被切换到DPRAM2,端口B2的数据速率也是100Mbit/s,DPRAM2在第2个10ms被写入1Mbit数据。周而复始,在第3个10ms,数据流又切换到DPRAM1,DPRAM1被写入1Mbit数据。
图1-9 利用乒乓操作降低数据速率
仔细分析一下,就会发现到第3个缓冲周期时,留给DPRAM1读取数据并送到“数据预处理模块1”的时间一共是20ms。有的读者比较困惑于DPRAM1的读数时间为什么是20ms,其实这一点完全可以实现。首先在第2个缓冲周期,向DPRAM2写数据的10ms内,DPRAM1可以进行读操作;在第1个缓冲周期的第5ms起(绝对时间为5ms时刻),DPRAM1就可以边向500kbit以后的地址写数,边从地址0读数,到达10ms时,DPRAM1刚好写完了1Mbit数据,并且读了500kbit数据,这个缓冲时间内DPRAM1读了5ms的时间;在第3个缓冲周期的第5ms起(绝对时间为35ms时刻),同理可以边向500kbit以后的地址写数,边从地址0读数,又读取了5个ms,截止到DPRAM1第1个周期存入的数据被完全覆盖以前,DPRAM1最多可以读取20ms时间,而所需读取的数据为1Mb,所以端口C1的数据速率为1Mbit/20ms=50Mbit/s,因此“数据预处理模块1”的最低数据吞吐能力也仅仅要求为50Mbit/s。同理“数据预处理模块2”的最低数据吞吐能力也仅仅要求为50Mbit/s。换言之,通过乒乓操作,“数据预处理模块”的时序压力减轻了,所要求的数据处理速率仅仅为输入数据速率的1/2。
通过乒乓操作实现低速模块处理高速数据的实质是通过DPRAM这种缓存单元,实现了数据流的串并转换,并行用“数据预处理模块1”和“数据预处理模块2”处理分流的数据,是面积与速度互换原则的又一个体现。
1.2.2 串并转换
串并转换是FPGA设计的一个重要思想,从小的着眼点讲,它是数据流处理的常用手段;从大的着眼点讲,它是面积与速度互换思想的直接体现。本章1.1.1小节“面积和速度的平衡与互换原则”的所有例子也都可以用来说明串并或并串转换的设计技巧。总的来说,将串行转换为并行,一般旨在通过复制逻辑,提高整个设计的数据吞吐率,其本质是通过面积的消耗提高系统工作速率;而将并行转换为串行,一般旨在节约资源,因为设计速度有足够余量,通过提高串行通道的工作速率而节约了面积,其本质是通过速度的提高节约芯片面积。希望读者不要狭隘地理解为串并转换仅仅是串行数据流和并行数据流之间的转换(当然这是串并转换的最常见形式),而应将串并转换作为一种设计思想,将它理解为一种广义的操作方法,前面反复强调的SERDES技术就是串并转换的一个最典型的体现。
数据流串并转换的实现方法多种多样,根据数据的排序和数量的要求,可以选用寄存器、RAM等实现。前面乒乓操作的举例,就是通过DPRAM实现了数据流的串并转换,而且由于使用了DPRAM,数据的缓冲区可以开得很大。对于数量比较小的设计可以采用寄存器完成串并转换,如无特殊需求,应该用同步时序设计完成串并之间的转换。比如数据从串行到并行,数据排列顺序是高位在前,可以用下面的编码实现:
prl_temp <= {prl_temp,srl_in};
其中,prl_temp是并行输出缓存寄存器,srl_in是串行数据输入。
对于排列顺序有规定的串并转换,可以用case语句判断实现;对于复杂的串并转换,还可以用状态机实现。串并转换的方法总的来说比较简单,在此不做更多的解释。
1.2.3 流水线操作
首先需要声明的是,这里所讲的流水线是指一种处理流程和顺序操作的设计思想,并非FPGA、ASIC设计中优化时序所用的“Pipelining”,关于Pipelining优化时序的方法在本章1.3.8节“使用Pipelining技术优化时序”有详细的介绍。
流水线处理是高速设计中的一个常用设计手段。如果某个设计的处理流程分为若干步骤,而且整个数据处理是“单流向”的,即没有反馈或者迭代运算,前一个步骤的输出是下一个步骤的输入,则可以考虑采用流水线设计方法提高系统的工作频率。
流水线设计的结构示意图如图1-10所示。
图1-10 流水线设计的结构示意图
其基本结构是将适当划分的n个操作步骤单流向串联起来。流水线操作的最大特点和要求是,数据流在各个步骤的处理,从时间上看是连续的,如果将每个操作步骤简化,假设为通过一个D触发器(就是用寄存器打一个节拍),那么流水线操作就类似一个移位寄存器组,数据流依次流经D触发器,完成每个步骤的操作。流水线设计时序示意图如图1-11所示。
图1-11 流水线设计时序示意图
流水线设计的关键在于整个设计时序的合理安排、前后级接口间数据流速的匹配,这就要求每个操作步骤的划分必须合理,要统筹考虑各个操作步骤间的数据流量。如果前级操作时间恰好等于后级的操作时间,设计最为简单,前级的输出直接汇入后级的输入即可;如果前级操作时间小于后级的操作时间,则需要对前级的输出数据适当缓存,才能汇入后级,还必须注意数据速率的匹配,防止后级数据的溢出;如果前级操作时间大于后级的操作时间,则必须通过逻辑复制、串并转换等手段将数据流分流,或者在前级对数据采用存储、后处理方式,否则会造成与后级的处理节拍不匹配。
流水线处理方式之所以频率较高,是因为复制了处理模块,它是面积换取速度思想的又一种具体体现。
1.2.4 异步时钟域数据同步
异步时钟域数据同步是FPGA/CPLD设计的一个常见问题,既是一个重点也是一个难点问题,很多设计工作时的不稳定都是源于异步时钟域数据同步不稳定。
一、两类异步时钟域同步的表现形式
异步时钟域数据同步也被称为数据接口同步,顾名思义,是指如何在两个时钟不同步的数据域之间可靠地进行数据交换的问题。数据的时钟域不同步主要有以下两种情况。
•两个域的时钟频率相同,但是相差不固定,或者相差固定但是不可测,简称为同频异相问题。
•两个时钟域频率根本不同,简称为异频问题。
二、两种不推荐的异步时钟域操作方法
首先讨论两种在FPGA/CPLD设计中不推荐的异步时钟域转换方法,一种是通过增加Buffer或其他门延时调整采样,另一种是盲目使用时钟正负沿调整数据采样。
(1)通过Buffer等组合逻辑延迟线调整采样时间。
在早期逻辑电路图设计阶段,有一些设计者养成了手工加入Buffer或非门调整数据延迟的习惯,从而保证本级模块的时钟对上级模块数据的建立、保持时间的要求。这些做法目前主要应用的场合有两种,一是使用分立逻辑元件(如74系列)搭建数字逻辑电路,另一种是在ASIC设计领域。目前使用分立逻辑元件搭建数字逻辑电路的场合一般为系统复杂度相对较低,系统灵活性要求不高的场合。在上述场合使用分立逻辑器件设计数字逻辑电路,由于可以使用的调整延时的手段相对有限,而且采用插入Buffer、数字延迟逻辑甚至两个非门等手段调整采样的Setup和Hold时间是可以接受的。而ASIC设计领域采用这种方法是以严格的仿真和约束条件作为强力支持的。
正如本章1.1.4小节“同步设计原则”所述,使用组合逻辑方法产生延迟,容易产生毛刺,而且这种设计方法的时序余量较差,一旦外界条件变换(环境试验,特别是高低温试验),采样时序就有可能完全紊乱,造成电路瘫痪。另外,一旦芯片更新换代,或者移植到其他器件族的芯片上,采样时延必须重新调整,电路的可维护性和继承性都很差。
(2)盲目使用时钟正负沿调整数据采样。
很多初学者习惯随意使用时钟的正负沿调整采样,甚至产生一系列不同相位或不同占空比的时钟,使用其正负沿调整数据。这种做法是不推荐的,原因如下。
•如果在一个时钟周期内,使用时钟的双沿同时操作,则使用该时钟的同相倍频时钟也能实现相同的功能。换句话说,一个时钟周期内,使用时钟的双沿同时操作,相当于使用了一个同相的倍频时钟。此时因为设计的时钟频率提升,所有相关的使用约束都会变得更紧,不利于可靠实现。
•在FPGA中,一般PLL和DLL都能较好地保证某个时钟沿的Jitter、Skew和占空比等各种参数指标,而对于另一个时钟沿的指标控制并不是那么严格。特别对于综合、实现等EDA的软件,如果没有明确对另外一个沿进行相关,这个沿的时序分析不一定完善,其综合或实现结果就不一定能严格满足用户期望的时序要求(如Setup、Hold时间等),往往造成在该沿操作不稳定的结果。
如果设计者并不十分清楚,同时使用上下沿,不如直接使用同相倍频时钟更加简单、明确、可靠;如果设计者十分清楚同一周期使用双沿的注意事项,附加了相应的约束,这种做法并非不可。
这里需要补充以下3点。
•使用者虽然使用了同一个时钟的两个沿,但没有在同一个周期内同时使用双沿,则不会增加时钟频率。
•关于ASIC的DDR和QDR。DDR、QDR本身就是利用了上下沿采样的原理,这是因为,存储器件高速发展,时钟速度已经成为存取器件的瓶颈,所以可用时钟上下沿操作缓解对Single edge RAM时钟振荡器的要求。但是大家必须清楚,DDR、QDR的时钟电路是专用高速设计电路,对时钟的正沿及负沿的Jitter、Skew和占空比等指标都有详细和明确的要求,这一点是和FPGA中的情况截然不同的。这是ASIC芯片中DDR和QDR的设计方法。
•关于FPGA内部的DDR、QDR接口。目前所有主流FPGA(Altera、Lattice、Xilinx等)都支持DDR接口,DDR是FPGA的一个重要应用。Altera和Lattice的DDR接口电路还支持自动调整DQS采样DQ的功能。DDR IP Core的情况如下:133MHz、166MHz比较常见,几乎所有的FPGA厂商都能提供,并且某些型号的FPGA上已经成功开发出200MHz时钟速率的DDR控制器。FPGA内DDR接口电路很多部分都是采用专用硬件电路设计的,如DQS采样DQ、DDR专用时钟电路(DLL或PLL)、DDR数据的Mux(复用)与Demux(解复用)等。FPGA的DDR接口电路通过专用硬件电路和相关的约束解决时序瓶颈,这与本节所述并非一类情况,与前文论述并不矛盾。
三、异步时钟域数据同步常用方法
下面分别介绍前面提出的两大类异步时钟域数据同步问题的解决方法。
(1)同频异相问题。
同频异相问题的简单解决方法是用后级时钟对前级数据采样两次,即通常所述的用寄存器打两次。这种做法有效地减少了亚稳态的传播,使后级电路数据都是有效电平值(关于亚稳态的概念,请参考本章1.2.4小节的论述)。但是这种做法并不能保证两级寄存器采样后的数据是正确的电平值,因为一旦Setup或Hold时间不满足,采样发生亚稳态,则经判决时间(Resolution Time)后,可能判决到错误电平值。所以这种方法仅适用于对少量错误不敏感的功能单元。
可靠的做法是用DPRAM、FIFO或者一段寄存器Buffer完成异步时钟域的数据转换。把数据存放在DPRAM或FIFO的方法如下:将上级芯片提供的数据随路时钟作为写信号,将数据写入DPRAM或者FIFO,然后使用本级的采样时钟(一般是数据处理的主时钟)将数据读出即可。由于时钟频率相同,因此DPRAM或FIFO两端的数据吞吐率一致,实现起来相对简单。
(2)异频问题。
可靠地完成异频问题的解决方法就是使用DPRAM或FIFO。其实现思路与前面所述一致,用上级随路时钟写上级数据,然后用本级时钟读出数据。由于时钟频率不同,因此两个端口的数据吞吐率不一致,设计时一定要开好缓冲区,并通过监控(Full、Half、Empty等指示)确保数据流不会溢出。
另外,Altera和数据采样相关的约束有Period、tsu、th和tco等约束,其详细含义和使用方法参见本书第4章“时序约束与时序分析”。
四、亚稳态
异步时钟域转换的核心就是要保证下级时钟对上级数据采样的Setup时间和Hold时间。如果触发器的Setup时间或Hold时间不满足,就可能产生亚稳态,此时触发器输出端Q在有效时钟沿之后比较长的一段时间内处于不确定的状态,在这段时间内Q端产生毛刺并不断振荡,最终固定在某一电压值,此电压值并不一定等于原来数据输入端D的数值,这段时间称为决断时间(Resolution time)。经过Resolution time之后Q端将稳定到0或1上,但是究竟是0还是1,这是随机的,与输入没有必然的关系,如图1-12所示。
图1-12 亚稳态产生示意图
亚稳态的危害主要体现在破坏系统的稳定性。由于输出在稳定下来之前可能是毛刺、振荡或固定的某一电压值,因此亚稳态将导致逻辑误判,严重情况下输出0~1之间的中间电压值还会使下一级产生亚稳态,即导致亚稳态的传播。逻辑误判导致功能性错误,而亚稳态的传播则扩大了故障面。另外,在亚稳态状态下,任何诸如环境噪声、电源干扰等细微扰动都将导致更恶劣的状态不稳定,这时这个系统的传输延迟增大,状态输出错误,在某些情况下甚至会使寄存器在两个有效判定门限(VoL、VoH)之间长时间地振荡。
只要系统中有异步元件,亚稳态就无法避免,因此设计的电路首先要减少亚稳态导致的错误,其次要使系统对产生的错误不敏感。前者要靠同步设计来实现,而后者根据不同的设计应用有不同的处理办法。
使用两级寄存器采样可以有效地减少亚稳态继续传播的概率。如图1-13所示,左边为异步输入端,经过两级触发器采样,在右边的输出与bclk同步,而且该输出基本不存在亚稳态。其原理是即使第一个触发器的输出端存在亚稳态,经过一个Clk周期后,第二个触发器D端的电平仍未稳定的概率非常小,因此第二个触发器Q端基本不会产生亚稳态。理论上如果再添加一级寄存器,使同步采样达到3级,则末级输出为亚稳态的概率几乎为0。
图1-13 两级寄存器采样降低亚稳态概率
使用图1-13所示的两级寄存器采样仅能降低亚稳态的概率,并不能保证第二级输出的稳态的电平就是正确电平。前面说过经过Resolution time之后寄存器输出的电平是一个不确定的稳态值,也就是说这种处理方法并不能排除采样错误的产生,这时就要求所设计的系统对采样错误有一定的容忍度。有些应用本身就对采样错误不敏感,如一帧图像编码,一段话音编码等;而有些系统对错误采样比较敏感,这类由于亚稳态造成的采样是一些突发的错误,所以可以采用一些纠错编码手段完成错误的纠正。