Skip to content
VLSI Mentor

Wishbone · Module 6

Read Cycle Flow

One Wishbone read followed through nine stages from a client request to a returned value: what each stage contributes, why the forward and return paths are asymmetric, and where a read that hangs actually stopped.

Module 5 taught the handshake as a timed contract — a cycle that frames, a strobe that presents, a termination that answers. Reads and writes were vehicles for it.

Module 6 makes one of them the subject.

What is the complete architectural path of a single Wishbone read?

1. The Nine Stages

A read passes through nine identifiable stages. Naming them now gives the rest of Module 6 — and every debugging section in it — a shared vocabulary.

A block diagram of a complete Wishbone read path arranged as two rows. The top row is the forward path, running left to right: the client issues a read request, the master accepts and presents it on the bus as an address with write enable low, the interconnect decodes that address to select one slave and produce a local offset, and the slave uses that offset to index its register bank. The bottom row is the return path, running right to left: the register value enters the slave's read multiplexer which drives it onto the slave data output together with an acknowledge, the interconnect merges responses from all slaves onto one return path, the master captures the value at the termination edge, and the client receives the result with a completion pulse.1. CLIENTread request2. MASTERADR_O, WE_O=0, CYC/STB3. DECODEselect + local offset4. SLAVEindex the register5. READ MUXDAT_O + ACK_O6. MERGEone return path7. CAPTUREat the ACK edge8. RESULTrdat + done12
Figure 1 — the complete read path. The forward path carries the question; the return path carries the answer.
StageWhat it contributesOwns itChapter
1 Client requesta local intention: read this addressclient5.5
2 Master presentsADR_O, WE_O negated, CYC_O+STB_Omaster6.2
3 Decodeglobal address → slave select + local offsetinterconnect6.2
4 Slave indexeslocal offset → which registerslave6.3
5 Read muxregister value → DAT_O, plus ACK_Oslave6.3, 6.4
6 Mergeone slave's response onto the return pathinterconnect6.3
7 CaptureDAT_I sampled at the termination edgemaster6.3
8 Resultrdat + one completion pulsemaster5.6
9 ReleaseCYC_O/STB_O negatedmaster5.2

The ninth stage has no box in the figure because it produces nothing — but a master that never reaches it has not finished, and Chapter 5.6 showed what a missing release costs.

2. Reading Is Not the Absence of Writing

WE_O negated means read, not idle. That sounds obvious and produces a specific bug when misread.

The WE_O signal description is explicit: "The write enable output [WE_O] indicates whether the current local bus cycle is a READ or WRITE cycle. The signal is negated during READ cycles, and is asserted during WRITE cycles."

It says nothing about whether a transfer exists. That is CYC_O and STB_O's job, and Chapter 5.1 established that values on wires are not requests. WE_O low with both qualifiers low is an idle bus; WE_O low with both asserted is a read in progress. The direction bit does not distinguish those two — the qualifiers do.

What the master still drives during a read. RULE 3.60 qualifies ADR_O, DAT_O(), SEL_O() and WE_O with STB_Onote that DAT_O is in that list. A master presenting a read still has its write-data output qualified, and Chapter 4.6 showed it typically carries the previous write's value. The specification's own SINGLE READ figure shows the master's DAT_O in an undefined state throughout.

Which is why a slave must check WE_I before writing anything — a point Chapter 4.6 made and that Section 6 of this chapter revisits from the read side.

3. The Running Peripheral

Module 6 uses one device throughout, extended as chapters require.

Byte offsetWord offsetRegisterAccessContents
0x000STATUSread-onlyflags, some externally driven
0x041COUNTread-onlya free-running counter
0x082CONTROLread/writeconfiguration
0x0C3INPUT_DATAread-onlyan external input, changes on its own
0x104IDread-onlya constant

