Skip to content

UVM

Layered Sequences

Building a protocol stack in stimulus — a high-level sequence produces high-level transactions that a translation (layering) sequence decodes into low-level transactions, so each protocol layer is written independently.

Advanced Sequences · Module 10 · Page 10.2

The Engineering Problem

The previous chapter coordinated stimulus across parallel interfaces (Module 10.1). This one goes the other direction — down, through abstraction levels of a single interface. Many protocols are layered: a packet sits on frames, a frame on bytes, a transaction on bus beats. If a sequence had to generate the lowest-level items directly — hand-encoding every packet into bytes — the high-level intent would be buried in encoding detail, and the encoding couldn't be reused or swapped. Real protocol stimulus needs protocol layers: write at the level you mean (packets), and have a translation turn it into the level the wires use (bytes).

Layered sequences are that protocol stack, in stimulus. A high-level sequence produces high-level transactions (packets) on an upper sequencer. A layering (translation) sequence on the lower sequencer pulls each high-level transaction, translates it into one or more low-level transactions (the bytes/frames that encode it), and drives them through the low-level handshake. So the high-level protocol is written independently of the low-level encoding, and the translation — the protocol mapping — is isolated in one adapter sequence. Swap the low-level encoding and only the translation changes; the packet-level sequences are untouched. This chapter is layered sequences: the stack, the translation sequence that bridges layers, how the upper sequencer feeds the lower, and why an incomplete translation silently corrupts the protocol.

How do layered sequences build a protocol stack in stimulus — a high-level sequence producing high-level transactions, a translation sequence decoding them into low-level transactions — so each layer is written independently, and what happens when the translation is incomplete?

Motivation — why stimulus needs protocol layers

Layered sequences exist because layered protocols need layered stimulus, and each property of the pattern serves that:

  • Protocols are layered, so stimulus should mirror them. A packet protocol is a stack — packets over frames over bytes. Writing stimulus that mirrors the stack (a packet sequence, a translation, a byte driver) keeps each level's logic at its own level, instead of collapsing the whole stack into one sequence hand-encoding bytes.
  • High-level intent should be written high, so the upper sequence speaks packets. A test means "send this packet," not "drive these 64 bytes in this framing." Letting the high-level sequence produce packets keeps the test's intent legible and the high-level sequences reusable across encodings.
  • Encoding should be isolated, so the translation is one adapter. The packet→bytes mapping is one concern that belongs in one place. A translation sequence holds it, so the encoding logic isn't smeared across every high-level sequence — and changing the encoding touches only the translation.
  • Layers should be swappable, so they're decoupled. Because the high-level sequence produces packets and the translation produces bytes, you can swap the low layer (a different framing, a different bus) by rewriting only the translation — the packet sequences carry over, exactly like reusing an application protocol over a different link layer.
  • The upper sequencer is a source, so the lower layer pulls from it. The high-level transactions have to get to the translation. The upper sequencer acts as a source the translation sequence pulls from (rather than being connected to a driver), so high-level items flow down into the translation on demand.

The motivation, in one line: layered protocols need stimulus that mirrors the stack, so layered sequences put high-level intent in a high-level sequence (packets), isolate the encoding in a translation sequence (packets→bytes), and drive the result through the low-level layer — keeping each layer independent, legible, and swappable.

Mental Model

Hold layered sequences as a shipping pipeline with a packing station:

Layered sequences are a shipping pipeline: you describe a shipment in high-level terms (an order), a packing station breaks it into labeled boxes (the encoding), and the truck carries the boxes — each station works in its own terms. The order desk (high-level sequence) writes orders in business terms — "ship this product to this address" — knowing nothing about box sizes or tape. The packing station (translation sequence) is the adapter: it takes each order and translates it into the physical reality — the right boxes, the labels, the packing slip (one order becomes several boxes) — this is the one place that knows how an order becomes cargo. The truck (low-level driver) just carries whatever boxes it's handed onto the road (the wire). The power is independence: the order desk never thinks about boxes, the truck never thinks about orders, and if you change box standards (a new encoding), you re-train only the packing station — orders and trucks are unchanged. The one way to ruin a shipment: the packing station packs incompletely — boxes the product but forgets the address label (drops a high-level field) — so the cargo is physically real but malformed, and it arrives at the wrong place or can't be received.

