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
    • Designing the Address Map
    • Implementing Address Decode
    • Decode Errors and Default Slaves
      • DECERR Versus SLVERR Versus PSLVERR
      • Default-Slave Design
      • Debugging Address Hangs and Mismatches
    • Register Maps and Banks
    • Security and Privilege Regions
    • The Software View and the Hardware-Software Contract
    • IP-XACT and Automated Assembly
    • Memory-Map Verification
  • 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
  • SoC Interview Prep16
  • Capstone: Integrate NanoSoC14
Loading lesson

←Decode Errors and Default Slaves
  1. Topics
  2. SoC Design
  3. Memory Maps and Address Decode
  4. Decode Errors and Default Slaves
  5. Default-Slave Design
On this page

    Part 3 of 14, lesson 10 of 26Part 3 of 14/Memory Maps and Address Decode/Lesson 10 of 26All levels

    Default-Slave Design

    Why an unmapped access must complete, how the AXI and APB default slaves answer, and a model that proves the beats.

    Why it matters

    A decoder without a default slave is a promise the hardware cannot keep: some address in 32 bits will miss every select, the master will wait for a response that never comes, and the CPU will hang on what should have been a trappable error. The default slave exists so that every address completes. On NanoSoC three responders share that duty: the interconnect default answering DECERR for holes only (first beat one clock after the address handshake, then one beat per clock while the master is ready), the secure-fault responder answering SLVERR with no data for a mapped-but-forbidden access, and the APB default answering PSLVERR with the same timing as a normal peripheral access so the bridge never has to special-case it. The first two differ only in the code they return, so one design serves both behind a mode input. One simplification to note: the sketch omits the ID ports, and a production responder must echo each transaction's ID on its read and write responses; the beat accounting below is unaffected.

    The core idea

    Both AXI responders accept the address at once, then return one error beat per requested beat: a burst of length N, encoded as ARLEN N minus 1, gets exactly N read beats carrying the responder's code on every beat, DECERR for the default slave and SLVERR for the fault responder, with RLAST on the last beat only. Writes get every write beat accepted and dropped, then a single write response carrying the same code. The beat count is held in a small down-counter preloaded from ARLEN, which is why the proof below checks every length from 1 to 16 in both modes. The APB default slave is simpler: it answers any selected access with pready and pslverr together after one wait state, three clocks per access, so unmapped slots and offsets cost software exactly what a slow peripheral costs and hang nothing.

    nano_axi_default_slave.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
    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
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    // NanoSoC teaching values: error responders. Every rejected access completes; none hangs.
    // fault_mode = 0: default slave, holes only, DECERR. fault_mode = 1: secure-fault
    // responder, mapped-but-forbidden, SLVERR with no data. Both return one error beat
    // per requested beat with RLAST on the last; writes are sunk, one B response.
    module nano_axi_default_slave (
      input  logic       aclk,
      input  logic       aresetn,
      input  logic       fault_mode,
      input  logic       arvalid,
      output logic       arready,
      input  logic [7:0] arlen,
      output logic       rvalid,
      input  logic       rready,
      output logic [1:0] rresp,
      output logic       rlast,
      input  logic       awvalid,
      output logic       awready,
      input  logic       wvalid,
      output logic       wready,
      input  logic       wlast,
      output logic       bvalid,
      input  logic       bready,
      output logic [1:0] bresp
    );
      logic [7:0] beats_left;
      logic       active;
      logic       w_active, w_last_seen;
    
      always_ff @(posedge aclk or negedge aresetn) begin
        if (!aresetn) begin
          active <= 1'b0;
          beats_left <= 8'h0;
        end else if (arvalid && arready) begin
          active <= 1'b1;
          beats_left <= arlen;
        end else if (rvalid && rready) begin
          if (beats_left == 8'h0) active <= 1'b0;
          else beats_left <= beats_left - 8'h1;
        end
      end
      assign arready = ~active;
      assign rvalid = active;
      assign rresp = fault_mode ? 2'b10 : 2'b11; // SLVERR for fault, DECERR for holes
      assign rlast = (beats_left == 8'h0);
    
      always_ff @(posedge aclk or negedge aresetn) begin
        if (!aresetn) begin
          w_active <= 1'b0;
          w_last_seen <= 1'b0;
        end else if (awvalid && awready) begin
          w_active <= 1'b1;
          w_last_seen <= 1'b0;
        end else if (wvalid && wready && wlast) begin
          w_last_seen <= 1'b1;
        end else if (bvalid && bready) begin
          w_active <= 1'b0;
          w_last_seen <= 1'b0;
        end
      end
      assign awready = ~w_active;
      assign wready = w_active & ~w_last_seen; // stop accepting once WLAST seen
      assign bvalid = w_active & w_last_seen;
      assign bresp = fault_mode ? 2'b10 : 2'b11; // same code as the read side
    endmodule
    
    module nano_apb_default_slave (
      input  logic pclk,
      input  logic presetn,
      input  logic psel,
      input  logic penable,
      output logic pready,
      output logic pslverr
    );
      // One wait state like the DMA: setup, access, access-with-ready.
      logic wait1, done2;
      always_ff @(posedge pclk or negedge presetn) begin
        if (!presetn) begin
          wait1 <= 1'b0;
          done2 <= 1'b0;
        end else begin
          wait1 <= psel & ~penable;
          done2 <= wait1 & psel & penable;
        end
      end
      assign pready = done2;
      assign pslverr = done2;
    endmodule
    

    The model

    Two checks back the responder. The reference model below is an independent statement of the required behaviour, not a copy of the RTL: for every legal burst length it requires exactly that many response beats carrying the mode's code on every beat with RLAST only on the last, even when the master stalls ready, and exactly one write response per burst. It checks all sixteen lengths in both modes (DECERR for holes, SLVERR for faults), with and without stalls. Because the model is written from the requirement, it can fail: change the required RLAST position or a code and it does. The RTL itself is exercised by the self-checking testbench at the end of the listing, which drives all sixteen lengths in both modes with a stalled RREADY and write beats with gaps, holds the write response until it is accepted, and offers the first beat of the next burst while the previous response is still pending. Re-add the earlier bug, wready = w_active with no WLAST term, and the testbench fails: that early beat would be swallowed and the next burst would hang.

    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
    DECERR, SLVERR = 0b11, 0b10
    
    def run_reads(arlen, fault, stall_every=0):
        # Mirror of the RTL down-counter; resp code follows fault_mode.
        resp = SLVERR if fault else DECERR
        beats_left = arlen
        codes, last_at = [], None
        cycle = 0
        while True:
            rready = True if stall_every == 0 else (cycle % stall_every != 1)
            if rready:
                codes.append(resp)
                if beats_left == 0:
                    last_at = len(codes)
                    break
                beats_left -= 1
            cycle += 1
            assert cycle < 1000
        return codes, last_at
    
    def run_writes(awlen, fault):
        # Every beat accepted and dropped, then exactly one write response.
        sunk = awlen + 1
        return sunk, [SLVERR if fault else DECERR]
    
    for fault in (False, True):
        want = SLVERR if fault else DECERR
        for arlen in range(16):
            for stall in (0, 3):
                codes, last_at = run_reads(arlen, fault, stall)
                assert len(codes) == arlen + 1 and last_at == arlen + 1
                assert all(c == want for c in codes)
            sunk, bresps = run_writes(arlen, fault)
            assert sunk == arlen + 1 and bresps == [want]
    codes, last_at = run_reads(3, False)
    try:
        assert last_at == 3  # negative control: RLAST one beat early must be rejected
        raise SystemExit("reference model cannot fail")
    except AssertionError:
        pass
    print("PASS: both modes, lengths 1..16, exact beats, code per beat, RLAST last, one B response")

    What the review looks for

    • Every decoder output fans into either a real slave or a default slave; the connectivity check proves no select dangles.

    • The reference model above, or its equivalent, runs in the build for all sixteen burst lengths in both modes.

    • Write bursts to holes are sunk and answered, not just reads: the write path has its own counter and its own test.

    Verify and debug

    Send single and sixteen-beat reads and writes to one address in each hole and count the beats: H1 and H4 must each return exactly the requested beats with DECERR and a single RLAST or write response, H3 must return one SLVERR per access with no hang, and a non-secure burst at SRAM1 must return SLVERR on every beat from the fault responder, never DECERR from the default slave. If a burst returns short, the down-counter was preloaded wrong; if a faulted burst returns DECERR, the fault select is wired into the wrong responder. Both are caught by the model before they reach simulation.

    An APB bridge that ignores PREADY or drops PSLVERR: a slow peripheral appears to answer instantly with stale data, or its error never reaches software. Honour PREADY on every transfer and propagate PSLVERR into the AXI error response; the bridge needs its own protocol-checker test with randomised wait states.

    If asked why the default slave needs a counter at all, answer with bursts: one address phase can demand sixteen data beats, and each beat needs its own response with RLAST exactly once. A slave that answers the address but not the beats hangs the master mid-burst.

    Check yourself A four-beat read targets hole H1. How many response beats arrive, with what code and what RLAST pattern?

    Four beats, DECERR on all four, RLAST low on the first three and high on the fourth. The count comes from ARLEN plus one; the code is 2'b11 on every beat.

    Related topics

    • DECERR Versus SLVERR Versus PSLVERR

    • Next: Debugging Address Hangs and Mismatches

    • Protocol First Principles: AXI4

    • Protocol First Principles: APB

    Previous

    48 / 289

    Next: Debugging Address Hangs and Mismatches

    Up next

    Up nextDebugging Address Hangs and Mismatches

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error