reg model使用篇-uvm_reg_block常用操作

(1) 每一个register model被继承到验证平台后,都必须进行reset操作,这样才能保证每个寄存器的值等于我们设置的初始值.

(2) register model并不会自动的进行reset操作,必须显式的调用reset函数进行复位操作.

1.1 uvm_reg_block的reset函数

function void uvm_reg_block::reset(string kind = "HARD");

   foreach (regs[rg_]) begin
     uvm_reg rg = rg_;
     rg.reset(kind);
   end

   foreach (blks[blk_]) begin
     uvm_reg_block blk = blk_;
     blk.reset(kind);
   end
endfunction

 

1.2 uvm_reg的reset

(1) m_atomic本质上是一个semaphore,用于实现进程的同步; uvm_reg的new函数中会为其分配一个key;

function void uvm_reg::reset(string kind = "HARD");
   foreach (m_fields[i])
      m_fields[i].reset(kind);
   // Put back a key in the semaphore if it is checked out
   // in case a thread was killed during an operation
   void'(m_atomic.try_get(1));
   m_atomic.put(1);
   m_process = null;
   Xset_busyX(0);
endfunction: reset

 

1.3 uvm_reg_field的reset

(1) m_reset中的记录是在uvm_reg_field的configure函数中通过调用set_reset函数插入的;

function void uvm_reg_field::reset(string kind = "HARD");

   if (!m_reset.exists(kind))
      return;

   m_mirrored = m_reset[kind];
   m_desired  = m_mirrored;
   value      = m_mirrored;

   if (kind == "HARD")
      m_written  = 0;

endfunction: reset

 

 function void uvm_reg_field::set_reset(uvm_reg_data_t value,
                                        string kind = "HARD");
   m_reset[kind] = value & ((1<<m_size) - 1);
 endfunction: set_reset

 

function void uvm_reg_field::configure(uvm_reg        parent,
                                       int unsigned   size,
                                       int unsigned   lsb_pos,
                                       string         access,
                                       bit            volatile,
                                       uvm_reg_data_t reset,
                                       bit            has_reset,
                                       bit            is_rand,
                                       bit            individually_accessible);
   m_parent = parent;
   if (size == 0) begin
      `uvm_error("RegModel",
         $sformatf("Field \"%s\" cannot have 0 bits", get_full_name()));
      size = 1;
   end

   m_size      = size;
   m_volatile  = volatile;
   m_access    = access.toupper();
   m_lsb       = lsb_pos;
   m_cover_on  = UVM_NO_COVERAGE;
   m_written   = 0;
   m_check     = volatile ? UVM_NO_CHECK : UVM_CHECK;
   m_individually_accessible = individually_accessible;

   if (has_reset)
      set_reset(reset);
   else
      uvm_resource_db#(bit)::set({"REG::", get_full_name()},
                                 "NO_REG_HW_RESET_TEST", 1);

   m_parent.add_field(this);

   if (!m_policy_names.exists(m_access)) begin
      `uvm_error("RegModel", {"Access policy '",access,
       "' for field '",get_full_name(),"' is not defined. Setting to RW"})
      m_access = "RW";
   end

   if (size > m_max_size)
      m_max_size = size;

   // Ignore is_rand if the field is known not to be writeable
   // i.e. not "RW", "WRC", "WRS", "WO", "W1", "WO1"
   case (access)
    "RO", "RC", "RS", "WC", "WS",
      "W1C", "W1S", "W1T", "W0C", "W0S", "W0T",
      "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS",
      "WOC", "WOS": is_rand = 0;
   endcase

   if (!is_rand)
     value.rand_mode(0);

   m_field_registry[get_full_name()] = this;
endfunction: configure

2. get_root_blocks

(1) 得到所有的root blocks;

(2) 在使用get_root_blocks函数得到reg_block的指针后,使用cast将其转化为目标reg_block形式;

extern static  function void get_root_blocks(ref uvm_reg_block blks[$]);
function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]);

   foreach (m_roots[blk]) begin
      blks.push_back(blk);
   end

endfunction: get_root_blocks

 

