本文转载自:<span id="profileBt"><a href="https://mp.weixin.qq.com/s/IPtgm3kwcyO6AXvEiCm25A">FPGA打工人微信公众号</a></sp…;
<font color="#FF8000">注:本文由作者授权转发,如需转载请联系作者本人</font>
<strong>数据类型及精度</strong>
传统的C语言数据类型 以8为边界,即数据宽度为8的整数倍,比如32bit,64bit等,相比之下RTL数据的位宽即比较灵活,可以自定义,所以HLS引入了任意精度,采用任意精度的最大好处就是可以根据需求自定义位宽,进而降低对资源的消耗。
<center><img src="http://xilinx.eetrend.com/files/2022-08/%E5%8D%9A%E5%AE%A2/100562771-26…; alt=""></center>
[u]是区分有符号数还是无符号数,<W>表示位宽,最大1024。C++还引入了定点数。
#include <ap_int.h>
#ifdef _NO_SYNTH_
typedef int data_t ;
#else
typedef ap_int<18> data_t ;
#endif
<strong>定点数据类型</strong>
定点化数据在FPGA算法实现中不说常用吧,应该是逃不过的一道坎。
ap_[u]fixed<W,I,Q,O,N>:W表示的是整个数据字长,I表示整数部分数据字长,W-I则表示为小数部分字长。Q表示低位部分的量化模式,一般默认为AP_TRN_ZERO,即移除后面多余的位。O表示溢出模式,默认为AP_WRAP,即高位直接舍去。
<center><img src="http://xilinx.eetrend.com/files/2022-08/%E5%8D%9A%E5%AE%A2/100562771-26…; alt=""></center>
详细说说参数Q和参数O:
上面也说过,参数Q默认情况是AP_TRN_ZERO,当设置为AP_RND后,采用的是四舍五入(四舍五入具体实现方法就是被保留的最后一位的下一位是1时,则在最后一位加1,否则直接移除)。
ap_fixed<3,2,AP_RND> data = 1.25;
3代表data的数据长度,2代表整个整数部分的数据长度,AP_RND表示Q参数为四舍五入,最后得到的结果为1.5:
<center><img src="http://xilinx.eetrend.com/files/2022-08/%E5%8D%9A%E5%AE%A2/100562771-26…; alt=""></center>
当O设置为AP_SAT时,截取后的数据为其能表示的最大值。
ap_fixed<4,4,AP_RND,AP_SAT> data = 19;
4代表data的数据长度,第二个4代表整个整数部分的数据长度。AP_SAT表示截取后的数据为其能表示的最大值,因为第一位为符号位,所以最大值只能为7。
<center><img src="http://xilinx.eetrend.com/files/2022-08/%E5%8D%9A%E5%AE%A2/100562771-26…; alt=""></center>
<strong>结构体</strong>
HLS也是支持结构体的,可能要注意的是,当结构体为函数的参数时,结构体中的标量数据会映射为scalar端口,数组则映射为memory端口。比如:
typedef struct {
data_t data_test ;
mem_t mem_test[5] ;
} test_str;
test_str StrPort(test_str data_in)
{
test_str data_out ;
int i ;
data_out.data_test = data_in.data_test + 20 ;
for (i=0;i<5;i++)
{
data_out.mem_test[i] = data_in.mem_test[i] - 20 ;
}
return data_out ;
}
<strong>枚举类型</strong>
枚举是用关键字enum来定义。
typedef enum
{
M_INLE,
M_TEST1,
M_TEST2,
M_END
}mode_t;
在上面的变量mode_t中占2bit,HLS会自动推断并分配给合适的位宽。若枚举出现在函数的参数中,则会作为一个整数来实现port。