Skip to content
VLSI Mentor

Wishbone · Module 5

Transaction Completion

One clock edge ends a Wishbone transfer, and four things must happen at it in the right relationship: capture the read data, record the result, release the bus, and report exactly once.

Chapter 5.5 closed the boundary where a client request becomes a bus transaction. This chapter closes the other one.

What exactly happens at the edge where the slave terminates the outstanding transfer?

1. Before, At, and After the Edge

Chapter 5.1 introduced edge-by-edge narration. Here it is applied to the one edge that matters most, for a read that terminates with ACK.

Before the edge — the slave has driven its answer and the master has not yet seen it.

  • Master drives: CYC_O, STB_O, ADR_O, WE_O, SEL_O, all stable since acceptance (RULE 3.60).
  • Slave drives: ACK_O asserted, and DAT_O carrying valid read data (RULE 3.65).
  • Master's state: active_q set. Nothing has been captured.

At the edge — both sides sample.

  • The master samples ack_i asserted. Its transfer is complete.
  • The master samples dat_i. This is the only edge at which that value is meaningful.
  • The slave samples its own inputs and sees the transfer still presented.

After the edge — the master's state has moved.

  • active_q cleared, so CYC_O and STB_O negate.
  • rdat_o now holds the captured data.
  • done_o asserted for one cycle.
  • The slave, seeing STB_I negate, drops ACK_O and stops driving DAT_O — RULE 3.50 and OBSERVATION 3.10.

Between this edge and the next — the read data on the bus is already gone. A master that deferred its capture has nothing to capture.

2. Why the Capture Cannot Be Deferred

This is worth stating sharply because the bug it prevents is the most common in Wishbone.

RULE 3.65"SLAVE interfaces MUST qualify the following signals with [ACK_O], [ERR_O] or [RTY_O]: [DAT_O()]."

A slave's read data is qualified by its own termination. Not by the strobe, not by the address — by the termination. So it is meaningful in exactly the cycles where a termination is asserted, and a conformant slave drives '0 otherwise, which Chapter 4.4 showed also keeps a merged return path clean.

The master therefore has exactly one opportunity, and the symptom of missing it is distinctive: every read returns the previous read's value. A perfect, consistent off-by-one across every read points at the capture edge and nothing else — and it looks like a software bug, which is why it costs time.

3. Reporting Exactly Once

The fourth obligation is the one the specification says nothing about, because it lives on the client side.

A bus transaction produces one termination. The master must turn that into one local completion.

Reporting twice double-counts: a client tracking outstanding requests leaks, a DMA descriptor advances twice, a semaphore is released twice.

Reporting zero times hangs the client, which is indistinguishable from a bus hang at the level the client can see.

The structural risk is a done_o that is a level rather than a pulse. If done_o is asserted while the master is idle, a client sampling it every cycle sees one completion per idle cycle. wb_single_master defaults done_o <= 1'b0 at the top of its always_ff and sets it only in the completion branch, which makes the pulse structural rather than a convention.

The second risk is a completion generated from the wrong condition — from ack_i alone, for instance, rather than from active_q && ack_i. That reports a completion for a termination the master did not provoke, which is property P3 in Chapter 5.1.

