Skip to content
VLSI Mentor

Wishbone · Module 3

The Interconnect

Two conforming Wishbone interfaces still cannot talk without something between them. The INTERCON holds the address map, distributes exactly one strobe, merges read data and terminations, and answers for addresses nobody owns — and the specification defines it by its job rather than by a signal set.

Chapter 3.3 and Chapter 3.4 built two endpoints that each refuse to know things. The master does not know which slave an address reaches; the slave does not know its own base address. Those refusals are what make both reusable, and they leave a gap that something must fill.

If masters and slaves implement compatible Wishbone interfaces, what still has to happen between them?

1. Endpoint Protocol Versus Interconnect Policy

This distinction is the strategic point of the chapter, and it is worth stating before any RTL.

Endpoint protocolInterconnect policy
Fixed bythe specificationthe integrator
Coverssignals, directions, qualification, termination, resetmap, decode, topology, arbitration, unmapped behaviour
Same across systems?yesno
Where a conformance bug livesin a master or a slave
Where an integration bug liveshere

Read the last two rows. A conforming master and a conforming slave can be assembled into a system that does not work, and when that happens the fault is almost always policy rather than protocol. Chapter 2.2's overlapping regions, Chapter 2.6's ownership corruption and Chapter 1.2's undefined unmapped behaviour are all policy failures — and none of them is detectable by checking either endpoint against the specification.

The specification is explicit about the boundary. It names point-to-point, shared bus, crossbar switch and data flow as interconnection arrangements rather than mandating one, and it states that arbitration methodology is the end user's choice, naming priority and round-robin as examples.

A Wishbone INTERCON performs four jobs between one master and several slaves. First it decodes the master's address against the system address map, which lives here because neither endpoint may hold it. Second it distributes exactly one strobe, so that exactly one slave sees a qualified transfer; the cycle signal and the remaining request signals are broadcast unchanged. Third it merges the selected slave's read data and termination back toward the master, because the master has a single response port and there are several slaves. Fourth it provides a default slave that answers addresses no real slave owns, so an unmapped access terminates with an error rather than hanging the master forever.MASTERdrives an address1. Decodethe map lives here2. Distribute STBexactly one slave3. Merge responseDAT_O, ACK/ERR/RTY4. Default slaveunmapped terminatesSLAVE — GPIOlocal offset onlySLAVE — UARTlocal offset onlySLAVE — Timerlocal offset onlyAll four are POLICYnot fixed by the spec12
Figure 1 — the INTERCON's four jobs, each a consequence of something an endpoint refuses to know.

2. Which Signals Are Decoded, and Which Are Broadcast

A detail that surprises people: the INTERCON does not need to gate most of the request.

SignalTreatmentWhy
ADR_Obroadcast, optionally truncatedSlaves see a local offset; the upper bits are the decoder's
DAT_O (write data)broadcastHarmless — a slave that is not strobed ignores it
WE_O, SEL_ObroadcastSame reason
CYC_ObroadcastEvery slave in the cycle sees it; RULE 3.35 needs it alongside STB_I
STB_Odecoded, per slaveThis is the selection
DAT_I (read data)multiplexedMany sources, one destination
ACK_I, ERR_I, RTY_ImultiplexedSame

The strobe is the selection. Everything else on the request path can be broadcast because Chapter 3.4's slave ignores it all unless CYC_I & STB_I is true for it. That is Chapter 2.3's fan-out/fan-in asymmetry in Wishbone terms: broadcasting costs wiring, and merging costs a multiplexer that grows with every slave.

CYC_O is broadcast rather than decoded, and that is deliberate. All slaves in a shared arrangement see the same cycle signal; what distinguishes them is which one gets a strobe. A design that decoded CYC_O per slave would work, and would also make RULE 3.35's CYC_I & STB_I test redundant at the slave — which is a bad trade, because the slave-side test is what protects the system from a broadcast-strobe bug in the INTERCON.

3. RTL — A Wishbone INTERCON