//示例
class case0_cfg_vseq extends uvm_sequence;
    ...
    virtual task body();
        uvm_status_e   status;
        uvm_reg_data_t value;
        bit[31:0]      counter;
        uvm_reg_block  blks[$];
        reg_model      p_rm;
        ...

        uvm_reg_block::get_root_blocks(blks);
        if(blks.size()==0) begin
            `uvm_fatal(**)
        end
        else begin
            if(!$cast(p_rm,blks[0])) begin
                **
            end
            p_rm.invert.read(status,value,UVM_FRONTDOOR);
            ...
        end
    endtask

endclass

3. get_registers

(1) 得到在当前register_block里面例化的registers;

(2) 注意: register可能位于不同或多个address maps中,为了获取特定address map中的registers,需要使用uvm_reg_map::get_registers();

function void uvm_reg_block::get_registers(ref uvm_reg regs[$],
                                           input uvm_hier_e hier=UVM_HIER);
   foreach (this.regs[rg])
     regs.push_back(rg);

   if (hier == UVM_HIER)
     foreach (blks[blk_]) begin
       uvm_reg_block blk = blk_;
       blk.get_registers(regs);
     end
endfunction: get_registers

 

function void uvm_reg_block::add_reg(uvm_reg rg);
   if (this.is_locked()) begin
      `uvm_error("RegModel", "Cannot add register to locked block model");
      return;
   end

   if (this.regs.exists(rg)) begin
      `uvm_error("RegModel", {"Register '",rg.get_name(),
         "' has already been registered with block '",get_name(),"'"})
       return;
   end

   regs[rg] = id++;
endfunction: add_reg

 

4. add_hdl_path

function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL");

  uvm_queue #(string) paths;

  paths = hdl_paths_pool.get(kind);

  paths.push_back(path);

endfunction

 

local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; //uvm_reg_block内变量
//uvm_pool.svh
class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object;
  ...
  protected T pool[KEY];
  ...
endclass

class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T);

  ...
  virtual function T get (string key);
    if (!pool.exists(key))
      pool[key] = new (key);
    return pool[key];
  endfunction
  ...

endclass

 

5. configure

function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path="");
  this.parent = parent;
  if (parent != null)
    this.parent.add_block(this);
  add_hdl_path(hdl_path);

  uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this);
endfunction

 

6. get_reg_by_name

function uvm_reg uvm_reg_block::get_reg_by_name(string name);

   foreach (regs[rg_]) begin
     uvm_reg rg = rg_;
     if (rg.get_name() == name)
       return rg;
   end

   foreach (blks[blk_]) begin
      uvm_reg_block blk = blk_;
      uvm_reg subregs[$];
      blk_.get_registers(subregs, UVM_HIER);

      foreach (subregs[j])
         if (subregs[j].get_name() == name)
            return subregs[j];
   end

   `uvm_warning("RegModel", {"Unable to locate register '",name,
                "' in block '",get_full_name(),"'"})
   return null;

endfunction: get_reg_by_name

7.get_parent

function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path="");
  this.parent = parent;
  if (parent != null)
    this.parent.add_block(this);
  add_hdl_path(hdl_path);

  uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this);
endfunction

function uvm_reg_block uvm_reg_block::get_parent();
   get_parent = this.parent;
endfunction: get_parent

 

8.update

task uvm_reg_block::update(output uvm_status_e  status,
                           input  uvm_path_e    path = UVM_DEFAULT_PATH,
                           input  uvm_sequence_base  parent = null,
                           input  int                prior = -1,
                           input  uvm_object         extension = null,
                           input  string             fname = "",
                           input  int                lineno = 0);
   status = UVM_IS_OK;

   if (!needs_update()) begin
     `uvm_info("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating",
                    fname, lineno, this.get_name()), UVM_HIGH);
      return;
   end

   `uvm_info("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path",
                    fname, lineno, this.get_name(), path.name ), UVM_HIGH);

   foreach (regs[rg_]) begin
      uvm_reg rg = rg_;
      if (rg.needs_update()) begin
         rg.update(status, path, null, parent, prior, extension);
         if (status != UVM_IS_OK && status != UVM_HAS_X) begin;
           `uvm_error("RegModel", $sformatf("Register \"%s\" could not be updated",
                                        rg.get_full_name()));
           return;
         end
      end
   end

   foreach (blks[blk_]) begin
     uvm_reg_block blk = blk_;
     blk.update(status,path,parent,prior,extension,fname,lineno);
   end
endtask: update

 

9.write_reg_by_name

task uvm_reg_block::write_reg_by_name(output uvm_status_e   status,
                                      input  string              name,
                                      input  uvm_reg_data_t      data,
                                      input  uvm_path_e     path = UVM_DEFAULT_PATH,
                                      input  uvm_reg_map      map = null,
                                      input  uvm_sequence_base   parent = null,
                                      input  int                 prior = -1,
                                      input  uvm_object          extension = null,
                                      input  string              fname = "",
                                      input  int                 lineno = 0);
   uvm_reg rg;
   this.fname = fname;
   this.lineno = lineno;

   status = UVM_NOT_OK;
   rg = this.get_reg_by_name(name);
   if (rg != null)
     rg.write(status, data, path, map, parent, prior, extension);

endtask: write_reg_by_name

 

10.read_reg_by_name

task uvm_reg_block::read_reg_by_name(output uvm_status_e  status,
                                     input  string             name,
                                     output uvm_reg_data_t     data,
                                     input  uvm_path_e    path = UVM_DEFAULT_PATH,
                                     input  uvm_reg_map     map = null,
                                     input  uvm_sequence_base  parent = null,
                                     input  int                prior = -1,
                                     input  uvm_object         extension = null,
                                     input  string             fname = "",
                                     input  int                lineno = 0);
   uvm_reg rg;
   this.fname = fname;
   this.lineno = lineno;

   status = UVM_NOT_OK;
   rg = this.get_reg_by_name(name);
   if (rg != null)
     rg.read(status, data, path, map, parent, prior, extension);
endtask: read_reg_by_name

 

posted @ 2023-01-28 20:21  luckylan  阅读(1210)  评论(0)    收藏  举报