Skip to content
VLSI Mentor

Wishbone · Module 18

Routing

Forward and return routing as one property with five parts, measured on both topologies — and five broken interconnects in which every master and every slave still obeys every rule in B3.

Chapter 18.2 built a second topology and asserted that both route correctly. The assertion has not been examined.

How do the forward and return paths stay coherent — and what does it look like when one of them does not?

1. Two Directions, and Only One of Them Gets Built First

FORWARD ROUTING is master → owner → request context → decoded slave. It is the direction people draw, the direction the address points, and the direction that is obviously necessary.

RETURN ROUTING is selected slave → termination and data → originating master. It is the direction that is forgotten, and a system with a perfect forward path and a careless return path is the most common serious interconnect defect there is.

Here is why it is easy to get wrong. On a shared bus, the return route can be derived from the forward one: the shared address is the owner's address, so decoding it live tells you both where the request went and where the answer came from. Chapter 18.1 §3 made exactly that argument and it was correct there.

On a crossbar it is false. A master waiting at S0 has its own address on its own pins while S1 answers somebody else. Decode that master's address live and you hand it S1's answer. The return route has to be keyed on which slave granted this master, which is state the forward route does not need.

So "routing" is not one mechanism. It is two, and the second one's correctness argument is topology-specific — which is precisely the kind of reasoning that does not survive a copy-paste from one design to the next.

2. What a Route Audit Actually Checks

Turn the five agreements into eight comparisons and you have something executable.

check
destinationthe slave with an active phase is the one its owner's address decodes to
forward contextthat slave's ADR, WE and DAT are its owner's, all of them
no routeno phase is presented at a slave with no owner
exclusivityno master holds two slaves at once
stabilityno slave's owner moves while a phase is unanswered
return ownershipno master sees a termination from a slave it does not hold
data sourceread data matches the slave that granted the master
signatureread data matches the slave the address intended

The last two are deliberately both present, and they are not redundant. The structural check asks whether the wiring is self-consistent; the signature check is a known-answer test that survives a defect in which the structural check's own premises have moved. Section 6 contains a defect that the structural check misses and the signature check catches.

3. RTL — The Route Probe

