Skip to content
VLSI Mentor

Wishbone · Module 4

DAT_O

Both masters and slaves have a DAT_O, and they mean opposite things. What each must drive, when it must be valid, and why a master may legally leave stale write data on the bus during a read.

Chapter 4.3 settled where. The next two chapters settle what — and the first of them has to clear up a name that causes more wiring errors than any other in the interface.

If an interface owns DAT_O, what must it drive, and when?

1. Two Paths, Not One Bus

Wishbone has two unidirectional data paths, and each is an output at one end and an input at the other.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  MASTER                           SLAVE
  ──────                           ─────
  DAT_O  ───── write data ──────▶  DAT_I
  DAT_I  ◀──── read data  ──────   DAT_O

Why two paths rather than one bidirectional bus. Chapter 2.3 §1 gave the general reason: on-chip, a tri-state net costs more than it saves, so the industry standard is separate paths with multiplexing in the fabric. Wishbone follows that, and the consequence is visible in the interconnect — Chapter 3.5 §2 broadcasts the master's DAT_O to every slave and multiplexes the slaves' DAT_O back.

The asymmetry is not cosmetic. The write path has one producer and many possible consumers, which is free. The read path has many producers and one consumer, which requires selection. That is why adding a slave costs almost nothing on the write side and one more multiplexer input per data bit on the read side.

2. The Master's Output: Write Data

RULE 3.60"MASTER interfaces MUST qualify the following signals with [STB_O]: [ADR_O], [DAT_O()], [SEL_O()], [WE_O], and [TAGN_O]."

DAT_O is in that list, so the master's obligations are the same as for the address:

It is meaningful only under STB_O. Between transfers it carries residue, and no slave may act on it.

It must be stable while the transfer is presented. If a slave waits, the write data must not move — the structural-stability argument from Chapter 3.3, met by driving the bus from a latched copy.

One thing the rule does not say, and it matters: nothing requires the master to drive meaningful data on a read. The specification qualifies DAT_O with STB_O, not with STB_O && WE_O. Engineering consequence: a slave must not attach significance to DAT_I during a read, and a master is free to leave whatever it likes there. Most masters simply present the last write value, which is exactly what Chapter 3.3's copy engine does.

3. The Slave's Output: Read Data

A slave's DAT_O carries the value at the addressed location, and it has one obligation the master's side does not.

It must be meaningful in the termination cycle. Chapter 3.7 established that read data is valid in the cycle the termination is asserted and is not held afterwards. That is the window the master captures in.

And it must be quiet when this slave is not the one being addressed. This is the obligation people miss, and it is not a specification rule — it is a consequence of how fabrics merge.

