Zynq-PL中創建AXI Master接口IP及AXI4-Lite總線主從讀寫時序測試(轉)


 

轉載:原文  http://www.eefocus.com/antaur/blog/17-08/423751_6cc0d.html

0. 引言

通過之前的學習,可以在PL端創建從機模式的AXI接口IP核。但是從機模式是被動接收數據,而不能主動的去獲取數據,因此計划研究一下AXI Master接口的IP核的構建方法。 

1. 利用向導創建AXI Lite Master測試用例

 

 

image001.png

image003.png

 

image005.png

 

image007.png

image009.png

在這一步,AXI類型為Lite型的,可選參數如下所示:

image011.png

在這里,重點是Interface Mode,前面的實驗中采用的是默認配置Slave,即設計的IP接口為從機。本實驗中,要將其設置為Master。

下面的三個參數跟Sl**e模式下可配置的參數類型是相同的。具體的說明如下所示:

image013.png

Data Width:為數據總線的位寬,單位為bits

image015.png

Memory Size:只有在IP類型為AXI FULL Slave模式下才有效,目前不討論。

image017.png

Number of Registers:只有在IP接口類型為AXI Lite Slave模式下才有效,可以參看之前的實驗說明。

 

image019.png

 

 

至此,利用向導工具創建一個AXI Lite Master類型的IP接口配置完畢。

 

2. 源碼分析

2.1 頂層源碼解析

系統會自動生成一個該IP的工程,可以查看生成的源代碼,並在此基礎上進行修改。

 

 

image021.png

 

 

從上圖可以看出,向導工具就生成了兩個模塊。直接綜合后,查看RTL級圖的操作入口如下所示:

image023.png

顯示結果如下:

image025.png

可以看出頂層模塊只是做了簡單的直連封裝,內部沒有任何邏輯設計,查看代碼(附錄1)也是如此,唯一有用的操作配置了內層模塊實例的參數。

具體配置測參數如下所示:

image027.png

 

 

可以看到配置了5個參數,其中:

C_M00_AXI_ADDR_WIDTH表示地址總線的位寬,這里配置為32bits,由於涉及到總線的協議,建議不要動這個參數。

C_M00_AXI_DATA_WIDTH表示數據總線的位寬,這里配置為32bits,同樣的原因,建議不要動這個參數。

其余的三個參數是根據測試用例的用戶邏輯相關的,具體意義在底層模塊的源碼分析(附錄2)中會詳細解釋,這里簡單說明一下:

C_M00_AXI_TARGET_SLAVE BASE_ADDR表示本IP作為主機欲訪問的從機內存的基地址。

C_M00_AXI_START_DATA_VALUE表示對從機寄存器進行寫入操作的測試數據

C_M00_AXI_TRANSACTIONS_NUM表示測試的次數

具體邏輯及各參數的意義見下文對底層模塊的解析。

 

image029.png

2.2 底層源碼解析

向導自動生成的示例程序中底層模塊為AzIP_AXI_Master_Ex1_v1_0_M00_AXI,該模塊並不是一個Master型的IO標准接口,而只是一個用戶測試用例的邏輯操作。而Master的Write和Read讀寫邏輯並沒有很完畢的封裝,需要仔細分析示例代碼進行拆分。

具體的代碼解析詳見后面附錄2的注釋說明,這里給出的僅是本人對此分析得到的筆記。

  1. 測試業務邏輯

 

測試業務邏輯的本質如下圖所示,就是一個典型的內存讀寫操作的測試流程。

image032.gif

 

 

代碼編寫時采用狀態機的方式。

image033.png

 

其中:

 

【地址操作分析】:

從機寄存器的初始地址有變量C_M00_AXI_TARGET_SLAVE_BASE_ADDR定義,在構建集成系統時,對應從機的內存映射必須於配置相同。

AXI總線上寫操作地址總線綁定如下,C_M00_AXI_TARGET_SLAVE_BASE_ADDR為基地址,而axi_awaddr定義地址偏移量。

image035.png

image037.png

段內地址偏移量初始化值為0,每次寫入成功后,地址偏移量+4,這是因為地址定義的單位是字節Byte,而數據總線為32bits,即4個字節,因此沒寫入32bits,會用掉從機4個地址的存儲空間。

 

image039.png

 

關於讀取操作指定寄存器的地址定義及處理過程是類似的。

【數據操作分析】:

寫操作使用的數據總線綁定到一個內部寄存器上。

 

image041.png 

初始化時,測試數據寄存器被設置為參數配置的數值,之后每次加1。 

image043.png

 

image045.png

測試數據向從機寫入之后,內部備份保存一份,存在寄存器expected_rdata中,代碼如下:

image047.png

可以看到代碼邏輯完全相同,但是整個代碼架構真的不敢苟同。

 

數據比較段的代碼如下:

image049.png

相應的邏輯應該是一旦有一次出錯,read_mismatch就置為1,如果下次對了,該狀態寄存器仍然保持數據為1,直到復位操作。

 

(2)AXI4-Lite總線接口定義

在進行AXI4-Lite總線讀寫時序操作時,首先要明確總線的讀寫操作接口。

查看相關技術文檔,這里主要用到以下兩個技術文檔:

  • ARM公司發布的《ARM AMBA AXI Protocol v2.0 Specification》
  • Xilinx公司發布的《Vivado Design Suite : AXI Reference Guide》UG1037(v3.0)2015

    image051.png

    可以看到,無論是AXI4總線還是精簡版的AXI4-Lite總線接口分成5大類,這5大類又分別****於Write操作核Read操作。

     

    Write操作

    1. 寫地址:主機-->從機
    2. 寫數據:主機-->從機
    3. 寫應答:從機-->主機

    Read操作

    1. 讀地址:主機-->從機
    2. 讀數據:從機-->主機
     

下面重點研究一下AXI4-Lite總線具體是如何定義的,它與AXI4總線協議有什么不同?

首先看一下AXI4總線協議的官方定義:

image053.png

再看一下AXI4-Lite總線協議的官方定義:

 

image055.png

 

不支持突發(burst)傳輸模式,及burst length=1

數據總線寬度只能為32bit或則64bits

