2020年7月23日木曜日

VIvado SimulatorでUVMを試してみた話

Vivado 2019.2でUVMが使えるようになっていたので試してみた話。 各種サンプルに記載があるuvm_config_dbにvirtual interfaceを指定するようなテストベンチを実行しようとするとxelabがsegmentation faultを起こす模様。

環境

Ubuntu 18.04 Vivado 2019.2 UVM 1.2

テストベンチ

色々確認した後があって汚いけど以下の通り

`timescale 1ns/1ps
module tb_uvm_test;
    `include "uvm_macros.svh"
    import uvm_pkg::*;

    class sample_seq_item extends uvm_sequence_item;
      rand logic [7:0] addr, data;
      `uvm_object_utils_begin(sample_seq_item)
        `uvm_field_int (addr, UVM_DEFAULT)
        `uvm_field_int (data, UVM_DEFAULT)
      `uvm_object_utils_end
      function new (string name = "sample_seq_item_inst");
        super.new(name);
      endfunction : new
    endclass

    class sample_sequencer extends uvm_sequencer #(sample_seq_item);
        `uvm_component_utils(sample_sequencer)
        `uvm_new_func
        task run_phase(uvm_phase phase);
            uvm_report_info("SEQR","Hi I am Sequencer");
        endtask
    endclass

    interface sample_if(input logic clk, rstz);
        logic[7:0] addr,data;
        logic valid;
    endinterface

    class sample_driver extends uvm_driver #(sample_seq_item);
        `uvm_component_utils(sample_driver)
//        virtual sample_if vif;
        function new (string name ="sample_driver", uvm_component parent);
            super.new(name, parent);
        endfunction
//        function void build_phase(uvm_phase phase);
//            super.build_phase(phase);
//            if(!uvm_config_db#(virtual sample_if)::get(this, "", "vif", vif))
//                `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
//        endfunction: build_phase
        task run_phase(uvm_phase phase);
            uvm_report_info("DRIVER", "Hi! I am sample_driver");
//            sample_seq_item trans_item;
//            vif.valid = 1'b0;
//            @(posedge cif.rstz);// wait negate reset
//            forever begin
//                seq_item_port.get_next_item(trans_item);
//                // get several value from trans_item and drive
//                // signals, receive signals via virtual interface
//                @(posedge vif.clk);
//                vif.valid <= 1'b1;
//                vif.addr  <= trans_item.addr;
//                vif.data  <= trans_item.data;
//                @(posedge vif.clk) vif.valid <= 1'b0;
//                seq_item_port.item_done();
//            end
        endtask
    endclass

    class sample_monitor extends uvm_monitor;
        `uvm_component_utils(sample_monitor)
//        virtual sample_if vif;
        function new(string name="sample_monitor", uvm_component parent);
            super.new(name, parent);
        endfunction
//        function void build_phase(uvm_phase phase);
//            super.build_phase(phase);
//            if(!uvm_config_db#(virtual sample_if)::get(this, "", "vif", vif))
//                `uvm_fatal("NOVIF",{"virtual interface must be set for:", get_full_name(), ".vif"});
//        endfunction: build_phase
        task run_phase(uvm_phase phase);
            uvm_report_info("MONITOR","Hi! I am sample_monitor");
//            fork
//                //check_clock;
//                check_trans;
//            join
        endtask
//        task check_trans;
//            forever begin
//                @(posedge vif.valid) uvm_report_info("MON", $sformatf("addr=%02Xh, data=%02Xh", vif.addr, vif.data));
//            end
//        endtask;
//        task check_clock;
//            forever begin
//                wait(vif.clk===1'b0);
//                uvm_report_info("MON", "fall clock");
//                wait(vif.clk===1'b1);
//                uvm_report_info("MON", "rise clock");
//            end
//        endtask
    endclass
    class sample_agent extends uvm_agent;
        `uvm_component_utils(sample_agent)
        `uvm_new_func
        sample_driver       driver;
        sample_sequencer    sequencer;
        sample_monitor      monitor;
        function void build_phase(uvm_phase phase);
            driver = sample_driver::type_id::create("driver",this);
            sequencer = sample_sequencer::type_id::create("sequencer",this);
            monitor = sample_monitor::type_id::create("monitor",this);
        endfunction
        function void connect_phase(uvm_phase phase);
            if(get_is_active() == UVM_ACTIVE) begin
                driver.seq_item_port.connect(sequencer.seq_item_export);
            end
        endfunction
        task run_phase(uvm_phase phase);
            uvm_report_info("AGENT", "Hi! I am Agent");
        endtask
    endclass
    class sample_env extends uvm_env;
        `uvm_component_utils(sample_env)
        `uvm_new_func
        sample_agent agent;
        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            agent = sample_agent::type_id::create("agent",this);
        endfunction
    endclass
