1.4.3 流水原则
流水原则是指要求我们在设计中使用流水线设计方法将数据处理流程分割为若干个子步骤,使数据在这些子步骤中流动起来。
如图1-38所示,假定某处理流程可分解为读操作、计算操作和写操作3个步骤,采用流水线方式就是在这3个步骤之间插入流水寄存器。这样处理流程就由顺序方式变为流水线方式,顺序方式和流水线方式如图1-39所示,这样带来的好处也是显而易见的,不仅提高了处理速度,而且降低了从输入到输出的总时钟周期个数(Latency)。使用流水线技术是有要求的:数据流是单向流动,不存在反馈支路。流水线技术也体现了FPGA处理数据的特征:动态处理。
图1-38
图1-39
利用这个思想,从微观角度而言,我们可以把一段长路径切割为多段短路径,在每段短路径之间插入流水寄存器以暂存中间数据,目的仍是将一个大操作分解为若干个小操作,而每个小操作比大操作的延时要小,因此可以提高时钟频率,同时,各个小操作可以并行执行,因此又能提高数据吞吐率。如图1-40所示,图中,上部路径有6个LUT,仅从逻辑延时的角度来看,总逻辑延时为6Tilo(Tilo为LUT从输入到输出的延时)。现将这6个LUT分为两组,在两组LUT之间插入寄存器,从而形成两条时序路径,每条时序路径的逻辑延时降低至3Tilo。这实际上是将路径的逻辑级数由6降至3。从这个角度而言,流水线技术也是修复时序违例的一种方法。
图1-40
FPGA芯片内触发器的个数远远多于LUT的个数,如UltraScale SLICE内有8个LUT,但有16个触发器。因此,对于逻辑级数较高的路径,可通过插入流水寄存器的方法改善其时序性能。那么,如何判断逻辑级数是否过高呢?通常,一个“LUT+一根走线”的延迟为0.5ns(经验值,适用于Xilinx 7系列FPGA和UltraScale/UltraScale+FPGA),假定寄存器时钟周期为T,那么该路径所能承载的最大逻辑级数为T/0.5,也就是2T。如果逻辑级数大于2T,而时序未能收敛,就可以怀疑时序违例跟逻辑级数较高有关。
尽管流水寄存器对改善时序有所帮助,但并不意味着流水寄存器越多越好。事实上,过重的流水会导致触发器的利用率增加,这也意味着触发器控制集增加,从而会引发布线拥塞。同时应注意,增加流水寄存器会导致Latency(Latency的具体含义请参考本书1.5节)发生变化。从图1-40中不难看出,上部路径Latency为2,下部路径Latency为3。
流水线方式的另一种形式是乒乓操作,如图1-41所示。输入数据流通过1:2解复用器分时流向两个数据缓存模块。为便于说明,假定每4个数据构成待处理的一帧数据,形成如图1-42所示的时序图。当selx为0时,数据流向数据缓存模块1,相应的数据缓存模块1的写使能信号wen1被抬高,将第一帧数据A0~A3写入;当selx为1时,数据流向数据缓存模块2,相应的数据缓存模块2的写使能信号wen2被抬高,将第二帧数据B0~B3写入,同时,缓存模块1的读使能信号被抬高,开始从数据缓存模块1中读出第一帧数据A0~A3,并传送给数据预处理模块1。当selx再次为0时,数据又流向数据缓存模块1,向数据缓存模块1写入第三帧数据C0~C3,同时,开始从数据缓存模块2中读出第二帧数据B0~B3并传送给数据预处理模块2,如此循环。从而,数据缓存模块1中存储的永远是奇数帧数据,数据缓存模块2中存储的是偶数帧数据。数据缓存模块1在执行写操作时,数据缓存模块2在执行读操作,而数据缓存模块1在执行读操作时,数据缓存模块2在执行写操作。这样,对两个数据预处理模块而言,只要在8个时钟周期内处理4个数据即可。这实际上减轻了数据预处理模块的时序压力。两个数据预处理模块的输出端连接2:1复用器,在sely的控制下即可将预处理结果不间断地传送给下游处理单元(在图1-42中,数据预处理模块的Latency为6)。
图1-41
图1-42