不支持獨家訪問(exclusive accesses)

image057.png

即AXI4-Lite不支持突發(burst)傳輸模式。

【說明】關於突發(burst)傳輸模式是否采用將在后面分析讀寫時序時重點討論。這里先鋪墊一下。

image059.png

AXI4總線,由於讀寫通道是分離的,可以提供實時雙向的數據傳輸。

采用突發(burst)傳輸模式,可以在發送1個地址之后,最多支持突發256words的數據。(Words??2字節嗎??)

 

下面看一下AXI4-Lite總線協議的物理接口Port的定義:

image061.png

可以看出除了時鍾和復位信號后,也是前文介紹的5類信號通道。

但是作為一個簡化的總線協議,其物理接口應該比完整版的AXI4總線要少,具體精簡掉了哪些?詳見下表。

 

image063.png

 

學習完原理性的基礎知識之后,我們來看一下示例程序代碼是否符合官方標准。

分析AXI Master示例IP源代碼的Port定義,代碼即注釋說明如下所示:

【AXI4-Lite Write Address Channel】

image065.png

 

 

image067.png

image069.png

 

 

在示例程序中,AXI Master模塊的M_AXI_AWPROT管腳始終輸出為:3’b000

【AXI4-Lite Write data Channel】

 

image071.png

 

 

其中端口M_AXI_ARPROT,參見【AXI4-Lite Write Address Channel】中的M_AXI_AWPROT

 

【AXI4-Lite Read Data Channel】

 

 

image071.png

 

 

image079.png

image075.png

在示例程序中,AXI Master模塊由於數據總線位寬為32bit,因此M_AXI_WSTRB管腳始終輸出為:4’b1111

 

【AXI4-Lite Write response Channel】

image077.png

image079.png

image081.png

 

 

【AXI4-Lite Read Address Channel】

 

 

image083.png

 

其中端口M_AXI_ARPROT,參見【AXI4-Lite Write Address Channel】中的M_AXI_AWPROT

 

【AXI4-Lite Read Data Channel】

 

image083.png

其中端口M_AXI_RRESP,參見【AXI4-Lite Write response Channel】中的M_AXI_BRESP 

image085.png

其中端口M_AXI_RRESP,參見【AXI4-Lite Write response Channel】中的M_AXI_BRESP

 

(3)AXI4-Lite總線讀寫時序分析1--寫入操作時序

研究總線協議的交互時序,必須依賴協議標准,但是能夠查到的官方協議標准均沒有對AXI4-Lite總線的讀寫時序進行獨立的時序設定。

Xilinx公司發布的文檔,引用的還是ARM公司發布的文檔,對於總線寫入時序邏輯示意圖如下:

image087.png

表示,主機需要先寫地址,然后寫入一系列數據,為什么是四個暫時不確定,從機處理完畢后回復一個應答響應。

 

ARM公司發布的文檔《ARM AMBA AXI Protocol v2.0 Specification》中沒有AXI4-Lits的寫入時序邏輯,只有Write brust的時序示意圖。如下所示

 

image089.png

 

經過前面的研究,知道AXI4-Lite是brust length=1的Write brust,因此我自行簡化上述時序圖如下:

 image091.png

如果主機連續發送兩次數據寫入操作,我猜測的時序邏輯圖應該如下所示: 

image093.png

分析示例程序中,AXI Master模塊的源代碼,繪制相應的主機向從機寫入數據的時序邏輯如下圖所示:

 

image096.gif

查看代碼,分析得到的時序與個人分析得到的原理時序並不完全匹配。這里先鋪墊一下,后文將會對示例源碼的時序進行仿真分析,得到對應可用的時序,用於將來自行編寫接口時使用。記得看下文。

(4) AXI4-Lite總線讀寫時序分析2--讀取操作時序

同樣先學習一下官方協議。 

image097.png

以及來自官方文檔的讀取操作時序圖。

image099.png

同樣自行分析對於brust length=1的AXI4-Lite總線,讀取操作的時序圖如下所示 

image101.png

示例代碼的操作時序這里就不在畫處理流程圖了。下文會通過時序仿真給出示例中采用的時序關系。

(5) 示例工程的時序分析

【工程創建的原始出發點】:

根據上述對AXI4-Lite總線接口的分析,其實就是主機和從機之間的數據通信。聯想到之間創建的AXI4-Lite Sl**e示例IP核,是否能創建一個頂層模塊直接將AXI4-Lite Sl**e示例IP核與AXI4-Lite Sl**e示例IP核直接相連,完成AXI4-Lite總線讀寫操作?

為了驗證上述想法,首先再創建一個AXI4-Lite Sl**e示例IP核,參數要與AXI4-Lite Master示例IP核的參數向對應,下面將端口定義對比如下:

 

image103.png

從上圖的對比中,可以看出AXI4-Lite主從機的接口其實是一一匹配的。

創建一個頂層文件Top_AXI4_Lite_Interfce_Demo,將生成的主從示例直接對連。代碼見附錄3.相應的層級結構如下圖所示。

 

image105.png

綜合完的RTL級連接圖如下所示。

 

image107.png

對該頂層文件創建仿真驅動,代碼如下所示:

