Skip to content
VLSI Mentor

Wishbone · Module 3

Data Flow

One Wishbone access, followed through every block in both directions: what the master drives, where the address changes form, which signals are broadcast and which are decoded, and how read data and termination find their way back to exactly one requester.

Three modules now exist: a master that owns its request, a slave that answers and refuses to know, and an INTERCON that holds the map. This chapter wires them together and follows single accesses through the result.

For one Wishbone transfer, exactly what information moves, in which direction, through which block — and where does it change form?

1. The Complete System

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_soc — the Module 3 system, assembled from the modules built in
// Chapters 3.3, 3.4 and 3.5.
//
// PURPOSE. Show the wiring, which is where the data-flow story actually
// lives. Nothing new is implemented here — this module is composition.
//
//   wb_copy_master  (3.3)  →  wb_intercon  (3.5)  →  three wb_gpio_slave (3.4)
//
// The three slaves are instances of the SAME design at three different
// bases. None of them knows its base; the INTERCON's map parameter does.
// That is the reuse property of Chapters 3.4 and 3.5 in one line of code.
//
// Reset is SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_soc #(
  parameter int unsigned AW = 32,
  parameter int unsigned DW = 32,
  parameter int unsigned NS = 3
) (
  input  logic          clk_i,
  input  logic          rst_i,

  // Local control of the copy engine
  input  logic          start_i,
  input  logic [AW-1:0] src_i,
  input  logic [AW-1:0] dst_i,
  input  logic [15:0]   count_i,
  output logic          busy_o,
  output logic          done_o,
  output logic          error_o,

  // Pins of the three peripheral instances
  output logic [7:0]    p0_out, p1_out, p2_out,
  output logic [7:0]    p0_oe,  p1_oe,  p2_oe,
  input  logic [7:0]    p0_in,  p1_in,  p2_in
);
  // ── Master ↔ INTERCON nets ───────────────────────────────────────────
  logic            m_cyc, m_stb, m_we, m_ack, m_err, m_rty;
  logic [AW-1:0]   m_adr;
  logic [DW/8-1:0] m_sel;
  logic [DW-1:0]   m_dat_w;     // master → slave
  logic [DW-1:0]   m_dat_r;     // slave → master

  // ── INTERCON ↔ slave nets. Note what is SHARED and what is PER-SLAVE:
  //    one address, one write-data bus, one cycle signal, one direction and
  //    one byte-select bus are broadcast to all three. Only the strobe and
  //    the response signals are per-slave.
  logic            s_cyc, s_we;
  logic [NS-1:0]   s_stb;
  logic [AW-1:0]   s_adr;       // LOCAL offset, already masked
  logic [DW/8-1:0] s_sel;
  logic [DW-1:0]   s_dat_w;
  logic [NS*DW-1:0] s_dat_r_flat;
  logic [NS-1:0]   s_ack, s_err, s_rty;

  wb_copy_master #(.AW(AW), .DW(DW), .CW(16)) u_master (
    .clk_i(clk_i), .rst_i(rst_i),
    .start_i(start_i), .src_i(src_i), .dst_i(dst_i), .count_i(count_i),
    .busy_o(busy_o), .done_o(done_o), .error_o(error_o),
    .cyc_o(m_cyc), .stb_o(m_stb), .we_o(m_we), .adr_o(m_adr),
    .sel_o(m_sel), .dat_o(m_dat_w), .dat_i(m_dat_r),
    .ack_i(m_ack), .err_i(m_err), .rty_i(m_rty));

  wb_intercon #(.AW(AW), .DW(DW), .NS(NS)) u_intercon (
    .clk_i(clk_i), .rst_i(rst_i),
    // Master side
    .m_cyc_i(m_cyc), .m_stb_i(m_stb), .m_we_i(m_we), .m_adr_i(m_adr),
    .m_sel_i(m_sel), .m_dat_i(m_dat_w), .m_dat_o(m_dat_r),
    .m_ack_o(m_ack), .m_err_o(m_err), .m_rty_o(m_rty),
    // Slave side
    .s_cyc_o(s_cyc), .s_stb_o(s_stb), .s_we_o(s_we), .s_adr_o(s_adr),
    .s_sel_o(s_sel), .s_dat_o(s_dat_w), .s_dat_i_flat(s_dat_r_flat),
    .s_ack_i(s_ack), .s_err_i(s_err), .s_rty_i(s_rty));

  // ── Three instances of ONE slave design, at three bases the slaves do
  //    not know. Every port below except the strobe and the responses is
  //    the same net on all three instances.
  wb_gpio_slave #(.AW(AW), .DW(DW), .PINS(8)) u_gpio0 (
    .clk_i(clk_i), .rst_i(rst_i),
    .cyc_i(s_cyc), .stb_i(s_stb[0]), .we_i(s_we), .adr_i(s_adr),
    .sel_i(s_sel), .dat_i(s_dat_w), .dat_o(s_dat_r_flat[0*DW +: DW]),
    .ack_o(s_ack[0]), .err_o(s_err[0]), .rty_o(s_rty[0]),
    .pins_out(p0_out), .pins_oe(p0_oe), .pins_in(p0_in));

  wb_gpio_slave #(.AW(AW), .DW(DW), .PINS(8)) u_gpio1 (
    .clk_i(clk_i), .rst_i(rst_i),
    .cyc_i(s_cyc), .stb_i(s_stb[1]), .we_i(s_we), .adr_i(s_adr),
    .sel_i(s_sel), .dat_i(s_dat_w), .dat_o(s_dat_r_flat[1*DW +: DW]),
    .ack_o(s_ack[1]), .err_o(s_err[1]), .rty_o(s_rty[1]),
    .pins_out(p1_out), .pins_oe(p1_oe), .pins_in(p1_in));

  wb_gpio_slave #(.AW(AW), .DW(DW), .PINS(8)) u_gpio2 (
    .clk_i(clk_i), .rst_i(rst_i),
    .cyc_i(s_cyc), .stb_i(s_stb[2]), .we_i(s_we), .adr_i(s_adr),
    .sel_i(s_sel), .dat_i(s_dat_w), .dat_o(s_dat_r_flat[2*DW +: DW]),
    .ack_o(s_ack[2]), .err_o(s_err[2]), .rty_o(s_rty[2]),
    .pins_out(p2_out), .pins_oe(p2_oe), .pins_in(p2_in));
