<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

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

3天內不再提示

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

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

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

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

這次實現并逐漸優化了三個版本的卷積加速模塊,先簡要描述各個版本的主要內容。

版本一

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

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

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

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

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

9個寄存器單獨賦值,程序中分別向對應地址寫入內容,通過總線進行傳輸。

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

可以從驅動的書寫簡單理解一下:

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核的實現的方法_性能的對比及差異的分析

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

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

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

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

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

可以通過寫的驅動簡單理解一下:

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秒

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

兩個寄存器的乘法LUT太大,無法硬件優化

總線周期太慢太慢

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

版本二的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總線問題:

假設所有數據均來自于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 ?。?!

總結

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

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

附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,

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

// ********** 注意 這里是地址 下面是數據 ********

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

// to accept an address and associated control signals.

output wire S_AXI_AWREADY,

// 寫數據,32位到1024位寬

// 從主設備來的數據 從設備接收

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

input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,

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

// 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,

// 寫有效。為高指示數據有效。

// Write valid. This signal indicates that valid write

// data and strobes are available.

input wire S_AXI_WVALID,

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

// Write ready. This signal indicates that the slave

// can accept the write data.

output wire S_AXI_WREADY,

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

// Write response. This signal indicates the status

// of the write transaction.

output wire [1 : 0] S_AXI_BRESP,

// 寫響應有效。為高指示響應數據有效

// 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,

//

// 讀地址。讀地址給出突發數據傳輸的第一個傳輸地址。

// 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核的實現的方法_性能的對比及差異的分析

新建IP核如下:

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

工程頂層圖如下:

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

附3:軟件驅動

#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;

}

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

    關注

    4

    文章

    317

    瀏覽量

    49089
  • AXI
    AXI
    +關注

    關注

    1

    文章

    126

    瀏覽量

    16332
收藏 人收藏

    評論

    相關推薦

    玩轉賽靈思Zedboard開發板(5):基于AXI Lite總線的從設備IP設計

    本小節通過使用XPS中的定制IP向導(ipwiz),為已經存在的ARM PS 系統添加用戶自定IP(Custom IP ),了解AXI Lite I
    發表于 12-23 15:39 ?1.1w次閱讀

    基于IP的Viterbi譯碼器實現

    Viterbi譯碼的基本過程,接著根據Viterbi譯碼器IP的特點,分別詳細介紹了并行結構、混合結構和基于混合結構的增信刪余3種Viterbi譯碼器IP的主要
    發表于 04-26 16:08

    【鋯石A4 FPGA試用體驗】IP之PLL(一)新建IP

    :Tools---MegaWizard Plug-In Manager打開后,可以看到如下的界面,其中有三個選項。第一:創建IP第二
    發表于 09-23 21:44

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

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

    有人有經驗AXI4-Stream到視頻輸出IP嗎?

    現在我正在使用Xilinx的AXI視頻處理內核進行小型設計?,F在我面對一奇怪的問題。我的設計很簡單。我使用Xilinx的三個內核:1.測試模式發生器(TPG)2。視頻定時控制(VTC
    發表于 03-08 10:00

    PCIE項目中AXI4 IP例化詳解

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

    【fpga仿真輔助工具】AXI總線性能監測&分析工具——varon

    數據傳輸量,突發長度,延遲,和總線事務。它有助于用戶在設計初期對AXI總線的瓶頸進行分析。 VARONIP包括可配置的主站或從站IP,提供可合成的FPGA IP。這使得將
    發表于 11-02 16:54

    基于IP的FPGA設計方法是什么?

    的分類和特點是什么?基于IP的FPGA設計方法是什么?
    發表于 05-08 07:07

    XILINX MIG(DDR3) IPAXI接口與APP接口的區別以及優缺點對比

    XILINX MIG(DDR3) IPAXI接口與APP接口的區別以及優缺點對比
    發表于 11-24 21:47

    AXI FIFO和AXI virtual FIFO這兩IP的使用方法

    ,MicroBlaze 應用程序)可能會發生沖突。在 IP 定制時,我們能夠分配的空間需要注意。接下來創建一以 Xilinx FPGA(S7-50 )為目標的小項目,項目主要演示AXI Virtual FIFO
    發表于 11-04 11:03

    一步一步學ZedBoard Zynq(四):基于AXI Lite 總線的從設備IP設計

    本小節通過使用XPS中的定制IP向導(ipwiz),為已經存在的ARM PS 系統添加用戶自定IP(Custom IP ),了解AXI Lite I
    發表于 02-10 20:37 ?5513次閱讀

    AXI接口簡介_AXI IP核的創建流程及讀寫邏輯分析

    本文包含兩部分內容:1)AXI接口簡介;2)AXI IP核的創建流程及讀寫邏輯分析。 1AXI簡介(本部分內容參考官網資料翻譯) 自定義
    的頭像 發表于 06-29 09:33 ?1.5w次閱讀
    <b class='flag-5'>AXI</b>接口簡介_<b class='flag-5'>AXI</b> <b class='flag-5'>IP</b>核的創建流程及讀寫邏輯<b class='flag-5'>分析</b>

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

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

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

    在 Vivado 中自定義 AXI4-Lite 接口的 IP,實現一個簡單的 LED 控制功能,并將其掛載到 AXI Interconnect 總線互聯結構上,通過 ZYNQ 主機控制
    發表于 06-25 16:31 ?2259次閱讀
    自定義<b class='flag-5'>AXI</b>-Lite接口的<b class='flag-5'>IP</b>及源碼<b class='flag-5'>分析</b>

    LogiCORE JTAG至AXI Master IP核簡介

    中的一個參數來選擇。 集成設計環境(IDE)。AXI數據總線的寬度可定制。該IP可通過AXI4互連驅動AXI4-Lite或AXI4內存映射從
    的頭像 發表于 10-16 10:12 ?577次閱讀
    LogiCORE JTAG至<b class='flag-5'>AXI</b> Master <b class='flag-5'>IP</b>核簡介
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>