18.1-2RVWMO: The Memory Consistency Model

Part I Linux boot: required Vol. I (Unprivileged) pp. 85–89 · ~8 min read

  • global memory order
  • preserved program order
  • single-copy atomic
  • syntactic dependency
  • load value axiom
  • atomicity axiom
  • progress axiom
  • rcpc/rcsc annotation

A memory consistency model is the ISA’s answer to one question: which values may a load return? RVWMO (RISC-V Weak Memory Ordering) answers it weakly — single-hart code appears in-order to itself, but other harts may observe your memory operations in a different order unless one of a short list of rules says otherwise. This is the contract your load/ store unit, store buffer, and cache hierarchy sign. (Scope note: this chapter formalizes regular main memory only — I/O ordering, instruction fetch, FENCE.I, and page-table walks are defined elsewhere and not yet folded into the formalism.)

18.1.1 The vocabulary

An execution has a global memory order : one total order over every hart’s memory operations. Memory instructions give rise to operations — load, store, or (for AMOs) both at once — and every operation is single-copy atomic : nobody ever sees half of one.

Bookkeeping rules that matter to hardware:

  • An aligned instruction of ≤ XLEN bits → exactly one operation. Exceptions: a failed SC generates none; RV32 FLD/FSD may generate several.
  • Misaligned accesses (and >XLEN FP accesses) may decompose into byte-granularity components, unordered among themselves — the license that makes trap-and-emulate byte loops legal. Inside a misaligned atomicity granule (PMA), no decomposition happens.
  • LR and SC are paired when no other LR/SC sits between them.
  • Operations may carry annotations: aq on LR/AMO ⇒ acquire-RCsc, rl on SC/AMO ⇒ release-RCsc; RCpc annotations currently arise only from Ztso, but the model is forward-compatible with native load-acquire/store-release instructions.

18.1.2 Syntactic dependencies

RVWMO orders through register dataflowsyntactically, not semantically. j has a syntactic dependency on i if a source register of j traces back through the register graph (via instructions that “carry” dependencies) to a destination of i. Three flavors matter: address (feeds an address source register), data (feeds a store’s data register), control (a branch/indirect jump in between depends on i). x0 never participates; the per-instruction fine print (loads/JALR/AMOs carry nothing; a successful SC’s rd is a destination; CSR instructions mirror Table 7) is cataloged in §18.3.

18.1.3 Preserved program order — the 13 rules

The global memory order must respect this subset of each hart’s program order (both operations to regular main memory):

PPO: a precedes b in the global order if… (AMOs count as both load and store)
RuleWhat it means for your pipeline
1 · Overlap: b is a store, addresses overlapSame-address write orderingNo store-store reorder to the same bytes
2 · CoRR: both loads of byte x, no store to x between, values from different writesSame-address read coherenceTwo reads of the same location must not go backwards in time
3 · a from AMO/SC, b load returns its valueAtomic write forwarding ordersA load that consumes an AMO/SC result is ordered after it
4 · A FENCE orders a before bExplicit fenceYour fence implementation defines the pred/succ drain points
5 · a has an acquire annotationAcquire keeps everything after itaq = no later op observed first
6 · b has a release annotationRelease keeps everything before itSC.rl / AMO.rl: drain prior accesses before it performs
7 · a and b both RCscSync ops totally orderedAll aq/rl-marked ops order among themselves
8 · a paired with bLR before its SCTrivially true in any sane LSU
9 · address dependencyb’s address comes from aNo value speculation through addresses
10 · data dependencyb’s store data comes from aStore data must actually be computed before the store performs globally
11 · control dependency, b is a STORENo speculative storesLoads may hoist past branches; stores never
12 · b load returns value of an intervening store m that addr/data-depends on aForwarding cannot launder orderingStore-buffer forwarding keeps the forwarded store’s dependencies
13 · intervening m has an address dependency on a, b is a storeUnresolved addresses block later storesA store cannot become visible while an older access’s address is unknown
Dotted-underlined cells have explanations — click one.

18.1.4 The three axioms