4. RTL — The Completion Path

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_completion_master — the termination edge, made explicit.
//
// PURPOSE. Chapter 5.5's wb_single_master handles completion correctly but
// compactly. This one separates the four obligations of Section 1 into
// named, individually reviewable steps, and distinguishes the three
// termination classes at the client interface instead of merging them.
//
// It is the Module 5 reference master. Everything Module 5 has established
// is present: latched metadata (5.5), level-sampled termination (5.4),
// PERMISSION 3.40 qualifiers (5.1), and a one-pulse local completion.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00, 3.20).
// ─────────────────────────────────────────────────────────────────────────
module wb_completion_master #(
  parameter int unsigned AW = 30,
  parameter int unsigned DW = 32
) (
  input  logic            clk_i,
  input  logic            rst_i,

  // ── local client side ───────────────────────────────────────────────
  input  logic            req_i,
  input  logic            req_we_i,
  input  logic [AW-1:0]   req_adr_i,
  input  logic [DW-1:0]   req_dat_i,
  input  logic [DW/8-1:0] req_sel_i,
  output logic            acc_o,
  output logic            busy_o,
  output logic            done_o,       // ONE pulse per accepted request
  output logic [1:0]      status_o,     // 0=ok 1=error 2=retry
  output logic [DW-1:0]   rdat_o,

  // ── Wishbone MASTER interface ───────────────────────────────────────
  output logic            cyc_o,
  output logic            stb_o,
  output logic            we_o,
  output logic [AW-1:0]   adr_o,
  output logic [DW-1:0]   dat_o,
  output logic [DW/8-1:0] sel_o,
  input  logic [DW-1:0]   dat_i,
  input  logic            ack_i,
  input  logic            err_i,
  input  logic            rty_i
);
  localparam logic [1:0] ST_OK = 2'd0, ST_ERR = 2'd1, ST_RTY = 2'd2;

  logic            active_q;
  logic            we_q;
  logic [AW-1:0]   adr_q;
  logic [DW-1:0]   dat_q;
  logic [DW/8-1:0] sel_q;

  assign acc_o  = req_i & ~active_q;
  assign busy_o = active_q;

  assign cyc_o = active_q;                     // PERMISSION 3.40
  assign stb_o = active_q;
  assign we_o  = we_q;                         // all from the private copy
  assign adr_o = adr_q;                        // (Chapter 5.5)
  assign dat_o = dat_q;
  assign sel_o = sel_q;

  // ── THE TERMINATION, DECODED ONCE ─────────────────────────────────────
  // RULE 3.45 makes these mutually exclusive at the slave, so at most one
  // is asserted. Decoding them in one place means the completion branch
  // cannot disagree with itself about which one arrived.
  logic terminated;
  assign terminated = ack_i | err_i | rty_i;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      active_q <= 1'b0;                        // RULE 3.20
      we_q     <= 1'b0;
      adr_q    <= '0;
      dat_q    <= '0;
      sel_q    <= '0;
      done_o   <= 1'b0;
      status_o <= ST_OK;
      rdat_o   <= '0;
    end else begin
      // ── OBLIGATION 4a: done_o defaults LOW every cycle ───────────────
      // This default is what makes done_o a PULSE structurally. A design
      // that sets done_o in the completion branch and clears it elsewhere
      // depends on the "elsewhere" being reachable; this one cannot fail
      // that way.
      done_o <= 1'b0;

      if (acc_o) begin
        active_q <= 1'b1;
        we_q     <= req_we_i;
        adr_q    <= req_adr_i;
        dat_q    <= req_dat_i;
        sel_q    <= req_sel_i;
      end else if (active_q && terminated) begin
        // ══ THE TERMINATION EDGE ═════════════════════════════════════════
        // All four obligations of Section 1, in one place.

        // ── 1. CAPTURE READ DATA ────────────────────────────────────────
        // Three conditions, each excluding a different wrong cycle:
        //   active_q : the slave is still driving the return path
        //   ack_i    : the termination SUCCEEDED (no defined value on
        //              ERR_I; nothing happened on RTY_I)
        //   !we_q    : this was a read
        // RULE 3.65 gives exactly one cycle in which dat_i is meaningful,
        // and this is it. Deferring by one cycle yields the previous
        // read's value on every read.
        if (ack_i && !we_q) rdat_o <= dat_i;

        // ── 2. RECORD WHICH TERMINATION ─────────────────────────────────
        // Kept DISTINCT rather than merged into a single error flag.
        // ERR and RTY oblige a client to do different things: an error
        // must not be retried, a retry should be (Chapters 4.11, 4.12).
        // Collapsing them here would discard the one bit of information
        // the third termination signal exists to carry.
        if      (ack_i) status_o <= ST_OK;
        else if (err_i) status_o <= ST_ERR;
        else            status_o <= ST_RTY;

        // ── 3. RELEASE THE BUS ──────────────────────────────────────────
        // Clearing active_q negates CYC_O and STB_O together, which is
        // correct for a single-transfer cycle (Chapter 5.2). The slave
        // then drops ACK_O in response, per RULE 3.50.
        active_q <= 1'b0;

        // ── 4. REPORT ONCE ──────────────────────────────────────────────
        // Guarded by active_q, so a termination the master did not
        // provoke cannot generate a completion.
        done_o <= 1'b1;
      end
    end
  end
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_latecapture_master — THE OFF-BY-ONE, isolated for simulation.
//
// NOT A REFERENCE DESIGN. Identical to wb_completion_master except that
// the read-data capture is moved OUTSIDE the active_q guard, so it runs in
// the cycle AFTER the termination. By then the master has negated STB_O,
// the slave has stopped driving DAT_O per RULE 3.65, and the return path
// has reverted to zero.
//
// Everything on the bus remains fully conformant. Only the captured value
// is wrong, and it is wrong in the characteristic way: every read returns
// the PREVIOUS read's value.
// ─────────────────────────────────────────────────────────────────────────
module wb_latecapture_master #(
  parameter int unsigned AW = 30,
  parameter int unsigned DW = 32
) (
  input  logic            clk_i,
  input  logic            rst_i,
  input  logic            req_i,
  input  logic            req_we_i,
  input  logic [AW-1:0]   req_adr_i,
  input  logic [DW-1:0]   req_dat_i,
  input  logic [DW/8-1:0] req_sel_i,
  output logic            acc_o,
  output logic            busy_o,
  output logic            done_o,
  output logic [DW-1:0]   rdat_o,

  output logic            cyc_o,
  output logic            stb_o,
  output logic            we_o,
  output logic [AW-1:0]   adr_o,
  output logic [DW-1:0]   dat_o,
  output logic [DW/8-1:0] sel_o,
  input  logic [DW-1:0]   dat_i,
  input  logic            ack_i,
  input  logic            err_i,
  input  logic            rty_i
);
  logic            active_q, we_q, cap_q;
  logic [AW-1:0]   adr_q;
  logic [DW-1:0]   dat_q;
  logic [DW/8-1:0] sel_q;

  assign acc_o  = req_i & ~active_q;
  assign busy_o = active_q;
  assign cyc_o  = active_q;
  assign stb_o  = active_q;
  assign we_o   = we_q;
  assign adr_o  = adr_q;
  assign dat_o  = dat_q;
  assign sel_o  = sel_q;

  always_ff @(posedge clk_i) begin
    if (rst_i) begin
      active_q <= 1'b0; we_q <= 1'b0; cap_q <= 1'b0;
      adr_q <= '0; dat_q <= '0; sel_q <= '0;
      done_o <= 1'b0; rdat_o <= '0;
    end else begin
      done_o <= 1'b0;
      cap_q  <= 1'b0;

      // ── THE BUG ─────────────────────────────────────────────────────
      // cap_q was set at the termination edge, so this runs ONE CYCLE
      // LATE. dat_i has already reverted — RULE 3.65 means the slave
      // stopped driving it when STB_O went away.
      if (cap_q) rdat_o <= dat_i;

      if (acc_o) begin
        active_q <= 1'b1; we_q <= req_we_i; adr_q <= req_adr_i;
        dat_q <= req_dat_i; sel_q <= req_sel_i;
      end else if (active_q && (ack_i || err_i || rty_i)) begin
        active_q <= 1'b0;
        done_o   <= 1'b1;
        if (ack_i && !we_q) cap_q <= 1'b1;      // defer the capture
      end
    end
  end