endmodule

The line worth pausing on is the instantiation. Three instances of one design, differing only in which strobe bit they receive and which pins they drive. Not one of them contains an address constant, and moving any of them is a change to the INTERCON's BASE_FLAT parameter alone.

That is the whole architecture paying off, and it is only possible because Chapter 3.4's slave refused to know its base and Chapter 3.5's INTERCON accepted the map.

2. The Two Paths

One Wishbone access travels two paths through the same three blocks. Outbound, the master drives a system address, write data, direction and byte selects into the interconnect. The interconnect decodes the address against the map, masks away the upper bits to produce a local offset, broadcasts the offset and the other request signals to all three slaves, and asserts a strobe to exactly one of them. Inbound, the selected slave drives read data and one termination; the interconnect multiplexes those from three sources down to one and returns them to the master, which captures read data in the termination cycle. The address is the only thing that changes form, and it changes inside the interconnect.MASTERdrives system addressOUT: decode + maskaddress changes formhereOUT: broadcastall but the strobeOUT: one strobethe selectionSLAVE, local offsetacts, then terminatesIN: multiplexthree sources, onemasterIN: capturein the termination cycle12
Figure 1 — outbound the request fans out and the address changes form; inbound the response fans in and nothing changes form.

One thing changes form, and it changes in one place. A system address enters the INTERCON; a local offset leaves it. Nothing else is transformed — write data, direction and byte selects pass through untouched, and read data and terminations come back untouched.

That single transformation is where most integration bugs live, because it is the only point where two halves of the system hold different ideas about what an address means. Section 5's debugging order is built around it.

3. Case A — the Master Writes a GPIO Output Register

Base 0x4000_1000 is u_gpio1; offset 0x04 is OUT. The master writes 0x0000_00FF to 0x4000_1004.

A write access traced through four participants. The copy engine's local client asks the master to write. The master latches the request and drives a system address of 0x40001004, write data, direction and byte selects, and asserts both the cycle and strobe qualifiers. The interconnect decodes the address, finds it inside the second region, masks the address down to local offset 0x004, broadcasts the request to all three slaves and asserts a strobe to slave one only. Slave one sees its cycle and strobe inputs both asserted, decodes offset 0x004 as its output register, writes lane zero, and asserts acknowledge. The interconnect multiplexes that acknowledge back to the master. The master observes the acknowledge, closes the cycle and reports completion to its client.Write to GPIO1 OUT at 0x4000_1004ClientMASTERINTERCONSLAVE 1write 0xFF to0x4000_1004ADR=0x4000_1004,DAT, WE=1, SELCYC=1, STB=1broadcast: CYC, DAT,WE, SELSTB[1]=1, ADR=0x004(masked)ACK_O — lane 0writtenACK_Idone
Figure 2 — one write, traced through every block. Read downward; each message is one thing moving.

