LR/SC gives RISC-V lock-free primitives with a forward-progress asterisk; Zacas adds the industry-standard alternative — single-instruction compare-and-swap at 32, 64, and (RV64) 128 bits. Depends on Zaamo; encoded as an ordinary AMO:
Semantics: temp = mem[rs1]; if (temp == rd) mem[rs1] = rs2; rd = temp. The dual-role rd is the ergonomic win — a failed CAS
returns the fresh value, so retry loops never reload.
| RV32 | RV64 | |
|---|---|---|
| AMOCAS.W | 32-bit, plain registers. | Compares against rd[31:0], stores rs2[31:0], result SIGN-EXTENDED into rd. |
| AMOCAS.D | 64-bit via EVEN register pairs rd/rd+1, rs2/rs2+1. | 64-bit, plain registers. |
| AMOCAS.Q | — | 128-bit via even pairs — the ABA-killer width. |
The expected-value pair may be assembled with two ordinary loads that race against writers — harmless: the CAS’s own load-pair is atomic, and any inconsistency simply fails the compare while handing back the truth.
Ordering fine print
Success: aq/rl work as on any AMO. Failure: acquire (if aq) but never release, whatever rl says — there’s no meaningful publish when nothing was stored. A failed CAS may write the old value back or skip the write, but either way it’s an AMO for RVWMO’s PPO rules — and consequently always requires write permission, even to fail.
Hardware Designer Notes
AMOCAS.Q is the sizing question: a 128-bit atomic needs a 16-byte single-beat path to the coherence point (or line-locking). If your data bus is 64 bits, budget the Q variant as a two-beat locked sequence in the L1 controller — and get the failure-ordering corner (acquire-not-release) into your litmus-test suite early.
Minimal Linux-boot hart MUST
- Extend the AMO datapath with a compare-before-write: the ALU stage that computed add/and/or for AMOs gains an equality path gating the store
- For paired widths: an atomic load-pair/store-pair path and the even-register decode check (odd → illegal)
- Enforce write permission on the address regardless of comparison outcome, and the no-release-on-failure rule in your fence/ordering logic
MAY simplify / trap-and-emulate
- Implement the maybe-write on failure as an unconditional writeback of the old value — legal, and it simplifies single-beat memory systems
- Skip Zacas for a Linux-boot v1 (kernel falls back to LR/SC) — RVA23 lists it; 128-bit CAS is what makes userspace lock-free libraries portable from x86
Check yourself — AMOCAS
1.What double duty does rd serve in AMOCAS, and why is that clever?
2.How does RV32 get a 64-bit CAS (and RV64 a 128-bit one)?
3.A CAS with .aqrl FAILS the comparison. What ordering does it provide?
4.Why does the Michael-Scott queue example use AMOCAS.Q on a pointer that's only 64 bits?