Wishbone · Module 28
Intermediate Questions
Three flawed slaves, three waveform predictions, and the measurement that shows one write committing four times while every Wishbone rule is obeyed.
Chapter 28.1 was about describing the interface. This chapter is about predicting what a given piece of RTL will actually do — which is the first point in a Wishbone interview where memorisation stops working entirely.
The questions here all have the same shape: here is something that looks fine. Run it in your head.
1. Why A Zero-Wait Slave Hides Bugs
What the question tests: whether you understand that a phase without wait states has no interior.
Look at this and say what is wrong with it.
logic commit;
assign commit = WRITE_ON_STB ? (present && we_i) : (ack_o && we_i);INTERVIEW REVIEW EXAMPLE — the WRITE_ON_STB branch is intentionally broken.
The broken branch commits on every clock the request is presented. The correct branch commits on the clock it is accepted. At zero wait states those are the same clock and the two branches are indistinguishable — not hard to tell apart, identical.
Here is the same slave, same program — one write to a register that increments on every committed write, then a read back:
rig transfers commits value read back
correct, WAITS=3 2 1 1
WRITE_ON_STB, WAITS=0 2 1 1
WRITE_ON_STB, WAITS=3 2 4 4
commits per write correct 1 broken@0 1 broken@3 4Three rigs. The broken one at zero waits is byte-identical to the correct one. Add three wait states and the same RTL commits four times.
Two things to take from the table. First, the transfer count is 2 in every row — a termination census cannot see this defect at all. Second, the reason a storage register would have hidden it even at three waits: writing 0xA1B2C3D4 four times leaves 0xA1B2C3D4. The defect is only observable through something not idempotent, which is why the register under test increments.
A design that passes only at zero latency has not been tested. It has been avoided.
2. Partial Writes, And Why The Bug Escapes
Q. What does SEL_O() do, and how would a byte-lane bug get through your test suite?
SEL_O() indicates which lanes carry valid data. Chapter 13.3 built the merge. The interview question is the second half.
Consider a slave that ignores SEL_I and writes all four lanes:
for (b = 0; b < SW; b = b + 1)
if (IGNORE_SEL || sel_i[b])
mem[widx][b*8 +: 8] <= dat_i[b*8 +: 8];INTERVIEW REVIEW EXAMPLE — IGNORE_SEL is intentionally broken.
Q. Which test exposes it? Not the obvious one. A single-lane write of zeros into a location that already holds zeros produces the correct answer whether the mask is honoured or not. The stimulus hits the partial-write case, a coverage model records the bin as covered, and the defect walks through.
The test that exposes it needs a non-zero background: seed the word, write one lane, read it back. The measured control case from Chapter 28.1 — 0xA1B2C3D4 seeded, lane 1 written with 0xBB, read back 0xA1B2BBD4 — is exactly that shape, and every other lane in it is a live witness.
Coverage says the situation occurred. It does not say the stimulus was sensitive to the bug.
3. Retry Is A Termination, Not A Wait
Q. How is RTY different from waiting? What state may advance when you receive one?
Waiting is the absence of an answer. RTY is an answer: the phase is over, STB_O may be negated, the bus is free. And the operation did not happen.
So the split is:
| may advance | must not advance |
|---|---|
| anything counting phases | anything counting work done |
| a retry counter, a backoff timer | the operation index, a data pointer, a byte count |
Here is a driver that gets it wrong in one line, and one that does not:
// THE ONE LINE. On RTY the retry-aware driver leaves the
// operation index exactly where it was, so the next request it
// presents is the same request. The broken driver advances and
// reports work that never happened.
if (is_rty && RETRY_AWARE) begin
idx_q <= idx_q;
end else begin
idx_q <= idx_q + 5'd1;
ndone_q <= ndone_q + 16'd1;
endFour operations; the memory answers RTY once, on its third transfer. Predict both rigs before looking.
driver attempts operations done RTY seen phases at the pins
retry-aware 5 4 1 5
RTY = done 4 4 1 4
terminations at the master port
driver ACK RTY ERR
retry-aware 4 1 0
RTY = done 3 1 0
memory writes committed retry-aware 3 RTY = done 2
word at 0x0104 retry-aware 0x33330000 RTY = done 0x22220000Note the ACK column, taken from a raw-pin census rather than from the driver being judged: 4 versus 3. The broken driver claims four operations and the pins recorded three successful ones. That single discrepancy is the whole diagnosis, and it is available without opening a waveform.
Note also what is not wrong: neither driver violates the protocol. B3 does not require a master to persevere. What the broken one does is claim an operation completed when the bus said otherwise — and when and how to retry is explicitly supplier-defined, which means it is your specification that this driver violates, not Wishbone's.
4. What Changes When ACK Is Registered
Q. You move ACK_O behind a flip-flop. What changes?
A weak answer: "it gets slower." A better one names both halves.
What changes architecturally: nothing. Same target, same operation, same committed data, same termination class.
What changes in clocks: one extra per transfer, because the master cannot see the answer until the clock after the slave decided it.
What changes in timing: the combinational path from the master's STB_O through the slave's termination logic and back to the master's ACK_I is broken. That path is real, and the specification names it:
OBSERVATION 3.50 — In large high speed designs the asynchronous assertion ... could lead to unacceptable delay times, caused by the loopback delay from the MASTER to the SLAVE and back to the MASTER.
Chapter 28.4 measures the clock half and says plainly which half was not measured.
5. Three Waveform Predictions
6. Decoding, Safely
Q. How do you decode address ranges without introducing an aliasing bug?
The mechanism is Chapter 12.3. The interview question is what makes one decoder trustworthy and another not, and it comes down to two things you can state in a sentence each.
Compare the full width. Here is the compare, with both defects a decoder of this shape can carry:
logic [AW-1:0] cmp_mask0, cmp_mask1, cmp_adr;
assign cmp_mask0 = WINDOW_WIDE ? (S0_MASK[AW-1:0] & ~16'h0100)
: S0_MASK[AW-1:0];
assign cmp_mask1 = S1_MASK[AW-1:0];
assign cmp_adr = ADDR_TRUNCATE ? {{(AW-8){1'b0}}, oadr[7:0]} : oadr;
logic hit0, hit1;
assign hit0 = ((cmp_adr & cmp_mask0) == (S0_BASE[AW-1:0] & cmp_mask0));
assign hit1 = ((cmp_adr & cmp_mask1) == (S1_BASE[AW-1:0] & cmp_mask1));INTERVIEW REVIEW EXAMPLE — WINDOW_WIDE and ADDR_TRUNCATE are intentionally broken.
A compare that silently drops high bits does not produce a missing region — it produces an extra one. Addresses that belong nowhere start matching somewhere. With the windows at 0x0000–0x00FF and 0x0100–0x01FF, work out which addresses each defect misroutes before reading on; the two defects agree on the one address a bug report would quote, and disagree on exactly one other.
address expected decoder 1 decoder 2 d1 multi-select
0x0000 S0 regs S0 regs S0 regs no
0x00ff S0 regs S0 regs S0 regs no
0x0100 S1 mem S0 regs S0 regs YES
0x01ff S1 mem S0 regs S0 regs YES
0x0200 unmapped unmapped S0 regs no
0x0300 unmapped unmapped S0 regs no
0x1000 unmapped unmapped S0 regs no
target mismatches decoder 1 4 decoder 2 7
multi-select events decoder 1 4 decoder 2 0
protocol violations decoder 1 P0 0 P2 0 decoder 2 P0 0 P2 00x0200 is the discriminating address, and it is not the one that reproduces the bug. A widened window still ends at 0x01FF, so 0x0200 remains unmapped; a truncated compare discards the high byte, 0x0200 becomes 0x0000, and the register window claims it. Sweep window boundaries, not typical addresses. Neither decoder violates a single rule.
Report overlap. If two regions can claim one address, first-match-wins resolves it deterministically and silently. The shadowed peripheral does not complain; it simply stops receiving traffic. A decoder that cannot report multi-select cannot tell you this happened.
// An overlap that first-match-wins makes SILENT. A widened window
// does not announce itself as a collision; it simply shadows its
// neighbour, and this is the only wire that says so.
assign p2_multi_o = present && hit0 && hit1;Q. What happens on an unmapped address? Whatever you decided. B3 defines nothing. A default responder answering ERR is the only one of the three common policies that tells anybody — and it is a policy, so say so.
7. Read-Modify-Write And The Word "Indivisible"
Q. Does an RMW cycle guarantee atomicity?
This is the intermediate question most likely to catch a well-read candidate, because the specification's own section opens with:
"The RMW (read-modify-write) cycle is used for indivisible semaphore operations."
That is a statement of purpose. Section 3.4 provides no locking mechanism, no arbitration rule and no protection guarantee. What RULE 3.85 and §3.4 actually define is a structure: one CYC_O spanning a read transfer and a write transfer.
So the honest decomposition has three parts, and a strong answer gives all three:
- Protocol —
CYC_Oheld across both halves. This is all Wishbone defines. - Arbiter — exclusivity additionally requires an arbiter that honours
CYC_Ias a bus claim. RECOMMENDATION 3.05 says arbitration logic "often usesCYC_Ito select between MASTER interfaces." Often, not must. - Target — and no second port into the slave. Chapter 4.9 measured a lost update with
CYC_Oheld perfectly, through a dual-port slave.
Never say "holding
CYC_Omakes it atomic." Say: holdingCYC_Ois the protocol half; exclusivity also needs an arbiter that honours it and a target with no back door.
8. Designing For Arbitrary Latency
Q. How would you write a master that tolerates any slave latency?
The answer is a state machine with one property: nothing that belongs to the request is re-derived while the phase is open. Capture the request when you issue it, drive the captured copy, and change nothing until a termination arrives.
The dashed return edge is the RTY path from Section 3: back to PRESENT with the same captured request, not back to IDLE to fetch a new one.
An interviewer will push on the capture: "why not just drive the client's signals directly?" Because the client is not bound by RULE 3.60. It may withdraw, change its mind, or be a FIFO that pops. The register is what converts an unconstrained client into a conformant master.
9. Three Code Reviews In One Sitting
Given ten minutes and three snippets, what do you say about each?
| snippet | the defect | the discriminating test |
|---|---|---|
commit keyed to stb_i | commits once per presented clock | run it with wait states against a non-idempotent register |
| byte lanes ignored | partial writes overwrite untouched lanes | seed non-zero, write one lane, read back |
RTY treated as completion | work counted that did not happen | compare driver completions against a raw-pin ACK census |
Notice what the third column has in common: none of the three defects is found by the test that reproduces the symptom. Each is found by a test constructed so that the defect and the correct behaviour must disagree.
10. What To Carry Forward
- Zero latency is not a test configuration, it is a blind spot. Two of this chapter's three defects are structurally invisible there.
- Commit on the termination. Then find a non-idempotent location and prove it.
RTYends the phase and not the work. Phases may advance; work may not.- A coverage hit is not sensitivity. Seed non-zero before you believe a byte-lane test.
- RULE 3.60 binds the master, not the interconnect. The same property can be clean at one boundary and broken at another.
- RMW is a structure, not a guarantee. Protocol, arbiter, target — all three or none.
- Capture the request. A wait-tolerant master is one with nothing live left to change.
Chapter 28.3 adds a second master, an interconnect, and the question of whether the transfer that completed was even yours.
Continue learning
Related tutorials
- Related topic
Temporary Resource Unavailability
A full queue can be answered with wait states or with RTY. Measured against the same condition: 11 clocks of bus occupancy and one attempt, against 4 clocks and four attempts.
- Related topic
Bus Transactions
A transaction is the unit of bus work: one beginning, one ending, and an interval in between during which the request must not move. Making waiting expressible is what lets a slow target share a bus with a fast one, and it is what turns an initiator from a wire into a state machine with real failure modes.
- Related topic
ACK_I
The only mandatory termination. What a slave promises by asserting it, how wait states work without a wait signal, and why RULE 3.55 requires a master to keep working when a slave holds it asserted.
- Related topic
RTY_I
A slave saying "not now" rather than "no". Unlike a wait state it releases the bus, which breaks a whole class of deadlock — and unlike an error it invites another attempt, which is what makes livelock possible.
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.
