Skip to content
VLSI Mentor

Wishbone · Module 10

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.

Module 10 has built three components that can fail an access, and they all report it identically.

A transfer failed. Which component decided that, and how do you find out?

1. The Debug Tree

Four questions, in order of what each one eliminates. This extends Chapter 9.5's procedure rather than replacing it — the first question is the same one.

Q1 — Did a termination occur at all?

No → this is not an error, it is an absence. Go to Q2. Yes → go to Q3.

Q2 — Is anything selected?

Nothing selected → the address reached no target. A decode or software address bug, and the peripheral is entirely innocent — it never saw the access. Chapter 10.3's SIM F. Something selected → the target has it. Is its latency counter progressing? Progressing means slow; stuck means Chapter 9.5's hang.

Q3 — Which class?

ACK → the transfer succeeded. If the result is wrong, this is not an error-handling problem — go to Chapter 9.5's stale-data and commit questions. And check the master is not misreporting: compare client successes against bus ACK count. ERR → go to Q4. RTYModule 11, which has not shipped.

Q4 — Who generated the ERR?

This is the question the bus cannot answer, and Section 3's probe answers it from three local signals:

EvidenceSource
watchdog expired assertedtimeout — nothing refused anything
default responder selectedunmapped address
peripheral selectedthe peripheral refused — its register or its operation
none of the abovethe model is wrong; investigate the probe

Note the priority. expired is tested first, because a watchdog error is generated at the guard and the select lines beneath it may still show whatever the decoder was doing. The error did not come from there, and classifying by select alone would blame the wrong component.

2. Provenance Is Designed In

The reconstruction in Section 3 works because three signals happen to exist. None is a Wishbone signal; all three were added for other reasons and turn out to carry the answer.

sel_periph / sel_default exist because a decoder must select something. expired exists because a watchdog must decide something. Latency is derivable from the bus.

A system that exposes none of them can report only that something failed. That is the practical content of "the source of the error is defined by the IP core supplier": the supplier decides, and if the supplier does not also publish it, nobody downstream can recover it.

The three cheapest instruments, in order of value:

A default-responder hit counter. Non-zero means software addressed something that does not exist. It localises to the address with no peripheral-side investigation at all.

A watchdog timeout counter, and a drain-abandoned counter beside it. The first says the system gave up; the second says it gave up and reopened without draining, which is Chapter 10.4's residual leak window.

A failing-address register. An ERR with no address is nearly useless in a system with more than one peripheral.

What not to do is invent an error payload in DAT_I. RULE 3.65 qualifies DAT_O() with the termination, so a slave may drive something — but there is no defined meaning, a different slave will choose differently, and a client that reads it is depending on an accident. Diagnostic information belongs in registers a debugger can read, not smuggled into a data bus.

