Part 4 · TLM & Analysis · Intermediate
Type Mismatch and $cast Failures: Parameterized Port Compatibility
Debugging TLM type mismatches across parameterized ports/exports/imps and defensive handling of $cast conversion failures.
Why type mismatches happen
Parameterized TLM endpoints must agree on transaction type exactly. Similar-looking classes or inheritance assumptions often break compatibility at connect-time or consume-time.
A typical bug is wiring uvm_analysis_port#(base_txn) to a sink expecting uvm_analysis_imp#(derived_txn, sb) and then trusting implicit conversion.
[TLM] parameter compatibility rule
source endpoint type: T_src
sink endpoint type: T_sink
safe when:
- endpoint signatures match exactly, OR
- sink logic explicitly handles base type + cast checks
unsafe when:
- mismatched typedef aliases hide different payload layouts
- sink assumes derived fields always existclass pkt_base extends uvm_sequence_item;
rand bit [31:0] addr;
`uvm_object_utils(pkt_base)
endclass
class pkt_axi extends pkt_base;
rand bit [7:0] len;
`uvm_object_utils(pkt_axi)
endclassEndpoint generic type is part of the interface contract.
Inheritance does not remove need for defensive cast checks at sinks.
Type aliases can hide drift across packages; audit imports explicitly.
Connect-time and runtime mismatch patterns
Some mismatches fail immediately during connect, while others compile/connect but fail when sink code casts and accesses derived fields.
class mon extends uvm_component;
`uvm_component_utils(mon)
uvm_analysis_port #(pkt_base) ap;
endclass
class sb extends uvm_component;
`uvm_component_utils(sb)
uvm_analysis_imp #(pkt_axi, sb) analysis_export;
function void write(pkt_axi t);
// expects AXI-specific fields
`uvm_info("SB", $sformatf("len=%0d", t.len), UVM_MEDIUM)
endfunction
endclass[UVM][TLM] mismatch manifestation
case A: hard mismatch at connect
mon.ap (pkt_base) -> sb.analysis_export (pkt_axi) may reject
case B: permissive chain with runtime cast
sink write(pkt_base t):
if (!$cast(ax, t)) -> drop or fatal depending policyfunction void write(pkt_base t);
pkt_axi ax;
if (!$cast(ax, t)) begin
`uvm_error("TLM_CAST",
$sformatf("Expected pkt_axi got %s", t.get_type_name()))
return;
end
process_axi(ax);
endfunctionPrefer base-type sink signatures when heterogeneous producers are expected.
Convert with explicit $cast and a clear policy on failure.
Log actual type names in errors to speed triage.
Defensive design for mixed transaction families
When one sink handles multiple transaction types, route by type and keep per-type handlers small and explicit.
class proto_scoreboard extends uvm_component;
`uvm_component_utils(proto_scoreboard)
uvm_analysis_imp #(pkt_base, proto_scoreboard) analysis_export;
function void write(pkt_base t);
pkt_axi ax;
pkt_apb apb;
if ($cast(ax, t)) begin
handle_axi(ax);
return;
end
if ($cast(apb, t)) begin
handle_apb(apb);
return;
end
`uvm_warning("TLM_CAST",
$sformatf("Unhandled type %s", t.get_type_name()))
endfunction
endclass[UVM][TLM] cast-policy ladder
strict mode:
unknown type -> UVM_FATAL
bring-up mode:
unknown type -> UVM_WARNING + counter++
regression mode:
unknown type budget threshold -> fail testint cast_fail_count;
function void report_phase(uvm_phase phase);
if (cast_fail_count > 0)
`uvm_error("TLM_CAST_SUMMARY",
$sformatf("cast failures=%0d", cast_fail_count))
endfunctionCentralize cast policy so behavior is consistent across sinks.
Track cast-failure counts and expose them in report_phase.
Avoid silent return on cast failure without diagnostics.
Type-debug checklist
When a transaction disappears, verify endpoint type declarations first, then validate runtime type names at publish and consume points.
[TLM] fast type checklist
1) inspect producer endpoint declaration type
2) inspect sink endpoint declaration type
3) inspect intermediate export typedefs/aliases
4) log t.get_type_name() at producer and sink
5) audit $cast return handling
6) verify clone/copy preserve derived fieldsfunction void publish(pkt_base t);
`uvm_info("TLM_TYPE",
$sformatf("publish type=%s", t.get_type_name()), UVM_HIGH)
ap.write(t);
endfunctionfunction void write(pkt_base t);
`uvm_info("TLM_TYPE",
$sformatf("consume type=%s", t.get_type_name()), UVM_HIGH)
// cast logic...
endfunctionKey takeaways
Parameterized endpoint types define the TLM contract.
Use explicit $cast checks with clear failure policy.
Type-name tracing at both endpoints quickly isolates mismatches.
Mixed-type sinks should route explicitly and report unknowns.
Common pitfalls
Assuming inheritance guarantees sink compatibility automatically.
Ignoring $cast return values and dereferencing invalid handles.
Using overly narrow sink types when multiple producers feed one path.
Losing derived fields in clone/copy and blaming connection logic.