Part 9 · Register Model (RAL) · Intermediate
config_db Sharing: Multi-Level Env, One Model
How to keep a single reg_model handle across test, chip_env, and block_env hierarchy layers.
One model handle across hierarchy
Large environments often include test -> chip_env -> subsystem_env -> block_env. If each layer creates its own reg_model instance, frontdoor and mirror state diverge immediately.
Use uvm_config_db to pass one canonical reg_model handle down the hierarchy so every component references the same object tree.
[UVM][RAL] hierarchical sharing pattern
test_top
│ creates reg_model once
▼
chip_env
│ get reg_model from config_db
│ set same handle to subsystems
▼
subsystem_env
│ get same handle
│ set same handle to block envs
▼
block_env/reg_env
│ get same handle
└ bind maps, adapters, predictors
All components point to one model instance.Create-once at top, consume-everywhere below is the safest ownership model.
Log object handles at each level during bring-up to prove identity equality.
Never hide fallback local model creation without a warning/fatal policy.
Reference implementation across three levels
test class (producer)
class soc_reg_test extends uvm_test;
`uvm_component_utils(soc_reg_test)
chip_env env;
soc_reg_root reg_model;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = chip_env::type_id::create("env", this);
reg_model = soc_reg_root::type_id::create("reg_model");
reg_model.build();
reg_model.lock_model();
// publish globally for env tree
uvm_config_db#(soc_reg_root)::set(this, "env*", "reg_model", reg_model);
endfunction
endclasschip_env (pass-through owner)
class chip_env extends uvm_env;
`uvm_component_utils(chip_env)
subsystem_env ss0, ss1;
soc_reg_root reg_model;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ss0 = subsystem_env::type_id::create("ss0", this);
ss1 = subsystem_env::type_id::create("ss1", this);
if (!uvm_config_db#(soc_reg_root)::get(this, "", "reg_model", reg_model))
`uvm_fatal("RAL_CFG", "chip_env missing shared reg_model")
// republish same handle downward
uvm_config_db#(soc_reg_root)::set(this, "ss0*", "reg_model", reg_model);
uvm_config_db#(soc_reg_root)::set(this, "ss1*", "reg_model", reg_model);
endfunction
endclassreg_env (consumer)
class reg_env extends uvm_env;
`uvm_component_utils(reg_env)
soc_reg_root reg_model;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(soc_reg_root)::get(this, "", "reg_model", reg_model))
`uvm_fatal("RAL_CFG", "reg_env did not receive shared reg_model")
endfunction
endclassIdentity checks and anti-patterns
Identity assertion helper
function void check_model_identity(string who, soc_reg_root m);
if (m == null)
`uvm_fatal("RAL_CFG", {who, ": reg_model is null"})
`uvm_info("RAL_CFG", $sformatf("%s reg_model handle=%0p", who, m), UVM_LOW)
endfunctionAnti-pattern: silent local fallback
// Avoid this pattern in deep envs:
if (!uvm_config_db#(soc_reg_root)::get(this, "", "reg_model", reg_model)) begin
// BAD: creates hidden second model and causes divergence
reg_model = soc_reg_root::type_id::create("reg_model_local");
reg_model.build();
reg_model.lock_model();
end[UVM][RAL] divergence symptom map
Symptom: block_env mirror differs from test mirror
Likely cause: multiple model instances
Symptom: one reg sequence works in ss0 but fails in ss1
Likely cause: ss1 created its own fallback model
Symptom: predictor appears connected but mirror checks still stale
Likely cause: predictor bound to different model instanceKey takeaways
Multi-level envs must share exactly one reg_model instance.
Use config_db get/fatal pattern; avoid silent local creation.
Print and compare object handles during bring-up to prove identity.
Common pitfalls
Creating local fallback model in a lower env after get() failure.
Publishing to a narrow path that misses some children.
Sharing root model but accidentally binding predictor to a clone map.