4. RTL — The Master and the Register Bank

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_read_master — the Module 6 running master.
//
// PURPOSE. Turn a local client read request into a Wishbone read and return
// the value. It is Chapter 5.6's wb_completion_master specialised for reads:
// the same client contract, the same acceptance boundary, the same
// level-sampled termination and the same one-pulse completion.
//
// WHAT IS NEW HERE is only that WE_O is driven low and that the captured
// value is the point of the exercise rather than a detail of it.
//
// CLIENT CONTRACT (LOCAL POLICY, not Wishbone — RULE 2.15 would require a
// datasheet to state it):
//   * req_i is accepted only in a cycle where acc_o is also asserted.
//   * one transaction outstanding at a time.
//   * done_o pulses once per accepted request; rdat_o is then valid and held.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00, 3.20).
// ─────────────────────────────────────────────────────────────────────────
module wb_read_master #(
  parameter int unsigned AW = 30,          // WORD address width
  parameter int unsigned DW = 32
) (
  input  logic            clk_i,
  input  logic            rst_i,

  // ── local client side (not Wishbone) ────────────────────────────────
  input  logic            req_i,
  input  logic [AW-1:0]   req_adr_i,       // WORD address
  input  logic [DW/8-1:0] req_sel_i,
  output logic            acc_o,
  output logic            busy_o,
  output logic            done_o,
  output logic [1:0]      status_o,        // 0=ok 1=error 2=retry
  output logic [DW-1:0]   rdat_o,

  // ── Wishbone MASTER interface ───────────────────────────────────────
  output logic            cyc_o,
  output logic            stb_o,
  output logic            we_o,
  output logic [AW-1:0]   adr_o,
  output logic [DW-1:0]   dat_o,
  output logic [DW/8-1:0] sel_o,
  input  logic [DW-1:0]   dat_i,
  input  logic            ack_i,
  input  logic            err_i,
  input  logic            rty_i
);
  localparam logic [1:0] ST_OK = 2'd0, ST_ERR = 2'd1, ST_RTY = 2'd2;

  // ── STATE ─────────────────────────────────────────────────────────────
  // active_q: a read is outstanding. adr_q / sel_q: the PRIVATE COPY that
  // makes RULE 3.60 satisfiable across an unbounded wait (Chapter 5.5).
  logic            active_q;
  logic [AW-1:0]   adr_q;
  logic [DW/8-1:0] sel_q;

  assign acc_o  = req_i & ~active_q;
  assign busy_o = active_q;

  // ── BUS OUTPUTS ───────────────────────────────────────────────────────
  // PERMISSION 3.40 lets both qualifiers share one signal: this master
  // never negates STB_O mid-transfer.
  assign cyc_o = active_q;
  assign stb_o = active_q;
  assign adr_o = adr_q;
  assign sel_o = sel_q;

  // WE_O held low for the whole transfer. RULE 3.60 qualifies it with
  // STB_O, so it must be stable while the transfer is presented — here it
  // is a constant, which satisfies that trivially and makes the read
  // direction impossible to corrupt mid-transfer.
  assign we_o = 1'b0;

  // DAT_O is a master OUTPUT even on a read, and RULE 3.60 qualifies it.
  // Driving zero is an EDUCATIONAL CHOICE, not a requirement: the
  // specification's SINGLE READ figure shows it undefined, and Chapter 4.6
  // showed a master legally leaving stale write data here. Zero makes
  // simulation traces easier to read and hides nothing, because a correct
  // slave ignores DAT_I entirely when WE_I is negated.
  assign dat_o = '0;

  logic terminated;
  assign terminated = ack_i | err_i | rty_i;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      active_q <= 1'b0;                    // RULE 3.20
      adr_q    <= '0;
      sel_q    <= '0;
      done_o   <= 1'b0;
      status_o <= ST_OK;
      rdat_o   <= '0;
    end else begin
      done_o <= 1'b0;                      // done_o is a PULSE

      if (acc_o) begin
        // ── READ START ──────────────────────────────────────────────────
        // Metadata captured once. From the next edge the client may change
        // its inputs freely; the bus is driven from adr_q / sel_q.
        active_q <= 1'b1;
        adr_q    <= req_adr_i;
        sel_q    <= req_sel_i;
      end else if (active_q && terminated) begin
        // ── TERMINATION EDGE ────────────────────────────────────────────
        // Chapter 5.6's four obligations. The capture condition needs only
        // two terms here rather than three, because this master never
        // writes — there is no `!we_q` to check.
        //
        //   active_q : the transfer is still presented, so the selected
        //              slave is still driving the return path
        //   ack_i    : a SUCCESSFUL termination. RULE 3.65 ties the slave's
        //              DAT_O to its termination; on ERR or RTY there is no
        //              defined read value.
        if (ack_i) rdat_o <= dat_i;

        status_o <= ack_i ? ST_OK : (err_i ? ST_ERR : ST_RTY);
        active_q <= 1'b0;                  // release CYC_O and STB_O
        done_o   <= 1'b1;                  // report exactly once
      end
    end
  end
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_read_regs — the running peripheral, read path only.
//
// PURPOSE. Turn a local word offset into a register value, and terminate.
// This is stage 4, 5 and part of 6 of Figure 1.
//
// TERMINATION STYLE. Combinational, which PERMISSION 3.30 explicitly allows
// ("i.e. there is a combinatorial logic path between [STB_I] and [ACK_O]")
// and OBSERVATION 3.40 credits with one transfer per clock. Chapter 6.4
// builds the registered alternative and weighs them.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_read_regs #(
  parameter int unsigned OFF_AW = 3,       // 8 word offsets
  parameter int unsigned DW     = 32
) (
  input  logic              clk_i,
  input  logic              rst_i,
  // Wishbone SLAVE interface
  input  logic              cyc_i,
  input  logic              stb_i,
  input  logic              we_i,
  input  logic [OFF_AW-1:0] adr_i,         // LOCAL word offset
  input  logic [DW-1:0]     dat_i,
  input  logic [DW/8-1:0]   sel_i,
  output logic [DW-1:0]     dat_o,
  output logic              ack_o,
  output logic              err_o,
  // device-side inputs: genuinely external, change on their own
  input  logic [DW-1:0]     input_data_i,
  input  logic [7:0]        flags_i
);
  // Word offsets. The byte offsets a datasheet would quote are 4x these.
  localparam logic [OFF_AW-1:0] O_STATUS = 3'd0;   // byte 0x00
  localparam logic [OFF_AW-1:0] O_COUNT  = 3'd1;   // byte 0x04
  localparam logic [OFF_AW-1:0] O_CTRL   = 3'd2;   // byte 0x08
  localparam logic [OFF_AW-1:0] O_INPUT  = 3'd3;   // byte 0x0C
  localparam logic [OFF_AW-1:0] O_ID     = 3'd4;   // byte 0x10

  localparam logic [DW-1:0] ID_VALUE = 32'h5742_0601;  // "WB", module 6 rev 1

  logic [DW-1:0] ctrl_q;
  logic [DW-1:0] count_q;

  // ── THE QUALIFIED TRANSFER ────────────────────────────────────────────
  // RULE 3.30 forbids responding to any slave signal while CYC_I is
  // negated; RULE 3.35 requires the termination to be generated from the
  // AND of CYC_I and STB_I.
  logic xfer;
  assign xfer = cyc_i & stb_i;

  // ── OFFSET LEGALITY ───────────────────────────────────────────────────
  logic known_off;
  always_comb begin
    unique case (adr_i)
      O_STATUS, O_COUNT, O_CTRL, O_INPUT, O_ID: known_off = 1'b1;
      default:                                  known_off = 1'b0;
    endcase
  end

  // A write to a read-only offset is refused. Module 6 is about reads, so
  // the write path exists only to keep CONTROL genuinely writable and to
  // keep the read/write distinction honest.
  logic illegal;
  assign illegal = ~known_off | (we_i & (adr_i != O_CTRL));

  // RULE 3.35 both; RULE 3.45 mutually exclusive by construction.
  assign err_o = xfer &  illegal;
  assign ack_o = xfer & ~illegal;

  // ── THE READ MULTIPLEXER ──────────────────────────────────────────────
  // RULE 3.65 requires a slave to qualify DAT_O() with its termination, so
  // ack_o appears in the condition. Driving '0 otherwise also keeps a
  // merged return path clean (Chapter 3.5) — Chapter 6.3 develops both.
  //
  // dat_o is assigned unconditionally first, so every path through this
  // block writes it. That is what prevents an inferred latch.
  always_comb begin
    dat_o = '0;
    if (xfer && !we_i && ack_o) begin
      unique case (adr_i)
        O_STATUS: dat_o = {24'd0, flags_i};
        O_COUNT:  dat_o = count_q;
        O_CTRL:   dat_o = ctrl_q;
        O_INPUT:  dat_o = input_data_i;    // sampled combinationally
        O_ID:     dat_o = ID_VALUE;
        default:  dat_o = '0;
      endcase
    end
  end

  // ── STATE ─────────────────────────────────────────────────────────────
  // count_q free-runs: it is a genuinely moving value, which makes it a
  // useful read target for detecting a master that captures at the wrong
  // edge (Chapter 6.3).
  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      ctrl_q  <= '0;
      count_q <= '0;
    end else begin
      count_q <= count_q + 32'd1;
      // The only write path. Gated on ack_o, not merely on xfer — the
      // distinction is invisible here because this slave never waits, and
      // load-bearing the moment it does (Chapters 5.3 and 6.5).
      if (xfer && we_i && ack_o && (adr_i == O_CTRL)) begin
        for (int unsigned n = 0; n < DW/8; n++) begin
          if (sel_i[n]) ctrl_q[n*8 +: 8] <= dat_i[n*8 +: 8];
        end
      end
    end
  end
endmodule

Reading the pair

Purpose. The master converts a client intention into a qualified read and captures the answer; the register bank converts a local offset into a value and terminates.

Interface. The master's client side is Module 5's contract unchanged. The slave sees a Wishbone slave interface plus two genuinely external device inputs.

State. Master: the outstanding flag and the address/select copy. Slave: CONTROL and a free-running counter.

Combinational logic. Master: acc_o and all bus outputs from state. Slave: xfer, offset legality, two exclusive terminations, and the read multiplexer.

Sequential logic. Master: capture at acceptance, capture-and-release at termination. Slave: the counter, and the single write path.

Read start. CYC_O and STB_O rise together at the edge following req_i & ~active_q, with adr_q already loaded at that same edge. RULE 3.25's "no later than" is met by rising together.

Address. From adr_q, written once. It cannot move while the transfer is outstanding — Chapter 6.2 simulates what happens when it can.

Data return. From the slave's read multiplexer, gated on ack_o per RULE 3.65.

ACK. Combinational from the qualified transfer and offset legality, per PERMISSION 3.30.

Capture. rdat_o <= dat_i at the termination edge, only on ack_i.

Waiting. This pair never waits — ack_o is asserted in the presented cycle. Chapter 6.5 adds latency and shows what must stay coherent.

Reset. Synchronous, active high. active_q <= 0 negates both qualifiers, satisfying RULE 3.20 through the state encoding.

Failure modes. Section 6.

Simplifications. No interconnect yet — the slave's adr_i is assumed already decoded to a local offset, which Chapter 6.2 builds. One outstanding transaction. No read side effects until Chapter 6.5.

5. The Canonical Read, Edge by Edge

A single Wishbone read

6 cycles
Six clock cycles showing one complete Wishbone read. Cycle one is idle with all qualifiers negated. In cycle two the master asserts both the cycle and strobe signals, drives word address four on the address output, and holds write enable low to indicate a read. The slave, which answers combinationally, therefore asserts its acknowledge and drives the identification value in the same cycle. At the edge ending cycle two the master samples the acknowledge asserted and captures the returned data. In cycle three both qualifiers are negated, the acknowledge has fallen in response, the returned data line has reverted to zero, and the master's captured result register now holds the identification value with its completion pulse asserted.read presented; slave answersread presented; slaveanswerscaptured + reportedcaptured + reportedCLK_ICYC_OSTB_OWE_OADR_O----0x004----------------ACK_IDAT_I0x0574206010x00x00x00x0rdat_o0x00x057420601574206015742060157420601done_ot0t1t2t3t4t5
Figure 2 — one complete read of ID. The address is presented for one cycle; the answer is valid for one cycle.

Narrate it — this is the habit Module 6 trains.

Before edge 2. The master drives CYC_O, STB_O, ADR_O = 4 and WE_O = 0. The slave, answering combinationally, already has ACK_O asserted and 0x57420601 on its DAT_O. Nothing has been observed yet by either side.

At edge 2 — both the sampling edge and the termination edge. The slave sees a qualified transfer. The master samples ack_i asserted and dat_i in the same instant. This is the only edge at which the returned value is meaningful, per RULE 3.65.

After edge 2. active_q has cleared, so CYC_O and STB_O are negated. rdat_o holds the value. done_o pulses. The slave, seeing STB_I negate, drops ACK_O and reverts DAT_O — RULE 3.50, which OBSERVATION 3.10 calls automatic.

Why sampling and termination coincide here. The slave is combinational, so Chapter 5.7's CONTINUATION interval is empty. The entire forward-and-return path of Figure 1 must resolve inside cycle 2 — which is OBSERVATION 3.50's loopback, and the reason Chapter 6.4 exists.

6. Failure Modes and Discriminating Evidence

Symptom: the read hangs — STB_O asserted, no termination, forever.

Candidate causes. Any of the nine stages. All produce an identical master-side waveform, which is why probing in order matters more than guessing.

Discriminating evidence. Walk the path from Figure 1:

ProbeIf absent, the fault is
CYC_O/STB_O at the masterthe master's own state machine, or a RULE 3.25 duration violation (5.2)
CYC_I/STB_I at the intended slaveaddress decode or forward routing
ACK_O inside that slavethe slave — usually an unhandled default in the offset decoder
ACK_I back at the masterthe response merge, or a master lacking the termination the slave produced

The first probe where the expected signal is missing names the stage, and nothing else does. Chapter 5.1 §5 established this sequence; Chapter 6.6 turns it into a full method.

Likely RTL location. Determined by the probe, never assumed.

Symptom: the read completes and returns the wrong register's value.

Candidate causes. Wrong address on the bus, wrong decode, wrong local offset, or a wrong read-multiplexer case.

Discriminating evidence. Compare ADR_O at the master against the intended word address, then the decoded select, then the local offset, then the multiplexer output. The first mismatch names the stage. Chapter 6.2 and Chapter 6.3 develop each.

Symptom: the read completes and returns zero.

Candidate causes. An offset the slave does not implement — but that should produce ERR_O, not ACK_O with zero. Or the master captured outside the termination cycle and sampled a reverted return path.

Discriminating evidence. Check status_o. ST_ERR means the slave refused and zero is expected; ST_OK with zero means the capture is suspectChapter 5.6 measured a late-capturing master returning zero on every read.

Symptom: reading a register appears to change the device.

Candidate causes. Either the slave has a genuine read side effect (see the callout in Section 2), or its write path is missing its WE_I term and is firing on reads.

Discriminating evidence. Check what value the register took. A genuine read-to-clear takes a defined value — usually zero. A missing-WE_I bug takes the previous write's data, because RULE 3.60 leaves that on DAT_O during a read (Chapter 4.6). That fingerprint separates a feature from a bug in one observation.

7. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_read_flow_checker — the read-path invariants introduced here.
//
// P1 and P2 are SPECIFICATION. P3 is a DESIGN OBLIGATION derived from
// RULE 3.65 — the rule constrains the SLAVE's DAT_O, and what the master
// does with that window is the master's design (Chapter 5.8 Section 11).
// P4 is LOCAL POLICY for this master's client contract.
// ─────────────────────────────────────────────────────────────────────────
module wb_read_flow_checker #(
  parameter int unsigned DW = 32
) (
  input logic          clk_i,
  input logic          rst_i,
  input logic          cyc_o,
  input logic          stb_o,
  input logic          we_o,
  input logic          ack_i,
  input logic          err_i,
  input logic          rty_i,
  input logic [DW-1:0] rdat_q,       // white-box: captured result
  input logic          busy_o,
  input logic          done_o
);
  default disable iff (rst_i);

  // P1 — SPECIFICATION (RULE 3.25). A strobe never exists outside a cycle.
  property p_stb_implies_cyc;
    @(posedge clk_i) stb_o |-> cyc_o;
  endproperty
  a_stb_implies_cyc : assert property (p_stb_implies_cyc)
    else $error("RULE 3.25: STB_O asserted without CYC_O");

  // P2 — SPECIFICATION (RULE 3.60, as stability). WE_O is qualified by
  //      STB_O, so the DIRECTION of a presented transfer cannot change
  //      while it is outstanding. A read must stay a read.
  property p_direction_stable;
    @(posedge clk_i) (cyc_o && stb_o && !(ack_i||err_i||rty_i)) |=> $stable(we_o);
  endproperty
  a_direction_stable : assert property (p_direction_stable)
    else $error("RULE 3.60: WE_O changed while the transfer was outstanding");

  // P3 — DESIGN OBLIGATION (from RULE 3.65). The captured result changes
  //      only at the edge of a SUCCESSFUL termination of a presented read.
  //      Catches both the off-by-one capture and an unconditional one.
  //      $past is required: rdat_q changes AT the edge, while the
  //      conditions authorising it were true BEFORE it.
  property p_capture_on_successful_read;
    @(posedge clk_i) $changed(rdat_q) |-> $past(cyc_o && stb_o && ack_i && !we_o);
  endproperty
  a_capture_on_successful_read :
    assert property (p_capture_on_successful_read)
    else $error("read data captured outside a successful read termination");

  // P4 — LOCAL POLICY. One completion per bus termination, and never
  //      without an outstanding transaction.
  property p_done_follows_termination;
    @(posedge clk_i) done_o
      |-> $past(busy_o && cyc_o && stb_o && (ack_i || err_i || rty_i));
  endproperty
  a_done_follows_termination : assert property (p_done_follows_termination)
    else $error("completion pulse without a matching bus termination");
