精华内容
下载资源
问答
  • UVM入门和进阶.pdf

    2021-04-23 22:06:17
    UVM入门资料
  • UVM入门与进阶

    2021-03-26 16:45:28
    UVM入门与进阶(实验部分)phase机制config机制消息管理 phase机制 phase机制使得验证环境从组建、到连接、再到执行得以分阶段进行,按照层次结构和phase顺序严格执行,继而避免一些依赖关系,也使得UVM用户可以正确...

    UVM入门与进阶(实验部分)

    phase机制

    phase机制使得验证环境从组建、到连接、再到执行得以分阶段进行,按照层次结构和phase顺序严格执行,继而避免一些依赖关系,也使得UVM用户可以正确地将不同的代码放置到不同的phase块中。

    • 代码:
    
    package phase_order_pkg;
      import uvm_pkg::*;
      `include "uvm_macros.svh"
    
      class comp2 extends uvm_component;
        `uvm_component_utils(comp2)
        function new(string name = "comp2", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp2 build phase entered", UVM_LOW)
          `uvm_info("BUILD", "comp2 build phase exited", UVM_LOW)
        endfunction
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          `uvm_info("CONNECT", "comp2 connect phase entered", UVM_LOW)
          `uvm_info("CONNECT", "comp2 connect phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "comp2 run phase entered", UVM_LOW)
          `uvm_info("RUN", "comp2 run phase entered", UVM_LOW)
        endtask
        function void report_phase(uvm_phase phase);
          super.report_phase(phase);
          `uvm_info("REPORT", "comp2 report phase entered", UVM_LOW)
          `uvm_info("REPORT", "comp2 report phase exited", UVM_LOW)   
        endfunction
      endclass
      
      class comp3 extends uvm_component;
        `uvm_component_utils(comp3)
        function new(string name = "comp3", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp3 build phase entered", UVM_LOW)
          `uvm_info("BUILD", "comp3 build phase exited", UVM_LOW)
        endfunction
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          `uvm_info("CONNECT", "comp3 connect phase entered", UVM_LOW)
          `uvm_info("CONNECT", "comp3 connect phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "comp3 run phase entered", UVM_LOW)
          `uvm_info("RUN", "comp3 run phase entered", UVM_LOW)
        endtask
        function void report_phase(uvm_phase phase);
          super.report_phase(phase);
          `uvm_info("REPORT", "comp3 report phase entered", UVM_LOW)
          `uvm_info("REPORT", "comp3 report phase exited", UVM_LOW)   
        endfunction
      endclass
      
      class comp1 extends uvm_component;
        comp2 c2;
        comp3 c3;
        `uvm_component_utils(comp1)
        function new(string name = "comp1", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp1 build phase entered", UVM_LOW)
          c2 = comp2::type_id::create("c2", this);
          c3 = comp3::type_id::create("c3", this);
          `uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
        endfunction
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          `uvm_info("CONNECT", "comp1 connect phase entered", UVM_LOW)
          `uvm_info("CONNECT", "comp1 connect phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
          `uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
        endtask
        function void report_phase(uvm_phase phase);
          super.report_phase(phase);
          `uvm_info("REPORT", "comp1 report phase entered", UVM_LOW)
          `uvm_info("REPORT", "comp1 report phase exited", UVM_LOW)   
        endfunction
      endclass
    
      class phase_order_test extends uvm_test;
        comp1 c1;
        `uvm_component_utils(phase_order_test)
        function new(string name = "phase_order_test", uvm_component parent = null);
          super.new(name, parent);
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "phase_order_test build phase entered", UVM_LOW)
          c1 = comp1::type_id::create("c1", this);
          `uvm_info("BUILD", "phase_order_test build phase exited", UVM_LOW)
        endfunction
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          `uvm_info("CONNECT", "phase_order_test connect phase entered", UVM_LOW)
          `uvm_info("CONNECT", "phase_order_test connect phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "phase_order_test run phase entered", UVM_LOW)
          phase.raise_objection(this);
          #1us;
          phase.drop_objection(this);
          `uvm_info("RUN", "phase_order_test run phase exited", UVM_LOW)
        endtask
        function void report_phase(uvm_phase phase);
          super.report_phase(phase);
          `uvm_info("REPORT", "phase_order_test report phase entered", UVM_LOW)
          `uvm_info("REPORT", "phase_order_test report phase exited", UVM_LOW)    
        endfunction
        
        task reset_phase(uvm_phase phase);
          `uvm_info("RESET", "phase_order_test reset phase entered", UVM_LOW)
          phase.raise_objection(this);
          #1us;
          phase.drop_objection(this);
          `uvm_info("RESET", "phase_order_test reset phase exited", UVM_LOW)
        endtask
        
        task main_phase(uvm_phase phase);
          `uvm_info("MAIN", "phase_order_test main phase entered", UVM_LOW)
          phase.raise_objection(this);
          #1us;
          phase.drop_objection(this);
          `uvm_info("MAIN", "phase_order_test main phase exited", UVM_LOW)
        endtask 
      endclass
    endpackage
    
    module phase_order;
    
      import uvm_pkg::*;
      `include "uvm_macros.svh"
      import phase_order_pkg::*;
    
      initial begin
        run_test("phase_order_test"); // empty test name
      end
    
    endmodule
    
    • 实验结果:
      在这里插入图片描述
      在这里插入图片描述

    config机制

    • 代码:
    // An highlighted block
    interface uvm_config_if;
      logic [31:0] addr;
      logic [31:0] data;
      logic [ 1:0] op;
    endinterface
    
    package uvm_config_pkg;
      import uvm_pkg::*;
      `include "uvm_macros.svh"
      
      class config_obj extends uvm_object;
        int comp1_var;
        int comp2_var;
        `uvm_object_utils(config_obj)
        function new(string name = "config_obj");
          super.new(name);
          `uvm_info("CREATE", $sformatf("config_obj type [%s] created", name), UVM_LOW)
        endfunction
      endclass
      
      class comp2 extends uvm_component;
        int var2;
        virtual uvm_config_if vif;  
        config_obj cfg; 
        `uvm_component_utils(comp2)
        function new(string name = "comp2", uvm_component parent = null);
          super.new(name, parent);
          var2 = 200;
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp2 build phase entered", UVM_LOW)
          if(!uvm_config_db#(virtual uvm_config_if)::get(this, "", "vif", vif))
            `uvm_error("GETVIF", "no virtual interface is assigned")
            
          `uvm_info("GETINT", $sformatf("before config get, var2 = %0d", var2), UVM_LOW)
          uvm_config_db#(int)::get(this, "", "var2", var2);
          `uvm_info("GETINT", $sformatf("after config get, var2 = %0d", var2), UVM_LOW)
          
          uvm_config_db#(config_obj)::get(this, "", "cfg", cfg);
          `uvm_info("GETOBJ", $sformatf("after config get, cfg.comp2_var = %0d", cfg.comp2_var), UVM_LOW)     
          
          `uvm_info("BUILD", "comp2 build phase exited", UVM_LOW)
        endfunction
      endclass
    
      class comp1 extends uvm_component;
        int var1;
        comp2 c2;
        config_obj cfg; 
        virtual uvm_config_if vif;
        `uvm_component_utils(comp1)
        function new(string name = "comp1", uvm_component parent = null);
          super.new(name, parent);
          var1 = 100;
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp1 build phase entered", UVM_LOW)
          if(!uvm_config_db#(virtual uvm_config_if)::get(this, "", "vif", vif))
            `uvm_error("GETVIF", "no virtual interface is assigned")
            
          `uvm_info("GETINT", $sformatf("before config get, var1 = %0d", var1), UVM_LOW)
          uvm_config_db#(int)::get(this, "", "var1", var1);
          `uvm_info("GETINT", $sformatf("after config get, var1 = %0d", var1), UVM_LOW)
          
          uvm_config_db#(config_obj)::get(this, "", "cfg", cfg);
          `uvm_info("GETOBJ", $sformatf("after config get, cfg.comp1_var = %0d", cfg.comp1_var), UVM_LOW)
          
          c2 = comp2::type_id::create("c2", this);
          `uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
        endfunction
      endclass
    
      class uvm_config_test extends uvm_test;
        comp1 c1;
        config_obj cfg;
        `uvm_component_utils(uvm_config_test)
        function new(string name = "uvm_config_test", uvm_component parent = null);
          super.new(name, parent);
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "uvm_config_test build phase entered", UVM_LOW)
          
          cfg = config_obj::type_id::create("cfg");
          cfg.comp1_var = 100;
          cfg.comp2_var = 200;
          uvm_config_db#(config_obj)::set(this, "*", "cfg", cfg);
          
          uvm_config_db#(int)::set(this, "c1", "var1", 10);
          uvm_config_db#(int)::set(this, "c1.c2", "var2", 20);
          
          c1 = comp1::type_id::create("c1", this);
          `uvm_info("BUILD", "uvm_config_test build phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "uvm_config_test run phase entered", UVM_LOW)
          phase.raise_objection(this);
          #1us;
          phase.drop_objection(this);
          `uvm_info("RUN", "uvm_config_test run phase exited", UVM_LOW)
        endtask
      endclass
    endpackage
    
    module uvm_config;
    
      import uvm_pkg::*;
      `include "uvm_macros.svh"
      import uvm_config_pkg::*;
      
      uvm_config_if if0();
    
      initial begin
        uvm_config_db#(virtual uvm_config_if)::set(uvm_root::get(), "uvm_test_top.*", "vif", if0);
        run_test("uvm_config_test"); // empty test name
      end
    
    endmodule
    
    • 实验结果:
      在这里插入图片描述

    消息管理

    • 代码:
    
    package uvm_message_pkg;
      import uvm_pkg::*;
      `include "uvm_macros.svh"
      
      class config_obj extends uvm_object;
        `uvm_object_utils(config_obj)
        function new(string name = "config_obj");
          super.new(name);
          `uvm_info("CREATE", $sformatf("config_obj type [%s] created", name), UVM_LOW)
        endfunction
      endclass
      
      class comp2 extends uvm_component;
        `uvm_component_utils(comp2)
        function new(string name = "comp2", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp2 build phase entered", UVM_LOW)
          `uvm_info("BUILD", "comp2 build phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "comp2 run phase entered", UVM_LOW)
          `uvm_info("RUN", "comp2 run phase exited", UVM_LOW)
        endtask
      endclass
    
      class comp1 extends uvm_component;
        `uvm_component_utils(comp1)
        function new(string name = "comp1", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "comp1 build phase entered", UVM_LOW)
          `uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
          `uvm_info("RUN", "comp1 run phase exited", UVM_LOW)
        endtask
      endclass
    
      class uvm_message_test extends uvm_test;
        config_obj cfg;
        comp1 c1;
        comp2 c2;
        `uvm_component_utils(uvm_message_test)
        function new(string name = "uvm_message_test", uvm_component parent = null);
          super.new(name, parent);
        endfunction
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          `uvm_info("BUILD", "uvm_message_test build phase entered", UVM_LOW)
          cfg = config_obj::type_id::create("cfg");
          c1 = comp1::type_id::create("c1", this);
          c2 = comp2::type_id::create("c2", this);
    
          //TODO-5.1
          //Use set_report_verbosity_level_hier() to disable all of UVM messages
          //under the uvm_message_test
           set_report_verbosity_level_hier(UVM_NONE);
          
          //TODO-5.2
          //Use set_report_id_verbosity_level_hier() to disable all of 
          //"CREATE", "BUILD", "RUN" ID message under the uvm_message_test
          // Think why message "CREATE" could not be disabled ?
          //set_report_id_verbosity_hier("BUILD", UVM_NONE);
          //set_report_id_verbosity_hier("CREATE", UVM_NONE);
          //set_report_id_verbosity_hier("RUN", UVM_NONE);
          
          //TODO-5.3
          //Why the UVM message from config_obj type and uvm_message module
          //could not be disabled? Please use the message filter methods
          //to disable them
          // uvm_root::get().set_report_id_verbosity_hier("CREATE", UVM_NONE);
          // uvm_root::get().set_report_id_verbosity_hier("BUILD", UVM_NONE);
          // uvm_root::get().set_report_id_verbosity_hier("RUN", UVM_NONE);
          `uvm_info("BUILD", "uvm_message_test build phase exited", UVM_LOW)
        endfunction
        
        // NOTE::
        // Try to put the set_report_XXX function below inside
        // end_of_elaboration_phase and check the differences with the function
        // call inside build_phase
        //
        // set verbosity with 'hier' function must be applied once all
        // sub-components are created
        function void end_of_elaboration_phase(uvm_phase phase);
          //TODO-5.2
          //Use set_report_id_verbosity_level_hier() to disable all of 
          //"CREATE", "BUILD", "RUN" ID message under the uvm_message_test
          // Think why message "CREATE" or "BUILD" could not be disabled ?
          set_report_id_verbosity_hier("BUILD", UVM_NONE);
          set_report_id_verbosity_hier("CREATE", UVM_NONE);
          set_report_id_verbosity_hier("RUN", UVM_NONE);
        endfunction
    
        task run_phase(uvm_phase phase);
          super.run_phase(phase);
          `uvm_info("RUN", "uvm_message_test run phase entered", UVM_LOW)
          phase.raise_objection(this);
          phase.drop_objection(this);
          `uvm_info("RUN", "uvm_message_test run phase exited", UVM_LOW)
        endtask
      endclass
    endpackage
    
    module uvm_message_ref;
    
      import uvm_pkg::*;
      `include "uvm_macros.svh"
      import uvm_message_pkg::*;
      
      initial begin
        //TODO-5.3
        //Why the UVM message from config_obj type and uvm_message module
        //could not be disabled? Please use the message filter methods
        //to disable them
        uvm_root::get().set_report_id_verbosity_hier("TOPTB", UVM_NONE);
        `uvm_info("TOPTB", "RUN TEST entered", UVM_LOW)
        run_test(""); // empty test name
        `uvm_info("TOPTB", "RUN TEST exited", UVM_LOW)
      end
    
    endmodule
    
    • 实验结果
      在这里插入图片描述
    展开全文
  • UVM入门实验4

    2021-03-05 10:40:38
    UVM入门实验3中,实现了monitor、reference model与checker之间的通信是通过TLM端口或者TLM FIFO来完成,相较于之前的mailbox句柄连接,更加容易定制,也使得组件的独立性提高。 本次实验需要实现: 将产生...

    在UVM入门实验3中,实现了monitorreference modelchecker之间的通信是通过TLM端口或者TLM FIFO来完成,相较于之前的mailbox句柄连接,更加容易定制,也使得组件的独立性提高。

    本次实验需要实现:

    • 将产生transaction并且发送至drivergenerator组件,拆分为sequencesequencer

    • 在拆分的基础上,实现底层的sequence

    • 完成sequencerdriver的连接和通信工作。

    • 构建顶层的virtual sequencer

    • 将原有的mcdf_base_test拆分为mcdf_base_virtual_sequencemcdf_base_test,前者发挥产生序列的工作,后者只完成挂载序列的工作。

    • 将原有的mcdf_data_consistence_basic_testmcdf_full_random_test继续拆分为对应的virtual sequence和轻量化的顶层test

    通过实验4可以将generatordrivertest的关系最终移植为sequencesequencerdrivertest的关系。

    一、driver与sequence的改建

    移除原有在各个driver中的mailbox句柄,以及在do_driver()任务中使用mailbox句柄通信的方式,转而用uvm_driver::seq_item_port进行通信,同时定义对应的uvm_sequencer

    	//移除各个`driver`中的`mailbox`句柄
        //mailbox #(reg_trans) req_mb;
        //mailbox #(reg_trans) rsp_mb;
    
    
        task do_drive();
          reg_trans req, rsp;
          @(posedge intf.rstn);
          forever begin
            seq_item_port.get_next_item(req);
            this.reg_write(req);
            void'($cast(rsp, req.clone()));
            rsp.rsp = 1;
            rsp.set_sequence_id(req.get_sequence_id());
            seq_item_port.item_done(rsp);
          end
        endtask
    
      class reg_sequencer extends uvm_sequencer #(reg_trans);
        `uvm_component_utils(reg_sequencer)
        function new (string name = "reg_sequencer", uvm_component parent);
          super.new(name, parent);
        endfunction
      endclass: reg_sequencer
    

    二、底层sequence的提取

    将原来在各个generator中发送transaction的任务,提取为各个对应的底层sequence。在各个agent中声明、创建对应的sequencer,并且将其与driver通过TLM port连接起来。

      //extract chnl_data_sequence from the reg_generator
      class reg_base_sequence extends uvm_sequence #(reg_trans);
        rand bit[7:0] addr = -1;
        rand bit[1:0] cmd = -1;
        rand bit[31:0] data = -1;
    
        constraint cstr{
          soft addr == -1;
          soft cmd == -1;
          soft data == -1;
        }
    
        `uvm_object_utils_begin(reg_base_sequence)
          `uvm_field_int(addr, UVM_ALL_ON)
          `uvm_field_int(cmd, UVM_ALL_ON)
          `uvm_field_int(data, UVM_ALL_ON)
        `uvm_object_utils_end
        `uvm_declare_p_sequencer(reg_sequencer)
    
        function new (string name = "reg_base_sequence");
          super.new(name);
        endfunction
    
        task body();
          send_trans();
        endtask
    
        // generate transaction and put into local mailbox
        task send_trans();
          reg_trans req, rsp;
          `uvm_do_with(req, {local::addr >= 0 -> addr == local::addr;
                             local::cmd >= 0 -> cmd == local::cmd;
                             local::data >= 0 -> data == local::data;
                             })
          `uvm_info(get_type_name(), req.sprint(), UVM_HIGH)
          get_response(rsp);
          `uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH)
          if(req.cmd == `READ) 
            this.data = rsp.data;
          assert(rsp.rsp)
            else $error("[RSPERR] %0t error response received!", $time);
        endtask
    
        function void post_randomize();
          string s;
          s = {s, "AFTER RANDOMIZATION \n"};
          s = {s, "=======================================\n"};
          s = {s, "reg_base_sequence object content is as below: \n"};
          s = {s, super.sprint()};
          s = {s, "=======================================\n"};
          `uvm_info(get_type_name(), s, UVM_HIGH)
        endfunction
      endclass: reg_base_sequence
    
      class idle_reg_sequence extends reg_base_sequence;
        constraint cstr{
          addr == 0;
          cmd == `IDLE;
          data == 0;
        }
        `uvm_object_utils(idle_reg_sequence)
        function new (string name = "idle_reg_sequence");
          super.new(name);
        endfunction
      endclass: idle_reg_sequence
    
      class write_reg_sequence extends reg_base_sequence;
        constraint cstr{
          cmd == `WRITE;
        }
        `uvm_object_utils(write_reg_sequence)
        function new (string name = "write_reg_sequence");
          super.new(name);
        endfunction
      endclass: write_reg_sequence
    
      class read_reg_sequence extends reg_base_sequence;
        constraint cstr{
          cmd == `READ;
        }
        `uvm_object_utils(read_reg_sequence)
        function new (string name = "read_reg_sequence");
          super.new(name);
        endfunction
      endclass: read_reg_sequence 
    
      // register agent
      class reg_agent extends uvm_agent;
        reg_driver driver;
        reg_monitor monitor;
        // declare the sequencer
        reg_sequencer sequencer;
        local virtual reg_intf vif;
    
        `uvm_component_utils(reg_agent)
    
        function new(string name = "reg_agent", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          driver = reg_driver::type_id::create("driver", this);
          monitor = reg_monitor::type_id::create("monitor", this);
          // instantiate the sequencer
          sequencer = reg_sequencer::type_id::create("sequencer", this);
        endfunction
    
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          //connect the driver and the sequencer
          driver.seq_item_port.connect(sequencer.seq_item_export);
        endfunction
    
        function void set_interface(virtual reg_intf vif);
          this.vif = vif;
          driver.set_interface(vif);
          monitor.set_interface(vif);
        endfunction
      endclass
    
    

    三、移除generator的踪迹

    mcdf_base_test中移除generator的声明、创建以及和driver之间的连接。

      class mcdf_base_test extends uvm_test;
        //remove the generators' handle clarification
        //chnl_generator chnl_gens[3];
        //reg_generator reg_gen;
        //fmt_generator fmt_gen;
        mcdf_env env;
        virtual chnl_intf ch0_vif ;
        virtual chnl_intf ch1_vif ;
        virtual chnl_intf ch2_vif ;
        virtual reg_intf reg_vif  ;
        virtual arb_intf arb_vif  ;
        virtual fmt_intf fmt_vif  ;
        virtual mcdf_intf mcdf_vif;
    
        `uvm_component_utils(mcdf_base_test)
    
        function new(string name = "mcdf_base_test", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          // get virtual interface from top TB
          if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
    
          this.env = mcdf_env::type_id::create("env", this);
          //remove the generators' instantiation 
          //foreach(this.chnl_gens[i]) begin
          //  this.chnl_gens[i] = chnl_generator::type_id::create($sformatf("chnl_gens[%0d]",i), this);
          //end
          //this.reg_gen = reg_generator::type_id::create("reg_gen", this);
          //this.fmt_gen = fmt_generator::type_id::create("fmt_gen", this);
        endfunction
    
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          // After get virtual interface from config_db, and then set them to
          // child components
          this.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif);
    
          // remove the cross-hierarchy handle connection between drivers
          //and generators since they are now connected inside the agents by the
          //TLM ports connection between the sequencer and the driver
          /*
          foreach(this.chnl_gens[i]) begin
            this.env.chnl_agts[i].driver.req_mb = this.chnl_gens[i].req_mb;
            this.env.chnl_agts[i].driver.rsp_mb = this.chnl_gens[i].rsp_mb;
          end
          this.env.reg_agt.driver.req_mb = this.reg_gen.req_mb;
          this.env.reg_agt.driver.rsp_mb = this.reg_gen.rsp_mb;
          this.env.fmt_agt.driver.req_mb = this.fmt_gen.req_mb;
          this.env.fmt_agt.driver.rsp_mb = this.fmt_gen.rsp_mb;
          */
        endfunction
    
        function void end_of_elaboration_phase(uvm_phase phase);
          super.end_of_elaboration_phase(phase);
          uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);
          uvm_root::get().set_report_max_quit_count(1);
          uvm_root::get().set_timeout(10ms);
        endfunction
    
        task run_phase(uvm_phase phase);
          // NOTE:: raise objection to prevent simulation stopping
          phase.raise_objection(this);
    
          `uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW)
          this.do_reg();
          this.do_formatter();
          this.do_data();
          `uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW)
    
          // NOTE:: drop objection to request simulation stopping
          phase.drop_objection(this);
        endtask
    
        // do register configuration
        virtual task do_reg();
        endtask
    
        // do external formatter down stream slave configuration
        virtual task do_formatter();
        endtask
    
        // do data transition from 3 channel slaves
        virtual task do_data();
        endtask
    
        virtual function void set_interface(virtual chnl_intf ch0_vif 
                                            ,virtual chnl_intf ch1_vif 
                                            ,virtual chnl_intf ch2_vif 
                                            ,virtual reg_intf reg_vif
                                            ,virtual arb_intf arb_vif
                                            ,virtual fmt_intf fmt_vif
                                            ,virtual mcdf_intf mcdf_vif
                                          );
          this.env.chnl_agts[0].set_interface(ch0_vif);
          this.env.chnl_agts[1].set_interface(ch1_vif);
          this.env.chnl_agts[2].set_interface(ch2_vif);
          this.env.reg_agt.set_interface(reg_vif);
          this.env.fmt_agt.set_interface(fmt_vif);
          this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif);
          this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif);
        endfunction
    
        virtual function bit diff_value(int val1, int val2, string id = "value_compare");
          if(val1 != val2) begin
            `uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2)) 
            return 0;
          end
          else begin
            `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)
            return 1;
          end
        endfunction
    
        // remove the tasks and they are implemented already by register
        //sequences
        //  -idle_reg()
        //  -write_reg()
        //  -read_reg()
        virtual task idle_reg();
          void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});
          reg_gen.start();
        endtask
    
        virtual task write_reg(bit[7:0] addr, bit[31:0] data);
          void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});
          reg_gen.start();
        endtask
    
        virtual task read_reg(bit[7:0] addr, output bit[31:0] data);
          void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});
          reg_gen.start();
          data = reg_gen.data;
        endtask
      endclass: mcdf_base_test
    

    四、移除uvm_base_test的transaction发送方法。

    将已经被从uvm_base_test移植到reg_pkg中的方法idle_reg()write_reg()read_reg()uvm_base_test中移除。由此uvm_base_test只变为了容器的性质,在它内部主要由mcdf_envmcdf_config配置对象以及被用来挂载的顶层sequence构成。

        task run_phase(uvm_phase phase);
          // NOTE:: raise objection to prevent simulation stopping
          phase.raise_objection(this);
    
          this.run_top_virtual_sequence();
    
          // NOTE:: drop objection to request simulation stopping
          phase.drop_objection(this);
        endtask
    
        virtual task run_top_virtual_sequence();
          // User to implement this task in the child tests
        endtask
    
        //remove the tasks and they are implemented already by register
        //sequences
        //  -idle_reg()
        //  -write_reg()
        //  -read_reg()
        /*
        virtual task idle_reg();
          void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});
          reg_gen.start();
        endtask
    
        virtual task write_reg(bit[7:0] addr, bit[31:0] data);
          void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});
          reg_gen.start();
        endtask
    
        virtual task read_reg(bit[7:0] addr, output bit[31:0] data);
          void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});
          reg_gen.start();
          data = reg_gen.data;
        endtask
        */
    

    五、添加顶层的virtual sequencer

    由于MCDF验证环境中存在多个底层的sequencersequence,因此这就需要有顶层的virtual sequencervirtual sequence统一调度。在定义了mcdf_virtual_sequencer之后,在mcdf_env中声明、例化,并且完成其与底层sequencer的句柄连接。

      class mcdf_virtual_sequencer extends uvm_sequencer;
        reg_sequencer reg_sqr;
        fmt_sequencer fmt_sqr;
        chnl_sequencer chnl_sqrs[3];
        `uvm_component_utils(mcdf_virtual_sequencer)
        function new (string name = "mcdf_virtual_sequencer", uvm_component parent);
          super.new(name, parent);
        endfunction
      endclass
    
      // MCDF top environment
      class mcdf_env extends uvm_env;
        chnl_agent chnl_agts[3];
        reg_agent reg_agt;
        fmt_agent fmt_agt;
        mcdf_checker chker;
        mcdf_coverage cvrg;
        // declare the virtual sequencer handle
        mcdf_virtual_sequencer virt_sqr;
    
        `uvm_component_utils(mcdf_env)
    
        function new (string name = "mcdf_env", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          this.chker = mcdf_checker::type_id::create("chker", this);
          foreach(chnl_agts[i]) begin
            this.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]",i), this);
          end
          this.reg_agt = reg_agent::type_id::create("reg_agt", this);
          this.fmt_agt = fmt_agent::type_id::create("fmt_agt", this);
          this.cvrg = mcdf_coverage::type_id::create("cvrg", this);
          //  instantiate the virtual sequencer
          virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
        endfunction
    
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp);
          chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp);
          chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp);
          reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp);
          fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp);
          //  connect the sequencer handles of the virtual sequencer to
          //those dedicated sequencer objects inside the agents
          virt_sqr.reg_sqr = reg_agt.sequencer;
          virt_sqr.fmt_sqr = fmt_agt.sequencer;
          foreach(virt_sqr.chnl_sqrs[i]) virt_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer;
        endfunction
      endclass: mcdf_env
    

    六、重构mcdf_base_test

    原有的mcdf_base_test除了承担其容器的功能,还在其run_phase阶段中实现了sequence的分阶段发送功能。在添加了顶层的virtual sequencer之后,需要将所有发送序列的顺序和组织等内容均移植到mcdf_base_virtual_sequence,因此需要将mcdf_base_test::run_phase()发送序列的功能移植到定义的mcdf_base_virtual_sequence一侧,而在移植后,mcdf_base_test::run_phase()只需要挂载对应的顶层virtual sequence即可。

      // MCDF base test 容器作用
      class mcdf_base_test extends uvm_test;
        // remove the generators' handle clarification
        mcdf_env env;
        virtual chnl_intf ch0_vif ;
        virtual chnl_intf ch1_vif ;
        virtual chnl_intf ch2_vif ;
        virtual reg_intf reg_vif  ;
        virtual arb_intf arb_vif  ;
        virtual fmt_intf fmt_vif  ;
        virtual mcdf_intf mcdf_vif;
    
        `uvm_component_utils(mcdf_base_test)
    
        function new(string name = "mcdf_base_test", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        function void build_phase(uvm_phase phase);
          super.build_phase(phase);
          // get virtual interface from top TB
          if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
          if(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin
            `uvm_fatal("GETVIF","cannot get vif handle from config DB")
          end
    
          this.env = mcdf_env::type_id::create("env", this);
          // remove the generators' instantiation 
        endfunction
    
        function void connect_phase(uvm_phase phase);
          super.connect_phase(phase);
          // After get virtual interface from config_db, and then set them to
          // child components
          this.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif);
    
          // remove the cross-hierarchy handle connection between drivers
          //and generators since they are now connected inside the agents by the
          //TLM ports connection between the sequencer and the driver
        endfunction
    
        function void end_of_elaboration_phase(uvm_phase phase);
          super.end_of_elaboration_phase(phase);
          uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);
          uvm_root::get().set_report_max_quit_count(1);
          uvm_root::get().set_timeout(10ms);
        endfunction
    
        task run_phase(uvm_phase phase);
          // NOTE:: raise objection to prevent simulation stopping
          phase.raise_objection(this);
    
          this.run_top_virtual_sequence();
    
          // NOTE:: drop objection to request simulation stopping
          phase.drop_objection(this);
        endtask
    
        virtual task run_top_virtual_sequence();
          // User to implement this task in the child tests
        endtask
    
        virtual function void set_interface(virtual chnl_intf ch0_vif 
                                            ,virtual chnl_intf ch1_vif 
                                            ,virtual chnl_intf ch2_vif 
                                            ,virtual reg_intf reg_vif
                                            ,virtual arb_intf arb_vif
                                            ,virtual fmt_intf fmt_vif
                                            ,virtual mcdf_intf mcdf_vif
                                          );
          this.env.chnl_agts[0].set_interface(ch0_vif);
          this.env.chnl_agts[1].set_interface(ch1_vif);
          this.env.chnl_agts[2].set_interface(ch2_vif);
          this.env.reg_agt.set_interface(reg_vif);
          this.env.fmt_agt.set_interface(fmt_vif);
          this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif);
          this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif);
        endfunction
    
    
        // remove the tasks and they are implemented already by register
        //sequences
        //  -idle_reg()
        //  -write_reg()
        //  -read_reg()
      endclass: mcdf_base_test
    
      class mcdf_base_virtual_sequence extends uvm_sequence;
        idle_reg_sequence idle_reg_seq;
        write_reg_sequence write_reg_seq;
        read_reg_sequence read_reg_seq;
        chnl_data_sequence chnl_data_seq;
        fmt_config_sequence fmt_config_seq;
    
        `uvm_object_utils(mcdf_base_virtual_sequence)
        `uvm_declare_p_sequencer(mcdf_virtual_sequencer)
    
        function new (string name = "mcdf_base_virtual_sequence");
          super.new(name);
        endfunction
    
        virtual task body();
          `uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW)
          this.do_reg();
          this.do_formatter();
          this.do_data();
          `uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW)
        endtask
    
        // do register configuration
        virtual task do_reg();
          //User to implment the task in the child virtual sequence
        endtask
    
        // do external formatter down stream slave configuration
        virtual task do_formatter();
          //User to implment the task in the child virtual sequence
        endtask
    
        // do data transition from 3 channel slaves
        virtual task do_data();
          //User to implment the task in the child virtual sequence
        endtask
    
        virtual function bit diff_value(int val1, int val2, string id = "value_compare");
          if(val1 != val2) begin
            `uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2)) 
            return 0;
          end
          else begin
            `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)
            return 1;
          end
        endfunction
      endclass
    

    七、重构mcdf_data_consistence_basic_test

    将其产生和发送transaction的任务,都移植到mcdf_data_consistence_basic_virtual_sequence,而进一步减轻mcdf_data_consistence_basic_test的代码量。测试的动态场景往往都是由virtual sequence统一组织的,而test层往往之后做run_phase前的一些验证环境的配置。

      class mcdf_data_consistence_basic_virtual_sequence extends mcdf_base_virtual_sequence;
        `uvm_object_utils(mcdf_data_consistence_basic_virtual_sequence)
        function new (string name = "mcdf_data_consistence_basic_virtual_sequence");
          super.new(name);
        endfunction
        task do_reg();
          bit[31:0] wr_val, rd_val;
          // slv0 with len=8,  prio=0, en=1
          wr_val = (1<<3)+(0<<1)+1;
          `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR; data == wr_val;})
          `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR;})
          rd_val = read_reg_seq.data;
          void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
    
          // slv1 with len=16, prio=1, en=1
          wr_val = (2<<3)+(1<<1)+1;
          `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR; data == wr_val;})
          `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR;})
          rd_val = read_reg_seq.data;
          void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));
    
          // slv2 with len=32, prio=2, en=1
          wr_val = (3<<3)+(2<<1)+1;
          `uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR; data == wr_val;})
          `uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR;})
          rd_val = read_reg_seq.data;
          void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
    
          // send IDLE command
          `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr)
        endtask
        task do_formatter();
          `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;})
        endtask
        task do_data();
          fork
            `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; })
            `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;})
            `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;})
          join
          #10us; // wait until all data haven been transfered through MCDF
        endtask
      endclass: mcdf_data_consistence_basic_virtual_sequence
    
      class mcdf_data_consistence_basic_test extends mcdf_base_test;
    
        `uvm_component_utils(mcdf_data_consistence_basic_test)
    
        function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        task run_top_virtual_sequence();
          mcdf_data_consistence_basic_virtual_sequence top_seq = new();
          top_seq.start(env.virt_sqr);
        endtask
      endclass: mcdf_data_consistence_basic_test
    
    展开全文
  • UVM入门系列(四)----通过uvm_gen脚本快速搭建一般验证平台(下) 目录UVM入门系列(四)----通过uvm_gen脚本快速搭建一般验证平台(下)前言1、reference model2、scoreboard3、function coverage总结 前言 本篇...

    UVM入门系列(四)----通过uvm_gen脚本快速搭建一般验证平台(下)


    前言

    本篇博文继续之前博文的内容对验证平台进行补全,之前博文内容链接:
    UVM入门系列(一)----通过uvm_gen脚本快速搭建一般验证平台(上)
    UVM入门系列(三)----通过uvm_gen脚本快速搭建一般验证平台(中)


    1、reference model

    声明transaction,i_seq_item接受自i_monitor,o_seq_item发送至scoreboard进行比较。

      i_seq_item req;
      o_seq_item m_trans;
    

    声明port,analysis_port用于向scoreboard发送o_seq_item,blocking_get_port用于从i_monitor接受i_seq_item。

      uvm_blocking_get_port#(i_seq_item) get_port;
      uvm_analysis_port#(o_seq_item) analysis_port;
    
    function add_refm::new(string name, uvm_component parent);
      super.new(name, parent);
      get_port=new("get_port",this);
      analysis_port=new("analysis_port",this);
      req=i_seq_item::type_id::create("req",this);
    endfunction : new
    

    main_phase:reference model从fifo中取出数据,进行计算处理后,通过analysis_port的write函数发送给scoreboard。

    fork    
        forever begin
            m_trans=o_seq_item::type_id::create("m_trans",this);
            get_port.get(req);
            do_ref(req);
            analysis_port.write(m_trans);
            `uvm_info("REFM",m_trans.sprint,UVM_MEDIUM)
        end
    join_none
    
    task add_refm::do_ref(i_seq_item req);
        bit [8:0] tmp;
        tmp=req.a+req.b+req.cin;
        m_trans.sum=tmp[7:0];
        m_trans.cout=tmp[8];
    endtask
    

    2、scoreboard

    声明transaction,req是来自o_monitor监测的DUT的输出,ref_req是来自reference model的标准输出;

      o_seq_item req;
      o_seq_item ref_req;
    

    声明port

      uvm_blocking_get_port#(o_seq_item) get_o_port;
      uvm_blocking_get_port#(o_seq_item) get_ref_port;
    
    
    function add_scb::new(string name, uvm_component parent);
      super.new(name, parent);
      get_o_port=new("get_o_port",this);
      get_ref_port=new("get_ref_port",this);
      req=o_seq_item::type_id::create("req",this);
      ref_req=o_seq_item::type_id::create("ref_req",this);
    endfunction : new
    
    

    main_phase:分别接收从来自i_monitor的DUT输出和来自reference model的标准输出,进行对比,对比失败则产生uvm_error

    fork 
        forever begin
            get_o_port.get(req);
            get_ref_port.get(ref_req);
            do_scb(req,ref_req);
        end 
    join_none
    task add_scb::do_scb(o_seq_item req0,o_seq_item req1);
        bit right;
        right=req0.compare(req1);
        if(!right)
            `uvm_error("FAILED","COMPARED FAILED")
        else
            `uvm_info("SUCCESS","COMPARED SUCCESS",UVM_LOW)
    endtask    
    

    3、function coverage

    由于DUT功能很简单,功能覆盖率只进行输入接口的采样。
    声明接口

     virtual interface i_agent_if vif;
     virtual interface cr_if cvif;
    

    定义覆盖组

    covergroup input_cov;
            coverpoint vif.cin;
            coverpoint vif.a;
            coverpoint vif.b;
    endgroup
    

    run_phase:进行信号采样

    task add_coverage::run_phase(uvm_phase phase);
            do_sample();
    endtask
    task add_coverage::do_sample();
        forever begin
            @(posedge cvif.sysclock);
            input_cov.sample();
        end
    endtask 
    

    report_phase:打印覆盖率信息。

    function void add_coverage::report_phase(uvm_phase phase);
        string s;
        super.report_phase(phase);
    
        s="\n--------------------------------------------------\n";
        s={s,"COVERAGE SUMMARY \n"};
        s={s,$sformatf("total coverage:%1.f \n",$get_coverage())};
        s={s,$sformatf("input coverage:%1.f \n",this.input_cov.get_coverage())};
        s={s,"\n-------------------------------------------------\n"};
        `uvm_info(get_type_name(),s,UVM_LOW)
    endfunction
    
    

    4、 env

    连接reference和scoreboard之间的数据通道:

      uvm_tlm_analysis_fifo#(o_seq_item) ref_scb_fifo;
      m_refm.analysis_port.connect(ref_scb_fifo.analysis_export);
      m_scb.get_ref_port.connect(ref_scb_fifo.blocking_get_export);
    
    

    例化coverage:

    add_coverage        m_cov; 
    m_cov  = add_coverage::type_id::create("m_cov",this); 
    

    5、仿真结果:

    总结

    至此,本次验证平台的搭建已经基本结束,新手入门,欢迎大佬指正。

    展开全文
  • UVM入门实验0

    2021-02-21 23:07:00
    一、编译UVM代码 编译文件uvm_compile.sv,等待正常编译结束,在work库中仿真模块uvm_compile,在命令窗口执行run -all。 uvm_compile.sv代码 module uvm_compile; import uvm_pkg::*; `include "uvm_macros.svh" ...

    一、编译UVM代码

    编译文件uvm_compile.sv,等待正常编译结束,在work库中仿真模块uvm_compile,在命令窗口执行run -all

    uvm_compile.sv代码

    module uvm_compile;
      import uvm_pkg::*;
      `include "uvm_macros.svh"
    
      initial begin
        `uvm_info("UVM", "Hello, welcome to RKV UVM training!", UVM_LOW)
        #1us;
        `uvm_info("UVM", "Bye, and more gifts waiting for you!", UVM_LOW)
      end
    endmodule
    

    UVM验证顶层都必须有import uvm_pkg::*'include "uvm_macros.svh"这两行代码代表着预编译的UVM库。

    仿真结果:
    在这里插入图片描述

    二、SV与UVM之间的关系

    通过编译仿真sv_class_inst.sv文件,实际上是SV模块实验环节的抽象,它只是在顶层module容器中要例化软件验证环境的顶层,即SV class top。从打印出的信息可以看出,相当于测试的开始,到验证环境的搭建,激励的发送,检查的执行等,最后又到了测试的结束。

    sv_class_inst.sv代码

    module sv_class_inst;
    
      import uvm_pkg::*;
      `include "uvm_macros.svh"
    
      class top;
        function new();
          `uvm_info("SV_TOP", "SV TOP creating", UVM_LOW)
        endfunction
      endclass
    
      initial begin
        top t; 
        `uvm_info("SV_TOP", "test started", UVM_LOW)
        t = new();
        `uvm_info("SV_TOP", "test finished", UVM_LOW)
      end
    
    endmodule
    

    仿真结果:
    在这里插入图片描述
    而编译仿真uvm_class_inst.sv,从打印的信息来看,也是在模拟验证结构的创立,只不过利用了UVM类uvm_component来定义了top类,继而在创建了这个“顶层”验证结构

    uvm_class_inst.sv代码

    module uvm_class_inst;
    
      import uvm_pkg::*;
      `include "uvm_macros.svh"
    
      class top extends uvm_component;
        `uvm_component_utils(top)
        function new(string name = "top", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("UVM_TOP", "SV TOP creating", UVM_LOW)
        endfunction
      endclass
    
    
      initial begin
        top t; 
        `uvm_info("UVM_TOP", "test started", UVM_LOW)
        t = new("t", null);
        `uvm_info("UVM_TOP", "test finished", UVM_LOW)
      end
    
    endmodule
    

    仿真结果:
    在这里插入图片描述
    所谓的UVM验证环境指的首先是提供一个UVM的“容器”,即接下来所有的UVM对象都会放置在其中,这样也可以成为UVM的顶层,这就类似于之前SV模块实验中的顶层容器test一样。

    三、UVM验证顶层与SV验证顶层的对比

    编译仿真uvm_test_inst.sv文件,从打印信息看出UVM验证结构的构建经历了9个phase。

    uvm_test_inst.sv代码

    package test_pkg;
      import uvm_pkg::*;
      `include "uvm_macros.svh"
    
      class top extends uvm_test;
        `uvm_component_utils(top)
        function new(string name = "top", uvm_component parent = null);
          super.new(name, parent);
          `uvm_info("UVM_TOP", "SV TOP creating", UVM_LOW)
        endfunction
        task run_phase(uvm_phase phase);
          phase.raise_objection(this);
          `uvm_info("UVM_TOP", "test is running", UVM_LOW)
          phase.drop_objection(this);
        endtask
      endclass
    
    endpackage
    
    module uvm_test_inst;
    
      import uvm_pkg::*;
      `include "uvm_macros.svh"
      import test_pkg::*;
    
    
      initial begin
        `uvm_info("UVM_TOP", "test started", UVM_LOW)
        run_test("top");
        `uvm_info("UVM_TOP", "test finished", UVM_LOW)
      end
    
    endmodule
    

    仿真结果:
    在这里插入图片描述

    四、启动UVM验证的必要步骤

    只有继承于uvm_test的类,才可以作为UVM验证环境的顶层,创建顶层验证环境,有且只能依赖于run_test(“UVM_TEST_NAME”)来传递,或者通过仿真参数传递,而不是通过构建函数new(),尽管new()可以创建一个对象,但是不能做与顶层验证环境相关的其他工作。

    搭建验证框架 -> 验证组件之间的连接和通信 -> 编写测试用例,继而完成复用和覆盖率收敛

    展开全文
  • UVM入门实验2

    2021-02-26 17:33:27
    首先将各个package中的SV组件替换为UVM组件 实现组件对应原则 SV的transaction类对应uvm_sequence_item SV的driver类对应uvm_driver SV的generator类对应uvm_sequence + uvm_sequencer SV的monitor对应uvm_monitor ...
  • UVM入门实验5

    2021-03-08 08:56:59
    定义uvm_reg和uvm_reg_block的以及mcdf_rgm寄存器模块。 // Dedicated register description [write-read reg] with uvm_reg type class ctrl_reg extends uvm_reg; `uvm_object_utils(ctrl_reg) uvm_reg_field ...
  • UVM入门系列(一)----通过uvm_gen脚本快速搭建一般验证平台(上) 目录UVM入门系列(一)----通过uvm_gen脚本快速搭建一般验证平台(上)前言一、reference model二、scoreboard总结 前言 本篇博文继续之前博文的...
  • UVM入门系列----通过uvm_gen脚本快速搭建一般验证平台(一) 索引UVM入门系列----通过uvm_gen脚本快速搭建一般验证平台(一)序一、uvm_gen脚本二、代码的补全1.interface1.1.i_agent_if.sv(verf/tb/agent/i)1.2.o...
  • UVM入门实验1

    2021-02-22 11:32:47
    `uvm_component_utils(T) `uvm_object_utils(T) 编译仿真factory_mechanism.sv文件 object_create类 class object_create extends top; trans t1, t2, t3, t4; `uvm_component_utils(object_create) function ...
  • UVM入门系列(二)----VCS仿真脚本的使用 本篇博文的内容对上一博文的内容进行初步仿真。 文章目录UVM入门系列(二)----VCS仿真脚本的使用前言一、rtllist.f?二、vcs编译三、仿真四、查看波形总结 前言 本篇博文...
  • UVM入门实验3

    2021-02-28 19:00:30
    一、TLM单向通信和多向通信 在之前的monitor到checker的通信,以及...将monitor中的用来与checker中的mailbox通信的mon_mb句柄替换为对应的uvm_blocking_put_port类型。 uvm_blocking_put_port #(mon_data_t) mon_bp_p
  • INTRO本节内容主要来自《UVM实战》的第三章的前半部分,详细介绍了一些UVM中的基础知识点,如UVM类继承关系,UVM的树型结构和field automation机制。UVM类继承关系在前一篇文章的简单的UVM框架Testbench中,我们曾...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 209
精华内容 83
关键字:

uvm入门