One probe serves both topologies, which is only possible because both are describable in the same five terms.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_route_probe — the route-provenance audit.
//
// SIMULATION ONLY. int counters, no synthesis intent, and nothing here is a
// Wishbone feature. It is written once and used for BOTH topologies, which
// is only possible because both are described in the same five terms:
//
//   ORIGIN        which master issued this
//   INTENDED      which slave its address decodes to
//   ACTUAL        which slave actually saw a cycle
//   SOURCE        which slave produced the termination and data
//   RECIPIENT     which master received them
//
// A transaction is correct when all five agree. Every defect in Module 18
// breaks exactly one of the agreements, and this module names which.
//
// The shared bus has one global owner; the crossbar has one owner per
// slave. The probe takes the PER-SLAVE view, and the shared-bus rig derives
// it from its global owner plus the decoded destination. That is why one
// probe serves both topologies rather than two probes serving one each.
//
// DATA PROVENANCE IS CHECKED TWICE, DELIBERATELY:
//   structurally  the value the master received equals the value the slave
//                 that granted it was driving;
//   by signature  the value equals SIG of the INTENDED slave plus the
//                 offset, which is a known-answer test that survives a
//                 defect in which the structural check's own premises move.
// ─────────────────────────────────────────────────────────────────────────
module wb_route_probe #(
  parameter int unsigned AW       = 12,
  parameter int unsigned DW       = 32,
  parameter int unsigned SEL_BIT  = 11,
  parameter int unsigned OFF_BITS = 8,
  parameter logic [31:0] SIG0     = 32'hA000_0000,
  parameter logic [31:0] SIG1     = 32'hB100_0000
) (
  input  logic          clk_i,
  input  logic          rst_i,
  // masters, as seen at their own ports
  input  logic          m0_cyc_i, m0_stb_i, m0_we_i,
  input  logic [AW-1:0] m0_adr_i,
  input  logic [DW-1:0] m0_wdat_i, m0_rdat_i,
  input  logic          m0_ack_i, m0_err_i,
  input  logic          m1_cyc_i, m1_stb_i, m1_we_i,
  input  logic [AW-1:0] m1_adr_i,
  input  logic [DW-1:0] m1_wdat_i, m1_rdat_i,
  input  logic          m1_ack_i, m1_err_i,
  // slaves, as seen at their own ports
  input  logic          s0_cyc_i, s0_stb_i, s0_we_i,
  input  logic [AW-1:0] s0_adr_i,
  input  logic [DW-1:0] s0_wdat_i, s0_rdat_i,
  input  logic          s0_ack_i, s0_err_i,
  input  logic          s1_cyc_i, s1_stb_i, s1_we_i,
  input  logic [AW-1:0] s1_adr_i,
  input  logic [DW-1:0] s1_wdat_i, s1_rdat_i,
  input  logic          s1_ack_i, s1_err_i,
  // per-slave ownership, 0 NONE / 1 M0 / 2 M1
  input  logic [1:0]    sown0_i, sown1_i,
  // violations
  output int unsigned   v_dest_o,      // request reached the wrong slave
  output int unsigned   v_fwd_o,       // forward context is not the owner's
  output int unsigned   v_noroute_o,   // a phase presented with no owner
  output int unsigned   v_excl_o,      // a master owns two slaves at once
  output int unsigned   v_stable_o,    // owner moved under an open phase
  output int unsigned   v_retown_o,    // a master saw a foreign termination
  output int unsigned   v_src_o,       // data did not come from the granter
  output int unsigned   v_sig_o,       // data is not the intended slave's
  // concurrency
  output int unsigned   clk_active0_o, clk_active1_o,
  output int unsigned   clk_both_o, clk_none_o, clk_one_o,
  // contention, per destination
  output int unsigned   con_s0_o, con_s1_o,
  // terminations
  output int unsigned   n_ack0_o, n_ack1_o, n_err0_o, n_err1_o,
  output int unsigned   n_m0term_o, n_m1term_o
);
  localparam logic [1:0] NONE = 2'd0, M0 = 2'd1, M1 = 2'd2;

  logic m0_dest, m1_dest;
  assign m0_dest = m0_adr_i[SEL_BIT];
  assign m1_dest = m1_adr_i[SEL_BIT];

  logic a0, a1;                       // slave path active this clock
  assign a0 = s0_cyc_i && s0_stb_i;
  assign a1 = s1_cyc_i && s1_stb_i;

  logic t0, t1;                       // slave terminating
  assign t0 = s0_ack_i || s0_err_i;
  assign t1 = s1_ack_i || s1_err_i;

  logic m0t, m1t;
  assign m0t = m0_ack_i || m0_err_i;
  assign m1t = m1_ack_i || m1_err_i;

  // what each slave's owner intended
  logic dest_bad0, dest_bad1, fwd_bad0, fwd_bad1;
  always_comb begin
    dest_bad0 = 1'b0; fwd_bad0 = 1'b0;
    if (a0) begin
      if (sown0_i == M0) begin
        dest_bad0 = (m0_dest != 1'b0);
        fwd_bad0  = (s0_adr_i != m0_adr_i) || (s0_we_i != m0_we_i)
                 || (s0_we_i && (s0_wdat_i != m0_wdat_i));
      end else if (sown0_i == M1) begin
        dest_bad0 = (m1_dest != 1'b0);
        fwd_bad0  = (s0_adr_i != m1_adr_i) || (s0_we_i != m1_we_i)
                 || (s0_we_i && (s0_wdat_i != m1_wdat_i));
      end
    end
    dest_bad1 = 1'b0; fwd_bad1 = 1'b0;
    if (a1) begin
      if (sown1_i == M0) begin
        dest_bad1 = (m0_dest != 1'b1);
        fwd_bad1  = (s1_adr_i != m0_adr_i) || (s1_we_i != m0_we_i)
                 || (s1_we_i && (s1_wdat_i != m0_wdat_i));
      end else if (sown1_i == M1) begin
        dest_bad1 = (m1_dest != 1'b1);
        fwd_bad1  = (s1_adr_i != m1_adr_i) || (s1_we_i != m1_we_i)
                 || (s1_we_i && (s1_wdat_i != m1_wdat_i));
      end
    end
  end

  // return ownership: a master may see a termination only from a slave it
  // owns, and only on a clock that slave is terminating
  logic ret_bad0, ret_bad1;
  assign ret_bad0 = m0t && !((sown0_i == M0 && t0) || (sown1_i == M0 && t1));
  assign ret_bad1 = m1t && !((sown0_i == M1 && t0) || (sown1_i == M1 && t1));

  // data provenance, structural and by signature
  logic [DW-1:0] exp0_src, exp1_src, exp0_sig, exp1_sig;
  logic [OFF_BITS-1:0] off0, off1;
  assign off0 = m0_adr_i[OFF_BITS-1:0];
  assign off1 = m1_adr_i[OFF_BITS-1:0];
  assign exp0_src = (sown1_i == M0) ? s1_rdat_i : s0_rdat_i;
  assign exp1_src = (sown1_i == M1) ? s1_rdat_i : s0_rdat_i;
  assign exp0_sig = (m0_dest ? SIG1 : SIG0) + {{(DW-OFF_BITS){1'b0}}, off0};
  assign exp1_sig = (m1_dest ? SIG1 : SIG0) + {{(DW-OFF_BITS){1'b0}}, off1};

  logic src_bad0, src_bad1, sig_bad0, sig_bad1;
  assign src_bad0 = m0_ack_i && !m0_we_i && (m0_rdat_i !== exp0_src);
  assign src_bad1 = m1_ack_i && !m1_we_i && (m1_rdat_i !== exp1_src);
  assign sig_bad0 = m0_ack_i && !m0_we_i && (m0_rdat_i !== exp0_sig);
  assign sig_bad1 = m1_ack_i && !m1_we_i && (m1_rdat_i !== exp1_sig);

  logic excl_bad;
  assign excl_bad = ((sown0_i == M0) && (sown1_i == M0))
                 || ((sown0_i == M1) && (sown1_i == M1));

  logic [1:0] p0_q, p1_q;
  logic       open0_q, open1_q;

  logic c0, c1;                       // both masters want this slave
  assign c0 = (m0_cyc_i && !m0_dest) && (m1_cyc_i && !m1_dest);
  assign c1 = (m0_cyc_i &&  m0_dest) && (m1_cyc_i &&  m1_dest);

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      v_dest_o <= 0; v_fwd_o <= 0; v_noroute_o <= 0; v_excl_o <= 0;
      v_stable_o <= 0; v_retown_o <= 0; v_src_o <= 0; v_sig_o <= 0;
      clk_active0_o <= 0; clk_active1_o <= 0;
      clk_both_o <= 0; clk_none_o <= 0; clk_one_o <= 0;
      con_s0_o <= 0; con_s1_o <= 0;
      n_ack0_o <= 0; n_ack1_o <= 0; n_err0_o <= 0; n_err1_o <= 0;
      n_m0term_o <= 0; n_m1term_o <= 0;
      p0_q <= NONE; p1_q <= NONE; open0_q <= 1'b0; open1_q <= 1'b0;
    end else begin
      v_dest_o    <= v_dest_o    + (dest_bad0 ? 1 : 0) + (dest_bad1 ? 1 : 0);
      v_fwd_o     <= v_fwd_o     + (fwd_bad0  ? 1 : 0) + (fwd_bad1  ? 1 : 0);
      v_noroute_o <= v_noroute_o + ((a0 && sown0_i == NONE) ? 1 : 0)
                                 + ((a1 && sown1_i == NONE) ? 1 : 0);
      v_excl_o    <= v_excl_o    + (excl_bad ? 1 : 0);
      v_retown_o  <= v_retown_o  + (ret_bad0 ? 1 : 0) + (ret_bad1 ? 1 : 0);
      v_src_o     <= v_src_o     + (src_bad0 ? 1 : 0) + (src_bad1 ? 1 : 0);
      v_sig_o     <= v_sig_o     + (sig_bad0 ? 1 : 0) + (sig_bad1 ? 1 : 0);

      // owner stability: the owner moved while a phase was open
      if (open0_q && sown0_i != p0_q) v_stable_o <= v_stable_o + 1;
      else if (open1_q && sown1_i != p1_q) v_stable_o <= v_stable_o + 1;
      p0_q <= sown0_i; p1_q <= sown1_i;
      open0_q <= a0 && !t0;
      open1_q <= a1 && !t1;

      if (a0) clk_active0_o <= clk_active0_o + 1;
      if (a1) clk_active1_o <= clk_active1_o + 1;
      if (a0 && a1)   clk_both_o <= clk_both_o + 1;
      else if (a0 || a1) clk_one_o <= clk_one_o + 1;
      else            clk_none_o <= clk_none_o + 1;

      if (c0) con_s0_o <= con_s0_o + 1;
      if (c1) con_s1_o <= con_s1_o + 1;

      if (s0_ack_i) n_ack0_o <= n_ack0_o + 1;
      if (s1_ack_i) n_ack1_o <= n_ack1_o + 1;
      if (s0_err_i) n_err0_o <= n_err0_o + 1;
      if (s1_err_i) n_err1_o <= n_err1_o + 1;
      if (m0t) n_m0term_o <= n_m0term_o + 1;
      if (m1t) n_m1term_o <= n_m1term_o + 1;
    end
  end
endmodule

Reading it

The shared bus has one global owner and the crossbar has one per slave, so the probe takes the per-slave view and the shared-bus rig projects its global owner onto the destination it is driving. That is two lines of wiring and it is what makes a single audit possible across two architectures.

dest_bad0 is the forward-destination check and it reads backwards from the slave. For each slave with an active phase, find its owner, and ask what that master's address decodes to. If S0 is busy on behalf of a master whose address says S1, the request is at the wrong slave. The decoder may be perfectly correct and this check still fires — decode is a decision; this tests whether the decision was carried out.

ret_bad0 is the return-ownership check, and it is two conditions rather than one: a master may see a termination only from a slave it holds, and only on a clock that slave is terminating. The second half catches a termination invented by the interconnect.

The two data checks differ in what they trust. exp0_src asks what the granting slave was driving — so it tests the return mux against the grant. exp0_sig computes SIG + offset from the master's own address, and trusts nothing in the interconnect at all.

Everything here is int unsigned and simulation-only. A silicon version would be narrow counters behind a status register, and none of it is a Wishbone feature — a system that exposes none of it can report only that something is wrong.

The provenance chain as a loop. A master is the origin of a request. Its address is decoded to an intended destination. The forward route carries the request to an actual destination, which should be the intended one. That slave becomes the source of a termination and read data. The return route carries them back to a recipient, which should be the original master. The loop closes only when the actual destination equals the intended one and the recipient equals the origin; a break at either point produces a system in which every endpoint is still individually correct.ORIGINthe masterINTENDEDdecode says S0ACTUALthe slave in a cycleSOURCEwho terminatedRECIPIENTwho was toldaddressforward routeanswersreturn routemust be the same12

The loop closes only if ACTUAL == INTENDED and RECIPIENT == ORIGIN. Both of those are the interconnect's job, and neither is checked by anything in the protocol.

4. Simulation — SIM E: All Four Routes, All Five Agreements

Two pairs of simultaneous reads on the crossbar, arranged so that each master uses each slave.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM E - five things that must agree ===
    ORIGIN, INTENDED, ACTUAL, SOURCE, RECIPIENT.
    Every read below is checked against the signature of the
    slave its address decodes to, not against the slave that
    happened to answer.

      M0 -> S0  0x031  read 0xa0000031   expected 0xa0000031
      M1 -> S1  0x833  read 0xb1000033   expected 0xb1000033
      M0 -> S1  0x835  read 0xb1000035   expected 0xb1000035
      M1 -> S0  0x037  read 0xa0000037   expected 0xa0000037

    provenance audit, correct crossbar
      request reached the wrong slave        0
      forward context was not the owner's    0
      a phase presented with no owner        0
      a master owned two slaves at once      0
      owner moved under an open phase        0
      a master saw a foreign termination     0
      data did not come from the granter     0
      data was not the intended slave's      0

Reading it

Four reads, four signatures, four matches. M0 → S0 got 0xA0000031; M1 → S1 got 0xB1000033; then the destinations swap and M0 → S1 gets 0xB1000035 while M1 → S0 gets 0xA0000037.

The swap is the interesting half. Between the two pairs each master changed destination, so each slave's owner changed and each master's return source changed — and the audit's eight counters stayed at zero throughout.

Read the audit as three groups. The first four counters are the forward path: destination, context, no-route, exclusivity. The fifth is retention. The last three are the return path, and they are the ones that the next section removes.

Nothing here is surprising, which is exactly why it is worth running before Section 5. A checker that has only ever reported zero has not been shown to report anything.

5. Simulation — SIM F: A Return Path Keyed on the Wrong Thing

Both masters read S0. The broken crossbar routes each master's response from the slave its address currently decodes to, instead of from the slave that granted it. Everything else — the decode, the arbiter, the forward mux, the retention — is untouched.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM F - a return path keyed on the current decode ===
    Both masters read S0. The broken crossbar routes each
    master's response from the slave its address CURRENTLY
    decodes to, instead of from the slave that granted it.

      rig        M0 read      M1 read     S0 reads
      correct    0xa0000041   0xa0000042   2
      broken     0xa0000042   0xa0000042   1

    measure                           correct  broken
      foreign termination seen            0       1
      data not from the granter           0       0
      data not the intended slave's       0       1
      terminations at S0                  2       1
      terminations delivered to masters   2       2

    endpoint conformance across BOTH rigs
      STB_O without CYC_O, or two terminations at once: 0
    -> every master and every slave obeyed RULE 3.25 and
       RULE 3.45 in both rigs. One of the two systems is
       still wrong, and no endpoint could have known.

Reading it — three numbers

M0 read 0xA0000042 in the broken rig, and 0x42 is M1's offset. M0 asked for 0x041 and was handed M1's word.

S0 reads: correct 2, broken 1. The slave performed one read in the broken system and two in the correct one — and yet:

terminations delivered to masters: correct 2, broken 2. Two masters completed on one slave transfer. M0's read never happened at S0 at all; it completed on M1's ACK, with M1's data, because on that clock M0's address also decoded to S0.

Now the line that makes this chapter's point:

STB_O without CYC_O, or two terminations at once: 0 — across both rigs.

Every master and every slave in both systems obeyed RULE 3.25 and RULE 3.45. A protocol checker on any port of either system reports nothing. One of the two systems is wrong and no endpoint could have known, because the defect is a relationship between ports and every rule in B3 is about a single port.

And note which checker caught it. Data not from the granter: broken 0. The structural check missed it — the granting slave genuinely was S0 and S0's data genuinely was what M0 received. The signature check caught it, because it compares against the slave the address intended and the offset the master asked for. That is why both checks are in the probe.

6. The Negative-Control Gate

Five checkers, seven interconnects — two correct, five broken by one named term each — and one stimulus.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === NEGATIVE-CONTROL GATE ===
    one stimulus, seven interconnects. SB = shared bus,
    XB = crossbar. Each broken rig differs from its correct
    counterpart by exactly one named term.

    checker                 corSB  misrt  ORdat  bcast  corXB  ctxmx  liveR
    ROUTE DESTINATION       PASS   FAIL   PASS   PASS   PASS   PASS   PASS
    DATA PROVENANCE         PASS   FAIL   FAIL   FAIL   PASS   FAIL   FAIL
    RETURN OWNERSHIP        PASS   PASS   PASS   FAIL   PASS   PASS   FAIL
    FORWARD CONTEXT         PASS   PASS   PASS   PASS   PASS   FAIL   PASS
    OWNER STABILITY         PASS   PASS   PASS   PASS   PASS   PASS   PASS

    raw counts        dest  sig  return  fwd  stable
      correct SB        0    0     0     0     0
      misroute         12    5     0     0     0
      OR read data      0    6     0     0     0
      broadcast         0    5     5     0     0
      correct XB        0    0     0     0     0
      context mix       0    2     0     5     0
      live return       0    3     3     0     0

    what each master last read
      correct SB   M0 0xb1000098  M1 0xb1000099
      misroute     M0 0xb1000098  M1 0xa0000099
      OR read data M0 0xb1000098  M1 0xb1000099
      correct XB   M0 0xb1000098  M1 0xb1000099
      context mix  M0 0xb1000098  M1 0xb1000098
      live return  M0 0xb1000099  M1 0xb1000099

    NEGATIVE-CONTROL CHECKERS REQUIRED:  >= 4
    CHECKERS PASS BOTH CORRECT DUTs:     10/10
    CHECKERS FAIL TARGET BROKEN DUT:     5/5
      1 ROUTE DESTINATION   <- misroute
      2 DATA PROVENANCE     <- OR-reduced read data
      3 RETURN OWNERSHIP    <- broadcast termination
      4 FORWARD CONTEXT     <- same-slave context mixing
      5 DATA PROVENANCE     <- live return decode

Reading it

Both correct interconnects pass all five checkers: 10/10. Every broken one fails the checker aimed at it: 5/5.

The raw counts table is where the defects stop being labels.

misroute fires the destination checker twelve times and the signature checker five times. Twelve clocks on which a slave was in a cycle on behalf of a master whose address decoded elsewhere, producing five reads with the wrong signature. M1 read 0xA0000099 where it should have read 0xB1000099 — the right offset, from entirely the wrong peripheral.

OR read data fires only the signature checker, six times. The destination was right, the context was right, the termination went to the right master — and the data was the bitwise OR of two slaves. In this run the ORed value happened to be readable; in general it is a value neither slave holds.

broadcast fires return ownership five times and the signature checker five times. Two masters completing on one slave's termination, which is Chapter 16.3's defect arriving in a system that now also has a destination to get wrong.

context mix fires the forward-context checker five times and the signature checker twice, and its read row is the clearest single line in the table: M0 0xb1000098 M1 0xb1000098. Two masters, two different addresses, the same word.

live return fires return ownership and the signature checker three times each — SIM F, counted.

And one column is worth a sentence on its own: OWNER STABILITY passes everywhere. All five defects leave retention intact. A retention checker — the whole subject of Chapter 17.5 — catches none of them. These are routing defects, and they need routing checkers.

7. What B3 Says About Return Routing

Almost nothing, and the shape of the silence matters.

RULE 3.45 constrains a slave: "If a SLAVE supports the [ERR_O] or [RTY_O] signals, then the SLAVE MUST NOT assert more than one of the following signals at any time: [ACK_O], [ERR_O] or [RTY_O]." That is one slave's outputs. It says nothing whatever about an interconnect combining two slaves' terminations.

RULE 3.30 is the one that actually helps: "SLAVE interfaces MAY NOT respond to any SLAVE signals when [CYC_I] is negated." Gate CYC per destination and an unselected slave contributes nothing — which is why OR-ing terminations is survivable in a system that gates correctly, and catastrophic in one that does not. "ACK can be ORed because only one slave will respond" is an assumption about your own gating, and it has to be verified rather than assumed.

RECOMMENDATION 3.10 is the only place B3 asks an interconnect for behaviour beyond wiring: "Design INTERCON modules to prevent deadlock conditions." Not "route responses correctly" — deadlock, with a watchdog as the suggested remedy.

And the specification states plainly that master-side and slave-side waveforms differ once an interconnect exists: "the MASTER and SLAVE interfaces can be connected together in different ways... the actual waveforms at the SLAVE may vary from those at the MASTER." Everything in this chapter lives in that variation.

8. When a Destination Has to Be Retained

The question is not "should I add a destination register" but "is the thing I am decoding guaranteed to belong to the open transfer".

On the shared bus: yes, and Chapter 18.1 §3 gave the argument — the shared address is the owner's, the owner is retained for its whole CYC_O (RULE 3.25 plus Chapter 17.5's rule), and ADR_O is qualified by STB_O (RULE 3.60). A destination register there would store what the address already says.

On the crossbar: no. A waiting master's address is not the address of the transfer being answered. The grant is the retained state, and this module keeps it as sown0_q/sown1_q rather than as an explicit per-master destination.

ZipCPU's wbxbar keeps it the other way round — a per-master slave index, mindex[N], with the stated reason being "faster/cheaper logic on the return path, since we can now use a fully populated LUT rather than a priority based return scheme". Same invariant, different encoding, and the choice is about implementation cost.

The invariant is what travels:

The destination associated with an open transfer must not change while that transfer is unanswered, and the return path must be derived from that destination rather than from anything that can move.

9. Failure Modes and Discriminating Evidence

SYMPTOM — a master reads peripheral-looking data from a RAM address.

Candidates. Wrong destination decode. A return mux selecting the wrong slave. Stale or live destination state.

Discriminating evidence. Origin, address, decoded destination, actual destination, response source, data source — in that order. The first pair that disagrees names the stage. With signatured slaves the last one is free.

SYMPTOM — both masters complete on one ACK.

Candidates. Broadcast return. A missing ownership qualifier on one of the termination classes.

Discriminating evidence. Client completions against slave terminations. They must be equal. In SIM F they were 2 and 1. This identity needs no model of the interconnect — two counters.

SYMPTOM — a transfer hangs only for one address range.

Candidates. The decode produces no select. The selected slave never terminates. The return path for that slave is unconnected.

Discriminating evidence. Did any slave's CYC_I assert? If not, it is decode and Chapter 12.6's default-slave question. If yes and nothing came back, it is the return route or the slave.

SYMPTOM — wrong data after a long wait, only under load.

Candidates. A live return decode; the owner or destination moved during the wait.

Discriminating evidence. The destination at issue against the destination at termination, and the granting slave at both moments. Long waits are when this defect becomes reachable — with fast slaves the window is one clock.

SYMPTOM — everything passes and the system is still wrong.

Candidates. You are running a protocol checker on a routing problem.

Discriminating evidence. Section 6's table. Five broken interconnects, every endpoint rule-clean.

10. Verification

Twelve property groups, and the classification is the point.

#propertyclass
P1no master holds two slaveslocal interconnect
P2no phase presented at a slave with no ownerlocal interconnect
P3at most one decoded destination per requestlocal map policy
P4a slave's phase belongs to a master addressing itlocal interconnect
P5the forward context is one master's, wholelocal, motivated by RULE 3.60
P6a master sees a termination only from a slave it holdslocal interconnect
P7read data comes from the granting slavelocal interconnect
P8a slave's owner is stable under an open phaselocal policy
P9an open transfer's destination does not movelocal policy
P10STB_O implies CYC_O, at every portRULE 3.25
P11a slave is silent without CYC_IRULE 3.30
P12at most one termination per slaveRULE 3.45

Three of twelve are spec-derived. Module 16's ratio was four of thirteen and Module 17's three of fourteen. An interconnect study is almost entirely local by construction, and P12 is in the list mainly to be pointed at: it constrains a slave, and every defect in Section 6 satisfies it.

SVA REVIEWED BY INSPECTION ONLY. Icarus Verilog does not execute concurrent assertions; the property file was run through iverilog -g2012 and rejected. None of the properties was executed as an assertion. Every one has a named procedural equivalent in wb_route_probe that was executed, and those counters are what Sections 4 to 6 report.

Elaboration is not synthesis. All published modules elaborate individually and together under iverilog -g2012, with no duplicate module names. Every always_comb assigns all of its outputs on every path, so none infers a latch; every output has one driver by inspection; and no combinational loop exists — one would not have produced eleven deterministic runs. No synthesis tool was run and no area, timing or frequency claim appears anywhere in this module.

11. Common Mistakes

"Routing the request correctly is enough."

Why it is wrong: SIM F's forward path is perfect. The wrong master completed anyway.

"ACK can be ORed from every slave, because only one will respond."

Why it is dangerous: that sentence is an assumption about your gating, not a fact about slaves. It is true exactly when every unselected slave has CYC_I negated — RULE 3.30 — and false the moment a decode overlaps. The safer model is provenance: select by destination, and check it.

"Read data can be ORed because only one slave drives it."

Why it is wrong in this module's measurement: the OR read data rig fired the signature checker six times. A slave that is not selected still drives its output port, and B3 nowhere requires a slave to drive zeros.

"Protocol-compliant masters and slaves guarantee a correct SoC."

Why it is wrong: Section 6, in one table. Five broken interconnects, every endpoint clean.

"Address decode and routing are the same."

Why it is wrong: the misroute rig has a perfect decoder. Decode is a decision; routing is whether the decision was carried out — in both directions.

"A destination register is always needed." / "A destination register is never needed."

Why both are wrong: the shared bus does not need one and the crossbar does, and the reason is a specific argument about what the decoded address belongs to. Section 8 is the argument; neither slogan survives it.

"If the arbiter is right and the decoder is right, the interconnect is right."

Why it is wrong: context mix has a correct arbiter and a correct decoder, and hands one slave M0's address with M1's data. Two correct decisions can still be carried out incoherently.

12. Interview Reasoning

"What is the difference between decode and routing?"

Decode answers "which slave should this go to". Routing is whether the request got there and whether the answer got back. A correct decoder with a broken forward mux produces a request at the wrong slave; a correct forward path with a broken return mux produces the right transfer reported to the wrong master.

"Why is response routing as important as request routing?"

Because a master has no other way to know. It sees a termination on its own port and believes it. Nothing in a Wishbone response identifies its source — that is why this module's slaves carry signatures, and why a real system cannot.

"How would you prove the correct slave supplied read data?"

Two ways, and use both. Structurally, compare against what the granting slave was driving. By known answer, compare against a value only that slave can produce. SIM F is a defect the first check misses and the second catches.

"How would you prove the correct master received the termination?"

Client completions against slave terminations must be equal, and each completion must coincide with a termination at a slave that master holds. Two counters and one comparison.

"Why can every endpoint pass a Wishbone check while the SoC is wrong?"

Because every rule in B3 is about one port. RULE 3.25 is about a master's CYC_O and STB_O; RULE 3.30 and RULE 3.45 are about a slave's outputs. A routing defect is a relationship between ports and there is no rule about relationships.

"When is OR-ing slave terminations acceptable?"

When you have verified that at most one slave can ever be in a cycle — which is a property of your decode and your gating, not of the slaves. State it as an assumption and check it, because it is exactly the thing an overlapping address map breaks.

13. Understanding Check

In SIM F the slave performed one read and two masters completed. Which of the five agreements broke?

RECIPIENT. The origin, intended, actual and source were all S0 and M1's transfer. M0 was told about a transaction that was not its own.

The structural data check passed on SIM F and the signature check failed. Why keep both?

They trust different things. The structural check asks whether the return mux agrees with the grant — and in SIM F it did, because M0's live decode happened to match the granting slave. The signature check trusts nothing in the interconnect.

OWNER STABILITY passes on all five broken interconnects. What does that tell you about checker selection?

That a checker catches its own class and nothing else. Retention was Module 17's subject and every defect here leaves it intact. A verification plan assembled from the previous module's checkers would have passed all five.

Your interconnect ORs slave ACKs. A colleague says RULE 3.45 makes this safe. Are they right?

No. RULE 3.45 says one slave will not assert two terminations at once. It says nothing about two slaves, and the safety of OR-ing depends entirely on your own guarantee that only one slave is ever in a cycle.

Which single counter would you add first to an interconnect you did not write?

Client completions against slave terminations. It is two counters, needs no model of the topology, and it is the one that catches a broadcast return — the defect that silently corrupts a master that was doing nothing wrong.

14. What's Next

Both topologies now route correctly and both have been proved to, against defects built to break them.

What actually grows when a system gets bigger — and along which dimension does a topology "scale"?

Chapter 18.4 — Scalability counts structure rather than asserting adjectives: contention domains, arbiters, decoders and mux inputs as M and S grow. It also measures a crossbar whose second path is entirely idle, because "we have more paths" and "our traffic uses them" are different claims.

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.