HLS增大带宽的方法

带宽的重要性

根据roofline模型,一个平台的吞吐率取决于片外存储带宽和峰值计算性能,在加速卷积层时,制约系统吞吐率的瓶颈是峰值计算性能,而对于全连接层,计算量较小,而参数却非常多,无法完全存储在FPGA的片内RAM上,因此权值需要从片外存储器(DDR)读取,此时限制吞吐率的瓶颈主要是内存带宽。下面将介绍如何增大PL访问ddr的带宽。

data_pack

在本人的设计中,权重被量化为16位定点数,而AXI HP接口的位宽最大为64bit,这意味这事实上m_axi总线一次可以传输4个权重数据,吞吐率增大了4倍,在HLS中,可以用结构体和data_pack指令来实现这一目标。
下面是一个用作演示的Demo

#include"fc.h"

typedef ap_fixed<16,8,AP_RND,AP_SAT> data_t;
typedef struct data_in{
	data_t A[4];
}din;

void fc(volatile din* in,volatile din* out){
#pragma HLS INTERFACE m_axi port=in offset=slave bundle=IN num_read_outstanding=32
#pragma HLS INTERFACE m_axi port=out offset=slave bundle=OUT num_write_outstanding=32
#pragma HLS INTERFACE s_axilite port=return bundle=CTRL
#pragma HLS  data_pack variable=in
#pragma HLS  data_pack variable=out

   din a[100];
   int i;
   for(i=0;i<100;i++)
	   a[i]=*((din*)in+i);            //(din*)必须要
   for(i=0;i<100;i++)
	   *((din*)out+i)=a[i];
}

这里,我们先定义结构体din,它包含一个数组A[4],即4个权重,然后用data_pack指令对该结构体打包。下面有一个值得注意的地方
a[i]=*(in+i)语句,如果in是普通的数据类型而不是结构体,这样写就没什么问题了,但是in是结构体就会报错
在这里插入图片描述
加上强制类型转换 ( d i n ∗ ) (din*) (din)后就可以了。

直接使用更宽的数据

头文件如下,我们定义64位数据以并行传输4个16bit数据

#include<ap_int.h>
#include<iostream>
using namespace std;

//typedef struct{
//	ap_int<16> a[4];
//}data_t;

typedef ap_int<64> data_t;

void func(volatile data_t* in,volatile data_t* out);



设计文件如下,我们可以通过tmp1(MSB-1,LSB)来截取64位数据中的某16位数据,这里完成的功能是将每个16位数据增加1,写回。

#include<cstring>
#include"transfer.h"



void func(volatile data_t* in,volatile data_t* out){
#pragma HLS INTERFACE m_axi depth=100 port=in offset=slave  bundle=BUS
#pragma HLS INTERFACE m_axi depth=100 port=out offset=slave  bundle=BUS
#pragma HLS INTERFACE s_axilite port=return bundle=CTRL
//#pragma HLS data_pack variable=in
//#pragma HLS data_pack variable=out
	data_t tmp2;
	data_t tmp1;
    for(int m=0;m<4;m++){
    	int offset=m*100/4;
    	for(int i=0;i<100/4;i++){
#pragma HLS PIPELINE II=1
			tmp1=*((data_t*)in+offset+i);
    	    tmp2(63, 48)=tmp1(63,48)+1;
    	    tmp2(47,32)=tmp1(47,32)+1;
    	    tmp2(31,16)=tmp1(31,16)+1;
    	    tmp2(15,0)=tmp1(15,0)+1;
    	    *((data_t*)out+offset+i)=tmp2;
    	}
    }
}

testbench如下

#include"transfer.h"

int main(){

	ap_int<16> a[400];
	ap_int<16> b[400];
	for(int i=0;i<400;i++)
		a[i]=i;
	func((volatile data_t*)a,(volatile data_t*)b);
	for(int i=0;i<400;i++)
		cout<<b[i]<<endl;
}

综合成功,以下是csim仿真波形,说明这四个数据的确是并行传输的:

在这里插入图片描述

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页