4. RTL — Both Output Sides

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_dat_master_out — the MASTER's DAT_O: write data.
//
// PURPOSE. Show the output-side obligation in isolation: the write data is
// latched once, driven from the register, and never moves while the
// transfer is presented (RULE 3.60).
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_dat_master_out #(
  parameter int unsigned AW = 30,
  parameter int unsigned DW = 32
) (
  input  logic          clk_i,
  input  logic          rst_i,

  input  logic          go_i,
  input  logic          we_i,
  input  logic [AW-1:0] adr_i,
  input  logic [DW-1:0] wdat_i,

  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,        // MASTER DAT_O = WRITE data
  input  logic          ack_i,
  input  logic          err_i,
  input  logic          rty_i
);
  logic          active_q, we_q;
  logic [AW-1:0] adr_q;
  logic [DW-1:0] dat_q;

  // Every qualified signal is driven from a REGISTER. That is what makes
  // RULE 3.60's stability obligation structural — the client may change
  // wdat_i the cycle after go_i and the bus does not move.
  assign cyc_o = active_q;
  assign stb_o = active_q;
  assign we_o  = we_q;
  assign adr_o = adr_q;
  assign dat_o = dat_q;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      active_q <= 1'b0;               // RULE 3.20
      we_q     <= 1'b0;
      adr_q    <= '0;
      dat_q    <= '0;
    end else if (!active_q) begin
      if (go_i) begin
        active_q <= 1'b1;
        we_q     <= we_i;
        adr_q    <= adr_i;
        // Latched on every transfer, read or write. RULE 3.60 qualifies
        // DAT_O with STB_O, NOT with STB_O && WE_O — so a master is not
        // required to present anything meaningful here on a read, and a
        // slave must not attach significance to it.
        dat_q    <= wdat_i;
      end
    end else if (ack_i || err_i || rty_i) begin
      active_q <= 1'b0;
    end
  end
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_dat_slave_out — the SLAVE's DAT_O: read data.
//
// PURPOSE. Show the two obligations on a slave's data output: present the
// addressed value when qualified for a read, and drive ZERO otherwise so a
// merged return path is not corrupted.
//
// The second obligation is a DESIGN CONVENTION, not a Wishbone rule — see
// Section 3. It is the safe default for a reusable slave.
// ─────────────────────────────────────────────────────────────────────────
module wb_dat_slave_out #(
  parameter int unsigned OFF_AW = 10,
  parameter int unsigned DW     = 32
) (
  input  logic                clk_i,
  input  logic                rst_i,
  input  logic                cyc_i,
  input  logic                stb_i,
  input  logic                we_i,
  input  logic [OFF_AW-1:0]   adr_i,
  input  logic [DW-1:0]       dat_i,     // SLAVE DAT_I = WRITE data in
  output logic [DW-1:0]       dat_o,     // SLAVE DAT_O = READ data out
  output logic                ack_o
);
  localparam logic [OFF_AW-1:0] W_CTRL   = 'd0;
  localparam logic [OFF_AW-1:0] W_SCRATCH = 'd1;
  localparam logic [OFF_AW-1:0] W_ID     = 'd2;     // read-only constant

  logic [DW-1:0] ctrl_q, scratch_q;

  logic xfer;
  assign xfer = cyc_i & stb_i;                       // RULES 3.30 & 3.35

  assign ack_o = xfer;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      ctrl_q    <= '0;
      scratch_q <= '0;
    end else if (xfer && we_i) begin
      unique case (adr_i)
        W_CTRL:    ctrl_q    <= dat_i;
        W_SCRATCH: scratch_q <= dat_i;
        default:   ;                                 // W_ID is read-only
      endcase
    end
  end

  // ── The read-data output ─────────────────────────────────────────────
  // Three conditions gate it, and each does a distinct job:
  //   xfer   — this slave is the one being addressed   (RULES 3.30, 3.35)
  //   !we_i  — this is a read; a write has no read data
  //   case   — the offset exists
  //
  // The unconditional `dat_o = '0` before the branch is the important line.
  // It is the DEFAULT, so on every path where this slave is not producing
  // data it produces zero — which is what keeps an OR-based return path
  // from being corrupted, and what prevents a latch being inferred.
  always_comb begin
    dat_o = '0;
    if (xfer && !we_i) begin
      unique case (adr_i)
        W_CTRL:    dat_o = ctrl_q;
        W_SCRATCH: dat_o = scratch_q;
        W_ID:      dat_o = DW'(32'h5742_0001);   // "WB", revision 1
        default:   dat_o = '0;
      endcase
    end
  end
endmodule

Reading the pair

Purpose. Two interfaces, both driving a signal called DAT_O, carrying opposite information in opposite directions.

Ports that matter. On the master, dat_o is an output carrying write data and dat_i would be read data returning. On the slave the two are exchanged. Nothing in the names tells you which is which — only the module you are looking at does.

Ownership. The master drives write data; the slave drives read data; neither drives the other's.

Combinational logic. The master has none on the data path — dat_o is a register output. The slave's dat_o is a multiplexer with an unconditional zero default.

Sequential logic. The master latches write data on acceptance of a local request. The slave holds two application registers.

Timing. The master's dat_o is valid for as long as stb_o is asserted and does not move. The slave's dat_o is valid in the cycle ack_o is asserted, which for this always-immediate slave is the same cycle as the request.

Qualification. The master qualifies with stb_o per RULE 3.60. The slave qualifies with cyc_i & stb_i per RULES 3.30 and 3.35, and with !we_i, and with the offset being legal.

Reset. Synchronous, active high. The master's qualifiers are negated; the slave's application registers cleared (an educational choice, per Chapter 4.2).

Simplifications. No byte lanes — Chapter 4.7. No ERR_O or RTY_O. No wait states.

Failure modes.

  • Master drives dat_o from wdat_i directly. Works against an immediate slave, breaks the first time one waits.
  • Slave omits the dat_o = '0 default. A latch is inferred and, on an OR-based return path, every other slave's read is corrupted.
  • Slave omits !we_i. It drives read data during writes — harmless in a gated fabric, corrupting in an OR-based one.
  • Master's DAT_O wired to a slave's DAT_O. Two drivers on one net; the tools catch it. Wired to the master's own DAT_I produces reads returning the last value written — Section 6.

