Using Xilinx AXI VIP: A Comprehensive Tutorial

  Although the AXI interface is frequently used, many may not be aware that Vivado also integrates AXI Verification IP, which can serve as an AXI master, pass-through, and slave. In this content, we will explore how to use the AXI VIP as a master.

  Create a new Vivado project and a new block design named: axi_demo

Using Xilinx AXI VIP: A Comprehensive Tutorial

Create a new AXI VIP, with the parameter settings as follows. Set the first parameter to Master, and keep the others as default. Of course, you can modify them according to your actual needs, such as ID width, data width, etc.

Using Xilinx AXI VIP: A Comprehensive Tutorial
image-20230726185112648

Next, add the AXI BRAM Controller and Block Memory Generator:

Using Xilinx AXI VIP: A Comprehensive Tutorial

The address allocation is as follows: 0xc000_0000

Using Xilinx AXI VIP: A Comprehensive Tutorial

Generate various files for the IP:

Using Xilinx AXI VIP: A Comprehensive Tutorial

Create a new simulation tb_top file. Note that the file type is System Verilog.

Using Xilinx AXI VIP: A Comprehensive Tutorial
image-20230726185756796

The simulation code is placed at the end of the article. The imported axi_demo_axi_vip_0_0_pkg in the code is the component name of the AXI VIP plus the suffix _pkg. The subsequent mst_agent is also the component name plus the suffix _mst_t.

import axi_demo_axi_vip_0_0_pkg::*;
axi_demo_axi_vip_0_0_mst_t              mst_agent;
Using Xilinx AXI VIP: A Comprehensive Tutorial
image-20230726190026270

Run the simulation:

Using Xilinx AXI VIP: A Comprehensive Tutorial
image-20230726190219346

Add the M-AXI of the AXI VIP to the waveform window:

Using Xilinx AXI VIP: A Comprehensive Tutorial
image-20230726190445127

You can see that we initially wrote 0x12345678 to address 0xc0001000 and then initiated a read operation to retrieve that data.

Using Xilinx AXI VIP: A Comprehensive Tutorial
image-20230726190702883

Some students may be accustomed to using VCS for simulation. In the next article, we will use VCS + Verdi to simulate Vivado’s AXI VIP.

