Wishbone · Module 11
Real Examples
Five realistic conditions classified, and the one observation that separates a retry loop from a long wait: ten presentations against one, over the same thirty clocks.
Chapter 11.4 completed the mechanism. Every experiment so far was engineered to isolate one property — one deferral, one parameter, one defect.
Given a failing or stalled access, which of these is it — and which of them should be retried at all?
1. The Classification That Matters
The useful question is not "did it fail" but "will the same request behave differently later".
ERR answers no by definition. The target examined the request and refused it. Chapter 10.1 framed this as: ERR says something about your request. Nothing about the target's state will change that.
RTY answers possibly. The target said it is not ready — a statement about itself. It did not promise to become ready, which is why Chapter 11.2 bounds the attempts.
And three outcomes reach a client, not two. This is where the two-level model earns its keep:
| Client outcome | Bus evidence | What it means | Next step |
|---|---|---|---|
| success | an attempt was ACKed | done | proceed |
| failure | an attempt was ERRed | the request is wrong | fix the request |
| exhausted | every attempt RTYed | no bus event at all | back off, or escalate |
Exhaustion has no representation on the bus. No slave asserted it; it exists only inside the master. A system that does not expose it cannot recover the distinction afterwards — the trace shows N deferrals and then silence.
2. Why Exhaustion Must Not Be Reported as an Error
They lead to opposite actions, which is the practical case for keeping them apart.
An ERR means stop asking. Retrying gets the same answer; the fix is in the request — a wrong address, an illegal operation, a misconfigured map.
An exhaustion means the answer is still unknown. The operation may be entirely valid and may succeed a microsecond later. The fix is in the budget, the cadence, or the resource — not in the request.
And the investigations diverge immediately. An ERR sends an engineer to the target's decode and register map. An exhaustion sends them to the resource and to MAX_RETRIES. A merged report picks the wrong one half the time.
The hazard is worse in software than in hardware. A driver that sees "failed" for a transient queue-full condition may disable a working peripheral, where the correct response was to wait a moment and try again.
Where collapsing them is legitimate: a client with genuinely no way to re-queue work — a fixed-latency pipeline stage. Then converting exhaustion to a failure is a deliberate adaptation, and RULE 2.15 requires it to be documented. What is not legitimate is doing it because the contract only had two bits.
3. RTL — Attempt-Level Instrumentation
Section 5's question — "is this a retry loop or one long wait?" — cannot be answered from the client contract, because both look like an operation that has not finished. It needs the bus.
// wb_retry_probe — attempt-level instrumentation for a retrying system.
//
// SIMULATION AND DEBUG ONLY. Not synthesisable as written, and not a
// Wishbone feature.
//
// WHY IT EXISTS. From software's point of view a stalled access looks the
// same whether it is one long transfer, a stream of deferrals, or a policy
// that has already given up. Those have different causes and different
// fixes, and the bus alone does not separate them — so the probe counts
// what the bus carries and the master's contract reports what it does not.
//
// It classifies the CLIENT REQUEST, not the bus attempt, which is the
// two-level distinction Chapter 11.1 introduced:
//
// SUCCESS an attempt was acknowledged
// FAILURE an attempt was refused with ERR
// EXHAUSTED every allowed attempt was deferred
// OUTSTANDING still running when the observation window closed
//
// And it separates the two shapes that look identical from far away:
//
// one long transfer presentations = 1, waiting clocks large
// a retry loop presentations = N, each one short
//
// EVERYTHING HERE IS LOCAL DEBUG INSTRUMENTATION. A system that exposes
// none of it can report only that something is stuck.
// ─────────────────────────────────────────────────────────────────────────
module wb_retry_probe (
input logic clk_i,
input logic rst_i,
// the master's bus port
input logic cyc_i,
input logic stb_i,
input logic ack_i,
input logic err_i,
input logic rty_i,
// the master's client contract
input logic busy_i,
input logic done_i,
input logic ok_i,
input logic err_rep_i,
input logic exh_i,
output int unsigned presentations_o, // STB_O rising edges = attempts
output int unsigned pres_clocks_o, // clocks spent presenting
output int unsigned gap_clocks_o, // busy but presenting nothing
output int unsigned n_ack_o,
output int unsigned n_err_o,
output int unsigned n_rty_o,
output int unsigned n_success_o,
output int unsigned n_failure_o,
output int unsigned n_exhausted_o
);
logic stb_q;
always_ff @(posedge clk_i) begin
if (rst_i) begin
stb_q <= 1'b0;
presentations_o <= 0; pres_clocks_o <= 0; gap_clocks_o <= 0;
n_ack_o <= 0; n_err_o <= 0; n_rty_o <= 0;
n_success_o <= 0; n_failure_o <= 0; n_exhausted_o <= 0;
end else begin
stb_q <= stb_i;
// ── ATTEMPT COUNTING. A rising edge of STB_O is a new attempt,
// which is why the gap between attempts has to exist: without
// it there is no edge and no second attempt to count.
if (stb_i && !stb_q) presentations_o <= presentations_o + 1;
if (cyc_i && stb_i) begin
pres_clocks_o <= pres_clocks_o + 1;
if (ack_i) n_ack_o <= n_ack_o + 1;
if (err_i) n_err_o <= n_err_o + 1;
if (rty_i) n_rty_o <= n_rty_o + 1;
end
// Busy but presenting nothing: the retry gaps.
if (busy_i && !stb_i) gap_clocks_o <= gap_clocks_o + 1;
// ── CLIENT-REQUEST OUTCOMES, from the master's contract. None of
// these is a bus signal; exhaustion in particular has no bus
// representation at all.
if (done_i) begin
if (ok_i) n_success_o <= n_success_o + 1;
if (err_rep_i) n_failure_o <= n_failure_o + 1;
if (exh_i) n_exhausted_o <= n_exhausted_o + 1;
end
end
end
endmoduleReading it
presentations_o counts STB_O rising edges, and that choice is the whole instrument. An attempt is a presentation; counting RTY_I assertions instead would give the same number here and the wrong number against a master that failed to release — which is exactly the case worth detecting.
It also depends on the gap existing. Chapter 11.4 §1 showed that without a non-presented clock there is no rising edge and no second attempt. The counter and the protocol agree on what an attempt is.
gap_clocks_o counts busy-but-not-presenting, which is the retry cadence made visible. A large gap count with few presentations is a slow retry; a small one with many is a busy-wait.
The three client counters come from the master's contract, not the bus. n_exhausted_o in particular cannot be derived from any bus signal — it is the master reporting its own policy is spent.
Everything here is local debug instrumentation. int unsigned counters are simulation constructs; a silicon version would be narrow counters behind a status register. None of it is a Wishbone feature, and a system that exposes none of it can report only that something is stuck.
4. Simulation — SIM I: Five Conditions
One retry master with MAX_RETRIES = 3 against the COMMAND FIFO at DEPTH = 1. The queue is drained between two of the accesses, so the same write meets a full queue once and an empty one later.
=== SIM I - five conditions, classified ===
one retry master (MAX_RETRIES=3) against the COMMAND FIFO,
DEPTH=1. The queue is drained between some accesses.
condition attempts RTY verdict
read ID normal 1 0 SUCCESS
write COMMAND space free 1 0 SUCCESS
write COMMAND full, no drain 4 4 EXHAUSTED
write COMMAND full, drained first 1 0 SUCCESS
read word 7 not implemented 1 0 FAILURE
totals attempts 8 ACK 3 ERR 1 RTY 4
client success 3 failure 1 exhausted 1
FIFO pushes 2 last command 0xc0de0003Three verdicts from five accesses, and the attempts column explains each.
The two SUCCESS rows with one attempt each are the uninteresting case, and worth noting for that reason: a retry-capable master costs nothing when nothing defers. Its machinery is invisible.
Row three is the retry case that did not pay off. Four attempts, four deferrals, EXHAUSTED — the queue was full and nothing drained it. MAX_RETRIES = 3 gave four attempts, exactly as Chapter 11.2 §3 defined.
Row four is the same write against a drained queue: one attempt, SUCCESS. Identical request, identical master, opposite outcome — because the resource's state changed, which is precisely what RTY was reporting.
Row five is the case retry cannot help. One attempt, zero deferrals, FAILURE. The target refused the request rather than deferring it, and re-issuing would have produced the same refusal four times.
Read the totals as the two-level model. Eight bus attempts served five client requests. RTY = 4 against exhausted = 1 — four deferrals produced one exhausted request, which is the arithmetic a system that counts only transfers cannot reconstruct.
And pushes = 2 against three COMMAND writes. The exhausted write enqueued nothing across all four of its attempts — the side-effect contract from Chapter 11.4 holding across a full exhaustion, not just across a single deferral.
5. Simulation — SIM J: A Retry Loop or a Long Wait?
From software, a stalled operation looks the same either way — it has not completed. The two systems below are given the same permanently-full resource and observed for the same thirty clocks.
=== SIM J - a retry loop and a long wait, from evidence ===
both targets are permanently full; observed for 30 clocks.
rig presentations presenting gap clocks RTY outcome
retrying 10 10 18 10 EXHAUSTED
waiting 1 30 0 0 still outstanding
presentations separates them: many short attempts vs one long one.One number separates them: presentations. Ten against one.
The retrying rig made ten attempts — ten STB_O rising edges, ten clocks presenting, ten deferrals, eighteen clocks in the gaps. And it finished, reporting EXHAUSTED, because MAX_RETRIES = 9 bounded it.
The waiting rig made one attempt and was still presenting it after thirty clocks. Thirty clocks presenting, zero gap clocks, zero terminations of any kind.
Both look identical from the client. Neither operation completed successfully; neither returned data. A driver polling for completion sees the same nothing.
On the bus they are not remotely alike. Ten cycles of the same two rigs, drawn at the cadence the counters above measured — one clock presenting, two clocks released, against one presentation that never ends:
Ten attempts, or one that has not finished
10 cyclesR is the retrying rig, W the waiting one. Count rising edges on STB_O: three against one, in ten cycles. The counters in Section 3 report the same fact over thirty.
The two clocks where R drives nothing are the point of the whole module. They are the release that makes the next assertion a new transfer, and they are also the only clocks in this figure where any other master could have used the bus.
Reading a trace you were not given the answer to
The discriminators, in the order that costs least:
| Observation | Retry loop | Long wait |
|---|---|---|
STB_O rising edges | many | one |
| clocks presenting | few, in bursts | continuous |
| gap clocks | many | zero |
RTY_I seen | yes | no |
| bus available to others | mostly | never |
STB_O rising edges is the first thing to count, because it is unambiguous and needs no knowledge of the design. Many rises means many transfers; one rise means one transfer that has not ended.
And it distinguishes a third case that looks like both. A master that received RTY_I and failed to release shows one rising edge with RTY_I asserted across many clocks — the "retry as a wait state" bug from Chapter 11.2 §10. Counting RTY_I assertions would report that as ten attempts; counting rising edges correctly reports one.
The bus available row is why anyone cares. In the waiting column no other master ran for thirty clocks. If the thing that would drain this queue is another master, those are thirty clocks in which the system was deadlocked rather than merely slow — the structural hazard Chapter 4.12 §1 works in full.
6. The Full Debugging Path
A client operation has not completed. Four questions, in order of what each eliminates. This extends Chapter 10.5's procedure rather than replacing it.
Q1 — Did the client operation complete at all?
Yes → go to Q2. No → go to Q3.
Q2 — Which outcome?
success → not an error-handling problem; if the result is wrong, Chapter 9.5's data questions apply.
failure → a target refused it. Chapter 10.5's provenance question: which component generated the ERR?
exhausted → no target refused anything. Every attempt was deferred. Go to Q4.
Q3 — How many presentations?
One → one transfer, still outstanding. Is the target progressing? (Chapter 9.5) Is anything selected? (Chapter 10.3) Is the master failing to release after an RTY?
Many → a retry loop in progress. Go to Q4.
Q4 — Is the resource's ready condition changing?
Yes, occasionally → the cadence or the budget is mistuned. RETRY_DELAY or MAX_RETRIES.
No, never → retry is the wrong mechanism for this condition. Either the resource is genuinely stuck, or it needs something the retrying master is preventing — which in a shared-bus system is often the retrying master's own traffic.
What this procedure deliberately does not do is start at the target. Three of the four questions are answered from the master's contract and the bus, and in the exhausted and unmapped cases the target is entirely innocent.
7. Failure Modes and Discriminating Evidence
Symptom: software reports a device failure for a condition that is transient.
Candidate causes. Exhaustion collapsed into the error path, or a slave answering a busy resource with ERR_O.
Discriminating evidence. Client failures against bus ERR terminations. Failures exceeding errors means exhaustion is being reported as failure — no target refused anything.
Why it matters: the two lead to opposite responses. One says fix the request; the other says wait and try again.
Symptom: the bus is saturated and nothing completes.
Candidate causes. A retry loop against a resource that cannot clear, possibly because the retry traffic is itself preventing the drain.
Discriminating evidence. Presentations against successful completions, and whether the resource's ready condition ever changes. Ten attempts and no change is a livelock, not a slow system.
The fix is rarely a longer budget. If the condition never clears, more attempts reach the same place later.
Symptom: an operation is stuck and the bus looks idle.
Candidate causes. One long outstanding transfer — a waiting slave, or a master that failed to release after an RTY.
Discriminating evidence. STB_O rising edges: one. Then check whether RTY_I is asserted alongside the held STB_O, which identifies the non-releasing master specifically.
Symptom: a system works in isolation and deadlocks when a second master is added.
Candidate causes. A waiting slave whose resource is drained by that second master.
Discriminating evidence. One master holding CYC_O indefinitely while the drainer is starved of grants. Chapter 11.3 §1's question is the diagnostic, and the answer is to defer rather than to wait — no tuning fixes it.
8. Common Mistakes
"Retry is a general recovery mechanism."
Wrong mental model: anything that failed can be retried.
What is true: it addresses one condition — a resource that clears without the requester changing anything. Measured: of five conditions, one benefited, one was exhausted by it, and three were unaffected.
Concrete bug: retrying an ERR, which produces the same refusal repeatedly and converts a clean failure into latency.
Correct model: ask whether the same request will behave differently later. ERR answers no by definition.
"Exhaustion is a kind of error."
Wrong mental model: both are non-success, so both are failure.
What is true: no target refused anything. Every attempt was deferred; the master's own budget ran out. The operation may be valid and may succeed immediately afterwards.
Concrete bug: a driver disabling a working peripheral because a transient queue-full condition was reported as a device fault.
Observable evidence: client failures exceeding bus ERR count.
Correct model: three outcomes, not two. And exhaustion has no bus representation, so a system that does not expose it cannot recover the distinction.
"Many RTYs on a trace means many attempts."
Wrong mental model: counting the deferrals counts the attempts.
What is true: only if the master releases. A master holding STB_O after an RTY collects many RTY_I assertions across one transfer — and RULE 3.50 means the slave asserts it for as long as the request is presented.
Observable evidence: STB_O rising edges. Ten rises is ten attempts; one rise with RTY_I held is a master that never released.
Correct model: count presentations, not terminations.
"A busier bus means the system is making progress."
Wrong mental model: activity implies work.
What is true: measured — ten presentations, ten deferrals, zero commands enqueued. A livelocked retry loop is the busiest the bus ever looks.
Observable evidence: attempts against successful completions, and whether the resource's state changes.
Correct model: progress is measured in completed client operations, not in transfers.
9. Interview Reasoning
Count STB_O rising edges. One is a single outstanding transfer; many is a retry loop — and that one observation needs no knowledge of the design.
Why it works. Every attempt is a separate transfer, which means a separate presentation, which means a rising edge. A waiting transfer is presented once and held. I measured both against the same permanently-full resource over thirty clocks: ten presentations against one.
The supporting evidence lines up behind it. The retry rig spent ten clocks presenting and eighteen in gaps; the waiting rig spent all thirty presenting with no gaps at all. And the retrying one finished — reporting exhaustion, because its budget was bounded — while the waiting one was still outstanding when the window closed.
Why I would not count RTY_I assertions instead, which is the obvious alternative: it gives the right answer for a correct master and the wrong answer for a broken one. A master that fails to release after an RTY holds STB_O, and RULE 3.50 means the slave keeps asserting RTY_O — so you would count ten deferrals across one transfer and conclude the retry machine was working. Rising edges distinguish all three cases.
Then the follow-up question depends on which it is. Many presentations: is the resource's ready condition ever changing? If not, it is a livelock and more retries will not help. One presentation: is the target progressing — Chapter 9.5's latency-counter question — and is anything even selected, which is Chapter 10.3's.
And the reason it matters beyond diagnosis: in the waiting case, no other master ran for thirty clocks. If the thing that would drain the resource is another master, that is a deadlock rather than a delay.
10. Understanding Check
11. What Module 11 Established
| Chapter | What it added |
|---|---|
| 11.1 | RTY as a termination class; the resource that can say not now |
| 11.2 | every attempt is a separate transfer; request identity; MAX_RETRIES |
| 11.3 | wait or defer, measured: 11 clocks of occupancy against 4 |
| 11.4 | the irreducible gap; RETRY_DELAY; side-effect safety |
| 11.5 | classification, and the evidence that separates the failure shapes (this chapter) |
The module's central claim: RTY ends the attempt. If the operation happens again it happens in a new transfer, with the same identity and a fresh termination — and the client hears one outcome however many attempts it took.
What the specification actually provides. A third termination class, qualified like the others (RULE 3.35), exclusive with them (RULE 3.45), negated with STB_I (RULE 3.50), optional on both sides (PERMISSION 3.25), meaning "the interface is not ready to accept or send data, and the cycle should be retried" — with when and how supplier-defined and RULE 2.15 making that definition mandatory to publish.
What it does not provide, and this module measured all four: no obligation to retry, no guarantee the next attempt succeeds, no required retry delay, and no promise that a deferred attempt changed nothing. That last one is a target contract, and Chapter 11.4 measured a target that broke it turning one write into three.
What Module 11 did not do. It never routed a request by address, never arbitrated between masters, and never selected byte lanes. Module 12 owns address decoding, Module 13 byte selects, Module 17 arbitration. Retry was measured against a single master and a single target throughout, and Section 9's last answer marks where that stops being adequate.
How does a transfer reach the right target in the first place?
Module 12 — Address Decoding takes it up. It has not shipped yet, which is why it appears in bold rather than as a link. The full path is on the Wishbone curriculum index.
Continue learning
Related tutorials
- 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.
- Related topic
Debug Strategies
Four error sources arrive at the client as the same bit. A measured probe separates them from three local signals — and exposes two ways the evidence itself can mislead.
- Related topic
Data Flow
One Wishbone access, followed through every block in both directions: what the master drives, where the address changes form, which signals are broadcast and which are decoded, and how read data and termination find their way back to exactly one requester.
- Related topic
DAT_O
Both masters and slaves have a DAT_O, and they mean opposite things. What each must drive, when it must be valid, and why a master may legally leave stale write data on the bus during a read.
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.
