This is a deepdive into how set_auto_predict works.

When called on reg_map, It updates the mirror values with write/read operation going through the reg model.

blabla_reg_block_map.set_auto_predict(1);

The function is defined in uvm_reg_map.svh with the following comment

   // When ~on~ is ~TRUE~, 
   // the register model will automatically update its mirror
   // (what it thinks should be in the DUT) immediately after
   // any bus read or write operation via this map. Before a <uvm_reg::write>
   // or <uvm_reg::read> operation returns, the register's <uvm_reg::predict>
   // method is called to update the mirrored value in the register.
   //
   // When ~on~ is ~FALSE~, bus reads and writes via this map do not
   // automatically update the mirror. For real-time updates to the mirror
   // in this mode, you connect a <uvm_reg_predictor> instance to the bus
   // monitor. The predictor takes observed bus transactions from the
   // bus monitor, looks up the associated <uvm_reg> register given
   // the address, then calls that register's <uvm_reg::predict> method.
   // While more complex, this mode will capture all register read/write
   // activity, including that not directly descendant from calls to
   // <uvm_reg::write> and <uvm_reg::read>.
   //
   // By default, auto-prediction is turned off.

   function void set_auto_predict(bit on=1); m_auto_predict = on; endfunction

m_auto_predict is referenced only in get_auto_predict

  function bit  get_auto_predict(); return m_auto_predict; endfunction

get_auto_predict is called inside 2 tasks do_write and do_read. In do_write, the value is checked in UVM_FRONTDOOR case


      UVM_FRONTDOOR: begin
    ...
    ...
         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

The key function here is do_predict called with rw. For each field, field.do_prodict is called to predict each field. This is common function is called by RAL access API(poke, etc)

function void uvm_reg::do_predict(uvm_reg_item      rw,
                                  uvm_predict_e     kind = UVM_PREDICT_DIRECT,
                                  uvm_reg_byte_en_t be = -1);

   uvm_reg_data_t reg_value = rw.value[0];
   m_fname = rw.fname;
   m_lineno = rw.lineno;

   rw.status = UVM_IS_OK;

   if (m_is_busy && kind == UVM_PREDICT_DIRECT) begin
      `uvm_warning("RegModel", {"Trying to predict value of register '",
                  get_full_name(),"' while it is being accessed"})
      rw.status = UVM_NOT_OK;
      return;
   end
   
   foreach (m_fields[i]) begin
      rw.value[0] = (reg_value >> m_fields[i].get_lsb_pos()) &
                                 ((1 << m_fields[i].get_n_bits())-1);
      m_fields[i].do_predict(rw, kind, be>>(m_fields[i].get_lsb_pos()/8));
   end

   rw.value[0] = reg_value;

endfunction: do_predict

So, what is rw? In write where do_write is called, rw object is created and initialized with the data passed to write

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;

...
...
...

   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);