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
    • Topologies and Bridges
    • AXI Integration Details
    • Ordering and Deadlock at the Top
      • What Ordering the Integrator Owes
      • How Deadlock Happens at SoC Level
      • Proving Freedom and Debugging Hangs
    • QoS and Arbitration
    • NoC Basics
    • Coherent Interconnect View
    • Firewalls and Protection
    • Bandwidth and Latency Verification
  • 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

←Ordering and Deadlock at the Top
  1. Topics
  2. SoC Design
  3. Interconnect and Bus Fabrics
  4. Ordering and Deadlock at the Top
  5. What Ordering the Integrator Owes
On this page

    Part 4 of 14, lesson 8 of 26Part 4 of 14/Interconnect and Bus Fabrics/Lesson 8 of 26All levels

    What Ordering the Integrator Owes

    The guarantees software may rely on: device ordering, which event proves the data is written, and where serialisation happens.

    Why it matters

    The DMA finishes a job and raises irq_dma, the CPU takes the interrupt and checksums the destination buffer in SRAM1. Which event is allowed to start that checksum? On NanoSoC the DMA has no AXI port. The SBR reads the source into the DMA's input stream and writes the DMA's output stream to SRAM1 as master M1, straight through nano_xbar: no axi2apb bridge is on that path. irq_dma rises in the same cycle in which the DMA's last output beat first appears, before the SBR write engine has issued its last write and long before the last write response (BRESP) has come back. The SBR's own DONE bit is set only after the last BRESP, and irq_sbr follows it. The data-complete event is therefore the SBR's DONE, not the DMA's.

    The core idea

    Peripheral registers are device memory: non-cacheable, non-bufferable, strongly ordered, so accesses arrive in program order, and the axi2apb bridge returns B only after the APB access completes. Memory is normal memory: its writes may be buffered and merged, and AXI itself gives no ordering between a read and a write unless the master waits for the write response before issuing the read. The integrator owes software a rule that names the event after which data is visible: for a buffer written by the SBR, that is SBR STATUS.DONE (or irq_sbr), because DONE is set after the last BRESP. A later APB read of DMA STATUS goes through a different path (CPU, axi_cdc, xbar, axi2apb) and orders nothing against M1's writes.

    Pair

    Ordered?

    Why

    CPU write to a DMA register, then CPU read of the same register

    Yes

    Device memory, one bridge, one access at a time; B returns after the APB access completes.

    CPU write to UART DATA, then read of UART STATUS

    Yes

    Same bridge and the same rule, through the apb_cdc handshake.

    CPU write to SRAM, then CPU read of the same address

    Only if the CPU waits for B

    AXI has no ordering between the write and read channels; the blocking NanoSoC CPU waits, a buffering master would not.

    SBR final write to SRAM1, then irq_dma at the CPU

    Not guaranteed

    irq_dma is raised before the last BRESP; it wins or loses the race by timing.

    SBR final write to SRAM1, then SBR DONE and irq_sbr

    Yes

    DONE is set only after the last BRESP, so the data is in SRAM1 before the event exists.

    The race can be modelled. After irq_dma rises, the last write response arrives at most 8 clk_sys cycles later (83.3 ns, the whole fill and drain allowance of the job formula), while the interrupt takes at least 135.4 ns to reach the CPU. Today the data wins comfortably, so a handler that waits on irq_dma passes every test. That is a timing margin of 5 clk_sys cycles, not a guarantee: a deeper write buffer, a register slice pair on the write path or a slower destination that adds 5 or more clocks removes it, and the handler then reads stale data intermittently. A handler that waits on irq_sbr is correct for any write-path delay.

    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
    # NanoSoC teaching values: which event proves the SBR's writes are in SRAM1?
    T_SYS = 1e9 / 96e6 # ns
    T_PER = 1e9 / 24e6
    T_CPU = 1e9 / 192e6
    IRQ_BEST = 2 * T_PER + 1 * T_PER + 2 * T_CPU # 135.4 ns from the interrupt source to the CPU
    JOB_TAIL = 8 * T_SYS # upper bound on irq_dma to the last BRESP: the job's fill and drain allowance
    
    def times(event, extra_write_clks):
        # (time the CPU can see the event, time the last write is complete), ns after irq_dma rises
        t_data = JOB_TAIL + extra_write_clks * T_SYS
        if event == "irq_dma":
            return IRQ_BEST, t_data # raised without waiting for the last BRESP
        if event == "irq_sbr":
            return t_data + IRQ_BEST, t_data # SBR DONE is set after the last BRESP
        raise ValueError(event)
    
    def data_ready(event, extra):
        t_cpu, t_data = times(event, extra)
        return t_data < t_cpu
    
    assert abs(IRQ_BEST - 135.4) < 0.05
    for extra in (0, 2, 4):
        assert data_ready("irq_dma", extra) # today: the data happens to win
    assert not data_ready("irq_dma", 6) # a longer write path loses the race
    assert not data_ready("irq_dma", 20)
    for extra in range(0, 40):
        assert data_ready("irq_sbr", extra) # correct whatever the write path costs
    print("PASS: irq_dma wins only by timing (4 spare clocks), irq_sbr is correct for any write delay")

    What the review looks for

    • The integration spec names the point of serialisation for every master-to-slave path, not just the protocol default: for NanoSoC, the slave for memory and the single-access bridge for registers.

    • Every interrupt that announces data states which event proves the data is written: the SBR's DONE for buffers the SBR writes, never an upstream block's interrupt.

    • Device versus normal attributes in the map match the ordering assumptions of every driver.

    Verify and debug

    Write the write-then-interrupt test for the SBR path: run a job, wait for irq_sbr, then check the buffer with no extra delay. Then prove the test can fail: add a write-path delay of 6 clk_sys cycles to the SRAM1 write channel and check that a handler waiting on irq_dma now sees stale words while one waiting on irq_sbr still passes. If a hand-written handler fails intermittently, it is waiting on the wrong event. Randomise write-path timing while interrupts fire; an ordering bug scales with timing pressure, which is why directed tests with the default timing miss it.

    Interrupt arrives before the data it announces: the handler waits on irq_dma, which rises when the last word leaves the DMA, while the SBR is still writing it. The margin is a few clocks, so it passes today and fails after any change that lengthens the write path. Wait on irq_sbr or SBR STATUS.DONE (set after the last write response), then read the buffer.

    If asked where ordering is guaranteed, answer with the point of serialisation: the single place in each path where transactions become ordered, usually the slave or the target-side bridge. Then give the NanoSoC rule as the example: the data-complete event is the one that is set after the last write response, here the SBR's DONE, not the interrupt of an upstream block.

    Check yourself The handler enables irq_dma, takes the interrupt and reads the SRAM1 buffer. It works in every test. Why is it still wrong?

    irq_dma rises when the last word leaves the DMA, before the SBR has the last write response. The data wins only because the write path is shorter than the 135.4 ns interrupt path. DMA DONE says the last word left the DMA; SBR DONE says the last write response arrived.

    Related topics

    • Protocol First Principles: Ordering Across Bridges

    • Protocol First Principles: The Point of Serialisation

    • Protocol First Principles: Early and Final Acknowledgement

    • Next: How Deadlock Happens at SoC Level

    Previous

    72 / 289

    Next: How Deadlock Happens at SoC Level

    Up next

    Up nextHow Deadlock Happens at SoC Level

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Proving Freedom and Debugging Hangs