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
    • Partitioning and Hierarchy
    • Area Budgets
    • Timing Budgets Across Hierarchy
    • Power Budgets
    • Bandwidth Budgets
      • Workload to Bandwidth
      • Link Table and Sustained Rates
      • Spotting the Bottleneck
    • Budget Governance
    • Multi-Die and Chiplet View
  • 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

←Bandwidth Budgets
  1. Topics
  2. SoC Design
  3. Architecture and Budgets
  4. Bandwidth Budgets
  5. Workload to Bandwidth
On this page

    Part 2 of 14, lesson 13 of 21Part 2 of 14/Architecture and Budgets/Lesson 13 of 21All levels

    Workload to Bandwidth

    Turning NanoSoC workloads into bandwidth and latency numbers the link table can answer.

    Why it matters

    A DMA job, an instruction-fetch stream and a peripheral register poke each ask the fabric for something, and until each ask is a number in MB/s with a latency limit, the link table has nothing to answer. NanoSoC's workloads are small enough to price by hand, which is why the method sticks: bytes divided by time, plus the latency the software can tolerate.

    The core idea

    Demand is bytes over time. The 64-word DMA job moves 256 bytes in 72 system clocks (750 ns): 64 beats plus 8 clocks of pipeline fill and drain, the NanoSoC specification's job model, which assumes one word per clock with no burst bubbles. That is 341.3 MB/s on average, inside the 361.4 sustained link rate, which is why the job fits. If the one bubble per 16-beat burst is counted, the four bursts need 64 + 4 = 68 read clocks plus the 8 of fill and drain: a 76-clock job (791.7 ns, 323.4 MB/s on average). The lesson uses the 72-clock model by default and says so whenever the 76-clock model changes an answer. The CPU line fill moves 16 bytes in 125 ns, 128 MB/s, with a 93.75 ns first-word latency the core stalls on. The SPI image load moves 8,196 bytes in 10,928 us, 0.75 MB/s: trivial for the fabric, binding on the SPI line. Each demand also carries a latency side: the fetch latency sets stall time, the interrupt latency (135.4 to 182.3 ns) sets response time, and the boot table's 12.581 ms total is 86.9% SPI load, which no fabric upgrade can shorten.

    The calculator

    The script prices the three demands and checks each against its binding limit.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    dma_bytes, dma_time = 64*4, 72 * (1/96e6)
    dma_bw = dma_bytes / dma_time / 1e6
    assert abs(dma_bw - 341.33) < 0.5, dma_bw
    assert dma_bw < 361.4  # sustained link rate for burst 16
    # Same job with one bubble per 16-beat burst counted: 4 bursts, 76 clocks.
    clocks_bubbles = 64 + 64 // 16 + 8
    assert clocks_bubbles == 76
    bw_bubbles = dma_bytes / (clocks_bubbles / 96e6) / 1e6
    assert abs(bw_bubbles - 323.4) < 0.2, bw_bubbles
    # Pricing only the 64 beats gives 384 MB/s: above the 361.4 supply, a false overload.
    bw_64 = dma_bytes / (64 / 96e6) / 1e6
    assert abs(bw_64 - 384.0) < 0.01 and bw_64 > 361.4
    # Averaging over the 72-clock window hides that the read channel is at peak rate.
    assert bw_64 > dma_bw
    fill_bw = 16 / 125e-9 / 1e6
    assert abs(fill_bw - 128.0) < 0.5, fill_bw
    spi_bw = 8196 / 10928e-6 / 1e6
    assert abs(spi_bw - 0.75) < 0.01, spi_bw
    boot_total = 12580.917e-6
    assert abs(8196*8/6e6 / boot_total - 0.869) < 0.002
    print(f"PASS: DMA {dma_bw:.1f}, fill {fill_bw:.0f}, SPI {spi_bw:.2f} MB/s; SPI is 86.9% of boot")

    What the review looks for

    • Every workload priced as bytes over time with its time window stated.

    • Each demand paired with its latency limit: stall, response or boot share.

    • Demands summed per link before comparing with supply, not compared one by one.

    Verify and debug

    Recheck the time window first when a demand looks wrong: the DMA's 750 ns is the job time including fill and drain (N + 8 clocks), not the 64 beat times. Two opposite errors are common. Pricing only the 64 beats (666.7 ns) gives 384 MB/s, which is above the 361.4 supply and falsely condemns a job that fits. The other error averages over the long 72-clock window and hides that the read channel runs at the full 384 MB/s peak rate during the 64 beats; a design whose supply is only just above the average has no room for that peak. Quote N + 8 for the average, and the beat-rate peak next to it.

    Pricing a job as one long burst when it is not. A 64-word SBR job is four 16-beat bursts, and a start address near a 4 KB boundary forces an extra split, because a burst may not cross one. Each extra burst adds its bubble, so the 72-clock budget quietly becomes 77 or more and the demand per window rises. Count the bursts the master really issues, including boundary splits, before quoting a time.

    If asked whether the fabric can feed the DMA, answer 341.3 against 361.4 with the N + 8 pipeline stated. The two numbers and the pipeline are the whole answer.

    Price latency beside every rate, because software feels the slower of the two. The DMA job's 341.3 MB/s looks healthy until the 8-cycle fill and drain is added for short jobs: a 4-word transfer moves 16 bytes in 12 clocks (125 ns), which is 128 MB/s, less than half the headline rate. The interrupt path's 135.4 to 182.3 ns bounds the response to every peripheral event. A demand table with rates but no latencies approves workloads that stall; add the stall, the response and the boot share to each row before comparing.

    Check yourself Why is the SPI load 86.9% of boot but 0.75 MB/s of fabric demand?

    Because boot time is dominated by the slow line, not the fabric. The fabric idles between SPI bytes; speeding the fabric cannot shorten boot, only a faster line or a smaller image can.

    Related topics

    • Next: Link Table and Sustained Rates

    • Protocol First Principles: Little's Law

    • Arch: Memory Bandwidth and Latency

    Previous

    30 / 289

    Next: Link Table and Sustained Rates

    Up next

    Up nextLink Table and Sustained Rates

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Spotting the Bottleneck