XUP-P3R 配备先进的无源散热器

白皮书

用一个网络实例比较FPGA RTL和HLS C/C++

概述

大多数FPGA程序员认为,高级工具总是发出更大的比特流,作为提高生产率的 "代价"。但是这总是真的吗?在本文中,我们展示了一个真实的例子,我们使用传统的RTL/Verilog工具创建了一个普通的网络函数,RSS,然后在相同的硬件上使用高级合成(HLS)。我们发现,令人惊讶的是:HLS方法实际上使用了更少的FPGA门和内存。这是有原因的。继续阅读,了解详情。

FPGA开发的HLS方法是只抽象出可以在C/C++环境中轻松表达的应用程序的部分。通过使用Vivado(Xilinx)或Intel(Quartus)工具,HLS工具流程基本上可用于任何BittWare板。

要想在HLS取得成功,重要的是要认识到你的申请中哪些部分会很合适。准则包括:

  • 目标用途一般是指以高级语言开始定义的IP块。一个数学算法会很有效,或者像我们的RSS块那样,一些网络协议处理。
  • 另一类用途是那些定义不明确的块,因此可能需要多轮的实现。这里最大的好处是允许HLS工具自动对产生的本地FPGA代码进行流水线处理,通常比快速手工编码流水线的阶段要少。另外,当需要修改手工编码的流水线时,一个并行路径上的延迟变化会对所有的东西产生连锁反应。使用HLS工具自动进行第二次流水线,从头开始,消除了这种头痛的问题。
  • 最后,HLS流程使FPGA品牌和速度等级之间的代码移植变得更加容易。这是因为HLS会自动生成适当数量的流水线阶段--这是你在使用Verilog或VHDL时需要手动指定的。

目前HLS的局限性很明显,它的范围只限于IP块。应用团队仍然需要其他组件的RTL,尽管利用像BittWare的SmartNIC Shell这样的RTL部分,用户可能能够完全在HLS中定义他们独特的应用。还应该注意的是,对于最简单的代码或主要由预先优化的组件组成的大型设计来说,HLS是一个糟糕的选择。

我们的应用:FPGA上的联网RSS

什么是RSS?RSS是 "接收方扩展 "的意思。它是一种散列算法,用于在多个CPU上有效分配网络数据包。RSS是现代以太网卡的一项功能,一般实现微软定义的特定托普利茨哈希。

托管我们RSS应用的环境是BittWare的SmartNIC Shell。SmartNIC Shell的设计是为了让用户在构建基于FPGA的网络应用时有一个良好的开端。它为用户提供了一个优化的基于FPGA的100G以太网管道,包括用于主机交互的DPDK。用户所需要做的就是把他们的应用作为一个IP块放入。

在这种情况下,BittWare也是用户,我们已经创建了RSS的FPGA实现。使用传统RTL方法创建RSS的团队和HLS团队都能够使用SmartNIC Shell作为他们的FPGA以太网框架,并集中于RSS应用本身。

BittWare的RSS实施

我们基于FPGA的RSS实现是专门基于DPDK源码树中的C代码,该代码的测试函数也可在源码树中找到。我们的RSS应用还使用了一个64条目的指示表,而不是更常见的128条目的表。对这项HLS研究来说,重要的是我们要转移到FPGA中的函数一开始是用C语言定义的,这符合我们HLS成功的首要标准--用C或C++定义。

使用图元对数据包进行分组

RSS函数的目标是在CPU之间分配数据包,将相关的数据包流放在一起。不同的Toeplitz密钥集提供不同的分配模式。然而,不管是什么密钥集,我们的RSS函数都使用每个数据包的源和目的IP地址以及源和目的端口作为输入。这四个部分结合起来称为4元组。

注意,对于我们的RSS应用,我们假设4元组已经被解析并添加到数据包的元数据中。另一个SmartNIC Shell模块处理这个数据包分类功能。我们称该模块为 "解析器",这将是BittWare白皮书的一个单独主题。

我们的RSS实现目前接受一个96位的分类字段--足够用于IPv4源/目的和端口的4元组。解析器为数据包中没有的字段提供了零;如果一个数据包不包括任何IP有效载荷,完整的96位元组字段就是零。

许多RSS实施方案使用5元组而不是4元组。这样做将需要额外的8位来容纳协议号。RSS的HLS用户可以很容易地通过微小的源代码修改来适应这种变化。这种快速适应从4元组到5元组的能力是HLS成功的第二条标准的一个例子--对多轮实施的要求。

FPGA开发工具术语

