Part 7 · Environment & Tests · Intermediate
Multi-Agent Orchestration: Dependency Graphs and Barrier Timing
Coordinate APB/AXI/IRQ flows with explicit prerequisites, named barriers, timeout-protected waits, and closure checks.
Dependency-First Modeling
Write orchestration as a dependency graph. Start with ordering facts, then encode those facts as explicit sequence boundaries and event synchronization.
[TEST][UVM] dependency graph
step A:
APB programs DUT mode and threshold
step B:
wait cfg_done event from predictor/model
step C:
AXI starts payload stream
step D:
IRQ watcher arms before fault injection
step E:
APB injects fault command
step F:
wait irq_asserted + scoreboard_quiet
step G:
close scenario and drop objectiontask body();
apb_cfg_seq cfg;
axi_data_seq data;
irq_watch_seq irq;
cfg = apb_cfg_seq::type_id::create("cfg");
data = axi_data_seq::type_id::create("data");
irq = irq_watch_seq::type_id::create("irq");
cfg.start(p_sequencer.apb_sqr_h);
wait_event_or_fatal(cfg_done_e, 2000ns, "cfg_done");
fork
data.start(p_sequencer.axi_sqr_h);
irq.start(p_sequencer.irq_sqr_h);
join
endtaskKey takeaways
Dependency graphs eliminate ambiguous cross-agent timing assumptions.
Parallel branches should start only after prerequisites are satisfied.
Event-based barriers outperform fixed delays for long-term maintenance.
Common pitfalls
Launching child sequences before prerequisite configuration completes.
Guessing settle times with arbitrary delays.
Ignoring timeout protection on wait points.
Barrier and Event Strategy
uvm_event_pool ep;
uvm_event cfg_done_e;
uvm_event stream_done_e;
uvm_event irq_asserted_e;
uvm_event sb_quiet_e;
task pre_start();
ep = uvm_event_pool::get_global_pool();
cfg_done_e = ep.get("cfg_done");
stream_done_e = ep.get("stream_done");
irq_asserted_e = ep.get("irq_asserted");
sb_quiet_e = ep.get("sb_quiet");
endtasktask wait_event_or_fatal(uvm_event ev, time tmo, string name);
wait_cnt++;
if (!ev.try_wait_trigger(tmo)) begin
timeout_cnt++;
`uvm_fatal("ORCH_WAIT", $sformatf("timeout waiting %s (%0t)", name, tmo))
end
`uvm_info("ORCH_WAIT_OK", $sformatf("event=%s", name), UVM_MEDIUM)
endtask[TEST][UVM][ENV] event naming policy
cfg_done
stream_started
stream_done
irq_armed
irq_asserted
scoreboard_quiet
scenario_done
stable names are searchable and tool-friendlyName events by scenario semantics, not by implementation details.
Keep event definitions centralized and reused across sequences.
Always include timeout + event name in fatal diagnostics.
Applied Patterns
[TEST][UVM][VSEQ] orchestration quality gates
gate 1:
config completed before first payload transfer
gate 2:
interrupt watcher armed before fault trigger
gate 3:
no pending scoreboard activity at objection drop
gate 4:
child sequence completion status captured
gate 5:
all waits are timeout-protectedfunction void report_phase(uvm_phase phase);
if (!saw_cfg_before_data)
`uvm_error("ORCH_GATE", "cfg did not complete before data start")
if (!saw_irq_arm_before_fault)
`uvm_error("ORCH_GATE", "irq watcher was not armed before fault")
if (!saw_quiet_before_drop)
`uvm_error("ORCH_GATE", "objection dropped before scoreboard quiet")
endfunctionEncode quality gates as machine-checked booleans.
Treat orchestration failures as flow-contract violations.
Keep gates scenario-specific and easy to read in logs.