使用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。