So layered sequences are describe high, pack in the middle, carry low: the high-level sequence states intent, the translation sequence encodes it faithfully into low-level items, and the low-level driver carries them — with the packing station (translation) as the single, critical adapter that must encode everything the protocol needs.

Visual Explanation — the protocol stack

The defining picture is a stack: high-level sequence on top, a translation sequence in the middle, the low-level driver at the bottom — each layer in its own terms.

A protocol stack: high-level sequence on top, translation sequence in the middle, low-level driver at the bottomhigh-level sequence → translation sequence → low-level driverhigh-level sequence → translation sequence → low-level driverHigh-level sequence (packets)produces high-level transactions on the upper sequencer — written at the level you mean, encoding-agnostic.produces high-level transactions on the upper sequencer — written at the level you mean, encoding-agnostic.Translation (layering) sequencepulls each high-level transaction and decodes it into low-level transactions — the one adapter holding the encoding.pulls each high-level transaction and decodes it into low-level transactions — the one adapter holding the encoding.Low-level driver (bytes/frames)drives the low-level transactions onto the wire — works only in the low-level terms.drives the low-level transactions onto the wire — works only in the low-level terms.
Figure 1 — layered sequences mirror a protocol stack. The top layer is the high-level sequence, producing high-level transactions (packets) on the upper sequencer. The middle layer is the translation (layering) sequence: it pulls each high-level transaction and decodes it into low-level transactions (bytes/frames). The bottom layer is the low-level driver, which drives those low-level transactions onto the wire. Each layer works in its own terms — packets up top, bytes at the bottom — with the translation as the adapter between them. Swap the bottom layer and only the translation changes.

The figure shows the stack that defines layered sequences. The top layer is the high-level sequence, producing high-level transactions — packets — on an upper sequencer; it's written at the level you mean, knowing nothing about the byte encoding. The middle layer is the translation (layering) sequence — the adapter — which pulls each high-level transaction and decodes it into the low-level transactions (bytes, frames) that encode it; this is the one place the protocol mapping lives. The bottom layer is the low-level driver, which drives those low-level transactions onto the wire, working only in low-level terms. The crucial property is that each layer works in its own terms: packets at the top, bytes at the bottom, and the translation bridging them — exactly like a network stack where an application speaks messages, a transport speaks segments, and a link speaks frames, with adapters between. This separation delivers the independence that makes the pattern valuable: the high-level sequences are reusable across encodings (they only produce packets), the low-level driver is reused as-is (it only drives bytes), and the encoding is isolated in the translation — so swapping the low layer (a new framing, a different bus) means rewriting only the translation. The stack is the architecture; the translation is its keystone.

RTL / Simulation Perspective — the translation sequence

The heart of layered sequences is the translation sequence: it pulls a high-level item from the upper sequencer, decodes it into low-level items, and drives them. The code shows the pull-translate-drive loop.

the translation (layering) sequence: pull, translate, drive
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── HIGH-LEVEL sequence: produces packets on the UPPER sequencer (encoding-agnostic) ──
class packet_seq extends uvm_sequence #(packet);
  task body();
    packet pkt;
    repeat (n) `uvm_do(pkt)        // generate high-level packets — no byte detail here
  endtask
endclass
 
// ── TRANSLATION sequence: runs on the LOW sequencer; pulls packets, decodes to bytes ──
class layering_seq extends uvm_sequence #(byte_item);
  `uvm_declare_p_sequencer(low_sequencer)
  task body();
    packet pkt; byte_item b;
    forever begin
      // PULL a high-level transaction from the UPPER sequencer (it acts as a source)
      p_sequencer.up_seqr.get_next_item(pkt);     // get the next packet
      // TRANSLATE: decode the packet into low-level byte items (the encoding lives HERE)
      foreach (encode(pkt)[i]) begin              // one packet → many byte items
        b = byte_item::type_id::create("b");
        start_item(b);
        b.data = encode(pkt)[i];                  // map every field: header, length, payload, CRC
        finish_item(b);                           // DRIVE the low-level item
      end
      p_sequencer.up_seqr.item_done();            // signal the upper sequencer the packet is consumed
    end
  endtask
endclass
// connect: the layering sequence's p_sequencer.up_seqr must point at the high-level sequencer