An execution is legal iff a global memory order exists that respects PPO and satisfies:

  • Load Value : each byte of a load returns the latest store to that byte among (1) stores earlier in the global memory order and (2) stores earlier in program order. Clause (2) is store-to-load forwarding, architecturally blessed: your store buffer may serve a younger load before the store is globally visible.
  • Atomicity : for an aligned paired LR/SC, no other hart’s store to a read byte may intrude between the store the LR read from and the SC’s own store, in the global order.
  • Progress : no operation is preceded by an infinite sequence — stores eventually become visible; spin loops eventually observe updates.

Seeing it: message passing

The canonical two-hart test, in both verdicts — step through the executions:

MP (message passing) — unsynchronizedInitially: data = 0, flag = 0

Hart 0

  1. li t0, 42
  2. sw t0, (data)
  3. li t1, 1
  4. sw t1, (flag)

Hart 1

  1. lw a0, (flag)
  2. lw a1, (data)
a0=1, a1=0ALLOWEDNo PPO rule connects the two stores, nor the two loads — the stale-data outcome is architecturally allowed.
0/4

Step through one execution that shows how the verdict comes about.

MP — fenced and acquiredInitially: data = 0, flag = 0

Hart 0

  1. li t0, 42
  2. sw t0, (data)
  3. fence w, w
  4. li t1, 1
  5. sw t1, (flag)

Hart 1

  1. lw a0, (flag)
  2. fence r, r
  3. lw a1, (data)
a0=1, a1=0FORBIDDENfence w,w chains data-store < flag-store; fence r,r chains flag-load < data-load; the load-value axiom then forces a1=42 whenever a0=1.

18.2 Dependency granularity through CSRs

Syntactic dependencies thread through CSRs at defined granularities (Table 12): fflags per-bit (bits 4..0 independent), frm whole, fcsr per-field — with the aliasing between them tracked. Read-only CSRs don’t participate. The FP flags are accumulating CSRs : they carry a dependency only from themselves to themselves, so a chain of FP ops does not serialize on the flags register.

Hardware Designer Notes

The comforting theorem for a first core: an in-order, single-issue pipeline with a FIFO store buffer that forwards to same-address younger loads and drains on FENCE/aq/rl satisfies RVWMO by construction — every PPO rule falls out of in-order issue. The rules earn their keep the day you add out-of-order load issue, non-FIFO coalescing, or value prediction: then rules 2, 9-13 become real RTL assertions. Write them into your verification plan as litmus tests (the herd/litmus suites for RVWMO exist — run them against your core; the formal machinery lives in the appendices uA/uB).

Minimal Linux-boot hart MUST

  • Honor all 13 PPO rules in the LSU: no same-address store reorder, CoRR for loads, dependency-ordered issue (rules 9-13) — syntactic deps included, xor-zero idioms and all
  • Never let a control-dependent store drain before its branch resolves
  • Keep aq/rl semantics: acquire holds later accesses, release drains earlier ones (scoped per rule 7 for RCsc pairs)
  • Deliver the progress axiom: store buffers must drain; snoops must eventually invalidate spinning readers

MAY simplify / trap-and-emulate

  • Forward store-buffer data to younger same-address loads (Load Value clause 2)
  • Hoist control-dependent LOADS speculatively past branches — rule 11 deliberately omits them
  • Reorder independent loads/stores to different addresses arbitrarily — that is the “W” in RVWMO
  • Implement fences/aq/rl conservatively as full drains at first — correct, just slower

Check yourself — RVWMO

1.Hart 0: sw data; sw flag. Hart 1: lw flag (sees 1); lw data. No fences, no dependencies. May hart 1 read stale data?

2.Your store buffer forwards a not-yet-visible store to a younger load of the same address. Legal under RVWMO?

3.PPO rule 11 orders a→b when b is a STORE with a control dependency on a. Why doesn't the rule cover control-dependent LOADS?

4.lw a0,(t0); xor t1,a0,a0; add t2,t3,t1; lw a1,(t2). Is the second load ordered after the first?

5.Which annotation set makes an LR/SC pair sequentially consistent in the C++ seq_cst sense?

5 questions