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. Atomic and Shadowed Updates

Part 7 · Memory & Buses · Intermediate

Atomic and Shadowed Updates

Keep multiword values and safety-critical configuration coherent across several software writes.

Why this matters

A 64-bit setting written over a 32-bit bus is half old and half new for a moment. Hardware that samples in that window runs with a value software never chose.

After this lesson you can: build shadow registers with a commit step, and snapshot a wide counter on the low-word read.

The torn-update problem

A 64-bit configuration written over a 32-bit bus exists briefly as half old and half new. Hardware sampling during that window sees a value software never intended.

  1. Write low and high words into shadow registers.

  2. Track which words have been written.

  3. Commit with an explicit command or when the final required word arrives.

  4. Copy the complete shadow atomically into the active configuration.

Each slot is one clock cycle, and a write takes effect at the edge that ends its slot. The two data lanes show one digit per word, high word first: 11 is the old value, 22 the new one, and 12 a torn mix.

  • Slot 1: the new low word is written. The naive register shows 12 from slot 2: new low word, old high word.

  • Slots 2 and 3: hardware sampling the naive value sees 12, a limit software never wrote. The shadow design still shows the old 11.

  • Slot 4: commit copies both shadow words at once, so the shadow design goes straight from 11 to 22 in slot 5.

The commit logic computes the post-write shadow value before updating active state. This explicitly supports a final word write and commit on the same edge instead of silently committing the previous shadow value.

Decode LIMIT_LO/HI and LIMIT_COMMIT from the canonical field map in CSR Contract and Address Map. The mapped single-request port issues commit separately; this helper's simultaneous inputs support an internal caller, not two software writes on one bus edge. Its incomplete commit retains validity and returns no active update, matching the map's OK no-op policy.

Here wr_lo and wr_hi are decoded, accepted write pulses. A word counts as written only when at least one byte strobe is set; zero-strobe writes change neither shadow data nor validity. Partial writes intentionally preserve unselected shadow bytes, including bytes from the previous committed value. This is a word-touch contract, not a requirement to replace every byte. A replacement-only contract would instead track all eight byte-valid bits before allowing commit.

csr_shadow_limit.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
module csr_shadow_limit (
  input logic clk, rst_n,
  input logic wr_lo, wr_hi, commit_pulse,
  input logic [31:0] wdata,
  input logic [3:0] wstrb,
  output logic [63:0] active_q,
  output logic [1:0] shadow_valid_q
);
  logic [63:0] shadow_q, shadow_next;
  logic [1:0] valid_next;

  function automatic logic [31:0] merge_bytes(
    input logic [31:0] old_data, new_data, input logic [3:0] strb
  );
    logic [31:0] merged;
    merged = old_data;
    for (int b = 0; b < 4; b++)
      if (strb[b]) merged[b*8 +: 8] = new_data[b*8 +: 8];
    return merged;
  endfunction

  always_comb begin
    shadow_next = shadow_q;
    valid_next  = shadow_valid_q;
    if (wr_lo && |wstrb) begin
      shadow_next[31:0] = merge_bytes(shadow_q[31:0], wdata, wstrb);
      valid_next[0] = 1'b1;
    end
    if (wr_hi && |wstrb) begin
      shadow_next[63:32] = merge_bytes(shadow_q[63:32], wdata, wstrb);
      valid_next[1] = 1'b1;
    end
  end

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      shadow_q       <= '0;
      shadow_valid_q <= '0;
      active_q       <= '0;
    end else begin
      shadow_q       <= shadow_next;
      shadow_valid_q <= valid_next;
      if (commit_pulse && &valid_next) begin
        active_q <= shadow_next;
        shadow_valid_q <= '0;
      end
    end
  end
endmodule

For counters wider than the bus, snapshot-on-read is often safer: reading the low word captures the full counter into a snapshot, and the high-word read returns the matching snapshot half.

Tip

Expose a busy or commit-done bit when hardware needs time to apply configuration. Software should never infer completion from an arbitrary delay.

Check yourself Why is writing the high word last not sufficient by itself?

Hardware can still sample between writes, and retries or reordered software sequences can violate the convention. A commit event creates an explicit atomic boundary.

Remember

  • Write the words into shadow registers, then copy the whole shadow into the active value on an explicit commit.

  • A word counts as written only when a byte strobe is set. Unselected shadow bytes keep their old value.

  • For a counter wider than the bus, reading the low word snapshots the full value for the high-word read.

Rule of thumb: never let hardware see a partly written multi-word value.

Keep going

  • Interview: run a mock interview on this topic

Related topics

  • Interrupt register pattern

Previous

227 / 350

Next: Interrupt Register Pattern

Up next

Up nextInterrupt Register Pattern

Sign in to save progress

Practice this lessonReport an error

See also

  • CSR Contract and Address Map
  • Field Access Types
  • Hardware/Software Arbitration
clkwr_lowr_hicommitnaive_active111222shadow_active1122
A 64-bit value updated as two 32-bit writes: without a shadow the active value is torn for two cycles, with a shadow it changes once at commit