RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

UVM中通過(guò)靜態(tài)類實(shí)現(xiàn)對(duì)全局資源實(shí)現(xiàn)管理

ruikundianzi ? 來(lái)源:IC Verification Club ? 2023-08-07 17:35 ? 次閱讀

Static class

Systemverilog中可以使用static修飾變量,方法,得到靜態(tài)變量和靜態(tài)函數(shù)。static也可以直接修飾class,獲得靜態(tài)類。但是static class class_name .... endclass這種直接定義一個(gè)靜態(tài)類的方式是不允許的,只可以在一個(gè)class的內(nèi)部,通過(guò)static class_name的方式聲明一個(gè)靜態(tài)類。這一點(diǎn)SV與Jave相同。(Java中的 static class[2])

靜態(tài)類的特征:

1.相比automatic class, 靜態(tài)類被new創(chuàng)建后,其對(duì)應(yīng)的內(nèi)存空間一直存在,伴隨仿真結(jié)束。配合單例模式使用,則是全局唯一類的實(shí)例,可以被當(dāng)作全局變量使用。2.相比靜態(tài)變量,靜態(tài)類可以封裝更多內(nèi)容,充當(dāng)資源容器的角色。

所以UVM中對(duì)全局的資源管理,都是通過(guò)靜態(tài)類實(shí)現(xiàn)的。

uvm_pool

uvm_pool#(type KEY=int, T=uvm_void)是一個(gè)參數(shù)化的類,相當(dāng)于SV中的聯(lián)合數(shù)組。參數(shù)KEY是聯(lián)合數(shù)組的索引,參數(shù)T是聯(lián)合數(shù)組存儲(chǔ)的變量類型。uvm_pool封裝了原有聯(lián)合數(shù)組的操作方法,供訪問(wèn)內(nèi)部的聯(lián)合數(shù)組pool。m_global_pool是uvm_pool #(KEY, T)類型的靜態(tài)類,通過(guò)靜態(tài)方法get_global_pool可以獲得唯一的實(shí)例。uvm_queue #(T)和uvm_pool#(type KEY=int, T=uvm_void)類似,實(shí)現(xiàn)一個(gè)class-based dynamic queue.

# uvm_pool.svh

class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object;

  const static string type_name = "uvm_pool";

  typedef uvm_pool #(KEY,T) this_type;

  static protected this_type m_global_pool;
  protected T pool[KEY];

  // Function: new
  // Creates a new pool with the given ~name~.
  function new (string name="");
    super.new(name);
  endfunction
  // Function: get_global_pool
  // Returns the singleton global pool for the item type, T. 
  // This allows items to be shared amongst components throughout the
  // verification environment.
  static function this_type get_global_pool ();
    if (m_global_pool==null)
      m_global_pool = new("pool");
    return m_global_pool;
  endfunction

  // Function: get_global
  // Returns the specified item instance from the global item pool. 
  static function T get_global (KEY key);
    this_type gpool;
    gpool = get_global_pool(); 
    return gpool.get(key);
  endfunction
  // Function: get
  // Returns the item with the given ~key~.
  // If no item exists by that key, a new item is created with that key
  // and returned.
  virtual function T get (KEY key);
    if (!pool.exists(key)) begin
      T default_value;
      pool[key] = default_value;
    end
    return pool[key];
  endfunction

  virtual function void add (KEY key, T item);
    pool[key] = item;
  endfunction

  virtual function int num ();
    return pool.num();
  endfunction

......
...... 
......
endclass

uvm_event_pool

uvm_object_string_pool的KEY是string類型。uvm_event_pool由uvm_object_string_pool #(uvm_event)聲明,KEY是string類型,T是uvm_event類型。uvm_event是sv中event的class warpper,內(nèi)建了很多方法。

# uvm_pool.svh

class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T);
......
typedef class uvm_barrier;
typedef class uvm_event;

typedef uvm_object_string_pool #(uvm_barrier) uvm_barrier_pool;
typedef uvm_object_string_pool #(uvm_event) uvm_event_pool;
# uvm_event.svh

//------------------------------------------------------------------------------
// CLASS: uvm_event
// The uvm_event class is a wrapper class around the SystemVerilog event
// construct.  It provides some additional services such as setting callbacks
// and maintaining the number of waiters.
//------------------------------------------------------------------------------
class uvm_event extends uvm_object;

  const static string type_name = "uvm_event";

  local event      m_event;
  local int        num_waiters;
  local bit        on;
  local time       trigger_time=0;
  local uvm_object trigger_data;
  local uvm_event_callback  callbacks[$];

  function new (string name="");
    super.new(name);
  endfunction  