endmodule

P2 is worth a note. It is the read-specific form of RULE 3.60's stability obligation: a transfer whose WE_O flips mid-flight is not one transfer, and a slave that samples the direction late would perform the wrong operation. In wb_read_master it holds trivially because we_o is a constant — which is the point of making it a constant rather than a register.

Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection; the synthesizable RTL is elaborated and simulated in Section 8.

8. Simulation — The Basic Read, Measured

wb_read_master was pointed at wb_read_regs and asked to read each implemented offset once, plus one unimplemented offset.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIMULATION A - basic read ===
  off  register       expected     captured   status  ADR_O  WE_O  done
    0  STATUS         0x000000a5   0x000000a5   OK       0x0     0     1
    1  COUNT          (moving)     0x00000006   OK       0x1     0     1
    2  CONTROL        0x00000000   0x00000000   OK       0x2     0     1
    3  INPUT_DATA     0xcafebabe   0xcafebabe   OK       0x3     0     1
    4  ID             0x57420601   0x57420601   OK       0x4     0     1
    7  (unmapped)     -            0x57420601   ERR      0x7     0     1
  completions: 6 requests -> 6 done pulses
  WE_O asserted at any point: 0

Every implemented offset returned its own value, so the read multiplexer and the address path agree.

COUNT returned 0x06 — a moving value, captured at a specific edge, and the exact number depends only on how many cycles elapsed before that read. Chapter 6.3 uses exactly this property to expose a master that captures at the wrong edge, because a stale capture of a constant is invisible.

