7.5Non-Atomic Bus

book pp. 132–142 · ~5 min read

  • pipelined vs. split-transaction bus
  • stalling protocol
  • response before request
  • non-stalling protocol
  • livelock rule

Every protocol so far leaned on Atomic Transactions. That atomicity buys simplicity and costs performance: an atomic bus is the unpipelined processor of interconnects.

7.5.1–7.5.2 Three buses

Atomic bus (Fig 7.8)AddressRequest 1Request 2Request 3DataResponse 1Response 2Response 3Pipelined bus (Fig 7.9) — responses in request orderAddressRequest 1Request 2Request 3DataResponse 1Response 2Response 3Split-transaction bus (Fig 7.10) — responses out of orderAddressRequest 1Request 2Request 3DataResponse 2Response 3Response 1A fast on-chip Response 2 no longer waits behind DRAM-slow Response 1 — but responses must now carry the requestor’s identity.

Figures 7.8–7.10 (recreated): atomic, pipelined, and split-transaction buses.

An atomic bus’s throughput is capped by request+response latency — DRAM latency, in the worst case. A pipelined bus overlaps them (responses in order); a split-transaction bus lets a low-latency response overtake a slow one. (Atomic transactions can still be enforced on a pipelined bus with a same-block lookup table — the SGI Challenge did — but this section drops the property entirely.)

7.5.3 The system model

Split request bus and response bus, operating independently; each controller connects to both (memory issues no requests). Crucially, each controller’s incoming queues are processed in strict FIFO order, regardless of message type or address — if the head request stalls, everything behind it waits. That discipline preserves the total order; its side effects drive everything below.

7.5.4 The stalling protocol

Dropping Atomic Transactions makes new transitions possible: requests can now arrive for a block whose transaction is mid-flight. The key insight for reasoning about them: the transaction was ordered at its request, so a block in IM^D is logically M — an owner without data. This protocol’s answer: stall such requests until the data arrives (deadlock-safe, since the un-stalling Data travels the response network, which stalls can’t block):

Table 7.17 (recreated): stalling MSI, split-transaction bus — cache controller

Core eventsBus: ownBus: othersBus: own
StateLoadStoreReplacementOwn-GetSOwn-GetMOwn-PutMOther-GetSOther-GetMOther-PutMOwn Data Response

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

Stalling creates a strange new possibility — a requestor can see the response to its request before processing the request itself, because its own request is FIFO-queued behind a stalled one. Step through the book’s two-block scenario (Table 7.19):

C1 block XIM^D
C1 block Y
C1 request queue(empty)

C2 holds Y in M; the LLC owns X (DRAM-slow).

1 / 6C1 wants X; the LLC is slow

C1: store miss on X → issue GetM(X)/IM^AD. The GetM is serialized; C1 observes it (X: IM^D — logically M, awaiting data). The LLC is the owner but misses on-chip: it starts a LONG DRAM access.

That’s what the new X^A states are for: data in hand, transaction not yet in effect, block logically in its old state (IM^A ignores others’ requests; IM^D must answer them).

One more redesign: NoData is gone. The LLC now augments each block with an owner field, updated on every ownership-changing transaction — so a PutM from a non-owner is recognized at the LLC, and the II^A cache simply drops to I. (In a non-atomic system, NoData messages could be numerous and could even arrive before their PutMs.)

Tables 7.18/7.21 (recreated): memory controller with owner field — identical for both protocols

Request busResponse bus
StateGetSGetMPutM from ownerPutM from non-ownerData

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

7.5.5 The non-stalling protocol

Stalling the head of the queue delays every request behind it — even requests for other blocks the controller could happily process. Reordering is forbidden (total order!), so the fix is to process every request, in order, by remembering deferred work in the state name: IS^D_I (“awaiting data; when it comes, take my one load, then go to I”), IM^D_S, IM^D_SI, and friends:

Table 7.20 (recreated): NON-stalling MSI — count the transient states

Core eventsBus: ownBus: othersBus: own
StateLoadStoreReplacementOwn-GetSOwn-GetMOwn-PutMOther-GetSOther-GetMOther-PutMOwn Data Response

Cell format: action / next state (next state omitted when unchanged) · blank = event ignored · shaded = impossible. Click any cell or state chip.

Click a transition cell for its plain-English explanation, or a state chip for its invariants.

The memory controller still stalls — and not for laziness: a non-stalling memory in IorS^D observing GetM, then GetS, then GetM… would need transient states encoding arbitrarily long chains. There is no elegant bound smaller than the number of cores, so memory stalls and the caches don’t.

The scoreboard: nothing here is individually complicated, but the state count roughly tripled from the atomic-transactions baseline. That is the price of bus performance — and chapter 8’s directories will pay a related price for scalability.

Check yourself

1.What distinguishes a pipelined bus from a split-transaction bus, and what new burden does the latter add?

2.In the stalling split-transaction protocol, a cache in IM^D observes an Other-GetS. Why does it STALL rather than ignore or answer?

3.What do the new X^A states (IS^A, IM^A, SM^A) represent, and how does IM^A differ from IM^D?

4.The non-stalling protocol replaces stalls with states like IM^D_S. What does IM^D_S mean, and what rule prevents livelock?

5.Two mechanisms differ from the atomic-transaction protocols: NoData is gone, and the memory controller still stalls. Why each?

5 questions