一个基于ZYNQ、AXI接口的PL端卷积加速器,可由PS端调用(附Github源码)

ZYNQ_PL_CONV_ACC

摘要:一个基于ZYNQ,AXI接口的PL端卷积加速器,可由PS端调用

开发板型号:Zynq-7000 SoC XC7Z305 FPGA

开发平台:Vivado 2019.1; Vivado SDK 2019.1

Github源码链接:https://github.com/CY0807/ZYNQ_PL_CONV_ACC

1 文件描述:

(1)vivado_project存放了vivado和sdk原始工程文件

(2)c_project_demo存放了sdk工程中所用的核心代码

(3)image中存放了项目的一些截图与绘图,image目录下的仿真波形中存放着行为级仿真的截图,与工程中的仿真程序一一对应

2 硬件设计

1、总体框架:

其中PL_reg模块基于AXI-Lite总线生成可供PS端寻址的两个配置寄存器和两个状态寄存器,并将这4个寄存器的接口与PL端卷积加速器(PL_conv_acc)连接,PS端可以通过这几个寄存器用来对PL端的卷积加速器进行配置和查询状态。

DMA为Vivado自带IP核,基于AXI-Stream,用于发送图像数据、卷积核参数到PL端卷积加速器,接受来自PL端加速器的卷积结果。同样这些步骤可以用过PS端配置DMA来进行控制。

2、Block Design图:

block design

PL端加速器没有包含在Block Design中,在这个system中,将DMA的AXI-Stream接口和4个寄存器接口引出,并与在system_wrapper中例化的pl_conv_acc连接,从如下的文件组织结构图中可以看出:

文件组织结构

3、PL端加速器结构:

PL端加速器通过两个异步FIFO与AXI-Stream接口进行跨时钟域数据交换,数据从输入到输出分别要进行padding 、conv_window、bram_mac三个模块,这三个模块的功能分别是:

padding:对图像进行padding 0填充;

conv_window:采用窗口生成器对图像数据进行卷积,该卷积支持有符号数的运算以及定点数运算;在工程中,数据都被设置成32位,读者可以根据需要修改;

bram_mac:例化了一段block ram用来暂时存放来自conv_window的数据,并支持新老数据相加后存入block ram的功能;

其中conv_window可以选择接受来自padding模块的图像数据,也可以从input fifo中直接获得卷积核参数的数据;

configuration模块接受由PS端赋值的两个配置寄存器,并根据寄存器内容配置加速器的相关参数和使能信号,相关verilog程序如下:

`define define_width  32'h00000001 //设置输入图像宽度
`define define_height 32'h00000002 //设置输入图像高度
`define define_conv_coff 32'h00000003  //设置输入图像卷积核
`define define_conv_data 32'h00000004 //设置输入图像数据
`define define_decimal_num 32'h00000005 //设置输入定点数的小数位数
`define define_bram_mac_en 32'h00000006 //设置使能bram的mac功能
`define define_rd_result_en 32'h00000007 //设置使能读取结果
case(cfg_reg0)
		`define_width: begin
			max_width <= cfg_reg1;
		end
		`define_height: begin
			max_height <= cfg_reg1;
		end
		`define_decimal_num: begin
			decimal_num <= cfg_reg1;
		end
		`define_conv_coff: begin
			cfg_coff_en <= ~(cfg_reg1 == 'd0);
		end
		`define_conv_data: begin
			cfg_data_en <= ~(cfg_reg1 == 'd0);
		end
		`define_bram_mac_en:begin
			bram_mac_en <= ~(cfg_reg1 == 'd0);
		end
		`define_rd_result_en:begin
			rd_result_en <= ~(cfg_reg1 == 'd0);
		end
		default: begin
			max_width <= 'd256;
			max_height <= 'd256;
			decimal_num <= 'd0;
			cfg_coff_en <= 0;
			cfg_data_en <= 0;	
			bram_mac_en <= 0;
			rd_result_en <= 0;
		end
endcase

3 软件设计

详见工程中的sdk目录,核心代码如下:

int Status;
TxDone = 0;
RxDone = 0;
int Index;
int width = 10;
int height = 10;
int Len = width*height;
xil_printf("\r\n----Test----\r\n");
xil_printf("Len=%d\r\n",Len);
// set TX data
for(Index = 0; Index < Len; Index ++) {
	TxBufferPtr[Index] = Index+1;
}
xil_printf("TX data ready!\r\n");

// 1.configure image width
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 1);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 10);

