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
  • IP Integration and Handoff21
  • Top-Level Verification and Bring-up21
  • Package, Pads and I/O18
  • Chip Signoff and Tapeout18
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC19
Loading lesson

←SoC Design
  1. Topics
  2. SoC Design
  3. SoC Cheatsheet
On this page

    SoC DesignAll levels

    SoC Cheatsheet

    One-page revision of the SoC integration formulas, response codes, the NanoSoC address map and clock tables, the reset, power and boot sequences, the interrupt and DMA facts, and the integration and pre-tapeout checklists.

    Revision sheets drawn from the course. Formulas are exact where they are definitions. Every NanoSoC number is a teaching value from the running chip; none is a target for any real process or product. Addresses are byte addresses, sizes use 1 KB = 1024 bytes and MB/s means 10^6 bytes per second.

    Formulas

    Diagram
    peak bandwidth        = W x f                      W = 4 bytes, f = 96 MHz  ->  384.0 MB/s
    burst efficiency      = L / (L + 1)                one bubble cycle per burst of L beats
    sustained bandwidth   = peak x efficiency          min over every link of the path
    single-port memory    = reads + writes share one port, each of two streams gets sustained / 2
    APB access            = bytes x f / cycles per access (2 without wait state, 3 with one)
    period                = 1000 / f(MHz) ns           1 T_sys = 2 T_cpu, 1 T_per = 4 T_sys = 8 T_cpu
    PLL output            = f_ref x N / R              24 x 32 / 1 = 768 MHz; dividers 4 and 8
    baud                  = clk_per / (16 x BAUDDIV)   24e6 / (16 x 13) = 115,384.6
    SPI clock             = clk_per / (2 x (CLKDIV + 1))   CLKDIV = 1  ->  6 MHz
    DMA job time          = (N + 8) clk_sys            N = 64  ->  72 cycles = 750 ns
    interrupt latency     = 3 T_per + 2 T_cpu best; + T_per + T_cpu worst   135.4 / 182.3 ns
    utilisation           = core area / die core budget   0.655 / 0.940 = 69.7%
    power in a state      = dynamic + leakage          RUN 82.74, IDLE 16.89, SLEEP 1.40 mW
    energy                = power x time               82.74 mW x 750 ns = 62.1 nJ
    aligned base          = base mod size == 0         sizes are powers of two
    last address          = base + size - 1

    Response codes

    Code

    Where

    Meaning

    NanoSoC example

    OKAY (2'b00)

    AXI RRESP and BRESP

    Access completed normally.

    Any access to a mapped, permitted address.

    EXOKAY (2'b01)

    AXI RRESP and BRESP

    Exclusive access succeeded.

    Not used: the fabric has no exclusive access.

    SLVERR (2'b10)

    AXI RRESP and BRESP

    A slave was reached and refused or failed the access.

    Non-secure access to SRAM1; a write to the read-only ROM window; APB hole H3 (via PSLVERR).

    DECERR (2'b11)

    AXI RRESP and BRESP

    No slave claims the address.

    Holes H1, H2 and H4, from the default slave.

    PSLVERR = 1

    APB, in the completing cycle

    APB slave error; the bridge makes it SLVERR.

    DMA offset not in 0x00, 0x04, 0x08, 0x0C, 0x10; any reserved slot 7 to 15.

    NanoSoC address map

    Region

    Base

    End

    Size

    Secure

    Notes

    BOOTROM

    0x0000_0000

    0x0000_3FFF

    16 KB

    S and NS read

    Reset vector at 0x0000_0000

    Hole H1

    0x0000_4000

    0x1FFF_FFFF

    -

    -

    DECERR

    SRAM0

    0x2000_0000

    0x2000_FFFF

    64 KB

    S and NS

    Retained in SLEEP; stack top 0x2001_0000

    SRAM1

    0x2001_0000

    0x2001_FFFF

    64 KB

    Secure only

    NS access gives SLVERR

    Hole H2

    0x2002_0000

    0x3FFF_FFFF

    -

    -

    DECERR

    DMA

    0x4000_0000

    0x4000_0FFF

    4 KB

    NS OK

    Registers 0x00 to 0x10; aliased 16 times

    SBR

    0x4000_1000

    0x4000_1FFF

    4 KB

    NS OK

    SRC_ADDR, DST_ADDR, LEN, CTRL, STATUS

    UART

    0x4000_2000

    0x4000_2FFF

    4 KB

    NS OK

    SPI

    0x4000_3000

    0x4000_3FFF

    4 KB

    NS OK

    GPIO

    0x4000_4000

    0x4000_4FFF

    4 KB

    NS OK

    INTC

    0x4000_5000

    0x4000_5FFF

    4 KB

    NS OK

    RSTPWR

    0x4000_6000

    0x4000_6FFF

    4 KB

    Secure only

    Hole H3

    0x4000_7000

    0x4000_FFFF

    36 KB

    -

    PSLVERR then SLVERR

    Hole H4

    0x4001_0000

    0xFFFF_FFFF

    -

    -

    DECERR

    Diagram
    decode (nano_xbar):  addr[31:14] == 0       ROM
                         addr[31:16] == 0x2000  SRAM0
                         addr[31:16] == 0x2001  SRAM1
                         addr[31:16] == 0x4000  APB bridge, then addr[15:12] = slot (0 to 6 mapped, 7 to 15 default)
                         otherwise              default slave -> DECERR
    secure filter:       AxPROT[1] == 0 secure, 1 non-secure
    DMA registers:       0x00 CTRL  0x04 STATUS  0x08 LEN  0x0C KEY  0x10 COUNT   (byte offsets, 8-bit paddr)
    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
    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
    50
    # decode and map check in one place; the checker must be able to FAIL
    regions = [
        ("BOOTROM", 0x0000_0000, 0x4000), ("SRAM0", 0x2000_0000, 0x1_0000), ("SRAM1", 0x2001_0000, 0x1_0000),
        ("DMA", 0x4000_0000, 0x1000), ("SBR", 0x4000_1000, 0x1000), ("UART", 0x4000_2000, 0x1000),
        ("SPI", 0x4000_3000, 0x1000), ("GPIO", 0x4000_4000, 0x1000), ("INTC", 0x4000_5000, 0x1000),
        ("RSTPWR", 0x4000_6000, 0x1000),
    ]
    
    def check_map(regs):
        problems = []
        for name, base, size in regs:
            if size & (size - 1):
                problems.append(name + " size is not a power of two")
            elif base % size:
                problems.append(name + " base is not aligned to its size")
        ordered = sorted(regs, key=lambda r: r[1])
        for a, b in zip(ordered, ordered[1:]):
            if a[1] + a[2] > b[1]:
                problems.append(a[0] + " overlaps " + b[0])
        return problems
    
    def decode(addr, secure=True):
        if addr >> 14 == 0:
            return "BOOTROM", "OKAY"
        if addr >> 16 == 0x2000:
            return "SRAM0", "OKAY"
        if addr >> 16 == 0x2001:
            return "SRAM1", "OKAY" if secure else "SLVERR"
        if addr >> 16 == 0x4000:
            slot = (addr >> 12) & 0xF
            names = ["DMA", "SBR", "UART", "SPI", "GPIO", "INTC", "RSTPWR"]
            return (names[slot], "OKAY") if slot < 7 else ("default APB slave", "SLVERR")
        return "default slave", "DECERR"
    
    assert check_map(regions) == []
    assert regions[-1][1] + regions[-1][2] - 1 == 0x4000_6FFF
    # the planted overlap: an 8 KB DMA window collides with the SBR slot
    bad = [("DMA", 0x4000_0000, 0x2000) if r[0] == "DMA" else r for r in regions]
    assert check_map(bad) == ["DMA overlaps SBR"]
    # a misaligned base is caught too
    assert check_map([("X", 0x4000_0800, 0x1000)]) == ["X base is not aligned to its size"]
    
    assert decode(0x0000_4000) == ("default slave", "DECERR")          # H1
    assert decode(0x2002_0000) == ("default slave", "DECERR")          # H2
    assert decode(0x4000_7000) == ("default APB slave", "SLVERR")      # H3
    assert decode(0x4001_0000) == ("default slave", "DECERR")          # H4
    assert decode(0x2001_0000, secure=False) == ("SRAM1", "SLVERR")
    assert decode(0x4000_0100)[0] == "DMA"                              # the alias image
    assert decode(0x4000_6000)[0] == "RSTPWR"
    print("PASS: map is clean, planted overlap and misalignment are caught, holes answer as listed")

    Clocks and crossings

    Domain

    Frequency

    Period

    Source

    Blocks

    clk_cpu

    192 MHz

    5.208 ns

    768 / 4

    CPU core, I-cache, CPU side of the async AXI bridge

    clk_sys

    96 MHz

    10.417 ns

    768 / 8

    Fabric, SRAMs, ROM, DMA, SBR, AXI to APB bridge, APB decoder, bridge system side

    clk_per

    24 MHz

    41.667 ns

    Crystal, bypasses the PLL

    UART, SPI, GPIO, INTC, reset and power controller, bridge peripheral side

    • Ratio clk_cpu : clk_sys : clk_per = 8 : 4 : 1. The first two share a PLL but are signed off as asynchronous.

    • Ten crossing groups. Rule: nothing multi-bit crosses without a handshake or a FIFO, nothing single-bit crosses without two flops. Clock gates are not crossings.

    • Gates: clk_cpu on wfi; clk_dma and clk_sbr on CLK_EN bits; all latch-based and enabled by the reset and power controller.

    • PLL lock 256 clk_per = 10.667 us. Clocks open only after lock.

    Resets

    Source

    Condition

    Resets

    RST_CAUSE bit

    por_n

    Supply below threshold

    Everything including RST_CAUSE

    [0] POR

    pad_rst_n

    Pin low for more than 16 clk_per

    Everything except RST_CAUSE and SRAM contents

    [1] PAD

    sw_rst

    SWRST write with key 0xA5

    rst_sys_n and rst_cpu_n for 16 clk_sys

    [2] SW

    pwr_rst

    PD_SW powers up

    rst_sys_n and rst_cpu_n

    [3] WAKE

    Diagram
    cold boot release (hardware 53.948 us):
      R1 oscillator ready      1024 clk_per   42.667 us
      R2 rst_per_n released       2 clk_per   83.333 ns
      R3 PLL locked             260 clk_per   10.833 us
      R4 clock gates open         2 clk_per   83.333 ns
      R5 rst_sys_n released      18 clk_sys   187.5 ns
      R6 rst_cpu_n released   8 clk_sys + 2 clk_cpu   93.75 ns      slaves and fabric first, CPU last
    reset is asserted asynchronously, released synchronously in each domain (2-flop nano_rst_sync)

    Power

    State

    PD_AON

    PD_SW

    PLL

    Power

    Entry

    Exit

    RUN

    on

    on

    on

    82.74 mW

    Boot or wake

    wfi or SW_OFF_REQ

    IDLE

    on

    on, CPU clock gated

    on

    16.89 mW

    CPU wfi

    Any enabled interrupt

    SLEEP

    on, SRAM0 retained

    off, outputs isolated

    off

    1.40 mW

    SW_OFF_REQ

    GPIO, UART or power interrupt

    Diagram
    power-down (70 clk_per = 2.917 us):  quiesce DMA and SBR -> iso_sw_en (2) -> gate clocks (2) -> assert resets (2) -> open switch, ramp 64
                                            isolation before reset before power off
    power-up (wake, 14.073 us):            close switch, ramp 64 -> pgood +8 -> PLL relock 256 -> clocks open +2
                                            -> release isolation (+4 clk_sys) -> rst_sys_n (18 clk_sys) -> rst_cpu_n (8 clk_sys + 2 clk_cpu)
                                            RST_CAUSE[3] set; ROM jumps to 0x2000_0000 (SRAM0 retained)
    isolation: 47 (APB bridge) + 52 (SRAM0 port) + 13 (ROM port) + 2 (irq_dma, irq_sbr) = 114 clamps to 0; AON to SW needs none
    one voltage (0.9 V): isolation only, no level shifters

    Interrupts and the DMA

    IRQ

    Name

    Clear by

    Priority

    0

    irq_pwr

    W1C PWR_IRQ

    0 (highest)

    1

    irq_dma

    W1C DONE and ERR in DMA STATUS, or clear IRQ_EN

    1

    2

    irq_sbr

    W1C in SBR STATUS

    2

    3

    irq_uart

    Read or write DATA

    3

    4

    irq_spi

    Read DATA

    4

    5

    irq_gpio

    Remove the condition

    5

    6, 7

    Reserved, tied to 0

    n/a

    6, 7

    • All inputs are active-high levels. PENDING = RAW & ENABLE. TOP returns the lowest pending index, 0x1F if none. A pulse under 2 clk_per (83.3 ns) can be missed.

    • DMA CTRL: write 0x3 to start with the interrupt on (a write of 0x1 clears IRQ_EN). LEN and KEY writes are ignored while BUSY, with no error. GO does not clear ERR: write 0x6 to STATUS after every job.

    • SBR LEN and DMA LEN are separate: set both to the same word count. SBR CTRL.NS resets to 1 (non-secure); a secure source needs it cleared, and because the SBR slot is non-secure, non-secure software can clear it too: known weakness, partition not closed.

    • Source and destination in one SRAM bank halve the stream rate to 180.7 MB/s each.

    Boot flow

    Diagram
    hardware reset            53.948 us   (0.43% of boot)
    first fetch (line fill)  125 ns
    read RST_CAUSE           281.25 ns    WAKE: skip the clear, SRAM0 holds the image
    clear 4 KB of SRAM0       10.667 us   (cold boot only)
    UART init                843.75 ns
    banner, 16 chars       1,386.667 us   (11.0%)
    DMA self-test              8.385 us
    SPI load 8196 bytes   10,928.000 us   (86.9%)
    checksum 2048 words      192.000 us
    jump to 0x2000_0000        total 12.581 ms

    Checklists

    Block handoff into the top (before wiring)

    • Collateral complete and versioned: RTL, register description, constraints, power intent, test and debug models, change notices.

    • Port widths and address conventions recorded per block (for example byte offsets against word offsets, 8 address bits against 12).

    • Clock, reset and power domain of every port named; every crossing has a mechanism.

    • Reset values and what writes to read-only, busy and unmapped locations do are written down.

    • Unused inputs have tie-offs, unused outputs are listed, and lint runs with width errors not waived.

    Before tapeout

    • Map checker clean on the frozen map description: no overlap, every base aligned, holes and aliases listed and tested.

    • Connectivity and register sweeps pass on the frozen baseline, including each interrupt line against its controller input.

    • Reset order proven: the CPU leaves reset last, in simulation of the netlist as well as the RTL.

    • Power-aware simulation switched the domain off and on; all 114 clamps present and enabled before reset and power-off.

    • Crossing inventory matches the ten groups; no open crossing violations.

    • Every waiver has an owner, evidence, a review-by date and an expiry; none is past expiry.

    • Pad reset states and pulls reviewed against the ball-out (strap and test pins too, on any chip that has them: NanoSoC v1 has none).

    • Manifest checker passes against the baseline tuple; each owner has signed their evidence.

    First suspect for a symptom

    Symptom

    First suspect

    CPU stalls at PC = 0x0000_0000, ARVALID high, no RVALID

    Reset release order: CPU released with or before the fabric

    DMA output has bit 0 flipped after the SBR is started

    Overlapping decode windows: an SBR write also wrote the DMA KEY

    DMA DONE is set and irq high, but the ISR never runs

    Interrupt wired to the wrong controller input (check RAW)

    Only CTRL reads right; STATUS, LEN, KEY give PSLVERR and a COUNT read returns STATUS

    Address connected as word offsets instead of byte offsets

    Interrupt missed once in thousands of jobs

    Missing two-flop synchroniser on a crossing

    Sleep and wake loop, X on always-on side

    Missing isolation on interrupt or memory-port signals

    SBR ERR when copying from SRAM1

    SBR issues non-secure accesses: NS attribute reset value

    DMA ERR with COUNT short, or SBR BUSY forever

    LEN mismatch between the DMA and the SBR

    Second job wrong or irq stuck high

    LEN or KEY write ignored while BUSY; stale ERR not cleared

    CPU hangs on first DMA access after CLK_EN = 0

    Clock gated during an APB access with no bridge timeout

    A checklist run on a stale baseline proves nothing. Write the baseline tuple (design, constraints, tool versions, date) at the top of every run, and rerun the fastest check, the map checker, whenever the map description changes.

    Check yourself Software reads 0x4000_0204 and gets what looks like the DMA STATUS value. Is that a bug in the DMA?

    No. It is the alias: the slot is 4 KB but the DMA decodes only 8 address bits, so its 256-byte window repeats 16 times. Address 0x4000_0204 is offset 0x04 of the image at 0x4000_0200, which is STATUS. The remedy is a software rule (use only 0x4000_0000 to 0x4000_00FF) and a test that no slave uses apb_paddr[11:8], not a change inside the DMA.

    Related topics

    • Glossary

    • Metrics Reference

    • Reading Path

    • Up: course hub

    Previous

    5 / 294

    Next: What SoC Integration Is

    Up next

    Up nextWhat SoC Integration Is

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • How to Use This Course
    • The NanoSoC Tour
    • Reading Path