endmodule

Reading the pair

Purpose. The first master performs all four completion obligations at the right edge. The second defers one of them by a single cycle.

Interface. status_o replaces Chapter 5.5's merged err_o, keeping the three termination classes distinct at the client boundary.

State. Both hold the outstanding flag and the metadata copy. The broken master adds cap_q, and that register is the bug.

Combinational behaviour. acc_o, the qualifiers, the bus outputs from the private copy, and terminated.

Sequential behaviour. Capture on acceptance; the four completion steps on termination.

Request start. At the acc_o edge, per Chapter 5.5.

Waiting. Bus outputs register-held; nothing moves.

Termination. Level-sampled while active_q is set, per Chapter 5.4.

Read data. Captured at the termination edge under all three conditions. In the broken master, one cycle later, from a bus that has already reverted.

Write data. dat_q driven for the whole transfer, legal under RULE 3.60.

Reset. Synchronous, active high; active_q <= 0 negates both qualifiers.

Failure modes. Section 6.

Simplifications. One outstanding transaction. status_o records the class but implements no retry policy — that decision belongs to the client, and Module 11 owns retry properly.

5. Waveform — The Edge, and the Cycle After It

The termination edge: one cycle of valid read data

7 cycles
Seven clock cycles showing a read transfer terminating. From cycle two through cycle four the master presents the transfer with both qualifiers asserted and a stable address. The slave is busy in cycles two and three, during which its data output is zero because rule three point six five qualifies read data with the termination and no termination is asserted. In cycle four the slave asserts its acknowledge and simultaneously drives the read value A5; this is the single cycle in which the data is meaningful. The correct master's captured register shows A5 from cycle five onward. In cycle five the master has negated both qualifiers, the slave has dropped its acknowledge and its data output has reverted to zero. The late capturing master samples in cycle five and therefore stores zero rather than A5.ACK + data: the ONLY valid cycleACK + data: the ONLY validcyclecaptured; bus already revertedcaptured; bus alreadyrevertedlate capture finds 0x00late capture finds 0x00CLK_ICYC_OSTB_OACK_IDAT_I0x000x000x000xA50x000x000x00rdat (ok)0x000x000x000x000xA50xA50xA5rdat (late)0x000x000x000x000x000x000x00t0t1t2t3t4t5t6
Figure 1 — a read terminating. The data is meaningful for exactly one cycle; a capture one cycle late finds zero.