// 2.configure image height
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 2);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 10);

// 3.configure data decimal num
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 5);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 0);

// 4.disable bram mac and read
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 6);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 0);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 7);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 0);

// 5.configure conv coff
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 3);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 1);
	// conv coff TX data to DMA
int Len_conv_coff = 10;
Xil_DCacheFlushRange((u32)conv_coff, Len_conv_coff*4);
Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)conv_coff,
		Len_conv_coff*4, XAXIDMA_DMA_TO_DEVICE);
if (Status != XST_SUCCESS) {
	xil_printf("conv coff to DMA Fail!\r\n");
	return XST_FAILURE;
}
while(TxDone == 0);
xil_printf("conv coff to DMA OK!\r\n");
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 3);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 0);
usleep(10);

// 6.configure conv image data
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 4);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 1);
	// conv coff TX data to DMA
Xil_DCacheFlushRange((u32)TxBufferPtr, Len*4);
Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)TxBufferPtr,
		Len*4, XAXIDMA_DMA_TO_DEVICE);
if (Status != XST_SUCCESS) {
	xil_printf("conv image data to DMA Fail!\r\n");
	return XST_FAILURE;
}
while(TxDone == 0);
xil_printf("conv image data to DMA OK!\r\n");

// 7.wait for covolution complete
while((*pl_state) & 0x00000002 == 0);
xil_printf("conv OK!\r\n");
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 4);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 0);
usleep(10);

// 8.read convolution result
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 7);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 1);
	// DMA data to RX
Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)RxBufferPtr,
		Len*4, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
	xil_printf("DMA data to RX Fail!\r\n");
	return XST_FAILURE;
}	
while(RxDone == 0);
#ifndef __aarch64__
	Xil_DCacheInvalidateRange((u32)RxBufferPtr, Len*4);
#endif
xil_printf("DMA data to RX OK!\r\n");

// 9.wait util read result complete
usleep(10);
while((*pl_state)&0x00000004 == 0);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR, 7);
Xil_Out32(XPAR_PL_REG0_S00_AXI_BASEADDR+4, 0);

测试思路为:通过配置寄存器配置相关参数、传输卷积核参数数据、传输图像数据、等待卷积完成、发起读取结果请求、等待结果读取完成

在本示例中,输入的图像为10x10的数据,数值为1、2、3、···、100,padding为对1行、列进行补零,定点数小数位数为0,卷积核为3x3的全1矩阵,偏置为0。图像数据存储在TxBuffer中,地址为0x01100000,结果存储在RxBuffer中,地址为0x01300000,在SDK中进行测试,可见显示的两块区域的内存如下图:

SDK result

对于图中的结果可以验证是正确的。

附录 行为级仿真结果

1 padding模块

总体仿真时序

总体时序

可见时序图中data_valid中间有一段是低电平,说明输入数据是不连续的,在这里是为了验证padding模块支持对不连续输入数据的正确操作,在输入不连续处的波形图放大如下:

输入数据不连续处的波形图

此外,在图像的行之间的波形图放大如下:

图像行之间的波形

2 configurator模块

configurator

它根据两个配置寄存器:cfg_reg0和cfg_reg1的值配置其他相关变量

3 conv_window模块

总体时序图,其中图像高宽=32,图像数据为0,1,2,3······

总体波形图

配置卷积核系数处的波形图,其中w=1,偏置b=0,在cfg_conv_en为高电平时conv_window直接从input fifo中读取卷积核参数数据,反之从padding模块中读取图像数据

配置卷积核系数

输出结果的开端处:

输出数据开端处

输出结果的结尾处:

输出数据结尾处

4 bram_mac模块

波形总体图:首先关闭模块的bram_mac功能,输入数据1、2、3、···、100,再读取一遍数据,得到1、2、3、···、100;然后打开bram_mac功能,再输入一次数据同样为1、2、3、···、100,第二次读取数据,得到2、4、6、···、200

波形总体图

第一次读取数据波形图

第一次输出-关闭mac

第二次读取数据波形图

第二次输出-打开mac

5 conv_acc模块(顶层模块)

波形总体图:输入的图像为10x10的数据,数值为1、2、3、···、100,padding为对1行、列进行补零,定点数小数位数为0,卷积核为3x3的全1矩阵,偏置为0

总体波形图

输出结果的开端出的波形图

输出开端

输出结果的结尾出的波形图

输出结尾
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值