The unmapped offset returned ERR and left rdat_o unchanged at the previous read's value. That is correct: on an error there is no defined read value, so the master does not capture — and a client that checks status_o before using rdat_o is never misled. A client that ignores status_o sees a plausible stale value, which is the argument for the three-way status rather than a single flag.

WE_O was never asserted, confirming P2 held throughout.

9. Common Mistakes

"A Wishbone read has an address phase and then a data phase, like AXI."

Wrong mental model: separate handshaked channels.

Concrete bug: a master that presents an address, drops the strobe, and waits for data on a later "phase". The slave sees the request vanish and nothing ever completes.

Observable evidence: a strobe asserted for one cycle, then a hang with no termination.

Correct model: Classic has one handshake. The address is qualified by STB_O for the transfer's whole duration and the data comes back within that same transfer. Chapter 6.2 scopes the phrase "address phase" carefully for exactly this reason.

"WE_O low means the bus is idle."

Wrong mental model: the direction bit indicates activity.

Concrete bug: a slave gating on ~we_i without the qualifiers, acting on an idle bus whose WE_O happens to be low.

Observable evidence: reads that appear to happen with no software access, or side effects firing between transfers.

Correct model: WE_O describes direction, CYC_O & STB_O describe existence. Chapter 5.1 §1 is the general form of this.