Cycle 4 is one cycle wide and is the whole window. ACK_I and valid DAT_I coincide because RULE 3.65 ties them together.

Cycle 5 is why deferring fails. The master has negated STB_O; the slave has responded by dropping ACK_O and reverting DAT_O to zero, per RULE 3.50 and OBSERVATION 3.10. There is nothing left to capture.

In a busier system the late capture is worse than zero — it picks up whatever the next transfer puts on the return path, which is the classic "every read returns the previous read's value" signature.

6. Failure Modes and Discriminating Evidence

Symptom: every read returns the previous read's value.

Candidate causes. The capture runs one cycle after the termination.

Discriminating evidence. Put ACK_I, DAT_I and the master's capture strobe on one waveform. If the capture edge is one after the acknowledge edge, that is conclusive — and the perfect off-by-one across every read, with no dependence on address, is itself close to diagnostic.

Likely RTL location. The capture condition — typically if (ack_i) placed where active_q has already cleared.

Property. P1 in Section 7.

Symptom: reads return zero regardless of what the slave holds.

Candidate causes. The same deferred capture in a quiet system, where the return path reverts to zero rather than to another transfer's data.

Discriminating evidence. Check the slave's DAT_O in the acknowledged cycle. Correct there and zero at the master isolates the capture edge; zero at both is a RULE 3.65 violation in the slave.

Symptom: a failed access reports success, with plausible data.

Candidate causes. The capture is gated on terminated rather than on ack_i, so ERR_I or RTY_I also captures.

Discriminating evidence. Issue a read to an unmapped address and inspect status_o and rdat_o. A non-OK status with a changed rdat_o is conclusive — on an error there is no defined read value to have changed.

Property. P2.

Symptom: a client's outstanding-request counter drifts.

Candidate causes. done_o asserted for more than one cycle, or generated from a condition that can recur.

Discriminating evidence. Count done_o assertions against acc_o assertions over a run. Any inequality is conclusive, and the direction says which way it fails.

Likely RTL location. A done_o that is a level rather than a pulse, or one lacking a default assignment.

Property. P3.

Symptom: a completion is reported with no request outstanding.

Candidate causes. done_o derived from ack_i without the active_q guard, so a termination belonging to another master — or bus noise in a broken fabric — generates a spurious completion.

Discriminating evidence. done_o asserted while busy_o was low in the preceding cycle.

Property. P4.

