Skip to content

UVM

Nested Sequences

The parent-child hierarchy formed when sequences start sub-sequences — how passing the parent (this) makes a sub-sequence a child that inherits sequencer, priority, lock coverage, and lifetime.

Advanced Sequences · Module 10 · Page 10.3

The Engineering Problem

Module 9.5 covered how to run sub-sequences — sequentially or in parallel, with uvm_do. This chapter is about what nesting means: the parent-child hierarchy that forms when sequences start sub-sequences, and the context that flows through it. When a parent's body() starts a child, and the child starts a grandchild, a tree of sequences exists — and that tree is not just an execution order; it's a relationship through which sequencer, priority, lock coverage, and lifetime propagate. Get the relationship wrong — start a sub-sequence without linking it to its parent — and the child is an orphan that inherits none of that context, silently breaking the atomicity or pacing the parent intended.

A sub-sequence becomes a child when it's started with its parentsub.start(sequencer, this), or `uvm_do (which passes this automatically). That linkage establishes the parent-child relationship, and through it the child inherits context: it runs on the parent's sequencer by default, its place in arbitration relates to the parent's, a lock/grab held by the parent covers the child's items (the whole subtree is one unit on the sequencer), and the parent's lifetime spans the child (killing the parent kills the child). This chapter is the nesting hierarchy: the parent-child links, the context that flows down them, and why passing the parent is the one act that turns a sub-sequence from an orphan into a child.

What is the parent-child hierarchy formed by nested sequences, what context flows down it (sequencer, priority, lock coverage, lifetime), and why does passing the parent (this) — making the sub-sequence a child rather than an orphan — determine whether that context is inherited?

Motivation — why nesting is a relationship, not just an order

The parent-child hierarchy matters because nested sequences must behave as a coherent unit, and that requires the relationship — each property of nesting serves it:

  • A nested operation is one logical unit, so it needs a unifying relationship. "Configure-then-burst" implemented as a parent calling two children is one operation; for the sequencer to treat it as one (arbitrate it, lock it, kill it as a unit), the children must be linked to the parent. The parent-child relationship is that link.
  • Children should run where the parent does, so the sequencer is inherited. A sub-sequence almost always belongs on the same sequencer as its parent (same interface). Making the child inherit the parent's sequencer means you don't re-specify it, and the nested operation stays on one interface by default.
  • The parent's exclusivity should cover the children, so locks span the subtree. If a parent grabs the sequencer for an atomic operation built from sub-sequences, the children's items must be covered by that grab — otherwise the "atomic" operation isn't atomic. Lock coverage over the subtree requires the children to be in the subtree (linked to the parent).
  • The parent's lifetime should bound the children, so kill propagates. If a parent sequence is stopped, its children should stop too — a half-run nested operation is worse than none. The parent's lifetime spanning the children (kill propagation) needs the hierarchy.
  • The link is established by passing the parent, so that act is load-bearing. A sub-sequence is made a child by being started with its parent (this). Omit it and the sub-sequence runs un-parented — an orphan that inherits no context. So passing the parent isn't ceremony; it's what creates the relationship that all the inheritance flows through.

The motivation, in one line: a nested operation must behave as a coherent unit on the sequencer — arbitrated, locked, and killed together, on one sequencer — and that requires a parent-child relationship through which sequencer, lock, and lifetime propagate, established by the single act of passing the parent when starting a sub-sequence.

Mental Model

Hold nested sequences as a family tree where children inherit the parent's standing:

