软件定义FPGA计算的新方法

作者: Stephane Monboisset PLDA公司 QuickPlay市场营销与业务开发总监 smo@quickplay.io

QuickPlay 的高级工作流程让软件开发人员迅速构建基于 FPGA 的高效应用。

随着物联网和大数据处理的崛起,人们对数据传输和处理的需求急剧增长,仅靠 CPU 再也不能满足这一指数级增长需求。添加更多处理器和更多虚拟机来运行给定应用并不能彻底解决这一问题,因为对给定应用而言,能够在多个 CPU 上并行处理的应用有限。另一方面,现场可编程门阵列 (FPGA)具有所需的 I/O 带宽和处理能力,这一点无论是从纯粹的处理角度考虑,还是从功耗的角度考虑都非常重要。FPGA 对数据中心设备制造商而言,长期以来一直颇具吸引力。英特尔近期收购了第二大FPGA 厂商,这一举措是纯 CPU 解决方案再也不能满足应用需求的又一力证。

FPGA 实现相当复杂,这也是阻碍其广泛采用的主要障碍。到目前为止,在基于 FPGA 的平台上开发应用的唯一途径仍是采用一些最底层的硬件实现方案。这不仅让软件开发人员这一庞大的潜在客户群无法使用 FPGA 器件,还让传统 FPGA 设计人员的日子越来越不好过。

近期涌现的 FPGA 设计方法以高层次综合(HLS)工具为中心,充分利用 OpenCL ™、C 和C++ 等软件编程语言的优势,为软件开发人员提供了沙盒效应,在大量应用中能从基于 FPGA 的硬件加速中大受裨益。但这些方法往往存在一个关键的不足,即无法让软件开发人员定义并配置最适合其应用的硬件基础架构。业界一直都在追寻高级工作流程的圣杯,从而无需 FPGA 专业技术即可在基于FPGA 的平台上实现应用。

PLDA 在过去五年中已经开发出一种这样的工作流程。称作 QuickPlay 的工作流程能够高效解决实现复杂性问题,为 FPGA 开发提供多种使用模式。但其价值的核心源头之一是它让软件开发人员将原本用于 CPU 的应用部分或全部地实现在 FPGA硬件上的方式。QuickPlay 能够全面发挥 FPGA 资源的作用,将这些功能强大而复杂的器件转化为软件定义平台,无需艰苦的硬件设计即能获得 FPGA 带来的优势。

试想一种可以细分为两项功能的软件算法: 其中一项功能用于数据处理,然后另一项功能用于数据的进一步处理。从软件角度看,这种实现方案相当简单,就是先调用 Function1(),接着再单独调用Function2(),使用指针来定位待处理数据的位置。

如果没有合适的硬件抽象工具流程辅助,在基于 FPGA 的硬件平台上实现这种算法需要软件开发人员处理图 1 所示的硬件设计(其中内核 1 和内核2 分别是 Function 1 和 Function 2 的硬件实现)。该硬件设计需要包含两个元素:控制层面和数据层面。

控制层面起着执行引擎的作用,用于生成时钟与复位、管理系统启动、编排数据层面运行以及执行所有维护功能。数据层面例化并连接处理元件元、内核 1 和内核 2 以及用于读入数据和写出处理后数据所需的必备 I/O 接口。虽然不同的应用会要求使用不同的 I/O 接口,不过在我们的实例中使用的是以太网和 PCI Express(PCIe)这些接口,如图1 所示。

图 1 — 使用传统 FPGA 工具实现两功能算法的详细硬件实现

图 1 — 使用传统 FPGA 工具实现两功能算法的详细硬件实现

无需硬件专业知识,软件开发人员使用编译软件功能 Function1() 和Function2()(一般用 C 或 C++语言编写)的 HLS 工具就可以轻松地生成内核 1 和内核 2 到采用 VHDL 或 Verilog 等的 FPGA 硬件描述中。但是设计中每一个从性质上不属于算法的其他元素(接口、控制、时钟及复位)都不能用 HLS工具生成,硬件设计人员必须将它们设计为自定义硬件描述语言功能或 IP。获得这些元素并将它们连接起来构成了另一个难题,因为部分元素可能并非是现成的,或是具有不同的接口(类型和大小)、时钟要求以及专门的启动顺序等。

