Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
    • SRAM and ROM
    • Register Files
    • Valid/Ready Handshake
    • AXI-Lite
    • AXI-Stream
    • Bus Integration
    • Synchronous FIFO
    • Register-Map and CSR RTL
      • CSR Contract and Address Map
      • Field Access Types
      • Hardware/Software Arbitration
      • Byte Strobes and Partial Writes
      • Atomic and Shadowed Updates
      • Interrupt Register Pattern
      • Adapter and Signoff
      • Generated Register Workflow
      • The Firmware Side: a C Driver for W1C, RC and Shadow Registers
    • Memory Reliability
    • Peripheral RTL Integration
    • Full AXI4: RTL Roadmap
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Register-Map and CSR RTL
  1. Topics
  2. RTL Design
  3. Memory & Buses
  4. Register-Map and CSR RTL
  5. CSR Contract and Address Map

Part 7 · Memory & Buses · Intermediate

CSR Contract and Address Map

Specify alignment, decode, reset values, permissions, side effects, and unmapped-address behavior before writing RTL.

Why this matters

Software and hardware disagree silently when the register map is vague: a decoder that ignores high address bits aliases registers, and an undocumented reserved bit becomes a bug the day hardware uses it.

After this lesson you can: write a field-level CSR map with reset values, reserved bits and error responses, and decode it without aliasing.

The register specification is an interface

This is the canonical field-level map used by the decoder, driver and expected-value model. All stored fields reset to zero; busy reflects reset-idle hardware. All unlisted bits read zero and ignore writes. Writes apply only strobed bytes; reads return the pre-operation snapshot.

Address

Name

Fields / readback

Write semantics

0x00

CONTROL

[0] enable RW; [2:1] mode RW (0..3); [8] start reads 0

Start on strobed bit 8=1 only if pre-edge enable=1 and busy=0; otherwise error with no CONTROL update. Engine latches pre-edge mode/LIMIT.

0x04

STATUS

[0] busy RO; [1] done; [2] error

done/error W1C, hardware set wins; busy writes ignored

0x08

IRQ_ENABLE

[3:0] RW: done, config_error, timeout, datapath_fault

Mask notification only; capture continues

0x0C

IRQ_STATUS

[3:0] sticky pending in IRQ_ENABLE order

W1C, set wins. Same event drives corresponding STATUS bit: done -> bit 1; any fault -> bit 2. STATUS and IRQ_STATUS acknowledgements are independent.

0x10

LIMIT_LO

[31:0] low shadow word RW

Merge strobed bytes; any nonzero strobe sets shadow_valid[0]

0x14

LIMIT_HI

[31:0] high shadow word RW

Merge strobed bytes; any nonzero strobe sets shadow_valid[1]

0x18

LIMIT_COMMIT

[0] commit reads 0; [2:1] shadow_valid RO

Strobed bit 0=1 with both words touched copies shadow to active atomically and clears validity. Incomplete commit is an OK no-op retaining shadow/validity; software reads validity and retries.

0x1C / 0x20

LIMIT_ACTIVE_LO / HI

[31:0] active low/high word RO

Writes ignored; software serializes commits while reading both halves

LIMIT active and shadow reset to zero. A successful commit retains shadow data, so later partial writes preserve bytes from that value. The single-request map uses a separate commit write; the helper below also supports final-word-plus-commit for a wider internal caller. RC and W1S examples are teaching variants, not additional mapped fields. Disabled/busy START returns an error and sets config_error; unmapped/misaligned requests return error and no register side effect.

  • Addresses are naturally aligned.

  • Unmapped reads return zero plus an error response; unmapped writes have no effect.

  • Reserved bits read as zero and ignore writes.

  • Every reset value is visible to both RTL and software documentation.

design.sv
1
2
3
4
5
6
7
8
9
10
11
12
// snippet: transport-independent CSR request
typedef struct packed {
  logic        write;
  logic [11:0] addr;
  logic [31:0] wdata;
  logic [3:0]  wstrb;
} csr_req_t;

typedef struct packed {
  logic [31:0] rdata;
  logic        error;
} csr_rsp_t;

Concrete internal transport: one outstanding request total, req_take = req_valid && req_ready at a rising edge. The adapter holds request payload stable through that edge. The CSR bank captures read data/error and performs all side effects exactly once on req_take; it raises registered rsp_valid after that edge and holds response payload through rsp_valid && rsp_ready. req_ready stays low until the response retires (no same-edge replacement). sw_write, csr_write, wr_lo/wr_hi and command pulses below mean decoded req_take, never raw bus levels. Reset flushes the owned request/response epoch under coordinated adapter reset. RC variants capture old data and clear on req_take, with simultaneous hardware set winning; response delivery never clears again.

Each slot is one clock cycle, and a request is taken at the edge that ends its slot. The first read is CONTROL, which returns 5 (enable 1, mode 2); the second is STATUS, which returns 2 (done).

  • Slot 0: req_valid and req_ready are both high, so the CONTROL read is taken at the edge ending slot 0.

  • Slots 1 to 3: the response is valid with data 5. rsp_ready is low in slots 1 and 2, so the response is held, and req_ready stays low: the STATUS read waits.

  • Slot 3: rsp_ready is high, so the response retires at the edge ending slot 3. req_ready rises only in slot 4, never on the retiring edge.

  • Slot 4: the STATUS read is taken; its response 2 is valid and ready in slot 5 and retires.

Common pitfall

Do not silently alias addresses by decoding too few bits. Compare the complete implemented word address and define the error response for everything else.

Check yourself What should a reserved bit return after software writes one to it?

Zero. Reserved bits ignore writes and read as zero so future hardware can assign them without inheriting undocumented state.

Remember

  • Compare the whole implemented word address. Unmapped and misaligned accesses return an error and have no side effect.

  • Reserved bits read zero and ignore writes, so hardware can use them later.

  • Side effects happen once, on the accepted request, never on a raw bus level.

Rule of thumb: the register map is an interface: every reset value and error response is written down once.

Keep going

  • Practice: Memory-mapped register interface with read and write support

  • Code lab: GPIO direction register

  • Interview: run a mock interview on this topic

Related topics

  • Field access types

  • Address decode

Previous

223 / 350

Next: Field Access Types

Up next

Up nextField Access Types

Sign in to save progress

Practice this lessonReport an error

See also

  • Hardware/Software Arbitration
  • Byte Strobes and Partial Writes
  • Atomic and Shadowed Updates
clkreq_validreq_readyrsp_validrsp_readyrdata052
Two CSR reads on the single-outstanding transport: the first response is stalled for two cycles, and the second request waits until it retires