Part 4 · TLM & Analysis · Intermediate

Monitor Analysis Wiring: monitor.ap -> Scoreboard/Coverage

Canonical connect_phase wiring from monitor analysis_port to scoreboard and coverage subscribers, with lifecycle checks and debug strategy.

Canonical observation topology

The standard topology is monitor as producer, with scoreboards and coverage as passive consumers. The monitor should not know checker internals; it only publishes observed transactions.

diagram
[MON][TLM][CHECK] canonical topology

 [MON] bus monitor
    └─ ap.write(tr)
          ├─► [CHECK] scoreboard expected/actual logic
          ├─► [CHECK] coverage bins
          └─► [CHECK] optional predictor/model

 monitor stays passive and protocol-focused
 checkers stay consumer-focused
systemverilog
class my_agent extends uvm_agent;
  `uvm_component_utils(my_agent)
  my_monitor mon;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    mon = my_monitor::type_id::create("mon", this);
  endfunction
endclass
diagram
[CHECK] separation of concerns

 monitor:
   decode bus activity into transactions

 scoreboard:
   compare expected vs observed behavior

 coverage:
   collect scenario statistics and crosses
  • Keep monitor logic protocol-centric and checker-agnostic.

  • Use analysis fan-out to avoid bespoke branching in monitor code.

  • Treat scoreboard and coverage as independent consumers.


connect_phase wiring patterns

Perform analysis connections in connect_phase after all components are built. This keeps topology setup explicit and debuggable.

systemverilog
class my_env extends uvm_env;
  `uvm_component_utils(my_env)
  my_agent      agt;
  my_scoreboard sb;
  my_cov_sub    cov;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agt = my_agent::type_id::create("agt", this);
    sb  = my_scoreboard::type_id::create("sb", this);
    cov = my_cov_sub::type_id::create("cov", this);
  endfunction

  function void connect_phase(uvm_phase phase);
    agt.mon.ap.connect(sb.actual_in);
    agt.mon.ap.connect(cov.analysis_export);
  endfunction
endclass
diagram
[TLM] phase placement checklist

 build_phase:
   create monitor/checkers/subscribers

 connect_phase:
   connect monitor.ap -> consumer endpoints

 run_phase:
   monitor writes observations
   consumers ingest/check/sample
diagram
[MON][CHECK] topology validation

 before run:
   assert handles not null
   print connection map at UVM_LOW

 during run:
   confirm each consumer sees first N transactions
  • Connections belong in connect_phase for predictable lifecycle behavior.

  • Avoid hidden runtime dynamic connects unless thoroughly justified.

  • Add early sanity logs so missing links fail fast.


Transaction safety across multiple consumers

When one monitor stream feeds many consumers, decide and document whether transactions are immutable or clone-on-consume. This prevents subtle cross-consumer interference.

diagram
[MON][CHECK] transaction safety policy

 Policy A: immutable monitor txn objects
   + low overhead
   - requires strict team discipline

 Policy B: clone in each subscriber
   + local mutation safe
   - more memory/time overhead

 Policy C: clone once in monitor, pass snapshots
   + central control
   - monitor becomes heavier
systemverilog
function void write(my_txn t);
  my_txn local;
  local = t.clone();
  // Subscriber-specific normalization
  local.addr = normalize_addr(local.addr);
  q.push_back(local);
endfunction
diagram
[CHECK] debugging symptom map

 symptom: coverage bins shifted unexpectedly
 possible root: scoreboard mutating shared transaction

 symptom: random compare mismatches
 possible root: one consumer edits transaction before others use it
  • Pick one transaction ownership policy and enforce it consistently.

  • Clone before local mutation in mixed-consumer topologies.

  • Cross-consumer side effects are common if policy is undefined.


Walkthrough: practical monitor wiring debug

If scoreboard is silent, debug in layers: monitor production, connection correctness, and consumer ingestion. This is usually faster than deep waveform-first debugging.

systemverilog
task smoke_analysis_path(my_env env);
  // monitor emits at least one transaction
  wait (env.agt.mon.sample_count > 0);

  // consumer confirms ingestion
  wait (env.sb.actual_seen > 0);
  wait (env.cov.sample_count > 0);

  `uvm_info("AN_PATH_OK", "analysis wiring appears active", UVM_LOW)
endtask
diagram
[MON][TLM][CHECK] triage order

 1) monitor sample_count increasing?
 2) connect_phase has expected connect calls?
 3) consumer write() counters increasing?
 4) compare logic behaving as intended?

 stop at first failing boundary

Key takeaways

  • Monitor-to-scoreboard/coverage wiring is the central analysis topology in UVM.

  • Perform connects in connect_phase and verify path activity early in run.

  • Define transaction ownership/mutation policy before scaling subscribers.

  • Layered triage quickly isolates missing-wire vs bad-checker issues.

Common pitfalls

  • Connecting in ad-hoc places that depend on fragile build ordering.

  • Assuming monitor activity implies consumer ingestion without counters/logs.

  • Skipping transaction safety policy and debugging random downstream behavior.

  • Overcoupling monitor with checker internals through direct method calls.