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
    • The Integrator Role and Handoffs
    • Spec to Tapeout Flow
    • Contracts and Ownership
    • Reading the SoC Spec
      • Requirements into Constraints and Budgets
      • Ambiguity Hunting
      • NanoSoC Requirement-to-Budget Trace
  • 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

←Reading the SoC Spec
  1. Topics
  2. SoC Design
  3. What SoC Integration Is
  4. Reading the SoC Spec
  5. NanoSoC Requirement-to-Budget Trace
On this page

    Part 1 of 14, lesson 12 of 12Part 1 of 14/What SoC Integration Is/Lesson 12 of 12All levels

    NanoSoC Requirement-to-Budget Trace

    One end-to-end trace from requirements to power, area, bandwidth and boot budgets, all recomputed.

    Why it matters

    Every review board asks the same question about a number: where was it earned? NanoSoC quotes 82.74 mW, 0.655 mm2, 682.6 MB/s and 12.581 ms across this course, and each of them must trace back to a requirement, a derivation and a check. Power, area, stream bandwidth and boot time each get that treatment below, recomputed from the per-block values. When a later lesson quotes one of these numbers, this trace is the receipt, and it is the worked example the first two lessons were building toward.

    The core idea

    Requirement

    Budget derivation

    Result and margin

    Run a 64-word DMA job on 90 mW or less (illustrative cap)

    Sum of per-block dynamic plus leakage in RUN

    82.74 mW; margin 7.26 mW (8.1% of the cap); CPU core alone 39.20 mW, 47.4% of RUN

    Idle under 20 mW, sleep under 2 mW (illustrative caps)

    Gate CPU, DMA and SBR clocks; switch PD_SW off

    IDLE 16.89 mW; SLEEP 1.40 mW with SRAM0 retained

    Fit the core in about 70% utilisation

    Block area plus 12% routing overhead against 0.940

    0.585 plus 0.070 is 0.655; utilisation 69.7%

    Stream 64 words without stalling the fabric

    512 bytes in 72 system clocks against both SRAM banks

    Demand 682.6 MB/s against 722.8 sustained; margin 5.6%

    Boot an 8 KB image inside 20 ms (illustrative cap)

    Reset chain plus ROM steps plus SPI load

    12.581 ms; SPI load 86.9%, banner 11.0%

    Two derivations carry the weight. Power is an addition over eighteen rows (the 16 blocks, 15 modules plus the PLL macro, with the CPU core and its cache and the power switches listed separately) with three operating points each, and the script checks all three totals plus the CPU share. Bandwidth is a placement argument: the SBR reads from one SRAM bank while writing the other, so the job's 512 bytes move at the combined sustained rate of 722.8 MB/s, and the 72-clock job fits with 5.6% margin. Put the stream bridge's source and destination in the same bank and each stream halves to 180.7 MB/s, which is why the trace also constrains buffer placement, not just the fabric. The 5.6% is an average over the 72-clock job, which is the fill-and-drain model with one word per clock and no burst bubbles. Counting one bubble per 16-beat burst, the four read bursts take 68 clocks and the job about 76 clocks (792 ns); during its 64 beats the read channel then needs 384 MB/s against 361.4 MB/s sustained. Read the 5.6% as planning margin on the average, not as peak headroom.

    The trace, recomputed

    The script below re-derives the power totals, the area roll-up and the stream-bandwidth margin from the per-block specification values, asserting every total the course quotes. It is long because addition over eighteen rows is long; that is the point. A budget earned by a script stays earned when the next engineer changes a block.

    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
    # Per block: (area, dyn_run, leak, dyn_idle, dyn_sleep, leak_sleep).
    # NanoSoC specification section 10, power in mW, area in mm2.
    BLOCKS = {
        "cpu":      (0.150, 38.00, 1.20, 1.90, 0.00, 0.02),
        "icache":   (0.025, 4.00, 0.30, 0.20, 0.00, 0.01),
        "axi_cdc":  (0.015, 3.00, 0.12, 0.30, 0.00, 0.00),
        "xbar":     (0.040, 5.00, 0.32, 0.50, 0.00, 0.01),
        "dma":      (0.012, 3.00, 0.10, 0.00, 0.00, 0.00),
        "sbr":      (0.010, 2.00, 0.08, 0.00, 0.00, 0.00),
        "axi2apb":  (0.006, 1.00, 0.05, 0.10, 0.00, 0.00),
        "apb_cdc":  (0.004, 0.50, 0.03, 0.05, 0.00, 0.00),
        "sram1":    (0.100, 6.00, 1.20, 0.30, 0.00, 0.02),
        "switches": (0.010, 0.00, 0.08, 0.00, 0.00, 0.00),
        "sram0":    (0.100, 6.00, 1.20, 0.30, 0.00, 0.72),
        "rom":      (0.012, 1.00, 0.14, 0.00, 0.00, 0.14),
        "uart":     (0.008, 0.30, 0.06, 0.30, 0.03, 0.06),
        "spi":      (0.008, 0.40, 0.06, 0.40, 0.04, 0.06),
        "gpio":     (0.006, 0.20, 0.05, 0.20, 0.02, 0.05),
        "intc":     (0.004, 0.20, 0.03, 0.20, 0.02, 0.03),
        "rstpwr":   (0.015, 0.50, 0.12, 0.50, 0.05, 0.12),
        "pll":      (0.060, 6.00, 0.50, 6.00, 0.00, 0.00),
    }
    
    def col(i):
        return sum(v[i] for v in BLOCKS.values())
    
    area = col(0)
    assert abs(area - 0.585) < 1e-9, area
    core = area * 1.12  # 12% clock tree, routing and fill
    assert abs(core - 0.655) < 0.001, core
    assert abs(core / 0.940 - 0.697) < 0.001  # utilisation 69.7%
    
    run = col(1) + col(2)
    assert abs(run - 82.74) < 0.01, run
    assert abs(col(1) - 77.10) < 1e-9 and abs(col(2) - 5.64) < 1e-9
    cpu_share = (38.00 + 1.20) / run
    assert abs(cpu_share - 0.474) < 0.001  # CPU core is 47.4% of RUN
    assert abs(col(3) + col(2) - 16.89) < 0.01  # IDLE
    assert abs(col(4) + col(5) - 1.40) < 0.01  # SLEEP, SRAM0 retained
    
    job_bytes = 2 * 64 * 4  # 64-word stream: read bank plus write bank
    job_ns = 72 * 10.417  # N + 8 system clocks
    demand = job_bytes / job_ns * 1000  # bytes/ns -> MB/s
    supply = 2 * 361.4  # both SRAM banks at burst-16 sustained
    assert abs(demand - 682.6) < 0.5, demand
    margin = (supply - demand) / supply
    assert margin > 0.05, margin
    print("PASS: 82.74/16.89/1.40 mW; area 69.7%%; stream margin %.1f%%"
          % (margin * 100))

    What the review looks for

    • The trace recomputes from per-block values, never by quoting a total from memory.

    • Every requirement in the left column carries its cap, condition and owner from the earlier lessons.

    • Any block change re-runs the script before the budget table is updated.

    Verify and debug

    When a budget breaks, the script says which column moved: power, area or bandwidth. Resist adjusting the margin first; the margin is the last defence, and spending it silently is how a project discovers at signoff that every budget is exact and none is met. The boot-time half of the trace was already recomputed in the flow topic; together the two scripts cover all four budgets.

    Power budget from the wrong activity: a RUN figure quoted for one stated activity while the product can run many blocks at their peak at once, so the supply grid, designed to the quoted figure, droops. Symptom: speed fails or the chip resets only under maximum activity. The 82.74 mW row is a budget for the activity the trace names; any use case with more concurrent activity needs its own row, and dynamic IR analysis with realistic worst-case vectors is the check that catches the difference.

    If asked where the power goes, answer 82.74 mW with the split: 77.10 dynamic, 5.64 leakage, CPU core nearly half. Then give the sleep story: SLEEP at 1.40 mW against IDLE at 16.89 mW saves 15.49 mW, at the cost of the 14.07 microsecond wake sequence.

    Check yourself A new peripheral adds 2 mW dynamic in RUN. Which budgets move, and does anything break?

    RUN rises to 84.74 mW, still inside the 90 mW cap, and the margin falls from 7.26 mW to 5.26 mW (5.8%); the area roll-up also gains the block plus overhead. Nothing breaks unless a cap binds; the trace re-runs, the margins shrink on the record, and the owner of the new block signs the row.

    Related topics

    • Ambiguity Hunting

    • Spec to Tapeout Flow

    • NanoSoC Tour

    Previous

    17 / 289

    Next: Architecture and Budgets

    Up next

    Up nextArchitecture and Budgets

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Requirements into Constraints and Budgets