......
......
......
  virtual task wait_on (bit delta=0);
  virtual task wait_off (bit delta=0);
  virtual task wait_trigger ();
  virtual task wait_ptrigger ();
  virtual task wait_trigger_data (output uvm_object data);
  virtual task wait_ptrigger_data (output uvm_object data);
  virtual function void trigger (uvm_object data=null);
  virtual function uvm_object get_trigger_data ();
  virtual function time get_trigger_time ();
  virtual function void add_callback (uvm_event_callback cb, bit append=1);
  virtual function int get_num_waiters ();
......
endclass : uvm_event

使用

uvm_event_pool作為全局唯一的uvm_evnet的資源池,可以在不同component中調(diào)用,實(shí)現(xiàn)事件的同步功能。比如sequence和scoreboard需要通過(guò)event來(lái)握手:

# event_sequence.sv
class event_sequence extends uvm_sequence;
    ......
    uvm_event_pool events_pool;
    uvm_event sync_e;
    ......
    function new (string name = "event_sequence");
        events_pool = uvm_event_pool::get_global_pool();
        sync_e = events_pool.get("sync_e");
        // 也可以直接調(diào)用 sync_e = uvm_event_pool::get_global("sync_e");
    endfunction
    ......
    virtual task body();
    ......
        sync_e.trigger();
    ......
    endtask
endclass

# event_scb.sv
class event_scb extends uvm_scoreboard;
    ......
    uvm_event_pool events_pool;
    uvm_event sync_e;
    ......
    function new (string name = "event_sequence");
        events_pool = uvm_event_pool::get_global_pool();
        sync_e = events_pool.get("sync_e");
    endfunction
    ......
    virtual task wait_sync_e();
    ......
        sync_e.wait_trigger();
    ......
    endtask
endclass

