AMBA AXI · Module 10
Common CSR Design Patterns
The standard control/status-register behaviors implemented over AXI4-Lite — RW, RO, WO, W1C, W1S, RC and self-clearing bits — why a register's read and write paths can differ, and the canonical interrupt-register pattern.
A register block is more than an array of read-write words. Real control/status registers (CSRs) have typed behaviors: some are read-only status, some clear a bit when you write a 1, some are set by hardware and cleared by software, some auto-clear themselves. These CSR design patterns encode the interaction between hardware and software on each bit, and getting them right is what makes a register block usable and race-free — especially for interrupts. This chapter catalogs the standard patterns (RW, RO, WO, W1C, W1S, RC, self-clearing), explains why a register's read path and write path can have different semantics, and shows the canonical interrupt-register design. They're implemented over AXI4-Lite (Chapter 10.2), but the patterns apply to any register interface.
1. The Standard Access Types
Each register (or field, or bit) has a defined behavior on read and on write:
- RW (Read-Write) — normal storage: software reads back what it wrote. Configuration registers.
- RO (Read-Only) — software reads; writes have no effect (or return
SLVERR). Status, ID/version, and hardware-updated values. - WO (Write-Only) — the write has an effect but reads return 0/undefined. Rare — e.g., a trigger or a write-only data port.
- W1C (Write-1-to-Clear) — writing 1 to a bit clears it; writing 0 leaves it unchanged. The bit is typically set by hardware. The dominant pattern for interrupt/status flags.
- W1S (Write-1-to-Set) — writing 1 to a bit sets it; writing 0 leaves it. Used for set-only fields like interrupt-enable-set.
- RC (Read-to-Clear) — reading the register clears it (a read side effect). Used for some status/event counters.
(Variants exist — RW1C, RW1S, write-to-clear, self-clearing — covered below.) The point: the access type is part of the register's contract, and the slave's logic must implement exactly the specified behavior per bit.
2. Read Path vs Write Path Differ
The crucial concept: a register's read behavior and write behavior are independent, and hardware and software both touch it. A single bit has up to four interacting influences — software read, software write, hardware set, hardware clear — and the access type defines how they combine:
- A W1C interrupt flag: hardware sets the bit (event occurred); software reads it (sees the pending interrupt); software writes 1 to clear it (acknowledge); writing 0 does nothing. Read path = current flag state; write path = conditional clear.
- A status RO: hardware drives the value; software read returns it; software write is ignored. Read path = live hardware value; write path = no-op.
- A self-clearing "go" bit: software writes 1 to start an operation; hardware clears it when done. Read path = busy/idle; write path = trigger.
So the register block's logic is two separate concerns per bit — what a read returns, and what a write (with WSTRB) does — plus the hardware's own set/clear. Conflating them (e.g., implementing W1C as plain RW) breaks the contract.
3. Why W1C — Avoiding the Read-Modify-Write Race
W1C exists to solve a real concurrency problem with interrupt flags. Imagine a status register where software clears a flag with a plain read-modify-write (RW): read the register, clear the bit it handled, write it back. Between the read and the write, hardware sets another flag bit — and the write-back, carrying the stale read value, clobbers that newly-set bit, losing the interrupt. This is a classic lost-update race.
W1C eliminates it: software writes a word with 1 only in the bit(s) it wants to clear and 0 everywhere else; writing 0 doesn't affect a bit, so a bit hardware set in the meantime is untouched. No read-modify-write, no lost update — each clear is independent and idempotent. This is exactly why interrupt-status registers are W1C, not RW. (W1S serves the analogous purpose for set-only fields like enabling interrupts atomically.)
4. The Canonical Interrupt Register Set
The patterns combine into the standard interrupt register block, usually three (or more) registers:
- Interrupt Status (W1C) — one bit per interrupt source. Hardware sets a bit when its event fires; software reads to see what's pending and writes 1 to acknowledge/clear.
- Interrupt Enable/Mask (RW, or split W1S/W1C) — one bit per source, controlling whether that source's status contributes to the actual interrupt output. Software configures it.
- Masked Status (RO) — status AND enable, showing only enabled-and-pending interrupts; the actual interrupt line is the OR of these.
The interrupt output asserts when any (status AND enable) bit is set. Software's handler reads masked status to find the source(s), services them, and W1C-clears the status bits. This pattern — W1C status + RW/W1S/W1C enable + RO masked status — is ubiquitous because it's race-free (W1C) and lets software control which sources interrupt (enable) without disturbing pending flags.
5. Common Misconceptions
6. Debugging Insight
7. Verification Insight
8. Interview Questions
9. Summary
CSR design patterns are the typed behaviors of control/status registers — the per-bit contract between hardware and software. Beyond plain RW storage, the standard types are RO (status, writes ignored), WO (write-effect), W1C (write 1 to clear — the interrupt-flag workhorse), W1S (write 1 to set), RC (read clears), and self-clearing (software sets, hardware clears). The key insight is that a register's read path and write path are independent, with hardware and software both influencing each bit. W1C specifically exists to make flag clearing race-free — writing 1 to clear and 0-to-leave-alone avoids the read-modify-write lost-update that plain RW suffers when hardware sets another bit mid-clear.
These compose into the canonical interrupt register set: W1C Status (hardware sets, software clears), RW Enable (mask), and RO Masked Status (status AND enable) driving the interrupt line. Getting access types exactly right matters because they are the hardware/software contract — a mismatch causes lost interrupts, hangs, or corruption that's painful to debug since the bus transactions all succeed while the semantics are wrong. Verify each type's exact behavior (especially the W1C race and per-field byte writes) against a register reference model. Next: the consolidated AXI4-Lite verification checklist — the must-check list for a Lite slave, pulling together register semantics and protocol compliance.
10. What Comes Next
You've got the register patterns; next, the checklist to verify a Lite slave:
- 10.5 — AXI4-Lite Verification Checklist (coming next) — the consolidated must-check list for an AXI4-Lite slave, combining protocol compliance and register semantics.
Previous: 10.3 — APB vs AXI4-Lite. Related: 10.2 — Register Access with AXI4-Lite for the transactions these patterns ride on, and 6.7 — WSTRB Write Strobes for byte-field writes. For the broader protocol catalog, see the AMBA family overview doc.