`timescale 1ns / 1ps

import axi_vip_pkg::*;
import axi_demo_axi_vip_0_0_pkg::*;

module tb_top();

bit clk;
bit aresetn;

//used in API and parital randomization for transaction generation and data read back from driver
axi_transaction                         wr_transaction;                // Write transaction
axi_transaction                         rd_transaction;                // Read transaction

xil_axi_uint                            mtestWID;                      // Write ID  
xil_axi_ulong                           mtestWADDR;                    // Write ADDR  
xil_axi_len_t                           mtestWBurstLength;             // Write Burst Length   
xil_axi_size_t                          mtestWDataSize;                // Write SIZE  
xil_axi_burst_t                         mtestWBurstType;               // Write Burst Type  
xil_axi_uint                            mtestRID;                      // Read ID  
xil_axi_ulong                           mtestRADDR;                    // Read ADDR  
xil_axi_len_t                           mtestRBurstLength;             // Read Burst Length   
xil_axi_size_t                          mtestRDataSize;                // Read SIZE  
xil_axi_burst_t                         mtestRBurstType;               // Read Burst Type  
xil_axi_lock_t                          mtestLOCK;                     // LOCK value for WRITE/READ_BURST transaction
xil_axi_cache_t                         mtestCacheType = 3;            // Cache Type value for WRITE/READ_BURST transaction
xil_axi_prot_t                          mtestProtectionType = 3'b000;  // Protection Type value for WRITE/READ_BURST transaction
xil_axi_region_t                        mtestRegion = 4'b000;          // Region value for WRITE/READ_BURST transaction
xil_axi_qos_t                           mtestQOS = 4'b000;             // QOS value for WRITE/READ_BURST transaction
xil_axi_data_beat                       dbeat;                         // Data beat value for WRITE/READ_BURST transaction
xil_axi_user_beat                       usrbeat;                       // User beat value for WRITE/READ_BURST transaction
xil_axi_data_beat [255:0]               mtestWUSER;                    // Wuser value for WRITE/READ_BURST transaction
xil_axi_data_beat                       mtestAWUSER = 'h0;             // Awuser value for WRITE/READ_BURST transaction
xil_axi_data_beat                       mtestARUSER = 0;               // Aruser value for WRITE/READ_BURST transaction
xil_axi_data_beat [255:0]               mtestRUSER;                    // Ruser value for WRITE/READ_BURST transaction
xil_axi_uint                            mtestBUSER = 0;                // Buser value for WRITE/READ_BURST transaction
xil_axi_resp_t                          mtestBresp;                    // Bresp value for WRITE/READ_BURST transaction
xil_axi_resp_t[255:0]                   mtestRresp;                    // Rresp value for WRITE/READ_BURST transaction

bit [63:0]                             mtestWData;                     // Write Data
bit[8*4096-1:0]                        Wdatablock;                     // Write data block
xil_axi_data_beat                      Wdatabeat[];                    // Write data beats

bit [63:0]                             mtestRData;                     // Read Data
bit[8*4096-1:0]                        Rdatablock;                     // Read data block
xil_axi_data_beat                      Rdatabeat[];                    // Read data beats

  initial begin
    aresetn = 1'b0;
    clk = 1'b0;
    #100ns;
    aresetn = 1'b1;
  end 
   
always #10 clk <= ~clk;

axi_demo u_dut(
    .aclk_0       (clk     ),
    .aresetn_0    (aresetn )
);

axi_demo_axi_vip_0_0_mst_t              mst_agent;

initial begin
    mst_agent = new("master vip agent",u_dut.axi_vip_0.inst.IF);
mst_agent.start_master();               // mst_agent start to run
    mtestWID = $urandom_range(0,(1<<(0)-1)); 
mtestWADDR = 'hc000_1000;//$urandom_range(0,(1<<(32)-1));
mtestWBurstLength = 0;
mtestWDataSize = xil_axi_size_t'(xil_clog2((32)/8));
mtestWBurstType = XIL_AXI_BURST_TYPE_INCR;
mtestWData = 'h12345678;//$urandom();
$display("mtestWDataSize = %d", mtestWDataSize);
//single write transaction filled in user inputs through API 
single_write_transaction_api("single write with api",
                                 .id(mtestWID),
                                 .addr(mtestWADDR),
                                 .len(mtestWBurstLength), 
                                 .size(mtestWDataSize),
                                 .burst(mtestWBurstType),
                                 .wuser(mtestWUSER),
                                 .awuser(mtestAWUSER), 
                                 .data(mtestWData)
                                 );
                                  
mtestRID = $urandom_range(0,(1<<(0)-1));
mtestRADDR = mtestWADDR;
mtestRBurstLength = 0;
mtestRDataSize = xil_axi_size_t'(xil_clog2((32)/8)); 
mtestRBurstType = XIL_AXI_BURST_TYPE_INCR;
    
    $display("mtestRDataSize = %d", mtestRDataSize);
//single read transaction filled in user inputs through API 
single_read_transaction_api("single read with api",
                                 .id(mtestRID),
                                 .addr(mtestRADDR),
                                 .len(mtestRBurstLength), 
                                 .size(mtestRDataSize),
                                 .burst(mtestRBurstType)
                                 );
end

  task automatic single_write_transaction_api ( 
                                input string                     name ="single_write",
                                input xil_axi_uint               id =0, 
                                input xil_axi_ulong              addr =0,
                                input xil_axi_len_t              len =0, 
                                input xil_axi_size_t             size =xil_axi_size_t'(xil_clog2((32)/8)),
                                input xil_axi_burst_t            burst =XIL_AXI_BURST_TYPE_INCR,
                                input xil_axi_lock_t             lock = XIL_AXI_ALOCK_NOLOCK,
                                input xil_axi_cache_t            cache =3,
                                input xil_axi_prot_t             prot =0,
                                input xil_axi_region_t           region =0,
                                input xil_axi_qos_t              qos =0,
                                input xil_axi_data_beat [255:0]  wuser =0, 
                                input xil_axi_data_beat          awuser =0,
                                input bit [63:0]              data =0
                                                );
    axi_transaction                               wr_trans;
    $display("single_write_transaction_api size = %d", size);
    wr_trans = mst_agent.wr_driver.create_transaction(name);
    wr_trans.set_write_cmd(addr,burst,id,len,size);
    wr_trans.set_prot(prot);
    wr_trans.set_lock(lock);
    wr_trans.set_cache(cache);
    wr_trans.set_region(region);
    wr_trans.set_qos(qos);
    wr_trans.set_data_block(data);
    mst_agent.wr_driver.send(wr_trans);   
  endtask  : single_write_transaction_api 
 
  task automatic single_read_transaction_api ( 
                                    input string                     name ="single_read",
                                    input xil_axi_uint               id =0, 
                                    input xil_axi_ulong              addr =0,
                                    input xil_axi_len_t              len =0, 
                                    input xil_axi_size_t             size =xil_axi_size_t'(xil_clog2((32)/8)),
                                    input xil_axi_burst_t            burst =XIL_AXI_BURST_TYPE_INCR,
                                    input xil_axi_lock_t             lock =XIL_AXI_ALOCK_NOLOCK ,
                                    input xil_axi_cache_t            cache =3,
                                    input xil_axi_prot_t             prot =0,
                                    input xil_axi_region_t           region =0,
                                    input xil_axi_qos_t              qos =0,
                                    input xil_axi_data_beat          aruser =0
                                                );
    axi_transaction                               rd_trans;
    $display("single_read_transaction_api size = %d", size);
    rd_trans = mst_agent.rd_driver.create_transaction(name);
    rd_trans.set_read_cmd(addr,burst,id,len,size);
    rd_trans.set_prot(prot);
    rd_trans.set_lock(lock);
    rd_trans.set_cache(cache);
    rd_trans.set_region(region);
    rd_trans.set_qos(qos);
    mst_agent.rd_driver.send(rd_trans);   
  endtask  : single_read_transaction_api

endmodule

Leave a Comment