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
      • What the Integrator Owns
      • Anatomy of a Handoff
      • NanoSoC Cast and First Triage
    • Spec to Tapeout Flow
    • Contracts and Ownership
    • Reading the SoC Spec
  • 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

←The Integrator Role and Handoffs
  1. Topics
  2. SoC Design
  3. What SoC Integration Is
  4. The Integrator Role and Handoffs
  5. Anatomy of a Handoff
On this page

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

    Anatomy of a Handoff

    The eight items every block handoff must contain, the acceptance gate, and the wiring slip that proves why.

    Why it matters

    The DMA works perfectly in its own testbench and fails on NanoSoC in a way that takes a week to localise: reads of STATUS, LEN and KEY return an error, a read of COUNT quietly returns STATUS with no error at all, and only CTRL at offset 0x00 reads correctly. The cause is one wire in the wrapper. The DMA decodes byte offsets on an 8-bit paddr port, but the integrator connected word addresses, apb_paddr bits 9 down to 2, as is customary for other APB blocks. Offset 4 arrives as 1, which is unmapped, and offset 0x10 arrives as 0x04, which is STATUS, so only CTRL is right. The RTL was right, the bus was right, and the handoff was wrong: it never said, in a checkable form, which address bits the block consumes. The checklist below makes that sentence checkable for every block.

    The core idea

    A handoff is a versioned bundle of eight items, and the integrator accepts or rejects the bundle, never individual files. The RTL with its parameters fixed. The register map with offsets, access types and reset values. The clock, reset and power intent: which domains, which resets, which power domain, which enables. The constraint file for synthesis and timing. The CDC and RDC collateral: which crossings the block contains and which it assumes the parent provides. The software header or field list generated from the same map. The verification report: what was proven and what was waived. And the known-limitations note: the errata the block already carries. A bundle missing any one of these is not a handoff; it is a promise that someone else will fill the gap later, which is how word-address wiring meets byte-offset decode.

    Handoff item

    NanoSoC example

    What breaks without it

    RTL, parameters fixed

    DMA wrapped with WAIT_STATES 1

    Three-clock versus two-clock APB timing assumed wrong

    Register map with reset values

    CTRL reads bit 0 as 0, LEN resets to 0

    Driver writes 0x1 and silently disables the interrupt

    Clock, reset, power intent

    DMA on clk_sys, rst_sys_n, PD_SW

    Gated clock hangs the bus; missing isolation wakes the chip

    Constraints

    APB input delays at the slot

    Signoff passes, silicon fails at speed

    Crossing inventory

    irq_dma needs a 2-flop sync into clk_per

    Missed interrupt once in a few thousand jobs

    Generated software view

    Header from the same map table

    Header from an old map hits the wrong block

    Verification report

    Early-s_tlast sets ERR, proven in bench

    System test mistakes specified behaviour for a bug

    Known limitations

    LEN and KEY ignored while BUSY, no error

    Second job silently uses the stale KEY

    Acceptance is a gate with three positions, not a handshake. Complete means every item present, versioned and stamped with the same bundle revision: wire it in. Incomplete means items missing: reject it back to the owner with the missing list, and do not wire around the gap. Waived means an item is knowingly deferred with a named owner and a date: wire it in, but the waiver ages on the integration board and turns red if the date passes. The third position exists because real projects ship handoffs with gaps; the discipline is that a gap without a name and a date is a rejection, not a waiver.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // snippet: the DMA wrapper contract that the handoff must state.
    // The DMA decodes BYTE offsets on an 8-bit port, so the wrapper passes
    // apb_paddr[7:0] straight through and drops apb_paddr[11:8] (the alias).
    // Connecting apb_paddr[9:2] (word addresses) is the classic wiring slip:
    // STATUS, LEN and KEY then answer PSLVERR and COUNT reads STATUS with no error.
    // dma_paddr  <-- apb_paddr[7:0]   (byte offsets 0x00..0x10 mapped)
    // unused     <-- apb_paddr[11:8]  (nothing downstream may depend on these)

    The acceptance checker

    The script below is the gate in executable form: it lists the eight required items, passes a complete NanoSoC DMA bundle, rejects a bundle missing constraints and the crossing inventory, and accepts a waived bundle only when every waiver names an owner and a date. Keep this list beside the integration database and run it on every delivery; it takes milliseconds and it never gets tired of saying no.

    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
    REQUIRED = ["rtl", "regmap", "clock_reset_power", "constraints",
                "crossings", "software_view", "verification_report", "limitations"]
    
    def accept(bundle, waivers):
        provided = set(bundle)
        missing = [item for item in REQUIRED if item not in provided]
        excused = []
        for item in missing:
            w = waivers.get(item)
            if w and w.get("owner") and w.get("date"):
                excused.append(item)
        rejected = [item for item in missing if item not in excused]
        status = "accept" if not missing else ("waived" if not rejected else "reject")
        return status, rejected, excused
    
    good = {item: "rev C" for item in REQUIRED}
    assert accept(good, {})[0] == "accept"
    
    thin = {item: "rev C" for item in REQUIRED
            if item not in ("constraints", "crossings")}
    status, rejected, _ = accept(thin, {})
    assert status == "reject"
    assert rejected == ["constraints", "crossings"]
    
    status, rejected, excused = accept(
        thin, {"constraints": {"owner": "pd", "date": "M3"},
               "crossings": {"owner": "cdc", "date": "M3"}})
    assert (status, rejected, excused) == ("waived", [], ["constraints", "crossings"])
    
    status, rejected, _ = accept(thin, {"constraints": {"owner": "pd"}})
    assert status == "reject" and rejected == ["constraints", "crossings"]
    print("PASS: complete accepted, thin rejected, dated waivers excused")

    What the review looks for

    • Every block in the chip directory carries the same bundle revision across all eight items.

    • Every waiver names an owner and a milestone date, and no date is past.

    • The wrapper states, in a comment the checker can grep, which address bits each port consumes.

    Verify and debug

    When a block misbehaves only at the top level, read the bundle before the RTL: diff the register map against the driver's header field by field, confirm the parameter values against the verification report, and check the wrapper's address-bit comment against the block's port widths. The DMA word-address slip is found at once by that reading, because the handoff either states byte offsets, in which case the wrapper is wrong, or states nothing, in which case the handoff was never complete.

    Address truncation in a bridge or adapter: the DMA's 8-bit paddr against the bus's 12 bits is the mild form; narrowing a wider address or tying off upper bits aliases high memory onto low memory. The lint rule treats any port-width mismatch as an error, and the directed test touches a high address that must reach the default slave.

    If asked what you demand with third-party IP, recite the eight items, then say which two you check first: the address-bit convention and the clock, reset and power intent, because those two cause most first-silicon surprises.

    Check yourself A vendor delivers encrypted RTL with no crossing inventory. Accept, reject, or waive?

    Waive only with a named owner and a milestone date, and only if the wrapper can be constrained without it; otherwise reject. Encrypted RTL makes the inventory more important, not less, because you cannot reverse-engineer the crossings.

    Related topics

    • What the Integrator Owns

    • Next: NanoSoC Cast and First Triage

    • Contracts and Ownership

    Previous

    7 / 289

    Next: NanoSoC Cast and First Triage

    Up next

    Up nextNanoSoC Cast and First Triage

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error