UVM基礎之-------uvm factory機制override<博>

override功能是UVM中一個比較重要的功能,這個功能也是在factory裏面實現的,咱們會在env或者具體的case中使用override功能。
class case_x extends base_test;
    function void build_phase(uvm_phase phase);
       …
       set_type_override_by_type(my_driver::get_type(), new_driver::get_type());
    endfunction
endclass
在uvm_component中會有set_type_override_by_type接口函數,這個函數實際調用的是factory裏面的對應函數。

用於override功能的數據結構:
factory機制的 override 功能是經過幾個隊列實現的。最重要一個隊列以下:
protected uvm_factory_override m_type_overrides[$]; //這是一個記錄override數組
     1. uvm_factory_override其實很簡單,它是一個記錄把一個已經註冊的uvm_object_wrapper用另一個uvm_object_wrapper來進行替代的數據結構,該結構記錄了原wrapper名和對象,替換wrapper名和對象,full_inst_path來跟蹤對象的位置
     2. 跟這個隊列相關的task有兩個 set_type_override_by_type/ set_type_override_by_name
     3. 首先分析 set_type_override_by_type,可 以設定一個override讓一個wrapper取代另一個wrapper,而後將該override壓入數組,若是一個wrapper沒有註冊,函數中就將其註冊。 
     4.    set_type_override_by_name() 讓original_type_name的wrapper被override_type_name的wapper取代,在m_type_names[string]中查找出這兩個名字的wrapper並聲明一個override並壓入m_type_overrides[$],override_type_name的wapper不能爲空;original_type_name的wrapper能夠爲空,若是爲空就在m_lookup_strs[original_type_name] = 1中記錄這一個original_type_name的wrapper爲null的狀況 set_type_overide_by_name 與 set_type_override_by_type 幾乎徹底同樣,其 惟一的區別就是傳入的參數有差別
       function   void  uvm_factory::set_type_override_by_type (uvm_object_wrapper original_type,
                                                      uvm_object_wrapper override_type,
                                                      bit replace=1);
  bit replaced;
  // check that old and new are not the same
  if (original_type == override_type) begin        // 比較一下override 先後的兩個類型是否是同一個類型,若是是同一類型就沒有必要override
    if (original_type.get_type_name() == "" || original_type.get_type_name() == "<unknown>")
      uvm_report_warning("TYPDUP", {"Original and override type ",
                                    "arguments are identical"}, UVM_NONE);
    else
      uvm_report_warning("TYPDUP", {"Original and override type ",
                                    "arguments are identical: ",
                                    original_type.get_type_name()}, UVM_NONE);
    return;
  end
  // register the types if not already done so, for the benefit of string-based lookup
  if (!m_types.exists(original_type))       // 檢查一下輸入的兩個類型是否是已經在 factory 中註冊過了, 若是沒有,那麼就會註冊。也就是說,要保證在 override 以前,這兩種類型已經在 factory的 m_types數組中存在了
    register(original_type); 
  if (!m_types.exists(override_type))
    register(override_type); 
  // check for existing type override
  foreach (m_type_overrides[index]) begin   // 用於查看系統中已經有的override 信息
    if (m_type_overrides[index].orig_type == original_type ||
        (m_type_overrides[index].orig_type_name != "<unknown>" &&
         m_type_overrides[index].orig_type_name != "" &&
         m_type_overrides[index].orig_type_name == original_type.get_type_name())) begin
      string msg;
      msg = {"Original object type '",original_type.get_type_name(),
             "' already registered to produce '",
             m_type_overrides[index].ovrd_type_name,"'"};
      if (!replace) begin
        msg = {msg, ".  Set 'replace' argument to replace the existing entry."};
        uvm_report_info("TPREGD", msg, UVM_MEDIUM);
        return;
      end
      msg = {msg, ".  Replacing with override to produce type '",
                  override_type.get_type_name(),"'."};
      uvm_report_info("TPREGR", msg, UVM_MEDIUM);
      replaced = 1;
      m_type_overrides[index].orig_type = original_type; 
      m_type_overrides[index].orig_type_name = original_type.get_type_name(); 
      m_type_overrides[index].ovrd_type = override_type; 
      m_type_overrides[index].ovrd_type_name = override_type.get_type_name(); 
    end
  end
  // make a new entry
  if (!replaced) begin
    uvm_factory_override override;
    override = new(.orig_type(original_type),
                   .orig_type_name(original_type.get_type_name()),
                   .full_inst_path("*"),
                   .ovrd_type(override_type));
     m_type_overrides. push_back(override); // 用於向m_type_overrides隊列中插入一條記錄。這條記錄會調用uvm_factory_override的new函數來建立。在調用new的時候會輸入幾個參數
  end
