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
    • Interrupt Controller Integration
      • Levels, Polarity and Synchronisation
      • Priority, Masking and the TOP Register
      • The Wiring Table and the Controller Sketch
    • Interrupt Routing and Latency
    • DMA Integration
    • Peripheral Subsystem
    • Pad Muxing and GPIO
  • 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

←Interrupt Controller Integration
  1. Topics
  2. SoC Design
  3. Interrupts, DMA and Peripherals
  4. Interrupt Controller Integration
  5. Priority, Masking and the TOP Register
On this page

    Part 7 of 14, lesson 2 of 15Part 7 of 14/Interrupts, DMA and Peripherals/Lesson 2 of 15All levels

    Priority, Masking and the TOP Register

    Fixed priority with lower-number-wins, per-input masks, and the TOP register: the whole dispatch in three registers.

    Why it matters

    This lesson has one job: teach the three-register dispatch that every NanoSoC driver uses. Eight sources share one CPU line, so the controller must answer three questions in hardware: which inputs are currently asserting, which of those software wants to hear about, and which one comes first. The answers are RAW, ENABLE and PENDING plus the TOP register, and a driver that reads them in the right order handles any combination of simultaneous interrupts without ever touching a source block first.

    The core idea

    RAW holds the synchronised input levels, one bit per source. ENABLE is the mask software writes: a 1 lets that input through, and reset clears all eight so nothing interrupts before software is ready. PENDING is the AND of the two, combinational, with no storage of its own: clear an ENABLE bit and the pending bit vanishes in the same cycle; clear the source and it vanishes too. TOP scans the eight pending bits and reports the lowest index with a bit set, or 0x1F when none is pending. Priority is fixed and lower-number-wins: power events on input 0 always beat the DMA on input 1, which beats everything below. The ranking is deliberate, with one line of reasoning per rank: power first because it must never wait, DMA second because a stalled stream costs throughput, UART third because its holding register is only one byte deep.

    IRQ

    Source

    Cleared by

    Rank reason

    0

    Power and PLL events

    W1C on PWR_IRQ

    Must never wait.

    1

    DMA done or error

    W1C DONE or ERR, or clear IRQ_EN

    Stream stalls cost throughput.

    2

    Stream bridge done or error

    W1C in SBR STATUS

    Same stream, second half.

    3

    UART transmit or receive

    Touch the DATA register

    One byte of holding: overrun risk.

    4

    SPI receive

    Read DATA

    Same, slower.

    5

    GPIO level

    Remove the pin condition

    Slow by nature.

    6-7

    Reserved, tied to 0

    n/a

    Spares for growth.

    The dispatch loop is four steps: read TOP; if it is 0x1F there is nothing to do; service that source; clear the source's status so its level drops; repeat, because a higher-priority source may have arrived while servicing. Masking is the other half of the contract: a driver that is not ready for an input keeps its ENABLE bit at 0, and the pending bit never forms. The two spare inputs are tied to 0 at the top level, so their RAW bits can never set; any test that sees them set has found a wiring fault, not a new feature.

    Worked example: dispatch from three registers

    The script below models the controller's three registers exactly, PENDING as the AND and TOP as the lowest set index, then dispatches a UART-plus-GPIO pile-up while the DMA fires mid-service, exactly the case that rewards reading TOP again instead of assuming one round is enough.

    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
    def pending(raw, enable):
        # PENDING is exactly RAW & ENABLE; the spares are kept out by tying RAW to 0.
        return raw & enable
    
    def top(p):
        for i in range(8):
            if p & (1 << i):
                return i
        return 0x1F
    
    RAW_UART, RAW_GPIO, RAW_DMA = 0x08, 0x20, 0x02
    raw = RAW_UART | RAW_GPIO           # UART and GPIO assert together
    enable = 0xFF                       # everything unmasked
    p = pending(raw, enable)
    assert p == 0x28
    assert top(p) == 3                  # UART (3) beats GPIO (5)
    raw &= ~RAW_UART                    # service UART, its level drops
    p = pending(raw, enable)
    assert top(p) == 5
    raw |= RAW_DMA                      # DMA fires mid-service
    p = pending(raw, enable)
    assert top(p) == 1                  # DMA is dispatched before GPIO on the re-read
    raw &= ~(RAW_DMA | RAW_GPIO)
    assert top(pending(raw, enable)) == 0x1F
    assert pending(0xFF, 0x00) == 0x00  # masking removes everything
    assert pending(0x00, 0xFF) == 0x00  # RAW = 0 on the spares: nothing pends
    assert pending(0xC0, 0xFF) == 0xC0  # a set spare WOULD pend: only the tie-off keeps it out
    print("PASS: dispatch order UART, DMA, GPIO; mask and spares behave")

    What the review looks for

    • ENABLE resets to zero, and the boot code unmasks each input only after its handler is installed.

    • Every handler clears its source before returning, and reads TOP again rather than assuming the pile is empty.

    • The spare inputs have explicit tie-offs at the top level and a connectivity check that flags any use of inputs 6 or 7.

    Verify and debug

    Force each source in turn with the others masked and confirm TOP names it; then unmask all and force pairs to confirm the lower number wins. Write 0x1F-expectation tests for the idle case: TOP must read 0x1F with nothing pending, or the tied-off spares are floating. If the wrong handler runs, suspect the numbering-offset bug: wiring counted with a shared-peripheral base while software counted from zero.

    Interrupt numbering off-by-offset: the wiring uses one numbering base while the device tree or the vector table uses another, so the handler for the wrong device runs. Fixed by generating the RTL wiring and the software table from one IRQ list; caught by one automated test per IRQ that forces the source and checks which handler ran.

    If asked how eight sources share one line, say RAW, ENABLE, PENDING-as-AND and TOP-as-lowest-index, then walk the re-read loop. The fixed-priority trade-off to volunteer: no configuration, no starvation analysis, but a chatty low-priority source waits behind every power event.

    Check yourself GPIO and SPI assert together with all inputs enabled. Which is serviced first, and what must the handler do before returning?

    SPI on input 4 beats GPIO on input 5. The handler must clear the source, reading SPI DATA so the level drops, then read TOP again in case a higher-priority source arrived meanwhile.

    Related topics

    • Levels, Polarity and Synchronisation

    • Next: The Wiring Table and the Controller Sketch

    • RTL: Interrupt Register Pattern

    Previous

    134 / 289

    Next: The Wiring Table and the Controller Sketch

    Up next

    Up nextThe Wiring Table and the Controller Sketch

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error