DSP 多重运算匹配 - 2023.2 简体中文

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文

HLS 编译器会尝试识别加法-乘法、乘法-加法和 AMA 运算(以及减法-乘法、乘法-减法运算),使其分配与物理器件上 DSP 的相匹配。HLS 编译器会使用以下进程将运算与 DSP 匹配:

  • 内联函数(按需)
  • 提取常用子表达式
  • 匹配无扇出 add->mulmul->addadd->mul->add(其中,add 也可以是 sub)代码片段,这些代码片段满足 DSP 的位宽限制
  • 调度
  • 按 BIND_OP 编译指示的指引,选择 DSP 或 LUT 中的实现

HLS 编译器将运算或表达式与 DSP 实现相匹配的能力取决于:

  1. 数据类型和位宽
  2. 编码样式和表达式
  3. BIND_OP 和其他编译指示的使用

数据类型和位宽

DSP 匹配受限于目标器件上 DSP48 和 DSP58 的设计限制。请参阅UltraScale 架构 DSP Slice(UG579),了解针对 DSP48 的具体限制,并请参阅Versal 自适应 SoC DSP 引擎架构手册(AM004),了解针对 DSP58 的具体限制。

例如,在 Versal 器件中,DSP58 的端口宽度如下:

  • B 24 位
  • A 34 位
  • D 27 位
  • C 58 位
  • P 58 位

编码样式

代码的编写样式至关重要:

  • 位宽必须足够小以适应 DSP,包括中间结果
  • 不允许扇出,即使因常见的子表达式消除操作而导致的扇出也不允许。例如,由于抽取子表达式 a*b,导致以下代码与 DSP 分配不匹配:
    f1 = a*b+c;
    f2= a*b+d;
    提示: 为避免这一问题,请使用非内联函数,这些函数应精确包含要匹配的表达式。
  • 含指定时延的非内联函数(刘,时延为 2 的 MULADD)无法与 II=1 的累加器相匹配。原因是乘法器输入和加法器输入的就绪时间必须比产生累加输出早 2 个周期。在此情况下,MULADD 或 MAC 函数(如有)必须内联。

BIND_OP 和其他编译指示

对于 DSP 匹配,部分编译指示或指令可阻止在 DSP 中实现代码匹配,而其他编译指示或指令则可能有助于此。在以下代码示例中,BIND_OP 编译指示实际上阻止将 MULADD 表达式分配给 DSP。通过分配 mul 运算,它会阻止 HLS 编译器识别和分配 MULADD 表达式。在此情况下移除该编译指示将允许编译器完成分配。

static const int NFRAC = 14;
typedef ap_fixed<3+NFRAC,  3, AP_TRN, AP_WRAP> DATA_T;
…
ACC_T MAC( DATA_T din0, COEF_T coef, ACC_T  acc ) {
    acc = din0 * coef + acc;
#pragma HLS BIND_OP variable=acc op=mul impl=dsp latency=2
    return acc;
}
void process ( DATA_T din, DATA_T* dout0) {
#pragma HLS pipeline II=1
…
 LOOP_MAC: for (int i=0; i<l_COEFF; i++) {
    acc = MAC (sr[tdl_index], coeff[i], acc);
    tdl_index = tdl_index-1;
}

PIPELINE 编译指示会导致循环展开,并执行表达式平衡,这同样会阻止 DSP 匹配。在此情况下,添加 EXPRESSION_BALANCE OFF 以禁用表达式平衡将有助于 HLS 编译器识别用于 DSP 匹配的多重运算表达式。以下重做后的代码示例将改善 DSP 匹配。

static const int NFRAC = 14;
typedef ap_fixed<3+NFRAC,  3, AP_TRN, AP_WRAP> DATA_T;
…
ACC_T MAC( DATA_T din0, COEF_T coef, ACC_T  acc ) {
    acc = din0 * coef + acc;
    return acc;
}
void process ( DATA_T din, DATA_T* dout0) {
#pragma HLS pipeline II=1
#pragma HLS expression_balance off
…
 LOOP_MAC: for (int i=0; i<l_COEFF; i++) {
    acc = MAC (sr[tdl_index], coeff[i], acc);
    tdl_index = tdl_index-1;
}