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
      • Cycle Budgets for Crossing Paths
      • I/O Delay Budgeting
      • Margin Allocation and Handoff
    • Power Budgets
    • Bandwidth Budgets
    • 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

←Timing Budgets Across Hierarchy
  1. Topics
  2. SoC Design
  3. Architecture and Budgets
  4. Timing Budgets Across Hierarchy
  5. I/O Delay Budgeting
On this page

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

    I/O Delay Budgeting

    Budgeting chip I/O timing against the board: what the integrator owes the pins.

    Why it matters

    Inside the chip the integrator controls both ends of every path; at the pins the other end belongs to the board — the SPI flash that answers the second-stage load, the UART receiver sampling the boot banner, the GPIO sampling a wake button. I/O delay budgeting splits the interface period between chip and board so each side has a number it can close independently.

    The core idea

    Take the interface window and subtract what is not yours. The SPI clock on NanoSoC is generated from the 24 MHz peripheral clock as clk_per / (2 x (CLKDIV + 1)), which is 6 MHz at the reset value, a 166.667 ns period. The SPI is mode 0: each side launches data on the falling SCK edge and the other side samples on the next rising edge, so the window for a transfer in either direction is half a period, 83.333 ns, not a whole bit time. Board flight time, the flash's clock-to-output and setup, and the pad delay of SCK itself are board, device and pad properties; what remains is the chip's budget. The same split applies to the UART at 115,384.6 baud, where each bit lasts 8.667 us and the chip's share is generous, and in reverse to outputs, where the chip's clock-to-pad budget must leave the receiver's setup intact. The integrator's artifact is one row per pin group: period, board share, chip share, and the constraint that carries the chip share.

    Diagram
    # not-run: NanoSoC I/O budget sketches, NanoSoC teaching values
    SPI at 6 MHz, mode 0: period 166.667 ns, capture window = half = 83.333 ns.
      Illustrative values: flash setup 10 ns, flash clock-to-output 20 ns,
      board flight 2 ns each way, SCK pad skew to MOSI 5 ns, SCK output pad 6 ns.
      MOSI and CS out (chip to flash): chip clock-to-pad budget
        = 83.333 - (10 + 2 + 5) = 66.333 ns.
      MISO in (flash to chip), if captured synchronously by the SCK domain:
        chip pad plus route budget = 83.333 - (6 + 2 + 20 + 2 + 10) = 43.333 ns,
        because SCK leaves the pad late and the data must come back before
        the next rising edge (the SCK round trip is part of the budget).
      NanoSoC instead takes MISO through the X9 two-flop synchroniser: it is an
      asynchronous input, so no input-delay constraint applies and the cost is
      two clk_per of latency (83.333 ns), not a delay budget.
    UART at 115,384.6 baud: bit period 8,666.667 ns; mid-bit sampling leaves
      thousands of ns for the chip share: never the binding constraint.
    GPIO wake input: synchroniser costs 2 peripheral clocks (83.333 ns); the
      button is level-held, so latency is an envelope, not a frequency limit.

    The script turns the sketch into checks that can fail: it recomputes the half-period windows and the two chip budgets, and shows that the old whole-period reading would have hidden a violation.

    example.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    period = 1 / 6e6 * 1e9  # ns, SPI clock = 24 MHz / (2 x (1 + 1))
    assert abs(period - 166.667) < 0.001
    window = period / 2  # mode 0: launch on falling edge, sample on rising edge
    assert abs(window - 83.333) < 0.001
    # Illustrative device and board values (teaching values, not a datasheet).
    flash_setup, flash_tco, flight, pad_skew, sck_pad = 10.0, 20.0, 2.0, 5.0, 6.0
    mosi_budget = window - (flash_setup + flight + pad_skew)
    miso_budget = window - (sck_pad + flight + flash_tco + flight + flash_setup)
    assert abs(mosi_budget - 66.333) < 0.001, mosi_budget
    assert abs(miso_budget - 43.333) < 0.001, miso_budget
    # A whole-period reading would give a larger, wrong number.
    wrong_miso = period - (flash_tco + flight + flash_setup)
    assert wrong_miso > miso_budget
    # The check can fail: a 50 ns pad plus route delay on MISO violates the real budget
    # but would have passed against the wrong whole-period budget.
    chip_delay = 50.0
    assert chip_delay > miso_budget and chip_delay < wrong_miso
    # NanoSoC routes MISO through the X9 two-flop synchroniser: latency, not a delay budget.
    sync_latency = 2 * (1 / 24e6) * 1e9
    assert abs(sync_latency - 83.333) < 0.001
    print(f"PASS: window {window:.3f} ns, MOSI budget {mosi_budget:.3f} ns, MISO budget {miso_budget:.3f} ns, sync latency {sync_latency:.1f} ns")

    What the review looks for

    • One budgeted row per external interface with period, board share and chip share.

    • The chip share lands in the constraint set as an input or output delay, owned by the top level.

    • Slow interfaces carry short justifications, not full tables; effort follows binding constraints.

    Verify and debug

    Audit the constraint set against the budget rows: every external pin group needs its delay constraint, and every delay constraint needs a budget row that justifies it. The classic failure is a pin timed by default — no constraint, passes signoff, fails on the board — caught by listing unconstrained endpoints. On NanoSoC the SPI output pins (SCK, MOSI, CS) are the ones to check first; the MISO, UART RX and GPIO inputs go through synchronisers and carry no delay budget, but still need their asynchronous treatment declared so a later change cannot silently unconstrain them.

    An I/O delay written against the wrong clock. The SPI output delay is copied from the budget row but referenced to clk_per instead of the generated SCK, so the constraint checks a window of a different phase and the report is green while the flash sees MOSI changing next to the sampling edge. Name the reference clock on every budget row, and review any exception on an I/O path with evidence: it is the same family as the wrong false path or multicycle that passes signoff and fails at speed.

    If asked to budget an interface, start from the period, subtract board and device shares out loud, and hand the remainder to the chip. Say which share you are least sure of; that honesty is the senior signal.

    Do not forget the inputs that never toggle during normal operation: the GPIO wake button and the reset pin are level-held, so their budget is a synchroniser latency plus a pull-and-drive check, not a frequency race. The failure to budget for is a floating input sampled at release, caught by a pin-state table for reset rather than by timing analysis. NanoSoC has no boot-mode strap (boot is fixed: ROM first, then the SPI load), so its example is the RESET_N pin, which must be low for more than 16 clk_per cycles (666.7 ns) before it counts. Every pin group gets a row even when the row says not binding; the row is what stops a later change from silently unconstraining it.

    Check yourself Why does the UART get a paragraph while the SPI gets a table?

    Because budget effort follows binding constraints. The UART bit period is 8.667 us against nanosecond chip delays — no analysis needed beyond writing the constraint. The SPI at 6 MHz has a real split to compute.

    Related topics

    • Cycle Budgets for Crossing Paths

    • Next: Margin Allocation and Handoff

    • STA: Interface Budgets

    Previous

    25 / 289

    Next: Margin Allocation and Handoff

    Up next

    Up nextMargin Allocation and Handoff

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error