The code shows the three roles of the translation sequence. Pull: the high-level sequence (packet_seq) produces packets on the upper sequencer, and the translation sequence (layering_seq) pulls each one — p_sequencer.up_seqr.get_next_item(pkt) — treating the upper sequencer as a source (just as a driver pulls from a sequencer, Module 9.2; here the translation sequence is the consumer, so the upper sequencer is not connected to a driver but to the translation). Translate: for each packet, the translation decodes it into low-level byte_items — encode(pkt) maps the packet's fields (header, length, payload, CRC) into the byte stream; this is the one place the encoding lives, and it must map every field the protocol needs (the DebugLab is what happens if one is dropped). Drive: each low-level item is sent through the low-level handshake (start_item/finish_item, Modules 9.3–9.4) to the low-level driver, which puts bytes on the wire; then item_done tells the upper sequencer the packet was consumed. The connection (commented) is essential: the translation's p_sequencer.up_seqr must point at the high-level sequencer (wired like a virtual sequencer's handle, Module 10.1). So the translation sequence is consumer of packets, producer of bytes — the adapter that turns one layer's transactions into the next layer's, which is the entire mechanism of layered sequences.

Verification Perspective — one high-level transaction, many low-level

The translation's defining behavior is expansion: one high-level transaction becomes many low-level ones, and the mapping must be complete. Seeing the expansion shows both the power and the failure mode.

A packet's fields are each decoded by the translation into low-level byte itemsone packet→ headerbytes→ lengthbytes→ payload bytes→ CRC bytespacket (high-level)header · length · payload ·CRCTranslation sequencedecode every fieldheader byte itemslow-levellength byte itemslow-levelpayload byte itemslow-levelCRC byte itemslow-level12
Figure 2 — the translation expands one high-level transaction into many low-level ones. A packet (header, length, payload, CRC) is decoded by the translation sequence into a sequence of low-level byte items: header bytes, length bytes, payload bytes, CRC bytes. Every high-level field must map to low-level items, or the encoding is incomplete and the low-level traffic is malformed. The translation is the single point where this mapping lives — one packet in, many bytes out, with no field left behind.

The expansion is the translation's core, and completeness is its discipline. A single high-level transaction — a packet with header, length, payload, and CRC fields — is decoded by the translation into a sequence of low-level items: header bytes, then length bytes, then payload bytes, then CRC bytes. So one packet in becomes many bytes out, and the ordering and content of those bytes is the wire encoding of the protocol. The power is the abstraction: the high-level sequence produced one object (a packet), and the translation handled the entire decomposition into the wire format — so nothing above the translation thinks in bytes. The discipline is completeness: every high-level field must map to low-level items, because the translation is the single point where the encoding is realized — if it decodes the payload but forgets the length (or the CRC), the low-level traffic is malformed, and the DUT (or a receiving monitor) can't parse it correctly. This is the failure mode the DebugLab covers, and it's insidious because the translation is centralized: a dropped field doesn't error at the translation; it just produces valid-looking but incomplete low-level traffic that fails downstream. So the verification view of the translation is "one in, many out, every field accounted for": the expansion is what makes layering powerful, and the completeness of the mapping is what makes it correct.

Runtime / Execution Flow — the pull-translate-drive loop

At run time, the translation sequence runs a continuous loop: pull a high-level item from the upper sequencer, translate it into low-level items, drive them, repeat — the engine that connects the two layers.

The translation loop: pull a high-level transaction, translate to low-level, drive each, signal done, repeatpull high-level → translate → drive low-level → item_done → looppull high-level → translate → drive low-level → item_done → loop1Pull a high-level transactionget_next_item from the upper sequencer (the source of packets);blocks until one is available.2Translate into low-level itemsdecode every field of the packet into the byte/frame items thatencode it.3Drive each low-level itemstart_item/finish_item each byte item to the low-level driver —paced by the low layer.4item_done → loopsignal the upper sequencer the packet is consumed; back to pull.Back-pressure flows up.
Figure 3 — the translation sequence's pull-translate-drive loop. It pulls the next high-level transaction from the upper sequencer (which acts as a source), translates it into one or more low-level transactions, drives each through the low-level handshake, and signals the upper sequencer the high-level item is consumed — then loops. The high-level sequence is paced by this loop: it produces packets only as fast as the translation consumes them (back-pressure flows up the stack). The loop is what continuously bridges the two layers.

The loop is the engine that bridges the layers, and its structure has an important consequence. Step 1, the translation pulls a high-level transaction from the upper sequencer with get_next_item — which blocks until a packet is available (the upper sequencer is the source, the high-level sequence the producer). Step 2, it translates the packet, decoding every field into the low-level items that encode it. Step 3, it drives each low-level item through the low-level handshake (start_item/finish_item) to the low-level driver — and this is paced by the low layer (back-pressure from the low-level driver, Module 8.3). Step 4, it signals item_done to the upper sequencer (the packet is consumed) and loops back to pull the next. The consequence is back-pressure flowing up the stack: because the translation pulls the next packet only after fully driving the current one's bytes, the high-level sequence produces packets only as fast as the translation consumes them — which is only as fast as the low-level driver (and the DUT) accept bytes. So the whole stack is naturally paced from the bottom: a slow wire slows the byte driving, which slows the translation's loop, which slows the packet production. This is the same back-pressure as a single layer (Module 8.3), now propagating through the stack — each layer paced by the one below it. The pull-translate-drive loop is what makes layered sequences a live pipeline: packets flow down, back-pressure flows up, continuously.

Waveform Perspective — a packet expands into bytes

The layering's defining relationship — one high-level transaction becomes many low-level ones — is visible on a timeline: a single packet spanning the multiple byte transactions that encode it.

One high-level packet expands into multiple low-level byte transactions

12 cycles
One high-level packet expands into multiple low-level byte transactionsone high-level packet begins (upper layer)one high-level packet …translation drives header (H), length (L) bytestranslation drives hea…then payload bytes (P0..P2), then CRC (C)then payload bytes (P0…one packet = many bytes — the layering expansionone packet = many byte…clkpkt_activebyte_vldbyte--HLP0P1P2C----------t0t1t2t3t4t5t6t7t8t9t10t11
Figure 4 — the layering expansion on a timeline. pkt_active marks one high-level packet (its lifetime at the upper layer). Below it, byte shows the low-level transactions the translation produced from it — header (H), length (L), payload bytes (P0..P2), CRC (C) — driven in sequence on the wire. One packet at the top corresponds to many bytes at the bottom: the translation decoded the single high-level transaction into the byte stream that encodes it. The high layer thinks in one packet; the low layer drives many bytes — the abstraction the stack provides.

The waveform shows the abstraction ratio layered sequences provide. pkt_active marks one high-level packet — its lifetime at the upper layer, where the high-level sequence produced a single object. Below it, the byte trace shows the low-level transactions the translation decoded that packet into: a header byte (H), a length byte (L), payload bytes (P0P2), and a CRC byte (C) — driven in sequence on the wire. So one packet at the top corresponds to many bytes at the bottom, and the byte stream is the wire encoding of that one packet. The key reading is the layering: the high-level sequence thinks in one packet and never sees the bytes; the low-level driver drives many bytes and never sees the packet; the translation is the only thing that sees both — it took the single high-level transaction and expanded it into the byte stream. This is the same one-to-many relationship as a transaction's pin cycles (Module 8.1), but now it's transaction-to-transaction across a protocol layer: one high-level transaction becomes many low-level transactions, with the translation owning the expansion. The picture to carry is the stack made visible: a packet on top, its bytes below, and the translation as the layer that connects the one to the many — which is exactly the protocol abstraction the pattern exists to provide.

DebugLab — the translation that dropped a field

A layered protocol that produced malformed traffic because the translation skipped the length field

Symptom

A layered packet protocol worked for short, fixed cases but failed intermittently on the DUT: the receiver mis-parsed packets, treating payload bytes as the start of the next packet, so packet boundaries drifted and the scoreboard saw garbled data. The high-level packets were correct (the packet sequence generated valid packets), and the low-level driver drove bytes fine. Yet the bytes on the wire didn't correctly encode the packets — something between the layers was wrong.

Root cause

The translation sequence decoded the header, payload, and CRC but forgot to encode the length field — so the low-level byte stream had no length, and the receiver couldn't tell where each packet ended:

why the byte stream was malformed
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
packet (high-level):  { header; length; payload[]; crc }    // all fields valid
 
translation (decode): drive header bytes
                      // ✗ MISSING: drive length bytes
                      drive payload bytes
                      drive CRC bytes
 
→ byte stream on the wire:  [header][payload...][crc]   — NO length field
  receiver: can't determine packet boundary without length → mis-frames the next packet
  result:  intermittent corruption (works when boundaries happen to align, fails otherwise)
 
fix — encode EVERY high-level field the protocol requires:
  drive header bytes
  drive length bytes      // ✓ the dropped field, restored
  drive payload bytes
  drive CRC bytes

This is the incomplete translation bug, and it's characteristic of layered sequences because the translation is the single point where the high→low mapping lives. The high-level packet had a valid length field, but the translation sequence's decode logic omitted driving the length bytes onto the wire — so the byte stream encoded the header, payload, and CRC but not the length. A receiver that relies on the length to find packet boundaries therefore mis-frames: without the length, it can't tell where one packet ends and the next begins, so payload bytes bleed into the next packet's parsing, corrupting boundaries intermittently (it happens to work when boundaries coincidentally align, and fails otherwise — hence the non-deterministic symptom). Crucially, nothing errors at the translation: it produces valid-looking byte items, just an incomplete set — the corruption only manifests downstream, at the receiver, far from the missing line. The fix is to make the translation complete: encode every high-level field the protocol requires (here, restore the length bytes). The general lesson is that the translation sequence is the sole realization of the protocol encoding, so its completeness is critical — a dropped field doesn't fail loudly; it silently produces malformed low-level traffic, and the discipline is to verify the translation maps every high-level field to its low-level encoding, with the byte stream checked against the protocol spec.

Diagnosis

The tell is valid high-level transactions but malformed low-level traffic. Diagnose translation bugs:

  1. Confirm the layers individually. Verify the high-level sequence produces valid packets and the low-level driver drives bytes correctly — if both are fine, the bug is in the translation between them.
  2. Compare the byte stream to the protocol spec. Dump the low-level items the translation produced for one packet and check them against the encoding — a missing or mis-ordered field is the translation bug.
  3. Look for an omitted field in the decode. Trace the translation's decode logic and confirm every high-level field maps to low-level items; a field with no corresponding drive is the cause.
  4. Correlate with intermittency. Boundary/framing corruption that's intermittent often means a missing length/delimiter field — the byte stream is incomplete in a way that only sometimes misaligns.
Prevention

Make the translation complete and verified:

  1. Map every high-level field to low-level items. The translation must encode all fields the protocol requires — header, length, payload, CRC, delimiters; none may be dropped.
  2. Check the byte stream against the spec. Verify the translation's output for representative packets matches the protocol encoding exactly — ideally with a check or a decoding monitor, since a dropped field is silent.
  3. Keep the encoding in one translation sequence. Centralize the mapping so it's reviewed in one place and can't drift; resist spreading encoding logic across high-level sequences.
  4. Test boundary and variable-length cases. Fixed/short cases can hide a missing length field; exercise variable-length packets and back-to-back framing where the missing field corrupts boundaries.

The one-sentence lesson: the translation sequence is the single point where a layered protocol's high→low encoding is realized, so an incomplete translation — a high-level field (like the length) not encoded into low-level items — silently produces malformed low-level traffic that fails downstream at the receiver; map every high-level field to its low-level encoding and verify the byte stream against the spec.

Common Mistakes

  • An incomplete translation. Dropping a high-level field (length, CRC, a delimiter) from the decode produces malformed low-level traffic that fails downstream; map every field.
  • Spreading encoding across high-level sequences. The mapping belongs in one translation sequence; smearing it loses the layering's reuse and review benefits.
  • Not connecting the upper sequencer to the translation. The translation pulls high-level items from the upper sequencer (a source); an unconnected handle starves it (cf. Module 10.1's wiring).
  • Confusing vertical layering with horizontal coordination. Layered sequences go down through one interface's abstraction levels; virtual sequences go across parallel interfaces (Module 10.1) — different patterns.
  • Ignoring back-pressure through the stack. The high layer is paced by the low layer via the translation loop; assuming the high layer runs free can mis-model timing.
  • Testing only fixed/short cases. A missing length or framing field hides until variable-length or back-to-back packets misalign boundaries; test those.

Senior Design Review Notes

Interview Insights

Layered sequences build a protocol stack in stimulus, mirroring a layered protocol where, say, packets sit on bytes. A high-level sequence produces high-level transactions — packets — on an upper sequencer, written at the level you mean and knowing nothing about the byte encoding. A translation, or layering, sequence on the lower sequencer pulls each high-level transaction, decodes it into one or more low-level transactions — the bytes or frames that encode it — and drives those through the low-level handshake to the low-level driver, which puts bytes on the wire. So the flow is: the high-level sequence generates packets, the translation sequence consumes packets and produces bytes, and the low-level driver drives bytes. The upper sequencer acts as a source that the translation pulls from, rather than being connected to a driver, so high-level items flow down into the translation on demand. The value is that each layer is written independently in its own terms: the high-level sequences are reusable across encodings because they only produce packets, the low-level driver is reused as-is because it only drives bytes, and the encoding — the packet-to-bytes mapping — is isolated in the one translation sequence. That means swapping the low layer, like changing the framing or the bus, requires rewriting only the translation, leaving the packet-level sequences untouched, exactly like reusing an application protocol over a different link layer. It's vertical layering, going down through the abstraction levels of one interface, which is distinct from a virtual sequence's horizontal coordination across parallel interfaces.

The translation sequence is the adapter in the middle of the stack that converts high-level transactions into low-level ones — it pulls a high-level packet from the upper sequencer, decodes it into the low-level byte or frame items that encode it, and drives those to the low-level driver, then loops. It's the critical piece because it's the single point where the protocol's high-to-low encoding is realized: the high-level sequence doesn't know the byte format and the low-level driver doesn't know the packet structure, so the entire mapping between them lives in the translation. This centralization is what makes layering powerful — the encoding is in one reviewable place, and changing it touches only this sequence — but it's also why the translation is where the risky bugs are. Because it's the sole realization of the encoding, an incomplete translation that drops a high-level field, like forgetting to encode the length, silently produces malformed low-level traffic: nothing errors at the translation, it just emits valid-looking but incomplete bytes, and the corruption only manifests downstream at the receiver, which mis-frames packets. So the discipline around the translation is completeness and verification: it must map every high-level field the protocol requires to low-level items, and the byte stream it produces should be checked against the protocol spec, ideally with a decoding monitor, because a dropped field fails silently. The translation is the keystone of the layered architecture — one packet in, many bytes out, with every field accounted for.

Exercises

  1. Build the translation. Sketch a translation sequence that pulls a packet from the upper sequencer and drives header, length, payload, and CRC byte items — and note which line would cause malformed traffic if omitted.
  2. Diagnose the framing bug. A layered protocol mis-frames packets intermittently while packets and the byte driver are each fine. Name the likely cause and where to look.
  3. Argue the layering. Explain why the high-level sequences are reusable when you swap the low-level encoding, and what changes.
  4. Vertical vs horizontal. For (a) "send packets that encode into bytes" and (b) "configure over APB then drive AXI," say which uses layered sequences and which uses virtual sequences.

Summary

  • Layered sequences build a protocol stack in stimulus: a high-level sequence produces high-level transactions (packets) on an upper sequencer, a translation sequence pulls each and decodes it into low-level transactions (bytes/frames), and a low-level driver drives them — each layer in its own terms.
  • The translation sequence is the adapter: it pulls high-level items from the upper sequencer (a source), translates every field into low-level items, and drives them — the single point where the high→low encoding lives, so swapping the low layer changes only the translation.
  • One high-level transaction expands into many low-level ones, and the mapping must be complete: every high-level field must encode to low-level items, or the low-level traffic is malformed and fails downstream.
  • The pull-translate-drive loop propagates back-pressure up the stack: the translation pulls the next packet only after driving the current one's bytes, so the high layer is paced by the low layer (and the DUT) — back-pressure through the layers.
  • The durable rule of thumb: write high-level intent in a high-level sequence (packets), isolate the encoding in one translation sequence that maps every field to low-level items, and drive through the low-level layer — verifying the byte stream against the spec, because the translation is the sole, silent point where an incomplete encoding corrupts the protocol. (Layered = vertical depth through one interface; virtual = horizontal breadth across interfaces, Module 10.1.)

Next — Nested Sequences: layered sequences translate between protocol levels; nested sequences compose within a level — the next chapter examines sequences calling sequences calling sequences, the parent/child hierarchy that forms, and how context (sequencer, priority, lifetime) flows through the nesting.