QiitaのXilinxのAXI Verification IPを試す。とVivadoのexampleを交互にみながら、やり方としては間違ってるんだろうけど、なんとかレジスタライトができるようになりました。
サンプル記述
僕の環境だと
c:/home/myproj/sting/vivado/zybo/sting_ip/sting_ip.srcs/sources_1/bd/design_1/ip/design_1_axi_vip_0_1/sim/design_1_axi_vip_0_1.v
に、使いたいAXI VIPのソースがあって、そのソースの中にサンプル記述がありました。これを使います。
/////////////////////////////////////////////////////////////////////////// // How to start the verification component /////////////////////////////////////////////////////////////////////////// // design_1_axi_vip_0_1_mst_t design_1_axi_vip_0_1_mst; // initial begin : START_design_1_axi_vip_0_1_MASTER // design_1_axi_vip_0_1_mst = new("design_1_axi_vip_0_1_mst", `design_1_axi_vip_0_1_PATH_TO_INTERFACE); // design_1_axi_vip_0_1_mst.start_master(); // end
`design_1_axi_vip_0_1_PATH_TO_INTERFACEに何を入れて良いのか分からず、Qiitaを参考に自分の環境に合わせました。
initial begin design_1_axi_vip_0_1_mst = new("design_1_axi_vip_0_1_mst", reg_rw_tb.design_1.axi_vip_0.inst.IF); design_1_axi_vip_0_1_mst.start_master(); end
PATHの一番上がテストベンチ、次にデザイン名なので人によって変わってきます。これも、いったん何もしないSIMを実行して階層を見るのが結局早かったです。elaborateが終わっていると、どこかで右クリックして階層をExcelにexportできましたが、やり方を忘れました。
ライト動作
Qiitaの記事を参考に、ランダマイズされたライトトランザクションなら動いたのですが、ランダマイズしない状態でアドレスとデータを設定してもAXIのサイクルが発生しませんでした。多分、アドレスとデータ以外も設定しないといけないんだと思います。しょうが無いので、ランダマイズしたあと、set_addr()とset_data_block()を使うことで、狙ったアドレスにライトできました。
task reg_wr(input integer adr, input integer data); axi_transaction wr_transaction; wr_transaction = design_1_axi_vip_0_1_mst.wr_driver.create_transaction( "register write"); WR_TRANSACTION_FAIL: assert(wr_transaction.randomize()); wr_transaction.set_addr(adr); wr_transaction.set_data_block(data); design_1_axi_vip_0_1_mst.wr_driver.send(wr_transaction); endtask
AXI VIPとは?
Vengineerさんの作ったスライドを見ているともっと簡単にやってるんだけど・・
https://www.slideshare.net/ssuser479fa3/zynq-vip-78968931
AXI VIPには、スライドにあるようなAPIは無いので、AXI VIPとZynq VIPは別物なのかなと思ってます。Viva道厳しい。
シミュレーションの全ソース
`timescale 1ns/1ps import axi_vip_v1_0_2_pkg::*; import design_1_axi_vip_0_1_pkg::*; module reg_rw_tb(); localparam int LP_CLK_PERI = 10; localparam int LP_RST_PERI = 50; // DUT instance logic aresetn, aclk; logic axi_init; wire irq; design_1 design_1( .aclk(aclk), .aresetn(aresetn), .init_axi_txn(axi_init), .irq(irq)); task rst_gen(); aresetn = '0; axi_init = '1; #(LP_RST_PERI); axi_init = '0; aresetn = '1; endtask task clk_gen(); aclk = '0; forever #(LP_CLK_PERI/2) aclk = ~aclk; endtask task clk_dly(int n); repeat(n) @(posedge aclk); endtask // VIP decreation design_1_axi_vip_0_1_mst_t design_1_axi_vip_0_1_mst; initial begin design_1_axi_vip_0_1_mst = new("design_1_axi_vip_0_1_mst", reg_rw_tb.design_1.axi_vip_0.inst.IF); design_1_axi_vip_0_1_mst.start_master(); end task reg_wr(input integer adr, input integer data); axi_transaction wr_transaction; wr_transaction = design_1_axi_vip_0_1_mst.wr_driver.create_transaction( "register write"); WR_TRANSACTION_FAIL: assert(wr_transaction.randomize()); wr_transaction.set_addr(adr); wr_transaction.set_data_block(data); design_1_axi_vip_0_1_mst.wr_driver.send(wr_transaction); endtask // Testscenario initial begin fork clk_gen(); rst_gen(); join_none clk_dly(100); reg_wr(32'h04, 32'h12345678); clk_dly(100); clk_dly(1000); $finish(2); end endmodule