Symptom: an error and a retry are handled identically, and a transient failure becomes permanent.

Candidate causes. The master merges ERR_I and RTY_I into one flag at the client boundary.

Discriminating evidence. Not a waveform question — read the master's client interface. A single error bit where the bus carries three distinct terminations has discarded information RULE 3.45 went to the trouble of keeping exclusive.

Correct approach. status_o's three-way encoding. Chapter 4.12 showed why retrying an error loops forever and not retrying a retry fails needlessly.

7. Verification

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// wb_completion_checker — termination-edge properties.
//
// P1 and P2 are DESIGN OBLIGATIONS derived from RULE 3.65: the
// specification says a slave qualifies DAT_O with its termination, from
// which it follows that a master must capture there — but the
// specification does not dictate master capture timing, so these are
// house policy built on a specification fact. P3 and P4 are LOCAL POLICY
// encoding the client contract.
// ─────────────────────────────────────────────────────────────────────────
module wb_completion_checker #(
  parameter int unsigned DW = 32
) (
  input logic          clk_i,
  input logic          rst_i,
  input logic          cyc_o,
  input logic          stb_o,
  input logic          ack_i,
  input logic          err_i,
  input logic          rty_i,
  input logic          we_o,
  input logic [DW-1:0] rdat_q,        // white-box: captured read data
  input logic          acc_o,         // white-box: acceptance
  input logic          busy_o,
  input logic          done_o
);
  default disable iff (rst_i);

  // P1 — DESIGN OBLIGATION (from RULE 3.65). The captured read register
  //      changes only at the edge of a successful READ termination.
  //      Catches BOTH the off-by-one and an unconditional capture.
  //
  //      $past is required because rdat_q changes AT the edge while the
  //      conditions authorising it were true BEFORE it — the shift
  //      Chapter 4.5 Section 10 warned about getting backwards.
  property p_capture_at_termination_only;
    @(posedge clk_i) $changed(rdat_q)
      |-> $past(cyc_o && stb_o && ack_i && !we_o);
  endproperty
  a_capture_at_termination_only :
    assert property (p_capture_at_termination_only)
    else $error("read data captured outside a successful read termination");

  // P2 — DESIGN OBLIGATION. A failed termination captures nothing. There
  //      is no defined read value on ERR_I and nothing happened on RTY_I.
  property p_no_capture_on_failure;
    @(posedge clk_i) (cyc_o && stb_o && (err_i || rty_i)) |=> $stable(rdat_q);
  endproperty
  a_no_capture_on_failure : assert property (p_no_capture_on_failure)
    else $error("read data captured from a failed termination");

  // P3 — LOCAL POLICY. done_o is a ONE-CYCLE PULSE and follows a real
  //      termination of an outstanding transfer. Catches a level-style
  //      done_o and a completion generated from the wrong condition.
  property p_done_follows_termination;
    @(posedge clk_i) done_o
      |-> $past(busy_o && cyc_o && stb_o && (ack_i || err_i || rty_i));
  endproperty
  a_done_follows_termination : assert property (p_done_follows_termination)
    else $error("completion pulse without a matching bus termination");

  // P4 — LOCAL POLICY. Exactly one completion per acceptance, enforced as
  //      an alternation: an acceptance is always followed by a completion
  //      before the next acceptance. Catches both duplicated and dropped
  //      completions, which P3 alone would not.
  property p_one_done_per_accept;
    @(posedge clk_i) acc_o |=> (!acc_o throughout (done_o[->1]));
  endproperty
  a_one_done_per_accept : assert property (p_one_done_per_accept)
    else $error("a second acceptance occurred before the completion");
endmodule

P1 is the property this chapter exists for, and note that it is not a conformance property despite resting on RULE 3.65. The specification constrains the slave — it says when DAT_O is qualified. What a master does with that window is the master's design, so P1 is house policy built on a specification fact. That distinction is the kind Chapter 5.8 makes systematic.

P4 uses a goto repetition (done_o[->1]) to express alternation rather than trying to count. Counting completions against acceptances in a property is possible but fragile; alternation states the intent directly.

Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection; both masters are elaborated and the off-by-one is simulated in Section 8.