3. RTL — The Probe

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// wb_error_probe — error PROVENANCE instrumentation.
//
// SIMULATION AND DEBUG ONLY. Not synthesisable as written, and emphatically
// NOT a Wishbone feature.
//
// WHY THIS EXISTS. An ERR termination says THE TRANSFER FAILED. It does not
// say why, and it does not say who decided. The specification is explicit
// about that: the ERR_I description states that "the source of the error …
// is defined by the IP core supplier", and there is no standard payload,
// no error code and no source field anywhere in the interface.
//
// So provenance has to be RECONSTRUCTED from signals that already exist for
// other reasons. This probe does that from four observations, none of which
// is a Wishbone signal:
//
//   sel_periph   the decoder selected a real peripheral
//   sel_default  the decoder selected the default responder
//   expired      the watchdog's threshold fired
//   latency      clocks the transfer was presented before terminating
//
// EVERY ONE OF THESE IS LOCAL DEBUG INSTRUMENTATION. A different system
// would expose different signals, and a system that exposes none can only
// report that something failed. The lesson is that provenance is designed
// in, not derived from the bus.
//
// The classification below is this system's, and it is complete for this
// system because these are the only three components that can generate an
// error here.
// ─────────────────────────────────────────────────────────────────────────
module wb_error_probe #(
  parameter int unsigned AW = 30,
  parameter int unsigned DW = 32
) (
  input  logic          clk_i,
  input  logic          rst_i,

  // the master's port
  input  logic          cyc_i,
  input  logic          stb_i,
  input  logic [AW-1:0] adr_i,
  input  logic          ack_i,
  input  logic          err_i,

  // local instrumentation taps
  input  logic          sel_periph_i,
  input  logic          sel_default_i,
  input  logic          expired_i,

  output logic          valid_o,        // a transfer terminated this clock
  output int unsigned   source_o,       // see the localparams
  output logic [AW-1:0] adr_o,          // the failing address
  output int unsigned   latency_o,      // clocks presented before ending

  output int unsigned   n_ok_o,
  output int unsigned   n_periph_err_o,
  output int unsigned   n_default_err_o,
  output int unsigned   n_timeout_err_o,
  output int unsigned   n_unknown_o
);
  localparam int unsigned SRC_OK       = 0;   // ACK: no error
  localparam int unsigned SRC_PERIPH   = 1;   // the selected peripheral refused
  localparam int unsigned SRC_DEFAULT  = 2;   // no peripheral owns the address
  localparam int unsigned SRC_TIMEOUT  = 3;   // the watchdog gave up
  localparam int unsigned SRC_UNKNOWN  = 4;   // classification failed

  logic presented, terminated;
  assign presented  = cyc_i && stb_i;
  assign terminated = presented && (ack_i || err_i);

  int unsigned pres_q;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      pres_q <= 0; valid_o <= 1'b0; source_o <= SRC_OK;
      adr_o <= '0; latency_o <= 0;
      n_ok_o <= 0; n_periph_err_o <= 0; n_default_err_o <= 0;
      n_timeout_err_o <= 0; n_unknown_o <= 0;
    end else begin
      valid_o <= 1'b0;

      if (!presented) begin
        pres_q <= 0;
      end else if (terminated) begin
        valid_o   <= 1'b1;
        adr_o     <= adr_i;
        latency_o <= pres_q + 1;
        pres_q    <= 0;

        // ── THE CLASSIFICATION, in priority order. `expired` is tested
        //    first because a watchdog error is generated at the guard and
        //    the select lines below it may still show whatever the decoder
        //    was doing — the error did not come from there.
        if (ack_i) begin
          source_o <= SRC_OK;       n_ok_o          <= n_ok_o + 1;
        end else if (expired_i) begin
          source_o <= SRC_TIMEOUT;  n_timeout_err_o <= n_timeout_err_o + 1;
        end else if (sel_default_i) begin
          source_o <= SRC_DEFAULT;  n_default_err_o <= n_default_err_o + 1;
        end else if (sel_periph_i) begin
          source_o <= SRC_PERIPH;   n_periph_err_o  <= n_periph_err_o + 1;
        end else begin
          // An error with no identifiable source. In THIS system that
          // should be impossible, so a non-zero count means the probe's
          // model of the system is wrong — which is itself worth knowing.
          source_o <= SRC_UNKNOWN;  n_unknown_o     <= n_unknown_o + 1;
        end
      end else begin
        pres_q <= pres_q + 1;
      end
    end
  end
endmodule

Reading it

The probe is a classifier, not a checker. It does not decide whether anything is wrong — it decides who decided. Both are needed and they are different instruments: Chapter 10.2's wb_term_checker finds malformed terminations; this finds the origin of well-formed ones.

SRC_UNKNOWN is the honest arm. In this system it should be unreachable, so a non-zero count means the probe's model of the system is wrong — a fourth error source appeared, or a tap was mis-wired. A classifier without an "I don't know" bucket silently misclassifies instead.

The priority order is the design decision. Testing expired before the select lines encodes the fact that a watchdog error is manufactured at the guard, upstream of the decode. Reversing it would attribute every timeout to whichever component the decoder had selected, which is exactly the wrong answer and a plausible mistake.

Everything here is local debug instrumentation and none of it is synthesisable as written. int unsigned counters and string lookup belong in simulation; a silicon version would be narrow counters and a status register.

4. Waveform — Three Sources, Three Signatures

What separates three identical errors

10 cycles
Ten clock cycles comparing three failing accesses in parallel systems. The first access has the peripheral select asserted at cycles two and three and its error arrives at cycle three. The second has the default responder select asserted at cycle two and its error arrives at cycle two. The third asserts neither select signal in view; its watchdog expired signal and its error both assert at cycle six. Each failure has a distinct evidence signature even though all three reach the client as the same error bit.selects already differselects already differperipheral refusesperipheral refuseswatchdog gives upwatchdog gives upCLK_IL: sel periphL: ERR_IU: sel defltU: ERR_IT: expiredT: ERR_It0t1t2t3t4t5t6t7t8t9
Figure 1 — three failing reads in three identical systems, started on the same clock: word 7 (local invalid), word 100 (unmapped) and word 11 (a sensor slower than the watchdog tolerates). Traced from simulation.

All three rows pairs end in ERR_I, and all three reach their clients as the same bit. Nothing in the client contract separates them.

