ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

AXI VIPを使ってレジスタにライトする

QiitaのXilinxAXI 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 

アドレス4に、0x12345678を書き込んだ波形。

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