QuickPlay 能够充分利用 FPGA 资源,将这些功能强大而复杂的器件转化为软件定义平台,无需艰苦的硬件设计即能获得由FPGA 带来的优势。

除了设计工作,同样具有难度的是实现工作。这包括将设计映射到选定 FPGA 平台上的资源、生成适当的约束以及确认在 FPGA 硬件上完成逻辑综合与实现后满足这些约束要求。在新的 FPGA 硬件上实现有效设计也需要耗费一名经验丰富的硬件设计人员数星期的时间。

因此,任何旨在使用自定义硬件帮助软件开发人员来增强其应用的工具必须能够:
• 从纯软件代码中创建功能硬件;
• 根据需要采用现有的硬件 IP 模块;
• 调用并创建所有的支持硬件(接口、控制、时钟等);
• 支持使用现成商用开发板以及自定义平台;
• 确保生成的硬件能自动建构校正,这样无需进硬件调试;且
• 支持仅使用标准软件调试工具即可调试功能模块。

PLDA 重新设计 QuickPlay 以满足所有各项要求,让纯软件开发人员以极小工作量就能指定、构建和集成 FPGA 到自己的软件架构中。

以软件为中心的方法
使用 QuickPlay 实现整个设计流程相当简单直观:
1. 开发硬件引擎的 C/C++ 语言功能模型。
2. 使用标准的 C/C++ 语言调试工具来验证功能模型。
3. 指定目标 FPGA 平台和 I/O 接口(PCIe、以太网、DDR、QDR 等)。
4. 编译并构建硬件引擎。

该流程看似简单,但如果要无缝地工作,关键在于保证生成的硬件引擎在功能上与初始软件模型完全相同。换言之,功能模型必须具有确定性,这样无论硬件实现方案的运行速度有多快,软硬件执行的结果都是完全一致的。

但令人遗憾的是大多数并行系统都属于非确定性执行。例如多线程软件执行取决于 CPU、操作系统以及运行在同一主机上的无关进程。多次运行相同的多线程程序可能会得到不同的行为。硬件中这样的非确定性将会是一场灾难,因为这样会要求在电气波形层面调试硬件引擎本身,从而妨碍工具为软件开发人员抽象硬件的目的。

QuickPlay 使用直观的数据流模型,能从数学角度保证可确定性执行,与执行引擎无关。该模型由称之为内核的并行功能组成,负责与流通道进行通信。因此它与软件开发人员在白板上勾勒应用草图关联紧密。为确保行为的确定性,这些内核必须彼此进行通信,以防发生竞态条件和死锁等数据冲突。实现这一要求的方法是使用具备下列特点的流通道:(1)基于 FIFO,(2)阻塞式读取和阻塞式写入,以及(3)点对点。

这些就是 PLDA 据以构建 QuickPlay 的计算模型—— 卡恩进程网络(KPN)的特点。图 2 的QuickPlay 设计实例描述了 KPN 模型。

图2 — QuickPlay 中的设计实例

图2 — QuickPlay 中的设计实例

任何内核的内容都可以是任意 C/C++ 语言代码、第三方 IP,甚至是 HDL 代码(对硬件设计人员而言)。QuickPlay 采用相当简单直观的设计流程(图 3)。

图 3 — QuickPlay 采用简单直观的设计流。

图 3 — QuickPlay 采用简单直观的设计流。

当您完成软件调试阶段,并且纠正了所有的功能问题,就无需在硬件层面上进一步开展调试。

下面详细介绍 QuickPlay 设计流程的每一个步骤。

步骤 1 : 纯软件设计。在这个阶段,您可以用C 语言添加并连接处理内核,创建自己的FPGA 设计,然后使用自己的主机软件来指定通信通道。QuickPlay 基于 Eclipse 的集成开发环境(IDE)通过简单的 API 提供 C/C++ 语言库,用于创建内核、流、流端口和存储器端口,以及从流端口和存储器端口读取/ 写入。

此外,QuickPlay IDE 还提供直观的图形编辑器,便于您拖放内核与其他设计元素并绘制流。