Nesting is a family tree: a sub-sequence started as a child inherits the parent's standing — where it lives, its rank, the parent's protections, and the parent's fate — but only if it's actually claimed as a child. A parent sequence that starts a sub-sequence as its child passes down its standing: the child lives in the same house (runs on the parent's sequencer), holds a rank derived from the parent's (priority in arbitration), is sheltered by the parent's protections (a lock the parent holds covers the child too — the family is treated as one), and shares the parent's fate (if the parent is dismissed, the children go with it). This inheritance is what makes a nested operation behave as one family on the sequencer. But the inheritance only happens if the parent claims the childnames it as kin by passing itself (this) when starting it. Start a sub-sequence without claiming it and it's an orphan: it lives somewhere (a sequencer you gave it), but it bears no relation to the parent — none of the parent's standing applies, so the parent's lock doesn't shelter it, and it goes its own way in arbitration even while the parent thought the family was acting as one.

So nesting is claim your children: start a sub-sequence with the parent and it inherits the parent's sequencer, rank, protection, and fate; start it without and it's an orphan that shares none of them. The one act — passing the parent — is what makes the family a family.

The defining picture is a tree of parent-child links: a top sequence whose body() starts children, whose bodies start grandchildren — each linked to its parent.

A nesting tree: top sequence starts children with this; an unparented sub-sequence is an orphan outside the treestart(sqr, this) → childstart(sqr,this) →…start(sqr, this) → childstart(sqr,this) →…start(sqr, this) → grandchildstart(sqr,this) →…start(sqr) → ORPHAN (no this)start(sqr) →ORPHAN (no…top_seq (parent)body() starts childrenchild_alinked child (in tree)child_blinked child (in tree)grandchildlinked under child_aorphan_seqno parent — outside thetree12
Figure 1 — nested sequences form a parent-child tree. A top sequence's body() starts child sub-sequences (passing this as the parent), and each child's body() can start grandchildren the same way. The parent links (get_parent_sequence) form a tree. A sub-sequence started WITH its parent is a linked child, in the tree; one started WITHOUT (no this) is an orphan, outside the tree, even if it runs on the same sequencer. The tree — not just the call order — is what context propagates through.

The figure shows the tree nesting forms, and the crucial distinction between a child and an orphan. The top sequence's body() starts childrenchild_a, child_bwith its parent (start(sqr, this)), which links each child to the top sequence; and child_a in turn starts a grandchild the same way, extending the tree. These parent links (get_parent_sequence) form a navigable hierarchy: every linked sequence knows its parent, and the top sequence's subtree is a coherent set. The contrast is the orphan: a sub-sequence started without the parent (start(sqr) — no this) runs, possibly even on the same sequencer, but it is not in the tree — it has no parent link, so it bears no relationship to the top sequence. The reason this matters, and the whole point of the chapter, is that context propagates through the tree, not through the call order: being called by the top sequence is not enough; the sub-sequence must be linked as a child for the parent's sequencer, priority, lock, and lifetime to apply to it. So the tree drawn by the parent links — not merely "who started whom" — is the structure that governs how nested sequences behave together. A child is in the tree; an orphan is outside it, and the difference is the single argument this.

RTL / Simulation Perspective — starting children vs orphans

The difference between a child and an orphan is one argument when starting a sub-sequence. The code makes it concrete, alongside the context that flows through the link.

nesting: child (linked) vs orphan (un-parented), and inherited context
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class parent_seq extends uvm_sequence #(bus_item);
  `uvm_object_utils(parent_seq)
  task body();
    child_seq c = child_seq::type_id::create("c");
 
    // ── CHILD: started WITH the parent (this) → linked, inherits context ──
    c.start(get_sequencer(), this);     // child runs on the parent's sequencer, as a child
    //   `uvm_do(c)                       // equivalent: uvm_do passes this automatically
 
    // ── ORPHAN: started WITHOUT the parent → un-parented, inherits NOTHING ──
    // c.start(get_sequencer());         // ✗ no this → orphan: parent's lock/priority/lifetime don't apply
 
    // ── inherited context, when linked: ──
    //   sequencer : child runs on get_sequencer() (the parent's) unless another is passed
    //   priority  : the child's arbitration relates to the parent's
    //   lock/grab : a grab the parent holds covers the child's items (one subtree)
    //   lifetime  : if parent_seq is killed, the child is killed too
  endtask
endclass
 
// start signature: task start(uvm_sequencer_base sequencer, uvm_sequence_base parent_sequence = null, ...)
//   parent_sequence = this  → child;   parent_sequence = null (default/omitted) → orphan

The code centers on the start call's second argument, the parent sequence. Starting a child with thisc.start(get_sequencer(), this)links the child to the parent, so the child becomes part of the parent's sequence tree and inherits context. (`uvm_do(c) does the same, passing this automatically — which is why the macros are the safe default: they never orphan.) Starting without thisc.start(get_sequencer()), with parent_sequence defaulting to null — makes the sub-sequence an orphan: it runs, but it's un-parented, so none of the parent's context applies. The inherited context, listed in the comments, is what flows through the link: the sequencer (the child runs on get_sequencer() — the parent's — unless you pass a different one), the priority (the child's arbitration relates to the parent's, Module 9.2), the lock/grab (a grab the parent holds covers the child's items, because they're in the same subtree — the DebugLab), and the lifetime (killing parent_seq kills the child). The shape to carry: the start signature's parent argument is the link — this makes a child that inherits context, null (omitted) makes an orphan that inherits nothing — and `uvm_do always passes this, which is why it's the recommended way to nest.

Verification Perspective — what flows down the tree

The value of the parent-child link is the context it carries. Four things inherit through the tree, and knowing them is knowing why the link matters.

Sequencer, priority, lock, and lifetime flow from parent to child through the nesting linkchild runs on parent's sequencerchild runs onparent's…priority relates to parent'spriorityrelates to…parent's lock covers subtreeparent's lockcovers…kill parent →kill childrenParent sequencecontext sourceSequencer (inherited)child runs where parent doesPriority (related)child's arbitration rankLock/grab (covers subtree)parent's exclusivity shelterschildrenLifetime (spans children)kill parent → kill children12
Figure 2 — four kinds of context flow down the nesting tree. Sequencer: a child runs on the parent's sequencer by default. Priority: the child's arbitration priority relates to the parent's. Lock/grab: exclusivity the parent holds covers the whole subtree's items. Lifetime: the parent's lifetime spans the children — killing the parent kills them. All four propagate through the parent link, so a linked child inherits them and an orphan inherits none. The link is the conduit; passing this connects it.

The four inherited contexts are what make a nested operation a unit, and each flows through the parent link. Sequencer: a linked child runs on the parent's sequencer by default (get_sequencer()), so a nested operation stays on one interface without re-specifying it — you only pass a different sequencer when you deliberately want the child elsewhere. Priority: the child's place in arbitration (Module 9.2) relates to the parent's, so the nested operation competes for the sequencer with a coherent priority rather than the child arbitrating at some unrelated level. Lock/grab: this is the most consequential — exclusivity the parent holds covers the entire subtree, because the children's items are part of the parent's sequence tree on that sequencer; so a parent that grabs the sequencer makes all its descendants' items atomic together. Lifetime: the parent's lifetime spans the children — if the parent is stopped (killed), the children are stopped too, so a nested operation can't be left half-run. The unifying point is that all four propagate through the parent link — they are properties of the tree, not of being called. So a linked child inherits all four and behaves as part of the parent's unit; an orphan, having no link, inherits none — it runs on whatever sequencer it was given, arbitrates independently, is not covered by the parent's lock, and survives the parent's death. The link (passing this) is the conduit for all of this, which is why omitting it doesn't just "skip a nicety" — it severs every inheritance at once.

Runtime / Execution Flow — lock coverage and lifetime through the tree

At run time, the two most visible effects of the tree are lock coverage (a parent's grab covering the subtree) and lifetime (parent kill propagating to children). Both depend entirely on the link.

A parent's grab covers linked children's items; killing the parent kills linked children; orphans are exempt from bothparent grabs → linked children covered (atomic) → parent killed → children killedparent grabs → linked children covered (atomic) → parent killed → children killed1Parent grabs the sequencerclaims exclusivity for the nested operation (Module 9.2).2Linked children's items are coveredchildren started with this are in the subtree → the grab coverstheir items → atomic together.3An orphan child is NOT coveredstarted without this → outside the subtree → its items arbitratenormally and can interleave.4Killing the parent kills linked childrenthe parent's lifetime spans linked children (not orphans) — theystop with it.
Figure 3 — lock coverage and lifetime propagate through the linked tree. When a parent grabs the sequencer and then starts linked children, the children's items are part of the parent's subtree, so the grab covers them — they run atomically with no other sequence interleaving. And if the parent is killed, its linked children are killed with it. Both effects require the children to be in the tree (started with this); an orphan child is not covered by the grab and is not killed with the parent. Coverage and lifetime are tree properties.

The run-time behavior makes the tree's importance concrete through its two most consequential effects. Lock coverage (steps 1–3): when a parent grabs the sequencer (Module 9.2) for an atomic nested operation and then starts linked children, those children's items are part of the parent's subtree, so the grab covers them — the entire nested operation's items run atomically, with no other sequence interleaving. But an orphan child (step 3) is not in the subtree, so the parent's grab does not cover it — the orphan's items arbitrate normally and can interleave with other sequences, breaking the atomicity the parent's grab was meant to provide (exactly the DebugLab). Lifetime (step 4): the parent's lifetime spans its linked children, so killing the parent kills them too — a nested operation stops as a unit; but an orphan, having no link, would survive the parent's death. Both effects are tree properties: they apply to linked descendants and not to orphans, because both flow through the parent link. This is why nesting is a relationship, not just an order: whether a sub-sequence is covered by the parent's lock and bounded by the parent's lifetime depends entirely on whether it's in the tree — which depends entirely on whether it was started with this. The runtime view shows the stakes: an un-parented sub-sequence silently escapes the parent's exclusivity and lifetime, so the nested operation neither stays atomic nor stops as a unit.

Waveform Perspective — a parent's grab covering nested children

The tree's lock coverage is visible on a timeline: a parent grabs the sequencer, and its linked children's items all run atomically under that grab — but an orphan child's item interleaves.

A parent's grab covers linked children's items, but not an orphan's

12 cycles
A parent's grab covers linked children's items, but not an orphan'sparent grabs → linked children (P-c1, P-c2) run atomically under the grabparent grabs → linked …grab releasedgrab releasedorphan child (ORPH) not in subtree → arbitrates normallyorphan child (ORPH) no…another sequence's item (X) interleaves the orphan — no coverageanother sequence's ite…clkgrabitemP-c1P-c1P-c2P-c2--ORPHXORPHX------coveredt0t1t2t3t4t5t6t7t8t9t10t11
Figure 4 — lock coverage through the tree. The parent grabs the sequencer (grab high). Its linked children's items (item shows P-c1, P-c2 — the parent's subtree) run back-to-back atomically, because the grab covers the subtree. But an orphan child's item (ORPH), started without this, is NOT in the subtree, so it arbitrates normally and an OTHER sequence's item (X) interleaves around it. Linked children are sheltered by the parent's grab; the orphan is exposed. Coverage follows the tree, not the call order.

The waveform shows coverage following the tree. While the parent holds the grab (high on the left), its linked children's items — P-c1, P-c2, the parent's subtree — run back-to-back with the covered signal high: because the children are in the tree, the parent's grab covers them, so the whole nested operation's items are atomic, with nothing interleaving. Then the grab is released. The orphan child's items (ORPH), started without this, run later and are not covered — covered is low — so they arbitrate normally, and another sequence's item (X) interleaves between them. The visual contrast is the point: linked children's items form an uninterrupted block under the parent's grab, while the orphan's items are exposed to interleaving just like any independent sequence. The grab didn't behave differently — it covered the subtree, and the orphan simply wasn't in it. So the waveform makes the tree's reality concrete: coverage is a property of the tree, and a sub-sequence is sheltered by the parent's grab only if it's a linked child. The same nested operation is atomic when its sub-sequences are children and interleaved when one is an orphan — and the only difference is the this that was, or wasn't, passed when starting it.

DebugLab — the atomic operation an orphan sub-sequence broke

A nested operation that lost atomicity because a sub-sequence was started without its parent

Symptom

A parent sequence implemented an atomic read-modify-write as three sub-sequences and grabbed the sequencer to keep them together. Two of the sub-sequences ran atomically as intended, but the third had another sequence's transaction interleave into the middle of it — intermittently corrupting the operation, exactly as if the grab weren't held. The grab was held (the first two sub-sequences were protected), and the third sub-sequence was correct on its own. Only that one sub-sequence escaped the grab's protection.

Root cause

The third sub-sequence was started without passing the parent (this), so it was an orphan — not in the parent's subtree — and the parent's grab did not cover it:

why one sub-sequence escaped the parent's grab
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
parent_seq::body():
  grab(get_sequencer());                          // grab the sequencer for atomicity
  read_seq.start (get_sequencer(), this);         // ✓ child → covered by grab
  modify_seq.start(get_sequencer(), this);        // ✓ child → covered by grab
  write_seq.start(get_sequencer());               // ✗ NO this → ORPHAN → NOT covered by grab
  ungrab(get_sequencer());
 
→ read_seq and modify_seq are in the parent's subtree → the grab covers their items
  write_seq is un-parented (orphan) → NOT in the subtree → grab does NOT cover it
  → write_seq's items arbitrate normally → another sequence's item interleaves → atomicity broken
 
fix — start EVERY sub-sequence WITH the parent (this), so all are children under the grab:
  write_seq.start(get_sequencer(), this);         // ✓ now a child → covered by the grab
  // or use `uvm_do(write_seq), which passes this automatically

This is the orphan-escapes-the-grab bug, and it's a nesting bug, not a lock bug. A grab covers the grabbing sequence's subtree — every sub-sequence that is a linked child (or descendant) of the grabber. The parent grabbed the sequencer and started the first two sub-sequences with this, so they were children in the parent's subtree, and the grab covered their items — atomic. But the third sub-sequence was started without this (write_seq.start(get_sequencer())), so it was an orphan: it ran on the same sequencer but was not in the parent's subtree, and therefore not covered by the parent's grab. Its items arbitrated normally, so another sequence's transaction interleaved into the read-modify-write, breaking the atomicity — intermittently, because it depends on whether another sequence happened to have an item ready. The telltale is exactly this: most of a nested atomic operation is protected and one part isn't, which points not at the grab (it's held and working) but at one sub-sequence not being a child. The fix is to start every sub-sequence with this (or use `uvm_do, which always passes it), so all of them are children in the subtree the grab covers. The general lesson, and the chapter's thesis: a sub-sequence inherits the parent's context — including lock coverageonly if it's linked as a child by passing the parent; an orphan escapes the parent's grab, lifetime, and priority, so always pass the parent (or use `uvm_do) when nesting.

Diagnosis

The tell is part of a nested atomic operation protected and part not. Diagnose orphan bugs:

  1. Confirm the grab is held. If some sub-sequences are atomic, the grab is working — so the problem is one sub-sequence not being covered, i.e., not a child.
  2. Check each sub-sequence's start for the parent argument. Find the sub-sequence whose items interleave and confirm whether it was started with this. A start(sqr) without this is the orphan.
  3. Prefer `uvm_do to spot omissions. Sub-sequences started with `uvm_do always pass this; a hand-written start is where the parent is forgotten.
  4. Correlate with intermittency. Interleaving that depends on another sequence having an item ready is non-deterministic — the signature of an orphan escaping the grab, versus a deterministic logic bug.
Prevention

Always link sub-sequences to their parent:

  1. Pass this when starting any sub-sequence. sub.start(sequencer, this) makes it a child that inherits context (sequencer, priority, lock coverage, lifetime); omitting this orphans it.
  2. Prefer `uvm_do / `uvm_do_on. They pass the parent automatically, so a sub-sequence can't accidentally be orphaned — the safest default for nesting.
  3. Audit hand-written start calls. Where you must call start directly, verify the parent argument is present — this is where orphans are introduced.
  4. Test atomicity under contention. Run the nested atomic operation concurrently with other traffic; an orphan sub-sequence's interleaving surfaces only when another sequence competes.

The one-sentence lesson: a sub-sequence inherits the parent's context — sequencer, priority, lock coverage, and lifetime — only if it's started as a child by passing the parent (this), so a sub-sequence started without this is an orphan that escapes the parent's grab (and lifetime), breaking a nested atomic operation; always pass the parent, or use `uvm_do, which does it for you.

Common Mistakes

  • Starting a sub-sequence without passing the parent (this). It becomes an orphan that inherits no context — the parent's lock won't cover it, its lifetime won't bound it. Pass this (or use `uvm_do).
  • Assuming "called by the parent" means "child of the parent." Context flows through the parent link, not the call. A sub-sequence is a child only if started with the parent.
  • Expecting a parent's grab to cover an orphan. A grab covers the grabber's subtree; an orphan isn't in it, so its items interleave. Link all sub-sequences of an atomic operation.
  • Re-specifying the sequencer unnecessarily. A linked child runs on the parent's sequencer by default; only pass a different one when you mean the child to run elsewhere.
  • Forgetting that killing a parent kills linked children. The parent's lifetime spans linked children; rely on this for clean teardown, but don't expect it for orphans.
  • Hand-writing start where `uvm_do would do. The macros pass the parent automatically; hand-written start is where the parent argument gets forgotten.

Senior Design Review Notes

Interview Insights

A sub-sequence becomes a child when it's started with its parent passed in — sub.start(sequencer, this) — or via the uvm_do macros, which pass this automatically. That second argument to start, the parent sequence, is what links the sub-sequence into the parent's sequence tree. It matters because context flows through that link, not through the call order: being called by the parent isn't enough; the sub-sequence must be linked as a child for the parent's context to apply. What flows through the link is the sequencer (a linked child runs on the parent's sequencer by default), the priority (the child's arbitration relates to the parent's), the lock coverage (a grab the parent holds covers the child's items because they're in the same subtree), and the lifetime (killing the parent kills the linked children). So a linked child behaves as part of the parent's unit — arbitrated, locked, and killed together — which is exactly what you want when a nested operation should be one coherent thing. If you start a sub-sequence without passing the parent, the parent argument defaults to null and the sub-sequence is an orphan: it runs, possibly on the same sequencer, but it bears no relationship to the parent, so none of that context applies. The consequence is that an orphan escapes the parent's grab — its items arbitrate normally and can interleave with other sequences — and survives the parent's death. That's why passing the parent isn't ceremony; it's the single act that establishes the relationship all the inheritance flows through, and why uvm_do, which always passes this, is the safe default for nesting.

Four things flow down the parent link to a linked child. The sequencer: a child runs on the parent's sequencer by default, reached via get_sequencer, so a nested operation stays on one interface without re-specifying it, and you only pass a different sequencer when you deliberately want the child elsewhere. The priority: the child's place in the sequencer's arbitration relates to the parent's, so the nested operation competes for the sequencer coherently rather than the child arbitrating at some unrelated level. The lock or grab coverage: this is the most consequential — exclusivity the parent holds covers the entire subtree, because the children's items are part of the parent's sequence tree on that sequencer, so a parent that grabs the sequencer makes all its descendants' items atomic together. And the lifetime: the parent's lifetime spans the children, so if the parent is stopped or killed, the linked children are stopped too, meaning a nested operation can't be left half-run. All four are properties of the tree, propagating through the parent link, so a linked child inherits all of them and an orphan — a sub-sequence started without the parent — inherits none: it runs on whatever sequencer it was given, arbitrates independently, isn't covered by the parent's lock, and survives the parent's death. This is why the link is described as the conduit for context: passing this connects it, and omitting it severs all four inheritances at once. The practical takeaway is that to make a nested operation behave as one unit — on one sequencer, with one priority, atomic under a grab, bounded by one lifetime — every sub-sequence must be a linked child.

Exercises

  1. Link the children. Write a parent body() that grabs the sequencer and runs three sub-sequences atomically, ensuring all three are linked children — and show the one-argument difference that would orphan one.
  2. Trace the inheritance. List the four kinds of context a linked child inherits, and what an orphan gets instead for each.
  3. Diagnose the interleave. A grabbed nested operation has one sub-sequence interleaved while the others are atomic. Name the cause and the fix.
  4. Lifetime. Explain what happens to linked children versus an orphan when the parent sequence is killed, and why.

Summary

  • Nested sequences form a parent-child tree when a sequence's body() starts sub-sequences; a sub-sequence becomes a child only when started with its parentsub.start(sequencer, this) or `uvm_do (which passes this).
  • Context flows down the tree, not the call order: a linked child inherits the parent's sequencer (runs where the parent does), priority (arbitration relates to the parent's), lock/grab coverage (the parent's exclusivity covers the subtree), and lifetime (killing the parent kills the child).
  • An orphan inherits none of it: a sub-sequence started without the parent runs un-parented — not covered by the parent's lock, not bounded by its lifetime, arbitrating independently — even on the same sequencer.
  • The most consequential effects are lock coverage and lifetime: a parent's grab makes the whole linked subtree's items atomic, and killing the parent stops the linked children — but an orphan escapes both, intermittently breaking a nested atomic operation.
  • The durable rule of thumb: always start a sub-sequence with its parent (sub.start(sequencer, this), or `uvm_do) so it's a linked child that inherits the parent's sequencer, priority, lock coverage, and lifetime — because context propagates through the parent link, and an un-parented orphan silently escapes the parent's grab and lifetime, breaking nested operations that were supposed to act as one unit.

Next — Sequence Arbitration: nesting determines which sequences share a sequencer as one tree; arbitration determines which of the competing sequences (and trees) gets the sequencer next — the next chapter goes deeper on arbitration policies, priorities, and how the sequencer chooses among contending sequences.