Part 9 · Register Model (RAL) · Intermediate
Environment Build Checklist: Numbered Integration Steps
Deterministic step-by-step order for building and validating a RAL-enabled environment.
Why strict ordering matters
Register integration fails when objects are created in an ad-hoc order. A deterministic checklist makes build failures reproducible and keeps bring-up time low.
[UVM][RAL] build order timeline
1) create bus agent
2) create adapter
3) create predictor
4) get or create reg_model
5) reg_model.build()
6) reg_model.lock_model()
7) optional HDL path setup
8) publish reg_model via config_db
9) connect map/sequencer/adapter in connect_phase
10) connect monitor to predictor
11) run smoke register write + mirror checkNumbered integration steps
Create protocol agent(s) first so sequencer handles exist before connect.
Create one adapter instance and keep it for both set_sequencer and predictor.adapter.
Create predictor in build_phase, assign map/adapter in connect_phase.
Try config_db get for reg_model before creating a new model.
If get fails, create model, call build(), then lock_model().
Set HDL paths in model build when backdoor is required.
Publish the same model handle with config_db::set for downstream components.
In connect_phase, bind default_map to sequencer using set_sequencer().
Disable auto_predict when explicit predictor flow is used.
Connect monitor analysis port to predictor.bus_in.
Run one known write/read/mirror smoke test immediately after bring-up.
If any step is skipped, later errors often appear far from the root cause.
Do not defer model build/lock to run_phase; keep structural setup in build_phase.
Keep checklist visible in comments or project docs for new engineers.
Reference build_phase skeleton
class reg_env extends uvm_env;
`uvm_component_utils(reg_env)
apb_agent apb;
my_reg_block reg_model;
apb_reg_adapter adapter;
uvm_reg_predictor #(apb_item) predictor;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 1-3: core infrastructure
apb = apb_agent::type_id::create("apb", this);
adapter = apb_reg_adapter::type_id::create("adapter");
predictor = uvm_reg_predictor#(apb_item)::type_id::create("predictor", this);
// 4-6: obtain or create one shared model
if (!uvm_config_db#(my_reg_block)::get(this, "", "reg_model", reg_model)) begin
reg_model = my_reg_block::type_id::create("reg_model");
reg_model.build();
reg_model.lock_model();
end
// 7: optional model-level setup
// reg_model.add_hdl_path("tb_top.dut");
// 8: publish for children
uvm_config_db#(my_reg_block)::set(this, "*", "reg_model", reg_model);
endfunction
endclassChecklist assertions you can add
function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
if (reg_model == null)
`uvm_fatal("RAL_CFG", "reg_model is null after build_phase")
if (!reg_model.is_locked())
`uvm_fatal("RAL_CFG", "reg_model must be lock_model()'d before run")
endfunctionUse early fatal checks for null model and unlocked model.
Publishing reg_model in build_phase allows agents/sub-envs to consume it immediately.
Avoid lazy creation in connect_phase; structural ownership becomes unclear.
Bring-up smoke sequence
Run a minimal smoke immediately after environment creation to validate the checklist end-to-end.
task run_phase(uvm_phase phase);
uvm_status_e status;
uvm_reg_data_t data;
phase.raise_objection(this);
// frontdoor write through sequencer+adapter
env.reg_model.ctrl.write(status, 32'h0000_0001, UVM_FRONTDOOR, .parent(this));
if (status != UVM_IS_OK)
`uvm_fatal("RAL_SMOKE", "frontdoor write failed")
// frontdoor read should return same value
env.reg_model.ctrl.read(status, data, UVM_FRONTDOOR, .parent(this));
if (status != UVM_IS_OK)
`uvm_fatal("RAL_SMOKE", "frontdoor read failed")
// mirror check proves predictor flow
env.reg_model.ctrl.mirror(status, UVM_CHECK, UVM_FRONTDOOR, .parent(this));
if (status != UVM_IS_OK)
`uvm_error("RAL_SMOKE", "mirror check mismatch in smoke")
phase.drop_objection(this);
endtaskKey takeaways
A numbered checklist converts RAL bring-up from guesswork to repeatable setup.
Create/fetch model, build, lock, bind map, wire predictor, then smoke test.
Smoke mirror check should run on day one of integration.
Common pitfalls
Skipping smoke and discovering setup bugs only during long regressions.
Calling lock_model too late after sequences already started.
Creating adapter/predictor after connect_phase and missing bindings.