步骤 2 :功能验证。这一步的重点是确保步骤 1编写的软件模型能正确工作。实现的方法是先在桌面上编译软件模型,然后使用测试程序发送数据到输入以执行软件模型,最后验证输出的正确性。并行执行 FPGA 设计的软件模型,为每个内核提供独立的线程,以模拟实际硬件实现的并行性。

然后您可以使用标准软件调试方法和工具,如断点、检测点、分步执行以及格式化输出函数来调试软件模型。(在实现到硬件中之后您可能还想运行更多测试。我们将对此做简要描述。)从设计流程来看,这是您完成全部验证工作的步骤。一旦您完成这个调试步骤,您完成这个调试步骤,并且纠正了所有的功能问题,您就无需在硬件层面上进一步开展调试。

需要提醒的是: 功能模型完全不涉及任何硬件基础架构元素。上述实例的重点是简单的两功能模型。图1 中添加的系统构成(如通信组件、控制层面、时钟及复位)在这个建模和验证阶段完全不涉及。

步骤 3 : 硬件生成。这一步用于从用户的软件模型生成 FPGA 硬件。它涉及三个简单的操作:
1. 在 QuickPlay GUI 的下拉菜单中选择您想要实现到自己的设计中的 FPGA 硬件。QuickPlay 能够使用品种不断丰富的现成开发板来实现设计。这些开发板采用先进的赛灵思All Programmable FPGA、PCIe 3.0、10 Gb 以太网、DDR3 SDRAM、QDR2+SRAM 等。

2. 选择需要映射到设计输入及输出端口的物理接口(以及协议)。这些通过菜单都能方便选择。具体选择取决于用户选定的 FPGA 板件上提供的接口,例如 PCIe、10 Gb 以太网 TCP/IP 和 10 Gb 以太网 UDP。选择通信协议即自动调用实现连接所需的硬件 IP 模块以及其上分层的任何软件协议栈,从而完成整个系统的创建。

3. 启动构建流程这个过程包括运行 HLS 引擎(从 C 语言代码创建硬件),创建所需的系统硬件功能(我们原始实例中的控制层逻辑)和运行构建板件要求的硬件镜像所需的其他工具(例如赛灵思Vivado® 集成设计环境)。完成这个过程无需手动干预。

步骤 4 : 系统执行。这个步骤与步骤 2 中的功能模型执行(功能验证)相似,除了现在虽然主机应用仍然运行在软件中,但 FPGA 设计运行在选定的 FPGA 板件上。这意味着您可以从 FPGA 板件输入输出真实数据,从而进一步验证其功能的完整性。由于这样可以显著加快运行速度,而且因为您可以使用实时数据资源,您在这个阶段与在功能验证阶段相比可以运行数量多得多的测试。

步骤 5 : 系统调试。因为与功能验证阶段相比现在您可以运行数量多得多的测试,您可以发现在步骤 2 中未能发现的功能缺陷。那么您现在该如何调试呢?

如前文所述,您永远不必在硬件层面进行调试,即便缺陷是在在硬件中运行功能后发现的。由于 QuickPlay 保证软件模型和硬件实现之间的功能等效性,因此任何硬件版本中发生的缺陷也必然存在于软件版本中。这就是您无需在硬件中进行调试的原因;您只需要在软件域中调试就足够了。

作为由 QuickPlay 提供的抽象结果,算法保持纯粹性,着重处理数据操作,独立于底层通信细节。

只要您发现测试序列在硬件中失败,QuickPlay就能采集在设计输入端造成错误操作的事件序列,然后在软件环境中将其回放,以便您使用 Eclipse 调试器进行调试,从而找出缺陷的源头。

由于 QuickPlay 能自动为基础架构配置硬件,以便观察设计中的所有关键点,因此这样做的是可行的。您还可以禁用该基础架构以释放宝贵的硬件资源。图 4 所示即为添加了调试电路的实例系统。如果没有 QuickPlay,就必须插入某种调试基础架构并进行手动管理。而在使用 QuickPlay 的 情况下,这一切对软件开发人员来说都是自动化和透明化的。

图 4 — 自动创建调试基础架构

图 4 — 自动创建调试基础架构

