はじめに
今回はVivadoのVIP、AXI VIP(AXI Verification IP)を使って、AXI4-LiteのMasterとして動作させます。MicroBlazeの代わりとして、AXI GPIO IPのレジスタアクセスをすることを目標とします。
Vivadoバージョン: 2023.2
準備
以下では、Block Designを使って回路を作ります。また、IPのコンフィグを示します。
Block Design
簡単にするために、下記のようなブロック図を考えます。このBlock Designを「Create HDL Wrapper」して、DUTにします。
AXI VIPのコンフィグ
AXI VIPのProduct Guideはこちらです。以下の画像のようなコンフィグで動かします。
AXI GPIOのコンフィグ
GPIOのProduct Guideはこちらです。以下の画像のようなコンフィグで動かします。出力だけです。
AXI GPIO v2.0 Product Guide (PG144) • Viewer • AMD Technical Information Portal
レジスタ空間はこちらです。Address 0x0000にアクセスすれば、Output Dataを変えられるようです。
Address Editor
メモリマップは以下のようにしています。GPIOしかありませんが。
AXI VIPを動かす
AXI VIP Masterを使って、AXI GPIOのレジスタを叩き、出力を変化しているところを見ます。
テストベンチ
以下のようなテストベンチを記載しています。
- tb_top_gpio: テストベンチ TOPです
- test: Testシーケンスを記述しています
- DUT: Block Designから生成したWrapperファイルです
SystemVerilogのコードは以下です。テストベンチの書き方等はSystemVerilog TestBench Example – ADDER – Verification Guideを参考にしました。(全然わかりやすくかけてないですが。)
tb_top_gpio.sv
`timescale 1ns / 1ps
// Interface
`include "interface.sv"
// Testcase
`include "directed_test.sv"
module tb_top_gpio ();
bit aclk;
// creatinng instance of interface, inorder to connect DUT and testcase
intf i_intf (aclk);
// Testcase instance, interface handle is passed to test as an argument
test t1 (i_intf);
// instantiate bd
AXI_VIP_TEST_wrapper DUT (
.aclk_0(i_intf.aclk),
.aresetn_0(i_intf.aresetn),
.GPIO_0_tri_o(i_intf.GPIO_0_tri_o)
);
// Clock
localparam CLK_CYCLE = 5; // ns, 100MHz
always #(CLK_CYCLE) aclk <= ~aclk;
endmodule
interface.sv
interface intf (
input logic aclk
);
//declaring the signals
logic aresetn;
logic [31:0] GPIO_0_tri_o;
endinterface
test.sv
import axi_vip_pkg::*;
import AXI_VIP_TEST_axi_vip_0_0_pkg::*;
`ifndef GPIO_BASE_ADDR
`define GPIO_BASE_ADDR 32'h4000_0000
`endif
program test (
intf i_intf
);
bit [31:0] axi_addr;
logic [31:0] axi_rd_data = '0;
bit [31:0] axi_wr_data;
logic resp;
AXI_VIP_TEST_axi_vip_0_0_mst_t axi_mst_agent;
task wait_clk(int n);
repeat (n) @(posedge i_intf.aclk);
endtask
initial begin
i_intf.aresetn = 1'b0;
wait_clk(100);
i_intf.aresetn = 1'b1;
wait_clk(100);
// *******************************************************************
// * AXI VIP
// *******************************************************************
// Init AXI agent
axi_mst_agent = new("my vip agent", DUT.AXI_VIP_TEST_i.axi_vip_0.inst.IF);
axi_mst_agent.start_master();
/////////////////////////////////////////////////////////////////////
// Read Transactions
/////////////////////////////////////////////////////////////////////
axi_addr = `GPIO_BASE_ADDR + 0;
axi_mst_agent.AXI4LITE_READ_BURST(axi_addr, 0, axi_rd_data, resp);
$display($time, "ns, [READ] ADDR=%h, DATA=%h", axi_addr, axi_rd_data);
wait_clk(4);
/////////////////////////////////////////////////////////////////////
// Write Transactions
/////////////////////////////////////////////////////////////////////
axi_addr = `GPIO_BASE_ADDR + 0;
axi_wr_data = 32'h1;
axi_mst_agent.AXI4LITE_WRITE_BURST(axi_addr, 0, axi_wr_data, resp);
$display($time, "ns, [WRITE] ADDR=%h, DATA=%h", axi_addr, axi_wr_data);
wait_clk(4);
/////////////////////////////////////////////////////////////////////
// Read Transactions
/////////////////////////////////////////////////////////////////////
axi_addr = `GPIO_BASE_ADDR + 0;
axi_mst_agent.AXI4LITE_READ_BURST(axi_addr, 0, axi_rd_data, resp);
$display($time, "ns, [READ] ADDR=%h, DATA=%h", axi_addr, axi_rd_data);
wait_clk(100);
$finish();
end
endprogram
AXI VIP周りの説明を書いておくと、
まずはPackageのimportが必要です。
import axi_vip_pkg::*;
import AXI_VIP_TEST_axi_vip_0_0_pkg::*;
そしたら、MasterのAXI VIPを宣言(?)をします。
AXI_VIP_TEST_axi_vip_0_0_mst_t axi_mst_agent;
以下で初期設定を行って、
axi_mst_agent = new("my vip agent", DUT.AXI_VIP_TEST_i.axi_vip_0.inst.IF);
axi_mst_agent.start_master();
そしたら、行いたいタイミングで、AXI4 LiteのRead/Writeトランザクションを行います。AXI4LITE_READ_BURST
やAXI4LITE_WRITE_BURST
で行うようです。たまたま以下で見かけました。結構最近の記事のようです。(日本語に直されたのが最近かも)[日本語ブログ] AXI の基礎 3 – AXI VIP を使用したマスター AXI4-Lite のシミュレーション (xilinx.com)
/////////////////////////////////////////////////////////////////////
// Read Transactions
/////////////////////////////////////////////////////////////////////
axi_mst_agent.AXI4LITE_READ_BURST(axi_addr, 0, axi_rd_data, resp);
/////////////////////////////////////////////////////////////////////
// Write Transactions
/////////////////////////////////////////////////////////////////////
axi_mst_agent.AXI4LITE_WRITE_BURST(axi_addr, 0, axi_wr_data, resp);
シミュレーション波形
波形も確認しておきましょう。
矢印の位置で、AXI4 Lite経由でレジスタのRead/Writeおよび、GPIO出力の更新ができていることが確認できました。
おわりに
AXI VIPを使ってみました。初めて使ったのと、テストベンチの書き方が慣れないので、今後も勉強進めていきたいと思います。
参考資料
公式資料
AXI Verification IP (VIP) (xilinx.com)
AR# 70620: 検証 IP (VIP) の API 資料 (xilinx.com)
AXI の基礎 2 – AXI Verification IP (AXI VIP) を使用した AXI インターフェイスのシミュレーション (xilinx.com)
[日本語ブログ] AXI の基礎 3 – AXI VIP を使用したマスター AXI4-Lite のシミュレーション (xilinx.com)
その他記事
XilinxのAXI Verification IPを試す。 #FPGA – Qiita
FPGAの部屋 Vivado 2017.1 の新機能2(AXI Verification IPの概要) (fc2.com)
Xilinx AXI Verification IP (VIP) の Study | 株式会社ライト・ライト (rightxlight.co.jp)
AXI Verification IPを使って任意のアドレスにデータを書き込む #FPGA – Qiita
AXI VIPを使ってレジスタにライトする – ぱたへね (hatenablog.com)
SystemVerilog TestBench Example – ADDER – Verification Guide
コメント