1. 程式人生 > 其它 >UVM實用技巧【一】

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