目录
概述
复位的使用与性能之间的关系
SRL
乘法器和 RAM
一般逻辑
示例 1
示例2
示例3
示例4
使用加法器链(Adder Chains)而不是加法器树(Adder Trees)
最大化BRAM性能
HDL 编码风格
示例 5
综合工具设置
寄存器的一般用途
使用专用块寄存器
I/O 寄存器的使用
使用高扇出复制寄存器
示例 6
添加流水线
推断与实例化
时钟使能和门控时钟
嵌套的 If-Then-Else、 Case 语句和组合 For 循环
层次结构
结论
主要来自Xilinx《WP231,HDL Coding Practices to Accelerate Design Performance 》。
实现FPGA 设计最大性能化的一个重要因素是正确的RTL 编码设计。在实现RTL 级设计时做出的某些看似很小的决定可能意味着在低于 100 MHz 的设计和高于 400 MHz 的设计之间存在较大的性能差异。
可靠的设计性能是在设计过程中仔细考虑了许多因素的结果。首先,必须选择最适合设计的硬件平台。接下来,需要学习选择的器件架构以及综合工具的特性。最后,这也是本文档的主题,必须编写高效映射到目标器件的 HDL 代码。可以在网络上找到详细说明这些主题的资源。本文档通过介绍编码风格和小提示来提高设计性能,且重点关注后者。重申了正确的 FPGA 编码惯例,并介绍了直接适用于最新 Xilinx FPGA 架构的鲜为人知的技术。
很少有因素能像复位那样对性能、面积和功耗产生如此深远的影响。 一些系统架构师指定为系统使用全局异步复位,其目的仅是在上电时进行电路的初始化。然而,这对于FPGA 设计来说不是必需的。对于 Xilinx FPGA 的架构,复位的使用和复位类型会对设计性能产生深远的影响。复位策略可以是:
当前,所有的Xilinx FPGA 架构都能够将查找表 (LUT) 元素配置为逻辑、 ROM/RAM 或 SRL。综合工具可以从 RTL 代码中推断出这些结构中的任何一种;然而,如果使用了更好性能的移位寄存器 SRL,就无法在代码中实现复位,因为 SRL 库组件没有复位功能。在推断移位寄存器的代码中使用复位需要多个触发器或 SRL 周围的附加逻辑以实现复位功能。如图 1 所示,不对移位寄存器进行复位的代码通常会在输出上产生单个寄存器,这对于面积和性能而言是最佳的。
使用复位与不使用复位相比,对面积和功耗的影响则更为明显,但对性能的影响则不太明显。当用触发器构建移位寄存器时,移位寄存器的性能通常并不重要,因为寄存器之间的时序路径(触发器的时钟到输出、相关的布线延迟以及设置下一个触发器的时间)通常不足以成为设计中最长的路径。然而,增加的资源消耗(触发器和布线)却可能对设计其他部分的布局和布线选择产生负面影响,这会导致设计中其他路径的布线延迟更长。在向 SRL 添加额外逻辑以模拟复位功能的情况下,该逻辑的一部分出现在 SRL 的时钟输出上,从而增加了数据到达其目标逻辑所需的时间,从而降低了性能.
小技巧:避免对移位寄存器进行复位,因为它可以阻止推断出面积和性能更优的 SRL 库单元。
当前,所有的Xilinx FPGA 架构都包含专用的算术资源。此类资源可用于执行乘法,就像在许多 DSP 算法中一样,但也可用于其他应用,例如桶形移位器(barrel shifter)。
同样,几乎每个 FPGA 设计都使用各种大小的 RAM,无论何种应用。当前所有Xilinx FPGA 都包含BRAM 元素,这些元素可以实现为 RAM、 ROM、大型 LUT,甚至是一般逻辑。同时使用乘法器和 RAM 资源可以产生更紧凑和更高性能的设计。
复位类型的选择会影响设计的性能。乘法器模块和 RAM 寄存器都只包含同步复位;如果为这些功能编码了异步复位,则不能使用这些块中的寄存器。这对性能有严重影响。 例如,使用针对具有异步复位的最快 Virtex™-4 器件的全流水线乘法器可以产生大约 200 MHz 的性能。重新编写代码以使用同步复位可以将性能提高一倍以上,达到 500 MHz。
与乘法器类似, Virtex-4 块 RAM 具有可选寄存器。当使用这些输出寄存器时,它们可以减少 RAM 的时钟输出时间并提高整体设计速度。这些可选寄存器没有复位端口;因此,如果代码中使用了复位,则无法启用输出寄存器。
将 RAM 用作 LUT 或通用逻辑时会出现第二个问题。有时,出于面积和性能的原因, 将配置为 ROM 或通用逻辑的多个 LUT 压缩到单个块 RAM 中是有利的。这可以通过手动指定这些结构或通过约束综合工具将逻辑设计的部分映射到未使用的BRAM 资源来自动完成。由于BRAM 的复位配置,只有在使用同步复位(或无复位)时, 才可以映射通用逻辑而不改变设计功能。
小技巧:避免异步复位,因为它会阻止将寄存器打包到专用资源中并影响性能、利用率和工具优化。
异步复位也会对通用逻辑结构的性能产生影响。由于所有Xilinx FPGA 通用寄存器都包含将置位/复位编程为异步或同步的能力,因此可以看出使用异步复位没有任何损失;这种假设通常是错误的。图 2 中的代码示例说明了使用异步复位将如何抑制优化。如果不使用异步复位,则此类信号将使用的资源可用并可用于优化驱动该寄存器的其他同步路径(图 3 中的 FDRSE)。
为了实现异步复位代码,综合工具必须为数据路径推断出两个 LUT,因为要使用五个信号来创建这个逻辑。图 2 还显示了此代码的可能实现:
//异步复位
always @ (posedge CLK, posedge RST)
if (RESET)
Q <= 1 ' b0 ;
else
Q <= A | ( B & C & D & E ) ;
用同步复位重写相同的代码使综合工具在实现该功能时更加灵活。图 3 还显示了代码的可能实现:
//同步复位
always @ (posedge CLK)
i f (RESET)
Q <= 1 ' b0 ;
else
Q <= A | ( B & C & D & E ) ;
通过图 3 的结果,综合工具可以识别任何时候 A 为高电平有效, Q 始终为逻辑 1 (OR 功能)。现在将寄存器 (FDRSE) 配置为同步设置/复位操作,该设置现在可以自由地用作同步数据路径的一部分。
为了进一步说明异步置位或复位对性能的影响,可以检查一个具有 8 个信号的更复杂的函数。要实现此功能,至少需要 3 个 LUT。代码的可能实现如图 4 所示:
//异步复位
always @ (posedge CLK, posedge RST)
i f (RESET)
Q <= 1 ' b0 ;
else
Q <= ( F | G | H) & (A | ( B & C & D & E ) )
图 5 显示了使用同步复位编写的相同代码;还提供了代码的可能实现。
//同步复位
always @ (posedge CLK)
i f (RESET)
Q <= 1 ' b0 ;
else
Q <= ( F | G | H) & (A | ( B & C & D & E ) )
同样,图 5 中的最终实现不仅使用更少的 LUT 来实现相同的逻辑功能,而且由于几乎每个创建此功能的信号的逻辑电平减少,还能导致更快的设计结果。
由于设计中的大部分逻辑都是同步的,因此使用同步或完全不复位可以进一步优化设 计、减少面积和优化性能。
小技巧:
许多信号处理算法对输入样本流执行算术运算,然后对算术运算的所有输出求和。为了在 FPGA 等并行架构中实现求和,通常使用加法器树结构。加法器的数量取决于加法器树中的输入数量。加法器树中的输入越 多,需要的加法器就越多,从而增加了逻辑资源的数量和功耗。更大的树也意味着在树的最后阶段有更大的加法器;大加法器进一步减少系统的性能。
一种在保持加法器树的高性能的同时最小化设备利用率和功耗的方法是将加法器树实现为专用硅资源(参见图 6)。然而, FPGA 制造商不可能找到一种结构,既允许在专用资源中实现大多数加法器树,同时又将芯片面积保持在最小。
凭借其 DSP48 专用芯片列, Virtex-4 系列在实现求和方面采用了不同的方法。如图 7 所示,它涉及使用链式加法器而不是加法器树以增量方式计算总和。没有其他 FPGA 使用这种方法。这是最大化 DSP 算法性能和降低功耗的关键,因为逻辑和互连都完全包含在专用芯片中。流水线化时, DSP48 模块的性能在最快速度等级下为 500 MHz,与加法器的数量无关。级联端口与加法器/累加器的 48 位分辨率相结合,允许 当前样本计算以及迄今为止所有计算样本的总和。
为了利用 Virtex-4 加法器链结构,将加法器树描述替换为加法器链描述。 《UG073: XtremeDSP for Virtex-4 FPGA 用户指南》中详细介绍了将直接形式滤波器转换为转置形式或脉动形式的这一过程,并且通常涉及增加设计延迟。转换完成后,算法可以运行得比应用要求快很多。在这种情况下,可以通过使用多通道或折叠技术进一步降低设备利用率和功耗。这两种技术都有助于在较小的设备中实现设计,或者允许使用释放的资源 将功能添加到设计中。
小技巧:使用 Virtex-4 加法器级联代替加法器树。
在高效推断存储元素时,必须考虑影响性能的几个因素:
• 决定使用BRAM还是分布式 DRAM
• 是否使用输出流水线寄存器
• 避免异步复位
其他因素,即 HDL 编码风格和综合工具设置,同样会显着影响存储性能。
在推断双端口BRAM时,两个端口可以同时访问同一个存储器单元。例如,如果两个 端口同时在同一个存储单元上写入不同的值,则会产生冲突,并且无法保证存储单元的内容。
另一个常见的内存配置示例是内存输出的值取决于目标设备。最新的 Virtex 和 Spartan™ 系列具有三种可编程操作模式,可在写入操作发生时控制内存输出。设备 用户指南中提供了有关这些操作模式的其他信息。
如下所示,综合工具能够根据编码风格推断出BRAM。
/ / ' write first ' or transparent mode
always @ (posedge clk) begin
if (we ) begin
do <= data ;
mem [ address ] <= data ;
end else
do <= mem [ address ] ;
end
/ / ' read first ' or read before write mode ( slower )
always @ (posedge clk) begin
if (we )
mem [ address ] <= data ;
do <= mem [ address ] ;
end
/ / ' no change ' mode
always @ (posedge clk)
if (we )
mem [ address ] <= data ;
else
do <= mem [ address ] ;
end
小技巧:避免使用“read before write”模式以最大化BRAM 性能。
另一个可以显著影响BRAM性能的重要因素是综合工具的设置。一些综合工具(例如 Synpl icity®的 Synpl ify®)在 RAM 周围插入旁路逻辑,以防止 RTL 和硬件行为之 间可能出现的不匹配。当读取和写入操作发生在同一个存储单元上时,这个额外的逻辑旨在强制 RAM 输出为某些已知值。如果设计人员知道同一存储单元上的同时读写操作永远不会发生,则可以使用综合工具设置来防止将旁路逻辑添加到应用程序中 。额外的逻辑对存储性能有负面影响,因为它在存储的所有输出路径上增加了开销逻辑。消除或阻止附加逻辑可保持存储器性能。
/ / disable conflict avoidance logic
reg [ 7 : 0 ] mem [ 12 7 : 0 ] / * synthesis syn_ramstyle=no_rw_check* / ;
小技巧:检查综合工具设置、推断模板和限制,以最大限度地提高存储单元的性能。
FPGA 架构为每个 LUT 提供一个寄存器,在 I/O 和专用模块(例如存储器和 DSP)中提供额外的寄存器。使用这些资源对于实现最佳性能很重要。寄存器可用于加速设计性能的多种用途。它们可用于减少关键路径、关键网络扇出、设置和 I/O 或 专用块的时钟输出中的逻辑级数。
FPGA 具有用于大多数设计中使用的功能的专用电路,例如存储器或 DSP 模块。这些块具有可选寄存器。启用这些寄存器可通过减少设置、时钟输出和/或增加块时钟速度来加速块性能。综合工具会自动尝试将寄存器打包到这些块中,因为它可以节省面积、 提高功耗并提供最佳性能。设计人员可以使用约束来控制推断组件的综合工具映射。 然而,在实例化这些块时,需要启用为应用程序提供最佳性能的寄存器集;默认情况下,综合工具不会优化用户实例化的架构组件。在最佳情况下,应启用所有寄存器以获得最大性能;但是,延迟要求可能并不总是允许这样做。在这些情况下,设计人员有责任启用正确的寄存器集。例如, 当仅使用乘法器 (MREG) 和输入寄存器 (AREG 和 BREG) 时, Virtex-4 DSP48 单元(快速级)的时钟到输出设置为 1. 8 ns 和 2. 3 ns。保持相同的功能和延迟,但启用累加器输出寄存器 (PREG) 而不是 MREG,建立时间增加到 3 ns,而时钟输出缩短到 0. 6 ns。请参见图 8。
因此,重要的是要考虑:
小技巧:
所有 Xilinx FPGA 在 FPGA 输入和输出路径上都包含专用寄存器。通过利用这些寄存器,输入路径的建立时间和输出路径的时钟输出时间可以最小化,从而更容易满足捕获和向外部设备提供数据的时序要求。然而,有时使用专用 I/O 寄存器会对满足 FPGA 内的时序产生负面影响。它们的使用会延长内部逻辑的路由延迟。当需要满足 I/O 时序要求时,这些寄存器应放置在 I/O 中,或者当 I/O 时序要求允许时,它们应放置在 FPGA 架构中。一些综合工具,如 Synpl ify,会根据时序规范自动将寄存器放置在结构或 I/O 中。如果综合工具不支持自动布局或需要手动控制寄存器布局, 则必须执行以下步骤:
控制 I/O 寄存器使用平衡了数据路径进入和退出 FPGA 的时序与满足 FPGA 内部时序规范的需求。另一个值得注意的准则是在 HDL 代码的顶层描述 FPGA 的所有输入和输出端口上的寄存器。在使用分层设计方法实现 FPGA 时,在代码的顶层层次结构中指定寄存器可避免布局冲突。它还避免了为某些电路板原理图捕获工具不接受的端口描述创建分层名称。
小技巧:禁用将寄存器全局打包到 I/O 单元中。相反,仅将PCB上时序关键的寄存器约束到 FPGA I/O 单元中。
寄存器复制是一种通过复制寄存器来减少给定信号的扇出来提高关键路径速度的技术。 这为实现工具提供了更多的余地来放置和路由不同的负载和相关的逻辑。综合工具广泛使用这种技术。如果在时序报告中将具有长路由延迟的高扇出网络报告为关键路径,则应考虑对综合工具或手动复制寄存器的复制约束。以下的 HDL 代码说明了如何手动复制一次 64 负载信号。
( *EQUIVALENT_REGISTER_REMOVAL= "NO " * ) reg ce1 ,ce2 ;
/ / Clock enable register with 64 fanout
/ / replicated once
always @ (posedge clk)
begin
ce1 = ce ;
ce2 = ce ;
end
always @ (posedge clk)
begin
i f ( ce1 )
res [ 3 1 : 0 ] <= a_data [ 3 1 : 0 ] ;
i f ( ce2 )
res [ 63 : 3 2 ] <= a_data [ 63 : 3 2 ] ;
end
很多时候,需要添加额外的综合约束以确保手动复制的寄存器不会被综合工具优化掉。 在上面的示例中,使用了 XST 语法 (EQUIVALENT_REGISTER_REMOVAL)。
大多数综合工具使用扇出阈值限制来自动确定是否应该复制寄存器。调整这个全局阈值允许自动复制高扇出网络,但不能提供更精细的用户控制,即可以复制哪些特定寄存器。更好的方法是在特定寄存器或层次结构级别上应用属性,以指定哪些寄存器可以或不能复制。
小技巧:如果布局布线工具报告高扇出信号限制了设计性能,请考虑复制它们。
另一种提高性能的方法是用多级逻辑重构长数据路径,并将它们分布在多个时钟周期上。这种方法允许更快的时钟周期和增加的数据吞吐量,但代价是延迟和流水线开销逻辑管理。由于 FPGA 具有丰富的寄存器,因此额外的寄存器和开销逻辑通常不是问题。使用这种技术,数据路径跨越多个周期;因此,必须对设计的其余部分进行特殊考虑,以考虑增加的路径延迟。以下给出了一种编码风格,它在 32x32 乘法器的输 出上添加了六级寄存器。综合工具将这些寄存器流水线化到 Virtex-4 DSP48 的可选寄存器中,以最大限度地提高数据吞吐量。
parameter PIPE = 6 ;
reg signed [ 63 : 0 ] prod [ PIPE-1 : 0 ] ;
/ / 3 2x32 multiplier with 4 DSP4 8 ( PIPE=6 )
always @ (posedge clk) begin
prod [ 0 ] <= a * b ;
for ( i=1 ; i<=PIPE-1 ; i=i+1 )
prod [ i ] <= prod [ i-1 ] ;
end
assign mult_out = prod [ PIPE-1 ] ;
如果设计验证方法和工具集允许,则应考虑将重定时与流水线相结合以进一步提高设计性能。
重定时是一种综合或布局布线算法,可在组合逻辑中自动移动寄存器(寄存器平衡), 以改善时序,同时确保从设计的主要输入和输出中看到的相同行为。
重定时简化了 RTL 设计,因为无需更改任何代码即可提高性能。但是,重定时使设计验证更加复杂,因为寄存器名称、位置和功能不再与 RTL 描述匹配。因此,一些设计人员避免使用重定时。当重定时不是一个选项时,有关设备的知识有助于设计人 员描述 RTL 中的寄存器,以便这些寄存器有效地映射到可用的设备资源。
就性能而言,应始终考虑底层架构中的逻辑实现。还应考虑每段特定代码可能创建的 逻辑级别数和可能的信号扇出。必须选择 RTL 代码中寄存器的平衡布局,以便设计 的任何部分都不具有明显较大的逻辑电平或扇出部分。通过遵循这些指导方针,设计应该针对给定的逻辑映射充分发挥其性能潜力。
小技巧:通过平衡寄存器之间的逻辑级数来提高设计性能。在 RTL 代码中添加流水线级别,在相关时应用综合工具的重定时选项,或两者兼而有之。
通常最好从行为上描述设计并让综合工具将代码映射到 FPGA 中可用的门级资源。除了使代码更具可移植性之外,所有推断的逻辑对综合工具都是可见的,从而允许工具在函数之间 执行优化。这些优化包括:逻辑复制、重组和合并,或重新定时以平衡寄存器之间的逻辑延迟。当器件库单元被实例化时,综合工具默认不会优化它们。即使被指示优化器件库单元,综合工具通常也无法执行与 RTL 相同级别的优化。因此,综合工具通常只对 进出这些单元的路径进行优化,而不是通过这些单元。例如,如果一个 SRL 被实例化 并且由这个 SRL 驱动的逻辑锥很长,那么这条路径可能会成为一个瓶颈(在 SRL 部分 中提到)。 与常规寄存器相比, SRL 具有更长的时钟输出延迟。为了在提高其时钟输 出性能的同时保持 SRL 提供的面积减少,创建一个延迟比实际所需延迟少一个延迟的 SRL,最后一级在常规触发器中实现。
然而,在某些情况下需要实例化。这通常发生在综合工具映射不满足时序、功率或面积限制,或者无法推断 FPGA 内的特定特性时。通过实例化,设计人员可以完全控制综合工具。例如,为了获得更好的性能,设计人员可以仅使用 LUT 来实现比较器,而不是通常由综合工具选择的 LUT 和进位链元素的组合。在其他情况下,实例化是利用设备中可用的复杂资源的唯一方法。这可能是由于:
小技巧:
对于 CLB 寄存器,赛灵思通常建议使用专用时钟使能端口而不是门控时钟端口。门控时钟可能会导致毛刺、时钟延迟增加、时钟偏移和其他不良影响。使用时钟使能可以节省时钟资源并且可以改进设计的时序特性和分析。有几种方法可以使用设备上可用的时钟启用资源。要对整个时钟域进行门控以降低功耗,最好使用称为 BUFGCE 的启用时钟的全局缓冲资源(参见图 10)。
对于仅尝试在设计的小范围内暂停几个周期的应用,首选方法是使用 FPGA 寄存器的时钟使能引脚。本节中的第一个示例(参见图 11)说明了一种低效的门控时钟信号方式, 而第二个示例(参见图 12)显示了有效映射到时钟使能引脚的代码的修改版本。
assign GATECLK = ( IN1 & IN2 & CLK) ;
always @ (posedge GATECLK) begin
i f ( LOAD)
OUT1 <= DATA;
end
assign ENABLE = ( IN1 & IN2 & LOAD) ;
always @ (posedge CLOCK) begin
i f ( ENABLE )
DOUT <= DATA;
end
小技巧:
应避免嵌套的 if/case 语句以及其他语句中的语句。代码中的嵌套数量应该最少。 其他 if 语句中的 if 语句过多会使行长度过长,并且会抑制综合优化。通过将嵌套语句保持在最低限度,代码通常更具可读性、可移植性,并且可以更轻松地格式化以进行打印。
在 HDL 中描述 for 循环时,最好在数据路径中至少放置一个寄存器,尤其是当存在算术或其他逻辑密集型操作时。在编译期间,综合工具展开循环。如果没有这些同步元素, 综合工具会连接在循环的每次迭代中创建的逻辑,可能会导致非常长的组合路径并限制设计性能。
小技巧:
设计层次划分的选择通常取决于编写 HDL 代码的难易程度。然而,为了在性能方面实现最佳的整体设计层次结构,同时减少完成设计的整体时间,通常最好考虑设计优化、 实现方法和验证。在优化方面,大多数综合工具将逻辑设计层次结构视为“soft”,这意味着它们在可能的情况下保留层次结构,但在允许优化的地方分解层次结构或修改层次结构中的封装和逻辑内容。但是,如果采用增量设计或 KEEP HIERARCHY 等分层设计实践来进行验证,则无法跨逻辑边界执行优化。如果没有正确遵循某些准则,可能会导致具有更多逻辑级别或更多布局限制的不太优化的设计。即使使用非分层设计实现流程时,这些指南使其变得更容易,因此综合和布局布线工具更有可能在逻辑优化和布局方面做出最佳选择。以下列表简要说明了这些准则:
通过遵循这些简单的指导方针,所选层次结构干扰设计优化和性能的可能性要小得多。 如果在任何时候必须打破这些规则,我们鼓励调查实施设计中的关键路径,以确定修改层次结构是否可能对设计的最终性能产生影响。
综合和布局布线算法的最新进展使得实现特定器件的最佳性能变得更加简单。综合工具能够推断复杂的算术和存储描述并将其映射到专用硬件块上。它们还执行优化,例如重定时和逻辑以及寄存器复制。基于时序约束,布局布线工具现在可以重构网表并 执行时序驱动的封装和布局,以最大限度地减少布局和布线拥塞。然而,给定一个特 定的 RTL 描述,这些工具只能做很多事情来最大化性能。如果设计中需要更高的性能,那么一个非常有效的方法是进一步了解目标器件,调整工具约束和选项,并使用本文档中说明的编码指南。