The evidence separates them at three different clocks. The unmapped access is identified at cycle 2 — before it even terminates — by its select line. The local invalid at cycle 3. The timeout at cycle 6.

The unmapped case is diagnosable earliest and most cheaply. sel deflt is asserted the moment the address is decoded, which is why a hit counter on the default responder is the highest-value instrument in the system: it fires before anything has gone wrong downstream.

The timeout case asserts no select line in this view at all. That is what the probe's priority order handles: the error came from the guard, above the decode, and attributing it to whatever the decoder was doing would name the wrong component.

And the latency differences are real evidence too — 2, 1 and 7 presented clocks respectively in Section 5's measurement. A timeout is always the slowest failure in a system, by construction, because it is defined as the one that waited longest.

5. Simulation — SIM K

One system, five accesses, and the probe is not told which is which.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM K - four failures, one bit, and the evidence ===
    master -> watchdog(TIMEOUT_CYCLES=6) -> fabric -> peripheral
    every failure below reaches the client as err=1 and nothing else.

    access                          ok   err   probe says          clks
    read  word 4    legal           1     0    ACK (no error)      2
    read  word 7    local invalid   0     1    peripheral          2
    read  word 100  unmapped        0     1    default responder   1
    read  word 11   slow sensor     0     1    watchdog timeout    7
    write word 0    read-only       0     1    peripheral         23

    probe totals   ACK 1   peripheral 2   default 1   timeout 1   unknown 0
    guard          timeouts 1   late absorbed 0   abandoned 1
    fabric         default-responder hits 1

Every failure was classified, and unknown = 0. Four errors from three different components, separated by three signals none of which is part of Wishbone.

The ok/err columns are identical across all four failures. That is the problem the probe exists to solve, stated as data: the client contract preserves the verdict and discards the origin.

peripheral = 2 — the local invalid offset and the read-only write. Both are the peripheral's documented policy, and the probe does not distinguish which policy fired. It localises to a component, and narrowing further is that peripheral's status registers, not the bus's job.

Two ways the evidence itself misled, and both are real

This run produced two results I did not design for, and they are more instructive than the clean rows.

The last access reports 23 clocks. A write to word 0 should fail in about 2, as the second row shows for a comparable peripheral error. It took 23 because the previous access — the sensor timeout — was still draining, and Chapter 10.4's guard stalls new requests until the drain completes.

So latency evidence is contaminated by preceding failures. A transfer that arrives during a drain inherits the drain's remaining time. Reading 23 clocks as "this peripheral is slow" would be wrong, and the discriminator is the guard's draining signal or simply the ordering: an anomalous latency immediately after a timeout is usually the drain, not the target.

And abandoned = 1. The sensor takes 40 clocks; DRAIN_LIMIT is 32. The drain gave up before the target answered, which is exactly the residual-risk window Chapter 10.4 named — and it appeared here without being staged, simply because the parameters of a realistic system did not line up.

That counter is the system telling the truth about its own limits. A non-zero abandoned means a late response may still be in flight, and the very next access is the one at risk. In this run nothing leaked, because the sensor's answer landed while nothing was presented — but that was luck, not design.

The lesson from both is the same. Instrumentation has to be read in context. A latency figure, a timeout count and an abandonment count are each individually ambiguous; together with the ordering they are conclusive. A debugging procedure that reads one number in isolation will reach a confident wrong answer.

6. The Module's Failures, and the Evidence for Each

Every deliberately broken design in Module 10, arranged by what identifies it.

BugChapterBus conformant?Evidence
master folds ACK||ERR into success10.2yesclient successes > bus ACK count
slave asserts ACK and ERR together10.2no — RULE 3.45the checker's violation count
unmapped address, no responder10.3yesno select line asserted, transfer never ends
late response after timeout10.4yesreturned value belongs to a previous request
timeout classified as a peripheral fault10.5yesexpired asserted; no peripheral refused anything

Four of the five leave a fully conformant bus. That ratio is the module's summary of what a protocol checker is for: it catches the one that is a protocol violation and none of the others.

The evidence column is the useful part. Each entry is a specific observation, and none of them is "look at the waveform and think". Three are counters, one is a value comparison, one is the absence of a signal.

7. Common Mistakes

"An ERR means the peripheral rejected the access."

Wrong mental model: errors come from targets.

What is true: in this system they come from three places, and one of them — the watchdog — is not a target at all. Measured: one of four errors was a timeout, and the peripheral involved had not refused anything.

Concrete bug: investigating a peripheral for an error it never generated. The most expensive hour in this class of failure.

Observable evidence: expired, or the select lines.

Correct model: ask who generated it before asking why.

"A timeout tells you the target is broken."