开发在FPGA内运行的IP,传统上使用最初为ASIC开发而创建的语言。关于如何称呼这些语言,目前还没有共识。有时人们使用 "RTL",代表寄存器传输语言。另一些人使用 "HDL",代表硬件定义语言。两种最流行的HDL是VHDL和SystemVerilog。BittWare内部使用这两种语言,但我们的大型项目使用SystemVerilog和它的完整验证功能集。

验证是FPGA设计过程的一个重要部分,也是ASIC设计的一个关键部分。ASIC行业成本的上升促使人们需要先进的验证语言和技术来确保第一道硅的成功。这种需求促使Verilog语言加入了HVLs(高级验证语言)的功能,并最终合并到目前的SystemVerilog IEEE 1800标准中。现代ASIC验证也朝着通用验证方法(UVM)的方向发展,该方法提供了一种建立测试平台的标准方法。

FPGA开发的不同经济性以及在实验室立即测试设计的能力减缓了UVM在FPGA开发者中的采用。然而,高密度FPGA日益增长的复杂性促使许多团体采用与ASIC设计流程中使用的相同的验证方法。在BittWare,我们对FPGA验证采取了一种流畅的方法。我们经常使用基于廉价或免费模拟器中的SystemVerilog或VHDL功能的简单测试平台。然而,在适当的时候,我们会根据SystemVerilog和UVM的全部功能集建立现代测试平台。

HLS,或称高级合成,是指在比HDL更高的抽象层次上运行的语言。在实践中,HLS通常指的是C或C++的专门版本。然而,也有其他的HLS语言。例如,BittWare发行的一些第三方IP是用BlueSpec编写的。所有这些HLS工具都倾向于提供一种简单的、按钮式的方法来生成模块级的测试平台。在系统层面上仍然需要UVM。

最后,在今天的最高水平,是OpenCL。它是一种为GPU芯片开发的并行编程语言,并被重新用于FPGA领域。今天,OpenCL的应用几乎完全是HPC,即高性能计算,它被用来实现计算算法,其运行速度比基于英特尔的服务器运行速度快。

HLS编码的性能

尽管使用HLS提供了一个类似于软件的工具流程,但是开发人员仍然必须学习以硬件为中心的概念,例如流水线和迭代间隔,这些概念是他们在为传统处理器编写C代码时可能没有接触过的。

HLS代码主要用于开发嵌入式设计的IP组件,通常是流水线式的。我们的RSS应用也不例外。对于RSS来说,最小的性能要求是每个512位的输入字的处理速度足以跟上饱和的100Gb/s的网络接口。这相当于每个时钟周期以300MHz的频率处理一个新字。这个频率是具有挑战性的,因为即使是最快的FPGA,其运行频率也不会超过400MHz。很明显,我们必须在每个时钟周期处理一个新的字。

这就引入了迭代间隔(II)的概念,它指的是流水线中某一特定逻辑完成所需的时钟周期数。对于RSS模块,我们要求每个时钟都有一个结果,即II为1。因此,我们需要了解如何编写代码以避免破坏这一要求。

导致II型病变的原因包括以下几点:

  • 当一个流水线的下一个输出需要一个流水线中另一个变量的未来结果时,就会产生循环间的依赖性,例如递归。简单的递归运算符(如累加器)是允许的,因为FPGA包含在一个时钟周期内完成这些计算的逻辑。然而,更复杂的递归将需要更高的II值。
  • RSS设计要求流水线的每个阶段在3.3ns内完成。HLS工具会在需要的地方插入注册,以确保每个阶段满足这个时间要求。然而,如果组合逻辑不能被流水线化,就不一定能做到这一点。深层组合逻辑的例子可以是多个嵌套循环的索引计算。
  • 如果目标时钟频率太高,而FPGA结构的布线路径太长,根本无法满足时序要求,那么II将增加。解决这个问题的方法是将逻辑分成两条路径,以一半的时钟频率运行。

代码的主要部分在所需的输入元组字数上循环,创建一个新的哈希值。在这里的例子中,我们使用了一个3个字的输入元组,其散列值为96比特。

RSS-C 代码截图

这段代码实现了RSS计算的核心。它与从DPDK源树中提取的原始代码保持不变。因此,就这个RSS块而言,所有的移植工作都是在定义该块的AXI接口,并在定义中加入pragma语句,如II。

如果输入长度是一个常数,FPGA可以完全解开两个循环,以创建完全流水线的代码。

为了将IP组件集成到智能网卡框架工作中,需要定义接口和控制平面,以及任何读取和写入外部接口的逻辑。智能网卡框架使用AXI接口协议进行组件间的通信。

C 代码实用程序

定义AXI接口和添加pragma语句导致了太多的代码行,无法在这里用图显示。完整的源代码文件可从BittWare获得。

