Sunday, March 22, 2020

使用Vivado Xilinx AXI verification IP進行AXI ip開發驗證

Xilinx AXI Verification IP tutorial

前情提要

一般來說開發Xilinx FPGA上的AXI master/slave ip都是透過C/C++ 轉成HLS或是直接撰寫Verilog。透過C/C++ 轉成的HLS可以自己寫簡單的C/C++ 程式作為testbench,驗證結果可以直接看C/C++ testbench的結果而定,Verilog細節、AXI操作等問題Vivado HLS會幫你完全處理(如果這些部份出現問題,你也沒輒了)。但是透過Verilog直接寫成的IP,通常需要CPU還有記憶體界面(eg. mig)之類的進行全系統測試,而獲取波形等資訊需要透過合成ILA在板子上實際測試。這流程十分繁瑣,合成ILA會浪費大量syntesis和implementation時間,而且可以debug的的訊號數量受限於晶片上的block ram以及LUT數量。然而很多人忽略了Xilinx其實提供了AXI verification IP,可以簡單快速撰寫testbench直接進行behavior simulation,這對於縮短演算法邏輯開發的時間有益。

本文主要以 CPU <-> AXI slave <=> AXI master <-> memory此模式為主。

完整文件請看AXI Verification IP v1.0

AXI Verification IP 簡介

Xilinx AXI Verification IP主要提供的功能為:

  •  產生AXI master command與資料(可自訂)
  • 產生AXI slave進行資料讀取與回覆(也可以模擬mig記憶體界面)
  • 檢查AXI protocol

而Xilinx AXI Verification IP (VIP)主要有三種模式:

  • 作為AXI master
    • 用來測試AXI slave ip
  • 作為AXI slave
    • 用來測試AXI master ip
  • 作為AXI pass-through 
    • (檢查兩個AXI IP之間的通訊)


AXI VIP提供SystemVerilog界面,透過SystemVerilog的OOP包裝一些AXI protocol操作與memory model。讓開發者可以專注在測試策略上。

flow

tools -> create and Package New IP -> choose Create AXI Peripheral
其他創造ip都按照基本流程。




這邊可以選取Verify Peripheral IP using AXI4 VIP,會建構完整的測試template。

完成後會產生如下block diagram

並且產生以下範例testbench,註解為程式區段用途。

`timescale 1ns / 1ps
`include "my_dma_v1_0_tb_include.svh"
// 以下為必要package
import axi_vip_pkg::*;
import my_dma_v1_0_bfm_1_slave_0_0_pkg::*;
import my_dma_v1_0_bfm_1_master_0_0_pkg::*;

module my_dma_v1_0_tb();

// AXI slave VIP 參數宣告(以下省略部份程式碼)
xil_axi_uint                            error_cnt = 0;
xil_axi_uint                            comparison_cnt = 0;
axi_transaction                         wr_transaction;   
.......
xil_axi_uint                           mst_agent_verbosity = 0;  
xil_axi_uint                           slv_agent_verbosity = 0;  
// AXI Slave VIP with memory model (如果你的ip為AXI master full會自動產生對應VIP)
my_dma_v1_0_bfm_1_slave_0_0_slv_mem_t          slv_agent_0;

integer result_slave;  
bit [31:0] S00_AXI_test_data[3:0]; 
 localparam LC_AXI_BURST_LENGTH = 8; 
 localparam LC_AXI_DATA_WIDTH = 32; 