5. Waveform — Two Outputs, Two Windows

DAT_O on each side, in its own transfer

9 cycles
A Wishbone interface over nine clock cycles showing a write followed by a read. In cycles one and two a write is presented: the write enable is high, the master's data output carries the value being written and is stable across both cycles while the slave withholds acknowledge, and the slave's data output stays at zero because this is not a read. In cycle three the slave acknowledges and the write lands. Cycles four is idle. In cycles five and six a read is presented with write enable low, the master's data output still carries the old write value which is meaningless here, and the slave's data output is zero until the termination cycle. In cycle six the slave asserts acknowledge and drives the read value in that same cycle, which is the only cycle it is meaningful.write presented: master DAT_O meaningfulwrite presented: masterDAT_O meaningfulwrite accepted; value landswrite accepted; value landsread presented: master DAT_O now meaninglessread presented: masterDAT_O now meaninglessslave DAT_O valid ONLY hereslave DAT_O valid ONLY hereCLK_ISTB_OWE_Om DAT_O0x00000xCAFE0xCAFE0xCAFE0xCAFE0xCAFE0xCAFE0xCAFE0xCAFEs DAT_O0x00000x00000x00000x00000x00000x00000xCAFE0x00000x0000ACK_It0t1t2t3t4t5t6t7t8
Figure 1 — a write then a read. The master's DAT_O matters in the first; the slave's DAT_O matters in the second.

Two things to read off it.

The master's DAT_O still carries 0xCAFE during the read. It is qualified by STB_O and therefore technically "meaningful", but on a read it means nothing — RULE 3.60 does not condition it on WE_O, and the slave must not attach significance to it. A slave that wrote a register on a read because the data looked valid is a real bug, and Chapter 4.6 is the signal that prevents it.

The slave's DAT_O is zero everywhere except cycle 6. Not because the value is unknown, but because this slave drives zero whenever it is not producing read data — the merged-return-path obligation from Section 3.

6. Failure Modes and Discriminating Evidence

Symptom: every read returns the value most recently written, regardless of address.

Candidate causes. The master's DAT_O wired to its own DAT_I, directly or through a fabric that treated "the data bus" as one net.

Discriminating evidence. Write a distinctive value, then read a different address that should hold something else. If the write value comes back, the read path is looped to the write path and no slave is involved at all. Confirm by checking whether the addressed slave's DAT_O even changed.

Likely RTL location. The fabric's data wiring, not any endpoint.

Symptom: a read returns a value that shares bits with two different registers.

Candidate causes. An unselected slave driving non-zero DAT_O into an OR-based return path.

Discriminating evidence. Compare the returned value against every slave's DAT_O in the termination cycle. A bitwise OR of two of them is conclusive, and recognisable by eye once seen.

Likely RTL location. The offending slave's read mux — usually a missing unconditional zero default.

Property. P3 in Section 7.

Symptom: a slave's register changes during a read.

Candidate causes. The slave's write path is not gated on WE_I, so the master's stale DAT_O lands in a register.

Discriminating evidence. Perform a read of a writable register and check whether it changed. The value it takes will be the previous write's data, which is a distinctive fingerprint.

Likely RTL location. The slave's write branch condition — Chapter 4.6.

Symptom: writes succeed against fast slaves and corrupt against slow ones.

Candidate causes. The master drives dat_o from its client's live input rather than a latched copy.

Discriminating evidence. Trigger on stb_o asserted with no termination and watch dat_o. Any change is a RULE 3.60 violation.

Likely RTL location. The assign dat_o = … line.

Property. P1.

7. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_dat_o_checker — output-side data properties.
//
// P1 and P2 are SPECIFICATION requirements (RULE 3.60).
// P3 is a DESIGN CONVENTION required by an OR-based return path, not a
// Wishbone rule — see Section 3 and the label on the property.
// ─────────────────────────────────────────────────────────────────────────
module wb_dat_o_checker #(
  parameter int unsigned DW = 32
) (
  input logic          clk_i,
  input logic          rst_i,
  // Master side
  input logic          m_stb_o,
  input logic          m_we_o,
  input logic [DW-1:0] m_dat_o,
  input logic          m_ack_i,
  input logic          m_err_i,
  input logic          m_rty_i,
  // Slave side
  input logic          s_cyc_i,
  input logic          s_stb_i,
  input logic [DW-1:0] s_dat_o
);
  default disable iff (rst_i);

  logic terminated;
  assign terminated = m_ack_i | m_err_i | m_rty_i;

  // P1 — SPECIFICATION (RULE 3.60, as stability). On a WRITE, the data must
  //      not move while the transfer is outstanding. Restricted to writes
  //      deliberately: the rule qualifies DAT_O with STB_O, and a master is
  //      free to leave anything on it during a read, so asserting stability
  //      on reads would fail correct designs.
  property p_wdata_stable_while_presented;
    @(posedge clk_i) (m_stb_o && m_we_o && !terminated) |=> $stable(m_dat_o);
  endproperty
  a_wdata_stable : assert property (p_wdata_stable_while_presented)
    else $error("RULE 3.60: master DAT_O moved during an outstanding write");

  // P2 — SPECIFICATION (RULE 3.60, as qualification). Not assertable as a
  //      value constraint — the rule says DAT_O is MEANINGFUL under STB_O,
  //      not that it must be any particular value otherwise. Recorded here
  //      as a note rather than a property, because writing an assertion
  //      that forced DAT_O to zero between transfers would fail every
  //      conforming master.

  // P3 — DESIGN CONVENTION, not a Wishbone rule. Required by a fabric whose
  //      return path is an OR reduction; unnecessary in one that gates each
  //      slave's data. Bound to a slave written for the former.
  property p_slave_quiet_when_unqualified;
    @(posedge clk_i) (!(s_cyc_i && s_stb_i)) |-> (s_dat_o == '0);
  endproperty
  a_slave_quiet : assert property (p_slave_quiet_when_unqualified)
    else $error("convention: slave drove DAT_O = %h while unqualified", s_dat_o);
endmodule

P2 is deliberately not a property, and the comment says why. It is tempting to assert that DAT_O is zero between transfers, and it would fail every conforming master — the rule makes the signal meaningful under the strobe, not zero otherwise. Writing an assertion stronger than the rule is the failure mode Chapter 2.6 warned about, and it is worth leaving a visible note where the temptation is.

Tooling limitation. Icarus has no SVA support; reviewed by inspection only.

8. Common Mistakes

"DAT_O is the data bus."

Wrong mental model: one bidirectional data path with one name.

Concrete bug: the master's write-data output wired to its own read-data input, or a slave's read data driven onto the write-data net.

Observable evidence: reads returning the last value written, independent of address.

Correct model: two unidirectional paths. DAT_O on a master is write data; DAT_O on a slave is read data. Same name, opposite directions, different wires.

"A slave can drive whatever it likes when it is not selected."

Wrong mental model: the fabric ignores unselected slaves.

Concrete bug: on an OR-based return path, an unselected slave's non-zero data ORs into the selected slave's value.

Observable evidence: a read value sharing bits with two different registers.

Correct model: the INTERCON selects but cannot silence. Driving zero when unqualified is a convention the slave must follow because it does not know which kind of fabric it will land in.

"Write data is meaningless on a read, so a slave can use it."

Wrong mental model: whatever is on the master's DAT_O during a read is fair game.

Concrete bug: a slave whose write path is gated only on the transfer and not on WE_I, writing a register during a read with the previous write's data.

Observable evidence: a register that changes when software reads it, taking the value of the last write.

Correct model: RULE 3.60 qualifies DAT_O with STB_O alone, so a master may leave anything there during a read. The slave's obligation is to gate its write path on WE_I.

9. Interview Reasoning

Because it lets a module's port list be written and read without knowing what it will be connected to.

A slave's author declares DAT_O as an output and it is correct in every system the slave is ever instantiated in. If the names were global — "write data" and "read data" — a slave would have an output called write-data-something, which reads backwards, and every module would have to be written with the system in mind.

Where it bites is precisely where it helps. DAT_O on a master is write data; DAT_O on a slave is read data. They are different wires travelling in opposite directions, and an engineer who thinks of "the DAT_O net" connects a master's write data to its own read-data input.

The symptom of that mistake is distinctive: every read returns the last value written, regardless of address, because the read path is looped back to the write path and no slave is involved at all.

The habit that removes the confusion: read the direction aloud rather than the suffix — "data, master output, so write data" — until the translation stops being needed.

10. Understanding Check

11. What's Next

The output side is settled: two unidirectional paths, each an output at one end; the master's write data qualified by the strobe and stable while presented; the slave's read data valid in the termination cycle and zero otherwise.

Every one of those outputs is somebody else's input, and the receiving side has its own rules — in particular, the one that decides when a value may be believed.

When an interface receives DAT_I, what does that data mean, and when is it safe to use?

Chapter 4.5 — DAT_I 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.