reg model使用篇-uvm_reg常用操作part3(XatomicX/read/write(frontdoor/backdoor))

local semaphore         m_atomic;
local process           m_process;

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

task uvm_reg::XatomicX(bit on);
   process m_reg_process;
   m_reg_process=process::self();

   if (on) begin
     if (m_reg_process == m_process)
       return;
     m_atomic.get(1);
     m_process = m_reg_process;
   end
   else begin
      // Maybe a key was put back in by a spurious call to reset()
      void'(m_atomic.try_get(1));
      m_atomic.put(1);
      m_process = null;
   end
endtask: XatomicX

2. read/write (frontdoor)

 regmodel.register.read(status,value,UVM_FRONTDOOR,.parent(this));
 regmodel.register.write(status,value,UVM_FRONTDOOR,.parent(this));

2.1 read/write (frontdoor)操作的影响

(1) 当使用front-door(path=BFM), 一个或多个实际的transaction会发往DUT进行register的读写;

(2) 无论通过前门访问还是后门访问的方式从DUT中读取或写入寄存器的值,在操作完成后,寄存器模型都会根据读写的结果更新期望值和镜像值(其实是有前提条件的,对于后门访问,会自动更新镜像值和期望值; 对于前门访问,更新镜像值和期望值有两种方法: (a) auto_predict功能需要打开,即在env中调用uvm_reg_map.set_auto_predict(1),然后调用do-predict函数更新寄存器模型的mirror值; (b)关闭auto_predict功能,使用uvm_reg_predictor进行更新);

(3) 如果寄存器map到多个uvm_address_map,在调用uvm_reg的write/read task进行前门访问时,需要指定uvm_reg_map参数;

2.2 write (frontdoor)的源码

(1) uvm_reg::write

(1.1) FRONTDOOR write操作最终会转换为uvm_reg_map的do_write任务;

(1.2) uvm_reg_map的do_write任务会查看系统是否设置了adapter,如果没有设置,就直接启动sequence, 让sequencer发送uvm_reg_item类型的transaction;如果设置了,那就调用do_bus_write任务.

(1.3) uvm_reg_map的do_write完成后,如果auto predict功能打开了, uvm_reg的do_write会根据写入的值更新register model中寄存器的值;

task uvm_reg::write(output uvm_status_e      status,
                    input  uvm_reg_data_t    value,
                    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);

   // create an abstract transaction for this operation
   uvm_reg_item rw;

   XatomicX(1);

   set(value);

   rw = uvm_reg_item::type_id::create("write_item",,get_full_name());
   rw.element      = this;
   rw.element_kind = UVM_REG;
   rw.kind         = UVM_WRITE;
   rw.value[0]     = value;
   rw.path         = path;
   rw.map          = map;
   rw.parent       = parent;
   rw.prior        = prior;
   rw.extension    = extension;
   rw.fname        = fname;
   rw.lineno       = lineno;

   do_write(rw);

   status = rw.status;

   XatomicX(0);

endtask

 

(2) uvm_reg::do_write

task uvm_reg::do_write (uvm_reg_item rw);

   uvm_reg_cb_iter  cbs = new(this);
   uvm_reg_map_info map_info;
   uvm_reg_data_t   value;

   m_fname  = rw.fname;
   m_lineno = rw.lineno;

   if (!Xcheck_accessX(rw,map_info,"write()"))
     return;

   XatomicX(1);

   m_write_in_progress = 1'b1;

   rw.value[0] &= ((1 << m_n_bits)-1);
   value = rw.value[0];

   rw.status = UVM_IS_OK;

   // PRE-WRITE CBS - FIELDS
   begin : pre_write_callbacks
      ...
   end
   rw.element = this;
   rw.element_kind = UVM_REG;
   rw.value[0] = value;

   // PRE-WRITE CBS - REG
   pre_write(rw);
   for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
      cb.pre_write(rw);

   if (rw.status != UVM_IS_OK) begin
     m_write_in_progress = 1'b0;

     XatomicX(0);

     return;
   end

   // EXECUTE WRITE...
   case (rw.path)

      // ...VIA USER BACKDOOR
      UVM_BACKDOOR: begin
        ...
      end

      UVM_FRONTDOOR: begin

         uvm_reg_map system_map = rw.local_map.get_root_map();

         m_is_busy = 1;

         // ...VIA USER FRONTDOOR
         if (map_info.frontdoor != null) begin
            uvm_reg_frontdoor fd = map_info.frontdoor;
            fd.rw_info = rw;
            if (fd.sequencer == null)
              fd.sequencer = system_map.get_sequencer();
            fd.start(fd.sequencer, rw.parent);
         end

         // ...VIA BUILT-IN FRONTDOOR
         else begin : built_in_frontdoor

            rw.local_map.do_write(rw);

         end

         m_is_busy = 0;

         if (system_map.get_auto_predict()) begin
            uvm_status_e status;
            if (rw.status != UVM_NOT_OK) begin
               sample(value, -1, 0, rw.map);
               m_parent.XsampleX(map_info.offset, 0, rw.map);
            end

            status = rw.status; // do_predict will override rw.status, so we save it here
            do_predict(rw, UVM_PREDICT_WRITE);
            rw.status = status;
         end
      end

   endcase

   ...
   XatomicX(0);

