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
    • Topologies and Bridges
    • AXI Integration Details
    • Ordering and Deadlock at the Top
    • QoS and Arbitration
      • Round-Robin and Its Measured Cost
      • Starvation, Priority and Shaping
      • QoS in Practice on NanoSoC
    • NoC Basics
    • Coherent Interconnect View
    • Firewalls and Protection
    • Bandwidth and Latency Verification
  • 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

←QoS and Arbitration
  1. Topics
  2. SoC Design
  3. Interconnect and Bus Fabrics
  4. QoS and Arbitration
  5. Starvation, Priority and Shaping
On this page

    Part 4 of 14, lesson 12 of 26Part 4 of 14/Interconnect and Bus Fabrics/Lesson 12 of 26All levels

    Starvation, Priority and Shaping

    What actually bounds the CPU's wait behind a bulk master: priority, a regulator, or the length of the other master's burst.

    Why it matters

    A CPU line fill that waits behind an SBR stream is the first QoS problem NanoSoC meets, and the instinct is to reach for priority. Fixed priority, weighted shares, token buckets and aging are taught in the protocol course (see the links below); the applied question here is which of them changes the number that matters, the CPU's worst wait on a shared bank, and by how much.

    The core idea

    Bursts cannot be pre-empted, so whichever scheme is used, a CPU request that arrives just after an SBR burst has started waits for that burst to finish: 16 beats plus the bubble, 17 cycles, 177.1 ns. Priority and regulators change who goes next, not how long the current burst runs. Fixed priority to the SBR removes the bound completely (the CPU waits for ever while the SBR always has a request). Round-robin bounds the wait at one SBR burst. A token bucket on the SBR (a regulator that lets a burst start only when the bucket holds a full burst of tokens, filled at the reserved rate) restores the CPU's guaranteed service even if the SBR has fixed priority, and caps the SBR at its share. The lever that shortens the bound itself is the SBR's burst length: 4-beat SBR bursts cut the CPU's worst wait to 5 cycles, 52.1 ns, at the price of 307.2 instead of 361.4 MB/s on the SBR stream.

    Diagram
    # not-run: which lever changes what, NanoSoC teaching values
    scheme                         CPU worst wait          SBR rate
    SBR fixed priority             unbounded (starved)     361.4 MB/s
    round-robin (NanoSoC)          17 cycles = 177.1 ns    shared
    bucket on the SBR (proposed)   17 cycles = 177.1 ns    capped at its share
    round-robin, SBR 4-beat chunks  5 cycles =  52.1 ns    307.2 MB/s
    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
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    # NanoSoC teaching values: one SRAM bank shared by CPU 4-beat fills and the SBR.
    # Each burst costs beats + 1 bubble and cannot be pre-empted. The CPU asks every 50 cycles
    # (illustrative); the SBR always has more to move.
    CPU_BEATS, SBR_BEATS = 4, 16
    CPU_PERIOD = 50
    HORIZON = 5000
    
    def simulate(policy, sbr_burst=SBR_BEATS, fill=0.75):
        depth = sbr_burst
        tokens = float(depth)
        busy_until = 0
        cpu_wait_start = None
        cpu_waits = []
        sbr_beats = 0
        last = "cpu"
        for t in range(HORIZON):
            tokens = min(depth, tokens + fill)
            if t % CPU_PERIOD == 0 and cpu_wait_start is None:
                cpu_wait_start = t
            if t < busy_until:
                continue
            cpu_req = cpu_wait_start is not None
            sbr_req = True
            if policy == "bucket" and tokens < sbr_burst:
                sbr_req = False # the regulator holds the SBR back
            if cpu_req and sbr_req:
                if policy == "round_robin":
                    pick = "sbr" if last == "cpu" else "cpu"
                else:
                    pick = "sbr" # fixed priority to the SBR, with or without the bucket
            elif cpu_req:
                pick = "cpu"
            elif sbr_req:
                pick = "sbr"
            else:
                continue
            last = pick
            if pick == "cpu":
                cpu_waits.append(t - cpu_wait_start)
                cpu_wait_start = None
                busy_until = t + CPU_BEATS + 1
            else:
                if policy == "bucket":
                    tokens -= sbr_burst
                sbr_beats += sbr_burst
                busy_until = t + sbr_burst + 1
        worst = max(cpu_waits) if cpu_waits else HORIZON
        return worst, len(cpu_waits), sbr_beats
    
    worst, served, _ = simulate("sbr_priority")
    assert served == 0 and worst == HORIZON # the CPU is starved
    worst_rr, served_rr, sbr_rr = simulate("round_robin")
    assert served_rr == HORIZON // CPU_PERIOD and worst_rr <= SBR_BEATS + 1 # bound: one SBR burst
    worst_b, served_b, sbr_b = simulate("bucket")
    assert served_b == served_rr and worst_b <= SBR_BEATS + 1 # CPU served although SBR has priority
    assert sbr_b <= 0.75 * HORIZON + SBR_BEATS and sbr_b < sbr_rr # the regulator really caps the SBR
    worst_4, served_4, _ = simulate("round_robin", sbr_burst=4)
    assert worst_4 <= 4 + 1 # shorter SBR bursts shorten the bound itself
    ns = 1e9 / 96e6
    assert abs((SBR_BEATS + 1) * ns - 177.1) < 0.1 and abs((4 + 1) * ns - 52.1) < 0.1
    print("PASS: SBR priority starves the CPU, round-robin and bucket bound the wait at 17 cycles, 4-beat chunks at 5")

    What the review looks for

    • Each slave names its scheme and the worst-case wait it guarantees the lowest master, in cycles and nanoseconds, including the longest burst of the other master.

    • Any fixed-priority slave lists the rate limit that keeps the top master from pinning the bus.

    • Regulator settings are derived from the bandwidth budget, with bucket depth covering one full burst, not just the average.

    Verify and debug

    Reproduce starvation on purpose: pin the SBR at full rate and measure the CPU's worst wait against its deadline. The measured value must equal the longest SBR burst plus one: 17 cycles on NanoSoC. A longer wait means something else holds the port (a second SBR burst queued ahead, a slave stall). If you add a regulator, check it separately by setting its fill rate to zero and confirming the SBR stops after its bucket empties.

    Starvation from fixed priority: a bulk master with fixed higher priority starves a latency-critical master, with missed deadlines only when all masters are active. Caught by performance simulation with real traffic; fixed by round-robin, a regulator on the bulk master, or shorter bulk bursts. Check which lever matches the wait you need to bound.

    If asked to bound a CPU's wait behind a streaming master, say the wait is at least one of the other master's bursts whatever the priority, then name the levers in order of effect: shorten the burst, then regulate, then reorder. Quote 17 cycles against 5.

    Check yourself The SBR's priority is raised and its bursts stay 16 beats. Does the CPU's worst wait improve?

    No. A burst in progress cannot be pre-empted, so the CPU still waits up to 17 cycles; priority only matters for who starts next, and raising the SBR's priority makes it worse (starvation). Only shorter SBR bursts reduce the bound.

    Related topics

    • Round-Robin and Its Measured Cost

    • Next: QoS in Practice on NanoSoC

    • Protocol First Principles: Quality of Service

    • Protocol First Principles: Fairness and Starvation

    Previous

    76 / 289

    Next: QoS in Practice on NanoSoC

    Up next

    Up nextQoS in Practice on NanoSoC

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error