8. Simulation — Read Capture, Measured

Both masters performed three reads of distinct known values from wb_stb_wait_slave with three wait states, then a fourth read, with the captured value recorded after each completion.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  read   slave holds    correct     late
    1      0x11          0x11        0x0
    2      0x22          0x22        0x0
    3      0x33          0x33        0x0
  late-capture master final value: 0x0

The late-capture master returned zero on every read, because in this quiet two-node system the return path reverts to zero once the strobe drops — the slave obeying RULE 3.65 exactly as it should.

Note that its register never changed at all across three reads of three different values. It is not lagging by one; it is sampling a bus that has already gone idle.

In a busier fabric the same bug returns the previous read's value instead, which is harder to spot because the values look plausible. Zero is the friendlier symptom, and a design that sees uniform zeros from every read should suspect the capture edge before suspecting the slave.

9. Common Mistakes

"ACK means the data is available; I can read it next cycle."

Wrong mental model: the read data persists around the acknowledge.

Concrete bug: capture deferred by one cycle.

Observable evidence: every read returning zero, or every read returning the previous read's value — a perfect off-by-one with no address dependence.

Correct model: RULE 3.65 qualifies the slave's DAT_O with its termination. One cycle, then it is gone — and OBSERVATION 3.10 says the slave negates automatically when the strobe drops.

"A termination is a termination; capture on any of them."

Wrong mental model: the transfer ended, so take the data.

Concrete bug: capturing on ERR_I or RTY_I.

Observable evidence: a master reporting a failure while its data register changed — meaningless data that a client may act on.

Correct model: read data accompanies a successful termination. RULE 3.45 keeps the three exclusive precisely so a master can branch on which arrived.

"One error flag is enough at the client interface."

Wrong mental model: the client only needs success or failure.

Concrete bug: ERR_I and RTY_I merged. A transient condition becomes a permanent failure, or a permanent one is retried forever.

Observable evidence: spurious failures under load, or a master looping on an unmapped address.

Correct model: they differ in exactly one respect — whether retrying could succeed — and that is the information the third wire exists to carry. status_o keeps it.

10. Interview Reasoning

In the master's read-data capture, one cycle after the termination instead of at it.

The mechanism. RULE 3.65 qualifies a slave's DAT_O with its own termination, so the data is meaningful in exactly the cycle the acknowledge is asserted. At that edge the master clears its outstanding flag and negates STB_O. The slave, per RULE 3.50 and OBSERVATION 3.10, drops ACK_O and stops driving read data. A capture in the following cycle samples a return path that has already reverted.

Why the previous value specifically. The capture register holds whatever it got last time. If the fabric reverts to zero, every read returns zero. If another transfer is in flight, it picks that up. The consistent case — previous read's value — happens when the register simply is not rewritten, so the client keeps seeing the last successful capture.

What makes it diagnostic. The off-by-one is perfect and address-independent. Every read, every address, always the previous value. Bugs in a slave or in decode vary with address; this one does not. That pattern alone should point at the capture edge.

The one waveform that confirms it. ACK_I, DAT_I, and the master's capture strobe on the same axis. If the capture is one edge after the acknowledge, done.

Why it survives review. if (ack_i) rdat_o <= dat_i; is correct inside the state representing an outstanding transfer and wrong outside it. It is the same line of code in both places, so reading the line tells you nothing — you have to read where it sits.

The related bug worth checking simultaneously. If the capture is gated on terminated rather than ack_i, an errored read also captures. Issue a read to an unmapped address and see whether the data register moved; on an error there is no defined value for it to have moved to.

11. Understanding Check

12. What's Next

Initiation and completion are now both precise: a named acceptance edge with a full capture, and a termination edge with four obligations in the right relationship.

Everything so far has described which edge things happen on. Nothing has yet described what happens between edges — where the combinational paths run, why a slave that answers immediately can be protocol-perfect and still fail timing closure, and what the specification itself says about that tradeoff.

How do all the handshake signals relate around clock edges, and what does that cost in silicon?

Chapter 5.7 — Timing Relationships 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.