Skip to content
VLSI Mentor

Wishbone · Module 7

Wait States

While a read waits, the master waits for an answer. While a write waits, it holds the data that will mutate the device. Payload coherence and one-shot commits are the two obligations that follow.

Chapter 6.5 established how a slave throttles a transfer: it withholds its termination, and the master holds everything still. That mechanism is unchanged for a write. What changes is the stakes.

What must remain true while a write waits for the slave?

1. What the Master Must Hold

The list is longer than a read's by exactly one field, and that field is the dangerous one.

SignalMust beGoverned byIf it lapses
CYC_Oasserted throughoutRULE 3.25slave stops responding (RULE 3.30) — hang
STB_Oasserted throughoutRULE 3.60 / OBSERVATION 3.55request vanishes
ADR_OunchangedRULE 3.60, §3.2.2the wrong register is written
WE_Oasserted throughoutRULE 3.60the write becomes a read mid-flight
SEL_OunchangedRULE 3.60, §3.2.2the wrong bytes are written
DAT_OunchangedRULE 3.60, §3.2.2the wrong value is written

The bottom three rows have no read equivalent that damages the device. Chapter 6.5's table had ADR_O and SEL_O too, but a lapse there returned a wrong value; here it commits one.

And the master needs no special wait-state logic. Chapter 7.1's wb_write_master has none — its payload comes from registers written once, and its termination is sampled as a level. That is already correct for any latency, which is the point: waiting is not a feature a master implements, it is a consequence of holding still.

What the master must not do: report completion, release the bus, or accept a new request. Its acc_o term contains ~active_q for exactly that reason.

2. Presented Is Not Committed

Chapter 7.1 declared its slave's commit policy and noted the ack_o term in commit was redundant. Here it stops being redundant.

True forA side effect gated on it fires
presentedCYC_I & STB_I & WE_Ievery cycle of the waitonce per waiting cycle
committed — the slave's own commit eventexactly one cycleonce

For an ordinary register the difference is invisible. Writing 0x0F four times leaves 0x0F, and a read-back test passes.

It becomes visible the moment the write has a side effect:

  • a command register that launches an operation
  • a counter that increments on write
  • a FIFO that pushes
  • a write-one-to-clear status register

W1C is the interesting case, and it does not fail the way the others do. Clearing the same named bits four times is genuinely idempotent, and Section 5 measured a repeated-commit slave and a correct one producing identical EVENTS state. That is a real structural advantage of W1C over read-to-clear, and Section 5 works through why.

