floating-u球体育app下载

fpga/dsp > 可编程逻辑 > 详情

floating-point设计编码风格与技巧

发布时间:2024-10-29 发布时间:
|

尽管通常fixed-point(定点)比floating-point(浮点)算法的fpga实现要更快,且面积更高效,但往往有时也需要floating-point来实现。这是因为fixed-point有限的数据动态范围,需要深入的分析来决定整个设计中间数据位宽变化的pattern,为了达到优化的qor,并且要引入很多不同类型的fixed-point中间变量。而floating-point具有更大的数据动态范围,从而在很多算法中只需要一种数据类型的优势。

xilinx vivado hls工具支持c/c ieee-54标准单精度及双精度浮点数据类型,可以比较容易,快速地将c/c floating-point算法转成rtl代码。与此同时,为了达到用户期望的fpga资源与性能, 当使用vivado hls directives时需要注意c/c 编码风格与技巧相结合。

编码风格

1.1 单双精度浮点数学函数

#include
float example(float var)
{
return log(var); // 双精度自然对数
}

在c设计中, 这个例子, vviado hls 生成的rtl实现将输入转换成双精度浮点,并基于双精度浮点计算自然对数,然后将双精度浮点输出转换成单精度浮点.

#include
float example(float var)
{
return logf(var); // 单精度自然对数
}
在c设计中, logf才是单精度自然对数, 这个例子 vviado hls 生成的rtl实现将基于单精度浮点计算自然对数, 而且没有输入输出单双精度的互转。

1.2 浮点运算优化

我们先来看一个例子,三个从代数上看起来差不多的写法,但其在vivado hls中综合出来的是三个完全不一样的结果。

void example(float *m0, float *m1, float *m2, float var)
{
*m0 = 0.2 * var; // 双精度浮点乘法,单双精度类型转换
*m1 = 0.2f * var; // 单精度浮点乘法
*m2 = var / 20.0f; // 单精度浮点除法
}

vivado hls将日m0, m1, m2综合成不同的rtl实现。
因为0.2是一个不能精确表征的双精度数字, 所以m0运算会被vivado hls综合成一个双精度浮点乘法, 并且将var 转换成双精度, 然后将双精度乘法输出m0转换成单精度。
特别注意,如果希望vivado hls综合出单精度常熟,需要在常数后面加f, 如0.2f。这样m1综合成一个单精度乘法的输出。同理,m2将被vivado hls综合成单精度除法的输出。

我们来看另外一个例子。

void example(float *m0, float *m1, float var)
{
*m0 = 0.2f * 5.0f * var; // *m0 = var;常数乘法被优化掉
*m1 = 0.2f * var * 5.0f; // 两个双精度浮点乘法
}

再来看另一个例子。

void example(float *m0, float *m1, float var)
{
*m0 = 0.5 * var; //
*m1 = var/2; //
}
m0运算会被vivado hls综合成一个双精度浮点乘法, 并且将var 转换成双精度, 然后将双精度乘法输出m0转换成单精度。

m1运算会被vivado hls综合成简单的右移运算。所以如果用户希望实现对var除以2, 就写成m1这种表达式,而不是m0的表达式。

并行度与资源复用
由于浮点运算相比整型,定点运算耗用更可观的资源。vivado hls会尽量用更有效的资源来实现浮点运算,当数据的相关性及约束许可的情况下,在vivado hls中,会尽量复用一些浮点运算单元。为了说明这个,我们看一个简单的四个浮点加法例子, vivado hls复用一个浮点加法器来串行实现四个浮点加法。
void example(float *r, float a, float b,
float c, float d)
{
*r = a b c d;
}

有时设计需要更高的throughput及更低的latency。这时就需要提高设计的并行度。以下面例子来说明,在vivado hls就需要对for循环loop加pipeline与unroll 的directives。同时需要通过设置a,b,r0 为fifo, 并对其重排以提高i/o带宽两倍。这样vivado hls就会综合出两个浮点加法来并行实现,这是因为每个加法器计算是完全独立的。

void example(float r0[32], float a[32], float b[32])
{
#pragma hls interface ap_fifo port=a,b,r0
#pragma hls array_reshape cyclic factor=2 variable=a,b,r0
for (int i = 0; i < 32; i )
{
#pragma hls pipeline
#pragma hls unroll factor=2
r0[i] = a[i] b[i];
}
}

然而,如果更多复杂的运算,或许会导致不独立的浮点运算,在这种情况下,vivado hls不能重新排列这些运算的顺序,这样会导致更低的,不是所期望的复用。 下面举例来说明如何提高带有反馈浮点运算的性能。

这个例子的累加会导致recurrence,并且通常浮点加法的latency大于一个时钟周期,加的pipeline directive并不能达到一个时钟周期完成一次累加的throughput。

float example(float x[32])
{
#pragma hls interface ap_fifo port=x
float acc = 0;
for (int i = 0; i < 32; i )
{
#pragma hls pipeline
acc = x[i];
}
return acc;
}

为了对上面例子并行展开,可以对代码如下做较小的改动,也就是拆成先部分累加,再最后累加,当然也需要对输入数据进行简单的重新排列,以获得相应的i/o带宽,从而达到期望的并行度。

float top(float x[32])
{
#pragma hls interface ap_fifo port=x
float acc_part[4] = {0.0f, 0.0f, 0.0f, 0.0f};
for (int i = 0; i < 32; i = 4) { // 手动unroll by 4
for (int j = 0; j < 4; j ) { // 部分累加
#pragma hls pipeline
acc_part[j] = x[i j];
}
for (int i = 1; i < 4; i ) { //最后累加
#pragma hls unroll
acc_part[0] = acc_part[i];
}
return acc_part[0];
}


『本文转载自网络,u球体育app下载的版权归原作者所有,如有侵权请联系删除』

热门文章 更多
采用fusion fpga实现扩散炉温控系统的软硬件设计
网站地图