I
uvm_predictor
is UVM way to determine the value of registers model by monitoring the bus in case someone other than reg model is changing the registers. The usual boilerplate code looks something like this:
predict.map = regmodel.default_map;
predict.adapter = reg2rw; // reg2rw is adapter
bus.mon.ap.connect(predict.bus_in);
regmodel.default_map.set_auto_predict(0);
Looking at the source code, The following important variables bus_in
, map
and adapter
.
`uvm_component_param_utils(uvm_reg_predictor#(BUSTYPE))
// Variable: bus_in
//
// Observed bus transactions of type ~BUSTYPE~ are received from this
// port and processed.
//
// For each incoming transaction, the predictor will attempt to get the
// register or memory handle corresponding to the observed bus address.
//
// If there is a match, the predictor calls the register or memory's
// predict method, passing in the observed bus data. The register or
// memory mirror will be updated with this data, subject to its configured
// access behavior--RW, RO, WO, etc. The predictor will also convert the
// bus transaction to a generic <uvm_reg_item> and send it out the
// ~reg_ap~ analysis port.
//
// If the register is wider than the bus, the
// predictor will collect the multiple bus transactions needed to
// determine the value being read or written.
//
uvm_analysis_imp #(BUSTYPE, uvm_reg_predictor #(BUSTYPE)) bus_in;
...
...
// Variable: map
//
// The map used to convert a bus address to the corresponding register
// or memory handle. Must be configured before the run phase.
//
uvm_reg_map map;
// Variable: adapter
//
// The adapter used to convey the parameters of a bus operation in
// terms of a canonical <uvm_reg_bus_op> datum.
// The <uvm_reg_adapter> must be configured before the run phase.
//
uvm_reg_adapter adapter;
The class has one function write
connected to the bus_in
analysis imp above.
virtual function void write(BUSTYPE tr);
uvm_reg rg;
uvm_reg_bus_op rw;
if (adapter == null)
`uvm_fatal("REG/WRITE/NULL","write: adapter handle is null"
First use adapter to get the rw transaction and look up the register by address
// In case they forget to set byte_en
rw.byte_en = -1;
adapter.bus2reg(tr,rw);
rg = map.get_reg_by_offset(rw.addr, (rw.kind == UVM_READ));
Next, use the map to get local_map
local_map = rg.get_local_map(map,"predictor::write()");
map_info = local_map.get_reg_map_info(rg);
ir=($cast(ireg, rg))?ireg.get_indirect_reg():rg;
...
...
foreach (map_info.addr[i]) begin
if (rw.addr == map_info.addr[i]) begin
found = 1;
reg_item.value[0] |= rw.data << (i * map.get_n_bytes()*8);
predict_info.addr[rw.addr] = 1;
...
...
end
And eventually calling RAL function to do the magic
ir.XsampleX(reg_item.value[0], rw.byte_en,
reg_item.kind == UVM_READ, local_map);
...
...
...
rg.do_predict(reg_item, predict_kind, rw.byte_en);