// AXI master VIP 參數參數宣告
integer                                 i; 
integer                                 j;  
xil_axi_uint                            trans_cnt_before_switch = 48;  
xil_axi_uint                            passthrough_cmd_switch_cnt = 0;  
......
axi_ready_gen                           arready_gen2;  
xil_axi_payload_byte                    data_mem[xil_axi_ulong];  
//AXI master VIP
my_dma_v1_0_bfm_1_master_0_0_mst_t          mst_agent_0;
// Design under test
  `BD_WRAPPER DUT(
      .ARESETN(reset), 
      .ACLK(clock) 
    ); 
  
initial begin
    //基本AXI VIP agent初始設定
 slv_agent_0 = new("slave vip agent",DUT.`BD_INST_NAME.slave_0.inst.IF);
       slv_agent_0.set_agent_tag("Slave VIP");
    slv_agent_0.set_verbosity(slv_agent_verbosity);
    slv_agent_0.start_slave();
    mst_agent_0 = new("master vip agent",DUT.`BD_INST_NAME.master_0.inst.IF);//ms  
        mst_agent_0.set_agent_tag("Master VIP"); 
    mst_agent_0.set_verbosity(mst_agent_verbosity); 
    mst_agent_0.start_master(); 
     $timeformat (-12, 1, " ps", 1);
  end
  initial begin
    reset <= 1'b0;
    #100ns;
    reset <= 1'b1;
    repeat (5) @(negedge clock); 
  end
  always #5 clock <= ~clock;
  initial begin
      S_AXI_TEST ( );

    init_0 = 0;
    #200ns;
    init_0 =1'b1;
    #20ns;
    init_0 = 1'b0;
    
      #1ns;
      $finish;
  end
  initial begin
  #1;
    forever begin
      slv_agent_0.monitor.item_collected_port.get(slv_monitor_transaction);
      slave_moniter_transaction_queue.push_back(slv_monitor_transaction);
      slave_moniter_transaction_queue_size++;
    end
  end
//測試task範例
task automatic S_AXI_TEST;  
begin   
#1; 
   $display("Sequential write transfers example similar to  AXI BFM WRITE_BURST method starts"); 
   mtestID = 0; 
   mtestADDR = 64'h00000000; 
   mtestBurstLength = 0; 
   mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); 
   mtestBurstType = XIL_AXI_BURST_TYPE_INCR;  
   mtestLOCK = XIL_AXI_ALOCK_NOLOCK;  
   mtestCacheType = 0;  
   mtestProtectionType = 0;  
   mtestRegion = 0; 
   mtestQOS = 0; 
   result_slave = 1; 
  mtestWDataL[31:0] = 32'h00000001; 
  for(int i = 0; i < 4;i++) begin 
     S00_AXI_test_data[i] <= mtestWDataL[31:0];   
   //AXI master write transaction
   mst_agent_0.AXI4LITE_WRITE_BURST( 
   mtestADDR, 
   mtestProtectionType, 
   mtestWDataL, 
   mtestBresp 
   );   
   mtestWDataL[31:0] = mtestWDataL[31:0] + 1; 
   mtestADDR = mtestADDR + 64'h4; 
  end 
 $display("Sequential write transfers example similar to  AXI BFM WRITE_BURST method completes"); 
 $display("Sequential read transfers example similar to  AXI BFM READ_BURST method starts"); 
 mtestID = 0; 
 mtestADDR = 64'h00000000; 
 mtestBurstLength = 0; 
 mtestDataSize = xil_axi_size_t'(xil_clog2(32/8)); 
 mtestBurstType = XIL_AXI_BURST_TYPE_INCR;  
 mtestLOCK = XIL_AXI_ALOCK_NOLOCK;  
 mtestCacheType = 0;  
 mtestProtectionType = 0;  
 mtestRegion = 0; 
 mtestQOS = 0; 
 for(int i = 0; i < 4;i++) begin 
   //AXI master產生read transaction
   mst_agent_0.AXI4LITE_READ_BURST( 
        mtestADDR, 
        mtestProtectionType, 
        mtestRDataL, 
        mtestRresp 
      ); 

  end 
endtask  

endmodule


  • 對於slave agent有兩種model,分別是:
    • <component_name>_slv_t
      • 必須自行在user environment(testbecnch)中補上write response與read response(response包含回傳訊息的內容等)
    • <component_name>_slv_mem_t
      • write response與read response會由agent自行處理
      • 帶有memory model
      • 對於AXI full master的ip,Vivado會預設使用此agent


Testbench、AXI VIP與DUT的關係



以此架構產生的目標測試環境如上所示。其中由於AXI VIP slave是使用memory mode,所以Slave write/read driver不需要user自己在testbench中補上處理程序。

在使用memory model版本的AXI VIP,可以透過blackdoor_memory_write與blackdoor_memory_read存取模擬出的data memory,而AXI master則可透過一般AXI transaction進行讀寫。memory model大小取決於AXI data width的定址空間大小。

blackdoor memory read範例:
xil_axi_ulong mem_rd_addr = 32'h00000000;
bit [32-1:0] mem_rd_data;
mem_rd_data = slv_agent_0.mem_model.backdoor_memory_read(mem_rd_addr);
blackdoor memory write範例:
bit [32-1:0] wr_data = 0;
xil_axi_ulong wr_addr = 0;
bit [(32/8)-1:0] wr_strb = 4'hf; //byte select
slv_agent_0.mem_model.backdoor_memory_write(wr_addr,wr_data,wr_strb);

memory model使用上可以透過以下code將memory給入預設值方便debug:
slv_agent_0.mem_model.set_memory_fill_policy(XIL_AXI_MEMORY_FILL_FIXED);
slv_agent_0.mem_model.set_default_memory_value(32'hdeadbeef);

AXI master VIP進行AXI4 lite read/write的讀寫方式可透過:
xil_axi_ulong                           mtestADDR;
xil_axi_prot_t                          mtestProtectionType = 3'b000;
bit [63:0]                              mtestWDataL;
bit [63:0]                              mtestRDataL;
xil_axi_resp_t                          mtestBresp;
xil_axi_resp_t[255:0]                   mtestRresp;
mst_agent_0.AXI4LITE_WRITE_BURST(
        mtestADDR,
        mtestProtectionType,
        mtestWDataL,
        mtestBresp);
mst_agent_0.AXI4LITE_READ_BURST(
        mtestADDR,
        mtestProtectionType,
        mtestRDataL,
        mtestRresp);        

示範testbench code

在gist連結中:https://gist.github.com/Daichou/6b2e0a62bfc4eeb338e7f82fe40f0cc8

其他資源

Xilinx AXI VIP很多資訊只能透過從範例code看註解學習,開啟範例的方法為,先建立一個AXI VIP block design,在block diagram中點擊AXI VIP按右鍵然後會跳出選單,選取open IP example design。在該專案根目錄底下的imports就會含有所有範例testbench。

Reference




No comments:

Post a Comment

精選文章

使用Ardunio Atmega2560 連接 nRF24L01+

使用Ardunio Atmega2560 連接 nRF24L01+ 關於library 目前主流有 https://github.com/maniacbug/RF24 與 https://github.com/TMRh20/RF24 這兩個。 其中TMRh20大大做...