AMD FPGA设计优化宝典:面向Vivado/SystemVerilog
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.4 四大基本原则

尽管FPGA设计越来越复杂,但只要遵循一些基本的原则,就可以提高综合质量、减轻布局布线压力、减少设计迭代次数、加速时序收敛进程。

1.4.1 硬件原则

FPGA设计采用的主要编程语言包括VHDL、Verilog和SystemVerilog,三者均属于硬件描述语言(Hardware Description Language,HDL),其中SystemVerilog以其在验证方面显示的强大功能又被称为硬件描述与验证语言(Hardware Description and Verification Language,HDVL)。“硬件描述语言”顾名思义,描述的对象是硬件电路,是实实在在存在的硬件电路,这要求我们必须采用HDL可综合的部分进行电路设计,遵循可综合的代码规范。设计者需要了解所用的HDL哪些是可综合的,哪些是不可综合的。例如,延迟语句无论是VHDL中的wait for语句还是Verilog或SystemVerilog中的“#延迟时间”(延迟时间为具体数字),均是不可综合的。同样,除法运算“/”也是不可综合的(只有当除数为2的整数次幂时才可综合,此时等效于右移操作)。从数据类型角度而言,实数(real)是不可综合的。

相比于软件编程语言如C/C++,HDL具有两大特征:并发性和时序性。并发性体现在同一模块中的不同进程(VHDL中的process,Verilog中的always,SystemVerilog中的always_ff、always_comb和always_latch)是同时执行的,这反映了硬件电路的特征——一旦上电,同时工作;时序性则体现了不同数据路径在时钟作用下的相互关系及时序路径与控制路径的关系。时序是设计出来的,不是凑出来的,更不是测出来的。就这点而言,在开始编程之前,要有待设计电路的基本雏形。例如,要设计一个复数乘法器,就要先画出图1-36所示的硬件电路,图中D表示D触发器,第一个复数的实部和虚部分别为ar和ai,第二个复数的实部和虚部分别为br和bi。从图中也可以看出各数据路径之间的时序关系。“先有电路,再写代码”,RTL代码每一条语句都有与之对应的电路单元。

图1-36

硬件原则还要求我们对所选用的FPGA内部结构有所认识和了解,以确保RTL代码风格与FPGA内部结构相匹配,这样才能保证综合电路的质量。例如,7系列FPGA中的触发器复位信号只支持高有效,如果代码中的复位是低有效就会消耗额外的查找表(用于逻辑取反),而UltraScale/UltraScale+FPGA中的触发器则既支持高有效又支持低有效;7系列FPGA中的DSP48不支持异步复位,因此,如果代码中描述的乘法器使用了异步复位,那么相应的触发器是无法被吸收到DSP48内部的。

综上所述,硬件原则要做到:

(1)使用可综合的HDL代码描述电路。

(2)先有电路,再写代码。

(3)RTL代码风格与所选FPGA内部结构相匹配。

1.4.2 同步原则

同步原则指的是整个设计采用同步时序电路,“同步”意味着设计中的所有逻辑单元“步调保持一致”,即所有电路在同一时钟沿的触发下同步地处理数据。这样看来,设计中只允许存在一个时钟,我们把这种“同步”称为狭义的同步。毕竟,随着芯片规模的增大,设计复杂度的增加,设计中的时钟个数也越来越多。例如,外部存储器接口时钟、以太网接口时钟、PCIE接口时钟、PS侧时钟、PL主时钟等。因此,我们又引入了广义的同步。这里我们先给同步时钟下个定义。所谓同步时钟是指时钟组(一个时钟组至少有两个时钟)内的时钟之间有明确的相位关系。反之,若时钟组内的时钟之间没有明确的相位关系,则认为它们是异步时钟。最典型的同步时钟场景是时钟组内的时钟是由同一个MMCM/PLL生成的,而异步时钟场景则是由不同MMCM/PLL生成的,如图1-37所示。图中clk0和clk1是同步时钟,clka和clkb是同步时钟,但{clk0,clk1}和{clka,clkb}是异步时钟。从而,模块1内存在同步跨时钟域电路,而模块2内则存在异步跨时钟域电路。显然,后者无论是电路设计还是时序约束都更为复杂。因此,广义的同步是指电路在同步时钟的作用下处理数据。

图1-37

尽管当前的FPGA设计允许存在多个时钟,但仍要遵循“时钟个数尽可能少”的原则。一方面可以简化跨时钟域电路,另一方面也有利于时序约束和时序收敛。这就要求我们在设计初期制定时钟方案时就要明确:设计中有哪些时钟,它们之间的关系如何,是否可以由同一个MMCM生成。

