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