endtask: do_write

(3) uvm_reg_map.do_write

(3.1) 24到26行把要写的item通过sequencer发送出去,27行调用rw.end_event的wait_on;

(3.2) sequence.finish_item task中会调用sequencer.end_tr,而sequencer.end_tr会在driver调用item_done后结束;

(3.3) sequencer.end_tr内会触发end_event事件;

task uvm_reg_map::do_write(uvm_reg_item rw);

  uvm_sequence_base tmp_parent_seq;
  uvm_reg_map system_map = get_root_map();
  uvm_reg_adapter adapter = system_map.get_adapter();
  uvm_sequencer_base sequencer = system_map.get_sequencer();

  if (adapter != null && adapter.parent_sequence != null) begin
    uvm_object o;
    uvm_sequence_base seq;
    o = adapter.parent_sequence.clone();
    assert($cast(seq,o));
    seq.set_parent_sequence(rw.parent);
    rw.parent = seq;
    tmp_parent_seq = seq;
  end

  if (rw.parent == null) begin
     rw.parent = new("default_parent_seq");
     tmp_parent_seq = rw.parent;
  end

  if (adapter == null) begin
    rw.set_sequencer(sequencer);
    rw.parent.start_item(rw,rw.prior);
    rw.parent.finish_item(rw);
    rw.end_event.wait_on();
  end
  else begin
    do_bus_write(rw, sequencer, adapter);
  end

  if (tmp_parent_seq != null)
    sequencer.m_sequence_exiting(tmp_parent_seq);

endtask

2.3 read (frontdoor)源码

 

 

task uvm_reg::read(output uvm_status_e      status,
                   output uvm_reg_data_t    value,
                   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);
   XatomicX(1);
   XreadX(status, value, path, map, parent, prior, extension, fname, lineno);
   XatomicX(0);
endtask: read

 

task uvm_reg::XreadX(output uvm_status_e      status,
                     output uvm_reg_data_t    value,
                     input  uvm_path_e        path,
                     input  uvm_reg_map       map,
                     input  uvm_sequence_base parent = null,
                     input  int               prior = -1,
                     input  uvm_object        extension = null,
                     input  string            fname = "",
                     input  int               lineno = 0);

   // create an abstract transaction for this operation
   uvm_reg_item rw;
   rw = uvm_reg_item::type_id::create("read_item",,get_full_name());
   rw.element      = this;
   rw.element_kind = UVM_REG;
   rw.kind         = UVM_READ;
   rw.value[0]     = 0;
   rw.path         = path;
   rw.map          = map;
   rw.parent       = parent;
   rw.prior        = prior;
   rw.extension    = extension;
   rw.fname        = fname;
   rw.lineno       = lineno;

   do_read(rw);

   status = rw.status;
   value = rw.value[0];

endtask: XreadX

3. read/write (backdoor)

(1) 当使用back-door(path=BACKDOOR)时, 会通过uvm_hdl_read/uvm_hdl_deposit函数获取或修改DUT register值,而不会通过物理上的interface;

(2) 但是back-door的访问方式会尽量模拟前门访问的行为,比如如果对一个只读寄存器进行后门写操作,由于要模拟DUT的只读行为,所以是写不进去的;

(3) 无论通过前门访问还是后门访问的方式,从DUT中读取或写入寄存器的值,在操作完成后,寄存器模型都会根据读写的结果更新期望值和镜像值(对于前门访问而言,前提条件是system_map.get_auto_predict为1);

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