我们将重点集中在 C++ 描述的使用,其目标是利用 C++ 模板类来代表任意精度的整数类型以及利用模板功能来代表架构中参数化的模块。 图5给出总体设计方案,出发点是从MATLAB®功能描述中获得的C/C++参考代码。如图所示,在任何硬件目标平台中实现应用的第一步通常是重组C/C++ 参考代码。我们将“重组”表示为将原始C/C++ 代码以一种更适合目标处理引擎的格式进行重写(通常是为了使代码清晰明了、易于概念理解而不考虑最优性能)。例如,必须重新排列DSP处理器中的应用代码,以便算法可以高效地利用缓存。当目标器件是FPGA时,重组可能包括:重写代码用以表示可达到预期吞吐量的架构规范,或重写代码以高效利用FPGA的特定功能,例如嵌入式DSP宏。
图 5 C/C++ 改进型迭代设计方案
我们通过利用传统C/C++编译器(例如 gcc),并重新利用适用于C/C++参考代码校验的C/C++级测试台,可实现对 C/C++ 执行代码的功能校验。C/C++执行代码是高级综合工具的主要输入。但是,额外输入会显著影响生成硬件、及其性能和FPGA资源的使用数量。因此存在 2 个基本约束条件,分别为目标FPGA系列产品与目标时钟频率,它们都会影响生成架构中流水线级数的数量。 此外,高级综合工具可接受编译器指令(例如,在C/C++ 代码中插入注解),使设计者可以在不同C/C++代码段中应用不同的指令类型。例如,应用于循环(例如,循环展开)和其它数组(例如,指定哪些 FPGA 资源必须用于执行数组操作)的指令。 根据这些输入,高级综合工具生成输出架构 (RTL),并报告其吞吐量。然后设计者根据吞吐量的大小来修改指令,执行C/C++代码。如果生成的架构满足吞吐量方面的要求,则RTL输出用于FPGA实现工具 (ISE/EDK) 的输入。 只有在完成逻辑综合和布局布线之后,才报告可实现的最终时钟频率和FPGA资源使用数量。如果该设计不能满足时
序和FPGA资源限制这2方面要求,则该设计与预期设计不相符,那么设计者应修改C/C++执行代码或编译器指令。 SD高级综合实现 我们已经利用A u t o E S L的AutoPilot 2010.07.ft 工具实现了图1所示的WiMAX球形解码器的3个关键构建模块。需要重点强调的是,本方案所选择的算法与最近SDR会议论文中的算法一致,因此可以实现相同的BER。 在本节中,我们给出了用于该特殊实现的代码重写与编译器指令的具体示例。从MATLAB功能描述中获得的原始C参考代码大约有2000行,包括综合C代码与验证C代码。 代码只包括使用C内置数据类型的定点运算。一个对FPGA友好的实现几乎可以完成所有要求的浮点运算(例如 sqrt)。除了描述 FPGA 综合功能的C参考代码之外,还有一个完整的C级验证测试平台。我们从MATLAB描述中生成
输入测试矢量和重要的输出参考文件。 原始C / C + +参考代码符合MATLAB 规范的比特精度要求,并可通过由多个数据集构成的回归分析套件。该C/C++参考代码经历了不同类型的代码重组。例如,图5显示了3个我们已经实现的代码重组的例子。我们重新使用 C 级验证设施来检验 C/C++代码执行中的任何变化。而且,我们是在 C 级执行所有验证,而不是在寄存器传送级,这样可避免非常耗时的RTL仿真,从而有助于减少总体开发时间。 宏架构说明 代码重构的最重要部分是重写C/C++代码,以描述可有效实现特定功能的宏架构。换句话说,设计人员负责宏架构说明,而高级综合工具负责宏架构的生成。这类代码重组对得到的吞吐量和质量结果具有重大影响。就球形解码器而言,有几个这类代码重组的实例。例如,为了满足信道排序模块的高吞吐量要求,设计人员应使用C/C++来描述图2所示的宏架构。 这类C/C++代码由几个以数组为传递参数的函数构成。该高级综合工具可自动调用乒乓缓冲器中的数组,以实现在流
水线中并行执行多个矩阵计算模块。本级代码重组的另一个实例是决定特定模块的TDM结构中所使用信道的数量(例如,信道矩阵重排序模块使用5条信道,修正后的实部QR分解模块使用15条信道)。 图6是宏架构说明的一个实例。图3为描述球形检测器的C++代码片段框图。我们注意到图中有一条调用9个函数的流水线,其中每个函数代表图3中的一个模块。函数之间的通信通过传递数组来完成,这些数组被第5行和第7行的适当指令 (pragmas) 映射至数据流接口(不是 FPGA 嵌入式 BRAM 存储器)。
图 6 球形检测器宏架构描述
参数化的重要性 参数化是代码重写的另一个关键实例。我们广泛利用C++模板函数来表示架构中的参数化模块。在球形解码器的实现过程中,该类代码重写有几个不同实例。一个具体实例是应用于信道重排序模块的不同类型矩阵操作。图2所示的矩阵计算模块(4×4, 3×3与2×2)就包含不同类型的矩阵操作,例如矩阵求逆或矩阵相乘。将这些模块进行编码并作为 C++ 模板函数,模板参数即矩阵的行数与列数。 图7为矩阵相乘的C++模板函数。除了矩阵行数和列数这两个参数之外,该模板函数还有第三个参数,即MM_II(矩阵相乘初始化间隔),该参数用于指定二次连续循环迭代之间的时钟周期数量。第 9 行的指令 (pragma)用于对具体实例所需吞吐量进行参数化。这是一项很重要的功能,原因是它可对生成的微体系架构产生重要影响—也就是高级综合工具具备充分利用资源共享的能力,从而可以减少用于具体实现中的 FPGA 资源数量。例如,高级综合工具仅仅通过修改初始化间隔 (Initiation Interval) 参数并使用相同的 C++ 代码,即可在执行不同矩阵求逆(4×4, 3×3, 2×2) 模块的过程中自动实现不同层面的资源共享。
图 7 代码参数化实例
FPGA最优化 FPGA最优化是代码重写的最后一个实例。设计人员可以重写C/C++代码,以更高效地利用特定FPGA资源,从而可以改善时序并减小存储区域的使用。该类最优化方面的两个具体实例是比特宽度最优化与嵌入式DSP模块 (DSP48) 的高效使用。高效利用DSP48可以改善时序并提高FPGA资源利用率。 我们利用内置C/C++数据类型(例如short、int)来编写C/C++参考代码,同时利用18位定点数据类型来表示矩阵元素。我们已经利用C++模板类来表示任意精度的定点数据类型,因此可减少FPGA资源的使用并将时序影响最小化。 图8是一个先执行乘法后执行减法的C++模板函数,而输入操作数宽度是需要设置的参数。可将这两个运算操作映射至嵌入式DSP48模块中。在图8中,有两条指令指示高级综合工具用最多两个时钟周期来调度这些操作并使用寄存器来存储输出返回值。
图 8 针对 DSP48 有效利用的 FPGA 性能最优化
生产力度量指标 在图9中,我们绘出利用AutoESL的AutoPilot所生成设计的规模大小(即FPGA资源使用情况)随时间变化的曲线,并与传统系统生成器 (RTL)的实现过程相比较。利用高级综合工具,我们可以实现很多有效的解决方案,且这些解决方案的规模随时间而变化。因此,设计人员可根据代码重组的数量,在获取解决方案的速度与解决方案的规模大小之间做出权衡。另外,RTL 解决方案只有一种,而且开发周期较长。
图 9 FPGA 资源用量随着开发时间增加而下降
我们已经观察到可以用相对较少的时间来获得几个明显比传统RTL解决方案使用更多FPGA资源(例如区域)的综合解决方案。另一方面,设计人员也可自行决定在工具专家等级下工作,通过执行更高级的C/C++代码重组技术(例如特定FPGA的最优化),实现用更少的FPGA资源生成更多的解决方案。 最后,因为我们是在C/C++级执行所有验证,从而可以避免耗时的RTL。因此,在 C/C++ 级执行设计验证将明显缩短总体开发时间。 质量结果 在图10中,我们对比了分别利用高级综合工具与系统参考生成器(基本属于结构化的RTL设计,显示使用如DSP48模块的FPGA基元)这两种不同方法来实现的完整球形解码器,在其最终FPGA资源使用量和总体开发时间这两方面进行了比较。AutoESL开发时间包括工具学习、产生结果、设计空间探测与详细验证所需要的时间。
图 10 质量结果的度量标准体现了 AutoESL 优势。
为了更精确地比较,我们利用针对Virtex-5 FPGA的最新Xilinx ISE 12.1工具重新实现RTL参考设计。同样,我们利用针对同类FPGA的ISE 12.1来执行由AutoESL AutoPilot生成的RTL。图10显示AutoESL AutoPilot节约FPGA资源效果明显,主要是因为在实现矩阵求逆模块时实现了资源共享。 我们也观察到寄存器的使用数量明显减少,查找表 (LUT) 的使用量略有提高。产生这种结果的部分原因在于 AutoESL
实现过程中延迟线被映射至 SRL16(例如 LUT),而在系统生成器方案中,则利用寄存器实现上述功能。在其它模块中, 我们交替使用BRAM 与 LUTRAM,导致信道预处理器的 BRAM 使用率较低。 AutoESL AutoPilot完成对底层FPGA实现细节的抽象(例如时序与流水线设计)。与使用传统RTL设计方案相比,其产生的质量结果更具竞争力。C/C++级验证避免使用耗时的RTL仿真,从而可以减少总体开发时间。但是,对于具有挑战性的复杂设计而言,如果想取得卓越的效果,则必须给出优异的宏架构定义,且必须具备扎实的FPGA设计工具知识,还要有理解与解释FPGA工具报告的能力。 |