`timescale 1ns / 1ps
module Sim_AXI4_Lite_Interface(); reg axi_ACLK; // AXI總線時鍾 reg axi_ARESETn; // 系統復位信號,低電平有效 reg r_app_txn; // 應用級復位信號,負脈沖,上升沿復位 wire w_err; // 狀態指示,異常 wire w_txn_done; // 狀態指示,發送完畢 Top_AXI4_Lite_Interfce_Demo Ut1 (
.axi_ACLK(axi_ACLK), .axi_ARESETn(axi_ARESETn), .app_TXn(r_app_txn), .state_err(w_err), .state_done(w_txn_done) );
parameter PERIOD = 2; always begin #(PERIOD/2); axi_ACLK = ~axi_ACLK; end initial begin axi_ACLK = 1'b0; axi_ARESETn = 1'b1; r_app_txn = 1'b1; #(10*PERIOD); axi_ARESETn = 1'b0; #(5*PERIOD); r_app_txn = 1'b0; #(2*PERIOD); axi_ARESETn = 1'b1; #(4*PERIOD); r_app_txn = 1'b1; end endmodule

 

 

運行后的仿真結果如下所示: 

 

仿真結果1:先寫入4次,然后讀取4次的時序仿真結果

 

image109.png

仿真結果2:先寫入1次,然后讀取1次的時序仿真結果

image111.png

仿真結果3:僅寫入1次時序仿真結果

image113.png

                                              仿真結果4:僅讀取1次時序仿真結果

 

image115.png

仿真結果5:先寫入2次,再讀取2次時序仿真結果

image117.png

  • 對比仿真得到的寫入操作時序和從官網文檔分析得到的時序

 

image119.png

【個人心得】

可以看出,AXI4中設定的5類通道都是相互獨立的,示例仿真中,應為AWVALID和WVALID是同時給從機的,從機就同時采樣AWADDR總線和WDATA總線數據,並同時給出了應答AWREADY和WREADY。

從機在匹配完Address和Data后,給出應答BVALID。

而官方文檔上的時序時先發地址后發數據,正常的從機也是能夠正確響應的。

結論,自行編寫接口時,每個通道要獨立處理,不要耦合到一起。

  • 對比仿真得到的讀取操作時序和從官網文檔分析得到的時序

 

image121.png

【個人心得】

由於沒有經過總線控制器,而是直連的,因此時序仿真結果圖中從機的響應速度很快,而原理圖中有個響應處理延時。

 

2. 總結

通過本學習筆記,詳細分析了AXI4-Lite總線主機端的交互處理時序,以后就可以自行編寫主從機的接口了。

 


附錄1:頂層模塊源代碼:

 `timescale 1ns / 1ps
module Top_AXI4_Lite_Interfce_Demo
#(
parameter  C_AXI_START_DATA_VALUE  = 32'hAA000000,
parameter  C_AXI_TARGET_SLAVE_BASE_ADDR  = 32'h40000000,
parameter integer C_AXI_ADDR_WIDTH  = 32,
parameter integer C_AXI_DATA_WIDTH  = 32,
parameter integer C_AXI_TRANSACTIONS_NUM  = 4
)
(
    input axi_ACLK,
    input axi_ARESETn,
    input app_TXn,
    output state_err,
    output state_done
    );
    wire w_err;       // 狀態指示,異常
    wire w_txn_done;  // 狀態指示,發送完畢
    assign state_err  = w_err;
    assign state_done = w_txn_done;
wire [C_AXI_ADDR_WIDTH-1 : 0] axi_AWADDR; // AXI總線信號:AWADDR wire [2 : 0] axi_AWPROT; // AXI總線信號:AWPROT wire axi_AWVALID; // AXI總線信號:AWVALID wire axi_AWREADY; // AXI總線信號:AWREAD wire [C_AXI_DATA_WIDTH-1 : 0] axi_WDATA; // AXI總線信號:WDATA wire [C_AXI_DATA_WIDTH/8-1 : 0] axi_WSTRB; // AXI總線信號:WSTRB wire axi_WVALID; // AXI總線信號:WVALID wire axi_WREADY; // AXI總線信號:WREADY wire [1 : 0] axi_BRESP; // AXI總線信號:BRESP wire axi_BVALID; // AXI總線信號:BVALID wire axi_BREADY; // AXI總線信號:BREADY wire [C_AXI_ADDR_WIDTH-1 : 0] axi_ARADDR; // AXI總線信號:ARADDR wire [2 : 0] axi_ARPROT; // AXI總線信號:ARPROT wire axi_ARVALID; // AXI總線信號:ARVALID wire axi_ARREADY; // AXI總線信號:ARREADY wire [C_AXI_DATA_WIDTH-1 : 0] axi_RDATA; // AXI總線信號:RDATA wire [1 : 0] axi_RRESP; // AXI總線信號:RRESP wire axi_RVAILD; // AXI總線信號:RVAILD wire axi_RREADY; // AXI總線信號:RREADY

