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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • The NanoSoC Tour
  • Reading Path
  • SoC Glossary10
  • SoC Metrics Reference
  • SoC Cheatsheet
  • What SoC Integration Is12
  • Architecture and Budgets21
  • Memory Maps and Address Decode26
  • Interconnect and Bus Fabrics26
  • Clock and Reset Architecture24
  • Power Architecture21
  • Interrupts, DMA and Peripherals15
  • Memories, Boot and Security21
    • Memory Subsystem Integration
    • ECC and Error Handling
    • External Memory Controller Integration
    • Boot ROM and Boot Modes
      • Reset Vector and Boot-Source Select
      • The NanoSoC Boot Flow in Time
      • ROM to SRAM Handoff and Patching
    • eFuse and OTP
    • Secure Boot and Root of Trust
    • Security Architecture
  • IP Integration and Handoff21
  • Top-Level Verification and Bring-up21
  • Package, Pads and I/O18
  • Chip Signoff and Tapeout18
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←Boot ROM and Boot Modes
  1. Topics
  2. SoC Design
  3. Memories, Boot and Security
  4. Boot ROM and Boot Modes
  5. ROM to SRAM Handoff and Patching
On this page

    Part 8 of 14, lesson 12 of 21Part 8 of 14/Memories, Boot and Security/Lesson 12 of 21All levels

    ROM to SRAM Handoff and Patching

    Cause, stack, clear, load, checksum, jump: the handoff contract, the wake shortcut, and fixing ROM after tapeout.

    Why it matters

    This lesson has one job: hand control from unchangeable ROM to writable SRAM without dropping the baton. The handoff is six acts, read the cause, set the stack pointer, clear memory (cold boot only), load the image, verify it, jump, and each act has a failure that looks like the next act's bug. The wake shortcut skips the middle entirely, which only works because the cause is read before anything is written. And because ROM cannot be fixed, the lesson ends with the patching hooks that let a fixed ROM survive its own errata.

    The core idea

    RST_CAUSE is read first, before any write to SRAM0. Power-on, pad and software resets are cold boots; a wake cause skips the clear and the load and jumps straight to 0x2000_0000 on the retained image, because the clear would otherwise wipe state that sleep was supposed to keep. On a cold boot the stack pointer is then set to 0x2001_0000 (the end of SRAM0) before any call or push, and the clear loop zeroes 4 KB of SRAM0 with posted writes. Which 4 KB is a NanoSoC teaching choice, since the boot table only says 4 KB of SRAM0: the top 4 KB, 0x2000_F000 to 0x2000_FFFF, where the ROM's own stack and variables live, so the image area from 0x2000_0000 is untouched until the load overwrites it. The clear initialises those 1024 words only. That is 1/16 of SRAM0 and none of SRAM1, so with SECDED the rest of SRAM0 and all of SRAM1 must be written before they are read: all 16,384 words of one bank at one write per system clock take about 170.7 microseconds. A software reset re-enters with its cause bit set so drivers reinitialise instead of assuming a clean slate. The load moves 8 KB plus a 4-byte command at 6 Mb/s, the checksum rereads 2,048 words at 18 CPU clocks each for 192 microseconds, and the jump lands on the first loaded word. The wake jump skips verification entirely: a product with secure boot must decide whether a retained image is trusted because retention protects it, or is re-verified (the 192 microsecond checksum, plus authentication) before the jump. Patching, a NanoSoC teaching value since the NanoSoC reference defines no patch block, would reserve a small table of address-and-redirect entries that diverts a matched ROM address to SRAM0 code. That table is mutable state redirecting the root of trust, so it needs rules: entries are loaded only after the patch image passes the same authentication as any other image, they are locked once written (or come from fuses), and the comparator on the ROM read path adds delay that the 24-clock line fill and 18-clock access figures do not include. An erratum then costs entries, not a respin, but never at the price of an unverified redirect.

    Diagram
    # not-run: handoff step costs from the NanoSoC boot ledger, NanoSoC teaching values
    Clear 4 KB (cold boot only): 1024 posted writes x 1 T_sys = 1024 x 10.4167 ns = 10.667 us.
    Checksum: 2048 single reads x 18 T_cpu = 2048 x 93.75 ns = 192.000 us.
    DMA self-test: 625 + 875 + 750 + 135.4 ns + 6000 ns = 8.385 us.
    Wake shortcut: 14.073 us power-up, then the line fill (0.125 us) and the cause read (0.281 us): about 14.479 us to the jump (derived).
    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    t_sys = 1 / 96e6
    t_cpu = 1 / 192e6
    assert 4 * 1024 // 4 == 1024
    assert 0x2000_FFFF - 0x2000_F000 + 1 == 4 * 1024
    clear = 1024 * t_sys
    checksum = 2048 * 18 * t_cpu
    dma_test = 625e-9 + 875e-9 + 72 * t_sys + 135.4e-9 + 6000e-9
    assert abs(clear * 1e6 - 10.667) < 0.002, clear
    assert abs(checksum * 1e6 - 192.0) < 0.01, checksum
    assert abs(dma_test * 1e6 - 8.385) < 0.01, dma_test
    print(f"clear {clear * 1e6:.3f} us, checksum {checksum * 1e6:.3f} us, DMA test {dma_test * 1e6:.3f} us")
    def boot(cause_wake):
        t = 24 * t_cpu + 281.25e-9
        if cause_wake:
            return t
        return t + clear + checksum + dma_test
    assert boot(False) > boot(True)
    assert abs((14.073e-6 + boot(True)) * 1e6 - 14.479) < 0.002
    words_sram0 = 64 * 1024 // 4
    ecc_init = words_sram0 * t_sys
    assert abs(ecc_init * 1e6 - 170.667) < 0.001
    assert 1024 / words_sram0 == 1 / 16
    print(f"wake path to the jump: {(14.073e-6 + boot(True)) * 1e6:.3f} us; full-bank ECC init {ecc_init * 1e6:.1f} us")
    print("PASS: clear 10.667 us, checksum 192.000 us, DMA test 8.385 us, wake skips all three")

    What the review looks for

    • The handoff sequence is written as six acts with the actor and the cost of each, with the cause read first and the clear marked cold-boot-only.

    • The wake path is a named branch with its own test, not an afterthought: retained image, no SPI traffic, jump observed.

    • Patch entries, if provided, are loaded only from an authenticated image, locked once written, and costed on the ROM read path; each redirects one ROM address to SRAM0 code.

    Verify and debug

    Boot each reset cause separately: cold loads and jumps, wake jumps without SPI activity and with the retained image bytes unchanged (compare the first 4 KB before and after), software reset re-enters cleanly. Corrupt one image byte in a scratch build and confirm the checksum refuses the jump; corrupt the stack setup and confirm the failure points at the clear loop, not the loader. Test every patch entry by triggering its address and observing the redirect.

    Boot alias never removed: a reset-time mirror of boot memory that stays visible after software remaps, so vectors fetch from the wrong place. Symptom: correct image, wrong vectors. Caught by a boot-sequence software test that reads vectors after remap. Fix: explicit remap control with a removal check. NanoSoC avoids the species with its fixed map, but every remapped design needs the check.

    If asked what the ROM does before the jump, answer with the six acts, cause first, and two numbers: 10.667 microseconds to clear, 192 microseconds to verify. Then add the wake shortcut in one sentence: the cause is read before the clear, so a wake jumps on the untouched image.

    Check yourself The checksum passes but the image crashes on its first instruction. Which handoff act is suspect, and which is cleared?

    Suspect the jump target first: a wrong entry address, or an image linked for another base, runs garbage from a perfectly checksummed load. The next suspect is a bad image that was checksummed correctly (the checksum proves the bytes arrived, not that the code is right). The load path is cleared, because the checksum matched. The clear loop is not cleared by the checksum at all; only a separate test of the cleared region does that.

    Related topics

    • The NanoSoC Boot Flow in Time

    • Next: eFuse and OTP

    • RISC-V: Boot and Firmware Flow

    Previous

    162 / 289

    Next: eFuse and OTP

    Up next

    Up nexteFuse and OTP

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Reset Vector and Boot-Source Select