由于Xilinx编译器的常量是以英特尔的字节顺序(little-endian),但网络协议使用的是网络字节顺序(big-endian),因此存在一个字节性的挑战。这并不影响性能或资源的使用,但需要在HLS中处理任何输入数据之前改变其字节序。

本地编程与HLS的对比:结果

我们有两个FPGA RSS实现的原因是我们的初始版本是用Verilog编写的。这是在我们正在评估的假设下发生的:本地FPGA编码总是导致最小的资源使用。然而,BittWare的一位工程师对这一决定提出了质疑,并在HLS中重新实现了RSS,以测试这一方法。他是对的,现在BittWare已经用HLS代码替换了我们SmartNIC Shell中的RSS模块和解析器模块。

两种RSS的实施方式

特征维罗格HLS C
CLBs44,4352,385
BRAM121
登记册52,3524,843
代码行数650459

两种实现方式的最大区别是Verilog/RTL版本使用了FIFO,而HLS C++版本没有使用。我们很惊讶地看到,通过转移到HLS,资源的使用量实际上下降了--这不是我们在所有情况下所期望的。

节省的时间呢?粗略地说,我们看到原生RTL版本的时间线为一个月,而HLS代码在一周内完成。

英特尔HLS与赛灵思HLS的比较

这个例子使用Xilinx HLS。然而,使用高级语言的一个关键优势是它们能够在一定程度上抽象出不同技术架构之间的基本差异。英特尔也有一个相当的编译器,它也可以将C++编译成门的RTL代码。

为了使用英特尔i++编译器编译相同的代码,需要对数据类型进行一些细微的改变,并对#pragmas进行改变。英特尔和赛灵思之间最大的区别是,英特尔使用Avalon流接口,而赛灵思使用AXI。这就需要一个简单的垫片接口来从一个转换到另一个。

共同模拟

一旦功能得到验证,调用协同仿真环境进行周期精确的RTL仿真是一项非常简单的工作。Vivado-HLS会自动生成一个RTL测试平台,它由原始C++代码生成的向量驱动。用户唯一需要修改的是处理他们设计中的任何无限循环或阻塞接口。RSS模块被设计成作为固件流水线的一部分无限期地运行。因此,模拟将永远不会完成,协同模拟将挂起。为了避免这种情况,我们将RSS代码的 "while (1) "主循环改为固定长度,足以消耗测试平台的所有输入,并足以产生所有需要的输出。

协同仿真提供了一个额外的信心,即RTL已经由工具正确生成,模块的时序特性符合原始设计参数。

协同仿真流程也可作为英特尔HLS工具栈的一部分。

通过IP块构建HLS

HLS工具流程需要对所使用的接口协议有内在的认识。BittWare的IP块通常使用高级可扩展接口(AXI)进行通信。具体来说,AXI4-Stream用来传递数据包,AXI4-Lite作为控制平面。

对于100GbE,BittWare使用AXI4-Stream接口,该接口为512比特宽,时钟频率为300MHz。与每个数据包相关的元数据都在自己的总线上,当数据包的TLAST信号被确认时,元数据在数据包结束时有效。数据包的元数据在不同的区块和不同的版本之间不断变化。它通常包括以下信息:

  • 数据包到达的物理以太网连接器的编号。
  • MAC发现的与数据包相关的任何错误
  • 一个80位IEEE-1588格式的时间戳,或者有时是一个缩短的64位格式的时间戳
  • 一个 "删除 "位,表示该数据包需要在下一次机会从流中删除。
  • 一个我们通常称为 "队列 "的数字,表示数据包的目的地。它是由管道中的一个IP块(甚至可能是这个块)计算的

我们对RSS块的控制平面包括:

  • 一个启用/禁用位
  • 托普利茨散列的20个16位密钥
  • 一个有64个条目的指示表
SmartNIC 外壳框图,突出显示 RSS IP 块

SmartNIC Shell框架的实施实例框图。这里的RSS块被替换成了HLS实现。

总结

今天的高层FPGA开发工具被设计用来减少上市时间和对硬件工程师的依赖。然而,使用这些工具总是带来应用性能的妥协--无论是速度还是硅资源,这种假设是错误的。

我们发现使用HLS为BittWare的SmartNIC Shell开发IP块,将开发时间从大约一个月缩短到一周。我们还发现,它实际上使用了较少的门电路来实现。

XUP-P3R板的所有者和SmartNIC Shell的用户可以获得RSS块的源代码。这是一个很好的例子,说明了如何在HLS代码中使用AXI接口。请联系BittWare代表以了解更多信息。

除了本地开发工具外,HLS还可用于所有BittWare FPGA板。我们还提供一系列支持OpenCL开发的板子,请点击这里了解更多