2020年7月24日金曜日

Vivado SimulatorでUVMを試してみた話その2

Vivado 2019.2でUVMが使えるようになっていたので試してみた話その2。 ここの サンプルをUVM1.2向けにしながら動作を確認しました。

環境

Ubuntu 18.04 Vivado 2019.2 UVM 1.2

テストベンチ

ひとまず波形の出力とログの確認ができたので一度終了。 後で続きやりたくなるかもしれないのでアップ。

`timescale 1ns/1ps
interface sample_if(input logic clk, rstz);
    logic[7:0] addr,data;
    logic valid;
endinterface


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

    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);
            sample_seq_item trans_item;
            vif.valid = 1'b0;
            uvm_report_info("DRIVER", "Hi! I am sample_driver");
            @(posedge vif.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;
        `uvm_object_utils(issue_one_trans_seq)
        function new(string name="issue_one_trans_seq");
            super.new(name);
        endfunction
      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;
      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);
           env=sample_env::type_id::create("env",this);
            super.build_phase(phase);
        endfunction

        task run_phase(uvm_phase phase);
            issue_one_trans_seq seq = issue_one_trans_seq::type_id::create("seq");
            uvm_report_info("TEST", "Hello World from class test");
            phase.raise_objection(this);
            seq.start(env.agent.sequencer);
            phase.drop_objection(this);
        endtask
    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
    initial begin
        `uvm_info("info", "Hello World from initial block", UVM_LOW)
        uvm_config_db#(virtual sample_if)::set(uvm_root::get(), "*", "vif", sif);
        run_test("test");
    end
endmodule

実行結果

$ ninja open_tb_uvm_test
[1/4] 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
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/4] Generating sim/work/xsim/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
WARNING: [VRFC 10-3522] missing or empty argument against format specification for 'sformatf' [/home/akira/work/hls/ICS_IF/test/src/tb_uvm_test.sv:132]
Completed static elaboration
Starting simulation data flow analysis
WARNING: [XSIM 43-4100] "/home/akira/work/hls/ICS_IF/test/src/tb_uvm_test.sv" Line 8. Module tb_uvm_test has a timescale but at least one module in design doesn't have timescale.
WARNING: [XSIM 43-4100] "/home/akira/work/hls/ICS_IF/test/src/tb_uvm_test.sv" Line 2. Module sample_if has a timescale but at least one module in design doesn't have timescale.
WARNING: [XSIM 43-4100] "/home/akira/work/hls/ICS_IF/build/sim/work/tb_uvm_test/xsim/glbl.v" Line 6. Module glbl has a timescale but at least one module in design doesn't have timescale.
Completed simulation data flow analysis
Time Resolution for simulation is 1ps
Compiling package uvm.uvm_pkg
Compiling package std.std
Compiling module xil_defaultlib.sample_if
Compiling module xil_defaultlib.tb_uvm_test
Compiling module xil_defaultlib.glbl
Built simulation snapshot tb_uvm_test
[3/4] Generating sim/work/xsim/tb_uvm_test.wdb
tb_uvm_test.sh - Script generated by export_simulation (Vivado v2019.2 (64-bit)-id)


****** xsim v2019.2 (64-bit)
  **** SW Build 2708876 on Wed Nov  6 21:39:14 MST 2019
  **** IP Build 2700528 on Thu Nov  7 00:09:20 MST 2019
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.

source xsim.dir/tb_uvm_test/xsim_script.tcl
# xsim {tb_uvm_test} -autoloadwcfg -tclbatch {cmd.tcl} -key {Behavioral:sim_1:Functional:tb_uvm_test} -protoinst {protoinst_files/ics_if.protoinst} -protoinst {protoinst_files/ics_if.protoinst} -protoinst {protoinst_files/sim_ics_if.protoinst}
Vivado Simulator 2019.2
INFO: [Wavedata 42-565] Reading protoinst file protoinst_files/ics_if.protoinst
WARNING: [Wavedata 42-558] Couldn't load one or more protocol instances from protoinst file protoinst_files/ics_if.protoinst for the following reason(s):
There are no instances of module "ics_if" in the design.

INFO: [Wavedata 42-565] Reading protoinst file protoinst_files/ics_if.protoinst
WARNING: [Wavedata 42-558] Couldn't load one or more protocol instances from protoinst file protoinst_files/ics_if.protoinst for the following reason(s):
There are no instances of module "ics_if" in the design.

INFO: [Wavedata 42-565] Reading protoinst file protoinst_files/sim_ics_if.protoinst
WARNING: [Wavedata 42-558] Couldn't load one or more protocol instances from protoinst file protoinst_files/sim_ics_if.protoinst for the following reason(s):
There are no instances of module "sim_ics_if" in the design.

Time resolution is 1 ps
source cmd.tcl
## set curr_wave [current_wave_config]
## if { [string length $curr_wave] == 0 } {
##   if { [llength [get_objects]] > 0} {
##     add_wave /
##     set_property needs_save false [current_wave_config]
##   } else {
##      send_msg_id Add_Wave-1 WARNING "No top level signals found. Simulator will start without a wave window. If you want to open a wave window go to 'File->New Waveform Configuration' or type 'create_wave_config' in the TCL console."
##   }
## }
## log_wave -r /
WARNING: [Simtcl 6-197] One or more HDL objects could not be logged because of object type or size limitations.  To see details please rerun the command with -verbose (-v).
## run -all
UVM_INFO /proj/xbuilds/SWIP/2019.2_0924_1936/installs/lin64/Vivado/2019.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(18601) @ 0: reporter [UVM/RELNOTES]
      (Specify +UVM_NO_RELNOTES to turn off this notice)
  with `UVM_OBJECT_DO_NOT_NEED_CONSTRUCTOR undefined.

  You are using a version of the UVM library that has been compiled
  with `UVM_NO_DEPRECATED undefined.

  You are using a version of the UVM library that has been compiled

  ***********       IMPORTANT RELEASE NOTES         ************
----------------------------------------------------------------
(C) 2013-2014 NVIDIA Corporation
(C) 2011-2013 Cypress Semiconductor Corp.
(C) 2006-2014 Synopsys, Inc.
(C) 2007-2014 Cadence Design Systems, Inc.
(C) 2007-2014 Mentor Graphics Corporation


----------------------------------------------------------------

UVM_INFO /home/akira/work/hls/ICS_IF/test/src/tb_uvm_test.sv(212) @ 0: reporter [info] Hello World from initial block
UVM_INFO @ 0: reporter [RNTST] Running test test...
UVM_INFO /proj/xbuilds/SWIP/2019.2_0924_1936/installs/lin64/Vivado/2019.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(20867) @ 0: reporter [UVM/COMP/NAMECHECK] This implementation of the component name checks requires DPI to be enabled
UVM_INFO @ 0: uvm_test_top [TEST] Hello World from class test
UVM_INFO @ 0: uvm_test_top.env.agent [AGENT] Hi! I am Agent
UVM_INFO @ 0: uvm_test_top.env.agent.sequencer [SEQR] Hi I am Sequencer
UVM_INFO @ 0: uvm_test_top.env.agent.monitor [MONITOR] Hi! I am sample_monitor
UVM_INFO @ 0: uvm_test_top.env.agent.driver [DRIVER] Hi! I am sample_driver
I am issue_one_trans_seq
UVM_INFO @ 200000: uvm_test_top.env.agent.monitor [MON] addr=00h, data=10h
UVM_INFO /proj/xbuilds/SWIP/2019.2_0924_1936/installs/lin64/Vivado/2019.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(19968) @ 1300000: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO /proj/xbuilds/SWIP/2019.2_0924_1936/installs/lin64/Vivado/2019.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(13673) @ 1300000: reporter [UVM/REPORT/SERVER] [info]     1
[UVM/RELNOTES]     1
[UVM/COMP/NAMECHECK]     1
[TEST_DONE]     1
[TEST]     1
[SEQR]     1
[RNTST]     1
[MONITOR]     1
[MON]     1
[DRIVER]     1
[AGENT]     1
** Report counts by id
UVM_FATAL :    0
UVM_ERROR :    0
UVM_WARNING :    0
UVM_INFO :   11
** Report counts by severity

--- UVM Report Summary ---


$finish called at time : 1300 ns : File "/proj/xbuilds/SWIP/2019.2_0924_1936/installs/lin64/Vivado/2019.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv" Line 18699
## quit
INFO: [Common 17-206] Exiting xsim at Fri Jul 24 07:02:17 2020...
[4/4] cd /home/akira/work/hls/ICS_IF/build && /opt/Xilinx/Vivado/2019.2/bin/v....tcl -tclargs /home/akira/work/hls/ICS_IF/build/sim/work/xsim/tb_uvm_test.wdb

****** Vivado v2019.2 (64-bit)
  **** SW Build 2708876 on Wed Nov  6 21:39:14 MST 2019
  **** IP Build 2700528 on Thu Nov  7 00:09:20 MST 2019
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.

source /home/akira/work/vivado_cmake_helper/vivado_open_wdb.tcl
# set wdbfile_name   [lindex $argv  0]
# start_gui
INFO: [Common 17-206] Exiting Vivado at Fri Jul 24 07:02:55 2020...

波形


参考ページ

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

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

2020年7月12日日曜日

VIvado_HLSとVivadoのBlockDesignをCMakeでビルドしてみた

Vivado_HLSとVivadoのBlockDesignをCMAKEでパッケージしてみた話です。 使っているヘルパースクリプトはgithubのリポジトリにて公開しています。 使用方法もgithubのリポジトリで公開しています。 また、CMakeLists.txtの例をヘルパースクリプトのリポジトリのexampleフォルダーに保存しています。

環境

Vivado 2019.2
Vivado_HLS 2019.2
CMake 3.10.2

事前準備

VIVADO_CMAKE_HELPER環境変数にリポジトリパスを登録します。 次のスクリプトを動かしてください。

source <path-to-repository>/setup.sh

使い方

vivado_hls

ディレクトリ構造

サンプルは以下に示すディレクトリ構造を想定しています。

project_top
├── CMakeLists.txt:リポジトリ同梱のCMakeLists.txt.hls_example
├── directives.tcl
├── include:ヘッダ置き場
├── src:ソース置き場
└── test:テストベンチ置き場
    ├── include:テストベンチ用ヘッダ置き場
    └── src:テストベンチ用ソース置き場

CMakeLists.txtの編集方法

ヘッダの保存パスをCFLAGS及びCFLAGS_TESTBENCHにリストとして追加してください。
ソースをSRC_FILESやTESTBENCH_FILESにリストとして追加してください。
リストは区切りの";"を":"に置き換えてください。(そうしないと誤動作する)
その後vivado_hls_export.cmakeをインポートしてください。
これはビルドに必要なcustom_commandとcustom_targetを追加します.
加えて、インストール設定も追加します。archive zipファイルを除き生成結果のipフォルダーをCMAKE_INSTALL_PREFIX/${project_name}にコピーします。

インストール

インストールは以下コマンドで実行できます。<>でくくった部分は環境に合わせて設定してください。

source <path_to_vivado>/setup.sh
source <path_to_this_repository>/setup.sh
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path_to_user_ip_repository>
cmake --build .
make install

vivado ip packager(ipx)

ディレクトリ構造

サンプルは以下に示すディレクトリ構造を想定しています。

project_top
├── CMakeLists.txt:リポジトリ同梱のCMakeLists.txt.ipx_example
├── scripts:blockdesign.tclが保存されることを期待
├── src:rtlモジュール置き場
└── test:テストベンチ置き場
    └── src:テストベンチ用ソース置き場

CMakeLists.txtの編集方法

blockdesign.tclはvivadoのwrite_bd_tclコマンドを使用して作成してください。
design_nameとCMakeLists.txtの編集方法project_nameが同じになるようにしてください。
(または生成されたblockdesign.tclを修正してdesign_nameを変更してください)
必要に応じてrtl moduleとtestbenchをそれぞれSRC_FILES、TESTBENCH_FILESに追加してください。
リストは区切りの";"を":"に置き換えてください。(vivado_hls同様)
その後vivado_ipx_export.cmakeをincludeしてください。
これはビルドに必要なcustom_commandとcustom_targetを追加します。
また、インストール設定を行います。archive zipファイルを除き生成結果のipフォルダーをCMAKE_INSTALL_PREFIX/${project_name}にコピーします。

インストール

インストールは以下コマンドで実行できます。<>でくくった部分は環境に合わせて設定してください。

source <path_to_vivado>/setup.sh
source <path_to_this_repository>/setup.sh
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path_to_user_ip_repository>
cmake --build .
make install

プロジェクトのネスト

プロジェクトがネストしていても動作します。ICS_IFに例があります。
add_subdirectory(modules)で追加し、各々ビルドできるようにCMakeLists.txtを作成してください。

2020年6月19日金曜日

ICS_IPをつくる〜その1仕様検討

ジオニックテクニクスで使用しているサーボモータのKRS-3204と、KRS-3302をシリアルコントロールする話です。
通信インターフェースのICSに対応したIPが落ちていないのでこれを自作していきます。
せっかくの題材なのでこれまであまり本格的にやっていなかった高位合成を試していくこととします。
とりあえずは仕様を検討していきます。

ICSの仕様はここです。日本語なので楽勝。必要そうな情報は以下の通り。

最大接続数:
 Max 32個(ID:0〜31)
定周期送信データ:
 ポジション設定 14bit(周期0)x32
定周期受信データ:
 現在ポジション 14bit(周期0)x32
 現在電流値 7bit(周期1)x32
 現在温度 7bit(周期2)x32
オンデマンド送信データ:
 ストレッチ 7bit
 スピード 7bit
 電流制限 7bit
 温度制限 7bit
 EEPROM 64byte
オンデマンド受信データ:
 EEPROM 64byte
 (角度取得 14bit => ソフトで初期処理時に定周期送信データのポジション設定に反映する)
 
ポジションと電流値は制御に使いそうなので早い周期で回しておきます。
温度は比較的に急変しにくいと思うので少しゆっくりした周期で取得します。
オンデマンドの送信はそれほど多く発生しないと思われるので、全体で共有します。
ROSのサービスで使われることを想定します。
設定が反映されているかどうかはオンデマンドでEEPROMのデータを取得して確認します。
角度取得は初期化時にオンデマンドで取得できるようにしておきます。
定周期送信データは32ch分を一括で転送できるように連続して配置します。
定周期受信データも一括して取得できるようにポジション、電流値、温度毎に連続して配置します。

とりあえずレジスタマップはこんな感じかな。

offsetnamebitR/Winitial valuedescription
0x0010baud_rate[3:0]R/W0b00000:115200bps
1:625000bps
2:1152000bps
other:禁止


[31:4]R0x0000000RSV
0x0018number_of_servos[7:0]R/W0x01ICSで通信するサーボの数を書くこと


[31:8]R0x000000RSV
0x0020cyclic0_config[15:0]R/W0x000Acyclic0で通信する周期をms単位で指定


[30:16]R0x0000RSV


[31]R/W0b00:cyclic0の通信停止
1:cyclic0の通信開始
0x0028cyclic1_config[15:0]R/W0x000Acyclic1で通信する周期をms単位で指定


[30:16]R0x0000RSV


[31]R/W0b00:cyclic1の通信停止
1:cyclic1の通信開始
0x0030cyclic2_config[15:0]R/W0x03E8cyclic2で通信する周期をms単位で指定


[30:16]R0x0000RSV


[31]R/W0b00:cyclic2の通信停止
1:cyclic2の通信開始
0x0038ondemand_cmd[7:0]R/W0x00送信サイズをバイト単位で指定


[30:8]R0x00RSV


[31]R0b0ondemand通信ステータス
0:通信完了
1:通信中


[31]W0b0ondemand通信コマンド
0:変化なし
1:通信指示
0x0040RSV[31:0]R/W0x00000000RSV





0x07FCRSV[31:0]R/W0x00000000RSV
0x0800cyclic0_tx_0[7:5]R/W0b100ポジション設定コマンド(0b100)を書くこと


[4:0]R/W0b00000対象となるサーボのIDを書くこと


[15:8]R/W0x00RSV


[31:16]R/W0x0000設定舵角14bit(bit31,bit30は0固定)
0x0804cyclic0_tx_1[31:0]R/W0x00000080cyclic0_tx_0同様
0x0808cyclic0_tx_2[31:0]R/W0x00000080cyclic0_tx_0同様





0x087Ccyclic0_tx_31[31:0]R/W0x00000080cyclic0_tx_0同様
0x0880cyclic1_tx_0[7:5]R/W0b10115


[4:0]R/W0b00000対象となるサーボのIDを書くこと


[15:8]R/W0x03サブコマンドとして電流値を指定すること(0x03)


[23:16]R/W0x00RSV


[31:24]R/W0x00RSV
0x0884cyclic1_tx_1[31:0]R/W0x000003A0cyclic1_tx_0同様





0x08FCcyclic1_tx_31[31:0]R/W0x000003A0cyclic1_tx_0同様
0x0900cyclic2_tx_0[7:5]R/W0b101パラメータ読み出しコマンド(0b101)を書くこと


[4:0]R/W0b00000


[15:8]R/W0x04サブコマンドとして温度を指定すること(0x04)


[23:16]R/W0x00RSV


[31:24]R/W0x00RSV
0x0904cyclic2_tx_1[31:0]R/W0x000004A0cyclic2_tx_0同様





0x097Ccyclic2_tx_31[31:0]R/W0x000004A0cyclic2_tx_0同様
0x0980ondemand_tx_0_wd0[7:5]R/W0b000ICSの任意のコマンドを指定すること


[4:0]R/W0b00000対象のIDを記載すること


[15:8]R/W0x00ICSの2byte目を書くこと


[23:16]R/W0x00ICSの3byte目を書くこと


[31:24]R/W0x00ICSの4byte目を書くこと
0x0984ondemand_tx_0_wd1[7:0]R/W0x00ICSの5byte目を書くこと


[15:8]R/W0x00ICSの6byte目を書くこと


[23:16]R/W0x00ICSの7byte目を書くこと


[31:24]R/W0x00ICSの8byte目を書くこと





0x09C0ondemand_tx_0_wd17[7:0]R/W0x00ICSの65byte目を書くこと


[15:8]R/W0x00ICSの66byte目を書くこと


[23:16]R/W0x00RSV


[31:24]R/W0x00RSV
0x09C4RSV[31:0]R/W0x00RSV





0x0C00cyclic0_rx_0[7:5]R/W0x0000cyclic0_tx_0に対応する返信コマンド(0b000)


[4:0]R/W0b00cyclic0_tx_0に対応する返信データに記載されているサーボID


[15:8]R/W0x00受信カウンタ


[31:16]R/W0x00現在角度の取得結果。通信データと異なり14bitのデータに復元する
0x0C04cyclic0_rx_1[31:0]R/W0x00000000cyclic0_rx_0同様





0x0C7Ccyclic0_rx_31[31:0]R/W0x00000000cyclic0_rx_0同様
0x0C80cyclic1_rx_0[7:0]R/W0x00cyclic1_tx_0に対応した返信コマンドとIDが保存される


[15:8]R/W0x00cyclic1_tx_0に対応したサブコマンドが保存される


[23:16]R/W0x00読み出した電流値が保存される


[31:24]R/W0x00受信カウンタ
0x0C84cyclic1_rx_1[31:0]R/W0x00000000cyclic1_rx_0同様





0x0CFCcyclic1_rx_31[31:0]R/W0x00000000cyclic1_rx_0同様
0x0D00cyclic2_rx_0[7:0]R/W0x00cyclic1_tx_0に対応した返信コマンドとIDが保存される


[15:8]R/W0x00cyclic1_tx_0に対応したサブコマンドが保存される


[23:16]R/W0x00読み出した温度値が保存される


[31:24]R/W0x00受信カウンタ
0x0D04cyclic2_rx_1[31:0]R/W0x00000000cyclic2_rx_0同様





0x0D7Ccyclic2_rx_31[31:0]R/W0x00000000cyclic2_rx_0同様
0x0D80ondemand_rx_0_wd0[7:5]R/W0b000ondemand_tx_0_wd0に対応した返信コマンドが保存される


[4:0]R/W0b00000ondemand_tx_0_wd0に対応した返信コマンドのIDが保存される


[15:8]R/W0x00ondemand_tx_0の返信データ2byte目が保存される


[23:16]R/W0x00ondemand_tx_0の返信データ3byte目が保存される


[31:24]R/W0x00ondemand_tx_0の返信データ4byte目が保存される





0x0DC0ondemand_rx_0_wd17[7:0]R/W0x00ondemand_tx_0の返信データ65byte目が保存される


[15:8]R/W0x00ondemand_tx_0の返信データ66byte目が保存される


[23:16]R/W0x00RSV


[31:24]R/W0x00受信カウンタ
0x0DC4RSV[31:0]R/W0x00000000RSV





0x0FFCRSV[31:0]R/W0x00000000RSV