endfunction

類型被override時實例的建立:
set_type_override_by_type(my_driver::get_type(), new_driver::get_type());分析當 drv = my_driver::type_id::create(「drv」, this);會發生什麼事情;
  這個create是屬於 class uvm_component_registry #(my_driver,  「my_driver」)
在這裏調用 obj = f.create_component_by_type(get(),contxt,name,parent);
    1. 傳入的第一個參數是 uvm_component_registry #(my_driver,  「my_driver」)中的靜 態成員變量me
  2.第二個參數是contxt,由上面的code得出這是」uvm_test_done.env.agent
  3.第三個參數是字符串「drv」
  4.第四個參數是parent,這裏是this,指代的drv的父component

factory的create_component_by_type函數裏面override功能的關鍵在下面的這一句:
   requested_type = find_override_by_type(requested_type, full_inst_path);
       1. 第一個參數是靜態成員變量me,
       2. 第二個參數是full_inst_path

find_override_by_type函數以下:

function uvm_object_wrapper uvm_factory::find_override_by_type(uvm_object_wrapper requested_type,
                                                               string full_inst_path);
  uvm_object_wrapper override;
  uvm_factory_queue_class qc = null;
  if (m_inst_override_queues.exists(requested_type))        //requested_type == my_driver
    qc = m_inst_override_queues[requested_type];             //檢查是否有具體的事例的override, 因爲 factory 的 override 有兩種,一種是整個驗證平臺中相關類的全部實例都進行override,另一種是隻針對特定的實例進行 override。
  foreach (m_override_info[index]) begin  //這裏防止造成環路的override
    if ( //index != m_override_info.size()-1 &&
       m_override_info[index].orig_type == requested_type) begin
      uvm_report_error("OVRDLOOP""Recursive loop detected while finding override.", UVM_NONE);
      if (!m_debug_pass)
        debug_create_by_type (requested_type, full_inst_path);
      return requested_type;
    end
  end
  // inst override; return first match; takes precedence over type overrides
  if (full_inst_path != "" && qc != null)
    for (int index = 0; index < qc.queue.size(); ++index) begin
      if ((qc.queue[index].orig_type == requested_type ||
           (qc.queue[index].orig_type_name != "<unknown>" &&
            qc.queue[index].orig_type_name != "" &&
            qc.queue[index].orig_type_name == requested_type.get_type_name())) &&
          uvm_is_match(qc.queue[index].full_inst_path, full_inst_path)) begin
        m_override_info.push_back(qc.queue[index]);
        if (m_debug_pass) begin
          if (override == nullbegin
            override = qc.queue[index].ovrd_type;
            qc.queue[index].selected = 1;
          end
        end
        else begin
          if (qc.queue[index].ovrd_type == requested_type)
            return requested_type;
          else
            return find_override_by_type(qc.queue[index].ovrd_type,full_inst_path);
        end
      end
    end
  // type override - exact match
  foreach (m_type_overrides[index]) begin                                     // 檢查 m_type_overrides中是否 有對應 my_driver 的記錄。剛好找到了一條,把這條記錄放入 m_override_info 中                                                                               
    if (m_type_overrides[index].orig_type == requested_type ||
        (m_type_overrides[index].orig_type_name != "<unknown>" &&
         m_type_overrides[index].orig_type_name != "" &&
         requested_type != null &&
         m_type_overrides[index].orig_type_name == requested_type.get_type_name())) begin
       m_override_info.push_back(m_type_overrides[index]);
      if (m_debug_pass) begin
        if (override == nullbegin
          override = m_type_overrides[index].ovrd_type;
          m_type_overrides[index].selected = 1;
        end
      end
      else begin
        if (m_type_overrides[index].ovrd_type == requested_type)// ///檢查 m_type_overrides 中找到的這條記錄中 ovrd_type 是否是就是要查找的類型,在本例中就至關因而看new_driver是否是等於my_driver,很顯然是不等於的,因此會調用find_override_by_type函數,這至關因而遞歸調用,只是此次調用傳入的第一個參數將會是表明 new_driver 的 uvm_component_registry#(new_driver, 「new_driver」)的靜態成員變量me,第二個參數是字符串my_driver。
          return requested_type;
        else
          return find_override_by_type(m_type_overrides[index].ovrd_type,full_inst_path);
      end
    end
  end
  // type override with wildcard match
  //foreach (m_type_overrides[index])
  //  if (uvm_is_match(index,requested_type.get_type_name())) begin
  //    m_override_info.push_back(m_inst_overrides[index]);
  //    return find_override_by_type(m_type_overrides[index],full_inst_path);
  //  end
  if (m_debug_pass && override != null)
    if (override == requested_type)
      return requested_type;
    else
      return find_override_by_type(override,full_inst_path);
  return requested_type;
endfunction  

這個 find_override_by_type 函數爲何要作成遞歸的方式呢?由於假設系統中 有一個 A,結果使用 override 語句把 A 用 B 給 override 了,然後面又用 override 語
句把 B 用 C 給 override 了,此時建立 A 的實例,獲得的應該是 C 的實例。只有在 find_override_by_type 中遞歸調用,才能完整的實現這一功能。 

這是另一我的給出來的函數分析,

    function uvm_object_wrapper uvm_factory::find_override_by_type
 
     argument:(uvm_object_wrapper requested_type, string full_inst_path);
 
     這個函數在m_type_overrides[index]和 m_inst_override_queues中查找requested_type類型的wrapper.
 
     該函數的算法實現比較有意思,作爲一篇對uvm源碼剖析的文章,不才索性分析一二。本函數的實現和使用和下一個函數的實現和使用緊密相連。因爲存在着ab_override(a_wrapper-->b_wrapper),bc_override(b_wrapper-->c_wrapper),ca_override(c_wrapper-->a_wrapper)可見這些override構成了一個circle,咱們的實現中須要找出這些circle並識別出來,找到最終的wrapper。這也是這個函數代碼實現中最讓人難理解的地方。
 
該函數的實現過程能夠份量條線:
 
m_debug_pass=0:
 
      1. 取出qc=m_inst_override_queues[requested_type],在m_override_info[index]中記錄了ab_override(a_wrapper-->b_wrapper),bc_override(b_wrapper-->c_wrapper),ca_override(c_wrapper-->a_wrapper) 這樣的override鏈條,這樣的鏈條是經過遞歸調用函數自己的方法生成的,開始時該記錄爲空,m_override_info[index]中元素的個數也記錄了本次遞歸的深度。  
 
      2. 查詢m_override_info[index]中每一個override的org_type如何和本次查找的requested_type同樣,則意味着出現了circle,報告出錯。在初次調用中m_override_info[index]中爲空,在遞歸調用中若是m_override_info[index]中有override的前後爲ab_override,bc_override,對ca_override調用find_override_by_type(qc.queue[index].ovrd_type,full_inst_path)將會發現ca_override的a_wrapper已經在m_override_info[index]的ab_override中,致使返現circle報告出錯。
 
      3.if(full_inst_path != "" && qc != null)則在inst override; return first match;並將match的override記錄入m_override_info[index]。若是match的override.override_type==requested_type則意味着override.org_type==requested_type,return requested_type;不然遞歸調用find_override_by_type(qc.queue[index].ovrd_type,full_inst_path)
 
      4.遞歸調用的最後會發現qc=m_inst_override_queues[requested_type]中的qc爲空,即某個不存在override的的葉子wrapper
 
      5.用一樣的方法2,3,4查詢m_type_overrides[index]
 
      6.最終返回一個wrapper
 
m_debug_pass=1:
 
      1.同上
 
      2.同上
 
      3.基本原理同上3,實現的時候略有不一樣,他首先查找qc中匹配的override寫入在m_override_info[index]中,取出第一個override=override.over_type,而後取出m_type_overrides[index]中匹配的override寫入m_override_info[index]。最後遞歸調用本函數 find_override_by_type(override,full_inst_path)override.over_type,在第2步的時候就會查詢override是否已是一個m_override_info[index]的override的org_type,這樣就能很早就發現circle,而不用遞歸調用好久後發現。
 
      4.同上
 
      5.同上
 
      6.返回override中的葉子就是最後的wrapper
 
    function uvm_object_wrapper uvm_factory::find_override_by_name:
 
     argument:(string requested_type_name, string full_inst_path);
 
     這是uvm factory中的一個wrapper查找算法,該算法從m_wildcard_inst_overrides,m_inst_override_name_queues,m_inst_override_queues,m_type_overrides,m_types_names中查找出一個wrapper來產生咱們但願的數據。
 
      對該算法的實現作詳盡介紹:
 
     1.若是requested_type_name在 m_type_names[requested_type_name]中註冊,則取出inst
 
     2.若是m_type_names[requested_type_name]不存在就從qc = m_inst_override_name_queues[requested_type_name];若是存在就從qc = m_inst_override_queues[rtype]
 
     3. m_debug_pass=0時,同上一個函數的第3步
 
     4. 查詢m_wildcard_inst_overrides若是存在和requested_type_name匹配的則生成一個override加入m_inst_override_queues
 
     5. 同m_debug_pass=0時,同上一個函數的第5步查詢m_type_overrides[index]
 
     6.返回一個葉子wrapper


  protected uvm_factory_queue_class   m_inst_override_queues[uvm_object_wrapper];
          這個隊列爲須要的inst記錄了一組override隊列:
          set_inst_override_by_type():當設置了一個original_type和一個override_type的override,並將該override記錄進對應original_type的隊列。若是original_type和override_type都沒有註冊,則調用register()註冊這些type。

設要替換的實例的路徑爲:env.agent.drv,則在某 case 的 build_pahse 進行以下 的 override:
set_inst_override_by_type(「env.agent.drv」, my_driver::get_type(), new_driver::get_type ()); 經過最終調用下面的語句在m_inst_override_queues中增長一條記錄。
 
m_inst_override_queues[original_type].queue.push_back(override);

當咱們執行下面的override語句的時候:
set_inst_override_by_type(「env.agent.drv」, my_driver::get_type(), new_driver::get_type ());
調用的依然是find_override_by_type:執行這個函數裏面// inst override; return first match; takes precedence over type overrides下面的語句

  protected uvm_factory_queue_class  m_inst_override_name_queues[string];
    1. 這是一個記錄僅有類型名字沒有類型實例的數組,存在着將一個 original_type_name的null wrapper用一個original_type_name的wrapper取代的狀況,這種狀況的override記錄在這個隊列中。 
    2. set_inst_override_by_name()讓original_type_name的wrapper被override_type_name的wapper取代,在m_type_names[string]中查找出這兩個名字的wrapper並聲明一個override並壓入m_inst_override_queues。若是m_type_names[string]中找不到original_type_name的wrapper,則在m_inst_override_name_queues記錄這個original_type爲空的override;若是original_type_name中含有通配符,則找到m_type_names[string]中全部匹配的wrapper併爲其創建override記錄在m_inst_override_queues中。並把含有通配符的原始override記錄在m_wildcard_inst_overrides[$]中。m_lookup_strs[original_type_name] = 1中記錄這一個original_type_name的wrapper爲null的狀況
  protected uvm_factory_override    m_wildcard_inst_overrides[$];
     1. set_inst_override_by_name()中若是錄入的original_type_name沒有在m_type_names[string]存在,同時original_type_name中存在*和?則對應的override將被記錄進這個隊列中
  local uvm_factory_override     m_override_info[$];
  local static bit m_debug_pass;

  function   void  uvm_factory::set_inst_override_by_type (uvm_object_wrapper original_type,
                                                      uvm_object_wrapper override_type,
                                                      string full_inst_path);
  
  uvm_factory_override override;
  // register the types if not already done so
  if (!m_types.exists(original_type))
    register(original_type); 
  if (!m_types.exists(override_type))
    register(override_type); 
  if (check_inst_override_exists(original_type,override_type,full_inst_path))
    return;
  if(!m_inst_override_queues.exists(original_type))
    m_inst_override_queues[original_type] = new;
  override = new(.full_inst_path(full_inst_path),
                 .orig_type(original_type),
                 .orig_type_name(original_type.get_type_name()),
                 .ovrd_type(override_type));
  m_inst_override_queues[original_type].queue.push_back(override);
 endfunction

   function void set_inst_override_by_name (     string      original_type_name,     string      override_type_name,     string      full_inst_path     )
   
    1. 當使用type 替換的時候 original_type和override_type都是指向types 代理對象的句柄, Preregistration is not required.
    2. 當使用name進行替換的時候, original_type_name要參考一個在factory裏面預約義的type, Future calls to any of the create_* methods with the same string and matching instance path will produce the type represented by override_type_name, which must be preregistered with the factory.
   3.  The full_inst_path is matched against the contentation of {parent_inst_path, 「.」, name} provided in future create requests. 
   4. When the factory processes instance overrides, the instance queue is processed in order of override registrations, and the first override match prevails.  Thus, more specific overrides should be registered first, followed by more general overrides.

function void set_type_override_by_type (     uvm_object_wrapper      original_type,      uvm_object_wrapper      override_type,       bit      replace)
function void set_type_override_by_name (     string      original_type_name,      string      override_type_name,       bit      replace      =      1     )

Creating:
function uvm_object uvm_factory::create_object_by_name (string requested_type_name,  
                                                        string parent_inst_path="",  
                                                        string name=""); 
  uvm_object_wrapper wrapper;
  string inst_path;
  if (parent_inst_path == "")
    inst_path = name;
  else if (name != "")
    inst_path = {parent_inst_path,".",name};
  else
    inst_path = parent_inst_path;
  m_override_info.delete();
  wrapper = find_override_by_name(requested_type_name, inst_path);//主 要用override 發生的時候,應該使用 override 以後的類型來建立實例
  // if no override exists, try to use requested_type_name directly
  if (wrapper==nullbegin
    if(!m_type_names.exists(requested_type_name)) begin // 當 override 不存在的時候纔會走的分支,它的主要做用就是到 m_type_names 這個數組中去尋找 requested_type_name,並把 m_type_names 中記錄的內容做爲wrapper的值。
      uvm_report_warning("BDTYP",{"Cannot create an object of type '",
      requested_type_name,"' because it is not registered with the factory."}, UVM_NONE);
      return null;
    end
    wrapper = m_type_names[requested_type_name];
  end
  return wrapper.create_object(name); //返回經過調用這個wrapper的create_object(name)所獲得的這個代理表示的object或者component的值
endfunction  


相關文章
相關標籤/搜索