• UVM实用技巧【一】



    今天介绍几个UVM中较为实用的函数,在能够辅助大家调试环境。

    打印环境拓扑结构

    有时候,我们可能由于某些原因,组件可能层次安排不对,或者组件没有create,但是自己却没有注意到。或者我们想要看看环境的整体结构,那么就能用方法uvm_top.print_topology()打印整个拓扑结构。

    它的函数原型是

    function void print_topology (
       	uvm_printer 	printer	 = 	null
    )
    

    UVM对他的解释是

    Print the verification environment’s component topology. The printer is a uvm_printer object that controls the format of the topology printout; a null printer prints with the default output.

    这个方法属于uvm_root类,我们在调用时,直接实用uvm_top这个句柄即可,这个句柄类型就是uvm_root,并且全局可见。例如,通过如下代码,就能在run_phase阶段打印

      task run_phase(uvm_phase phase);
        super.run_phase(phase);
        uvm_top.print_topology();
      endtask : run_phase
    

    打印信息如下

     ------------------------------------------------------------
     Name                     Type                    Size  Value
     ------------------------------------------------------------
     uvm_test_top             my_test                 -     @466 
       m_env                  my_env                  -     @473 
         m_driver             my_driver               -     @484 
           rsp_port           uvm_analysis_port       -     @499 
           seq_item_port      uvm_seq_item_pull_port  -     @491 
         m_sequencer          my_sequencer            -     @507 
           rsp_export         uvm_analysis_export     -     @514 
           seq_item_export    uvm_seq_item_pull_imp   -     @608 
           arbitration_queue  array                   0     -    
           lock_queue         array                   0     -    
           num_last_reqs      integral                32    'd1  
           num_last_rsps      integral                32    'd1  
     ------------------------------------------------------------
    

    能过够很清晰的看到各个组件,以及接口,甚至ID。

    方法默认的参数是uvm_printer printer = null有兴趣的读者可以自行了解UVM打打印机制

    统计config情况

    config为验证环境中的数据传递提供了很方便的方法,通常用来传递一些静态配置,还有virtual interface。也可以用来启动sequence。但是有时,错误的实用方式,例如路径不对,会导致数据传输失败,因此,UVM提供了一个方法用于统计config的set和get情况。

    函数原型为

    function void check_config_usage (
       	bit 	recurse	 = 	1
    )
    

    UVM的注释为

    Check all configuration settings in a components configuration table to determine if the setting has been used, overridden or not used. When recurse is 1 (default), configuration for this and all child components are recursively checked. This function is automatically called in the check phase, but can be manually called at any time.

    例如,在test中

      function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        m_env=my_env::type_id::create("m_env",this);
        uvm_config_db#(uvm_object_wrapper)::set(this, "m_env.m_sequencer.main_phase", "default_sequence",my_sequence::type_id::get());
      endfunction : build_phase
    
      task run_phase(uvm_phase phase);
        super.run_phase(phase);
        check_config_usage();
      endtask : run_phase
    

    打印信息为

     UVM_INFO @ 0: uvm_test_top [CFGNRD]  ::: The following resources have at least one write and no reads :::
     default_sequence [/^uvm_test_top.m_env.m_sequencer.main_phase$/] : (class uvm_pkg::uvm_object_wrapper) {my_sequence} @uvm_object_registry__36@1
     -  
       --------
       uvm_test_top reads: 0 @ 0  writes: 1 @ 0
    

    这个时候default_sequence还没有启动,所以写了一次,还没被读,如果加上了延时,或者在run_phase之后调用,那么就不会产生任何信息。

    检查configdb的配置

    有时候,一不小心写错config的路径,就会导致失败,但是自己又眼睛不好使,看不出自己那些错了,反复检查,层次并没有问题,但是就是并没有错。UVM提供了一个函数,用于查询config db的是否存在某个数据。

    函数原型为

    static function bit exists(
       	uvm_component 	cntxt,	  
       	string 	inst_name,	  
       	string 	field_name,	  
       	bit 	spell_chk	 = 
    )
    

    这是config_db的一个静态函数,在调用时和set是一样的。UVM对此的注释是

    Check if a value for field_name is available in inst_name, using component cntxt as the starting search point. inst_name is an explicit instance name relative to cntxt and may be an empty string if the cntxt is the instance that the configuration object applies to. field_name is the specific field in the scope that is being searched for. The spell_chk arg can be set to 1 to turn spell checking on if it is expected that the field should exist in the database. The function returns 1 if a config parameter exists and 0 if it doesn’t exist.

    最后一个参数为1时会进行拼写检查,帮你匹配相近的路径。如果存在便会返回1,否则,0

    例如,我们在test中使用default_sequence启动,但是发现无论如何都没有效果,那么我们可以在sequencer中用如下方式检查

      class my_sequencer extends uvm_sequencer #(my_item);
        `uvm_component_utils(my_sequencer)
        function new (string name = "my_sequencer", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        task main_phase(uvm_phase phase);
          super.main_phase(phase);
          uvm_config_db#(uvm_object_wrapper)::exists(this,"","default_sequence",1);
        endtask
    
      endclass: my_sequencer
    
    class my_test extends uvm_test;
      my_env m_env;
    
      `uvm_component_utils(my_test)
    
      function new(string name = "my_test", uvm_component parent=null);
        super.new(name, parent);
      endfunction : new
    
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        m_env=my_env::type_id::create("m_env",this);
        uvm_config_db#(uvm_object_wrapper)::set(this, "m_env.m_sequencer.main_phase", "default_sequnce",my_sequence::type_id::get());
      endfunction : build_phase
    
    endclass : my_test
    

    你发现哪里有问题了吗,上面的例子运行的结果是

     default_sequence not located
       did you mean default_sequnce?
    

    你会收获来自UVM的无情嘲讽,是的,没错,少打了一个e

    完整代码

    package lab_pkg;
      import uvm_pkg::*;
      `include "uvm_macros.svh"
    class my_item extends uvm_sequence_item;
    
      `uvm_object_utils(my_item)
    
      function new (string name = "my_item");
        super.new(name);
      endfunction
    endclass
    
    class my_driver extends  uvm_driver#(my_item);
    
      `uvm_component_utils(my_driver)
    
      // Constructor
      function new(string name = "my_driver", uvm_component parent=null);
        super.new(name, parent);
      endfunction : new
    
      task run_phase(uvm_phase phase);
        my_item req,rsp;
        super.run_phase(phase);
        uvm_top.print_topology();
        check_config_usage();
        forever begin
          seq_item_port.get_next_item(req);
          #100;
          `uvm_info(get_type_name,"get a item",UVM_LOW)
          void'($cast(rsp, req.clone()));
          rsp.set_sequence_id(req.get_sequence_id());
          seq_item_port.item_done(rsp);
        end
      endtask : run_phase
    
    endclass : my_driver
    
      class my_sequencer extends uvm_sequencer #(my_item);
        `uvm_component_utils(my_sequencer)
        function new (string name = "my_sequencer", uvm_component parent);
          super.new(name, parent);
        endfunction
    
        task main_phase(uvm_phase phase);
          super.main_phase(phase);
          uvm_config_db#(uvm_object_wrapper)::exists(this,"","default_sequence",1);
        endtask
    
      endclass: my_sequencer
    
      class my_sequence extends uvm_sequence #(my_item);
    
    
        `uvm_object_utils(my_sequence)
    
        function new (string name = "my_sequence");
          super.new(name);
        endfunction
    
        task body();
          if(starting_phase!=null)
            starting_phase.raise_objection(this);
          send_trans();
          if (starting_phase!=null) begin
            starting_phase.drop_objection(this);
          end
        endtask
    
        task send_trans();
          my_item req, rsp;
          `uvm_do(req)
          `uvm_info(get_type_name(), req.sprint(), UVM_HIGH)
          get_response(rsp);
          `uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH)
        endtask
      endclass: my_sequence
    
    class my_env extends uvm_env;
    
      my_driver m_driver;
      my_sequencer m_sequencer;
    
      `uvm_component_utils(my_env)
    
      function new(string name = "my_env", uvm_component parent=null);
        super.new(name, parent);
      endfunction : new
    
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        m_driver=my_driver::type_id::create("m_driver",this);
        m_sequencer=my_sequencer::type_id::create("m_sequencer",this);
      endfunction : build_phase
    
      function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        m_driver.seq_item_port.connect(m_sequencer.seq_item_export);
      endfunction : connect_phase
    
    endclass : my_env
    
    class my_test extends uvm_test;
      my_env m_env;
    
      `uvm_component_utils(my_test)
    
      // Constructor
      function new(string name = "my_test", uvm_component parent=null);
        super.new(name, parent);
      endfunction : new
    
      function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        m_env=my_env::type_id::create("m_env",this);
        uvm_config_db#(uvm_object_wrapper)::set(this, "m_env.m_sequencer.main_phase", "default_sequnce",my_sequence::type_id::get());
      endfunction : build_phase
    
      task run_phase(uvm_phase phase);
        super.run_phase(phase);
      endtask : run_phase
    
    endclass : my_test
    endpackage : lab_pkg
    

    tb代码为

    module tb ();
    
      import uvm_pkg::*;
      import lab_pkg::*;
      `include "uvm_macros.svh"
    
    initial begin
      run_test("my_test");
    end
    
    endmodule : tb
    
  • 相关阅读:
    Java基础-3y
    对线面试官面试系列-3y
    从零单排学Redis【青铜】
    mock官方文档
    route路由组件传递参数
    axios拦截器与vue代理设置
    Sass使用方法
    Less使用方法
    Vue-cli
    Vue-组件注册
  • 原文地址:https://www.cnblogs.com/icparadigm/p/15087266.html
Copyright © 2020-2023  润新知