Wishbone · Module 18
Shared Bus
Two masters and two slaves on one path, with all four routes measured — and two requests to different slaves that serialise anyway, because that is the topology and not the protocol.
Chapter 17.5 closed the arbitration question. Every system in Modules 16 and 17 had exactly one shared resource, and the address never had anywhere else to go.
What happens when several masters and several slaves share one transfer path?
1. Three Axes, Not One Word
"Bus complexity" is not a useful variable. Topology is three independent questions, and keeping them apart is what makes the rest of this module tractable.
AXIS A — MASTER CONTENTION. How many masters want the same resource at the same time? Modules 16 and 17 lived entirely on this axis.
AXIS B — SLAVE DESTINATION. Which slave owns this address? Module 12 lived entirely on this axis.
AXIS C — CONCURRENCY. Can two independent master→slave pairs make progress on the same clock? Neither previous module could ask this, because neither had two slaves that could be busy at once.
| topology | A: contention | B: destination | C: concurrency |
|---|---|---|---|
| point-to-point | impossible — one master | nothing to decode | one pair, always |
| shared bus | one global domain | decoded | none |
| crossbar | one domain per destination | decoded per master | independent pairs |
B3 names five interconnection means — "Point-to-point / Shared bus / Crossbar switch / Data flow interconnection / Off chip" — after the word "including". None is required and none is forbidden. A point-to-point system is fully conformant, and its glossary entry is the baseline the other four are measured against: "An interconnection system that supports a single WISHBONE MASTER and a single WISHBONE SLAVE interface. It is the simplest way to connect two cores."
2. RTL — A Slave That Says Who It Is
Every experiment in this module has to answer "which slave produced this?" from evidence. The teaching slave carries a signature so the answer is in the data.
// ─────────────────────────────────────────────────────────────────────────
// wb_tag_slave — a slave whose read data says which slave it is.
//
// Every routing experiment in Module 18 needs to answer "which slave
// produced this data?" from the data itself, so each instance carries a
// signature and returns SIG + offset on a read. With S0 signatured
// 0xA000_0000 and S1 signatured 0xB100_0000, a read of offset 5 returns
// 0xA000_0005 or 0xB100_0005 and the provenance is legible in the value.
//
// That is a TEACHING DEVICE, not a Wishbone feature. Nothing in B3 puts an
// identity in read data, and a real system cannot tell which slave answered
// except by trusting its own interconnect - which is the whole problem
// Chapter 18.3 is about.
//
// Three behaviours beyond the signature, each motivated:
//
// WAITS fixed wait states. The counter counts clocks the phase has
// been HELD and is cleared by the answer, never preloaded.
// RO_ABOVE offsets at or above this are read-only; a write to one is
// answered ERR_O. A register block with read-only status
// registers is ordinary, and it gives Module 18 an ERR that
// has to be routed like any other termination.
// RULE 3.30 ack/err are qualified by cyc_i && stb_i, so an unselected
// slave - one whose CYC_I the interconnect has gated away -
// cannot contribute anything to the shared response.
// ─────────────────────────────────────────────────────────────────────────
module wb_tag_slave #(
parameter int unsigned AW = 12,
parameter int unsigned DW = 32,
parameter int unsigned SW = DW/8,
parameter int unsigned WORDS = 256,
parameter int unsigned WAITS = 0,
parameter logic [31:0] SIG = 32'hA000_0000,
parameter int unsigned RO_ABOVE = 256 // none read-only by default
) (
input logic clk_i,
input logic rst_i,
input logic cyc_i,
input logic stb_i,
input logic we_i,
input logic [AW-1:0] adr_i,
input logic [DW-1:0] dat_i,
input logic [SW-1:0] sel_i,
output logic [DW-1:0] dat_o,
output logic ack_o,
output logic err_o,
// observation
output logic [15:0] reads_o,
output logic [15:0] writes_o
);
localparam int unsigned IW = $clog2(WORDS);
logic [DW-1:0] mem [0:WORDS-1];
logic [7:0] held_q;
logic [15:0] nrd_q, nwr_q;
logic [IW-1:0] idx;
assign idx = adr_i[IW-1:0];
logic xfer, ready, refused;
assign xfer = cyc_i && stb_i;
assign ready = xfer && (held_q >= WAITS[7:0]);
assign refused = ready && we_i && (idx >= RO_ABOVE[IW-1:0]);
assign ack_o = ready && !refused;
assign err_o = refused;
assign dat_o = mem[idx];
assign reads_o = nrd_q;
assign writes_o = nwr_q;
integer i, b;
always_ff @(posedge clk_i) begin
if (rst_i) begin
held_q <= 8'd0; nrd_q <= 16'd0; nwr_q <= 16'd0;
for (i = 0; i < WORDS; i = i + 1)
mem[i] <= SIG + i[31:0];
end else begin
if (!xfer || ack_o || err_o) held_q <= 8'd0;
else held_q <= held_q + 8'd1;
if (ack_o && we_i) begin
nwr_q <= nwr_q + 16'd1;
for (b = 0; b < SW; b = b + 1)
if (sel_i[b]) mem[idx][b*8 +: 8] <= dat_i[b*8 +: 8];
end
if (ack_o && !we_i) nrd_q <= nrd_q + 16'd1;
end
end
endmoduleReading it
SIG + offset is the whole instrument. S0 is signatured 0xA000_0000 and S1 0xB100_0000, so a read of offset 0x31 returns 0xA0000031 or 0xB1000031 and the provenance is legible in the value itself.
That is a teaching device and not a Wishbone feature. Nothing in B3 puts an identity in read data. A real system cannot tell which slave answered except by trusting its own interconnect — which is precisely the thing Chapter 18.3 shows can be wrong.
RO_ABOVE gives the module an ERR that is not contrived. A register block with read-only status registers is ordinary, and a write to one is wrong about the request, which is Chapter 11.2's test for ERR rather than RTY. An interconnect has to route an ERR exactly as carefully as an ACK, and a design that gets one right and the other wrong is common.
And ack_o/err_o are qualified by cyc_i && stb_i, which is what makes an unselected slave harmless. RULE 3.30: "SLAVE interfaces MAY NOT respond to any SLAVE signals when [CYC_I] is negated." Gating CYC per destination is therefore the load-bearing act of a decoder — everything else it does is tidiness by comparison.
3. RTL — The Shared Interconnect
Eight stages, kept visible, because the module is the lesson.
// ─────────────────────────────────────────────────────────────────────────
// wb_shared_intercon2x2 — two masters, two slaves, ONE shared path.
//
// The specification names this topology and says exactly why it behaves as
// it does: "The shared bus interconnection is a system where a MASTER
// initiates addressable bus cycles to a target SLAVE... As a consequence of
// this architecture, only one MASTER at a time can use the interconnection
// resource (i.e. bus)." That sentence is about the ARCHITECTURE, not about
// Wishbone - no rule in B3 serialises anything.
//
// The stages are kept visible because the whole module is the lesson:
//
// eligibility {m1_cyc, m0_cyc} who is asking
// selection wb_arb_policy Chapter 17.1, reused unchanged
// owner a register with a guard Chapter 17.5's retention rule
// forward mux owner -> shared request Chapter 16.3's one context
// decode shared adr -> destination Chapter 12.3, one bit of it
// gating destination -> one slave RULE 3.30 does the rest
// response destination -> shared provenance, and Section 3 of 18.3
// return shared -> owner only Chapter 16.3's demux
//
// ── WHY THE RESPONSE DECODE IS LIVE AND NOT REGISTERED ──────────────────
// The shared address IS the owner's address, and RULE 3.25 keeps a master's
// CYC_O asserted for the duration of its cycle while RULE 3.60 has it
// qualify ADR_O with STB_O. The destination therefore cannot move while a
// transfer is unanswered, and a destination register would add state that
// records what the address already says. Chapter 18.3 shows the topology in
// which that reasoning stops holding.
//
// ── THE FOUR DEFECTS ────────────────────────────────────────────────────
// All off by default. Each is one term, and none of them violates any rule
// in B3 - which is the point of Chapter 18.3's negative controls.
//
// MISROUTE the decode is inverted while M1 owns the path
// OR_ACK the two slaves' terminations are OR-ed instead of selected
// OR_DATA the two slaves' read data are OR-ed instead of selected
// BROADCAST the termination is delivered to both masters
// ─────────────────────────────────────────────────────────────────────────
module wb_shared_intercon2x2 #(
parameter int unsigned AW = 12,
parameter int unsigned DW = 32,
parameter int unsigned SW = DW/8,
parameter int unsigned SEL_BIT = 11, // 0 -> S0, 1 -> S1
parameter bit POLICY = 1'b1, // 0 fixed priority, 1 RR
parameter bit MISROUTE = 1'b0,
parameter bit OR_ACK = 1'b0,
parameter bit OR_DATA = 1'b0,
parameter bit BROADCAST = 1'b0
) (
input logic clk_i,
input logic rst_i,
// -- master 0 --
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_dat_i,
input logic [SW-1:0] m0_sel_i,
output logic [DW-1:0] m0_dat_o,
output logic m0_ack_o, m0_err_o,
// -- master 1 --
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_dat_i,
input logic [SW-1:0] m1_sel_i,
output logic [DW-1:0] m1_dat_o,
output logic m1_ack_o, m1_err_o,
// -- slave 0 --
output logic s0_cyc_o, s0_stb_o, s0_we_o,
output logic [AW-1:0] s0_adr_o,
output logic [DW-1:0] s0_dat_o,
output logic [SW-1:0] s0_sel_o,
input logic [DW-1:0] s0_dat_i,
input logic s0_ack_i, s0_err_i,
// -- slave 1 --
output logic s1_cyc_o, s1_stb_o, s1_we_o,
output logic [AW-1:0] s1_adr_o,
output logic [DW-1:0] s1_dat_o,
output logic [SW-1:0] s1_sel_o,
input logic [DW-1:0] s1_dat_i,
input logic s1_ack_i, s1_err_i,
// -- observation --
output logic [1:0] owner_o, // 0 NONE, 1 M0, 2 M1
output logic dest_o, // decoded destination of the shared req
output logic s_cyc_o, s_stb_o, s_we_o,
output logic [AW-1:0] s_adr_o,
output logic [DW-1:0] s_dat_o,
output logic s_ack_o, s_err_o,
output logic [DW-1:0] s_rdat_o
);
localparam logic [1:0] OWN_NONE = 2'd0;
localparam logic [1:0] OWN_M0 = 2'd1;
localparam logic [1:0] OWN_M1 = 2'd2;
// ── 1. ELIGIBILITY ──
logic [1:0] elig;
assign elig = {m1_cyc_i, m0_cyc_i};
// ── 2/3. SELECTION AND OWNERSHIP (Chapter 17.5, unchanged) ──
logic [1:0] owner_q;
logic own0, own1, cur_cyc, arb_event;
assign own0 = (owner_q == OWN_M0);
assign own1 = (owner_q == OWN_M1);
assign cur_cyc = (own0 && m0_cyc_i) || (own1 && m1_cyc_i);
assign arb_event = (owner_q == OWN_NONE) || !cur_cyc;
logic psel, pvalid, plast;
wb_arb_policy #(.NREQ(2), .POLICY(POLICY)) u_policy (
.clk_i(clk_i), .rst_i(rst_i), .req_i(elig), .commit_i(arb_event),
.sel_o(psel), .valid_o(pvalid), .last_o(plast));
logic [1:0] owner_n;
always_comb begin
owner_n = owner_q;
if (arb_event) begin
if (!pvalid) owner_n = OWN_NONE;
else if (psel) owner_n = OWN_M1;
else owner_n = OWN_M0;
end
end
always_ff @(posedge clk_i) begin
if (rst_i) owner_q <= OWN_NONE;
else owner_q <= owner_n;
end
assign owner_o = owner_q;
// ── 4. FORWARD MUX: one master's whole request context ──
logic s_cyc, s_stb, s_we;
logic [AW-1:0] s_adr;
logic [DW-1:0] s_dat;
logic [SW-1:0] s_sel;
assign s_cyc = (own0 && m0_cyc_i) || (own1 && m1_cyc_i);
assign s_stb = (own0 && m0_stb_i) || (own1 && m1_stb_i);
always_comb begin
if (own0) begin
s_adr = m0_adr_i; s_we = m0_we_i; s_dat = m0_dat_i; s_sel = m0_sel_i;
end else if (own1) begin
s_adr = m1_adr_i; s_we = m1_we_i; s_dat = m1_dat_i; s_sel = m1_sel_i;
end else begin
s_adr = '0; s_we = 1'b0; s_dat = '0; s_sel = '0;
end
end
// ── 5. DECODE: the interconnect's half of the address ──
// "The remaining address bits are decoded by the interconnection system."
// The slave decodes only the offset it needs, which is B3's Partial
// Address Decoding entry and Chapter 12.3's convention.
logic dest;
assign dest = MISROUTE ? (own1 ? ~s_adr[SEL_BIT] : s_adr[SEL_BIT])
: s_adr[SEL_BIT];
assign dest_o = dest;
// ── 6. GATING: exactly one slave sees a cycle ──
assign s0_cyc_o = s_cyc && !dest;
assign s0_stb_o = s_stb && !dest;
assign s1_cyc_o = s_cyc && dest;
assign s1_stb_o = s_stb && dest;
assign s0_we_o = s_we; assign s0_adr_o = s_adr;
assign s0_dat_o = s_dat; assign s0_sel_o = s_sel;
assign s1_we_o = s_we; assign s1_adr_o = s_adr;
assign s1_dat_o = s_dat; assign s1_sel_o = s_sel;
// ── 7. RESPONSE: from the destination, and only the destination ──
logic s_ack, s_err;
logic [DW-1:0] s_rdat;
assign s_ack = OR_ACK ? (s0_ack_i | s1_ack_i)
: (dest ? s1_ack_i : s0_ack_i);
assign s_err = OR_ACK ? (s0_err_i | s1_err_i)
: (dest ? s1_err_i : s0_err_i);
assign s_rdat = OR_DATA ? (s0_dat_i | s1_dat_i)
: (dest ? s1_dat_i : s0_dat_i);
assign s_cyc_o = s_cyc; assign s_stb_o = s_stb; assign s_we_o = s_we;
assign s_adr_o = s_adr; assign s_dat_o = s_dat;
assign s_ack_o = s_ack; assign s_err_o = s_err; assign s_rdat_o = s_rdat;
// ── 8. RETURN: to the owner, and only the owner ──
assign m0_ack_o = (BROADCAST || own0) && s_ack;
assign m0_err_o = (BROADCAST || own0) && s_err;
assign m1_ack_o = (BROADCAST || own1) && s_ack;
assign m1_err_o = (BROADCAST || own1) && s_err;
assign m0_dat_o = s_rdat;
assign m1_dat_o = s_rdat;
endmoduleReading it
Stages 2 and 3 are Chapter 17.5 unchanged — an eligibility vector, a separable policy, an owner register, and an arbitration event that fires only when nobody owns or the owner has released. Nothing about it needed to change to serve two slaves, which is itself the point: arbitration does not know what a destination is.
Stage 5 is Chapter 12.3 reduced to one bit, and the specification is explicit about the split it implements:
Partial Address Decoding — A method of address decoding where each SLAVE decodes only the range of addresses that it requires... The remaining address bits are decoded by the interconnection system.
So the address has two halves with two owners. The interconnect decodes adr[11] and picks a slave; the slave decodes adr[7:0] and picks a word. Neither one decodes the whole address, and B3 lists that as a feature — "Partial address decoding scheme for SLAVEs. This facilitates high speed address decoding, uses less redundant logic and supports variable address sizing and interconnection means."
Stage 6 is three characters wide and does most of the work:
assign s0_cyc_o = s_cyc && !dest;
assign s0_stb_o = s_stb && !dest;The payload fans out to both slaves unchanged. It does not need muxing, because only one slave has CYC_I and RULE 3.30 silences the other. An unselected slave is not outvoted — it is disconnected.
Now the one design decision in this module that deserves an argument, in Stage 7. The response is selected by dest, which is decoded live from the shared address on every clock. There is no destination register.
That is correct here, and the reasoning is specific rather than general. The shared address is the owner's address. RULE 3.25 keeps the owner's CYC_O asserted for the whole cycle and Chapter 17.5's retention rule keeps it the owner for the whole of that; RULE 3.60 has it qualify ADR_O with STB_O. The destination therefore cannot move while a transfer is unanswered, and a register recording it would store what the address already says.
Chapter 18.2 changes the topology and that reasoning stops holding. The invariant is what travels; the implementation trick does not.
4. Simulation — SIM A: The Route Matrix
Four transfers, one at a time: each master to each slave. The log records the origin, the address, the decoded destination, the owner, which slave answered, which master received it, and the data.
=== SIM A - the 2x2 route matrix on a shared bus ===
map: S0 = 0x000..0x0FF, S1 = 0x800..0x8FF, one address bit
S0 returns 0xA0000000+offset, S1 returns 0xB1000000+offset
from addr decoded owner src to read data
M0 0x004 S0 M0 S0 M0 0xa0000004
M0 0x806 S1 M0 S1 M0 0xb1000006
M1 0x00a S0 M1 S0 M1 0xa000000a
M1 0x80c S1 M1 S1 M1 0xb100000c
slave access counts S0 reads 2 S1 reads 2
route provenance violations
wrong destination 0 forward context 0 no route 0
foreign termination 0 data source 0 signature 0Reading it
Four rows, four different routes, and the data proves each one.
M0 → S0 returned 0xA0000004; M0 → S1 returned 0xB1000006. Same master, two destinations, two signatures. M1 → S0 returned 0xA000000A and M1 → S1 returned 0xB100000C — same two destinations, a different master, and the offsets are each master's own.
The owner and to columns agree on every row, which is the return-route half. The decoded and src columns agree on every row, which is the forward half. All four agreements hold, and the eight provenance counters are zero.
S0 reads 2, S1 reads 2 comes from the slaves' own counters rather than from the bus. Each slave saw exactly the two transfers addressed to it and no others — the other two never reached it, because its CYC_I was gated away.
Nothing here is surprising, and that is the point of running it. This is the baseline the next four chapters are measured against, and it is the only simulation in Module 18 in which nothing competes and nothing overlaps.
5. A Shared Bus Is Not One Slave
Worth stating plainly, because the word invites the wrong reading.
"Shared" describes the transfer resource, not the destination. This system has two slaves, a decoder, and four working routes. What is shared is the path they all hang off — and a real SoC shared bus has a dozen slaves on it.
The decode still happens. Every transfer still selects one slave; the others still see CYC_I negated and still contribute nothing. A shared bus and a crossbar decode the same address in the same way — Chapter 18.2 changes where the decode sits relative to the arbitration, not whether it happens.
Everything narrows to one arrow and then widens again. That arrow is the shared resource, and every transfer in the system — from either master, to either slave — passes through it. SIM B is what that costs.
6. Simulation — SIM B: Different Destinations, Same Queue
Now the experiment that creates the need for the next chapter. M0 asks for 0x005, which is S0. M1 asks for 0x807, which is S1. They ask on the same clock.
=== SIM B - different destinations, still serialized ===
M0 asks for 0x005 (S0) and M1 for 0x807 (S1) on one clock.
clk m0_cyc m1_cyc owner S0 active S1 active ACK
1 0 0 - 0 0 -
2 0 0 - 0 0 -
3 1 1 - 0 0 -
4 1 1 M1 0 1 S1
5 1 0 M1 0 0 -
6 1 0 M0 1 0 S0
7 0 0 M0 0 0 -
8 0 0 - 0 0 -
9 0 0 - 0 0 -
clocks with both slave paths active 0
clocks with exactly one active 2
M0 read 0xa0000005 M1 read 0xb1000007
-> the two requests went to different slaves and still
took turns. That is the topology, not the protocol:
"only one MASTER at a time can use the interconnection
resource (i.e. bus)" is a consequence of a shared bus.Reading it — clock 3
Clock 3: both masters assert CYC_O, and neither slave is active. There is one shared path and it has not been granted yet.
Clock 4: the owner is M1, S1 is active, S1 acknowledges. Clock 6: the owner is M0, S0 is active, S0 acknowledges.
Clocks with both slave paths active: 0.
Two requests, two different slaves, two slaves that were both free — and they took turns. S0 was idle for the whole of M1's transfer and S1 was idle for the whole of M0's. Nothing was busy. Nothing was contended. They serialised anyway.
And it is essential to name the cause correctly. No rule was broken. No master waited for a slave. The bottleneck is the single shared request path, and the specification attributes the behaviour to the architecture in exactly those terms:
The shared bus interconnection is a system where a MASTER initiates addressable bus cycles to a target SLAVE... As a consequence of this architecture, only one MASTER at a time can use the interconnection resource (i.e. bus).
"As a consequence of this architecture." Not as a consequence of Wishbone. There is no rule in B3 that serialises anything — a conformant Wishbone system can carry two transfers at once, and Chapter 18.2 measures one that does.
This is a trade-off and not a defect. One arbiter, one decoder, one set of wires, and one place to look when something goes wrong. Chapter 18.4 is where what it costs gets counted structurally, and it does not conclude that shared buses are obsolete.
7. Failure Modes and Discriminating Evidence
SYMPTOM — a master reads plausible-looking data from the wrong peripheral.
Candidates. The decode selected the wrong slave. The response mux selected the wrong slave. The address changed under an open phase.
Discriminating evidence. The signature. With signatured slaves the value names its source; without them, compare the decoded destination against which slave's CYC_I was asserted, and then against which slave terminated. Three separate facts that must agree, and the first pair that disagrees names the stage.
SYMPTOM — a transfer to one address range hangs, others work.
Candidates. The decode produces no select for that range. The selected slave never terminates. The response path for that slave is not connected.
Discriminating evidence. Whether any slave's CYC_I went high. If none did, it is the decode and Chapter 12.6's default-slave question. If one did and nothing came back, it is the return route or the slave.
SYMPTOM — two independent requests serialise unexpectedly.
Candidates. The topology is a shared bus. Or it is nominally a crossbar with a shared internal path.
Discriminating evidence. Per-slave activity on the same clock. SIM B's clocks with both paths active: 0 is the signature of a genuinely shared path. A crossbar claiming concurrency and measuring zero has a shared path inside it, which is Chapter 18.4's false-parallelism case.
SYMPTOM — an unselected slave's registers change.
Candidates. CYC_I not gated by the decode, only STB_I. A decode that overlaps two ranges.
Discriminating evidence. The slave's own write counter against the transfers addressed to it. RULE 3.30 makes a slave silent when CYC_I is negated; a slave that acted anyway either received CYC_I or is itself defective.
8. Common Mistakes
"An interconnect is just an address decoder."
Why it is wrong: the decoder answers one of four questions. Ownership, forward routing and return routing are the other three, and Chapter 18.3 measures a system with a perfect decoder that is still broken.
"A shared bus can only have one slave."
Why it is wrong: SIM A has two and four working routes. "Shared" is about the path, not the destination.
"Two masters targeting different slaves always run in parallel."
Why it is wrong: SIM B. Both slaves free, both requests independent, zero overlap. Parallelism is a property of the topology, and a shared bus does not have it.
"Serialisation on a shared bus is a Wishbone limitation."
Why it is wrong: it is a consequence of choosing a shared bus, and the specification's glossary says so in those words. B3 contains no rule about concurrency at all — none permitting it, none forbidding it.
"The decode has to happen in the interconnect."
Why it is wrong: it is split. B3's own cycle walkthroughs say "SLAVE decodes inputs, and responding SLAVE asserts [ACK_I]" twelve times, and its Partial Address Decoding entry says the interconnection system decodes the remaining bits. Both are true, of different halves of the address.
"If the address decodes correctly, the transfer is correct."
Why it is wrong: the decode is a decision. Routing is whether the decision was carried out, in both directions. Chapter 18.3 separates them and breaks the second while leaving the first intact.
9. Interview Reasoning
"What does an interconnect actually have to preserve?"
Four agreements: ownership, destination, forward route, return route — and that they all describe the same transaction. A decoder alone preserves one of them.
"Why can a shared bus serialise transfers to independent slaves?"
Because the resource that is shared is the request path, not the destination. Both slaves may be free; there is still one set of wires between the masters and the decoder, and one owner of it.
"Is that a protocol limitation?"
No. The specification attributes it to the architecture — "as a consequence of this architecture" — and names four other interconnection means in the same feature list. A conformant Wishbone system can carry concurrent transfers.
"Where does the address get decoded?"
In two places, deliberately. The interconnection system decodes the bits that choose a destination; the slave decodes the bits that choose a register. B3 calls this Partial Address Decoding and lists it as a feature. Asking which one "the" decoder is misses the split.
"You are handed a two-master, four-slave shared bus and told a transfer goes to the wrong peripheral. What do you look at first?"
Three facts, in order: the decoded destination, which slave's CYC_I actually asserted, and which slave terminated. The first disagreement names the stage. Starting at the slave wastes time — it performed the transfer it was given.
10. Understanding Check
In SIM B both slaves were idle and both requests were independent. Why did they still take turns?
One shared request path. Ownership is granted to one master at a time, and until M1 released it, M0's request reached no decoder at all — so S0 never saw it.
SIM A shows S0 reads 2 from the slave's own counter. Why is that a stronger statement than counting bus acknowledgements?
Because it is the resource's view, not the path's. A bus counter says how many terminations happened; the slave's counter says how many transfers it actually performed. Chapter 18.3 shows a system where those two numbers differ.
The response mux here is a live decode with no destination register. When would that stop being safe?
When the address feeding the decode is no longer guaranteed to be the one belonging to the open transfer. Here it is the owner's, and the owner is retained for the whole cycle. Change the topology so a master can be waiting at one slave while another slave answers somebody else, and the reasoning collapses — which is Chapter 18.2.
A colleague proposes removing the CYC gating and decoding only STB. What breaks?
RULE 3.30 stops protecting you. A slave whose CYC_I is asserted may respond to its other inputs; the rule that keeps an unselected slave silent is specifically about CYC_I. Gating only STB leaves every slave nominally in a cycle.
11. What's Next
One path, correctly shared, with four working routes and no concurrency at all.
What has to change structurally before two independent transfers can proceed at the same time?
Chapter 18.2 — Crossbar Concepts moves the decode in front of the arbitration and replicates the arbitration per destination. Two slaves acknowledge two different masters on the same clock — and then the same crossbar, given the same destination twice, serialises exactly as before.
Continue learning
Related tutorials
- Related topic
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.
- Related topic
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.
- Related topic
CPU to Peripheral Communication
A CPU reaches hardware outside itself by reading and writing addressed locations, and a peripheral is hardware it cannot execute. Everything a driver does has to be expressed as a read or a write of a location the peripheral answers for — and once more than a couple of peripherals exist, wiring each one to the core separately stops scaling. That is the problem an on-chip bus is the answer to.
- Related topic
Need for Standardized Interconnects
An address map answers where a register lives. It says nothing about which wires carry the request, when they are valid, how the target reports completion, or what happens on an error. Three peripherals with three private interfaces produce three adapters, three verification efforts and three ways to be wrong — which is the argument for standardising the interface rather than the map.
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.