Step by step, with the block that owns each step:

#What happensOwnerEstablished in
1Request latched; Wishbone outputs driven from registersMASTER3.3
2CYC_O and STB_O asserted; request held until terminationMASTERRULE 3.60
30x40001 matches region 1 → hit[1]INTERCON3.5
4s_adr_o masked to 0x004INTERCONthe form change
5CYC, DAT, WE, SEL broadcast to all threeINTERCON3.5 §2
6s_stb_o[1] asserted; [0] and [2] lowINTERCONthe selection
7cyc_i & stb_i true → xfer; offset 0x04 = OUT; sel_i[0] set → out_q writtenSLAVE 1RULE 3.35
8ack_o asserted; err_o lowSLAVE 1RULE 3.45
9Reduction selects slave 1's ACKm_ack_oINTERCON2.3
10ACK_I observed → cycle closed, done_o pulsesMASTER3.3

Two observations worth extracting.

Slaves 0 and 2 saw everything except a strobe. They received the address, the write data, the direction and CYC_I — and did nothing, because cyc_i & stb_i was false for them. That is what makes broadcasting safe.

The write data was never decoded, masked or multiplexed. It went out untouched and was consumed by exactly one slave. Only the address changed, and only in the INTERCON.

4. Case B — the Master Reads a Status Register

Same system; the master reads 0x4000_2008, which is u_gpio2's read-only IN register.

Steps 1 through 6 are identical in shape — decode selects region 2, the offset becomes 0x008, s_stb_o[2] is asserted. The return path is where this case differs, and it is where the work is.

#What happensOwner
7xfer true; we_i low; offset 0x08 = IN; dat_o driven with in_sync_q, zero-extendedSLAVE 2
8Slaves 0 and 1 drive dat_o = '0, because xfer is false for themSLAVES 0, 1
9ack_o asserted by slave 2 onlySLAVE 2
10AND-OR reduction: m_dat_o = (0 | 0 | slave2_data)INTERCON
11ACK_I and DAT_I presented to the master in the same cycleINTERCON
12hold_q <= dat_i on the ACK_I edge — and nowhere elseMASTER

Step 8 is the one that is easy to skip and expensive to get wrong. The reduction is an OR. If slave 0 or 1 drove anything non-zero while unselected, it would be ORed into slave 2's value and the master would receive a number belonging to neither. Nothing would report an error.

The INTERCON cannot prevent this — it can select, but it cannot silence a slave that insists on driving. That is exactly why Chapter 3.4's property P3 is bound at the slave: the obligation sits where the capability sits.

Step 12 is the master's half of the same discipline. Read data is meaningful in the termination cycle. A capture one cycle later collects whatever the reduction produced next — which, once the master has dropped its strobe, is zero.

5. Debugging — Walk the Path in Order

An access that misbehaves can fail at any of six points. Walking them in a fixed order turns a search into four observations.

Step 1 — did the master present a legal request? Probe m_cyc_i, m_stb_i, m_adr_i. If the address is wrong, the fault is upstream of Wishbone entirely — in whatever computed it. If the address changes while the strobe is asserted and nothing has terminated, it is a master stability violation (Chapter 3.3, P2) and the peripheral is blameless.

Step 2 — did the decode select the right slave? Probe s_stb_o. This single vector separates four causes. All zero on a mapped address means the map constants are wrong. Two bits set means overlapping regions. One wrong bit means a wrong base. All bits set means a broadcast strobe rather than a decoded one.

Step 3 — did the address change form correctly? Compare s_adr_o with m_adr_i. Equal means the mask is missing and every register will appear shifted by the base. Masked by the wrong region's size means the offset loop and the hit index disagree.

Step 4 — did the slave act? Probe the slave's cyc_i, stb_i and its internal state. Both qualifiers asserted with no state change means the slave's own decode rejected the offset — check err_o, which is the slave telling you so.

Step 5 — did the slave terminate, and only the right one? Probe all three slaves' ack_o/err_o. A termination from an unstrobed slave is a RULE 3.35 violation in that slave — it is ignoring CYC_I, or terminating on something else entirely.

Step 6 — did the response reach the master intact? Compare the master's DAT_I against the selected slave's DAT_O in the termination cycle. Differing, with the value looking like two registers ORed together, means an unselected slave is driving.

6. Where the Critical Path Runs

The composition in Section 1 has one long combinational cone, and knowing its shape is more useful than knowing its length.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
master address register
   → INTERCON comparators        (parallel, cheap, flat with slave count)
   → strobe + offset mask
   → slave's internal decode and read mux
   → slave's DAT_O and termination
   → INTERCON response reduction (grows with slave count, in steps)
   → master's capture register

