Post_predict callback getting call twice in case reg sequence

In my DV environment we are having UVM RAL model created. And behavior of register are dependent on value of other register.
So we chose to add call backs like post_predict to register fields i.e.


// cbs
class my_cb extends uvm_reg_cbs;
 ..
 function void post_predict(...);
   ..
   `uvm_info("my_cb", "in post predict"); // print to display
   ..
 endfunction

endclass

// in env, registering reg field for callback
uvm_reg_field fld;
my_cb cb0;

// fld has handle register field 
cb0 = my_cb::type_id::create("cb0");
uvm_callback#(uvm_reg_field, uvm_reg_cbs)::add(fld, cb0);

// by default auto prediction is OFF only, so explicit prediction happens
// we have connected our monitor output to predictor bus_in
mon.ap.connect(prdc.bus_in);
// rest all ral model connection are okay including adapter and setting map and sequencer


// we have two types of sequences to write registers: normal frontdoor seq as well as register sequences
// non reg seq, writing directly using frontdoor seq
fd_wr_seq.start(my_sqr); 
// here when write to register completes, and monitor sends transaction over ap to predictor bus_in,
// as expected fld post_predict gets called and print "in post predict" displayed ONCE
// when register do_predict get's called in predictor:

  142   virtual function void write(BUSTYPE tr);
    ...
  216               rg.do_predict(reg_item, predict_kind, rw.byte_en);
  217               if(reg_item.kind == UVM_WRITE)
  218                 `uvm_info("REG_PREDICT", {"Observed WRITE transaction to register ",
  219                          ir.get_full_name(), ": value='h",
  220                          $sformatf("%0h",reg_item.value[0]), " : updated value = 'h", 
  221                          $sformatf("%0h",ir.get())},UVM_HIGH)

// we are also able to see above "Observed WRITE transaction to register" print too after "in post predict" displayed 

// in reg seq, writing to register having above field
write_reg(rg, status, data); 
// here we are seeing "in post predict" displayed TWICE


As per debug with UVM_FULL, to see what exactly happening in UVM RAL.
It seems that similar to usual non-reg frontdoor sequence we are able to see “Observed WRITE transaction to register” print too after “in post predict” displayed

However there are following additional observations:


// write_reg implicitly is calling write through frontdoor access and calls following:

//uvm_reg::do_write(..)
 2269          else begin : built_in_frontdoor
 2270 
 2271             rw.local_map.do_write(rw);
 2272 
 2273          end

// in uvm_reg_map, finally do_bus_write function gets called which initiates transaction to sequencer

 1804 task uvm_reg_map::do_bus_write (uvm_reg_item rw,
 1805                                 uvm_sequencer_base sequencer,
 1806                                 uvm_reg_adapter adapter);
      .... 
 1889       bus_req.set_sequencer(sequencer);
 1890       rw.parent.start_item(bus_req,rw.prior);
 1891 
 1892       if (rw.parent != null && i == 0)
 1893         rw.parent.mid_do(rw);
 1894 
 1895       rw.parent.finish_item(bus_req);
 1896       bus_req.end_event.wait_on();
 1897 
 1898       if (adapter.provides_responses) begin
 1899         uvm_sequence_item bus_rsp;
 1900         uvm_access_e op;
 1901         // TODO: need to test for right trans type, if not put back in q
 1902         rw.parent.get_base_response(bus_rsp);
 1903         adapter.bus2reg(bus_rsp,rw_access);
 1904       end
 1905       else begin
 1906         adapter.bus2reg(bus_req,rw_access);
 1907       end
 1908 
 1909       if (rw.parent != null && i == addrs.size()-1)
 1910         rw.parent.post_do(rw);
 1911 
 1912       rw.status = rw_access.status;
 1913 
 1914       `uvm_info(get_type_name(),
 1915          $sformatf("Wrote 'h%0h at 'h%0h via map \"%s\": %s...",
 1916             data, addrs[i], rw.map.get_full_name(), rw.status.name()), UVM_FULL)

// so we are able to observed above "Wrote 'h<value> at 'h<addr> via map" display

// once control returns back to uvm_reg it further executes following code:
 2271             rw.local_map.do_write(rw);
 2272 
 2273          end
 2274 
 2275          m_is_busy = 0;
 2276 
 2277          if (system_map.get_auto_predict()) begin
 2278             uvm_status_e status;
 2279             if (rw.status != UVM_NOT_OK) begin
 2280                sample(value, -1, 0, rw.map);
 2281                m_parent.XsampleX(map_info.offset, 0, rw.map);
 2282             end
 2283 
 2284             status = rw.status; // do_predict will override rw.status, so we save it here
 2285             do_predict(rw, UVM_PREDICT_WRITE);
 2286             rw.status = status;
 2287          end
 2288       end
 2289       
 2290    endcase
 2291 
 2292    value = rw.value[0];
 2293 
 2294    // POST-WRITE CBS - REG
 2295    for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
 2296       cb.post_write(rw);
 2297    post_write(rw);
 2298 
 2299    // POST-WRITE CBS - FIELDS
 2300    foreach (m_fields[i]) begin
 2301       uvm_reg_field_cb_iter cbs = new(m_fields[i]);
 2302       uvm_reg_field f = m_fields[i];
 2303       
 2304       rw.element = f;
 2305       rw.element_kind = UVM_FIELD;
 2306       rw.value[0] = (value >> f.get_lsb_pos()) & ((1<<f.get_n_bits())-1);
 2307       
 2308       for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
 2309          cb.post_write(rw);
 2310       f.post_write(rw);
 2311    end
 2312    
 2313    rw.value[0] = value;
 2314    rw.element = this;
 2315    rw.element_kind = UVM_REG;
 2316 
 2317    // REPORT
 2318    if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin
 2319      string path_s,value_s;
 2320      if (rw.path == UVM_FRONTDOOR)
 2321        path_s = (map_info.frontdoor != null) ? "user frontdoor" :
 2322                                                {"map ",rw.map.get_full_name()};
 2323      else
 2324        path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor";
 2325 
 2326      value_s = $sformatf("=0x%0h",rw.value[0]);
 2327 
 2328       uvm_report_info("RegModel", {"Wrote register via ",path_s,": ",
 2329                                    get_full_name(),value_s}, UVM_HIGH);
 2330    end

// NOW, this is code where things didn't went as expected .. 

>> // so we are able to observed above "Wrote 'h<value> at 'h<addr> via map" display
// after seeing display from uvm_reg_map, we expected next display from uvm_reg above line 2328
// i.e. "Write register via "
// but instead we are seeing additional call to post_predict(seeing display too) BEFORE we seeing "Write register via "


We haven’t set auto prediction to 1, so default is expected to be 0.
Can someone guide here from where fld.post_predict callback is happening between line 2271 to 2328 of uvm_reg.svh

Sincere apologies for putting up big code here.
I am trying to reproduce issue in smaller setup, if required can try to share.
Meanwhile any insights will be really helpful.
Thanks.

In reply to bhupeshpaliwal:
Can I seek some experts suggestion here ?