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.