軟件版本:vitis2020.2(vivado2020.2)
操作系統:WIN10 64bit
硬件平台:適用XILINX A7/K7/Z7/ZU/KU系列FPGA(米聯客MZU07A-EG開發硬件平台)
登錄"米聯客"FPGA社區-www.uisrc.com視頻課程、答疑解惑!
1.1概述
使用XILINX 的軟件工具VIVADO以及XILINX的7代以上的FPGA或者SOC掌握AXI-4總線結束,並且可以靈活使用AXI-4總線技術完成數據的交換,可以讓我們在構建強大的FPGA內部總線數據互聯通信方面取得高效、高速、標准化的優勢。
本文實驗目的:
1:學習AXI總線協議包括AXI-FULL、AXI-Lite
2:掌握基於VIVADO工具產生AXI協議模板
3:掌握通過VIVADO工具產生AXI-lite-Slave代碼,並且會修改寄存器
4:理解AXI-lite-Slave中自定義寄存器的地址分配
5:掌握通過VIVADO封裝AXI-LITE-SLAVE 圖形化IP
6:通過仿真驗證AXI-LITE IP的工作是否正常。
1.2AXI總線協議介紹
1.2.1AXI總線概述
在XIINX FPGA的軟件工具vivado以及相關IP中有支持三種AXI總線,擁有三種AXI接口,當然用的都是AXI協議。其中三種AXI總線分別為:
AXI4:(For high-performance memory-mapped requirements.)主要面向高性能地址映射通信的需求,是面向地址映射的接口,允許最大256輪的數據突發傳輸;
AXI4-Lite:(For simple, low-throughput memory-mapped communication )是一個輕量級的地址映射單次傳輸接口,占用很少的邏輯單元。
AXI4-Stream:(For high-speed streaming data.)面向高速流數據傳輸;去掉了地址項,允許無限制的數據突發傳輸規模。
由於AXI4和AXI4-Lite信號大部分一樣,以下只介紹AXI4信號.另外對於AXI4-Stream協議不再本文中接收,后面有單獨介紹的文章。
1.2.2AXI-4總線信號功能
1:時鍾和復位
信號 |
方向 |
描述 |
ACLK |
時鍾源 |
全局時鍾信號 |
ARESETn |
復位源 |
全局復位信號,低有效 |
寫地址通道信號:
信號 |
方向 |
描述 |
AWID |
主機to從機 |
寫地址ID,用來標志一組寫信號 |
AWADDR |
主機to從機 |
寫地址,給出一次寫突發傳輸的寫地址 |
AWLEN |
主機to從機 |
AWLEN[7:0]決定寫傳輸的突發長度。AXI3只支持1~16次的突發傳輸(Burst_length=AxLEN[3:0]+1),AXI4擴展突發長度支持INCR突發類型為1~256次傳輸,對於其他的傳輸類型依然保持1~16次突發傳輸(Burst_Length=AxLEN[7:0]+1)。 burst傳輸具有如下規則: wraping burst ,burst長度必須是2,4,8,16 burst不能跨4KB邊界 不支持提前終止burst傳輸 |
AWSIZE |
主機to從機 |
寫突發大小,給出每次突發傳輸的字節數支持1、2、4、8、16、32、64、128 |
AWBURST |
主機to從機 |
突發類型: 2'b00 FIXED:突發傳輸過程中地址固定,用於FIFO訪問 2'b01 INCR :增量突發,傳輸過程中,地址遞增。增加量取決AxSIZE的值。 2'b10 WRAP:回環突發,和增量突發類似,但會在特定高地址的邊界處回到低地址處。回環突發的長度只能是2,4,8,16次傳輸,傳輸首地址和每次傳輸的大小對齊。最低的地址整個傳輸的數據大小對齊。回環邊界等於(AxSIZE*AxLEN) 2'b11 Reserved |
AWLOCK |
主機to從機 |
總線鎖信號,可提供操作的原子性 |
AWCACHE |
主機to從機 |
內存類型,表明一次傳輸是怎樣通過系統的 |
AWPROT |
主機to從機 |
保護類型,表明一次傳輸的特權級及安全等級 |
AWQOS |
主機to從機 |
質量服務QoS |
AWREGION |
主機to從機 |
區域標志,能實現單一物理接口對應的多個邏輯接口 |
AWUSER |
主機to從機 |
用戶自定義信號 |
AWVALID |
主機to從機 |
有效信號,表明此通道的地址控制信號有效 |
AWREADY |
從機to主機 |
表明"從"可以接收地址和對應的控制信號 |
2:寫數據通道信號:
信號名 |
方向 |
描述 |
WID |
主機to從機 |
一次寫傳輸的ID tag |
WDATA |
主機to從機 |
寫數據 |
WSTRB |
主機to從機 |
WSTRB[n:0]對應於對應的寫字節,WSTRB[n]對應WDATA[8n+7:8n]。WVALID為低時,WSTRB可以為任意值,WVALID為高時,WSTRB為高的字節線必須指示有效的數據。 |
WLAST |
主機to從機 |
表明此次傳輸是最后一個突發傳輸 |
WUSER |
主機to從機 |
用戶自定義信號 |
WVALID |
主機to從機 |
寫有效,表明此次寫有效 |
WREADY |
從機to主機 |
表明從機可以接收寫數據 |
寫響應信號:
信號名 |
方向 |
描述 |
BID |
從機to主機 |
寫響應ID tag |
BRESP |
從機to主機 |
寫響應,表明寫傳輸的狀態 |
BUSER |
從機to主機 |
用戶自定義 |
BVALID |
從機to主機 |
寫響應有效 |
BREADY |
主機to從機 |
表明主機能夠接收寫響應 |
3:讀地址通道信號:
信號 |
方向 |
描述 |
ARID |
主機to從機 |
讀地址ID,用來標志一組寫信號 |
ARADDR |
主機to從機 |
讀地址,給出一次讀突發傳輸的讀地址 |
ARLEN |
主機to從機 |
ARLEN[7:0]決定讀傳輸的突發長度。AXI3只支持1~16次的突發傳輸(Burst_length=AxLEN[3:0]+1),AXI4擴展突發長度支持INCR突發類型為1~256次傳輸,對於其他的傳輸類型依然保持1~16次突發傳輸(Burst_Length=AxLEN[7:0]+1)。 burst傳輸具有如下規則: wraping burst ,burst長度必須是2,4,8,16 burst不能跨4KB邊界 不支持提前終止burst傳輸 |
ARSIZE |
主機to從機 |
讀突發大小,給出每次突發傳輸的字節數支持1、2、4、8、16、32、64、128 |
ARBURST |
主機to從機 |
突發類型: 2'b00 FIXED:突發傳輸過程中地址固定,用於FIFO訪問 2'b01 INCR :增量突發,傳輸過程中,地址遞增。增加量取決AxSIZE的值。 2'b10 WRAP:回環突發,和增量突發類似,但會在特定高地址的邊界處回到低地址處。回環突發的長度只能是2,4,8,16次傳輸,傳輸首地址和每次傳輸的大小對齊。最低的地址整個傳輸的數據大小對齊。回環邊界等於(AxSIZE*AxLEN) 2'b11 Reserved |
ARLOCK |
主機to從機 |
總線鎖信號,可提供操作的原子性 |
ARCACHE |
主機to從機 |
內存類型,表明一次傳輸是怎樣通過系統的 |
ARPROT |
主機to從機 |
保護類型,表明一次傳輸的特權級及安全等級 |
ARQOS |
主機to從機 |
質量服務QoS |
ARREGION |
主機to從機 |
區域標志,能實現單一物理接口對應的多個邏輯接口 |
ARUSER |
主機to從機 |
用戶自定義信號 |
ARVALID |
主機to從機 |
有效信號,表明此通道的地址控制信號有效 |
ARREADY |
從機to主機 |
表明"從"可以接收地址和對應的控制信號 |
4:讀數據通道信號:
信號名 |
方向 |
描述 |
RID |
從機to主機 |
一次讀傳輸的ID tag |
RDATA |
從機to主機 |
讀數據 |
RRESP |
從機to主機 |
讀響應,表明讀傳輸的狀態 |
RLAST |
從機to主機 |
表明此次傳輸是最后一個突發傳輸 |
RUSER |
從機to主機 |
用戶自定義信號 |
RVALID |
從機to主機 |
寫有效,表明此次寫有效 |
RREADY |
主機to從機 |
表明從機可以接收寫數據 |
1.2.3數據有效的情況
AXI4所采用的是一種READY,VALID握手通信機制,簡單來說主從雙方進行數據通信前,有一個握手的過程。傳輸源產生VLAID信號來指明何時數據或控制信息有效。而目地源產生READY信號來指明已經准備好接受數據或控制信息。傳輸發生在VALID和READY信號同時為高的時候。VALID和READY信號的出現有三種關系。
-
VALID先變高READY后變高。時序圖如下:
在箭頭處信息傳輸發生。
-
READY先變高VALID后變高。時序圖如下:
同樣在箭頭處信息傳輸發生。
-
VALID和READY信號同時變高。時序圖如下:
在這種情況下,信息傳輸立馬發生,如圖箭頭處指明信息傳輸發生。
1.2.4突發式讀寫
1:突發式寫時序圖
這一過程的開始時,主機發送地址和控制信息到寫地址通道中,然后主機發送每一個寫數據到寫數據通道中。當主機發送最后一個數據時,WLAST信號就變為高。當設備接收完所有數據之后他將一個寫響應發送回主機來表明寫事務完成。
2:突發式讀的時序圖
當地址出現在地址總線后,傳輸的數據將出現在讀數據通道上。設備保持VALID為低直到讀數據有效。為了表明一次突發式讀寫的完成,設備用RLAST信號來表示最后一個被傳輸的數據。
1.3創建axi4-lite-slave總線接口IP
新建fpga工程,過程省略
新建完成工程后,單擊菜單欄Tools->Create and Package New IP,開始創建一個AXI4-Lite接口總線IP
選擇使用vivado自帶的AXI總線模板創建一個AXI4-Lite接口IP
設置IP的名字為saxi_lite
模板支持3中協議,分別是AXI4-Full AXI4-Lite AXI4-Stream
總線包括Master和Slave兩種模式,這里選擇Slave模式
這里選擇Verify Peripheral IP using AXI4 VIP 可以對AXI4-Lite快速驗證
單擊Finish 后展開VIVADO自動產生的demo,單擊Block Design的工程,可以看到如下2個IP。其中saxi_lite_0就是我們自定義的IP,另外一個master_0是用來讀寫我們自定義的saxi_lite_0,以此驗證我們的IP正確性。
繼續站看代碼看看里面有什么東西
右擊Generate Output Products
路徑uisrc/03_ip/saxi_lite_1.0/hdl路徑下的saxi_lite_v_0_S00_AXI.v就是我們的源碼。另外一個saxi_lite_v1_0.v是軟件產生了一個接口文件,如果我們自己定義IP可有可無。
1.4程序分析
axi總線信號的關鍵無非是地址和數據,而寫地址的有效取決於AXI_AWVALID和AXI_AWREADY,寫數據的有效取決於S_AXI_WVALID和S_AXI_WREADY。同理,讀地址的有效取決於AXI_ARVALID和AXI_ARREADY,讀數據的有效取決於S_AXI_RVALID和S_AXI_RREADY。所以以下代碼的閱讀分析注意也是圍繞以上4個信號的有效時序。
以下程序我們把關鍵信號的代碼拆分閱讀
1:axi-lite-slave的axi_awready
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awready <= 1'b0;
aw_en <= 1'b1;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)
begin
// slave is ready to accept write address when
// there is a valid write address and write data
// on the write address and data bus. This design
// expects no outstanding transactions.
axi_awready <= 1'b1;
aw_en <= 1'b0;
end
else if (S_AXI_BREADY && axi_bvalid)
begin
aw_en <= 1'b1;
axi_awready <= 1'b0;
end
else
begin
axi_awready <= 1'b0;
end
end
end
2:axi-lite-slave的axi_awaddr
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_awaddr <= 0;
end
else
begin
if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)
begin
// Write Address latching
axi_awaddr <= S_AXI_AWADDR;
end
end
end
3:axi-lite-slave的axi_wready
當滿足(~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )==1條件,設置axi_wready有效。
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_wready <= 1'b0;
end
else
begin
if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )
begin
// slave is ready to accept write data when
// there is a valid write address and write data
// on the write address and data bus. This design
// expects no outstanding transactions.
axi_wready <= 1'b1;
end
else
begin
axi_wready <= 1'b0;
end
end
end
4:axi-lite-slave的寫數據寄存器
axi-lite-slave很重要一點功能就是配合SOC的處理器部分完成一些低速外設,或者寄存器的控制。需要使用多寄存器或者外設,一般在ip代碼里面就已經設置好了。前面用vivado的模板產生自定義ip的時候,我們選擇了4個32bits寄存器,以下的模板中slv_reg0~ slv_reg3共計4個32bits寄存器。
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;
end
else begin
if (slv_reg_wren)
begin
case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
2'h0:
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
2'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
2'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
2'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
default : begin
slv_reg0 <= slv_reg0;
slv_reg1 <= slv_reg1;
slv_reg2 <= slv_reg2;
slv_reg3 <= slv_reg3;
end
endcase
end
end
end
5:axi-lite-slave的axi_bvalid信號
axi_bvalid用於告知axi master axi-slave端已經完成數據接收了
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_bvalid <= 0;
axi_bresp <= 2'b0;
end
else
begin
if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
begin
// indicates a valid write response is available
axi_bvalid <= 1'b1;
axi_bresp <= 2'b0; // 'OKAY' response
end // work error responses in future
else
begin
if (S_AXI_BREADY && axi_bvalid)
//check if bready is asserted while bvalid is high)
//(there is a possibility that bready is always asserted high)
begin
axi_bvalid <= 1'b0;
end
end
end
end
6:axi-lite-slave的axi_arready
當條件滿足(~axi_arready && S_AXI_ARVALID)==1設置axi_arready有效,並且寄存住總線上的地址axi_araddr <= S_AXI_ARADDR
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_arready <= 1'b0;
axi_araddr <= 32'b0;
end
else
begin
if (~axi_arready && S_AXI_ARVALID)
begin
// indicates that the slave has acceped the valid read address
axi_arready <= 1'b1;
// Read address latching
axi_araddr <= S_AXI_ARADDR;
end
else
begin
axi_arready <= 1'b0;
end
end
end
7:axi-lite-slave的axi_araddr
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_arready <= 1'b0;
axi_araddr <= 32'b0;
end
else
begin
if (~axi_arready && S_AXI_ARVALID)
begin
// indicates that the slave has acceped the valid read address
axi_arready <= 1'b1;
// Read address latching
axi_araddr <= S_AXI_ARADDR;
end
else
begin
axi_arready <= 1'b0;
end
end
end
8:axi-lite-slave的axi_rvalid信號
當條件滿足(axi_arready && S_AXI_ARVALID && ~axi_rvalid)==1的時候設置axi_rvalid有效,表示axi-lite-slave總線上的數據是有效的。
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rvalid <= 0;
axi_rresp <= 0;
end
else
begin
if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)
begin
// Valid read data is available at the read data bus
axi_rvalid <= 1'b1;
axi_rresp <= 2'b0; // 'OKAY' response
end
else if (axi_rvalid && S_AXI_RREADY)
begin
// Read data is accepted by the master
axi_rvalid <= 1'b0;
end
end
end
assign S_AXI_RVALID = axi_rvalid;
9:axi-lite-slave的讀數據寄存器
本文實驗中,axi-master寫入4個寄存器數據,然后讀出,通過查看數據是否一致可以確認axi-lite-slave工作是否正常。當slv_reg_rden有效的時候,數據被讀入寄存器axi_rdata,當axi_rvalid有效的時候,數據被鎖存。
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] )
2'h0 : reg_data_out <= slv_reg0;
2'h1 : reg_data_out <= slv_reg1;
2'h2 : reg_data_out <= slv_reg2;
2'h3 : reg_data_out <= slv_reg3;
default : reg_data_out <= 0;
endcase
end
always @( posedge S_AXI_ACLK )
begin
if ( S_AXI_ARESETN == 1'b0 )
begin
axi_rdata <= 0;
end
else
begin
// When there is a valid read address (S_AXI_ARVALID) with
// acceptance of read address by the slave (axi_arready),
// output the read dada
if (slv_reg_rden)
begin
axi_rdata <= reg_data_out; // register read data
end
end
end
當我們閱讀后分析完以上代碼后,可以發現,axi-lite-slave的代碼中沒有突發長度的處理,每次只處理一個地址的一個數據。並且也沒有WLAST和RLAST信號,說明axi-lite-slave適合一些低速的數據交互,但是可以節省一些FPGA的邏輯資源。
1.5實驗結果
單擊仿真
添加觀察信號
AXI總下依次寫入1 2 3 4,slv_reg0~slv_reg3完成數據寄存
讀數據