3. RTL — A Delayed Write Slave With Side Effects

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_delayed_write_slave — the running peripheral, with latency and two
// side-effecting registers.
//
// PURPOSE. Make a write take LAT cycles, and give it state whose repeated
// update is OBSERVABLE — so the presented-versus-committed distinction
// stops being theoretical.
//
// ── DECLARED COMMIT POLICY (LOCAL, not Wishbone) ──────────────────────
//   Commits on the same rising clock edge for which it returns ACK_O for
//   a qualified write. Identical in wording to Chapter 7.1's slave; the
//   difference is that ACK_O now arrives LAT cycles later, so `commit` is
//   true for one cycle out of LAT+1 rather than one out of one.
//
// WHAT THE LATENCY MODEL IS. A counter — NOT realistic hardware latency.
// It is an EDUCATIONAL MODEL standing in for the real sources: a register
// file with a pipelined write port, a peripheral that must accept a
// command before it can be overwritten, a bridge to another clock domain,
// or a resource that is briefly busy. What matters for the protocol is
// only that the slave is not ready yet.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_delayed_write_slave #(
  parameter int unsigned OFF_AW = 4,
  parameter int unsigned DW     = 32,
  parameter int unsigned LAT    = 3          // cycles before terminating
) (
  input  logic              clk_i,
  input  logic              rst_i,
  input  logic              cyc_i,
  input  logic              stb_i,
  input  logic              we_i,
  input  logic [OFF_AW-1:0] adr_i,
  input  logic [DW-1:0]     dat_i,
  input  logic [DW/8-1:0]   sel_i,
  output logic [DW-1:0]     dat_o,
  output logic              ack_o,
  output logic              err_o,
  // device side, all observable for QA
  input  logic [7:0]        event_set_i,     // events arriving from hardware
  output logic [DW-1:0]     control_o,
  output logic [7:0]        events_o,        // W1C status
  output logic              cmd_pulse_o,     // one-cycle command strobe
  output logic [7:0]        launches_o       // side-effect COUNT
);
  localparam int unsigned NL = DW/8;

  localparam logic [OFF_AW-1:0] O_CTRL   = 4'd2;   // byte 0x08  RW
  localparam logic [OFF_AW-1:0] O_ID     = 4'd4;   // byte 0x10  RO
  localparam logic [OFF_AW-1:0] O_EVENTS = 4'd8;   // byte 0x20  W1C
  localparam logic [OFF_AW-1:0] O_CMD    = 4'd9;   // byte 0x24  WO, pulses

  localparam logic [DW-1:0] ID_VALUE = 32'h5742_0701;

  logic [DW-1:0] ctrl_q;
  logic [7:0]    events_q;
  assign control_o = ctrl_q;
  assign events_o  = events_q;

  logic xfer;
  assign xfer = cyc_i & stb_i;                    // RULES 3.30 & 3.35

  // ── LEGALITY ──────────────────────────────────────────────────────────
  logic known_off, writable;
  always_comb begin
    unique case (adr_i)
      O_CTRL, O_ID, O_EVENTS, O_CMD: known_off = 1'b1;
      default:                       known_off = 1'b0;
    endcase
  end
  always_comb begin
    unique case (adr_i)
      O_CTRL, O_EVENTS, O_CMD: writable = 1'b1;
      default:                 writable = 1'b0;   // ID is read-only
    endcase
  end

  logic illegal;
  assign illegal = ~known_off | (we_i & ~writable);

  // ── THE LATENCY COUNTER ───────────────────────────────────────────────
  // `ready` is declared and assigned BEFORE the block that uses it —
  // Icarus rejects a reference that precedes its declaration, and the
  // order reads better anyway.
  //
  // The counter resets the moment the transfer is not presented, which is
  // what satisfies RULE 3.50 structurally: when STB_I goes away the
  // counter returns to zero and no termination can be asserted.
  logic [7:0] waited_q;
  logic       ready;
  assign ready = (waited_q >= 8'(LAT));

  always_ff @(posedge clk_i) begin
    if (rst_i)       waited_q <= '0;
    else if (!xfer)  waited_q <= '0;
    else if (!ready) waited_q <= waited_q + 8'd1;
    else             waited_q <= '0;              // one termination per transfer
  end

  // ── TERMINATION ───────────────────────────────────────────────────────
  assign err_o = xfer & ready &  illegal;
  assign ack_o = xfer & ready & ~illegal;

  // ── THE COMMIT EVENT ──────────────────────────────────────────────────
  // ONE named term. It contains ack_o, so it is true for exactly one cycle
  // out of the LAT+1 the transfer is presented for.
  //
  // Replace `commit` with `xfer & we_i` in the block below and this slave
  // launches the command LAT+1 times, and clears EVENTS LAT+1 times —
  // Section 5 measures both.
  logic commit;
  assign commit = xfer & we_i & ack_o;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      ctrl_q      <= '0;
      events_q    <= '0;
      cmd_pulse_o <= 1'b0;
      launches_o  <= '0;
    end else begin
      cmd_pulse_o <= 1'b0;                        // default: a ONE-CYCLE pulse

      // ── W1C EVENTS ──────────────────────────────────────────────────
      // Writing a 1 CLEARS that bit; writing a 0 preserves it. Only the
      // selected byte lane participates — an unselected lane must not
      // clear anything, which is why sel_i[0] gates it.
      //
      // The clear and the hardware set are combined into ONE assignment so
      // an event arriving in the same cycle as the commit is not lost: it
      // is OR-ed in after the mask is applied, and the NEXT write sees it.
      // Writing them as two separate statements would make the outcome
      // depend on statement order, which is the race Chapter 6.5 Section 11
      // described from the read side.
      if (commit && (adr_i == O_EVENTS) && sel_i[0]) begin
        events_q <= (events_q & ~dat_i[7:0]) | event_set_i;
      end else begin
        events_q <= events_q | event_set_i;
      end

      // ── COMMAND PULSE ───────────────────────────────────────────────
      // A write to COMMAND produces exactly one cycle of cmd_pulse_o and
      // increments a launch counter. launches_o is NOT a Wishbone signal;
      // it exists so a testbench can count the side effect. A production
      // peripheral would not export it.
      if (commit && (adr_i == O_CMD)) begin
        cmd_pulse_o <= 1'b1;
        launches_o  <= launches_o + 8'd1;
      end

      // ── ORDINARY MASKED REGISTER ────────────────────────────────────
      if (commit && (adr_i == O_CTRL)) begin
        for (int unsigned n = 0; n < NL; n++)
          if (sel_i[n]) ctrl_q[n*8 +: 8] <= dat_i[n*8 +: 8];
      end
    end
  end

  // ── READ PATH ─────────────────────────────────────────────────────────
  // RULE 3.65: qualified by the termination. COMMAND is write-only and
  // reads back zero; a design could equally refuse the read with ERR_O,
  // which is an implementation policy rather than a rule.
  always_comb begin
    dat_o = '0;
    if (xfer && !we_i && ack_o) begin
      unique case (adr_i)
        O_CTRL:   dat_o = ctrl_q;
        O_ID:     dat_o = ID_VALUE;
        O_EVENTS: dat_o = {24'd0, events_q};
        default:  dat_o = '0;
      endcase
    end
  end
endmodule

Reading it

Purpose. Make a write take time, and give it three kinds of state — an ordinary masked register, a W1C status, and a command pulse — so the commit event's cardinality is observable in three different ways.

Interface. A standard Wishbone slave plus device-side signals. launches_o and events_o are not Wishbone signals; they exist for measurement.

State. The latency counter, CONTROL, the W1C EVENTS, the command pulse and its counter.

Combinational logic. xfer, legality, writability, ready, the two terminations, commit, and the read multiplexer.

Sequential logic. The counter; three separate commit-gated updates; the pulse's default-low assignment.

Write start. No start event — only the first cycle in which xfer is true. ready transitioning is what the slave manufactures.

Address, data, byte enables. All consumed combinationally in the commit cycle. Because the master holds them still under RULE 3.60 and §3.2.2, reading them at the commit rather than latching is safe — and Chapter 7.3 §3 showed the alternative choice and why a registered slave should latch instead.

Commit. xfer & we_i & ack_o, true for one cycle out of LAT+1.

Waiting. waited_q counts 0…LAT; xfer is true throughout; ack_o for one cycle.

Reset. Synchronous, active high. The counter also clears whenever the transfer goes away, preventing a response outliving its request.

Failure modes. Section 6.

Simplifications. Fixed latency. W1C gated on sel_i[0] only, since EVENTS is a byte in lane 0 — Module 13 owns byte selects properly. COMMAND reads back zero rather than erroring.

4. Waveform — Four Cycles Presented, One Commit

A delayed write, and a side effect that fires once

9 cycles
Nine clock cycles showing a write to the command register through a slave with three wait states. From cycle two through cycle five the master asserts both qualifiers with write enable high, a stable word address of nine, stable write data and all four byte selects. The slave's wait counter advances through zero, one and two during cycles two, three and four, and reaches three in cycle five where it asserts its acknowledge. At the edge ending cycle five the slave commits, producing a single cycle command pulse in cycle six and incrementing its launch counter from zero to one. The transfer was presented for four cycles and produced exactly one launch.presented — stays presentedpresented — stays presentedCOMMIT: the only oneCOMMIT: the only oneone launch, not fourone launch, not fourCLK_ICYC_OSTB_OWE_OADR_O----0x90x90x90x9----------------DAT_O----00000001000000010000000100000001----------------ACK_Icmd_pulselaunches000001111t0t1t2t3t4t5t6t7t8
Figure 1 — a write to COMMAND with three wait states. The payload is frozen; the launch fires once.

Cycles 2 to 5 are identical on the bus. Same qualifiers, same address, same direction, same data, same byte enables. Nothing distinguishes them from one another — which is exactly why a side effect keyed on them fires four times.

Cycle 5 is the only special one, and what makes it special is generated by the slave: its own ready, and therefore its own acknowledge.

cmd_pulse is one cycle wide and launches goes 0 → 1. With the commit gated on xfer & we_i instead, launches reaches 4 and cmd_pulse is high for four consecutive cycles — while CYC_O, STB_O, WE_O, ADR_O, DAT_O and ACK_I are pixel-for-pixel identical.

5. Simulation — Payload Stability and the Single Commit

Simulation B — payload stability with a drifting client.

The client requests a write of 0x0000000F to CONTROL, then immediately moves its inputs to a completely different request, against a slave inserting three wait states.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIMULATION B - payload stability (LAT=3) ===
                                     correct      unlatched
    cycles the write was presented       4             4
    distinct ADR_O values on the bus     1             2
    distinct DAT_O values on the bus     1             2
    ADR_O at the commit edge           0x2           0x6
    DAT_O at the commit edge      0x0000000f    0xdeadbeef
    CONTROL after                 0x0000000f    0x00000000
    OUTPUT  after                 0x00000000    0xdeadbeef
    RULE 3.60 violation cycles           0             3

The correct master presented exactly one address and one data value across all four cycles, and CONTROL took the requested value.

The unlatched master committed a transaction nobody requested. CONTROL was never written; OUTPUT_DATA holds a value the client had already moved on from. Both masters reported success.

Simulation D — what stays coherent, measured field by field.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIMULATION D - delayed write (LAT=3) ===
    cycles the transfer was presented       4
    ADR_O changes while outstanding         0
    DAT_O changes while outstanding         0
    SEL_O changes while outstanding         0
    WE_O  changes while outstanding         0
    CYC_O deasserted while outstanding      0
    STB_O deasserted while outstanding      0
    master completions before termination   0
    commit events                           1

Every field in Section 1's table held still for all four cycles, and the master completed exactly once, at the termination.

Simulation E — the repeated side effect.

Two otherwise-identical slaves receive one write to COMMAND, then one W1C write to EVENTS with an event arriving during the wait.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIMULATION E - repeated side effect (LAT=3) ===
                                   gated on COMMIT   gated on PRESENT
    cycles presented                      4                4
    terminations returned                 1                1
    COMMAND launches                      1                4
  --- W1C EVENTS, one write, event 0x02 arrives mid-wait ---
    events pending at the start        0x05             0x05
    write data (bits to clear)         0x07             0x07
    events after the write             0x00             0x00
    events lost                           1                1

The broken slave launched the command four times. One software write, four operations started — and cmd_pulse_o was high for four consecutive cycles rather than one, so a downstream block edge-detecting it would see one launch while a level-sensitive one would see a long assertion. That is the failure this section exists to show.

The bus traces are byte-identical between the two slaves. A protocol checker attached to either passes.

6. Failure Modes and Discriminating Evidence

Symptom: one software write starts an operation several times.

Candidate causes. The commit is gated on the request being presented rather than accepted.

Discriminating evidence. Count side effects against the wait length, not against the number of writes. If the count equals the presented duration, that is conclusive — no other mechanism produces that correlation. The load dependence is the field clue: load introduces latency, latency lengthens the wait, and the wait is the multiplier.

Likely RTL location. The side effect's enable — a missing termination term.

Property. P3 in Section 7.

Symptom: a command pulse is high for several cycles instead of one.

Candidate causes. The same missing term, seen on the pulse rather than on the counter.

Discriminating evidence. Measure the pulse width against LAT. A downstream block that edge-detects will behave correctly and mask the bug; one that is level-sensitive will not. That divergence is itself diagnostic.

Symptom: a write lands in the wrong register, only when the slave is slow.

Candidate causes. The master's payload does not hold still — unlatched, or latched then rewritten.

Discriminating evidence. Watch ADR_O, DAT_O and SEL_O across the whole strobe assertion. Any change before termination is a RULE 3.60 violation, and §3.2.2 sharpens it by requiring validity through the edge after the strobe negates. Chapter 7.3 §5 separates the two master faults by the slave's remembered offset.

Property. P1.

Symptom: W1C status bits are occasionally lost under load.

Candidate causes. Not a repeated commit — Section 5 measured that a repeated W1C clear is idempotent and loses nothing. The real candidates are an event arriving in a cycle whose clear mask names it (inherent to the semantic, not a bug), or a clear-and-set written as two statements so the outcome depends on statement order.

Discriminating evidence. Compare the write's data against the lost bit. If the lost bit was named in the clear mask, nothing is wrong — software asked for it. If it was not named and still vanished, the set and clear are racing inside the register, which is the ordering hazard Section 3's combined assignment prevents.

Likely RTL location. The EVENTS update — specifically whether the clear and the hardware set are one assignment or two.

Symptom: the write hangs and the slave's counter is stuck.

Candidate causes. The counter advances only under a condition that stopped being true.

Discriminating evidence. xfer asserted at the slave with waited_q not advancing. Conclusive, and it localises inside the slave immediately.

Symptom: a master abandons a slow write.

Candidate causes. A timeout implemented by negating CYC_O.

Discriminating evidence. CYC_O negated with STB_O still asserted, or both dropped before any termination.

Correct approach. There is no protocol-level abandon (Chapter 5.2 §2) — and on a write it is worse than on a read, because the slave may have committed already and the master will never learn whether it did. RECOMMENDATION 3.10 puts the watchdog in the interconnect so the transfer is terminated rather than orphaned.

7. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_write_wait_checker — properties for a waited write.
//
// P1 is SPECIFICATION (RULE 3.60, and §3.2.2 via RULE 3.75). P2 is
// SPECIFICATION (RULE 3.50). P3 and P4 are DESIGN OBLIGATIONS — the
// specification does not know what side effects a slave has, so it cannot
// require them to happen once.
// ─────────────────────────────────────────────────────────────────────────
module wb_write_wait_checker #(
  parameter int unsigned AW = 30,
  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 [AW-1:0]   adr_i,
  input logic [DW-1:0]   dat_i,
  input logic [DW/8-1:0] sel_i,
  input logic            ack_o,
  input logic            err_o,
  // white-box
  input logic            commit,
  input logic [7:0]      launches_q,
  input logic            cmd_pulse
);
  default disable iff (rst_i);

  logic xfer, terminated;
  assign xfer       = cyc_i & stb_i;
  assign terminated = ack_o | err_o;

  // P1 — SPECIFICATION. The WHOLE payload holds still for the whole wait.
  //      This is the write-side form of Chapter 6.5's P1, extended with
  //      dat_i — the field whose lapse commits a wrong value rather than
  //      returning one. The end boundary is the termination; omitting it
  //      would forbid a legal back-to-back write.
  property p_payload_frozen_while_waiting;
    @(posedge clk_i) (xfer && we_i && !terminated)
      |=> ($stable(adr_i) && $stable(dat_i) && $stable(sel_i) &&
           $stable(we_i) && cyc_i && stb_i);
  endproperty
  a_payload_frozen_while_waiting :
    assert property (p_payload_frozen_while_waiting)
    else $error("RULE 3.60 / 3.2.2: write payload moved during the wait");

  // P2 — SPECIFICATION (RULE 3.50, OBSERVATION 3.10). A slow response
  //      cannot outlive the transfer that provoked it.
  property p_no_termination_without_strobe;
    @(posedge clk_i) !stb_i |-> !terminated;
  endproperty
  a_no_termination_without_strobe :
    assert property (p_no_termination_without_strobe)
    else $error("RULE 3.50: termination asserted with STB_I negated");

  // P3 — DESIGN OBLIGATION, and the one this chapter exists for. A side
  //      effect happens only at a COMMIT, never in a merely presented
  //      cycle. Fires on the FIRST extra launch rather than when a
  //      downstream symptom eventually surfaces.
  //
  //      No bus-level property can catch this: the bus is conformant
  //      throughout, so the checker needs the counter.
  property p_side_effect_once_per_commit;
    @(posedge clk_i) $changed(launches_q) |-> $past(commit);
  endproperty
  a_side_effect_once_per_commit :
    assert property (p_side_effect_once_per_commit)
    else $error("side effect fired outside a commit event");

  // P4 — DESIGN OBLIGATION. The command strobe is ONE cycle wide. Stated
  //      separately from P3 because a pulse and a counter fail
  //      differently: a stretched pulse may be harmless to an
  //      edge-detecting consumer and fatal to a level-sensitive one.
  property p_pulse_is_one_cycle;
    @(posedge clk_i) cmd_pulse |=> !cmd_pulse;
  endproperty
  a_pulse_is_one_cycle : assert property (p_pulse_is_one_cycle)
    else $error("command pulse wider than one cycle");
endmodule

P1 is the write-side extension of Chapter 6.5's payload property, and the added dat_i term is the whole difference. It is a conformance property — a passive bus monitor catches every master that violates it, with no white-box access.

P3 and P4 need internals and there is no alternative. Section 5 measured byte-identical bus traces between the correct and broken slaves. This is the seventh time this course has met that boundary, and Chapter 5.8 §8 collected the pattern.

Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection; the slave is elaborated and all three simulations above were run.

8. Common Mistakes

"Write data can change while waiting — the slave has already seen it."

Wrong mental model: the slave captured the payload on the first cycle.

Concrete bug: a master that updates DAT_O mid-transfer. PERMISSION 3.10 describes a conformant slave with no storage at all, which has nothing to have captured.

Observable evidence: a committed value matching neither the requested one nor anything the client currently holds — measured in Section 5.

Correct model: §3.2.2 requires the payload valid until the edge after the strobe negates. The slave may read it at any point in the transfer, including the last.

"A repeated write is harmless because writing the same value twice is idempotent."

Wrong mental model: register writes are the only kind of write.

Concrete bug: a command register launching four times, or a FIFO gaining four entries.

Observable evidence: an operation starting more times than software asked, correlated with load rather than with traffic.

Correct model: idempotence is a property of some targets. Gate on the commit always — the term costs nothing when redundant and is the whole defence when it is not.

"No ACK means the write failed."

Wrong mental model: absence of a response is an error.

Concrete bug: a master abandoning a slow write by negating CYC_O.

Observable evidence: a transfer orphaned mid-flight, with the slave possibly having committed and the master unable to learn whether it did.

Correct model: withholding the termination is how a slave throttles. It is neither error nor retry, and on a write an abandon is unrecoverable in a way a read abandon is not.

9. Interview Reasoning

Because CYC_I & STB_I & WE_I is true for every cycle the master waits, and a side effect gated on that term fires once per cycle.

The mechanism. The slave inserts three wait states, so the transfer is presented for four cycles. The master holds everything still — correctly, as RULE 3.60 and §3.2.2 require. Those four cycles are indistinguishable from one another on the bus, so there is nothing in the request itself that says "this is the same write you already saw".

What the master observes. One transfer, one termination, one completion. Its view is completely normal, which is why the bug is invisible from outside the slave — I measured byte-identical bus traces between the correct and broken versions.

Why it is invisible in unit test too. At zero wait states presented and committed are the same cycle, so the bug cannot appear. It appears when latency is introduced — a bridge, a clock crossing, a busier arbiter — and that change usually has nothing to do with the slave, so nobody re-reviews it.

Why an ordinary register hides it and a command does not. Writing 0x0F four times leaves 0x0F. A read-back test passes. A command launches four operations, a FIFO gains four entries, a counter advances four times — those have no idempotent reading.

The confirming observation. Count side effects against the wait length, not against the number of writes. Four launches for a three-wait write is conclusive; the correlation with latency rather than traffic is unique to this bug.

The fix and the habit. Gate the side effect on the slave's own commit event. Then write it that way always, including in slaves that never wait — every slave in Modules 5, 6 and 7 carries a redundant ack_o in its commit term for exactly this reason. It costs nothing when redundant and is the whole defence when a later timing change adds latency.

And the design-level point worth raising. If a peripheral has a genuinely one-shot action, a level-triggered write is a fragile way to express it. Making the pulse one cycle wide by construction — a default-low assignment overridden only at the commit, as this slave does — means the consumer does not have to be edge-sensitive to be safe.

10. Understanding Check

11. What's Next

Waiting is now fully specified for a write: the master freezes a payload that will mutate the device, and the slave commits exactly once however long it takes.

Every chapter so far has explained a mechanism and then shown a waveform of it. The last chapter reverses that. Given an unfamiliar trace and no explanation, the question becomes what it shows — and, for a write, whether the state that changed is the state that was asked for.

How do you read an arbitrary Wishbone write off a waveform, and localise a failure from evidence alone?

Chapter 7.5 — Waveform Analysis 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.