浮点与双精度 - 2021.2 Chinese

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

Document ID
UG1399
Release Date
2021-12-15
Version
2021.2 Chinese

Vitis HLS 支持 floatdouble 类型的综合。这两种数据类型均依据 IEEE-754 标准部分合规性来进行综合(请参阅 Floating-Point Operator LogiCORE IP 产品指南(PG060))。

  • 单精度 32 位
    • 24 位小数
    • 8 位指数
  • 双精度 64 位
    • 53 位小数
    • 11 位指数

除了将浮点和双精度类型用于标准算术运算(例如,+、-、* 等)外,浮点和双精度通常还可配合 math.h 一起使用(针对 C++,这 2 个类型还可配合 cmath.h 一起使用)。本节讨论了为标准运算符提供的支持。

以下代码示例显示的头文件可配合更新后的标准类型一起使用,以将数据类型定义为 doublefloat 类型。

#include <stdio.h>
#include <stdint.h>
#include <math.h>

#define N 9

typedef double din_A;
typedef double din_B;
typedef double din_C;
typedef float din_D;

typedef double dout_1;
typedef double dout_2;
typedef double dout_3;
typedef float dout_4;

void types_float_double(din_A inA,din_B inB,din_C inC,din_D inD,dout_1 
*out1,dout_2 *out2,dout_3 *out3,dout_4 *out4);

此更新后的头文件可配合以下代码示例一起使用,此代码中使用了 sqrtf() 函数。

#include "types_float_double.h"

void types_float_double(
 din_A  inA,
 din_B  inB,
 din_C  inC,
 din_D  inD,
 dout_1 *out1,
 dout_2 *out2,
 dout_3 *out3,
 dout_4 *out4
 ) {

 // Basic arithmetic & math.h sqrtf() 
 *out1 = inA * inB;
 *out2 = inB + inA;
 *out3 = inC / inA;
 *out4 = sqrtf(inD);

}

对以上示例进行综合后,可生成 64 位双精度乘法器、加法器和除法器运算符。这些运算符可由相应的浮点赛灵思 IP 目录核来实现。

使用 sqrtf() 的平方根函数是使用 32 位单精度浮点核来实现的。

如果使用双精度平方根函数 sqrt(),则将生成额外逻辑以在用于 inD 的 32 位单精度浮点类型与其它类型之间进行双向强制转换,out4: sqrt() 为双精度 (double) 函数,sqrtf() 为单精度 (float) 函数。

在 C 语言函数中,混用浮点类型和双精度类型时请谨慎处理,因为浮点到双精度和双精度到浮点转换单位是在硬件中推断所得的。

float foo_f    = 3.1459;
float var_f = sqrt(foo_f); 

以上代码可生成如下硬件:

wire(foo_t)
-> Float-to-Double Converter unit
-> Double-Precision Square Root unit
-> Double-to-Float Converter unit
-> wire (var_f)

使用 sqrtf() 函数即可:

  • 使硬件无需再使用类型转换器
  • 节省面积
  • 改进时序

对浮点和双精度类型进行综合时,Vitis HLS 会保留 C 语言代码中执行的运算顺序,以确保结果与 C 语言仿真结果相同。由于执行的饱和与截断操作,在单精度运算和双精度运算中不保证:

       A=B*C; A=B*F;
       D=E*F; D=E*C;
       O1=A*D O2=A*D;

对于 floatdouble 类型,不保证 O1O2 相同。

提示: 在某些情况下(视设计而定),展开或部分展开循环等最优化可能无法充分利用并行计算,因为 Vitis HLS 对浮点和双精度类型进行综合时会严格保留运算顺序。您可使用 config_compile -unsafe_math_optimizations 覆盖此限制。

对于 C++ 设计,Vitis HLS 可提供最常用的数学函数的位近似实现。

浮点累加器和 MAC

浮点累加器 (facc)、乘累加 (fmacc) 和乘加 (fmadd) 均可使用 config_op 命令来启用,如下所示:

config_op <facc|fmacc|fmadd> -impl <none|auto> -precision <low|standard|high>

Vitis HLS 为这些运算符提供不同精度级别的支持,以期在 Versal 器件和非 Versal 器件上能实现性能、面积和精度的取舍权衡。

  • 低精度累加适用于高吞吐量低精度浮点累加和乘累加,该模式仅在非 Versal 器件上可用。
    • 它使用具有预分频器和后分频器的整数累加器来将输入和输出转换为单精度或双精度浮点。
      • 它分别使用 60 位和 100 位累加器来执行单精度输入和双精度输入。
      • 由于 C++ 仿真相关精度不足,因此它可能导致协同仿真发生不匹配。
    • 它始终采用流水打拍,且 II=1,无源代码更改
    • 它使用的资源量约为标准精度浮点累加的 3 倍,因此根据时钟频率和目标器件,II 通常在 3 到 5 之间。
    使用低精度的情况下,在所有器件上都支持浮点和双精度累加,启动时间间隔 (II) 均为 1。这意味着以下代码可采用流水打拍,II 为 1 且无需进一步编码:
    float foo(float A[10], float B[10]) {
     float sum = 0.0;
     for (int i = 0; i < 10; i++) {
     sum += A[i] * B[i];
     }
     return sum;
    }
  • 标准精度累加和乘加适合大部分浮点用例,并且可在 Versal 器件和非 Versal 器件上使用。
    • 它始终使用真正的浮点累加器。
    • Versal 器件上,它可采用流水打拍,且 II=1。
    • 在非 Versal 器件上,它可采用流水打拍,且 II 通常介于 3 到 5 之间(取决于时钟频率和目标器件)。标准精度模式在 Versal 器件上比在非 Versal 器件上效率更高。
  • 高精度融合乘加适合高精度应用,可在 Versal 器件上使用。
    • 它使用额外的精度位
    • 虽然它使用的资源比非融合乘加更多,但它始终使用单个融合乘加,末尾采用单个舍入
    • 由于 C++ 仿真相关的额外精度,因此它可能导致协同仿真发生不匹配。
提示: 为了与先前版本实现相同结果,请使用以下配置:
config_op facc -impl auto -precision low