Skip to content
VLSI Mentor

Wishbone · Module 4

STB_O

Bus wires always carry values; STB_O is what turns a set of values into a request. Qualification, the termination every strobe is owed, and why silence is the one response a slave may never give.

Five chapters have described what a slave must do "when a transfer is qualified" without saying what qualifies it. Address, data, direction and byte lanes are all values, and values sit on wires whether or not anyone means anything by them.

What turns a set of stable bus values into a transfer the slave must act on?

1. Values Are Not Requests

A bus wire always carries a level. ADR_O has some value between transfers; so does WE_O, as Chapter 4.6 §3 made painfully concrete.

So a slave cannot decide what to do by looking at values. Every failure mode in the last five chapters reduces to a slave acting on a value at a moment when that value meant nothing.

STB_O is the moment marker. It separates "these wires happen to hold this" from "I am asking you to do this". Every other master output is data about the request; STB_O is the request.

Two consequences follow immediately, and both have appeared already:

Everything a slave does must be gated on it. Not the write path only — the read path, the error decision, the acknowledge. A slave that decodes its address continuously and only gates the final write has already made a decision it was not asked to make.

Everything a master drives must be qualified by it. RULE 3.60 names them in one list — ADR_O, DAT_O(), SEL_O(), WE_O and the tag outputs — which is why those four chapters all cite the same rule. The strobe is what makes those values a promise, and a promise that changes while it is being read is not one.

2. STB_O and CYC_O Are Not the Same Claim

Both are master outputs, both are usually asserted together, and in every RTL example in this module so far they have been driven from the same register. They mean different things, and Chapter 4.9 is about the difference.

The short form, enough to keep this chapter honest:

CYC_O claims the bus. It says this master is in the middle of something and the interconnect should keep its connection in place.

STB_O presents a transfer. It says: right now, this specific request.

A single-transfer master asserts both together and drops both together, which is why they look identical in Chapter 4.5's and Chapter 4.6's masters. A master performing several transfers in one tenure holds CYC_O across all of them and toggles STB_O per transfer.

RULES 3.30 and 3.35 are written the way they are because of that. RULE 3.30 forbids a slave from responding to any slave signal while CYC_I is negated; RULE 3.35 requires termination specifically to be generated from the AND of the two. The strobe alone is not authority to act — which matters in exactly the case where one master's strobe reaches a slave that a different master's cycle is using, and Chapter 4.9 develops it properly.

3. What a Slave Owes a Strobe

Every qualified transfer gets exactly one termination. A slave that decodes an address it does not implement still owes an answer — an error is an answer. Silence is not, and a slave that simply ignores an unrecognised offset hangs the master indefinitely, because the master has no timeout in the protocol to fall back on.

This is why every slave in Modules 3 and 4 asserts ERR_O on an unknown offset rather than doing nothing. It is not politeness; it is the only thing that keeps the bus alive.

A slave must not respond twice. One termination per strobe. Asserting ACK_O for two cycles while the strobe is held is a second answer to a question already answered, and Chapter 4.10 covers what a master does with it.

A slave must not respond to a strobe not aimed at it. The interconnect is responsible for delivering STB only to the selected slave — Chapter 3.5 covered how — but a slave that asserts ACK_O combinationally from stb_i alone, with no internal address check, will answer transfers meant for others in any fabric that broadcasts the strobe.

