Intel®高层次综合编译器专业版: 最佳实践指南

ID 683152
日期 12/04/2023
Public
文档目录

4.1.6. Pass-by-Value接口

对习惯于针对CPU编写代码的软件开发人员而言,按值传递数组中的每个单元可能并不直观,因为这样通常会导致许多函数调用或大型参数。然而,对于以FPGA器件为目标对象的代码,按值传递数组单元可使FPGA器件上的硬件更小,更简单。

可以将向量加法实例编码为按值传递向量数组单元,如下所示。struct用于按值传递整个数组(包含8个数据单元)。

当您使用struct传递数组时,还必须执行以下操作:
  • 定义element-wise(两个张量之间的操作,在相应张量内的对应的单元进行操作)复制构造函数。
  • 定义element-wise复制赋值运算符。
  • hls_register存储器属性添加到定义中所有的struct成员。
struct int_v8 {
    hls_register int data[8];

    //copy assignment operator 
    int_v8 operator=(const int_v8& org) {
         #pragma unroll
         for (int i=0; i< 8; i++) {
             data[i]       = org.data[i]      ;       
         }
            return *this;
    }
    
    //copy constructor
    int_v8 (const int_v8& org) {
         #pragma unroll
         for (int i=0; i< 8; i++) {
             data[i]       = org.data[i]      ;       
         }
    }

    //default construct & destructor 
    int_v8() {}; 
    ~int_v8() {};
};

component int_v8 vector_add(
    int_v8 a,
    int_v8 b) {
    int_v8 c;
    #pragma unroll 8
    for (int i = 0; i < 8; ++i) {
    c.data[i] = a.data[i]
    + b.data[i];
    }
    return c;
}

该组件仅采用和处理向量a和向量b的8个元素,并返回向量c的8个元素。要计算实例的1024个单元,则需要调用该组件128次(1024/8)。在此前的实例中,组件包含流水线化的循环,再此该组件被多次调用,且每次调用都被流水线化。

以下图示显示编译该实例时System Viewer中生成的Function View。
图 28. 使用Pass-By-Value接口的vector_add组件的System Viewer Function View


该组件的延时为1,且其具有的循环启动间隔(II)为1。
通过英特尔 Quartus Prime编译流程编译 Intel® Arria® 10器件组件得到如下QoR指标:
表 6.  Pass-by-Value接口的QoR指标1
QoR Metric Pointer Avalon® MM Host Avalon® MM Agent Avalon® ST Pass-by-Value
ALMs 15593.5 643 490.5 314.5 130
DSPs 0 0 0 0 0
RAMs 30 0 48 0 0
fMAX (MHz)2 298.6 472.37 498.26 389.71 581.06
Latency (cycles) 24071 142 139 134 128
Initiation Interval (II) (cycles) ~508 1 1 1 1
1用于计算QoR指标的编译流程采用英特尔 Quartus Prime Pro Edition 17.1。
2 fMAX的大小由计算单个seed得出。
使用pass-by-value接口的vector_add组件的 QoR指标显示使用较少ALM,更高组件fMAX与延时和II的优化值。该情况下,II与组件调用间隔相同。可每个时钟周期启动一次新的组件调用。启动间隔为1时,在128个周期中处理128次组件调用,因此总延时为128。