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
    • ECO and Respin Risk
    • Errata and Post-Silicon
      • From Bug to Erratum
      • Workarounds That Hold
      • The Loop to the Next Chip
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←Errata and Post-Silicon
  1. Topics
  2. SoC Design
  3. Chip Signoff and Tapeout
  4. Errata and Post-Silicon
  5. Workarounds That Hold
On this page

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

    Workarounds That Hold

    Driver rules that contain hardware bugs: the model that proves them, and the set-wins register behind one fix.

    Why it matters

    A workaround that works by accident fails at temperature, at a different clock ratio, or under the next compiler. The driver rules must be proven against a model of the actual hardware behaviour, including the races, or they are just another bug with a comment. This lesson proves the NanoSoC workaround rules against a cycle-level model of the real DMA status behaviour, then shows the hardware register pattern, set-wins write-1-to-clear, that removes one race class by construction. Its one job is trustworthy workarounds; turning them into next-chip rules is the last lesson.

    The core idea

    The DMA status behaviour has three sharp edges: length and key writes are silently ignored while busy, a control write copies bit 1 into the interrupt enable every time so writing 0x1 to start silently disables the interrupt, and starting a job clears DONE but never ERR. The driver rules follow each edge: wait for busy clear before touching length or key, always start with 0x3 so the enable survives, and always clear both DONE and ERR with 0x6 after every job. The model below executes the real behaviour, including a stuck ERR from a failed job and a key write attempted while busy, and runs all eight combinations of the three rules: exactly the full rule set gives a clean result. Then the register pattern: a write-1-to-clear status bit with set-wins arbitration, so a status event arriving in the same cycle as the clear is not lost, which is the clear-versus-set race fixed in RTL for the next chip.

    nano_w1c_status.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // Set-wins write-1-to-clear status bit. A hardware event in the same
    // cycle as a software clear sets the bit: the event is never lost.
    // Fix for the clear-versus-set race in new NanoSoC blocks.
    module nano_w1c_status (
      input  logic clk,
      input  logic rst_n,
      input  logic hw_set,     // event from the block, level or pulse
      input  logic sw_clear,    // software writes 1 to clear this bit
      output logic status       // sticky status until cleared
    );
      always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n)
          status <= 1'b0;
        else if (hw_set)
          status <= 1'b1;      // set wins over a simultaneous clear
        else if (sw_clear)
          status <= 1'b0;
      end
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    # Model the real DMA status behaviour and prove the driver rules.
    # Behaviour from the DMA register specification: GO clears DONE not ERR,
    # a CTRL write copies bit 1 into IRQ_EN every time, LEN and KEY writes
    # are ignored while BUSY. Eight rule combinations are run.
    from itertools import product
    
    def run(wait_busy, start3, clear_both):
        s = {"busy": False, "done": False, "err": False, "irq_en": False,
             "len": 0, "key": 0}
    
        def write_ctrl(v):
            s["irq_en"] = bool(v & 2)               # copied on every write
            if (v & 1) and not s["busy"]:
                s["busy"] = True
                s["done"] = False                   # ERR deliberately kept
    
        def write_key(v):
            if not s["busy"]:
                s["key"] = v
    
        def write_len(v):
            if not s["busy"]:
                s["len"] = v
    
        def finish(ok):
            s["busy"] = False
            s["done" if ok else "err"] = True
    
        def clear(v):
            if v & 2:
                s["done"] = False
            if v & 4:
                s["err"] = False
    
        def irq():
            return s["irq_en"] and (s["done"] or s["err"])
    
        start = 0x3 if start3 else 0x1
        clr = 0x6 if clear_both else 0x2
        write_len(4)
        write_key(0x11)
        write_ctrl(start)                           # job 1 starts
        assert not s["done"]                        # a second GO while busy is ignored
        write_ctrl(start)
        assert s["busy"]
        if wait_busy:
            finish(False)                           # job 1 fails: ERR
            write_key(0x22)                         # key written once idle
        else:
            write_key(0x22)                         # ignored: still busy
            finish(False)
        clear(clr)
        write_ctrl(start)                           # job 2 uses the new key
        finish(True)
        seen = irq()                                # was the interrupt delivered?
        clear(clr)
        return {"irq_seen": seen, "irq_after_clear": irq(),
                "key_ok": s["key"] == 0x22}
    
    def good(r):
        return r["irq_seen"] and not r["irq_after_clear"] and r["key_ok"]
    
    passing = [c for c in product([True, False], repeat=3) if good(run(*c))]
    assert passing == [(True, True, True)], passing
    assert run(True, False, True)["irq_seen"] is False      # 0x1: enable lost
    assert run(True, True, False)["irq_after_clear"] is True  # DONE alone: stuck
    assert run(False, True, True)["key_ok"] is False        # key write while busy
    print("PASS: of 8 rule combinations only the full rule set gives a clean job")

    What the review looks for

    • Every erratum workaround names the hardware behaviour it relies on, with the register-specification reference, not just the code.

    • The model or bench proof covers the race sequences: error then success, clear against event, start while busy.

    • New blocks use set-wins status registers, so the workaround class shrinks with each chip.

    Verify and debug

    The script already runs the model with the rules deliberately broken, one rule at a time: starting with 0x1 loses the interrupt, clearing DONE alone sticks it, writing key or length while busy is ignored. Each broken run must fail; a model that passes with broken rules proves nothing. On silicon, the same sequences run as driver tests with the interrupt line observed, bounded by the 135.4 to 182.3 ns latency so a stuck line is distinguished from a slow one.

    The clear-versus-set race: software clears a status bit in the same cycle hardware sets it, and the new event is lost. The set-wins module above is the RTL fix; until every block has it, the workaround is read-back after clear, and the erratum says so explicitly.

    If asked to prove a workaround, describe the model first and the code second: behaviour enumerated, rules derived, sequences proven, then the driver function. Code without the model is a claim; the model is the evidence.

    Check yourself The workaround clears both flags but the interrupt still sticks. What next?

    Read the DMA STATUS. If DONE or ERR is still set, the clear did not land: check for a clear written to the wrong offset (an unmapped offset answers PSLVERR) or a clear issued before BUSY dropped. If STATUS is clear, read the interrupt controller PENDING and RAW bits for the other sources (irq_sbr on input 2, irq_uart on 3, irq_spi on 4, irq_gpio on 5): the stuck line is a different source.

    Related topics

    • From Bug to Erratum

    • Next: The Loop to the Next Chip

    • Verification: Errata and Workarounds

    Previous

    248 / 289

    Next: The Loop to the Next Chip

    Up next

    Up nextThe Loop to the Next Chip

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error