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.

diagram
[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 objection
systemverilog
task 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
endtask

Key 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

systemverilog
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");
endtask
systemverilog
task 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
diagram
[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-friendly
  • Name 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

diagram
[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-protected
systemverilog
function 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")
endfunction
  • Encode quality gates as machine-checked booleans.

  • Treat orchestration failures as flow-contract violations.

  • Keep gates scenario-specific and easy to read in logs.