文章目录
优化语法
硬件资源指定语法
指定向FPGA硬件资源映射时的资源类型#
#pragma HLS RESOURCE variable =<temp>core =<Xilinxcore>
Examples :
a = b + c;
# pragma HLS RESOURCE variable =a core =AddSub_DSP
intA[1024];
# pragma HLS RESOURCE variable =A core =RAM_T2P_BRAM
数组划分语法
#pragma HLS array _partition variable =<name><type>factor =<int>dim =<int>
Type :complete ,cyclic ,block
dim=1,2,3(dim=0)
不同TYPE:
complete: 完全打散为N个数
Block: 打散为几个块
cycle: factor 取模的方式进行划分,如奇偶性
流水化
任务级流水化
#pragma HLS dataflow
管线优化
#pragma HLS PIPELINE
任务级流水化粒度更大,作用于不同的子函数,后面的代码只能包含函数调用和中间变量声明。
pipeline作用于循环的不同iteration
STREAM
数据类型: hls::stream<stream_type>
以高性能FIFO替代高资源占用的double-buffered RAM
指令:#pragma HLS stream variable =<variable>depth =<int>dim=<int>
- 数据类型为Istream ,使用流操作符操作
- 在函数参数配置时传引用“&”
- 必须有一个producer 和一个consumer
函数内联
#pragma HLS INLINE(off)
循环
循环边界
一般循环次数为定值,否则综合后无法获得性能估计(Latency=?)
#pragma HLS loop_tripcount min = <int> max = <int> avg =<int>
循环展开
手动展开或使用指令
#pragma HLS UNROLL(factor = <int>)
E.g., #pragma HLS UNROLL factor=2
过分了可能综合时间过长和失败
资源内容
硬件资源
可以存储于为片上的存储单元/Buffer/Scratchpad Memory
设计利用数据局部性提高重复访问数据的访问效率
- flip-flop(FF)
- 单个时钟周期内可并行访问多个地址
- 单个时钟周期内可完成读、写操作
- 容量有限:典型值大约100Kbytes
- Block RAM ( BRAM)
- 高容量:典型值在Mbytes 级别
- 访问性能受限:端口有限
- 权衡:带宽vs.容量
数值精度
头文件: ap_int.h,ap_fixed.h
支持任意精度、任意位宽的有/无符号数据类型:
- Unsigned int :ap_uint
- Signed int :ap_int
- Unsigned fixed : ap_ufixed<width,width_int>
- Signed fixed :ap _fixed<width,width_int>
精度处理
- 加法: ap_uint A = ap_uint B + ap_uint C ,where x = max (y,z) + 1
- 乘法: ap_uint A = ap_uint B * ap_uint C ,where x = y+z
其实说人话就是加法的精度取决于原来误差较大的,乘法则是原来的相乘
模块接口
在综合过程中定义生成的硬件接口
- 函数级(函数调用传参)的接口实现方式、控制协议
- ip级(顶层函数参数)的接口实现方式、控制协议
常用有
- ap_fifo:生成标准FIFO接口,常做模块间数据通路
- m_axi:生成AXI4总线的Master接口,常做IP外部数据访问接口
- s_axilite:生成AXI4-lite的Slave接口,常做控制IP调用的控制接口
优化案例
源码如下
void test()
{
float In[CHin][Rin][Cin];
float Out[CHout][R][C];
float W[CHout][CHin][K][K];
Output_Channel:
for(int cho=0; cho<CHout; cho++)
{
Input_Channel:
for(int chi=0; chi<CHin; chi++)
{
Row:
for(int r=0; r<R; r++)
{
Column:
for(int c=0; c<C; c++)
{
Kernel_Row:
for(int kr=0; kr<K; kr++)
{
Kernel_Column:
for(int kc=0; kc<K; kc++)
{
Out[cho][r][c] += In[chi][r+kr][c+kc] * W[cho][chi][kr][kc];
}
}
}
}
}
}
return;
}
未优化
数组展开及循环展开
void test()
{
float In[CHin][Rin][Cin];
#pragma HLS array_partition variable=In complete dim=1
float Out[CHout][R][C];
#pragma HLS array_partition variable=Out complete dim=1
float W[CHout][CHin][K][K];
#pragma HLS array_partition variable=W complete dim=1
#pragma HLS array_partition variable=W complete dim=2
Row:
for(int r=0; r<R; r++)
{
Column:
for(int c=0; c<C; c++)
{
Kernel_Row:
for(int kr=0; kr<K; kr++)
{
Kernel_Column:
for(int kc=0; kc<K; kc++)
{
Output_Channel:
for(int cho=0; cho<CHout; cho++)
{
#pragma HLS UNROLL
Input_Channel:
for(int chi=0; chi<CHin; chi++)
{
#pragma HLS UNROLL
Out[cho][r][c] += In[chi][r+kr][c+kc] * W[cho][chi][kr][kc];
}
}
}
}
}
}
return;
}
数组展开及PIPELINE优化
void test()
{
float In[CHin][Rin][Cin];
#pragma HLS array_partition variable=In complete dim=1
float Out[CHout][R][C];
#pragma HLS array_partition variable=Out complete dim=1
float W[CHout][CHin][K][K];
#pragma HLS array_partition variable=W complete dim=1
#pragma HLS array_partition variable=W complete dim=2
Row:
for(int r=0; r<R; r++)
{
Column:
for(int c=0; c<C; c++)
{
Kernel_Row:
for(int kr=0; kr<K; kr++)
{
Kernel_Column:
for(int kc=0; kc<K; kc++)
{
#pragma HLS PIPELINE
Output_Channel:
for(int cho=0; cho<CHout; cho++)
{
Input_Channel:
for(int chi=0; chi<CHin; chi++)
{
Out[cho][r][c] += In[chi][r+kr][c+kc] * W[cho][chi][kr][kc];
}
}
}
}
}
}
return;
}
不同循环顺序的PIPELINE优化
void test()
{
float In[CHin][Rin][Cin];
#pragma HLS array_partition variable=In complete dim=1
float Out[CHout][R][C];
#pragma HLS array_partition variable=Out complete dim=1
float W[CHout][CHin][K][K];
#pragma HLS array_partition variable=W complete dim=1
#pragma HLS array_partition variable=W complete dim=2
Kernel_Row:
for(int kr=0; kr<K; kr++)
{
Kernel_Column:
for(int kc=0; kc<K; kc++)
{
Row:
for(int r=0; r<R; r++)
{
Column:
for(int c=0; c<C; c++)
{
#pragma HLS PIPELINE
Output_Channel:
for(int cho=0; cho<CHout; cho++)
{
Input_Channel:
for(int chi=0; chi<CHin; chi++)
{
Out[cho][r][c] += In[chi][r+kr][c+kc] * W[cho][chi][kr][kc];
}
}
}
}
}
}
return;
}