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
      • IDs, Outstanding Counts and No WID
      • The 4 KB Rule and Burst Splitting
      • Width, Clock and Endianness Conversion
    • Ordering and Deadlock at the Top
    • 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

←AXI Integration Details
  1. Topics
  2. SoC Design
  3. Interconnect and Bus Fabrics
  4. AXI Integration Details
  5. The 4 KB Rule and Burst Splitting
On this page

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

    The 4 KB Rule and Burst Splitting

    Why no burst may cross a 4 KB boundary, how the SBR splits one that would, and what the split looks like on the wire.

    Why it matters

    The SBR streams a 64-word job whose source buffer starts at 0x2000_0FF0, 16 bytes below a 4 KB page boundary. If it issues one 16-beat read from that address, the burst would run 48 bytes past 0x2000_0FFF. Nothing on NanoSoC decodes differently at 0x2000_1000 (SRAM0 is 64 KB), so this particular burst would probably work. AXI forbids it anyway, because 4 KB is the smallest region a slave may own: a master may not assume that the next page belongs to the same slave. A fabric, a width converter or a later memory with 4 KB banks may split or misroute it, and the failure is intermittent, because it appears only when a buffer happens to straddle a page. The protocol checker flags it, and the SBR must split the burst itself.

    The core idea

    A burst must not cross a 4 KB boundary. With 4-byte beats a 16-beat INCR burst covers 64 bytes and is legal anywhere except when it starts within the last 60 bytes below a page edge (a burst starting exactly 64 bytes below the edge ends at 0x...FFF and is legal). The SBR therefore limits every burst by two rules at once: at most 16 beats (the fabric maximum), and no more beats than remain before the next 4 KB boundary. An 8-beat read from 0x0FF0 becomes two 4-beat bursts: beats 0 to 3 end exactly at 0x0FFF and beats 4 to 7 form a new burst from 0x1000. WLAST or RLAST marks the last beat of each issued burst, not of the original request, and the response path treats the two halves as independent transactions with the same ID.

    The waveform below is simulation output for the wave source of this topic: an 8-beat read split into two 4-beat bursts. One slot is one aclk cycle. The lanes carry handshakes and last flags only, no address or length, so the addresses 0x0FF0 and 0x1000 appear in the text, not in the picture.

    How to read it: arvalid pulses in slot 0 while arready stays high; rvalid then stays high for four beats (slots 1 to 4) with rlast on the fourth. rvalid is low in slots 5 and 6, and in slot 6 arvalid pulses again for the second burst, whose four beats (slots 7 to 10) carry the second rlast. The second lane is a testbench marker, high from the second address to the end of the second burst, so the two halves are easy to tell apart. An unsplit eight-beat burst would show one arvalid pulse and a single rlast on the eighth beat; the rlast after beat four of each half is the sign of the split.

    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
    PAGE = 0x1000 # 4 KB
    BEAT = 4 # bytes per beat on the 32-bit fabric
    MAXLEN = 16 # longest INCR burst on this fabric
    
    def split_burst(addr, total_beats):
        # NanoSoC teaching values: the SBR splitter. Every burst obeys BOTH limits.
        bursts = []
        left = total_beats
        while left > 0:
            to_edge = (PAGE - addr % PAGE) // BEAT
            n = min(left, MAXLEN, to_edge)
            bursts.append((addr, n))
            addr += n * BEAT
            left -= n
        return bursts
    
    def legal(bursts, addr, total_beats):
        # the protocol checker: contiguous, 1..16 beats, inside one page, nothing lost
        nxt, beats = addr, 0
        for a, n in bursts:
            if a != nxt or not 1 <= n <= MAXLEN or a % PAGE + n * BEAT > PAGE:
                return False
            nxt, beats = a + n * BEAT, beats + n
        return beats == total_beats
    
    def first_cut_splitter(addr, total_beats):
        # an earlier version: only the page edge limits the FIRST burst (the bug)
        n = min(total_beats, (PAGE - addr % PAGE) // BEAT)
        rest = split_burst(addr + n * BEAT, total_beats - n)
        return [(addr, n)] + rest
    
    cases = [
        (0x0FF0, 8, [(0x0FF0, 4), (0x1000, 4)]),
        (0x2000_0000, 64, [(0x2000_0000, 16), (0x2000_0040, 16), (0x2000_0080, 16), (0x2000_00C0, 16)]),
        (0x2000_0F00, 64, [(0x2000_0F00, 16), (0x2000_0F40, 16), (0x2000_0F80, 16), (0x2000_0FC0, 16)]),
        (0x2000_0FD0, 16, [(0x2000_0FD0, 12), (0x2000_1000, 4)]),
        (0x2000_0FF0, 64, [(0x2000_0FF0, 4), (0x2000_1000, 16), (0x2000_1040, 16), (0x2000_1080, 16), (0x2000_10C0, 12)]),
    ]
    for addr, n, want in cases:
        assert split_burst(addr, n) == want, hex(addr)
    # sweep every word-aligned start across two pages and several lengths
    for off in range(0, 2 * PAGE, 4):
        for n in (1, 3, 16, 17, 40, 64, 70):
            assert legal(split_burst(0x2000_0000 + off, n), 0x2000_0000 + off, n)
    # the checker can fail: the earlier splitter issues 64 beats where 16 is the limit
    assert not legal(first_cut_splitter(0x2000_0000, 64), 0x2000_0000, 64)
    assert not legal(first_cut_splitter(0x2000_0F00, 64), 0x2000_0F00, 64)
    print("PASS: 5 worked splits, 2-page sweep legal, the 16-beat cap bug is caught")

    What the review looks for

    • Every burst-issuing master and converter (on NanoSoC, the SBR) states its maximum burst length and its split rule, with both limits: 16 beats and the page edge.

    • The protocol checker flags any AxLEN that would cross a page, in every random test, not just directed ones.

    • WLAST and WSTRB handling is specified per issued burst, never per original request.

    Verify and debug

    Constrain random tests to start bursts near page edges: unaligned starts plus lengths up to 16 beats hit every split case within seconds, and lengths above 16 prove the second limit. If data lands in the wrong page, dump the issued AxADDR and AxLEN pairs and check each against its page: the offender is the pair whose bytes cross the boundary. Remember unaligned starts are legal; only the crossing is forbidden.

    Burst crosses a 4 KB boundary, or exceeds the length limit: a master or width converter that applies only one of the two limits issues illegal bursts, and data lands in the wrong page or the fabric rejects the request. Symptom is intermittent misplacement; caught by protocol-checker assertions and constrained-random SBR jobs; fixed by capping every burst at both limits in the master or the converter.

    If asked to split a burst on the spot, compute beats-to-boundary as page size minus offset, divided by bytes per beat, issue the smaller of that and 16, then repeat from the new address. Use the 0x0FF0 example: 16 bytes left means 4 beats, then restart at 0x1000.

    Check yourself A 16-beat burst starts at 0x2000_0FD0. How many bursts are issued, and where does the second start?

    Two: 48 bytes remain to the page edge, so 12 beats run to 0x2000_0FFF and the remaining 4 beats form a second burst from 0x2000_1000.

    Related topics

    • IDs, Outstanding Counts and No WID

    • Next: Width, Clock and Endianness Conversion

    • Protocol First Principles: AXI4

    Previous

    67 / 289

    Next: Width, Clock and Endianness Conversion

    Up next

    Up nextWidth, Clock and Endianness Conversion

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error
    aclkarvalidarreadyrvalidrlastsecond
    Simulation output: an 8-beat AXI read split into two 4-beat bursts at a 4 KB boundary, with rlast on each final beat