之所以遵循同步原则还因为相比于异步设计,同步设计有着明显的优点。首先,同步设计可以有效地避免毛刺的影响,增强设计的稳定性。组合逻辑可能会产生毛刺,如果毛刺仅存在于同步时序的数据路径中,那么受时钟驱动的触发器就可以过滤掉毛刺,因为触发器仅在时钟有效沿才会有动作,从而消除其对电路的影响。但如果将该组合逻辑的输出也连接到触发器的控制端,如作为触发器的异步复位/置位信号,当毛刺足够宽时,就可能导致触发器误动作。即使毛刺的宽度不足以驱动异步置位/复位端,也会造成触发器不稳定,甚至激发其产生亚稳态。其次,同步设计可以减少外部环境对芯片的影响。芯片的实际工作环境可能要比我们的实验环境更为恶劣,这也是我们做高低温实验的一个主要原因:检测当前设计是否能在不同环境下正常工作。此外,长时间运行也会使芯片自身温度升高,电压变得不稳定,芯片内部延时可能会发生微小变化。如果采用异步设计,时序要求比较严苛的电路将无法正常工作,这是因为异步逻辑设计的时序正确与否完全依赖于每个逻辑元件的逻辑延时和布线延时。最后,同步设计更有利于静态时序分析(Static Timing Analysis,STA)和验证设计的时序性能。这得益于同步设计的时序约束更为简单。即使对于同步跨时钟域路径,工具也可自动对其进行约束,当然有时会出现约束不合理的情形。

1.4.3 流水原则

流水原则要求我们在设计中使用流水线设计方法将数据处理流程分割为若干子步骤,使数据在这些子步骤中流动起来。

如图1-38所示,假定某处理流程可分解为读操作、计算操作和写操作三个步骤,采用流水线方式就是在这三个步骤之间插入流水寄存器。这样处理流程就由顺序方式变为流水线方式,如图1-39所示。带来的好处也是显而易见的:不仅提高了处理速度,而且降低了从输入到输出的总的时钟周期个数(Latency)。使用流水线技术是有要求的:数据流是单向流动,不存在反馈支路。流水线技术也体现了FPGA处理数据的特征:动态处理。

图1-38

图1-39

利用这个思想,从微观角度而言,我们可以把一条长路径切割为多段短路径,每段短路径之间插入流水寄存器以暂存中间数据,目的仍是将一个大操作分解为若干小操作,而每个小操作比大操作的延时要小,故可提高时钟频率;同时,每个小操作又可并行执行,故又能提高数据吞吐率。如图1-40所示,图中上部路径有6个LUT,仅从逻辑延时的角度来看,总逻辑延时为6TiloTilo为LUT从输入到输出的延时)。现将这6个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,下部则为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

1.4.4 面积和速度的平衡与互换原则

这里的面积指的是一个设计所消耗的FPGA的逻辑资源数量,直观的体现就是资源利用率报告。速度指的是设计在FPGA上稳定运行时所能达到的最高频率,也就是我们常说的Fmax,可间接地通过时序报告中的WNS(Worst Negative Slack:建立时间最小裕量。此值为0,说明建立时间收敛,为负则说明建立时间存在时序违例)换算获得。面积和速度这两个指标贯穿着FPGA设计的始终,是设计质量评价的终极标准。

面积和速度是对立统一的。要求一个设计以最少的资源为代价运行在最高的时钟频率下是不可行的。科学的设计目标应该是在保证设计满足时序性能(能够达到预期的Fmax)的前提下,尽可能地减少设计所消耗的资源;或者在限定的资源用量下,使设计的时序裕量更大,Fmax更高。这两种目标充分体现了面积和速度的平衡思想。

面积和速度直接影响设计的质量和成本。一方面,如果一个设计的时序裕量很大,Fmax很高,那么设计也就更为稳定,这对整个系统的质量是一种保障;另一方面,如果设计占用的资源很少,那么单位芯片上实现的功能模块就会更多一些,从而芯片的需求数量也会减少,整个系统的成本也随之下降。

面积和速度互换是FPGA设计的一个重要思想。从理论上讲,如果一个设计的Fmax远高于实际需求,那么就可以通过功能模块复用以减少整个设计消耗的逻辑资源,这其实就是用速度优势换取面积节约;相反,如果一个设计的Fmax要求很高,那么就可以通过并行复制多个操作模块以提高Fmax,这其实就是用增加面积换取Fmax的提升。那么,当面积和速度发生冲突时该如何解决呢?此时,我们应遵循“速度优先”的原则。

为进一步说明,我们以计算两个向量的内积为例,这两个向量长度均为4,表示为

A=[a0,a1,a2,a3]

B=[b0,b1,b2,b3]

两者的内积表示为

可见计算长度为4的向量的内积需要4次乘法和3次加法。

从数据流的角度而言,如果数据是顺序到达,则可采用图1-43所示方案,仅用1个乘加单元。如果数据并行到达,则可采用图1-44所示方案,4个乘法器并行工作,乘法器工作频率与输入数据采样率一致,此时数据吞吐率最大。如果依然采用图1-43所示方案就意味着需要将并行数据转为串行数据,乘法器的工作频率将是输入数据采样率的4倍。

图1-43

图1-43为串行方案,图1-44为全并行方案,前者消耗资源最少,但对于并行数据流Fmax将受限,后者Fmax最高,但消耗资源也最多。能否在面积与速度之间取得折中呢?答案是肯定的,这就是半并行方案,如图1-45所示。此时,对于4路并行数据,将其转为2路并行数据,即a0a2b0b0使用上部乘法器,a1a3b1b3使用下部乘法器。乘法器的工作频率将是输入数据采样率的2倍。

图1-44

图1-45