axi_ip_master_v1_0 # ( .C_M00_AXI_START_DATA_VALUE(C_AXI_START_DATA_VALUE), .C_M00_AXI_TARGET_SLAVE_BASE_ADDR(C_AXI_TARGET_SLAVE_BASE_ADDR), .C_M00_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), .C_M00_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), .C_M00_AXI_TRANSACTIONS_NUM(C_AXI_TRANSACTIONS_NUM) ) Ut1 ( //-- AXI4-Lite Global ---------------------------------------------- .m00_axi_aclk(axi_ACLK), .m00_axi_aresetn(axi_ARESETn), //------------------------------------------------------------------ .m00_axi_init_axi_txn(app_TXn), .m00_axi_error(w_err), .m00_axi_txn_done(w_txn_done), //--- AXI4-Lite Write Address Channel ------------------------------ .m00_axi_awaddr(axi_AWADDR), .m00_axi_awprot(axi_AWPROT), .m00_axi_awvalid(axi_AWVALID), .m00_axi_awready(axi_AWREADY), //--- AXI4-Lite Write data Channel ------------------------------ .m00_axi_wdata(axi_WDATA), .m00_axi_wstrb(axi_WSTRB), .m00_axi_wvalid(axi_WVALID), .m00_axi_wready(axi_WREADY), //--- AXI4-Lite Write response Channel ------------------------------ .m00_axi_bresp(axi_BRESP), .m00_axi_bvalid(axi_BVALID), .m00_axi_bready(axi_BREADY), //--- AXI4-Lite Read Address Channel ------------------------------ .m00_axi_araddr(axi_ARADDR), .m00_axi_arprot(axi_ARPROT), .m00_axi_arvalid(axi_ARVALID), .m00_axi_arready(axi_ARREADY), //--- AXI4-Lite Read Data Channel ------------------------------ .m00_axi_rdata(axi_RDATA), .m00_axi_rresp(axi_RRESP), .m00_axi_rvalid(axi_RVAILD), .m00_axi_rready(axi_RREADY) ); axi_ip_slave_v1_0 # ( .C_S00_AXI_DATA_WIDTH(C_AXI_ADDR_WIDTH), .C_S00_AXI_ADDR_WIDTH(7) ) Ut2 ( //-- AXI4-Lite Global ---------------------------------------------- .s00_axi_aclk(axi_ACLK), .s00_axi_aresetn(axi_ARESETn), //--- AXI4-Lite Write Address Channel ------------------------------ .s00_axi_awaddr(axi_AWADDR[6:0]), //注意:只有段地址!!!!!,做的axi_slave_ip的地址位寬為7,寄存器個數為32 .s00_axi_awprot(axi_AWPROT), .s00_axi_awvalid(axi_AWVALID), .s00_axi_awready(axi_AWREADY), //--- AXI4-Lite Write data Channel -------------------------------- .s00_axi_wdata(axi_WDATA), .s00_axi_wstrb(axi_WSTRB), .s00_axi_wvalid(axi_WVALID), .s00_axi_wready(axi_WREADY), //--- AXI4-Lite Write response Channel ------------------------------ .s00_axi_bresp(axi_BRESP), .s00_axi_bvalid(axi_BVALID), .s00_axi_bready(axi_BREADY), //--- AXI4-Lite Read Address Channel ------------------------------ .s00_axi_araddr(axi_ARADDR), .s00_axi_arprot(axi_ARPROT), .s00_axi_arvalid(axi_ARVALID), .s00_axi_arready(axi_ARREADY), //--- AXI4-Lite Read Data Channel ------------------------------ .s00_axi_rdata(axi_RDATA), .s00_axi_rresp(axi_RRESP), .s00_axi_rvalid(axi_RVAILD), .s00_axi_rready(axi_RREADY) ); endmodule 附錄2:底層模塊MASTER 頂層源代碼: `timescale 1 ns / 1 ps module axi_ip_master_v1_0 # ( // Users to add parameters here // User parameters ends // Do not modify the parameters beyond this line // Parameters of Axi Master Bus Interface M00_AXI parameter C_M00_AXI_START_DATA_VALUE = 32'hAA000000, parameter C_M00_AXI_TARGET_SLAVE_BASE_ADDR = 32'h40000000, parameter integer C_M00_AXI_ADDR_WIDTH = 32, parameter integer C_M00_AXI_DATA_WIDTH = 32, parameter integer C_M00_AXI_TRANSACTIONS_NUM = 4 ) ( // Users to add ports here // User ports ends // Do not modify the ports beyond this line // Ports of Axi Master Bus Interface M00_AXI input wire m00_axi_init_axi_txn, output wire m00_axi_error, output wire m00_axi_txn_done, input wire m00_axi_aclk, input wire m00_axi_aresetn, output wire [C_M00_AXI_ADDR_WIDTH-1 : 0] m00_axi_awaddr, output wire [2 : 0] m00_axi_awprot, output wire m00_axi_awvalid, input wire m00_axi_awready, output wire [C_M00_AXI_DATA_WIDTH-1 : 0] m00_axi_wdata, output wire [C_M00_AXI_DATA_WIDTH/8-1 : 0] m00_axi_wstrb, output wire m00_axi_wvalid, input wire m00_axi_wready, input wire [1 : 0] m00_axi_bresp, input wire m00_axi_bvalid, output wire m00_axi_bready, output wire [C_M00_AXI_ADDR_WIDTH-1 : 0] m00_axi_araddr, output wire [2 : 0] m00_axi_arprot, output wire m00_axi_arvalid, input wire m00_axi_arready, input wire [C_M00_AXI_DATA_WIDTH-1 : 0] m00_axi_rdata, input wire [1 : 0] m00_axi_rresp, input wire m00_axi_rvalid, output wire m00_axi_rready ); // Instantiation of Axi Bus Interface M00_AXI axi_ip_master_v1_0_M00_AXI # ( .C_M_START_DATA_VALUE(C_M00_AXI_START_DATA_VALUE), .C_M_TARGET_SLAVE_BASE_ADDR(C_M00_AXI_TARGET_SLAVE_BASE_ADDR), .C_M_AXI_ADDR_WIDTH(C_M00_AXI_ADDR_WIDTH), .C_M_AXI_DATA_WIDTH(C_M00_AXI_DATA_WIDTH), .C_M_TRANSACTIONS_NUM(C_M00_AXI_TRANSACTIONS_NUM) ) axi_ip_master_v1_0_M00_AXI_inst ( .INIT_AXI_TXN(m00_axi_init_axi_txn), .ERROR(m00_axi_error), .TXN_DONE(m00_axi_txn_done), .M_AXI_ACLK(m00_axi_aclk), .M_AXI_ARESETN(m00_axi_aresetn), .M_AXI_AWADDR(m00_axi_awaddr), .M_AXI_AWPROT(m00_axi_awprot), .M_AXI_AWVALID(m00_axi_awvalid), .M_AXI_AWREADY(m00_axi_awready), .M_AXI_WDATA(m00_axi_wdata), .M_AXI_WSTRB(m00_axi_wstrb), .M_AXI_WVALID(m00_axi_wvalid), .M_AXI_WREADY(m00_axi_wready), .M_AXI_BRESP(m00_axi_bresp), .M_AXI_BVALID(m00_axi_bvalid), .M_AXI_BREADY(m00_axi_bready), .M_AXI_ARADDR(m00_axi_araddr), .M_AXI_ARPROT(m00_axi_arprot), .M_AXI_ARVALID(m00_axi_arvalid), .M_AXI_ARREADY(m00_axi_arready), .M_AXI_RDATA(m00_axi_rdata), .M_AXI_RRESP(m00_axi_rresp), .M_AXI_RVALID(m00_axi_rvalid), .M_AXI_RREADY(m00_axi_rready) ); // Add user logic here // User logic ends endmodule 附錄3:底層模塊MASTER 底層源代碼: `timescale 1 ns / 1 ps module axi_ip_master_v1_0_M00_AXI # ( // Users to add parameters here // User parameters ends // Do not modify the parameters beyond this line // The master will start generating data from the C_M_START_DATA_VALUE value parameter C_M_START_DATA_VALUE = 32'hAA000000, // The master requires a target slave base address. // The master will initiate read and write transactions on the slave with base address specified here as a parameter. parameter C_M_TARGET_SLAVE_BASE_ADDR = 32'h40000000, // Width of M_AXI address bus. // The master generates the read and write addresses of width specified as C_M_AXI_ADDR_WIDTH. parameter integer C_M_AXI_ADDR_WIDTH = 32, // Width of M_AXI data bus. // The master issues write data and accept read data where the width of the data bus is C_M_AXI_DATA_WIDTH parameter integer C_M_AXI_DATA_WIDTH = 32, // Transaction number is the number of write // and read transactions the master will perform as a part of this example memory test. parameter integer C_M_TRANSACTIONS_NUM = 4 ) ( // Users to add ports here // User ports ends // Do not modify the ports beyond this line // Initiate AXI transactions input wire INIT_AXI_TXN, // Asserts when ERROR is detected output reg ERROR, // Asserts when AXI transactions is complete output wire TXN_DONE, // AXI clock signal input wire M_AXI_ACLK, // AXI active low reset signal input wire M_AXI_ARESETN, // Master Interface Write Address Channel ports. Write address (issued by master) output wire [C_M_AXI_ADDR_WIDTH-1 : 0] M_AXI_AWADDR, // 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. output wire [2 : 0] M_AXI_AWPROT, // Write address valid. // This signal indicates that the master signaling valid write address and control information. output wire M_AXI_AWVALID, // Write address ready. // This signal indicates that the slave is ready to accept an address and associated control signals. input wire M_AXI_AWREADY, // Master Interface Write Data Channel ports. Write data (issued by master) output wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA, // 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. output wire [C_M_AXI_DATA_WIDTH/8-1 : 0] M_AXI_WSTRB, // Write valid. This signal indicates that valid write data and strobes are available. output wire M_AXI_WVALID, // Write ready. This signal indicates that the slave can accept the write data. input wire M_AXI_WREADY, // Master Interface Write Response Channel ports. // This signal indicates the status of the write transaction. input wire [1 : 0] M_AXI_BRESP, // Write response valid. // This signal indicates that the channel is signaling a valid write response input wire M_AXI_BVALID, // Response ready. This signal indicates that the master can accept a write response. output wire M_AXI_BREADY, // Master Interface Read Address Channel ports. Read address (issued by master) output wire [C_M_AXI_ADDR_WIDTH-1 : 0] M_AXI_ARADDR, // 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. output wire [2 : 0] M_AXI_ARPROT, // Read address valid. // This signal indicates that the channel is signaling valid read address and control information. output wire M_AXI_ARVALID, // Read address ready. // This signal indicates that the slave is ready to accept an address and associated control signals. input wire M_AXI_ARREADY, // Master Interface Read Data Channel ports. Read data (issued by slave) input wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA, // Read response. This signal indicates the status of the read transfer. input wire [1 : 0] M_AXI_RRESP, // Read valid. This signal indicates that the channel is signaling the required read data. input wire M_AXI_RVALID, // Read ready. This signal indicates that the master can accept the read data and response information. output wire M_AXI_RREADY ); // function called clogb2 that returns an integer which has the // value of the ceiling of the log base 2 function integer clogb2 (input integer bit_depth); begin for(clogb2=0; bit_depth>0; clogb2=clogb2+1) bit_depth = bit_depth >> 1; end endfunction // TRANS_NUM_BITS is the width of the index counter for // number of write or read transaction. localparam integer TRANS_NUM_BITS = clogb2(C_M_TRANSACTIONS_NUM-1); // Example State machine to initialize counter, initialize write transactions, // initialize read transactions and comparison of read data with the // written data words. parameter [1:0] IDLE = 2'b00, // This state initiates AXI4Lite transaction // after the state machine changes state to INIT_WRITE // when there is 0 to 1 transition on INIT_AXI_TXN INIT_WRITE = 2'b01, // This state initializes write transaction, // once writes are done, the state machine // changes state to INIT_READ INIT_READ = 2'b10, // This state initializes read transaction // once reads are done, the state machine // changes state to INIT_COMPARE INIT_COMPARE = 2'b11; // This state issues the status of comparison // of the written data with the read data reg [1:0] mst_exec_state; // AXI4LITE signals //write address valid reg axi_awvalid; //write data valid reg axi_wvalid; //read address valid reg axi_arvalid; //read data acceptance reg axi_rready; //write response acceptance reg axi_bready; //write address reg [C_M_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; //write data reg [C_M_AXI_DATA_WIDTH-1 : 0] axi_wdata; //read addresss reg [C_M_AXI_ADDR_WIDTH-1 : 0] axi_araddr; //Asserts when there is a write response error wire write_resp_error; //Asserts when there is a read response error wire read_resp_error; //A pulse to initiate a write transaction reg start_single_write; //A pulse to initiate a read transaction reg start_single_read; //Asserts when a single beat write transaction is issued and remains asserted till the completion of write trasaction. reg write_issued; //Asserts when a single beat read transaction is issued and remains asserted till the completion of read trasaction. reg read_issued; //flag that marks the completion of write trasactions. The number of write transaction is user selected by the parameter C_M_TRANSACTIONS_NUM. reg writes_done; //flag that marks the completion of read trasactions. The number of read transaction is user selected by the parameter C_M_TRANSACTIONS_NUM reg reads_done; //The error register is asserted when any of the write response error, read response error or the data mismatch flags are asserted. reg error_reg; //index counter to track the number of write transaction issued reg [TRANS_NUM_BITS : 0] write_index; //index counter to track the number of read transaction issued reg [TRANS_NUM_BITS : 0] read_index; //Expected read data used to compare with the read data. reg [C_M_AXI_DATA_WIDTH-1 : 0] expected_rdata; //Flag marks the completion of comparison of the read data with the expected read data reg compare_done; //This flag is asserted when there is a mismatch of the read data with the expected read data. reg read_mismatch; //Flag is asserted when the write index reaches the last write transction number reg last_write; //Flag is asserted when the read index reaches the last read transction number reg last_read; reg init_txn_ff; reg init_txn_ff2; reg init_txn_edge; wire init_txn_pulse; // I/O Connections assignments //Adding the offset address to the base addr of the slave assign M_AXI_AWADDR = C_M_TARGET_SLAVE_BASE_ADDR + axi_awaddr; //AXI 4 write data assign M_AXI_WDATA = axi_wdata; assign M_AXI_AWPROT = 3'b000; assign M_AXI_AWVALID = axi_awvalid; //Write Data(W) assign M_AXI_WVALID = axi_wvalid; //Set all byte strobes in this example assign M_AXI_WSTRB = 4'b1111; //Write Response (B) assign M_AXI_BREADY = axi_bready; //Read Address (AR) assign M_AXI_ARADDR = C_M_TARGET_SLAVE_BASE_ADDR + axi_araddr; assign M_AXI_ARVALID = axi_arvalid; assign M_AXI_ARPROT = 3'b001; //Read and Read Response (R) assign M_AXI_RREADY = axi_rready; //Example design I/O assign TXN_DONE = compare_done; assign init_txn_pulse = (!init_txn_ff2) && init_txn_ff; //Generate a pulse to initiate AXI transaction. always @(posedge M_AXI_ACLK) begin // Initiates AXI transaction delay if (M_AXI_ARESETN == 0 ) begin init_txn_ff <= 1'b0; init_txn_ff2 <= 1'b0; end else begin init_txn_ff <= INIT_AXI_TXN; init_txn_ff2 <= init_txn_ff; end end //-------------------- //Write Address Channel //-------------------- // The purpose of the write address channel is to request the address and // command information for the entire transaction. It is a single beat // of information. // Note for this example the axi_awvalid/axi_wvalid are asserted at the same // time, and then each is deasserted independent from each other. // This is a lower-performance, but simplier control scheme. // AXI VALID signals must be held active until accepted by the partner. // A data transfer is accepted by the slave when a master has // VALID data and the slave acknoledges it is also READY. While the master // is allowed to generated multiple, back-to-back requests by not // deasserting VALID, this design will add rest cycle for // simplicity. // Since only one outstanding transaction is issued by the user design, // there will not be a collision between a new request and an accepted // request on the same clock cycle. always @(posedge M_AXI_ACLK) begin //Only VALID signals must be deasserted during reset per AXI spec //Consider inverting then registering active-low reset for higher fmax if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_awvalid <= 1'b0; end //Signal a new address/data command is available by user logic else begin if (start_single_write) begin axi_awvalid <= 1'b1; end //Address accepted by interconnect/slave (issue of M_AXI_AWREADY by slave) else if (M_AXI_AWREADY && axi_awvalid) begin axi_awvalid <= 1'b0; end end end // start_single_write triggers a new write // transaction. write_index is a counter to // keep track with number of write transaction // issued/initiated always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin write_index <= 0; end // Signals a new write address/ write data is // available by user logic else if (start_single_write) begin write_index <= write_index + 1; end end //-------------------- //Write Data Channel //-------------------- //The write data channel is for transfering the actual data. //The data generation is speific to the example design, and //so only the WVALID/WREADY handshake is shown here always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_wvalid <= 1'b0; end //Signal a new address/data command is available by user logic else if (start_single_write) begin axi_wvalid <= 1'b1; end //Data accepted by interconnect/slave (issue of M_AXI_WREADY by slave) else if (M_AXI_WREADY && axi_wvalid) begin axi_wvalid <= 1'b0; end end //---------------------------- //Write Response (B) Channel //---------------------------- //The write response channel provides feedback that the write has committed //to memory. BREADY will occur after both the data and the write address //has arrived and been accepted by the slave, and can guarantee that no //other accesses launched afterwards will be able to be reordered before it. //The BRESP bit [1] is used indicate any errors from the interconnect or //slave for the entire write burst. This example will capture the error. //While not necessary per spec, it is advisable to reset READY signals in //case of differing reset latencies between master/slave. always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_bready <= 1'b0; end // accept/acknowledge bresp with axi_bready by the master // when M_AXI_BVALID is asserted by slave else if (M_AXI_BVALID && ~axi_bready) begin axi_bready <= 1'b1; end // deassert after one clock cycle else if (axi_bready) begin axi_bready <= 1'b0; end // retain the previous value else axi_bready <= axi_bready; end //Flag write errors assign write_resp_error = (axi_bready & M_AXI_BVALID & M_AXI_BRESP[1]); //---------------------------- //Read Address Channel //---------------------------- //start_single_read triggers a new read transaction. read_index is a counter to //keep track with number of read transaction issued/initiated always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin read_index <= 0; end // Signals a new read address is // available by user logic else if (start_single_read) begin read_index <= read_index + 1; end end // A new axi_arvalid is asserted when there is a valid read address // available by the master. start_single_read triggers a new read // transaction always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_arvalid <= 1'b0; end //Signal a new read address command is available by user logic else if (start_single_read) begin axi_arvalid <= 1'b1; end //RAddress accepted by interconnect/slave (issue of M_AXI_ARREADY by slave) else if (M_AXI_ARREADY && axi_arvalid) begin axi_arvalid <= 1'b0; end // retain the previous value end //-------------------------------- //Read Data (and Response) Channel //-------------------------------- //The Read Data channel returns the results of the read request //The master will accept the read data by asserting axi_rready //when there is a valid read data available. //While not necessary per spec, it is advisable to reset READY signals in //case of differing reset latencies between master/slave. always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_rready <= 1'b0; end // accept/acknowledge rdata/rresp with axi_rready by the master // when M_AXI_RVALID is asserted by slave else if (M_AXI_RVALID && ~axi_rready) begin axi_rready <= 1'b1; end // deassert after one clock cycle else if (axi_rready) begin axi_rready <= 1'b0; end // retain the previous value end //Flag write errors assign read_resp_error = (axi_rready & M_AXI_RVALID & M_AXI_RRESP[1]); //-------------------------------- //User Logic //-------------------------------- //Address/Data Stimulus //Address/data pairs for this example. The read and write values should //match. //Modify these as desired for different address patterns. //Write Addresses always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_awaddr <= 0; end // Signals a new write address/ write data is // available by user logic else if (M_AXI_AWREADY && axi_awvalid) begin axi_awaddr <= axi_awaddr + 32'h00000004; end end // Write data generation always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 ) begin axi_wdata <= C_M_START_DATA_VALUE; end // Signals a new write address/ write data is // available by user logic else if (M_AXI_WREADY && axi_wvalid) begin axi_wdata <= C_M_START_DATA_VALUE + write_index; end end //Read Addresses always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin axi_araddr <= 0; end // Signals a new write address/ write data is // available by user logic else if (M_AXI_ARREADY && axi_arvalid) begin axi_araddr <= axi_araddr + 32'h00000004; end end always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) begin expected_rdata <= C_M_START_DATA_VALUE; end // Signals a new write address/ write data is // available by user logic else if (M_AXI_RVALID && axi_rready) begin expected_rdata <= C_M_START_DATA_VALUE + read_index; end end //implement master command interface state machine always @ ( posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 1'b0) begin // reset condition // All the signals are assigned default values under reset condition mst_exec_state <= IDLE; start_single_write <= 1'b0; write_issued <= 1'b0; start_single_read <= 1'b0; read_issued <= 1'b0; compare_done <= 1'b0; ERROR <= 1'b0; end else begin // state transition case (mst_exec_state) IDLE: // This state is responsible to initiate // AXI transaction when init_txn_pulse is asserted if ( init_txn_pulse == 1'b1 ) begin mst_exec_state <= INIT_WRITE; ERROR <= 1'b0; compare_done <= 1'b0; end else begin mst_exec_state <= IDLE; end INIT_WRITE: // This state is responsible to issue start_single_write pulse to // initiate a write transaction. Write transactions will be // issued until last_write signal is asserted. // write controller if (writes_done) begin mst_exec_state <= INIT_READ;// end else begin mst_exec_state <= INIT_WRITE; if (~axi_awvalid && ~axi_wvalid && ~M_AXI_BVALID && ~last_write && ~start_single_write && ~write_issued) begin start_single_write <= 1'b1; write_issued <= 1'b1; end else if (axi_bready) begin write_issued <= 1'b0; end else begin start_single_write <= 1'b0; //Negate to generate a pulse end end INIT_READ: // This state is responsible to issue start_single_read pulse to // initiate a read transaction. Read transactions will be // issued until last_read signal is asserted. // read controller if (reads_done) begin mst_exec_state <= INIT_COMPARE; end else begin mst_exec_state <= INIT_READ; if (~axi_arvalid && ~M_AXI_RVALID && ~last_read && ~start_single_read && ~read_issued) begin start_single_read <= 1'b1; read_issued <= 1'b1; end else if (axi_rready) begin read_issued <= 1'b0; end else begin start_single_read <= 1'b0; //Negate to generate a pulse end end INIT_COMPARE: begin // This state is responsible to issue the state of comparison // of written data with the read data. If no error flags are set, // compare_done signal will be asseted to indicate success. ERROR <= error_reg; mst_exec_state <= IDLE; compare_done <= 1'b1; end default : begin mst_exec_state <= IDLE; end endcase end end //MASTER_EXECUTION_PROC //Terminal write count always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) last_write <= 1'b0; //The last write should be associated with a write address ready response else if ((write_index == C_M_TRANSACTIONS_NUM) && M_AXI_AWREADY) last_write <= 1'b1; else last_write <= last_write; end //Check for last write completion. //This logic is to qualify the last write count with the final write //response. This demonstrates how to confirm that a write has been //committed. always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) writes_done <= 1'b0; //The writes_done should be associated with a bready response else if (last_write && M_AXI_BVALID && axi_bready) writes_done <= 1'b1; else writes_done <= writes_done; end //------------------ //Read example //------------------ //Terminal Read Count always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) last_read <= 1'b0; //The last read should be associated with a read address ready response else if ((read_index == C_M_TRANSACTIONS_NUM) && (M_AXI_ARREADY) ) last_read <= 1'b1; else last_read <= last_read; end /* Check for last read completion. This logic is to qualify the last read count with the final read response/data. */ always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) reads_done <= 1'b0; //The reads_done should be associated with a read ready response else if (last_read && M_AXI_RVALID && axi_rready) reads_done <= 1'b1; else reads_done <= reads_done; end //----------------------------- //Example design error register //----------------------------- //Data Comparison always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) read_mismatch <= 1'b0; //The read data when available (on axi_rready) is compared with the expected data else if ((M_AXI_RVALID && axi_rready) && (M_AXI_RDATA != expected_rdata)) read_mismatch <= 1'b1; else read_mismatch <= read_mismatch; end // Register and hold any data mismatches, or read/write interface errors always @(posedge M_AXI_ACLK) begin if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1) error_reg <= 1'b0; //Capture any error types else if (read_mismatch || write_resp_error || read_resp_error) error_reg <= 1'b1; else error_reg <= error_reg; end // Add user logic here // User logic ends endmodule 附錄4:底層模塊Slave 頂層源代碼: `timescale 1 ns / 1 ps module axi_ip_slave_v1_0 # ( // Users to add parameters here // User parameters ends // Do not modify the parameters beyond this line // Parameters of Axi Slave Bus Interface S00_AXI parameter integer C_S00_AXI_DATA_WIDTH = 32, parameter integer C_S00_AXI_ADDR_WIDTH = 7 ) ( // Users to add ports here // User ports ends // Do not modify the ports beyond this line // Ports of Axi Slave Bus Interface S00_AXI input wire s00_axi_aclk, input wire s00_axi_aresetn, input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr, input wire [2 : 0] s00_axi_awprot, input wire s00_axi_awvalid, output wire s00_axi_awready, input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata, input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb, input wire s00_axi_wvalid, output wire s00_axi_wready, output wire [1 : 0] s00_axi_bresp, output wire s00_axi_bvalid, input wire s00_axi_bready, input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr, input wire [2 : 0] s00_axi_arprot, input wire s00_axi_arvalid, output wire s00_axi_arready, output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata, output wire [1 : 0] s00_axi_rresp, output wire s00_axi_rvalid, input wire s00_axi_rready ); // Instantiation of Axi Bus Interface S00_AXI axi_ip_slave_v1_0_S00_AXI # ( .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH), .C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH) ) axi_ip_slave_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) ); // Add user logic here // User logic ends endmodule 附錄5:底層模塊Slave 底層源代碼: ////////此處需要說明一下:做的slave核時,寄存器個數為32,生成核后,地址寬度為7,為什么呢?因為一個寄存器為32位,4個字節,所以一個寄存器占用4個地址。2^7=128個地址,一個寄存器占4個。 `timescale 1 ns / 1 ps module axi_ip_slave_v1_0_S00_AXI # ( // Users to add parameters here // User parameters ends // Do not modify the parameters beyond this line // Width of S_AXI data bus parameter integer C_S_AXI_DATA_WIDTH = 32, // Width of S_AXI address bus parameter integer C_S_AXI_ADDR_WIDTH = 7 ) ( // 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, // 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, // Write data (issued by master, acceped by Slave) input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, // 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, // 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, // 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; // Example-specific design signals // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH // ADDR_LSB is used for addressing 32/64 bit registers/memories // ADDR_LSB = 2 for 32 bits (n downto 2) // ADDR_LSB = 3 for 64 bits (n downto 3) localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; localparam integer OPT_MEM_ADDR_BITS = 4; //---------------------------------------------- //-- Signals for user logic register space example //------------------------------------------------ //-- Number of Slave Registers 32 reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg4; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg5; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg6; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg7; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg8; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg9; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg10; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg11; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg12; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg13; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg14; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg15; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg16; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg17; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg18; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg19; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg20; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg21; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg22; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg23; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg24; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg25; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg26; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg27; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg28; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg29; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg30; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg31; wire slv_reg_rden; wire slv_reg_wren; reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; integer byte_index; // I/O Connections assignments assign S_AXI_AWREADY = axi_awready; assign S_AXI_WREADY = axi_wready; assign S_AXI_BRESP = axi_bresp; assign S_AXI_BVALID = axi_bvalid; assign S_AXI_ARREADY = axi_arready; assign S_AXI_RDATA = axi_rdata; assign S_AXI_RRESP = axi_rresp; assign S_AXI_RVALID = axi_rvalid; // Implement axi_awready generation // axi_awready is asserted for one S_AXI_ACLK clock cycle when both // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is // de-asserted when reset is low. always @( posedge S_AXI_ACLK ) begin if ( S_AXI_ARESETN == 1'b0 ) begin axi_awready <= 1'b0; end else begin if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) 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; end else begin axi_awready <= 1'b0; end end end // Implement axi_awaddr latching // This process is used to latch the address when both // S_AXI_AWVALID and S_AXI_WVALID are valid. 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) begin // Write Address latching axi_awaddr <= S_AXI_AWADDR; end end end // Implement axi_wready generation // axi_wready is asserted for one S_AXI_ACLK clock cycle when both // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is // de-asserted when reset is low. 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) 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 // 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; slv_reg19 <= 0; slv_reg20 <= 0; slv_reg21 <= 0; slv_reg22 <= 0; slv_reg23 <= 0; slv_reg24 <= 0; slv_reg25 <= 0; slv_reg26 <= 0; slv_reg27 <= 0; slv_reg28 <= 0; slv_reg29 <= 0; slv_reg30 <= 0; slv_reg31 <= 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: 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 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: 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 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: 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 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 5'h13: 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 19 slv_reg19[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h14: 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 20 slv_reg20[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h15: 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 21 slv_reg21[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h16: 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 22 slv_reg22[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h17: 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 23 slv_reg23[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h18: 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 24 slv_reg24[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h19: 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 25 slv_reg25[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h1A: 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 26 slv_reg26[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h1B: 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 27 slv_reg27[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h1C: 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 28 slv_reg28[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h1D: 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 29 slv_reg29[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h1E: 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 30 slv_reg30[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end 5'h1F: 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 31 slv_reg31[(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; slv_reg18 <= slv_reg18; slv_reg19 <= slv_reg19; slv_reg20 <= slv_reg20; slv_reg21 <= slv_reg21; slv_reg22 <= slv_reg22; slv_reg23 <= slv_reg23; slv_reg24 <= slv_reg24; slv_reg25 <= slv_reg25; slv_reg26 <= slv_reg26; slv_reg27 <= slv_reg27; slv_reg28 <= slv_reg28; slv_reg29 <= slv_reg29; slv_reg30 <= slv_reg30; slv_reg31 <= slv_reg31; end endcase end end end // Implement write response logic generation // The write response and response valid signals are asserted by the slave // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. // This marks the acceptance of address and indicates the status of // write transaction. 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 // Implement axi_arready generation // axi_arready is asserted for one S_AXI_ACLK clock cycle when // S_AXI_ARVALID is asserted. axi_awready is // de-asserted when reset (active low) is asserted. // The read address is also latched when S_AXI_ARVALID is // asserted. axi_araddr is reset to zero on reset assertion. 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 // Implement axi_arvalid generation // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both // S_AXI_ARVALID and axi_arready are asserted. The slave registers // data are available on the axi_rdata bus at this instance. The // assertion of axi_rvalid marks the validity of read data on the // bus and axi_rresp indicates the status of read transaction.axi_rvalid // is deasserted on reset (active low). axi_rresp and axi_rdata are // cleared to zero on reset (active low). 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 // 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_reg18; 5'h13 : reg_data_out <= slv_reg19; 5'h14 : reg_data_out <= slv_reg20; 5'h15 : reg_data_out <= slv_reg21; 5'h16 : reg_data_out <= slv_reg22; 5'h17 : reg_data_out <= slv_reg23; 5'h18 : reg_data_out <= slv_reg24; 5'h19 : reg_data_out <= slv_reg25; 5'h1A : reg_data_out <= slv_reg26; 5'h1B : reg_data_out <= slv_reg27; 5'h1C : reg_data_out <= slv_reg28; 5'h1D : reg_data_out <= slv_reg29; 5'h1E : reg_data_out <= slv_reg30; 5'h1F : reg_data_out <= slv_reg31; default : reg_data_out <= 0; endcase end // Output register or memory read data 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 // Add user logic here // User logic ends endmodule

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM