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 NanoSoC14
Loading lesson

←SoC Design
  1. Topics
  2. SoC Design
  3. The NanoSoC Tour
On this page

    SoC DesignAll levels

    The NanoSoC Tour

    The running chip of the course: its blocks, address map, clocks, resets, power, interrupts and boot flow, with every number the lessons quote.

    NanoSoC is a small 32-bit system that the whole course integrates together. A generic in-order core fetches through a 4 KB instruction cache, crosses into a 96 MHz AXI4 fabric with two masters and four slaves, and reaches on-chip ROM and RAM, a streaming DMA fed by a stream bridge, and a slow peripheral subsystem behind two bridges. One controller owns clocks, resets and power; one controller gathers eight interrupts. This page is the single place every number in the course comes from: the block list, the address map, the three clocks, the three resets, the two power domains, the interrupt table and the boot flow. When any two pages disagree, this one wins.

    Block diagram

    NanoSoC block diagram: the CPU, crossbar, memories, DMA path and peripheral buses.
    NanoSoC block diagram: the CPU, crossbar, memories, DMA path and peripheral buses.

    Solid edges carry bus traffic and dotted edges are interrupts. The data path SRAM0 to DMA to SRAM1 runs through the fabric: the SBR is the second master of nano_xbar, it reads one SRAM through the crossbar, streams the words through the DMA, and writes them back to the other SRAM through the crossbar. nano_rstpwr sits with the slow peripherals and drives the reset, clock and power sequences.

    Block list

    Block

    Role in one line

    Clock

    Power

    nano_cpu

    Generic 32-bit in-order core, 4 KB I-cache, one AXI4 master port

    clk_cpu

    PD_SW

    nano_axi_cdc_m

    Asynchronous AXI bridge between the CPU port and the fabric

    clk_cpu / clk_sys

    PD_SW

    nano_xbar

    AXI4 interconnect, 2 masters by 4 slaves, round-robin, secure filter, default slave

    clk_sys

    PD_SW

    nano_sram0

    64 KB on-chip RAM, retained when PD_SW is off

    clk_sys

    PD_AON

    nano_sram1

    64 KB on-chip RAM, secure-only

    clk_sys

    PD_SW

    nano_rom

    16 KB boot ROM, holds the reset vector

    clk_sys

    PD_AON

    nano_dma

    The UVM course DMA: XOR-with-KEY stream DMA, APB registers, AXI-Stream in and out, one interrupt

    clk_sys

    PD_SW

    nano_sbr

    Stream bridge: AXI4 master that turns memory into a stream and back, with an APB register block

    clk_sys

    PD_SW

    nano_axi2apb + nano_apb_dec

    AXI4 slave to APB bridge plus the APB slot decoder

    clk_sys

    PD_SW

    nano_apb_cdc

    APB request and acknowledge bridge to the slow peripherals

    clk_sys / clk_per

    PD_SW

    nano_uart

    UART, 8N1, 16x oversampling, one interrupt

    clk_per

    PD_AON

    nano_spi

    SPI master, mode 0, loads the second-stage image

    clk_per

    PD_AON

    nano_gpio

    16 pins, direction register, level interrupt

    clk_per

    PD_AON

    nano_intc

    Interrupt controller: 8 level inputs, one level output, fixed priority

    clk_per

    PD_AON

    nano_rstpwr

    Reset, clock and power controller, with the PLL wrapper and the power sequencer

    clk_per

    PD_AON

    PLL (analog macro)

    24 MHz in, 768 MHz VCO out

    clk_xtal

    PD_AON

    The top module is nanosoc_top. Pads and the crystal sit outside it: the chip has 31 pads (19 signal and 12 supply), in a conceptual 36-ball package. Where a lesson needs the wiring detail, the DMA's ports and the crossing inventory are given below; the full per-pin tables live in the lessons.

    Address map

    A 32-bit physical address, byte addressed, little endian. Peripheral registers are 32-bit and word aligned. Every base is aligned to its own power-of-two size, and no two rows overlap.

    Region

    Base

    Size

    End

    Notes

    BOOTROM

    0x0000_0000

    16 KB

    0x0000_3FFF

    Reset vector at 0x0000_0000; readable secure and non-secure

    Hole H1

    0x0000_4000

    0x1FFF_C000

    0x1FFF_FFFF

    No slave: default slave answers DECERR

    SRAM0

    0x2000_0000

    64 KB

    0x2000_FFFF

    Retained in SLEEP; stack top 0x2001_0000

    SRAM1

    0x2001_0000

    64 KB

    0x2001_FFFF

    Secure-only: a non-secure access returns SLVERR

    Hole H2

    0x2002_0000

    0x1FFE_0000

    0x3FFF_FFFF

    DECERR

    DMA

    0x4000_0000

    4 KB

    0x4000_0FFF

    Registers at 0x00 to 0x10; aliased 16 times, see below

    SBR

    0x4000_1000

    4 KB

    0x4000_1FFF

    SRC, DST, LEN, CTRL, STATUS

    UART

    0x4000_2000

    4 KB

    0x4000_2FFF

    SPI

    0x4000_3000

    4 KB

    0x4000_3FFF

    GPIO

    0x4000_4000

    4 KB

    0x4000_4FFF

    INTC

    0x4000_5000

    4 KB

    0x4000_5FFF

    RAW, ENABLE, PENDING, TOP

    RSTPWR

    0x4000_6000

    4 KB

    0x4000_6FFF

    Secure-only

    Hole H3

    0x4000_7000

    36 KB

    0x4000_FFFF

    Reserved APB slots: PSLVERR, seen as AXI SLVERR

    Hole H4

    0x4001_0000

    0xBFFF_0000

    0xFFFF_FFFF

    DECERR

    Decode in nano_xbar: addr[31:14] all zero selects ROM; addr[31:16] equal to 0x2000 selects SRAM0, 0x2001 SRAM1, 0x4000 the APB bridge; anything else reaches the default slave. Inside the APB window nano_apb_dec uses addr[15:12] as the slot number: slots 0 to 6 are mapped, slots 7 to 15 hit the default APB slave. The secure filter checks AxPROT[1], where 0 means secure and 1 means non-secure, at the interconnect and again per APB slot. DECERR is 2'b11 and SLVERR is 2'b10 on RRESP and BRESP. The deliberate alias: the decoder gives each slot 12 address bits but the DMA has only an 8-bit paddr port, so the wrapper passes apb_paddr[7:0] and the 256-byte DMA window repeats 16 times across 0x4000_0000 to 0x4000_0FFF. Software uses only 0x4000_0000 to 0x4000_00FF; offsets 0x14 to 0xFF inside each image still answer PSLVERR.

    Clocks and domains

    Domain

    Frequency

    Period

    Blocks

    clk_cpu

    192 MHz (768/4)

    5.208 ns

    nano_cpu, I-cache, CPU side of nano_axi_cdc_m

    clk_sys

    96 MHz (768/8)

    10.417 ns

    Fabric, memories, ROM, DMA, SBR, AXI-to-APB path, system side of both CDC bridges

    clk_per

    24 MHz (crystal)

    41.667 ns

    UART, SPI, GPIO, INTC, RSTPWR, peripheral side of nano_apb_cdc

    One 24 MHz crystal feeds a PLL with reference divide 1 and feedback multiply 32, so the VCO runs at 768 MHz, inside the 600 to 1200 MHz teaching range. Post-VCO dividers of 4 and 8 give clk_cpu and clk_sys; clk_per is the crystal itself, bypassing the PLL, so peripherals, the reset controller and wake logic keep running while the PLL is off. The lock counter waits 256 clk_per cycles, 10.667 us. The ratio is clk_cpu : clk_sys : clk_per = 8 : 4 : 1. The CPU and system clocks come from one PLL and are phase-related, but signoff treats them as asynchronous: separate roots after the divider, separate trees. Clock gating is glitch-free and latch-based throughout: the CPU clock gates on wfi, and clk_dma and clk_sbr gate on the CLK_EN bits in nano_rstpwr, all enabled by nano_rstpwr.

    Resets

    Four sources feed one controller, nano_rstpwr, which fans out three active-low nets, each asynchronously asserted and synchronously released through a two-flop synchroniser in its own domain. por_n comes from the analog power-on-reset cell and clears everything including the cause register. pad_rst_n comes from the RESET_N pin, debounced over 16 clk_per cycles (666.7 ns), and clears everything except the cause register and SRAM0 contents. sw_rst is a software write to RSTPWR.SWRST with the 0xA5 key, and resets rst_sys_n and rst_cpu_n only, for 16 clk_sys cycles. pwr_rst is the power-up of PD_SW. The rule is slaves and fabric first, masters last: rst_per_n leaves first, then rst_sys_n, and the CPU is the last thing to leave reset, 8 clk_sys plus 2 clk_cpu after rst_sys_n. The hardware sequence from por_n release to the CPU leaving reset takes 53.948 us, dominated by the 1024-cycle oscillator wait and the 256-cycle PLL lock.

    Power domains

    One voltage, 0.9 V, so there are no level shifters, only isolation. PD_AON is always on and holds nano_rstpwr, the PLL, nano_intc, nano_uart, nano_spi, nano_gpio, nano_sram0 and nano_rom; the SRAM0 arrays sit in PD_AON while their wrapper logic sits in PD_SW. PD_SW holds everything else: the CPU, both CDC bridges, the fabric, SRAM1, the DMA, the SBR and the APB path. RUN keeps everything on; IDLE gates the CPU clock; SLEEP switches PD_SW off with SRAM0 retained at 0.6 times its leakage. Power-down takes 70 clk_per (2.917 us) in the order isolate, gate the clocks, reset, then power off. Wake takes 14.073 us: switch ramp, power-good, PLL relock, clocks open, isolation released while the resets are still asserted, then rst_sys_n and last rst_cpu_n, with RST_CAUSE[3] set and the ROM jumping to the retained SRAM0 image. Isolation clamps to 0 on all 114 signals from PD_SW into PD_AON: 47 from the apb_cdc peripheral side, 52 on the SRAM0 macro port, 13 on the ROM port, and the two interrupt lines. The area and power figures are NanoSoC teaching values: 0.585 mm2 of blocks, 0.655 mm2 with clock tree, routing and fill, against a 0.940 mm2 budget (69.7% utilisation); RUN 82.74 mW, IDLE 16.89 mW, SLEEP 1.40 mW.

    Interrupts

    All eight inputs are active-high levels held by the source until software clears them. nano_intc stores nothing: PENDING equals RAW anded with ENABLE, the output irq_cpu is one active-high level to the CPU, and priority is fixed with the lowest number winning. A pulse shorter than 2 clk_per cycles (83.3 ns) can be missed.

    IRQ

    Name

    Source

    Cleared by

    0

    irq_pwr

    nano_rstpwr, OR of PWR_IRQ

    Write-1-to-clear PWR_IRQ

    1

    irq_dma

    nano_dma, interrupt enable ANDed with done-or-err

    Write-1-to-clear DONE or ERR in DMA STATUS

    2

    irq_sbr

    nano_sbr, enable ANDed with done-or-err

    Write-1-to-clear in SBR STATUS

    3

    irq_uart

    Transmit-empty or receive-not-empty, each gated by its enable

    Read or write DATA

    4

    irq_spi

    Enable ANDed with receive-not-empty

    Read DATA

    5

    irq_gpio

    OR of data inputs ANDed with enables

    Remove the pin condition

    6-7

    Reserved

    Tied to 0

    Not applicable

    From irq_dma rising to irq_cpu reaching the CPU takes 135.4 ns in the best case and 182.3 ns in the worst, through the two-flop synchroniser into clk_per, the controller register, and the two-flop synchroniser into clk_cpu.

    Boot flow

    Cold boot takes 12.581 ms from por_n release to the jump to 0x2000_0000, under a blocking model with a cold instruction cache. The hardware reset sequence above is only 0.43% of that. The ROM first reads RST_CAUSE: a wake skips the clear because SRAM0 is retained and holds the image. On a cold boot it sets the stack pointer to 0x2001_0000 and clears 4 KB of SRAM0, then initialises the UART, prints the 16-character banner at 115,384.6 baud (24 MHz divided by 16 times 13), and self-tests the DMA before loading anything: five reads check the reset values, seven writes program the key, the DMA length and start, and the SBR source, destination, length and start, the 64-word job runs in 72 clk_sys (750 ns), and 64 words are read back and compared. The second-stage image is 8 KB at 0x2000_0000, read over SPI at 6 Mb/s with a 4-byte command, then checksummed as 2048 single-word reads. The shares: the SPI load 86.9%, the UART banner 11.0%, everything else 2.1%. The boot lesson replays this table step by step.

    The reused DMA and the stream bridge

    The DMA is the UVM course's dma_dut, wrapped as nano_dma with WAIT_STATES set to 1, so one APB access takes 3 clocks. It has no AXI memory master: data enters on AXI-Stream and leaves on AXI-Stream. Its registers live at offsets 0x00 (CTRL: bit 0 GO, bit 1 IRQ_EN; every write copies bit 1 into IRQ_EN, and bit 0 reads back 0), 0x04 (STATUS: bit 0 BUSY read-only, bits 1 and 2 DONE and ERR, each write-1-to-clear), 0x08 (LEN, 16 bits of words to move), 0x0C (KEY, the 32-bit XOR key) and 0x10 (COUNT, words moved, cleared by GO). Any other offset in the 8-bit paddr space answers PSLVERR. After GO with a nonzero LEN, s_tready stays high whenever the one-word output register is free, each accepted word is stored as the input XOR KEY, and the LEN-th accepted word sets m_tlast, clears BUSY and sets DONE on the same edge. An early s_tlast ends the job with ERR instead; a GO with LEN 0 sets DONE at once and moves nothing; a GO while BUSY is ignored without an error; LEN and KEY writes while BUSY are silently ignored; GO clears DONE but never ERR; and the interrupt is a level, enable ANDed with done-or-err, held until software clears it. Because the DMA cannot touch memory itself, NanoSoC adds the stream bridge nano_sbr: an AXI4 master whose read engine turns SRAM words into the DMA's input stream and whose write engine turns the DMA's output stream back into SRAM words. The bridge has its own APB block with SRC_ADDR, DST_ADDR, LEN, CTRL (START, IRQ_EN, and the NS bit that sets AxPROT[1], reset to non-secure) and STATUS (BUSY, DONE, ERR for AXI error responses seen). Software writes one word count to both LEN registers, because the two lengths are separate and a mismatch stalls or errors the job. Known weakness of NanoSoC v1: the SBR register slot is non-secure, so non-secure software can clear NS and reach SRAM1 through the SBR; the partition is not closed until NS is writable only from the secure side. The UVM bench runs the DMA at 100 MHz; inside NanoSoC it runs at clk_sys, 96 MHz. For the block behind the wrapper see The DMA You Will Verify.

    Where each part is taught

    If you want

    Read

    The integrator's desk: roles, handoffs, milestones

    What the Integrator Owns

    Budgets: area, timing, power, bandwidth

    Area Roll-Up, Link Table and Sustained Rates

    This address map, designed and checked

    Sizes, Alignment and Windows, Holes, Aliases and Reserved Space

    Decode, default slaves and error answers

    Generating Decode from a Map Table, DECERR Versus SLVERR Versus PSLVERR

    The secure partition

    Secure and Non-Secure Regions, Secure-Access Filters

    The fabric, the bridges and the burst rules

    Shared Bus, Crossbar and Hierarchy, The 4 KB Rule and Burst Splitting

    The PLL, the dividers and the three domains

    Crystal, PLL and Dividers, Choosing Domains and Ratios

    Resets and the release order

    Release Order and Timing

    The ten crossings

    The Ten Crossings

    Power states, isolation and the cold-start line

    RUN, IDLE and SLEEP, Where the 114 Clamps Go, One Timeline from POR to First Fetch

    Interrupts, routing and latency

    The Wiring Table and the Controller Sketch, From DMA irq to CPU Entry

    The DMA and the stream bridge

    Programming the DMA Registers, The Stream Bridge and Length Agreement

    Memories, the boot ROM and this boot flow

    Macro Choice and Wrappers, The NanoSoC Boot Flow in Time

    Security across the chip

    The AxPROT Partition

    IP handoff and integration checks

    IP Integration and Handoff

    Top-level verification and bring-up

    Top-Level Verification and Bring-up

    Package, pads and I/O

    Package, Pads and I/O

    Signoff, waivers and tapeout

    Chip Signoff and Tapeout

    Interview preparation

    Interview Prep

    The full integration, checked end to end

    Capstone: Integrate NanoSoC

    The ten planted bugs

    Ten integration mistakes are planted in the lab data for the capstone to catch. Their names only, no spoilers:

    #

    Name

    1

    Address overlap

    2

    Reset release order

    3

    Mis-wired interrupt

    4

    Width and addressing mismatch

    5

    Unsynchronised crossing

    6

    Missing isolation

    7

    Secure attribute mismatch

    8

    Stream length mismatch

    9

    Silently ignored writes while BUSY, and sticky ERR

    10

    Clock gated off during an APB access

    Each one is a real failure with a symptom, a root cause and a fix, and each is guarded by a check the course installs. They all meet again in the Capstone, whose final script prints PASS only when the stage checks and the ten-bug test matrix agree.

    Headline numbers, rechecked

    The script below rechecks the numbers this page is most quoted for: the burst-16 sustained rate with its shared-bank half, and the boot-time shares. Change an input and see which assertion breaks first.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    PEAK = 4 * 96.0  # 32-bit fabric at 96 MHz: 384.0 MB/s
    SUSTAINED_16 = PEAK * 16 / 17  # one bubble per burst
    assert abs(PEAK - 384.0) < 1e-9
    assert abs(SUSTAINED_16 - 361.4) < 0.05
    assert abs(SUSTAINED_16 / 2 - 180.7) < 0.05  # shared bank splits the port
    
    BOOT_US = 12580.917
    assert abs(10928.0 / BOOT_US - 0.869) < 0.001  # SPI load share
    assert abs(1386.667 / BOOT_US - 0.110) < 0.001  # UART banner share
    assert abs(53.948 / BOOT_US - 0.00429) < 0.00001  # hardware reset share
    
    print("PASS: fabric 361.4, shared 180.7 each; boot 86.9% SPI, 11.0% banner, 0.43% reset")
    Check yourself The SBR reads SRAM0 and writes SRAM1 at the full stream rate, then both ends move to SRAM0. What changes, and why?

    Each stream drops from 361.4 MB/s to about 180.7 MB/s: one single-port bank serves reads and writes together, so the two streams split the port.

    Related topics

    • Up: course hub

    • How to Use This Course

    • Glossary

    • IP Integration and Handoff

    Previous

    2 / 289

    Next: Reading Path

    Up next

    Up nextReading Path

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • SoC Glossary
    • SoC Metrics Reference
    • SoC Cheatsheet