"A read cannot change hardware state."

Wrong mental model: reads are passive by definition.

Concrete bug: a driver that re-reads an interrupt status register "just to be safe", clearing events nobody handled.

Observable evidence: lost interrupts correlated with diagnostic or logging code.

Correct model: read-to-clear and pop-on-read are ordinary peripheral designs. The direction bit says where the data flows, not whether the device changed. Chapter 6.5 builds one correctly.

10. Interview Reasoning

Before the first edge. A client presents a read request. The master, idle, asserts its accept signal — that conjunction is the acceptance boundary, and it is the last moment the client's inputs matter.

At the acceptance edge. The master latches the word address and byte selects into private registers and sets its outstanding flag. The transaction now exists. Everything the bus sees from here comes from those registers, which is what makes RULE 3.60 satisfiable across a wait of unknown length.

Before the next edge. CYC_O and STB_O are asserted, ADR_O carries the word address, WE_O is negated to indicate a read. The interconnect decodes the address, selects one slave and presents a local offset. The selected slave indexes its register file and — if it answers combinationally — already has ACK_O asserted and the value on its DAT_O.

At the termination edge. The slave sees a qualified transfer. The master samples ack_i asserted while its own transfer is presented — that conjunction is what makes the termination its termination — and samples dat_i in the same instant. RULE 3.65 ties the slave's read data to its termination, so this is the only edge at which the value is meaningful.