4. RTL — A Slave Whose Every Output Is Gated

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_stb_slave — a slave in which EVERY externally visible behaviour is
// gated on the qualified transfer, and nothing else is.
//
// PURPOSE. Previous chapters gated one path at a time. This module shows
// the discipline applied uniformly, which is the form worth copying: a
// single `xfer` term, used everywhere, with no second path into any output.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_stb_slave #(
  parameter int unsigned OFF_AW = 4,
  parameter int unsigned DW     = 32
) (
  input  logic                  clk_i,
  input  logic                  rst_i,
  input  logic                  cyc_i,
  input  logic                  stb_i,
  input  logic                  we_i,
  input  logic [(DW/8)-1:0]     sel_i,
  input  logic [OFF_AW-1:0]     adr_i,
  input  logic [DW-1:0]         dat_i,
  output logic [DW-1:0]         dat_o,
  output logic                  ack_o,
  output logic                  err_o,
  output logic [DW-1:0]         ctrl_o
);
  localparam int unsigned NL = DW / 8;

  localparam logic [OFF_AW-1:0] W_CTRL   = 'd0;
  localparam logic [OFF_AW-1:0] W_STATUS = 'd1;

  logic [DW-1:0] ctrl_q;
  assign ctrl_o = ctrl_q;

  // ── THE ONE TERM ───────────────────────────────────────────────────────
  // RULE 3.30: never respond to slave signals while CYC_I is negated.
  // RULE 3.35: terminations generated from the AND of CYC_I and STB_I.
  // Named once,
  // used for every output below. There is no other path into any output.
  logic xfer;
  assign xfer = cyc_i & stb_i;

  logic known_off;
  always_comb begin
    unique case (adr_i)
      W_CTRL, W_STATUS: known_off = 1'b1;
      default:          known_off = 1'b0;
    endcase
  end

  logic illegal;
  assign illegal = (~known_off) |
                   (we_i & (adr_i == W_STATUS)) |    // read-only
                   (sel_i == '0);                    // empty lane mask

  // ── EXACTLY ONE TERMINATION PER QUALIFIED TRANSFER ─────────────────────
  // ack_o and err_o are mutually exclusive by construction, and both are
  // zero when xfer is low. A slave that can assert neither for a qualified
  // transfer hangs the master forever — there is no protocol timeout.
  assign err_o = xfer &  illegal;
  assign ack_o = xfer & ~illegal;

  logic write_ok;
  assign write_ok = xfer & we_i & ~illegal;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      ctrl_q <= '0;                                  // RULE 3.20
    end else if (write_ok) begin
      if (adr_i == W_CTRL) begin
        for (int unsigned n = 0; n < NL; n++) begin
          if (sel_i[n]) ctrl_q[n*8 +: 8] <= dat_i[n*8 +: 8];
        end
      end
    end
  end

  always_comb begin
    dat_o = '0;
    if (xfer && !we_i && !illegal) begin
      unique case (adr_i)
        W_CTRL:   dat_o = ctrl_q;
        W_STATUS: dat_o = {{(DW-8){1'b0}}, 8'hA5};
        default:  dat_o = '0;
      endcase
    end
  end
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_stb_hang_detector — a NON-SYNTHESIZABLE simulation monitor that
// catches the failure STB_O makes possible: a transfer never answered.
//
// This is a testbench component, not part of any design. It exists because
// the protocol has no timeout: if a slave declines to terminate, nothing
// in the bus recovers, and the only evidence is a simulation that stops
// making progress. A monitor converts that into a message with a cycle
// count and the address that caused it.
// ─────────────────────────────────────────────────────────────────────────
module wb_stb_hang_detector #(
  parameter int unsigned AW       = 30,
  parameter int unsigned MAX_WAIT = 64
) (
  input logic          clk_i,
  input logic          rst_i,
  input logic          cyc_i,
  input logic          stb_i,
  input logic [AW-1:0] adr_i,
  input logic          ack_i,
  input logic          err_i,
  input logic          rty_i
);
  int unsigned held;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      held <= 0;
    end else if (cyc_i && stb_i && !(ack_i || err_i || rty_i)) begin
      held <= held + 1;
      // MAX_WAIT is a TESTBENCH policy number, not a protocol limit. The
      // specification places no bound on how long a slave may take. The
      // monitor exists to make an UNBOUNDED wait visible, not to enforce
      // a bound that the bus does not have.
      if (held == MAX_WAIT) begin
        $display("[%0t] HANG: transfer at word adr 0x%0h unanswered for %0d cycles",
                 $time, adr_i, MAX_WAIT);
      end
    end else begin
      held <= 0;
    end
  end
endmodule

Reading the pair

Purpose. The slave shows uniform gating — one qualification term feeding every output. The monitor shows how to make the absence of a termination visible, since an unanswered strobe produces no event of its own.

Ownership. The slave drives DAT_O, ACK_O, ERR_O and nothing else. The monitor drives nothing; it observes.

Combinational logic. Slave: xfer, offset recognition, the legality term, two mutually exclusive terminations, write_ok, and the read multiplexer. Every one of them has xfer in it.

Sequential logic. Slave: one lane-gated register. Monitor: a counter reset by any termination or by the strobe dropping.

Timing. ack_o and err_o are combinational from xfer, so this slave terminates in the cycle the transfer is presented — the zero-wait-state form. Module 5 covers what changes when a slave needs longer, and Chapter 4.1 already placed the widely-quoted "all outputs are registered" sentence — it is descriptive text in the CLK_I signal description, not a numbered rule, so this shape is conformant.

Qualification. xfer is the only entry point. Search the module for ack_o, err_o, dat_o or ctrl_q and every assignment includes it.

Reset. Synchronous, active high, per RULES 2.30 and 3.00.

Simplifications. Two registers, no wait states, no retry. The monitor's MAX_WAIT is a testbench choice and says so.

Failure modes. Section 6.

5. Waveform — Presented, Answered, Gone

STB_O: the same values, twice meaningless and twice a request

9 cycles
Nine clock cycles. In cycle one the master asserts the cycle and strobe signals, presenting a write to word address four hundred with write enable high; the slave acknowledges in the same cycle and the register takes the value. In cycles two and three the strobe is low, but the address, write enable and data outputs all retain exactly the values they held during the transfer, because nothing requires a master to clear them. A correct slave does nothing at all in those cycles. In cycle four the strobe rises again presenting a second transfer, and the slave responds again. The point of the figure is that the bus values are identical in cycles one, two, three and four, and only the strobe distinguishes a request from residue.qualified: a real requestqualified: a real requestsame values, no requestsame values, no requestqualified againqualified againCLK_ICYC_OSTB_OADR_O0x0000x4000x4000x4000x4000x4000x4000x4000x400WE_OACK_Ictrl0x000x000x7F0x7F0x7F0x7F0x7F0x7F0x7Ft0t1t2t3t4t5t6t7t8
Figure 1 — two transfers and the gap between them. Outside the strobe, the bus values are unchanged and mean nothing.

Cycles 2 and 3 are the figure's whole argument. ADR_O still reads 0x400. WE_O is still high. DAT_O still carries the write data. Nothing about the values distinguishes these cycles from cycle 1 — and a slave gated only on address and direction would write its register three times instead of once.

STB_O is the only difference, and that is exactly its job.

Note also what ctrl does not do: it changes once per qualified transfer, at the edge following it. In cycle 5 the second transfer writes the same value again, so the register appears unchanged — which is why the error-injection test in Section 6 uses two different values.

6. Failure Modes and Discriminating Evidence

Symptom: a master hangs and the simulation stops making progress.

Candidate causes. A qualified transfer received no termination. Either the address selected no slave, or the selected slave has a path that decodes the offset but produces no answer.

Discriminating evidence. Look at CYC, STB and all three termination inputs. A strobe held for many cycles with all terminations low is conclusive, and the address in those cycles names the target. The monitor in Section 4 turns this into a printed message rather than a manual waveform hunt.

Likely RTL location. The slave's termination logic — most often a case whose default branch terminates nothing, or an interconnect that selected no slave and has no default responder.

Property. P1 in Section 7.

Symptom: a slave performs an operation several times for one software access.

Candidate causes. Something in the slave is gated on values rather than on the qualified transfer — typically a command pulse or a counter increment.

Discriminating evidence. Count the operations against the number of cycles the strobe was asserted. If the count matches the strobe's duration rather than the number of transfers, the gating is on level rather than on the qualified transfer. With wait states this multiplies; without them it is invisible, which is why the bug survives zero-wait-state testing.

Likely RTL location. Any sequential block whose enable omits xfer, or which uses xfer but is re-satisfied every cycle the strobe is held.

Symptom: two slaves acknowledge the same transfer.

Candidate causes. A slave asserting ACK_O from stb_i without an internal address check, in a fabric that broadcasts the strobe rather than routing it.

Discriminating evidence. Watch both slaves' ACK_O on one transfer. Two asserted is conclusive, and the resulting master behaviour — a transfer that appears to complete with merged read data — is otherwise baffling.

Likely RTL location. The slave's ack_o assignment, or the interconnect's strobe routing. Establish which by checking whether the non-selected slave's stb_i was asserted at all.

Symptom: a slave responds to another master's transfer.

Candidate causes. The slave's qualification uses stb_i alone, omitting cyc_i, in a multi-master system.

Discriminating evidence. Check cyc_i at the slave in the offending cycle. Low while stb_i is high is conclusive, and it is a direct RULE 3.30 violation rather than a design-quality issue.

Likely RTL location. The xfer term.

Property. P2.

7. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_stb_checker — qualification properties.
//
// P1 and P2 are SPECIFICATION-derived. P1 follows from the requirement
// that a transfer terminates: a bus with no timeout depends on it, and
// a slave that never answers contradicts the STB_O signal description's
// statement that a slave responds to EVERY assertion of the strobe.
// P2 is RULE 3.30 stated directly as a property.
//
// P3 is LOCAL DESIGN POLICY specific to the zero-wait-state slave in
// Section 4 — a slave with wait states legitimately holds a strobe without
// terminating, and Module 5 (Chapter 5.3) covers that shape.
// ─────────────────────────────────────────────────────────────────────────
module wb_stb_checker #(
  parameter int unsigned MAX_WAIT = 64
) (
  input logic clk_i,
  input logic rst_i,
  input logic cyc_i,
  input logic stb_i,
  input logic ack_i,
  input logic err_i,
  input logic rty_i,
  input logic slave_acted        // white-box: any state change or side effect
);
  default disable iff (rst_i);

  // P1 — SPECIFICATION-derived. A qualified transfer terminates within a
  //      bounded number of cycles. MAX_WAIT is a TESTBENCH bound, not a
  //      protocol one: the specification places no limit on slave latency.
  //      The property exists because an UNBOUNDED wait is indistinguishable
  //      from a hang, and a hang produces no event to trigger on.
  property p_transfer_terminates;
    @(posedge clk_i)
      (cyc_i && stb_i) |-> ##[0:MAX_WAIT] (ack_i || err_i || rty_i);
  endproperty
  a_transfer_terminates : assert property (p_transfer_terminates)
    else $error("qualified transfer not terminated within %0d cycles", MAX_WAIT);

  // P2 — RULE 3.30, directly. A slave acts only when BOTH qualifiers are
  //      asserted. Catches the single-master shortcut that breaks the
  //      moment a second master is added.
  property p_act_only_when_qualified;
    @(posedge clk_i) slave_acted |-> $past(cyc_i && stb_i);
  endproperty
  a_act_only_when_qualified : assert property (p_act_only_when_qualified)
    else $error("slave acted without a qualified transfer");

  // P3 — LOCAL POLICY for the zero-wait-state slave only. Exactly one
  //      termination per strobe: two terminations answer a question that
  //      was already answered.
  property p_one_termination;
    @(posedge clk_i)
      (cyc_i && stb_i && (ack_i || err_i || rty_i)) |=> !(ack_i || err_i || rty_i)
        or !$past(stb_i);
  endproperty
  a_one_termination : assert property (p_one_termination)
    else $error("a second termination followed the first");

  // P4 — SPECIFICATION-derived. Terminations are mutually exclusive: a
  //      transfer cannot both succeed and fail. Chapters 4.11 and 4.12
  //      develop what each one obliges the master to do.
  property p_terminations_exclusive;
    @(posedge clk_i) $onehot0({ack_i, err_i, rty_i});
  endproperty
  a_terminations_exclusive : assert property (p_terminations_exclusive)
    else $error("more than one termination asserted simultaneously");
endmodule

$onehot0 in P4 permits zero or one asserted. Note that Chapter 3.7 recorded an Icarus defect in $countones over a concatenation of 1-bit variables; $onehot0 here is inside SVA, which Icarus cannot execute at all, so the question does not arise — but a synthesizable checker written the same way should sum explicit casts instead.

Tooling limitation. Icarus has no SVA support; reviewed by inspection only.

8. Common Mistakes

"A slave can decode its address and respond; the strobe is a formality."

Wrong mental model: the address identifies the request.

Concrete bug: any path gated on address and direction but not on CYC_I & STB_I. It acts on residue, and Figure 1 shows exactly how much residue looks like a request.

Observable evidence: operations repeating, or happening with no software access at all.

Correct model: values are continuous, requests are discrete. RULES 3.30 and 3.35 name the conjunction that makes a request, and nothing else does.

"If a slave does not recognise the address, it should stay quiet."

Wrong mental model: not responding is the safe default.

Concrete bug: an unhandled default that terminates nothing. The master waits forever.

Observable evidence: a hang with the strobe held and all terminations low — and no error message, because nothing happened.

Correct model: silence is the one response that is never acceptable. There is no protocol timeout. Every qualified transfer gets exactly one termination, and an error is a perfectly good one.

"STB_O and CYC_O are the same signal with two names."

Wrong mental model: they are always identical, so one of them is redundant.

Concrete bug: a slave gating on stb_i alone. Correct in a single-master system, wrong the moment a second master exists — and the failure is intermittent and arbitration-dependent.

Observable evidence: a slave responding to a transfer belonging to another master, appearing as data corruption under load and nowhere else.

Correct model: they are identical only for a single-transfer master. RULES 3.30 and 3.35 require both, and Chapter 4.9 is about what the other one adds.

9. Interview Reasoning

First look: CYC, STB and the three termination inputs at the master.

The diagnostic shape is unmistakable. A strobe asserted and held for hundreds of cycles with ACK_I, ERR_I and RTY_I all low means a qualified transfer received no answer. Nothing else in Wishbone produces that picture.

Why it hangs rather than failing. The protocol has no timeout. A master presents a transfer and waits for a termination, and if none arrives it waits indefinitely — there is no rule that rescues it. The bus is not broken; it is doing precisely what it was told.

The address in those cycles names the culprit. Then one question: did any slave see this transfer?

  • STB_I asserted at a slave that produced nothing — the slave's termination logic has a path that answers nothing. Almost always an unhandled default in an offset decoder.
  • STB_I asserted nowhere — the interconnect decoded an address in no slave's range and there is no default responder. That is an interconnect gap, not a slave bug.

Why intermittent. Usually an address computed at runtime — a pointer, a descriptor field — that occasionally lands outside the map. The access pattern varies, so the failure does.

The fix has two parts, and the second is the important one. Fix the immediate hole. Then add a default responder in the interconnect that errors any address matching no slave, so the system's response to an unmapped access becomes a reported error rather than a hang. Chapter 3.5 covered that structure. A hang tells you nothing; an error tells you the address.

10. Understanding Check

11. What's Next

STB_O says this transfer. Both rules behind it name a second signal that has never been explained, and Section 2 deferred it deliberately.

A master that reads a value, modifies it and writes it back must not have another master change that location in between — and nothing covered so far prevents it.

What holds a master's claim on the bus across several transfers, and what stops another master from interleaving?

Chapter 4.9 — CYC_O answers it. 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.