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
  • 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
    • The Signoff Manifest
    • Waiver Governance
    • Closure Dashboards
    • Tapeout Readiness Review
      • Evidence per Owner
      • Go and No-Go
      • Last-Week Surprises
    • ECO and Respin Risk
    • Errata and Post-Silicon
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←Tapeout Readiness Review
  1. Topics
  2. SoC Design
  3. Chip Signoff and Tapeout
  4. Tapeout Readiness Review
  5. Last-Week Surprises
On this page

    Part 12 of 14, lesson 12 of 18Part 12 of 14/Chip Signoff and Tapeout/Lesson 12 of 18All levels

    Last-Week Surprises

    The failures that strike in the final week: gated-clock hangs, reset-order slips, and the guards that catch them.

    Why it matters

    The last week has its own failure distribution: not deep bugs, which the flow caught months ago, but configuration slips, a clock disabled to save power, a reset released in the wrong order after a hasty ECO. Each hangs the chip instead of erroring, because the final-week chip is misconfigured rather than misdesigned. This lesson names the three classic surprises, shows the watchdog guard in RTL, and states the pre-review sweep that catches the rest. Its one job is surviving the week; pricing the fixes belongs to the ECO topic.

    The core idea

    First surprise: the gated-clock hang. Software clears the DMA clock enable to save power, then touches a DMA register; with the clock stopped the block cannot drive PREADY and the bridge waits forever, hanging the CPU with no error and no timeout. The guard has two parts. A 256-cycle watchdog in the AXI-to-APB bridge ends the AXI side of the access with SLVERR (PSLVERR on the APB side) after 256 cycles, so the CPU gets an error instead of a hang. Because the slave clock is known to be stopped, the bridge then forces the APB side to idle; an APB master may not abandon a transfer while the slave is live, so the slave's state is undefined until its clock restarts, and after a timeout software must reset the DMA before reusing it. The preferred guard is the second one: hardware that refuses to gate a clock while the block is busy or while an access to it is outstanding. Second surprise: the reset-order slip, where the CPU leaves reset with the fabric and its first fetch enters a bridge still in reset and is lost. The guard is the release-order assertion that the CPU reset must rise strictly after the system reset. Third: the missing-interrupt miswire, where the DMA interrupt lands on spare input 6 while software waits on input 1. The guard is the connectivity test that forces each source and checks its matching status bit. The sweep before the review runs all three guards plus the map checker; it takes minutes and has veto power over the agenda.

    nano_apb_watchdog.sv
    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
    // NanoSoC teaching values: bridge watchdog. After 256 clk_sys cycles
    // of one outstanding access with no pready, timeout_err rises and STAYS
    // high until access_active falls, so the bridge cannot re-arm or lose
    // the event. The bridge uses it to end the AXI side with SLVERR.
    module nano_apb_watchdog (
      input  logic clk,
      input  logic rst_n,
      input  logic access_active,   // access issued, awaiting pready
      input  logic pready,          // slave ready, ends the access
      output logic timeout_err      // level, held until access_active falls
    );
      logic [7:0] count;
      logic fired;
    
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
          count <= 8'd0;
          fired <= 1'b0;
        end else if (!access_active) begin
          count <= 8'd0;            // idle: re-arm only when the access ends
          fired <= 1'b0;
        end else if (pready) begin
          count <= 8'd0;
        end else if (!fired) begin
          if (count == 8'd255)
            fired <= 1'b1;
          else
            count <= count + 8'd1;
        end
      end
    
      assign timeout_err = fired;
    endmodule
    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
    # The last-week sweep: map, reset order, interrupt wiring, watchdog
    # limit. Every check is computed from a table and has a bad input that
    # it must reject.
    def overlaps(windows):
        spans = sorted(windows.values())
        return [(a, b) for a, b in zip(spans, spans[1:]) if b[0] <= a[1]]
    
    MAP = {"DMA": (0x4000_0000, 0x4000_0FFF), "SBR": (0x4000_1000, 0x4000_1FFF),
           "UART": (0x4000_2000, 0x4000_2FFF)}
    assert overlaps(MAP) == []
    bad_map = dict(MAP, DMA=(0x4000_0000, 0x4000_1FFF))   # an 8 KB DMA window
    assert overlaps(bad_map) != []
    
    def cpu_last(release_ns):
        t = release_ns
        return t["rst_cpu_n"] > t["rst_sys_n"] > t["rst_per_n"]
    
    good = {"rst_per_n": 42750.0, "rst_sys_n": 53854.0, "rst_cpu_n": 53948.0}
    assert cpu_last(good)
    assert not cpu_last(dict(good, rst_cpu_n=53854.0))     # same step: the slip
    
    WIRING = {0: "irq_pwr", 1: "irq_dma", 2: "irq_sbr", 3: "irq_uart",
              4: "irq_spi", 5: "irq_gpio", 6: None, 7: None}
    
    def wiring_errors(netlist):
        return [(i, netlist.get(i), src) for i, src in WIRING.items()
                if netlist.get(i) != src]
    
    assert wiring_errors(dict(WIRING)) == []
    miswired = {**WIRING, 1: None, 6: "irq_dma"}
    assert wiring_errors(miswired) == [(1, None, "irq_dma"), (6, "irq_dma", None)]
    
    def limit_ok(limit, slowest_legal_cycles):
        return limit >= 4 * slowest_legal_cycles           # margin rule
    
    SLOWEST = 20          # 208.33 ns of peripheral access is about 20 clk_sys
    assert limit_ok(256, SLOWEST)
    assert not limit_ok(64, SLOWEST)
    print("PASS: map, reset order, IRQ wiring, watchdog limit all checked and rejectable")

    What the review looks for

    • The sweep output attached to the review pack, green, dated within the final week.

    • The watchdog present in the bridge with its 256-cycle limit documented as a hang guard, not a performance feature, and the busy-guard on clock gating beside it.

    • No clock-gating change in the final week without the busy-guard proof beside it.

    Verify and debug

    A hung CPU cannot read anything, so the usual first move, reading the clock-enable register, is not available: the CPU is blocked on the bridge, and RSTPWR is a secure-only block anyway. NanoSoC has no debug access path, which is exactly why the watchdog matters. Use what survives outside the CPU. A second bus master or a debug access path, where the chip has one, can read the registers. On NanoSoC, look at the externally visible pins: is the UART banner printed, is RESET_N toggled. Then reset and replay with a trace of register writes before the hang, and read CLK_EN and RST_CAUSE after the reset. Compare the last write before the hang with the surprise list: a write that cleared a clock enable points at the gated-clock hang, a software reset cause mid-transaction points at the partial-reset hang, and the interrupt raw bits against the wiring table cover the miswire. The hang triage in the hardware-debug course generalises this order in The Chip Hangs: What Do You Do?.

    A partial-reset hang: one side reset mid-transaction while the other waits for a response that never comes. Late resets to fix a last-week issue cause this exact hang; the drain and quiesce handshake must precede any reset, even in the final week, especially in the final week.

    If asked what you check the night before tapeout, answer the sweep: map, reset order, interrupt wiring, watchdog. Four guards, minutes to run, each tied to a failure that strikes in real final weeks.

    Check yourself The watchdog fires during normal operation on a slow peripheral. Guard misbehaving?

    The limit is wrong for the clock ratio, or the peripheral legitimately needs more than 256 fast cycles: the peripheral-side access costs 208.33 ns, about 20 system clocks, so 256 is generous on NanoSoC. On a slower fabric, size the limit from the slowest legal access plus margin, and document the arithmetic.

    Related topics

    • Go and No-Go

    • Next: ECO and Respin Risk

    • Hardware Debug: The Chip Hangs, What Do You Do?

    Previous

    243 / 289

    Next: ECO and Respin Risk

    Up next

    Up nextECO and Respin Risk

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Evidence per Owner