整个流程就是先在软件中建模,然后在硬件中构建并测试系统。如果存在缺陷,将失败的测试序列导回软件环境中,在软件环境中调试,修改源代码,然后重复这一过程。与传统流程相比这能显著提高生产力。

步骤 6(可选): 系统优化。在您完成调试阶段后,就会拥有一个能够在 FPGA 开发板上正确运行的功能设计。不过您可能想要进行一些性能优化,而且这也是性能优化的合适时间,因为您已经知道自己的系统能正确运行。

首先应该考虑的优化是优化功能模型。有可能存在更多并行的机会。例如您可以尝试使用不同的办法来分解或重构各项功能。在这个层面优化可以带来显著的性能提升。勿庸置疑,使用 VHDL 或Verilog 设计来开展优化工作需要占用大量的时间,而在 C 语言中进行调整则非常迅速与简捷。

其次您可以尝试使用其他速度更快的 FPGA 开发板。因为从功能模型映射到开发板十分容易,尝试各种不同开发板并从中选优是件简单的事情。

第三项需要优化的对象是 QuickPlay 使用高级综合创建的硬件内核。虽然得到的硬件能保证正确高效地运行,不过其运行效率未必有硬件工程人员手动编制的硬件高。在这个阶段您有多种选择: 您可以优化代码和 HLS 设置来改善生成的硬件;可以使用 Vivado HLS 来生成更高效的硬件;或是让硬件工程人员手动编制 HDL 中最关键的模块。

这些优化步骤并非是强制要求,不过在可用的硬件资源有限、而您又需要提升硬件性能时不妨一试。硬件工程师可可协助开展这些优化工作。当您完成任何此类调整后,只需重复构建流程。

通用流通道
QuickPlay 提供的通用流 API 完全抽象并独立于底层物理通信协议。流数据通过 ReadStream() 函数接收,使用WriteStream() 函数。这些函数可用于在内核之间、向嵌入式或板级存储器、向嵌入式或外部主机 CPU 发送与接收数据,从而无需开发人员理解或管理底层低级协议即可提供开发板架构灵活性。

选择的协议决定了通过什么硬件接收与发送数据。目前 QuickPlay 支持 ARM®AMBA® AXI4-Stream、DDR3、PCIe( 具备 DMA 功能) 以及 TCP/IP ; 更多协议正在添加中,也可根据需求添加协议。选择所需的协议不仅是设置实现协议所需的硬件,也是支持较高级协议层所需的软件协议栈,如图 5 所示。

图5 — 选择所需的协议对所要求的硬件与软件栈进行设置。

图5 — 选择所需的协议对所要求的硬件与软件栈进行设置。

QuickPlay 负责管理这些读写的具体实现(大小、对齐、封送处理等)。ReadStream() 和 WriteStream()语句最重要的特征是它们是阻塞式的: 如果遇到这两种语句之一,在所有预期的数据读或写完成前,不会进入到下一语句。这对实现算法的确定性有重要意义。

通用的 ReadStream() 和 WriteStream() 语句与实际底层协议硬件的“绑定”借助 QuickPlay 库发生在运行时间中。这不仅能防止通信细节让软件程序杂乱无章,还能够提供模块化和可移植性。改变通信协议无需对实际内核代码或主机软件做任何改动。Read-Stream() 和WriteStream() 语句会自动绑定到任何已选定的协议,不会给程序语义造成影响。

在由 QuickPlay 提供抽象的影响下,软件算法能保持纯粹性,着重处理数据操作,完全独立于底层的通信细节。

量产质量级输出
根据使用的 HLS 工具,通过学习编码方式,提高硬件生成效率,结果质量可得以进一步提高,不过这只是一种选择。

虽然在其他情况下您使用的硬件平台可能被简单地视为一种原型设计平台,但是您使用 QuickPlay创建的系统具有生产价值。在过去,从纯粹的软件设计到硬件辅助或纯硬件设计一般需要数月时间。QuickPlay 将其缩短为数天时间。

QuickPlay 方法实现了长期以来寻求的让软件开发人员为其全部或部分应用开发硬件设计的目标。通过在自己熟悉的领域中开展工作,软件工程师能够根据需要来使用定制硬件,自动生成工作效率更高的硬件强化应用,而且与手动设计相比能提前数月实现量产。