無(wú)論是uvm_component還是uvm_object,是否在同一個(gè)package中,都可以通過(guò)uvm_evnet_pool::get_global_pool()獲得全局唯一的uvm_event資源池。上述的uvm_event并不需要new(),因?yàn)檎{(diào)用get()函數(shù)時(shí)會(huì)自動(dòng)創(chuàng)建:

# uvm_object_string_pool #(uvm_event)

  // Function: get
  // Returns the object item at the given string ~key~.
  // If no item exists by the given ~key~, a new item is created for that key
  // and returned.
  virtual function T get (string key);
    if (!pool.exists(key))
      pool[key] = new (key);
    return pool[key];
  endfunction

uvm_event不僅可以用于event同步,也可以傳遞一些簡(jiǎn)單的數(shù)據(jù)。提供了兩個(gè)方法:wait_trigger_data (output uvm_object data)trigger (uvm_object data),可以傳遞uvm_object類型的數(shù)據(jù)。也可以add_callback加入回調(diào)函數(shù)。uvm_event[3]uvm中還提供了uvm_barrier用于多個(gè)組件之間的同步,uvm_barrier_pool存放所有的uvm_barrier。

uvm_config_db

結(jié)構(gòu)

uvm_resource#(type T): 各類資源(*scalar objectsclass handlesqueueslistsvirtual interfaces等*)的一個(gè)wrapper,內(nèi)部成員變量val是一個(gè)type T類型的句柄,通過(guò)調(diào)用write函數(shù),將val指向資源的實(shí)例( *!!! 對(duì)于class handlesvirtual interfaces,val看作句柄指向?qū)嵗?;?duì)于queueslists等,val是被直接賦值 !!!*)。set函數(shù)將uvm_resource加入全局資源池uvm_resources。

class uvm_resource #(type T=int) extends uvm_resource_base;
  typedef uvm_resource#(T) this_type;
  // singleton handle that represents the type of this resource
  static this_type my_type = get_type();
  // Can't be rand since things like rand strings are not legal.
  protected T val;
  ......
  // Function: get_type
  // Static function that returns the static type handle.  The return
  // type is this_type, which is the type of the parameterized class.
  static function this_type get_type();
    if(my_type == null)
      my_type = new();
    return my_type;
  endfunction
  ......
  // Function: set
  // Simply put this resource into the global resource pool
  function void set();
    uvm_resource_pool rp = uvm_resource_pool::get();
    rp.set(this);
  endfunction
  ......
  // Function: write
  // Modify the object stored in this resource container.  If the
  // resource is read-only then issue an error message and return
  // without modifying the object in the container.  If the resource is
  // not read-only and an ~accessor~ object has been supplied then also
  // update the accessor record.  Lastly, replace the object value in
  // the container with the value supplied as the argument, ~t~, and
  // release any processes blocked on
  // .  If the value to be written is
  // the same as the value already present in the resource then the
  // write is not done.  That also means that the accessor record is not
  // updated and the modified bit is not set.
  function void write(T t, uvm_object accessor = null);
    if(is_read_only()) begin
      uvm_report_error("resource", $sformatf("resource %s is read only -- cannot modify", get_name()));
      return;
    end
    // Set the modified bit and record the transaction only if the value
    // has actually changed.
    if(val == t)
      return;
    record_write_access(accessor);
    // set the value and set the dirty bit
    val = t;
    modified = 1;
  endfunction
  ......

uvm_resource_pool: 存放所有的uvm_resource, 全局唯一的實(shí)例uvm_resources。uvm_resource_pool::get()得到uvm_resources。(注意:這里的new函數(shù)使用了local修飾,而uvm_event_pool中的new沒(méi)有被local修飾。所以u(píng)vm_resource_pool和uvm_root擁有真正的全局唯一實(shí)例,而uvm_event_pool可以在外部手動(dòng)new創(chuàng)建多個(gè)實(shí)例。

rtab[string]ttab[uvm_resource_base]分別以nametype為索引存放uvm_resource。

//----------------------------------------------------------------------
// Class: uvm_resource_pool
//
// The global (singleton) resource database.
//
// Each resource is stored both by primary name and by type handle.  The
// resource pool contains two associative arrays, one with name as the
// key and one with the type handle as the key.  Each associative array
// contains a queue of resources.  Each resource has a regular
// expression that represents the set of scopes over with it is visible.
//
//|  +------+------------+                          +------------+------+
//|  | name | rsrc queue |                          | rsrc queue | type |
//|  +------+------------+                          +------------+------+
//|  |      |            |                          |            |      |
//|  +------+------------+                  +-+-+   +------------+------+
//|  |      |            |                  | | |<--+---*        |  T   |
//|  +------+------------+   +-+-+          +-+-+   +------------+------+
//|  |  A   |        *---+-->| | |           |      |            |      |
//|  +------+------------+   +-+-+           |      +------------+------+
//|  |      |            |      |            |      |            |      |
//|  +------+------------+      +-------+  +-+      +------------+------+
//|  |      |            |              |  |        |            |      |
//|  +------+------------+              |  |        +------------+------+
//|  |      |            |              V  V        |            |      |
//|  +------+------------+            +------+      +------------+------+
//|  |      |            |            | rsrc |      |            |      |
//|  +------+------------+            +------+      +------------+------+
//
// The above diagrams illustrates how a resource whose name is A and
// type is T is stored in the pool.  The pool contains an entry in the
// type map for type T and an entry in the name map for name A.  The
// queues in each of the arrays each contain an entry for the resource A
// whose type is T.  The name map can contain in its queue other
// resources whose name is A which may or may not have the same type as
// our resource A.  Similarly, the type map can contain in its queue
// other resources whose type is T and whose name may or may not be A.
//
// Resources are added to the pool by calling ; they are retrieved
// from the pool by calling  or .  When an object 
// creates a new resource and calls  the resource is made available to be
// retrieved by other objects outside of itsef; an object gets a
// resource when it wants to access a resource not currently available
// in its scope.
//----------------------------------------------------------------------
// static global resource pool handle
//----------------------------------------------------------------------
const uvm_resource_pool uvm_resources = uvm_resource_pool::get();

class uvm_resource_pool;

  static bit m_has_wildcard_names;
  static local uvm_resource_pool rp = get();

  uvm_resource_types::rsrc_q_t rtab [string];
  uvm_resource_types::rsrc_q_t ttab [uvm_resource_base];
 ......
  local function new();
  endfunction
  // Function: get
  //
  // Returns the singleton handle to the resource pool
  static function uvm_resource_pool get();
    if(rp == null)
      rp = new();
    return rp;
  endfunction
  ......
  // Function: get_by_name
  //
  // Lookup a resource by ~name~, ~scope~, and ~type_handle~.  Whether
  // the get succeeds or fails, save a record of the get attempt.  The
  // ~rpterr~ flag indicates whether to report errors or not.
  // Essentially, it serves as a verbose flag.  If set then the spell
  // checker will be invoked and warnings about multiple resources will
  // be produced.

  function uvm_resource_base get_by_name(string scope = "",
                                         string name,
                                         uvm_resource_base type_handle,
                                         bit rpterr = 1);

  // Function: get_by_type
  //
  // Lookup a resource by ~type_handle~ and ~scope~.  Insert a record into
  // the get history list whether or not the get succeeded.

  function uvm_resource_base get_by_type(string scope = "",
                                         uvm_resource_base type_handle);
  ......
......
endclass

uvm_resource_db#(type T):訪問(wèn)資源池的接口,內(nèi)部都是static function。

uvm_config_db#(type T):繼承于uvm_resource_db#(type T),進(jìn)行了一些功能擴(kuò)展。內(nèi)部都是static function。

接下來(lái)重點(diǎn)看一下uvm_config_db傳入的4個(gè)參數(shù):

cntxt:uvm_component類型,context上下文的含義,由cntxt可以確定資源的優(yōu)先級(jí),對(duì)同一個(gè)資源set,從UVM樹(shù)頂層往下,優(yōu)先級(jí)依次降低。cntxt = null時(shí),為uvm_root::get(),優(yōu)先級(jí)最高。

inst_name:string類型,通過(guò){cntxt.get_full_name(), ".", inst_name}組成的字符串設(shè)置資源的scope。內(nèi)部調(diào)用DPI,支持通配符。只有g(shù)et中的scope可以和set中的scope匹配上,才可以正常訪問(wèn)資源。

field_name: 資源名,scope內(nèi)的資源。也支持通配符,一般setget設(shè)置相同即可。

value:type T類型,資源的類型。get中的是inout,調(diào)用get函數(shù)先給value賦值,結(jié)束后再將val傳出,但是get中并沒(méi)有處理傳入value的代碼,不知道為什么這樣用。

class uvm_config_db#(type T=int) extends uvm_resource_db#(T);
......
  static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component];
......

   static function bit get(uvm_component cntxt,
                          string inst_name,
                          string field_name,
                          inout T value);
//TBD: add file/line
    int unsigned p;
    uvm_resource#(T) r, rt;
    uvm_resource_pool rp = uvm_resource_pool::get();
    uvm_resource_types::rsrc_q_t rq;

    if(cntxt == null) 
      cntxt = uvm_root::get();
    if(inst_name == "") 
      inst_name = cntxt.get_full_name();
    else if(cntxt.get_full_name() != "") 
      inst_name = {cntxt.get_full_name(), ".", inst_name};

   ......

    value = r.read(cntxt);

    return 1;
  endfunction

   static function void set(uvm_component cntxt,
                           string inst_name,
                           string field_name,
                           T value);

    uvm_root top;
    uvm_phase curr_phase;
    uvm_resource#(T) r;
    bit exists;
    string lookup;
    uvm_pool#(string,uvm_resource#(T)) pool;

    //take care of random stability during allocation
    process p = process::self();
    string rstate = p.get_randstate();
    top = uvm_root::get();
    curr_phase = top.m_current_phase;

    if(cntxt == null) 
      cntxt = top;
    if(inst_name == "") 
      inst_name = cntxt.get_full_name();
    else if(cntxt.get_full_name() != "") 
      inst_name = {cntxt.get_full_name(), ".", inst_name};

    ......
    r.write(value, cntxt);
    ......
  endfunction

有一種特殊的情況,就是cntxt = null, 而uvm_root::get().get_full_name()為空字符串。其他情況都是以u(píng)vm_test_top為開(kāi)頭設(shè)置scope。

Verdi也提供了GUI界面,可以看到setget的具體內(nèi)容,方便debug:

e06f881c-3504-11ee-9e74-dac502259ad0.png

使用

uvm_config_db機(jī)制本質(zhì)就是在一個(gè)地方創(chuàng)建資源,通過(guò)set以u(píng)vm_resource的形式存儲(chǔ)到uvm_resource_pool上。然后在另一個(gè)地方,通過(guò)get獲得之前創(chuàng)建的資源。

uvm_config_db機(jī)制還為資源加上了scope限制資源的訪問(wèn),保證數(shù)據(jù)安全;precedence設(shè)置優(yōu)先級(jí);override資源重寫;record記錄資源訪問(wèn)歷史用于debug等功能。

這里的資源可以是scalar objectsclass handlesqueueslistsvirtual interfaces等。

隊(duì)列,數(shù)組類型

對(duì)于隊(duì)列,數(shù)組的傳遞,int val_q[$]直接通過(guò)uvm_config_db#(int) :: set(this, "env.i_agt.drv","val_q",val_q);的方式會(huì)編譯報(bào)錯(cuò),因?yàn)閡vm_config_db#(type T=int)中type是int類型,而不是隊(duì)列類型。需要typedef int t_q[$] ;定義隊(duì)列類型。t_q val_q;uvm_config_db#(t_q) :: set(this, "env.i_agt.drv","val_q",val_q);

還有另一種方式,通過(guò)class封裝隊(duì)列(uvm已提供了uvm_queue#(type T)。這種方式的好處是,隊(duì)列在一端改變,另一段也可以看到隊(duì)列的修改,因?yàn)樽兞繉?duì)資源的訪問(wèn)是通過(guò)句柄的形式,指向同一處資源。而直接傳遞隊(duì)列,一端修改,另一端看不到,因?yàn)閮啥说年?duì)列是各自class scope中的兩份不同的數(shù)據(jù),只有再執(zhí)行一次setget操作才會(huì)獲得隊(duì)列的新內(nèi)容。

sequence中的資源訪問(wèn)

UVM中sequence不屬uvm_component,存在固定的生命周期,對(duì)資源的訪問(wèn),分為直接和間接兩種類型。以reg_model為例,reg_model在env中create, sequence通過(guò)reg_model訪問(wèn)寄存器

總結(jié)如下5種方式:

1.sequence沒(méi)有出現(xiàn)在樹(shù)形結(jié)構(gòu)中,難以確定路徑參數(shù),可以通過(guò)setnull, ""設(shè)定全局scope,這樣sequence在哪里都可以訪問(wèn)資源。注意:sequence沒(méi)有phase,get可以放在pre_bodybodypre_randomizepre_start中,只要在調(diào)用reg_model之前get被調(diào)用即可。

# env
top_reg_model m_regmodel;
m_regmodel = top_reg_model::create("m_regmodel");
uvm_config_db #(top_reg_model)::set(null, "","reg_model",m_regmodel);

# seq
top_reg_model m_regmodel;
uvm_config_db #(top_reg_model)::get(null, "","reg_model",m_regmodel);

// 為什么說(shuō) null, ""的組合是全局scope呢?
// TODO

1.sequence的路徑可以通過(guò)get_full_name()獲得。

# env
top_reg_model m_regmodel;
m_regmodel = top_reg_model::create("m_regmodel");
uvm_config_db #(top_reg_model)::set(this, " agt.sqr.* ","reg_model",m_regmodel);

# seq
top_reg_model m_regmodel;
uvm_config_db #(top_reg_model)::get(null, get_full_name(),"reg_model",m_regmodel);

1.sequence雖然不在樹(shù)形結(jié)構(gòu)上,但是其內(nèi)部成員變量m_sequencer在樹(shù)形結(jié)構(gòu)上,可以通過(guò)m_sequencer間接訪問(wèn)資源。

# env
top_reg_model m_regmodel;
m_regmodel = top_reg_model::create("m_regmodel");
uvm_config_db #(top_reg_model)::set(this, " agt.sqr","reg_model",m_regmodel);

# seq
top_reg_model m_regmodel;
uvm_config_db #(top_reg_model)::get(m_sequencer, "","reg_model",m_regmodel);

1.直接通過(guò)p_sequener訪問(wèn)資源。sequencer中g(shù)et獲得資源,sequence中調(diào)用p_sequencer.m_regmodel訪問(wèn)資源。2.直接賦值,在test中例化sequence時(shí),seq.m_regmodel = m_regmodel。也可以封裝到sequence中的function。

#seq
virtual function set_regmodel(top_reg_model m_regmodel);
    this.m_regmodel = m_regmodel;
endfunction

當(dāng)然也可以封裝到test中的function:

#test
virtual function set_regmodel(sequence_baes seq);
    seq.m_regmodel = m_regmodel;
endfunction

上述方法,本質(zhì)都是一樣的,將m_model句柄指向在env中創(chuàng)建的top_reg_model實(shí)例。

自定義資源池

我們也可以模仿uvm_event_pooluvm_resource_pool的方式,自定義一個(gè)資源池。

不使用uvm_config_db,自定義一個(gè)interface pool,示例如下(UVM實(shí)戰(zhàn) /ch10/section10.6/10.6.2):

# interface_pool

class if_object extends uvm_object;

   `uvm_object_utils(if_object)
   function new(string name = "if_object");
      super.new(name);
   endfunction

   static if_object me;

   static function if_object get();
      if(me == null) begin
         me = new("me");
      end
      return me;
   endfunction

   virtual my_if input_vif0;
   virtual my_if output_vif0;
   virtual my_if input_vif1;
   virtual my_if output_vif1;
endclass

# top_tb.sv 
module top_tb;
......
my_if input_if0(clk, rst_n);
my_if input_if1(clk, rst_n);
my_if output_if0(clk, rst_n);
my_if output_if1(clk, rst_n);

......
initial begin
   if_object if_obj; 
   if_obj = if_object::get();
   if_obj.input_vif0 = input_if0;
   if_obj.input_vif1 = input_if1;
   if_obj.output_vif0 = output_if0;
   if_obj.output_vif1 = output_if1;
end
endmodule

# base_test.sv
class base_test extends uvm_test;

   my_env         env0;
   my_env         env1;
   my_vsqr        v_sqr;   

   function new(string name = "base_test", uvm_component parent = null);
      super.new(name,parent);
   endfunction

   extern virtual function void build_phase(uvm_phase phase);
   extern virtual function void connect_phase(uvm_phase phase);
   extern virtual function void report_phase(uvm_phase phase);
   `uvm_component_utils(base_test)
endclass

......

function void base_test::connect_phase(uvm_phase phase);
   if_object if_obj; 
   if_obj = if_object::get();
   v_sqr.p_sqr0 = env0.i_agt.sqr;
   v_sqr.p_sqr1 = env1.i_agt.sqr;
   env0.i_agt.drv.vif = if_obj.input_vif0;
   env0.i_agt.mon.vif = if_obj.input_vif0;
   env0.o_agt.mon.vif = if_obj.output_vif0;
   env1.i_agt.drv.vif = if_obj.input_vif1;
   env1.i_agt.mon.vif = if_obj.input_vif1;
   env1.o_agt.mon.vif = if_obj.output_vif1;
endfunction

平臺(tái)中所有使用uvm_config_db的地方都可以通過(guò)這種方式替代,當(dāng)然并不建議這樣使用,uvm_config_db提供了更豐富的功能。這種方式的一個(gè)優(yōu)點(diǎn)是編寫錯(cuò)誤可以在編譯階段發(fā)現(xiàn),而uvm_config_db中字符串錯(cuò)誤不容易發(fā)現(xiàn)。

wait_modified

uvm_config_db不僅可以共享資源,也可以像uvm_event那樣,用于事件的同步,可以通過(guò)wait_modified實(shí)現(xiàn)。

drv0_seq在get之前,case0_vseq中必須先set,否則wait_modified會(huì)一直阻塞。因?yàn)閣ait_modified中調(diào)用@waiter.trigger,trigger是event類型;在set的最后,->w.trigger會(huì)觸發(fā)該event。平臺(tái)中所有的等待事件都放在了m_waiters[string]中,其中的索引sting對(duì)應(yīng)getset函數(shù)中第三個(gè)參數(shù)field_name。

class drv0_seq extends uvm_sequence #(my_transaction);
   ......
      virtual task body();
      bit send_en = 1;
      fork
         while(1) begin
            uvm_config_db#(bit)::wait_modified(null, get_full_name(), "send_en");
            void'(uvm_config_db#(bit)::get(null, get_full_name, "send_en", send_en)); 
            `uvm_info("drv0_seq", $sformatf("send_en value modified, the new value is %0d", send_en), UVM_LOW)
         end
      join_none
      repeat (10) begin
         `uvm_do(m_trans)
      end
   endtask
endclass

class case0_vseq extends uvm_sequence;
   ......
   virtual task body();
      my_transaction tr;
      drv0_seq seq0;
      drv1_seq seq1;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      fork
         `uvm_do_on(seq0, p_sequencer.p_sqr0);
         `uvm_do_on(seq1, p_sequencer.p_sqr1);
         begin
            #10000;
            uvm_config_db#(bit)::set(uvm_root::get(), "uvm_test_top.v_sqr.*", "send_en", 0);
            #10000;
            uvm_config_db#(bit)::set(uvm_root::get(), "uvm_test_top.v_sqr.*", "send_en", 1);
         end
      join 
      #100;
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask
endclass

class m_uvm_waiter;
  string inst_name;
  string field_name;
  event trigger;
  function new (string inst_name, string field_name);
    this.inst_name = inst_name;
    this.field_name = field_name;
  endfunction
endclass

class uvm_config_db#(type T=int) extends uvm_resource_db#(T);
......
  // Internal waiter list for wait_modified
  static local uvm_queue#(m_uvm_waiter) m_waiters[string];
......
  static task wait_modified(uvm_component cntxt, string inst_name,
      string field_name);
    process p = process::self();
    string rstate = p.get_randstate();
    m_uvm_waiter waiter;

    if(cntxt == null)
      cntxt = uvm_root::get();
    if(cntxt != uvm_root::get()) begin
      if(inst_name != "")
        inst_name = {cntxt.get_full_name(),".",inst_name};
      else
        inst_name = cntxt.get_full_name();
    end

    waiter = new(inst_name, field_name);

    if(!m_waiters.exists(field_name))
      m_waiters[field_name] = new;
    m_waiters[field_name].push_back(waiter);

    p.set_randstate(rstate);

    // wait on the waiter to trigger
    @waiter.trigger;

    // Remove the waiter from the waiter list 
    for(int i=0; iw.trigger;  
      end
    end

   ......
  endfunction

UVM_REGEX_NO_DPI

大量 ”濫用“uvm_config_db配置訪問(wèn)資源,會(huì)降低仿真速度。db:set/get()會(huì)自動(dòng)擴(kuò)展正則匹配,uvm_re_match()調(diào)用DPI的方式,增加仿真內(nèi)核切換時(shí)間,每一次get()需要遍歷set()的所有資源。而且不是簡(jiǎn)單的線性降低仿真速度??梢詢?yōu)化原有代碼,減少set/get調(diào)用;使用UVM_REGEX_NO_DPI禁用正則匹配,僅僅使用*?+這種簡(jiǎn)單的通配符。

e0ae822e-3504-11ee-9e74-dac502259ad0.png

如果在SoC級(jí)別的平臺(tái),發(fā)現(xiàn)build_phase占用太多時(shí)間,可以參考SNUG 2018 Auditing the UVM Resource Database[4]進(jìn)行優(yōu)化,對(duì)源碼進(jìn)行相應(yīng)修改,更好的Auditing平臺(tái)的資源配置。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 存儲(chǔ)器
    +關(guān)注

    關(guān)注

    38

    文章

    7484

    瀏覽量

    163761
  • UVM
    UVM
    +關(guān)注

    關(guān)注

    0

    文章

    182

    瀏覽量

    19167
  • GUI
    GUI
    +關(guān)注

    關(guān)注

    3

    文章

    659

    瀏覽量

    39654
  • DPI
    DPI
    +關(guān)注

    關(guān)注

    0

    文章

    36

    瀏覽量

    11509
  • 回調(diào)函數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    87

    瀏覽量

    11554

原文標(biāo)題:UVM設(shè)計(jì)模式:靜態(tài)類、資源管理、uvm_event、uvm_*_pool、uvm_config_db

文章出處:【微信號(hào):IP與SoC設(shè)計(jì),微信公眾號(hào):IP與SoC設(shè)計(jì)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    解鎖新姿勢(shì) | 如何用配置中心實(shí)現(xiàn)全局動(dòng)態(tài)流控?

    客戶端包依賴較少,不需要客戶端提供控制并發(fā)線程數(shù)的動(dòng)態(tài)調(diào)整接口。以上各種流量控制方法,在分布式架構(gòu)下,如果要做到全局動(dòng)態(tài)控制,一個(gè)簡(jiǎn)單的技術(shù)方法是依賴配置中心,即通過(guò)配置中心來(lái)進(jìn)行流控參數(shù)的下發(fā)
    發(fā)表于 01-24 16:41

    全局時(shí)鐘資源的例化方法有哪些?

    FPGA全局時(shí)鐘資源一般使用全銅層工藝實(shí)現(xiàn),并設(shè)計(jì)了專用時(shí)鐘緩沖與驅(qū)動(dòng)結(jié)構(gòu),從而使全局時(shí)鐘到達(dá)芯片內(nèi)部的所有可配置單元(CLB)、I/O單元(IOB)和選擇性塊RAM(Block Se
    發(fā)表于 10-22 06:01

    IC驗(yàn)證"一個(gè)簡(jiǎn)單的UVM驗(yàn)證平臺(tái)"是如何搭建的(六)

    的計(jì)算功能,完成scoreboard的比較功能。可以有成員變量,這些成員變量可以控制 的行為,如控制driver的行為等。當(dāng)要實(shí)現(xiàn)一個(gè)功能時(shí),首先應(yīng)該想到的是從
    發(fā)表于 12-04 15:48

    數(shù)字IC驗(yàn)證之“什么是UVM”“UVM的特點(diǎn)”“UVM提供哪些資源”(2)連載...

    ?uvm的特點(diǎn)以及uvm為用戶提供了哪些資源?什么是uvm呢?uvm是通用驗(yàn)證方法學(xué)的縮寫,是為驗(yàn)證服務(wù)的,
    發(fā)表于 01-21 16:00

    數(shù)字IC驗(yàn)證之“構(gòu)成uvm測(cè)試平臺(tái)的主要組件”(4)連載...

    測(cè)試案例完成的。因此在構(gòu)建env的時(shí)候,需要事先定義好配置接口,是env具有可配置性。  uvm不僅為驗(yàn)證工程師提供了測(cè)試平臺(tái)的結(jié)構(gòu),而且在uvm資源庫(kù)當(dāng)中。對(duì)于平臺(tái)中的每一個(gè)組件
    發(fā)表于 01-22 15:33

    什么是uvmuvm的特點(diǎn)有哪些呢

    大家好,我是一哥,上章內(nèi)容我們介紹什么是uvm?uvm的特點(diǎn)以及uvm為用戶提供了哪些資源?本章內(nèi)容我們來(lái)看一看一個(gè)典型的uvm驗(yàn)證平臺(tái)應(yīng)該
    發(fā)表于 02-14 06:46

    請(qǐng)問(wèn)一下在UVM的UVMsequences是什么意思啊

    UVM方法學(xué),UVMsequences 是壽命有限的對(duì)象。UVM sequences從uvm_sequence_item基擴(kuò)展得到,
    發(fā)表于 04-11 16:43

    深入了解Factory機(jī)制的實(shí)現(xiàn)方式

    uvm_default_factory定義了用于記錄重載信息的數(shù)據(jù)結(jié)構(gòu)(如下圖所示),并實(shí)現(xiàn)了在uvm_factory
    發(fā)表于 09-16 14:35

    如何構(gòu)建UVM寄存器模型并將寄存器模型集成到驗(yàn)證環(huán)境

    uvm_reg_block還可以包含其他子uvm_reg_block。在同一UVM還提供了uv
    發(fā)表于 09-23 14:29

    FPGA架構(gòu)全局時(shí)鐘資源介紹

    引言:本文我們介紹一下全局時(shí)鐘資源。全局時(shí)鐘是一個(gè)專用的互連網(wǎng)絡(luò),專門設(shè)計(jì)用于到達(dá)FPGA各種資源的所有時(shí)鐘輸入。這些網(wǎng)絡(luò)被設(shè)計(jì)成具有低偏
    的頭像 發(fā)表于 03-22 10:09 ?1.3w次閱讀
    FPGA架構(gòu)<b class='flag-5'>中</b>的<b class='flag-5'>全局</b>時(shí)鐘<b class='flag-5'>資源</b>介紹

    用個(gè)簡(jiǎn)單demo實(shí)現(xiàn)對(duì)全局變量的管理

    在項(xiàng)目中基本都會(huì)遇到全局變量,隨便放很容易忘記變量的使用,也不方便后續(xù)的閱讀,就需要對(duì)全局變量進(jìn)行統(tǒng)一管理,下面就用個(gè)簡(jiǎn)單demo,實(shí)現(xiàn)對(duì)全局
    的頭像 發(fā)表于 11-10 11:01 ?961次閱讀

    UVM的例化用new還是create

    UVM的例化用new和create有什么不同?什么時(shí)候可以用new?什么時(shí)候該用create? new是OOP自帶屬性,create是UVM override屬性,可以理解成
    的頭像 發(fā)表于 03-21 11:26 ?1350次閱讀

    UVM驗(yàn)證平臺(tái)頂層有什么作用

    因?yàn)镈UT是一個(gè)靜態(tài)的內(nèi)容,所以testbench理應(yīng)也是靜態(tài)的,其作為uvm驗(yàn)證環(huán)境和DUT的全局根結(jié)點(diǎn)。
    的頭像 發(fā)表于 03-21 11:33 ?1288次閱讀

    如何用Verdi查看UVM環(huán)境的變量?

    我們常用的debug UVM的方法是通過(guò)打印log實(shí)現(xiàn)。有沒(méi)有辦法像 debug RTL代碼一樣將 UVM 變量拉到波形上看呢?答案是有的
    的頭像 發(fā)表于 06-25 16:01 ?1730次閱讀
    如何用Verdi查看<b class='flag-5'>UVM</b>環(huán)境<b class='flag-5'>中</b>的變量?

    一文詳解UVM設(shè)計(jì)模式

    本篇是對(duì)UVM設(shè)計(jì)模式 ( 二 ) 參數(shù)化、靜態(tài)變量/方法/、單例模式、UVM_ROOT、工廠模式、
    的頭像 發(fā)表于 08-06 10:38 ?1779次閱讀
    一文詳解<b class='flag-5'>UVM</b>設(shè)計(jì)模式
    RM新时代网站-首页