0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

三個不同AXI IP核的實現(xiàn)的方法_性能的對比及差異的分析

Hx ? 作者:工程師陳翠 ? 2018-06-29 14:34 ? 次閱讀

本文先總結(jié)不同AXI IP核的實現(xiàn)的方法,性能的對比,性能差異的分析,可能改進的方面。使用的硬件平臺是Zedboard。

不同的AXI總線卷積加速模塊的概況

這次實現(xiàn)并逐漸優(yōu)化了三個版本的卷積加速模塊,先簡要描述各個版本的主要內(nèi)容。

版本一

版本一主要是用來測試AXI總線IP核的實現(xiàn)可能。

該模塊擁有19個32位寄存器

其中前9個寄存器用來保存需要計算的值

后面9個寄存器用來保存卷積核

在讀取第19個寄存器的地址的時候計算9個寄存器的卷積和(該計算可以在一個時鐘周期內(nèi)完成)

9個寄存器單獨賦值,程序中分別向?qū)刂穼懭雰?nèi)容,通過總線進行傳輸。

故樂觀的來算,需要10個總線周期可以獲取一個輸出

可以從驅(qū)動的書寫簡單理解一下:

void Conv_HW(int filter[3][3], int arr[100][100],

int filterW, int filterH, int arrW, int arrH) {

int i, j;

for (i = 2; i 《 filterH + arrH - 3; i++) {

for (j = 2; j 《 filterW + arrW - 3; j++) {

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR, arr[i][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+4, arr[i][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+8, arr[i][j - 2]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+12, arr[i - 1][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+16, arr[i - 1][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+20, arr[i - 1][j - 2]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+24, arr[i - 2][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+28, arr[i - 2][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR+32, arr[i - 2][j - 2]);

res[i][j] = Xil_In32(XPAR_CONV_0_S00_AXI_BASEADDR + 72);

}

if (i % 15 == 0)

printf(“=”);

}

}

版本一性能

版本一性能最慘,由于沒有時間戳,目測軟件計算速度遠遠快于FPGA核心運算速度。

版本一的改進速度就是引入滑動窗口,能夠最大程度減少總線周期。

版本二

版本二引入滑動窗口,和初期設計的概念相同。

三個不同AXI IP核的實現(xiàn)的方法_性能的對比及差異的分析

該模塊擁有19個32位寄存器

其中前9個寄存器用來保存需要計算的值

后面9個寄存器用來保存卷積核

在讀取第19個寄存器的地址的時候計算9個寄存器的卷積和(該計算可以在一個時鐘周期內(nèi)完成)

三個寄存器滑動賦值,該計算窗口在計算矩陣上滑動 除了冷啟動多余兩個周期用來預載寄存器,后面的每一個計算只需要四個總線周期

可以通過寫的驅(qū)動簡單理解一下:

void Conv_HW(int filter[3][3], int arr[100][100], int arrW, int arrH) {

int i, j;

i = 2; j = 2;

for (i = 2; i 《 arrH; i++) {

//pre load

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, arr[i - 1][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, arr[i][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, arr[i + 1][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, arr[i - 1][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, arr[i][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, arr[i + 1][j]);

for (j = 2; j 《 arrW; j++) {

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, arr[i - 1][j + 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, arr[i][j + 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, arr[i + 1][j + 1]);

res[i][j] = Xil_In32(XPAR_CONV_0_S00_AXI_BASEADDR + 72);

}

}

}

版本二性能

測試樣本 500*500的32bit單位的矩陣 計算200次。

軟件消耗33.78秒,卷積IP核心40.25秒

這樣的結(jié)果還是非常不樂觀,分析可能有兩種限制了IP核的速度。

兩個寄存器的乘法LUT太大,無法硬件優(yōu)化

總線周期太慢太慢

版本三對于這兩種可能進行探索。

版本二的FPGA部分核心代碼

// Implement memory mapped register select and write logic generation

// The write data is accepted and written to memory mapped registers when

// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to

// select byte enables of slave registers while writing.

// These registers are cleared when reset (active low) is applied.

// Slave register write enable is asserted when valid address and data are available

// and the slave is ready to accept the write address and write data.

assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;

always @( posedge S_AXI_ACLK )

begin

if ( S_AXI_ARESETN == 1‘b0 )

begin

slv_reg0 《= 0;

slv_reg1 《= 0;

slv_reg2 《= 0;

slv_reg3 《= 0;

slv_reg4 《= 0;

slv_reg5 《= 0;

slv_reg6 《= 0;

slv_reg7 《= 0;

slv_reg8 《= 0;

slv_reg9 《= 0;

slv_reg10 《= 0;

slv_reg11 《= 0;

slv_reg12 《= 0;

slv_reg13 《= 0;

slv_reg14 《= 0;

slv_reg15 《= 0;

slv_reg16 《= 0;

slv_reg17 《= 0;

// slv_reg18 《= 0;

end

else begin

if (slv_reg_wren)

begin

case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

5’h00:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 0

slv_reg0[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h01:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 1

slv_reg1[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h02:

begin

slv_reg0 《= slv_reg1;

slv_reg1 《= slv_reg2;

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 2

slv_reg2[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

end

5‘h03:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 3

slv_reg3[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h04:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 4

slv_reg4[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h05:

begin

slv_reg3 《= slv_reg4;

slv_reg4 《= slv_reg5;

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 5

slv_reg5[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

end

5’h06:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 6

slv_reg6[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h07:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 7

slv_reg7[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h08:

begin

slv_reg6 《= slv_reg7;

slv_reg7 《= slv_reg8;

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 8

slv_reg8[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

end

5‘h09:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 9

slv_reg9[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h0A:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 10

slv_reg10[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h0B:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 11

slv_reg11[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h0C:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 12

slv_reg12[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h0D:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 13

slv_reg13[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h0E:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 14

slv_reg14[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h0F:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 15

slv_reg15[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5’h10:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 16

slv_reg16[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

5‘h11:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 17

slv_reg17[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

// 5’h12:

// for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

// if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// // Respective byte enables are asserted as per write strobes

// // Slave register 18

// slv_reg18[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

// end

default : begin

slv_reg0 《= slv_reg0;

slv_reg1 《= slv_reg1;

slv_reg2 《= slv_reg2;

slv_reg3 《= slv_reg3;

slv_reg4 《= slv_reg4;

slv_reg5 《= slv_reg5;

slv_reg6 《= slv_reg6;

slv_reg7 《= slv_reg7;

slv_reg8 《= slv_reg8;

slv_reg9 《= slv_reg9;

slv_reg10 《= slv_reg10;

slv_reg11 《= slv_reg11;

slv_reg12 《= slv_reg12;

slv_reg13 《= slv_reg13;

slv_reg14 《= slv_reg14;

slv_reg15 《= slv_reg15;

slv_reg16 《= slv_reg16;

slv_reg17 《= slv_reg17;

end

endcase

end

end

end

// Implement memory mapped register select and read logic generation

// Slave register read enable is asserted when valid address is available

// and the slave is ready to accept the read address.

assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

always @(*)

begin

// Address decoding for reading registers

case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

5‘h00 : reg_data_out 《= slv_reg0;

5’h01 : reg_data_out 《= slv_reg1;

5‘h02 : reg_data_out 《= slv_reg2;

5’h03 : reg_data_out 《= slv_reg3;

5‘h04 : reg_data_out 《= slv_reg4;

5’h05 : reg_data_out 《= slv_reg5;

5‘h06 : reg_data_out 《= slv_reg6;

5’h07 : reg_data_out 《= slv_reg7;

5‘h08 : reg_data_out 《= slv_reg8;

5’h09 : reg_data_out 《= slv_reg9;

5‘h0A : reg_data_out 《= slv_reg10;

5’h0B : reg_data_out 《= slv_reg11;

5‘h0C : reg_data_out 《= slv_reg12;

5’h0D : reg_data_out 《= slv_reg13;

5‘h0E : reg_data_out 《= slv_reg14;

5’h0F : reg_data_out 《= slv_reg15;

5‘h10 : reg_data_out 《= slv_reg16;

5’h11 : reg_data_out 《= slv_reg17;

5‘h12 : reg_data_out 《= slv_reg0 * slv_reg9 +

slv_reg1 * slv_reg10 +

slv_reg2 * slv_reg11 +

slv_reg3 * slv_reg12 +

slv_reg4 * slv_reg13 +

slv_reg5 * slv_reg14 +

slv_reg6 * slv_reg15 +

slv_reg7 * slv_reg16 +

slv_reg8 * slv_reg17;

default : reg_data_out 《= 0;

endcase

end

版本三

先嘗試生成更小的LUT

該模塊擁有19個32位寄存器

其中前9個寄存器用來保存需要計算的值

卷積核固定在Verilog中,用來生成更小的LUT

一個計算只需要四個總線周期

性能測試

仍然軟件消耗33秒,卷積IP核心40秒

基本否決是LUT問題。

下面測試AXI總線問題:

假設所有數(shù)據(jù)均來自于FPGA,無需從總線寫入:

void Conv_HW(int filter[3][3], int arr[100][100], int arrW, int arrH) {

int i, j;

i = 2; j = 2;

for (i = 2; i 《 arrH; i++) {

for (j = 2; j 《 arrW; j++) {

res[i][j] = Xil_In32(XPAR_CONV_0_S00_AXI_BASEADDR + 72);

}

}

}

只需要9.47秒即可完成計算,并傳回CPU ?。?!

總結(jié)

至此,基本上可以否決利用AXI傳數(shù)據(jù)的可能,所有需要利用AXI總線傳輸數(shù)據(jù)的模塊均會被總線周期所連累,在優(yōu)化了傳輸后,仍然無法解決該問題。確實需要一個更快的方式來傳輸數(shù)據(jù)。

Altera的NIOS2中,直接利用IO口傳輸數(shù)據(jù),無需總線周期,再因為NIOS II內(nèi)核沒有流水線優(yōu)化,所以硬件確實比較快。

附1:AXI4 總線的 FPGA 接口部分

先看總線接口:

// Users to add ports here

// User ports ends

// Do not modify the ports beyond this line

// Global Clock Signal

// 全局時鐘

input wire S_AXI_ACLK,

// Global Reset Signal. This Signal is Active LOW

// 全局復位信號

input wire S_AXI_ARESETN,

// Write address (issued by master, acceped by Slave)

// 寫地址

input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,

// 寫地址的保護模式 包括privilege和security level

// Write channel Protection type. This signal indicates the

// privilege and security level of the transaction, and whether

// the transaction is a data access or an instruction access.

input wire [2 : 0] S_AXI_AWPROT,

// 寫地址有效信號。為高指示地址有效。

// Write address valid. This signal indicates that the master signaling

// valid write address and control information.

input wire S_AXI_AWVALID,

// 寫地址準備信號。為高表示從設備空閑,準備接收地址;為低表示從設備忙。

// ********** 注意 這里是地址 下面是數(shù)據(jù) ********

// Write address ready. This signal indicates that the slave is ready

// to accept an address and associated control signals.

output wire S_AXI_AWREADY,

// 寫數(shù)據(jù),32位到1024位寬

// 從主設備來的數(shù)據(jù) 從設備接收

// Write data (issued by master, acceped by Slave)

input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,

// 寫字節(jié)選通,用于表示更新存儲器的字節(jié)通道,對于數(shù)據(jù)總線的每8位數(shù)據(jù)有一位寫選通信號。

// Write strobes. This signal indicates which byte lanes hold

// valid data. There is one write strobe bit for each eight

// bits of the write data bus.

input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,

// 寫有效。為高指示數(shù)據(jù)有效。

// Write valid. This signal indicates that valid write

// data and strobes are available.

input wire S_AXI_WVALID,

// 寫準備。為高表示從設備空閑,準備接收數(shù)據(jù);為低表示從設備忙。

// Write ready. This signal indicates that the slave

// can accept the write data.

output wire S_AXI_WREADY,

// 寫響應。該信號表示寫狀態(tài),可允許相應的表示為OKAYEXOKAYSLVERRDECERR。

// Write response. This signal indicates the status

// of the write transaction.

output wire [1 : 0] S_AXI_BRESP,

// 寫響應有效。為高指示響應數(shù)據(jù)有效

// Write response valid. This signal indicates that the channel

// is signaling a valid write response.

output wire S_AXI_BVALID,

// 寫響應準備。為高表示主設備空閑,準備接收寫響應;為低表示主設備忙。

// Response ready. This signal indicates that the master

// can accept a write response.

input wire S_AXI_BREADY,

//

// 讀地址。讀地址給出突發(fā)數(shù)據(jù)傳輸?shù)牡谝粋€傳輸?shù)刂贰?/p>

// Read address (issued by master, acceped by Slave)

input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,

// 保護類型,建議值為000。

// Protection type. This signal indicates the privilege

// and security level of the transaction, and whether the

// transaction is a data access or an instruction access.

input wire [2 : 0] S_AXI_ARPROT,

//

// Read address valid. This signal indicates that the channel

// is signaling valid read address and control information.

input wire S_AXI_ARVALID,

// 讀地址準備信號。為高表示從設備空閑,準備接收地址;為低表示從設備忙。

// Read address ready. This signal indicates that the slave is

// ready to accept an address and associated control signals.

output wire S_AXI_ARREADY,

// Read data (issued by slave)

output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,

// Read response. This signal indicates the status of the

// read transfer.

output wire [1 : 0] S_AXI_RRESP,

// Read valid. This signal indicates that the channel is

// signaling the required read data.

output wire S_AXI_RVALID,

// Read ready. This signal indicates that the master can

// accept the read data and response information.

input wire S_AXI_RREADY

);

// AXI4LITE signals

reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;

reg axi_awready;

reg axi_wready;

reg [1 : 0] axi_bresp;

reg axi_bvalid;

reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;

reg axi_arready;

reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;

reg [1 : 0] axi_rresp;

reg axi_rvalid;

其中最為重要的讀取總線信號尋址的部分:

assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;

always @( posedge S_AXI_ACLK )

begin

if ( S_AXI_ARESETN == 1’b0 )

begin

slv_reg0 《= 0;

slv_reg1 《= 0;

slv_reg2 《= 0;

slv_reg3 《= 0;

slv_reg4 《= 0;

slv_reg5 《= 0;

slv_reg6 《= 0;

slv_reg7 《= 0;

slv_reg8 《= 0;

slv_reg9 《= 0;

end

else begin

if (slv_reg_wren)

begin

// 進行尋址

// 地址尋址 是這么玩的

// 當寄存器是32位的 最后就是 2位 4個Byte ADDR_LSB = 2

// 當寄存器是64位的 最后就是 3位 8個Byte ADDR_LSB = 3

// OPT_MEM_ADDR_BITS 用來尋址寄存器 這里選了十個寄存器 所以這里就是4位

case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

4‘h0:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

// 只有在對應的Bit位置為1的時候才能開始讀取

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 0

slv_reg0[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4’h1:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 1

slv_reg1[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4‘h2:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 2

slv_reg2[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4’h3:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 3

slv_reg3[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4‘h4:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 4

slv_reg4[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4’h5:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 5

slv_reg5[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4‘h6:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 6

slv_reg6[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4’h7:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 7

slv_reg7[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4‘h8:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 8

slv_reg8[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

4’h9:

for ( byte_index = 0; byte_index 《= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 9

slv_reg9[(byte_index*8) +: 8] 《= S_AXI_WDATA[(byte_index*8) +: 8];

end

default : begin

slv_reg0 《= slv_reg0;

slv_reg1 《= slv_reg1;

slv_reg2 《= slv_reg2;

slv_reg3 《= slv_reg3;

slv_reg4 《= slv_reg4;

slv_reg5 《= slv_reg5;

slv_reg6 《= slv_reg6;

slv_reg7 《= slv_reg7;

slv_reg8 《= slv_reg8;

slv_reg9 《= slv_reg9;

end

endcase

end

end

end

附2:AXI4的測試模塊與仿真測試

`timescale 1ns/1ns

module conv_axi_test();

parameter integer C_S00_AXI_DATA_WIDTH = 32;

parameter integer C_S00_AXI_ADDR_WIDTH = 6;

reg s00_axi_aclk;

// 全局復位信號

reg s00_axi_aresetn;

reg [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr;

wire [2 : 0] s00_axi_awprot;

reg s00_axi_awvalid;

wire s00_axi_awready;

reg [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata;

reg [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb;

reg s00_axi_wvalid;

wire s00_axi_wready;

wire [1 : 0] s00_axi_bresp;

wire s00_axi_bvalid;

wire s00_axi_bready;

reg [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr;

wire [2 : 0] s00_axi_arprot;

reg s00_axi_arvalid;

wire s00_axi_arready;

wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata;

wire [1 : 0] s00_axi_rresp;

wire s00_axi_rvalid;

wire s00_axi_rready;

conv_v1_0_S00_AXI # (

.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),

.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)

) conv_v1_0_S00_AXI_inst (

.S_AXI_ACLK(s00_axi_aclk),

.S_AXI_ARESETN(s00_axi_aresetn),

.S_AXI_AWADDR(s00_axi_awaddr),

.S_AXI_AWPROT(s00_axi_awprot),

.S_AXI_AWVALID(s00_axi_awvalid),

.S_AXI_AWREADY(s00_axi_awready),

.S_AXI_WDATA(s00_axi_wdata),

.S_AXI_WSTRB(s00_axi_wstrb),

.S_AXI_WVALID(s00_axi_wvalid),

.S_AXI_WREADY(s00_axi_wready),

.S_AXI_BRESP(s00_axi_bresp),

.S_AXI_BVALID(s00_axi_bvalid),

.S_AXI_BREADY(s00_axi_bready),

.S_AXI_ARADDR(s00_axi_araddr),

.S_AXI_ARPROT(s00_axi_arprot),

.S_AXI_ARVALID(s00_axi_arvalid),

.S_AXI_ARREADY(s00_axi_arready),

.S_AXI_RDATA(s00_axi_rdata),

.S_AXI_RRESP(s00_axi_rresp),

.S_AXI_RVALID(s00_axi_rvalid),

.S_AXI_RREADY(s00_axi_rready)

);

initial

begin:d

integer i;

s00_axi_aclk = 1;

for(i = 0; i《 1000;i++)

begin

#1 s00_axi_aclk = ~ s00_axi_aclk;

end

$finish();

end

initial

begin

s00_axi_aresetn = 0;

s00_axi_arvalid = 0;

#4 s00_axi_aresetn = 1;

s00_axi_awvalid = 1;

s00_axi_wvalid = 1;

s00_axi_awaddr = 0;

s00_axi_wstrb = 4‘b1111;

s00_axi_wdata = 3;

#4 s00_axi_awaddr = 6’b000100;

s00_axi_wdata = 21;

#4 s00_axi_awaddr = 6‘b001000;

s00_axi_wdata = 19;

#4 s00_axi_awaddr = 6’b001100;

s00_axi_wdata = 22;

#4 s00_axi_awaddr = 6‘b010000;

s00_axi_wdata = 20;

#4 s00_axi_awaddr = 6’b010100;

s00_axi_wdata = 13;

#4 s00_axi_awaddr = 6‘b011000;

s00_axi_wdata = 16;

#4 s00_axi_awaddr = 6’b011100;

s00_axi_wdata = 14;

#4 s00_axi_awaddr = 6‘b100000;

s00_axi_wdata = 7;

#4

s00_axi_arvalid = 1;

s00_axi_araddr = 6’b100100;

end

initial

begin

$dumpfile(“test.vcd”);

$dumpvars();

end

endmodule

利用iverilog進行仿真GTKwave顯示測試波形如下

三個不同AXI IP核的實現(xiàn)的方法_性能的對比及差異的分析

新建IP核如下:

三個不同AXI IP核的實現(xiàn)的方法_性能的對比及差異的分析

工程頂層圖如下:

三個不同AXI IP核的實現(xiàn)的方法_性能的對比及差異的分析

附3:軟件驅(qū)動

#include

#include “platform.h”

#include “xbasic_types.h”

#include “xparameters.h”

#include “xil_io.h”

#define test_speed

int res[1000][1000];

void delay() {

int i, j, k;

for (i = 0; i 《 1000; i++) {

for (j = 0; j 《 1000; j++) {

for (k = 0; k 《 100; k++)

;

}

}

}

void show_reg() {

int i;

u32 result;

printf(“ ============SHOW REG ================ ”);

for (i = 0; i 《 9; i++) {

result = Xil_In32(XPAR_CONV_0_S00_AXI_BASEADDR + 4 * i);

printf(“Reg %3d : %u ”, i, result);

}

}

void load_kernel(int filter[3][3]) {

UINTPTR kernel_addr = (UINTPTR) XPAR_CONV_0_S00_AXI_BASEADDR + 36;

Xil_Out32(kernel_addr, filter[0][0]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[0][1]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[0][2]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[1][0]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[1][1]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[1][2]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[2][0]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[2][1]);

kernel_addr = kernel_addr + 0x4;

Xil_Out32(kernel_addr, filter[2][2]);

}

void test_set() {

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, 3);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, 22);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, 16);

printf(“1 ”);

show_reg();

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, 21);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, 20);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, 14);

printf(“2 ”);

show_reg();

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, 19);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, 13);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, 7);

printf(“3 ”);

show_reg();

}

void Conv_SW(int filter[3][3], int arr[100][100], int arrW, int arrH) {

int i, j;

i = 2; j = 2;

for (i = 2; i 《 arrH; i++) {

for (j = 2; j 《 arrW;j++){

res[i][j] = 0;

res[i][j] += filter[0][0] * arr[i - 1][j - 1];

res[i][j] += filter[0][1] * arr[i - 1][j];

res[i][j] += filter[0][2] * arr[i - 1][j + 1];

res[i][j] += filter[1][0] * arr[i][j - 1];

res[i][j] += filter[1][1] * arr[i][j];

res[i][j] += filter[1][2] * arr[i][j + 1];

res[i][j] += filter[2][0] * arr[i + 1][j - 1];

res[i][j] += filter[2][1] * arr[i + 1][j];

res[i][j] += filter[2][2] * arr[i + 1][j + 1];

}

}

}

void Conv_HW(int filter[3][3], int arr[100][100], int arrW, int arrH) {

int i, j;

i = 2; j = 2;

for (i = 2; i 《 arrH; i++) {

//pre load

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, arr[i - 1][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, arr[i][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, arr[i + 1][j - 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, arr[i - 1][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, arr[i][j]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, arr[i + 1][j]);

for (j = 2; j 《 arrW; j++) {

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 8, arr[i - 1][j + 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 20, arr[i][j + 1]);

Xil_Out32(XPAR_CONV_0_S00_AXI_BASEADDR + 32, arr[i + 1][j + 1]);

res[i][j] = Xil_In32(XPAR_CONV_0_S00_AXI_BASEADDR + 72);

}

}

}

int main() {

printf(“HELLO WORLD”);

u32 result;

int filterW = 3;

int filterH = 3;

int arrW = 5;

int arrH = 5;

int resW = filterW + arrW - 1;

int resH = filterH + arrH - 1;

int i, j;

int pFilter[3][3];

int arr[100][100];

UINTPTR cur_addr = (UINTPTR) XPAR_CONV_0_S00_AXI_BASEADDR;

pFilter[0][0] = 1;

pFilter[0][1] = 3;

pFilter[0][2] = 1;

pFilter[1][0] = 0;

pFilter[1][1] = 5;

pFilter[1][2] = 0;

pFilter[2][0] = 2;

pFilter[2][1] = 1;

pFilter[2][2] = 2;

init_platform();

for (i = 0; i 《 9; i++) {

Xil_Out32(cur_addr, 0);

cur_addr = cur_addr + 4;

}

load_kernel(pFilter);

printf(“Kernel Loaded ”);

#ifdef test_single

test_set();

result = Xil_In32(XPAR_CONV_0_S00_AXI_BASEADDR + 72);

printf(“Test Set Result %u”, result);

show_reg();

#endif

#ifdef test_func

srand(10);

arrW = 20;

arrH = 20;

resH = filterH + arrH - 1;

resW = filterW + arrW - 1;

for (i = 0; i 《 arrH; i++) {

for (j = 0; j 《 arrW; j++) {

arr[i][j] = rand() % 20;

}

}

printf(“*********************************************** ”);

printf(“Filter: ”);

for (i = filterH - 1; i 》= 0; i--) {

for (j = filterW - 1; j 》= 0; j--) {

printf(“%d ”, pFilter[i][j]);

}

printf(“ ”);

}

printf(“*********************************************** ”);

printf(“Matrix: ”);

for (i = 0; i 《 arrH; i++) {

for (j = 0; j 《 arrW; j++) {

printf(“%4d ”, arr[i][j]);

}

printf(“ ”);

}

printf(“*********************************************** ”);

printf(“Software Start! ”);

Conv_SW(pFilter, arr, arrW, arrH);

printf(“ Software end! ”);

printf(“*********************************************** ”);

printf(“Result1: ”);

for (i = 0; i 《 resH; i++) {

for (j = 0; j 《 resW; j++) {

printf(“%5d ”, res[i][j]);

}

printf(“ ”);

}

for (i = 0; i 《 resH; i++) {

for (j = 0; j 《 resW; j++) {

res[i][j] = 0;

}

}

printf(“*********************************************** ”);

printf(“HardWare Start! ”);

Conv_HW(pFilter, arr, arrW, arrH);

printf(“ HardWare end!”);

printf(“Result2: ”);

for (i = 0; i 《 resH; i++) {

for (j = 0; j 《 resW; j++) {

printf(“%5d ”, res[i][j]);

}

printf(“ ”);

}

printf(“*********************************************** ”);

#endif

#ifdef test_speed

arrW = 500;

arrH = 500;

resH = filterH + arrH - 1;

resW = filterW + arrW - 1;

printf(“Software Start! ”);

for(i = 0; i《 200;i++) {

Conv_SW(pFilter, arr, arrW, arrH);

}

printf(“ Software end! ”);

printf(“HardWare Start! ”);

for(i = 0; i《 200;i++) {

Conv_HW(pFilter, arr, arrW, arrH);

}

printf(“ HardWare end!”);

cleanup_platform();

#endif

return 0;

}

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • IP核
    +關注

    關注

    4

    文章

    318

    瀏覽量

    49267
  • AXI
    AXI
    +關注

    關注

    1

    文章

    127

    瀏覽量

    16512
收藏 人收藏

    評論

    相關推薦

    基于IP橋接技術實現(xiàn)密碼算法多IP集成的應用方案設計

    分析上述兩種集成方法基礎上,本文基于方法二,給出了一種改進的多IP集成設計方法。
    的頭像 發(fā)表于 09-08 17:58 ?3537次閱讀
    基于<b class='flag-5'>IP</b>橋接技術<b class='flag-5'>實現(xiàn)</b>密碼算法多<b class='flag-5'>IP</b><b class='flag-5'>核</b>集成的應用方案設計

    有人知道為什么MIG IP中的AXI協(xié)議。為什么沒有AXI_WID這個信號呢?

    有人知道為什么MIG IP中的AXI協(xié)議。為什么沒有AXI_WID這個信號呢。
    發(fā)表于 04-13 09:22

    PCIE項目中AXI4 IP例化詳解

    ;next":選擇AXI4的IP:輸入IP的名稱:點擊"next":創(chuàng)建和使用AXI4的
    發(fā)表于 12-13 17:10

    基于MicroBlaze的AXI總線實時時鐘IP設計

    作者:薩其日娜 內(nèi)蒙古魯電電力工程有限公司 摘要: 應用MicroBlaze軟作為CPU的硬件平臺,在此平臺上設計了基于AXI總線的通用實時時鐘IP。給出了創(chuàng)建
    發(fā)表于 11-17 16:34 ?3842次閱讀

    AXI接口簡介_AXI IP的創(chuàng)建流程及讀寫邏輯分析

    本文包含兩部分內(nèi)容:1)AXI接口簡介;2)AXI IP的創(chuàng)建流程及讀寫邏輯分析。 1AXI
    的頭像 發(fā)表于 06-29 09:33 ?1.6w次閱讀
    <b class='flag-5'>AXI</b>接口簡介_<b class='flag-5'>AXI</b> <b class='flag-5'>IP</b><b class='flag-5'>核</b>的創(chuàng)建流程及讀寫邏輯<b class='flag-5'>分析</b>

    自定義sobel濾波IPIP接口遵守AXI Stream協(xié)議

    自定義sobel濾波IP IP接口遵守AXI Stream協(xié)議
    的頭像 發(fā)表于 08-06 06:04 ?3788次閱讀

    關于STM32各系列MCU性能對比及測試說明

    STM32各系列MCU性能對比及測試說明
    的頭像 發(fā)表于 03-04 10:20 ?1.3w次閱讀

    SoC設計中的IP與硬核的對比及方案選擇

    IP核可以兩種形式提供給客戶:軟和硬核。兩種方式都可使客戶獲得在功能上經(jīng)過驗證的設計。軟也被稱為可綜合內(nèi)核,需要由客戶進行綜合并在其SoC上實現(xiàn)。而硬核已完全
    發(fā)表于 01-07 07:32 ?3045次閱讀
    SoC設計中的<b class='flag-5'>IP</b>軟<b class='flag-5'>核</b>與硬核的<b class='flag-5'>對比及</b>方案選擇

    如何使用MicroBlaze調(diào)用AXI IP詳細解析

    在一項目中,當你使用microblaze作為控制器來進行系統(tǒng)調(diào)度的時候,一般是建議將所有模塊封裝成AXI形式的IP,這樣好管理,也容易調(diào)試。
    的頭像 發(fā)表于 04-27 11:17 ?6428次閱讀
    如何使用MicroBlaze調(diào)用<b class='flag-5'>AXI</b> <b class='flag-5'>IP</b><b class='flag-5'>核</b>詳細解析

    Xilinx FPGA里面的AXI DMA IP的簡單用法

    本文以浮點數(shù)Floating-point IP將定點數(shù)轉(zhuǎn)換為浮點數(shù)為例,詳細講解AXI DMA IP的使用
    的頭像 發(fā)表于 02-16 16:21 ?9072次閱讀
    Xilinx FPGA里面的<b class='flag-5'>AXI</b> DMA <b class='flag-5'>IP</b><b class='flag-5'>核</b>的簡單用法

    AXI4-Stream Video 協(xié)議和AXI_VDMA的IP介紹

    本文主要介紹關于AXI4-Stream Video 協(xié)議和AXI_VDMA的IP相關內(nèi)容。為后文完成使用帶有HDMI接口的顯示器構(gòu)建圖像視頻顯示的測試工程做準備。
    的頭像 發(fā)表于 07-03 16:11 ?7904次閱讀

    Video In to AXI4-Stream IP知識介紹

    大家好!今日分享一些關于Video In to AXI4-Stream IP 的知識。在具體學習IP的過程中,我也將分享一些關于如何看x
    的頭像 發(fā)表于 05-18 14:55 ?1442次閱讀
    Video In to <b class='flag-5'>AXI</b>4-Stream <b class='flag-5'>IP</b><b class='flag-5'>核</b>知識介紹

    簡單講解AXI Interconnect IP的使用方法

    最近需要用到AXI接口的模塊,xilinx的IP很多都用到了AXI總線進行數(shù)據(jù)和指令傳輸。如果有多個設備需要使用AXI協(xié)議對
    的頭像 發(fā)表于 06-19 15:45 ?8576次閱讀
    簡單講解<b class='flag-5'>AXI</b> Interconnect <b class='flag-5'>IP</b><b class='flag-5'>核</b>的使用<b class='flag-5'>方法</b>

    自定義AXI-Lite接口的IP及源碼分析

    在 Vivado 中自定義 AXI4-Lite 接口的 IP實現(xiàn)簡單的 LED 控制功能,并將其掛載到 AXI Interconnec
    發(fā)表于 06-25 16:31 ?2863次閱讀
    自定義<b class='flag-5'>AXI</b>-Lite接口的<b class='flag-5'>IP</b>及源碼<b class='flag-5'>分析</b>

    LogiCORE JTAG至AXI Master IP簡介

    LogiCORE JTAG至AXI Master IP是一可定制的,可生成AXIAXI總線可用于處理和驅(qū)動系統(tǒng)中FPGA內(nèi)部的
    的頭像 發(fā)表于 10-16 10:12 ?869次閱讀
    LogiCORE JTAG至<b class='flag-5'>AXI</b> Master <b class='flag-5'>IP</b><b class='flag-5'>核</b>簡介