After that edge. The master clears its outstanding flag, which negates both qualifiers. The captured value is in a register. One completion pulse goes to the client. The slave, seeing STB_I negate, drops ACK_O and stops driving read data — OBSERVATION 3.10 calls that automatic.

If the slave needs longer, nothing about the story changes except that the termination edge arrives later. The master holds everything still and samples the termination as a level every cycle. There is no separate wait signal — the slave throttles purely by withholding its acknowledge.

The two things I would emphasise as the actual content. The address is meaningful for the whole transfer; the data is meaningful for one cycle. And the master must sample the termination as a level, not an edge, because a slave may legally hold ACK asserted — RULE 3.55.

11. Understanding Check

12. What's Next

The whole read is now visible: nine stages, a forward path carrying a question and a return path carrying an answer, with the data meaningful for exactly one cycle.

The first payload on that forward path is the address, and it has been treated as a value that simply appears on ADR_O. It carries more than a number — it selects a device and a register inside it, and the phrase used for that interval invites an assumption from other protocols that is wrong here.

When does ADR_O identify the read target, and how long must that information stay coherent?

Chapter 6.2 — Address Phase answers it. The full path is on the Wishbone curriculum index.

Continue learning

Standards & specifications

Governing standard
Wishbone SoC Interconnection Architecture (OpenCores)(opens OpenCores in a new tab)

Defines the Wishbone signal set, the bus cycles built from it and the interface rules a portable IP core must follow. It deliberately leaves interconnect topology, address map and arbitration policy to the integrator, so those are system decisions rather than requirements of the specification.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Wishbone curriculum.