One master, three slaves and a default, built from the decode structure Chapter 2.2 established.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_intercon — a Wishbone Classic INTERCON: one MASTER, three SLAVEs,
// plus a built-in default slave for unmapped addresses.
//
// PURPOSE. Do the four jobs of Section 1 and nothing else. The map is a
// parameter, so the same module serves any system — which is the property
// that makes decode belong HERE rather than inside a peripheral.
//
// The region table is carried as a FLAT PACKED VECTOR rather than an
// unpacked array parameter: array parameters are legal SystemVerilog and
// unevenly supported across tools, and production IP that must build
// everywhere commonly slices a flat vector instead.
//
// SCOPE. Single master, so no arbitration — Chapter 2.6 covered the
// concept and Module 17 owns the implementation. Combinational decode and
// response merge; Section 6 discusses when that stops being the right
// choice.
//
// Reset is SYNCHRONOUS, ACTIVE HIGH throughout Module 3 (RULES 2.30, 3.00).
// This module holds no state, so rst_i reaches it only for the default
// slave's termination register.
// ─────────────────────────────────────────────────────────────────────────
module wb_intercon #(
  parameter int unsigned AW = 32,
  parameter int unsigned DW = 32,
  parameter int unsigned NS = 3,              // real slaves
  // Region bases, index 0 first: 0 = GPIO, 1 = UART, 2 = Timer.
  parameter logic [NS*32-1:0] BASE_FLAT =
      { 32'h4000_2000, 32'h4000_1000, 32'h4000_0000 },
  // Region sizes in bytes, same index order. Power-of-two and naturally
  // aligned, so membership is an equality test rather than two magnitude
  // comparisons — Chapter 2.2 Section 2.
  parameter logic [NS*32-1:0] SIZE_FLAT =
      { 32'h0000_1000, 32'h0000_1000, 32'h0000_1000 }
) (
  input  logic                clk_i,
  input  logic                rst_i,

  // ── MASTER side (this module is the slave-facing end of the master) ──
  input  logic                m_cyc_i,
  input  logic                m_stb_i,
  input  logic                m_we_i,
  input  logic [AW-1:0]       m_adr_i,
  input  logic [DW/8-1:0]     m_sel_i,
  input  logic [DW-1:0]       m_dat_i,       // master → slave data
  output logic [DW-1:0]       m_dat_o,       // slave → master data
  output logic                m_ack_o,
  output logic                m_err_o,
  output logic                m_rty_o,

  // ── SLAVE side, flattened ────────────────────────────────────────────
  output logic                s_cyc_o,       // broadcast
  output logic [NS-1:0]       s_stb_o,       // DECODED — one per slave
  output logic                s_we_o,
  output logic [AW-1:0]       s_adr_o,       // local offset
  output logic [DW/8-1:0]     s_sel_o,
  output logic [DW-1:0]       s_dat_o,       // broadcast write data
  input  logic [NS*DW-1:0]    s_dat_i_flat,  // each slave's read data
  input  logic [NS-1:0]       s_ack_i,
  input  logic [NS-1:0]       s_err_i,
  input  logic [NS-1:0]       s_rty_i
);
  function automatic logic [31:0] base_of(input int unsigned i);
    return BASE_FLAT[i*32 +: 32];
  endfunction
  function automatic logic [31:0] size_of(input int unsigned i);
    return SIZE_FLAT[i*32 +: 32];
  endfunction
  function automatic logic [DW-1:0] rdata_of(input int unsigned i);
    return s_dat_i_flat[i*DW +: DW];
  endfunction

  // ── Elaboration-time map checks. A map error becomes a build failure
  //    rather than a lab week. These are the ONLY place the map's
  //    correctness can be established exhaustively.
  initial begin
    for (int unsigned i = 0; i < NS; i++) begin
      if (size_of(i) != (32'd1 << $clog2(size_of(i))))
        $fatal(1, "wb_intercon: region %0d size %0h is not a power of two",
               i, size_of(i));
      if ((base_of(i) & (size_of(i) - 32'd1)) != 32'd0)
        $fatal(1, "wb_intercon: region %0d base %0h is not naturally aligned",
               i, base_of(i));
      for (int unsigned j = i + 1; j < NS; j++)
        if ((base_of(i) < base_of(j) + size_of(j)) &&
            (base_of(j) < base_of(i) + size_of(i)))
          $fatal(1, "wb_intercon: regions %0d and %0d overlap", i, j);
    end
  end

  // ── JOB 1: DECODE. One equality comparison per region, all parallel.
  logic [NS-1:0] hit;
  always_comb begin
    for (int unsigned i = 0; i < NS; i++)
      hit[i] = ((m_adr_i & ~(size_of(i) - 32'd1)) == base_of(i));
  end

  logic unmapped;
  assign unmapped = ~(|hit);

  // ── JOB 2: DISTRIBUTE. Only the STROBE is decoded; everything else on
  //    the request path is broadcast, because a slave ignores it all
  //    unless CYC_I & STB_I is true for that slave (RULE 3.35).
  //
  //    Gating by m_stb_i as well as by hit is what keeps a slave from
  //    being strobed on a cycle where the master is presenting nothing.
  assign s_cyc_o = m_cyc_i;
  assign s_we_o  = m_we_i;
  assign s_sel_o = m_sel_i;
  assign s_dat_o = m_dat_i;
  always_comb begin
    for (int unsigned i = 0; i < NS; i++)
      s_stb_o[i] = m_stb_i & hit[i];
  end

  // ── Local offset: keep only the bits below the hit region's size. The
  //    loop is priority-free-safe because at most one hit[i] can be set,
  //    which the elaboration overlap check guarantees.
  always_comb begin
    s_adr_o = m_adr_i;                        // unmapped passes through
    for (int unsigned i = 0; i < NS; i++)
      if (hit[i]) s_adr_o = m_adr_i & (size_of(i) - 32'd1);
  end

  // ── JOB 4: DEFAULT SLAVE. An unmapped, qualified transfer must END.
  //    Without this the master waits forever on a stray pointer — the
  //    hang Chapter 1.2 warned about, now given a concrete answer.
  //
  //    Registered so that err_o is not a combinational function of the
  //    master's own qualifiers, which would otherwise create a path from
  //    m_cyc_i/m_stb_i straight back to m_err_o.
  logic dflt_err_q;
  always_ff @(posedge clk_i) begin
    if (rst_i) dflt_err_q <= 1'b0;
    // One cycle of ERR_O per unmapped transfer: assert only when the
    // transfer is qualified and not already being terminated.
    else       dflt_err_q <= m_cyc_i & m_stb_i & unmapped & ~dflt_err_q;
  end

  // ── JOB 3: MERGE. AND-OR reduction over the hit vector. Correct ONLY
  //    because at most one hit[i] is set — a property the elaboration
  //    check guarantees and assertion P1 re-checks over all addresses.
  //    Stating the dependence where it is relied on is deliberate.
  always_comb begin
    m_dat_o = '0;
    m_ack_o = 1'b0;
    m_err_o = dflt_err_q;                     // the default slave's answer
    m_rty_o = 1'b0;
    for (int unsigned i = 0; i < NS; i++) begin
      m_dat_o |= {DW{hit[i]}} & rdata_of(i);
      m_ack_o |= hit[i] & s_ack_i[i];
      m_err_o |= hit[i] & s_err_i[i];
      m_rty_o |= hit[i] & s_rty_i[i];
    end
  end
endmodule

Reading this module

Purpose. Turn one master port into three slave ports plus a defined answer for everything else.

Interface contract. On the master side, this module presents the slave-facing half of a Wishbone connection. On the slave side, it drives one strobe per slave and broadcasts the rest.

Combinational behaviour, in the order the jobs happen. Three equality comparisons produce hit. unmapped is the NOR. Each slave's strobe is m_stb_i & hit[i]. The offset is masked by the hit region's size. The response reduction selects one slave's data and termination.

Sequential behaviour. Exactly one register: dflt_err_q. Everything else is combinational, and the one piece of state exists for a reason given in the comment — a combinational m_err_o derived from m_cyc_i and m_stb_i would put a path from the master's own outputs straight back into its inputs, which invites a loop if the master ever makes its qualifiers depend on a termination.

Why the default slave asserts for exactly one cycle. ~dflt_err_q in its own next-state expression makes it a one-shot: it rises the cycle after an unmapped qualified transfer and falls immediately, which gives the master a single termination rather than a stuck one.

Assumptions and simplifications. Single master, so no arbitration. NS fixed by the flat-vector parameters. No protection or security checks. Combinational decode and merge. The default slave errors rather than returning zeros, which is a policy choice — returning zeros is also defensible and some systems prefer it.

How it could fail.

  • Broadcast STB_O instead of decoding it. Every slave terminates every transfer; wb_gpio_slave's cyc_i & stb_i test does not save it, because both would be asserted.
  • Omit the m_stb_i term from s_stb_o[i]. A slave is strobed on cycles where the master is presenting nothing.
  • Omit the default slave. An unmapped access hangs the master forever with no diagnostic.
  • Omit the elaboration overlap check. Two hit bits can be set, the AND-OR reduction merges two slaves' data, and the master sees two terminations at once — the fault Chapter 3.3's P4 exists to catch.
  • Forget to mask s_adr_o. Slaves receive the full system address and every register appears shifted.

Scaling. The comparisons are parallel and cheap. The response reduction is what grows: one more input per slave, on every bit of DW, on the critical path of every transfer. Section 6.

4. Verification — Interconnect Invariants

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_intercon_checker — properties of the INTERCON's four jobs.
//
// These are ARCHITECTURAL properties of this interconnect's policy, not
// Wishbone conformance rules — with one exception, noted at P3. Module 26
// owns Wishbone verification.
// ─────────────────────────────────────────────────────────────────────────
module wb_intercon_checker #(
  parameter int unsigned NS = 3,
  parameter int unsigned DW = 32
) (
  input logic          clk_i,
  input logic          rst_i,
  input logic          m_cyc_i,
  input logic          m_stb_i,
  input logic [NS-1:0] s_stb_o,
  input logic [NS-1:0] s_ack_i,
  input logic          m_ack_o,
  input logic          m_err_o,
  input logic          m_rty_o,
  input logic [DW-1:0] m_dat_o
);
  default disable iff (rst_i);

  // P1 — at most one slave is strobed. $onehot0 rather than $onehot,
  //      because zero strobes is LEGAL here: an unmapped transfer strobes
  //      nobody and is answered by the default slave instead. This is the
  //      deliberate difference from Chapter 2.2's decoder, where the
  //      default target was inside the select vector.
  property p_stb_onehot0;
    @(posedge clk_i) $onehot0(s_stb_o);
  endproperty
  a_stb_onehot0 : assert property (p_stb_onehot0)
    else $error("s_stb_o=%b — two slaves strobed for one transfer", s_stb_o);

  // P2 — no slave is strobed unless the master is presenting a transfer.
  //      Catches a strobe derived from `hit` alone.
  property p_stb_requires_master;
    @(posedge clk_i) (|s_stb_o) |-> (m_cyc_i && m_stb_i);
  endproperty
  a_stb_requires_master : assert property (p_stb_requires_master)
    else $error("a slave was strobed with no qualified master transfer");

  // P3 — the master must never observe more than one termination. RULE
  //      3.45 constrains a SLAVE; this catches the INTERCON merging two,
  //      which no slave-side assertion can see.
  property p_one_termination;
    @(posedge clk_i) $onehot0({m_ack_o, m_err_o, m_rty_o});
  endproperty
  a_one_termination : assert property (p_one_termination)
    else $error("merged terminations: ack=%b err=%b rty=%b",
                m_ack_o, m_err_o, m_rty_o);

  // P4 — an unmapped, qualified transfer is eventually terminated. Stated
  //      with a bound because liveness is not checkable without one; two
  //      cycles is this design's registered default-slave latency.
  property p_unmapped_terminates;
    @(posedge clk_i) (m_cyc_i && m_stb_i && (s_stb_o == '0))
      |-> ##[1:2] (m_ack_o || m_err_o || m_rty_o);
  endproperty
  a_unmapped_terminates : assert property (p_unmapped_terminates)
    else $error("an unmapped transfer was not terminated — the master will hang");

  // P5 — a termination reaching the master corresponds to a strobed slave,
  //      or to the default slave. Catches a response merged from a slave
  //      that was not selected.
  property p_ack_from_selected;
    @(posedge clk_i) m_ack_o |-> ((s_stb_o & s_ack_i) != '0);
  endproperty
  a_ack_from_selected : assert property (p_ack_from_selected)
    else $error("ACK reached the master from a slave that was not strobed");
endmodule

Why P1 is $onehot0 here and $onehot in Chapter 2.2. The difference is where the default lives. Module 2's decoder put the default target inside the select vector, so exactly one bit was always set and $onehot was provable. This INTERCON keeps the default slave internal and out of s_stb_o, so an unmapped transfer legitimately strobes nobody. The property you can write is a diagnostic about the structure, and P4 is what covers the gap $onehot0 leaves.

Why P4 carries a bound. Eventually terminates is a liveness property and no finite trace can refute it. Bounding it — here, within two cycles — turns it into a safety property that a simulator can check, and choosing the bound forces you to state the default slave's latency explicitly.

Tooling limitation. Icarus Verilog has no SVA support, so this checker, like every checker in Module 3, was reviewed by inspection only. No tool available here has executed it. The synthesisable RTL is elaborated and, in Chapter 3.7, simulated.

5. Failure Modes and Discriminating Evidence

Symptom: a write to one peripheral also changes another.

Candidate causes. Overlapping regions in the map; a strobe broadcast rather than decoded; a slave terminating on STB_I alone.

Discriminating evidence. Probe every slave's STB_I on the failing transfer. Two asserted is decode — and the elaboration check should have caught it, so the map constants and the comparison expression disagree. All asserted is a broadcast strobe. Exactly one asserted, with another slave still changing state, is that slave ignoring its strobe.

Likely RTL location. In order: the s_stb_o[i] expression, then the region constants, then the slave.

Property that catches it. P1 for the decode; Chapter 3.4's P1 for the slave.

Symptom: the master hangs on one specific address.

Candidate causes. Unmapped with no default slave; a default slave that never terminates; or a selected slave that does not answer.

Discriminating evidence. Probe s_stb_o and the master's three termination inputs. s_stb_o all zero with no termination means the default slave is missing or broken — the address is unmapped and nothing is answering for it. A strobe asserted with no termination localises to that slave.

Property that catches it. P4.

Symptom: reads return a value that looks like two registers merged.

Candidate causes. Two hit bits set, so the AND-OR reduction ORs two slaves' data. Or an unselected slave driving non-zero DAT_O.

Discriminating evidence. Compare the master's DAT_I against each slave's DAT_O in the termination cycle. A bitwise OR of two is conclusive; then s_stb_o tells you whether the fault is decode or a noisy slave.

Property that catches it. P1 at the INTERCON; Chapter 3.4's P3 at the slave.

Symptom: every peripheral's registers appear shifted by a constant.

Candidate causes. s_adr_o not masked, so slaves receive the full system address.

Discriminating evidence. Compare s_adr_o against m_adr_i on a known access. Equal means the truncation is missing entirely.

Likely RTL location. The offset loop.

Symptom: a transfer to a valid address is answered with an error.

Candidate causes. The default slave's one-shot is not correctly gated — for instance, unmapped computed before the map was correct, or the ~dflt_err_q term dropped so it free-runs.

Discriminating evidence. Check unmapped and s_stb_o in the same cycle. unmapped high with a strobe asserted is a contradiction and points at the decode; unmapped low with dflt_err_q high points at the one-shot.

6. Where Combinational Merging Stops Being Right

The INTERCON above is entirely combinational except for one register. That is correct at three slaves and becomes a decision at more.

The path. Master address register → comparators → strobe → slave's internal logic → slave's DAT_O and termination → response reduction → master's capture register. All of it in one cycle.

What grows. The comparators are parallel and cheap. The response reduction takes one more input per slave, on every bit of the data width, and on an FPGA it grows in steps — flat until the device's LUT input count is exceeded, then a whole extra logic level across the full width at once. Chapter 2.3 has the numbers.

The two structural answers, and what each costs.

Register the response. Breaks the path cleanly and costs one cycle per transfer. It is affordable precisely because termination is signalled — a master waits for a termination however long it takes, so inserting a cycle is absorbed rather than breaking anything. That is the modifiability argument from Chapter 1.5, arriving as a concrete option.

Go hierarchical. Decode to a group, then within the group: two narrow reductions instead of one wide one. It constrains the map to contiguous groups, which is why real address maps cluster peripherals into a band.

A caution against over-claiming. How many slaves a flat INTERCON supports before timing becomes a problem depends on the device, the clock target, the data width and the synthesiser. The specification says nothing about it, and neither should anyone without a synthesis report for the part in question. What is safe to say is the shape: the reduction is the structure that grows, and both fixes depend on the master tolerating variable latency.

7. Common Mistakes

"Adopting Wishbone determines how my blocks are connected."

Wrong mental model: the protocol includes the fabric.

Concrete bug: an integrator searching the specification for the decode structure or the arbitration policy and concluding the document is incomplete; or an address map nobody documents because everyone assumed it was inherited.

Observable evidence: an undocumented map, and integration bugs concentrated in decode and arbitration.

Correct model: the specification defines MASTER and SLAVE interfaces and defines INTERCON by its job. It names four topologies rather than mandating one and states that arbitration methodology is the end user's choice.

"The interconnect should gate every request signal."

Wrong mental model: selection means isolating the slave from everything.

Concrete bug: wide per-slave multiplexers on address, data, direction and byte selects — area and delay bought for nothing.

Observable evidence: an INTERCON far larger than it needs to be, with the critical path made worse.

Correct model: only the strobe needs decoding. A conforming slave ignores everything unless CYC_I & STB_I is true for it, so the rest can be broadcast. That is the fan-out/fan-in asymmetry — broadcasting is free, merging is not.

"An unmapped access is not the interconnect's problem."

Wrong mental model: the map describes what exists and the rest is undefined harmlessly.

Concrete bug: a stray pointer reaches an unmapped address, nothing is strobed, nothing terminates, and the master waits forever. One bad pointer stops the system.

Observable evidence: a reproducible hang on one address with every slave's strobe low.

Correct model: the default slave is a design element you build. Its absence is what makes a hang reachable, and it is a policy decision — error or zeros — that the specification does not make for you.

"A one-hot select is what the decoder produces, so it must be one-hot."

Wrong mental model: the encoding guarantees the property.

Concrete bug: overlapping regions set two hit bits; the AND-OR reduction merges two slaves' data and two terminations reach the master.

Observable evidence: read values sharing bits with two registers, and a master seeing ACK_I and ERR_I together.

Correct model: one-hot is a property to be proved — by an elaboration check over the map and an assertion over the address. The encoding is a hope until then.

8. Interview Reasoning

Four things, each a direct consequence of something an endpoint deliberately refuses to know.

Decode. The master drives an address and does not know which slave it reaches; the slave interprets a local offset and does not know its own base. The map therefore lives in the INTERCON, and nowhere else.

Distribute exactly one strobe. Selection cannot be a slave's decision, because a slave that recognises its own address has been welded to one system. Only the strobe needs decoding — the cycle signal, address, write data, direction and byte selects can all be broadcast, because a conforming slave ignores them unless CYC_I and STB_I are both true for it.

Merge the response. The master has one response port and there are many slaves, so read data and termination must be multiplexed back. This is the fan-in structure that grows with every slave and carries the critical path.

Answer for unmapped addresses. Without a default slave an unmapped access terminates never, and a stray pointer hangs the system.

The framing that shows judgement: all four are policy, not protocol. A conforming master and a conforming slave can be assembled into a broken system, and when that happens the fault is almost always here.

9. Understanding Check

10. What's Next

The three architectural pieces now exist as real modules: a master that owns its request, a slave that answers and refuses to know, and an INTERCON that holds the map and does the four jobs neither endpoint may.

What has not been done is to follow a single access all the way through them.

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

Chapter 3.6 — Data Flow traces it end to end in both directions. 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.