Wrong mental model: the watchdog detected a fault.

What is true: the watchdog detected that it had waited long enough. Measured here: the sensor was working correctly and took 40 clocks against a threshold of 6.

Concrete bug: replacing a healthy peripheral because the threshold was set from the wrong worst case.

Observable evidence: the target's own progress — was its latency counter advancing when the guard fired?

Correct model: a timeout is the system's conclusion, not the target's report.

"The error data will tell me what went wrong."

Wrong mental model: DAT_I carries diagnostics on an error.

What is true: there is no error payload in Wishbone. RULE 3.65 lets a slave qualify DAT_O() with ERR_O, so something is driven, but no meaning is defined and different slaves choose differently — 0x00000000 in one of this module's slaves, 0xBAD0BAD0 in another, 0xE220DEF in the responder.

Concrete bug: software decoding the value as a status code.

Correct model: diagnostics belong in registers, and the value on an errored read should not be consumed at all.

"A long latency means a slow peripheral."

Wrong mental model: the number measures the target.

What is true: measured here — a peripheral error reporting 23 clocks because a preceding timeout's drain was still running. The latency belonged to the guard, not the target.

Observable evidence: the draining signal, or the ordering — an anomalous latency directly after a timeout.

Correct model: read instrumentation in context. One number in isolation supports a confident wrong answer.

"If the checker is green and the client is happy, the system is fine."

Wrong mental model: two independent checks are enough.

What is true: they cover different things and both can be green while a failure is silently mis-attributed. A timeout reported as an error is honest; a timeout investigated as a peripheral fault wastes the investigation.

Correct model: conformance, client contract and provenance are three separate properties requiring three separate instruments.

8. Interview Reasoning

I would establish who generated it before asking why, because in a real system there are at least three candidates and they need completely different investigations.

First: did a termination actually occur? If not, this is not an error at all — it is an absence, and the next question is whether anything is even selected. No select line asserted means the address reached nothing and the peripheral is innocent. That distinction saves the most time, because the instinct is to look inside a target that never saw the access.

Then: which component generated the error? In the system I built there are three sources and each leaves a distinct mark. A watchdog timeout asserts expired at the guard. An unmapped address asserts the default responder's select. A peripheral refusal asserts the peripheral's select. I classify in that order — watchdog first — because a timeout is manufactured above the decode, and the select lines underneath may still show whatever the decoder was doing.

What I measured. Four failures reaching the client as the same err bit, all four correctly attributed from three signals, none of which is a Wishbone signal.

And that is the general point I would make. The specification says outright that the source of the error is defined by the IP core supplier. There is no error code and no standard payload, so provenance is something you design in — a default-responder hit counter, a timeout counter, a failing-address register — or you cannot recover it afterwards.

Two cautions from the same run, both of which surprised me. A peripheral error measured 23 clocks because a previous timeout's drain was still stalling new requests — latency evidence is contaminated by preceding failures. And the drain was abandoned because the sensor was slower than the drain limit, which means a late response was still in flight.

So I would read the counters together with the ordering, never one in isolation. Each is individually ambiguous; together they are conclusive.

9. Understanding Check

10. What Module 10 Established

ChapterWhat it added
10.1the termination taxonomy; a client contract separating terminated from succeeded
10.2generation and consumption; one defect a checker finds, one it cannot
10.3local invalid offset vs unmapped address; the default responder
10.4timeout as system policy; the boundary edge; the late-response drain
10.5provenance, and the procedure that recovers it (this chapter)

The module's central claim: a transfer ends in one of three classes, and which class is architectural information, not a status flag. ERR means the transfer failed; it does not mean the target refused, and it does not mean anything about why.

What the specification actually provides. Three exclusive classes (RULE 3.45), qualified alike (RULE 3.35), negated alike (RULE 3.50), with read data qualified by whichever arrives (RULE 3.65). Both optional terminations are optional (PERMISSION 3.20, 3.25). The meaning of an error, and the master's reaction to it, are supplier-defined — and RULE 2.15 makes publishing both mandatory.

What it deliberately does not provide, and this module measured all four: no list of error conditions, no error payload, no timeout, and no cancellation. A watchdog is RECOMMENDATION 3.10's suggestion for preventing deadlock in an interconnect, and everything past that sentence is system policy.

What Module 10 did not do. It never deferred a transfer. Every failure here was final — nothing asked to be tried again, and no master re-issued anything. RTY appeared only to close the taxonomy.

What does a target do when it cannot serve a request now but could later — and how does a master respond without looping forever?

Module 11 — Retry Mechanism takes it up, beginning with the RTY signal. 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

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.