What grows and what does not. The comparators are parallel: adding a slave adds one, and nothing gets deeper. The response reduction takes one more input per slave, on every bit of the data width — the fan-in asymmetry from Chapter 2.3.

Two honest limits on what can be claimed here.

The specification says nothing about timing closure. How many slaves a flat INTERCON supports before this path becomes the critical one depends on the device, the clock target, the data width and the synthesiser. Anyone quoting a number without a synthesis report for the part in question is guessing.

Not every Wishbone implementation has this structure. A slave may register its termination and read data rather than producing them combinationally, which shortens this cone at the cost of a cycle. Chapter 3.4's slave chose the combinational form because it is never busy, and a design that needs the timing can register instead without changing any interface. A sentence in the specification is often quoted against this — the CLK_I signal description says all Wishbone output signals "are registered at the rising edge of CLK_I". It is descriptive text rather than a numbered rule, and the numbered requirements it is sometimes confused with (RULES 5.00 and 5.05) ask for synchronous methodology under one clock, which a combinational termination satisfies. Chapter 4.1 works through the distinction.

What is safe to say: the response path is the structure that grows, and both standard fixes — registering the response, or going hierarchical — cost a cycle and are affordable only because Wishbone signals termination rather than fixing a latency.

7. Common Mistakes

"The interconnect transforms the data."

Wrong mental model: everything passing through the fabric is processed.

Concrete bug: byte-lane rearrangement or width adaptation added inside the INTERCON "while we are here", which then applies to every slave whether or not it wanted it.

Observable evidence: a peripheral that works standalone and returns byte-swapped values in the system.

Correct model: exactly one thing changes form — the address, masked to a local offset. Write data, direction, byte selects, read data and terminations pass through untouched.

"An unselected slave's read data does not matter."

Wrong mental model: the multiplexer ignores it.

Concrete bug: on an AND-OR reduction, a slave driving non-zero DAT_O while unstrobed ORs into the selected slave's value.

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

Correct model: the INTERCON selects but cannot silence. Driving '0 when unqualified is the slave's obligation, which is why the property is bound there.

"If the slave has the right data, the read will work."

Wrong mental model: correctness of the value is sufficient.

Concrete bug: the master captures DAT_I a cycle after the termination, by which time the reduction is producing zero.

Observable evidence: every read returns zero, or the previous access's value — a clean off-by-one that looks like a software bug.

Correct model: read data is meaningful in the termination cycle. The value and the moment are both part of the contract.

"Trace the failing access from the slave backwards."

Wrong mental model: the wrong value came out of the slave, so start there.

Concrete bug: hours spent in a peripheral's register logic when the decode selected the wrong slave in the first place.

Observable evidence: a peripheral that reads correctly in its own testbench.

Correct model: walk forward. Request before response, because a wrong response to a wrong request tells you nothing. s_stb_o is the single highest-information probe in the system.

8. Interview Reasoning

At the master: the request is latched and the Wishbone outputs driven from registers rather than from the client's live signals, so stability is structural. CYC_O and STB_O are asserted and everything is held until a termination arrives.

At the INTERCON, four things happen. The address is compared against the region table. The upper bits are masked away, so what leaves is a local offset — the only thing in the whole access that changes form. The cycle signal, write data, direction and byte selects are broadcast to every slave. And exactly one strobe is asserted.

At the selected slave: CYC_I and STB_I are both true, so this is a transfer for it. It decodes the local offset, honours the byte selects, writes the register, and asserts exactly one termination.

On the way back: the INTERCON multiplexes that slave's termination down to the master's single response port. The master observes it, closes the cycle, and reports completion.

The detail that shows real understanding: the unselected slaves saw the address, the write data and CYC_I, and did nothing — because CYC_I & STB_I was false for them. That is what makes broadcasting safe, and it is why only the strobe needs decoding.

9. Understanding Check

10. What's Next

Data flow is now traceable in both directions: the request fans out with one transformation, the response fans in with none, and six ordered probes localise any fault to one block.

What the traces have described is where things go. They have not described the transfer as a thing with a beginning, a duration and an end — which is what a master's state machine actually reasons about, and what an arbiter in a larger system would observe.

What is the high-level lifetime of one Wishbone transaction, from a master's decision to act through the slave's termination and back to the caller — and what may vary along the way without breaking anything?

Chapter 3.7 — Transaction Lifecycle closes Module 3 and runs the whole system in simulation. 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.