//    virtual class sample_base_sequence extends uvm_sequence #(sample_seq_item);
//        function new(string name="sample_base_seq");
//            super.new(name);
//        endfunction
//        virtual task pre_body();
//            if(starting_phase != null) begin
//                `uvm_info(get_type_name(),
//                          $sformatf("%s pre_body() raising %s objection",
//                          starting_phase.get_name()), UVM_MEDIUM);
//                starting_phase.raise_objection(this);
//            end
//        endtask
//        // Drop the objection in the post_body so the objection is removed when
//        // the root sequence is complete.
//        virtual task post_body();
//            if(starting_phase != null) begin
//                `uvm_info(get_type_name(),
//                          $sformatf("%s post_bodu() dropping %s objection",
//                                    get_sequence_path(),
//                                    starting_phase.get_name()), UVM_MEDIUM);
//            starting_phase.drop_objection(this);
//            end
//        endtask
//    endclass
//    class issue_one_trans_seq extends sample_base_sequence;
//        function new(string name="issue_one_trans_seq", uvm_component parent);
//            super.new(name,parent);
//        endfunction
//        `uvm_object_utils(issue_one_trans_seq)
//        virtual task body();
//            sample_seq_item trans_item;
//            $display("I am issue_one_trans_seq");
//            `uvm_create(trans_item)
//            trans_item.addr = 8'h00;
//            trans_item.data = 8'h10;
//            `uvm_send(trans_item)
//            #1000 ns;
//        endtask
//    endclass
//    class test extends uvm_test;
//        `uvm_component_utils(test)
//        `uvm_new_func
//        sample_env env;
//        virtual function void build_phase(uvm_phase phase);
//            uvm_config_db#(uvm_object_wrapper)::set(this,
//                "env.agent.sequener.run_phase", "default_sequence",
//                issue_one_trans_seq::type_id::get());
//            env=sample_env::type_id::create("env",this);
//            super.build_phase(phase);
//        endfunction
//    endclass
    class sample_test extends uvm_test;
        `uvm_component_utils(sample_test)
        sample_env env;
        function new (string name="sample_test", uvm_component parent=null);
            super.new(name,parent);
        endfunction
        function void build_phase(uvm_phase phase);
            super.build_phase(phase);
            env = sample_env::type_id::create("env",this);
        endfunction
        task run_phase(uvm_phase phase);
            uvm_report_info("TEST", "Hello World from sample_test");
        endtask
    endclass

    logic clk, rstz;
    sample_if sif(clk, rstz);// interface
    initial begin
        fork
            begin
                clk = 1'b1;
                #100;
                forever #50 clk = ~clk;
            end
            begin
                rstz = 1'b0;
                #100;
                rstz = 1'b1;
            end
        join
    end
    class my_class;
        function new();
        endfunction
    endclass
    initial begin
        my_class mc = new;
        `uvm_info("info", "Hello World from initial block", UVM_LOW)
        uvm_config_db #(virtual sample_if)::set(uvm_root::get(), "*.env.*", "vif", sif);//xelab segmentation fault.
        run_test("sample_test");
    end
endmodule

実行メッセージ

[1/3] Generating sim/work/xsim/compile_tb_uvm_test.timestamp
tb_uvm_test.sh - Script generated by export_simulation (Vivado v2019.2 (64-bit)-id)

INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/hls/ICS_IF/test/src/tb_uvm_test.sv" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module tb_uvm_test
WARNING: [VRFC 10-3824] variable 'mc' must explicitly be declared as automatic or static [/home/akira/work/hls/ICS_IF/test/src/tb_uvm_test.sv:208]
INFO: [VRFC 10-2263] Analyzing Verilog file "/home/akira/work/hls/ICS_IF/build/sim/work/tb_uvm_test/xsim/glbl.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module glbl
[2/3] Generating sim/work/xsim/elaborate_tb_uvm_test.timestamp
FAILED: sim/work/xsim/elaborate_tb_uvm_test.timestamp
cd /home/akira/work/hls/ICS_IF/build/sim/work/xsim && source ./elaborate_tb_uvm_test.sh -noclean_files && /opt/Xilinx/Vitis/2019.2/tps/lnx64/cmake-3.3.2/bin/cmake -E touch elaborate_tb_uvm_test.timestamp
tb_uvm_test.sh - Script generated by export_simulation (Vivado v2019.2 (64-bit)-id)

Vivado Simulator 2019.2
Copyright 1986-1999, 2001-2019 Xilinx, Inc. All Rights Reserved.
Running: /opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/xelab --relax -L uvm --debug typical --mt auto -L xil_defaultlib -L xilinx_vip -L unisims_ver -L unimacro_ver -L secureip -L xpm --snapshot tb_uvm_test xil_defaultlib.tb_uvm_test xil_defaultlib.glbl -log tb_uvm_test_elaborate.log
Multi-threading is on. Using 2 slave threads.
Starting static elaboration
Pass Through NonSizing Optimizer
/opt/Xilinx/Vivado/2019.2/bin/loader: line 280:  1102 Segmentation fault      (core dumped) "$RDI_PROG" "$@"
ninja: build stopped: subcommand failed.

回避策

このままだとconnect_phaseでインターフェースの接続ができないので、検討中。 独自クラスのインスタンスは渡せてるっぽいのでこれを使えばインターフェースの受け渡しも可能か? 素直にバージョンアップ待つのが賢明な気もするけど。

interfaceをmodule内で定義しているのがどうもだめだった模様。 モジュールの外側で定義したら問題なく動いた。 この例が動いたので差分チェックして見つけた。

参考ページ

https://sites.google.com/site/playsystemverilog/uvm/uvm-introduction-for-10days https://www.accellera.org/images/downloads/standards/uvm/uvm_users_guide_1.2.pdf https://forums.xilinx.com/t5/Simulation-and-Verification/XELAB-2019-2-elaboration-fails-for-simple-UVM-example-design/m-p/1113039

0 件のコメント:

コメントを投稿