Wishbone · Module 5
The Wishbone Handshake
The smallest correct conversation between a Wishbone master and slave: a master presents a transfer and holds it, a slave terminates it, and the transaction exists across an interval rather than at an instant.
Module 4 gave every signal in the Classic interface a meaning, an owner, and a qualifying condition. It deliberately stopped before the question those twelve definitions exist to answer.
What is the smallest correct conversation between a Wishbone master and slave?
1. A Transaction Is an Interval, Not an Event
This is the single idea the rest of the module rests on.
It is tempting to think of a transfer as happening at a moment — the master "sends" a request, the slave "sends" a reply. That model is wrong in a way that produces real bugs, because Wishbone Classic has no messages and nothing is ever sent.
What actually happens is that the master drives a set of levels and holds them. The transfer is presented, continuously, for as many cycles as it takes. The slave sees those levels at every rising edge. When the slave is ready, it drives its termination, and the master — sampling at the same edges — observes it.
Three consequences follow immediately, and each is a chapter later in this module.
The request must persist. A master that presents a transfer and changes its mind next cycle has not performed a transfer; it has produced two partial ones. Chapter 5.5 is about what must be latched and held.
The termination must be attributed. A termination means this outstanding transfer completed. A master that sees ACK_I without knowing which of its own requests it belongs to cannot use it. Chapter 5.6 is about the completion edge.
The duration is not fixed and not knowable in advance. A slave answers when it can. Chapter 5.4 covers what that means for the master.
2. Who Owns Which Transition
Every edge in a Wishbone waveform is driven by exactly one side. Confusing ownership is the root of an entire class of debugging dead ends, so it is worth tabulating before any waveform appears.
| Transition | Owner | Governed by |
|---|---|---|
CYC_O rises | master | RULE 3.25 — no later than the edge qualifying STB_O |
STB_O rises | master | presents the transfer |
ADR/DAT/WE/SEL become meaningful | master | RULE 3.60 — qualified by STB_O |
ACK_O rises | slave | RULE 3.35 — in response to CYC_I & STB_I |
DAT_O becomes meaningful (read) | slave | RULE 3.65 — qualified by its termination |
STB_O falls | master | after observing the termination |
ACK_O falls | slave | RULE 3.50 — in response to STB_I negating |
CYC_O falls | master | when the cycle is over |
Read the last three rows together. The master drops STB_O because it saw ACK_O; the slave drops ACK_O because it saw STB_O drop. That is a loop, and OBSERVATION 3.10 describes the slave half of it as automatic: "SLAVE interfaces automatically negate [ACK_O], [ERR_O] and [RTY_O] when their [STB_I] is negated."
The loop is not a race, because both sides sample at the same rising edge and Wishbone is synchronous throughout — but it is why Chapter 5.7 has to separate what a signal does in simulation time from what is observed at an edge.
3. The Canonical Handshake
CYC, STB, ACK: one transfer, one termination
6 cyclesNarrate it edge by edge — this is the habit the whole module is training.
Before edge 2: the master drives CYC_O, STB_O and a meaningful ADR_O. Nothing has been observed yet.
At edge 2: the slave samples CYC_I & STB_I true. It now has a request. The master samples ACK_I low — no termination, so its transfer is still outstanding.
Between edges 2 and 3: everything the master drives must stay exactly as it is. This is RULE 3.60's qualification read as an obligation across a multi-cycle presentation.
At edge 3: same again. The slave is still working; the master still waits.
Before edge 4: the slave has driven ACK_O and valid read data.
At edge 4 — the termination edge: the master samples ACK_I high. This is the only edge at which the transfer completes, and it is the one edge at which DAT_I is meaningful, per RULE 3.65.
After edge 4: the master may negate CYC_O and STB_O. The slave, seeing STB_I negate, drops ACK_O and stops driving read data.
Count the cycles. The request was presented for three; the termination occupied one. A learner who can produce that narration from a waveform has the core skill this module teaches.
4. RTL — The Running Example
Module 5 uses one system throughout, extended as chapters require, rather than a new toy per chapter:
client request → wb_hs_master → Wishbone Classic → wb_hs_slave → registersConventions, inherited from Module 4 unchanged. AW = 30 word addresses on a 32-bit bus — Chapter 4.3 explained why the two byte-offset bits are not on the bus. DW = 32. SW = DW/8 = 4 byte lanes, per Chapter 4.7. Synchronous active-high reset per RULES 2.30 and 3.00. The qualified-transfer term is always xfer = cyc_i & stb_i.
// ─────────────────────────────────────────────────────────────────────────
// wb_hs_master — the minimal correct single-transfer master.
//
// PURPOSE. Show the smallest master that performs a complete, correct
// handshake. Every later chapter's master is this one with a specific
// weakness repaired, so it is worth reading closely.
//
// INTERFACE. A local client presents a request with req_i; the master
// reports completion with done_o. The client side is NOT Wishbone and is
// deliberately shaped differently so the two are never confused.
//
// CYC/STB. Driven from ONE register here. That is not laziness and it is
// not universally correct — it is explicitly permitted:
//
// PERMISSION 3.40 — "If a MASTER doesn't generate wait states, then
// [STB_O] and [CYC_O] MAY be assigned the same signal."
//
// This master never negates STB_O mid-transfer, so the permission applies.
// Chapter 5.2 shows the case where it does not.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00, 3.20).
// ─────────────────────────────────────────────────────────────────────────
module wb_hs_master #(
parameter int unsigned AW = 30,
parameter int unsigned DW = 32
) (
input logic clk_i,
input logic rst_i,
// ── local client side (not Wishbone) ────────────────────────────────
input logic req_i, // pulse: start a transfer
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 busy_o,
output logic done_o, // one-cycle pulse
output logic [DW-1:0] done_dat_o, // read result, held after done_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
);
// ── STATE ─────────────────────────────────────────────────────────────
// active_q is the whole state machine: the transfer is either outstanding
// or it is not. The metadata registers are what make the request PERSIST,
// which Section 1 identified as the first obligation of an interval-based
// protocol. Driving adr_o straight from req_adr_i would work only if the
// client happened to hold it — Chapter 5.5 makes that failure concrete.
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;
// ── COMBINATIONAL ─────────────────────────────────────────────────────
// Both qualifiers come from active_q (PERMISSION 3.40). Everything else
// comes from the latched metadata, so it is stable for exactly as long as
// the strobe is asserted — RULE 3.60's qualification met structurally
// rather than by a promise in a comment.
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;
assign busy_o = active_q;
// Any of the three terminations ends the transfer. Chapters 4.11 and 4.12
// covered what ERR and RTY additionally oblige; here they end it.
logic terminated;
assign terminated = ack_i | err_i | rty_i;
// ── SEQUENTIAL ────────────────────────────────────────────────────────
always_ff @(posedge clk_i) begin
if (rst_i) begin
// RULE 3.20: STB_O and CYC_O negated at the rising edge following the
// assertion of RST_I, and held negated. active_q drives both.
active_q <= 1'b0;
we_q <= 1'b0;
adr_q <= '0;
dat_q <= '0;
sel_q <= '0;
done_o <= 1'b0;
done_dat_o <= '0;
end else begin
done_o <= 1'b0; // default: done_o is a pulse
if (!active_q) begin
// ── REQUEST START ───────────────────────────────────────────────
// The metadata is captured HERE, once. From the next edge onward
// the client may do whatever it likes with its inputs.
if (req_i) 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
end else if (terminated) begin
// ── TERMINATION ─────────────────────────────────────────────────
// Sampled as a LEVEL in the cycle the transfer is presented, never
// as an edge. Chapter 5.4 explains why an edge would be wrong.
active_q <= 1'b0;
done_o <= 1'b1;
// Read data is captured on a SUCCESSFUL READ only: there is no
// defined read value on ERR or RTY (Chapter 4.5), and a write has
// no read data at all.
if (ack_i && !we_q) done_dat_o <= dat_i;
end
end
end
endmodule// ─────────────────────────────────────────────────────────────────────────
// wb_hs_slave — the minimal correct register-bank slave.
//
// PURPOSE. Answer every qualified transfer, in the cycle it is presented.
//
// TERMINATION TIMING. ack_o is combinational from the qualified transfer.
// That is not a shortcut; it is the form the specification anticipates:
//
// PERMISSION 3.30 — "The assertion of [ACK_O], [ERR_O], and [RTY_O] MAY
// be asynchronous to the [CLK_I] signal (i.e. there is a combinatorial
// logic path between [STB_I] and [ACK_O])."
//
// OBSERVATION 3.40 — "The asynchronous assertion ... assures that the
// interface can accomplish one data transfer per clock cycle."
//
// Chapter 5.7 weighs that against OBSERVATION 3.50's loopback delay.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_hs_slave #(
parameter int unsigned OFF_AW = 4, // 16 local registers
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 [OFF_AW-1:0] adr_i, // LOCAL offset
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 [DW-1:0] reg0_o // observable state
);
localparam int unsigned NL = DW/8;
localparam logic [OFF_AW-1:0] R_CTRL = 'd0;
localparam logic [OFF_AW-1:0] R_SCRAT = 'd1;
localparam logic [OFF_AW-1:0] R_ID = 'd2; // read-only constant
logic [DW-1:0] ctrl_q, scrat_q;
assign reg0_o = ctrl_q;
// ── THE QUALIFIED TRANSFER ────────────────────────────────────────────
// RULE 3.30 forbids responding to any slave signal while CYC_I is negated.
// RULE 3.35 requires the termination to be generated from the AND of
// CYC_I and STB_I. One term, used everywhere.
logic xfer;
assign xfer = cyc_i & stb_i;
// This slave keeps pace and does not use ERR_O or RTY_O, so it is exactly
// the case PERMISSION 3.10 describes: ACK_O tied to the AND of STB_I and
// CYC_I. Adding an error output would move it under PERMISSION 3.15.
assign ack_o = xfer;
// ── WRITE ACCEPTANCE ──────────────────────────────────────────────────
// Gated on ack_o, NOT merely on xfer. Here they are identical because
// this slave never waits — but writing it this way makes the rule
// explicit, and Chapter 5.3's delayed slave depends on the distinction:
// a request PRESENTED for four cycles must still be ACCEPTED once.
logic write_ok;
assign write_ok = xfer & we_i & ack_o & (adr_i != R_ID);
always_ff @(posedge clk_i) begin
if (rst_i) begin
ctrl_q <= '0;
scrat_q <= '0;
end else if (write_ok) begin
for (int unsigned n = 0; n < NL; n++) begin
if (sel_i[n]) begin
unique case (adr_i)
R_CTRL: ctrl_q [n*8 +: 8] <= dat_i[n*8 +: 8];
R_SCRAT: scrat_q[n*8 +: 8] <= dat_i[n*8 +: 8];
default: ;
endcase
end
end
end
end
// ── READ PATH ─────────────────────────────────────────────────────────
// RULE 3.65: a slave qualifies its DAT_O with its termination. Driving
// zero otherwise also keeps a merged return path clean (Chapter 3.5).
always_comb begin
dat_o = '0;
if (xfer && !we_i && ack_o) begin
unique case (adr_i)
R_CTRL: dat_o = ctrl_q;
R_SCRAT: dat_o = scrat_q;
R_ID: dat_o = 32'h5742_0001; // "WB", revision 1
default: dat_o = '0;
endcase
end
end
endmoduleReading the pair
Purpose. Together these are a complete, correct Wishbone Classic path. Everything in Module 5 after this chapter is a refinement of one of them.
Interface. The client side (req_i / done_o / busy_o) is deliberately not Wishbone-shaped. Keeping the two vocabularies visibly different is what stops a reader assuming the client protocol and the bus protocol have the same rules — they do not, and Chapter 5.5 turns that into a design obligation.
State. The master holds one flag plus the request metadata. The slave holds two registers. The metadata registers are the interesting part: they exist solely so the request persists across edges the client knows nothing about.
Combinational behaviour. Master: both qualifiers and all four detail outputs, straight from state. Slave: the qualified-transfer term, the acknowledge, the write-acceptance term, and the read multiplexer.
Sequential behaviour. Master: capture on req_i, release on termination. Slave: one lane-gated register update.
Request start. CYC_O and STB_O both rise at the edge following req_i, satisfying RULE 3.25's "no later than" trivially by rising together.
Waiting. Everything the master drives comes from registers that are written only at the start edge, so stability across the wait is structural.
Termination. The master samples ack_i/err_i/rty_i as levels while active_q is set.
Read data. Captured only on ack_i && !we_q.
Write data. dat_o is driven from dat_q for the whole transfer, including reads — legal, because RULE 3.60 qualifies DAT_O with STB_O and not with WE_O. Chapter 4.6 showed why a slave must therefore check WE_I.
Reset. Synchronous, active high; active_q <= 0 negates both qualifiers per RULE 3.20.
Failure modes. Section 6, and every subsequent chapter.
Simplifications. One outstanding transfer. No ERR_O/RTY_O in the slave. No wait states — added in 5.3. No interconnect; the slave's adr_i is assumed already decoded to a local offset, as Chapter 3.5 described.
5. The Debugging Path
When a Wishbone transfer misbehaves, there are four places to look and they are always the same four. Establishing the order here means later chapters can refer to it instead of repeating it.
Probe in order, and stop at the first surprise.
P1 — does the master drive CYC_O and STB_O at all? If not, the fault is in the master's own state machine or its client interface, and nothing downstream matters.
P2 — do they arrive at the intended slave? If P1 is fine and P2 is empty, the fault is address decode or forward routing in the interconnect. The slave is innocent.
P3 — does the slave generate ACK_O locally? If P2 is fine and P3 is empty, the fault is inside the slave. If ACK_O appears at a different slave than intended, it is a decode problem masquerading as a slave problem.
P4 — does ACK_I reach the master? If P3 is fine and P4 is empty, the fault is the return path — the response multiplexer, or a master that does not implement the termination the slave produced. OBSERVATION 3.35 names the second case explicitly: "If the SLAVE supports the [ERR_O] or [RTY_O] signals, but the MASTER does not support these signals, deadlock may occur."
Why this ordering matters more than it looks. All four failures produce the same symptom at the master — a strobe held forever with no termination. Chapter 4.8 called that the signature of an unanswered transfer, and it is, but it does not say who failed to answer. The probe sequence is what converts one symptom into one location.
6. Failure Modes and Discriminating Evidence
Symptom: the master hangs with STB_O asserted and no termination.
Candidate causes. Any of the four stages in Section 5.
Discriminating evidence. Walk P1→P4. The first probe where the expected signal is absent names the stage. This is the only systematic way to tell the four apart, because the master-side waveform is identical for all of them.
Likely RTL location. Determined by the probe, not guessed.
Property. A bounded-completion check — see Chapter 5.8 for why that is local policy rather than a protocol rule, and RECOMMENDATION 3.10 for what the specification suggests instead.
Symptom: the master completes immediately, always, regardless of address.
Candidate causes. A slave with ACK_O tied high rather than tied to the qualified transfer.
Discriminating evidence. Check ACK_O while CYC_I and STB_I are both low. Asserted is conclusive and is a direct RULE 3.35 violation.
Likely RTL location. The slave's ack_o assignment.
Symptom: read data is wrong but the transfer completes normally.
Candidate causes. The master captures outside the termination cycle, or the slave drives data outside its termination.
Discriminating evidence. Compare the slave's DAT_O in the acknowledged cycle against what the master stored. Correct at the slave and wrong at the master isolates the capture; wrong at both isolates the slave and is a RULE 3.65 violation.
Likely RTL location. The master's capture condition, or the slave's read-path gating.
Symptom: the transfer works once and the second one never starts.
Candidate causes. The master never returned to idle — active_q was not cleared, usually because the termination branch is unreachable.
Discriminating evidence. busy_o stuck high with no STB_O, or STB_O never dropping after an observed ACK_I.
Likely RTL location. The master's termination branch.
7. Verification
// ─────────────────────────────────────────────────────────────────────────
// wb_hs_checker — the module-wide handshake invariants, in one place.
//
// These four are re-used and extended by every later chapter in Module 5.
// Each is labelled SPECIFICATION or LOCAL POLICY, because the distinction
// changes what a failure means and who has to fix it.
// ─────────────────────────────────────────────────────────────────────────
module wb_hs_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 m_active, // white-box: transfer outstanding
input logic m_done // white-box: local completion pulse
);
default disable iff (rst_i);
// P1 — SPECIFICATION (RULE 3.25). CYC_O is asserted no later than the
// edge that qualifies STB_O, so a strobe without a cycle is never
// legal. Stated as the plain implication, checked every cycle:
// writing it as $rose(stb_o) |-> $rose(cyc_o) would WRONGLY forbid
// a master that opens its cycle early to request the bus.
property p_stb_implies_cyc;
@(posedge clk_i) stb_o |-> cyc_o;
endproperty
a_stb_implies_cyc : assert property (p_stb_implies_cyc)
else $error("RULE 3.25: STB_O asserted without CYC_O");
// P2 — SPECIFICATION (RULE 3.45). The three terminations are mutually
// exclusive. Written as an explicit integer sum rather than with
// $countones over a concatenation: Chapter 3.7 recorded an Icarus
// defect in exactly that construct which produced phantom failures.
property p_one_termination;
@(posedge clk_i) (int'(ack_i) + int'(err_i) + int'(rty_i)) <= 1;
endproperty
a_one_termination : assert property (p_one_termination)
else $error("RULE 3.45: more than one termination asserted");
// P3 — LOCAL POLICY. A termination is only meaningful against an
// outstanding transfer. This is NOT a Wishbone rule — the bus
// cannot see a master's intent — but a master acting on a
// termination it did not provoke is always wrong.
property p_termination_needs_outstanding;
@(posedge clk_i) (ack_i || err_i || rty_i) |-> m_active;
endproperty
a_termination_needs_outstanding :
assert property (p_termination_needs_outstanding)
else $error("termination observed with no outstanding transfer");
// P4 — LOCAL POLICY. One bus transaction yields exactly one local
// completion. Catches a duplicated done_o pulse, which silently
// double-counts at the client.
property p_one_done_per_transaction;
@(posedge clk_i) m_done |-> $past(m_active && (ack_i || err_i || rty_i));
endproperty
a_one_done_per_transaction : assert property (p_one_done_per_transaction)
else $error("local completion without a matching bus termination");
endmoduleP1 and P2 are conformance; a passive monitor on the bus can check both, and they hold for every Wishbone interface ever built.
P3 and P4 need white-box signals and encode this master's contract rather than the standard's. That split is not incidental — Chapter 4.9 §7 showed that protocol conformance is checkable from wires while intent is not, and Chapter 5.8 makes the distinction a design tool.
Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection only; the synthesizable RTL above is elaborated and simulated, and this module reports the two separately throughout.
8. Common Mistakes
"STB is valid and ACK is ready."
Wrong mental model: importing valid/ready semantics wholesale.
Concrete bug: a slave asserting ACK_O as an advertised readiness, independent of any presented transfer — typically tied high.
Observable evidence: every transfer completing in one cycle including ones to unmapped addresses, and, in a shared fabric, transfers completing that were addressed to a different slave.
Correct model: RULE 3.35 makes the termination a response. The nearest legal equivalent is PERMISSION 3.10's ACK_O tied to the AND of STB_I and CYC_I — which is a response, and which carries two preconditions.
"The request is sent, so the master can move on."
Wrong mental model: a transfer is a message.
Concrete bug: a master that drives ADR_O from a live client input rather than a latched copy, so the address changes while the transfer is outstanding.
Observable evidence: the slave acting on an address the client had already moved past — and under a fast slave the bug never appears at all, because the transfer completes before anything changes.
Correct model: the transfer is presented continuously and must persist until terminated. Chapter 5.5 builds the master that gets this right and simulates the failure.
"ACK arriving means the data is on the bus somewhere."
Wrong mental model: read data is available around the acknowledge.
Concrete bug: capturing DAT_I one cycle after ACK_I.
Observable evidence: every read returning the previous read's value — the off-by-one Chapter 4.5 traced.
Correct model: RULE 3.65 qualifies the slave's DAT_O with its termination. The data is meaningful in the termination cycle and is not held afterwards.
9. Interview Reasoning
A master presents a transfer and holds it until a slave terminates it.
The master's claim has two parts. CYC_O says a bus cycle is in progress — this master is mid-operation and, in a shared system, is requesting the bus. STB_O says that within that cycle, a specific transfer is being presented right now. Everything else the master drives — address, write data, direction, byte lanes — is detail about that transfer, and RULE 3.60 makes it meaningful only while the strobe qualifies it.
The slave's answer is a response, not a state. RULE 3.35 requires the termination to be generated in response to the logical AND of CYC_I and STB_I. The slave is not reporting its own condition; it is answering a specific question it was asked.
The transfer occupies an interval. It begins at the edge where the slave first observes the qualified request and ends at the edge where the master observes the termination. In between, the master changes nothing and the slave works.
Why I would avoid the valid/ready framing even loosely. It predicts that a slave can advertise readiness with no request present, and that prediction is exactly wrong — a slave doing so terminates transfers it was never given, including other slaves'. The analogy fails at the one place a candidate is most likely to be tested.
The asymmetry worth naming. Initiation is entirely the master's; completion is entirely the slave's. Neither can do the other's job, and there is no negotiation — which is why the whole protocol fits in three wires.
10. Understanding Check
11. What's Next
The handshake is now visible as a whole: a claim, a wait, an answer, a release. The rest of Module 5 takes it apart.
Both halves of the master's claim have been driven from one register so far, and PERMISSION 3.40 says that is fine — for a master that never waits. But the two signals mean different things, and the difference decides what happens to a transfer when a master releases the bus too early.
When does a basic bus cycle begin and end, relative to the transfer inside it?
Chapter 5.2 — CYC — Cycle answers it. The full path is on the Wishbone curriculum index.
Continue learning
Related tutorials
- Related topic
The Wishbone Mental Model
Wishbone is two levels, not one: a master opens a bus cycle and presents transfers inside it, and an addressed slave terminates each transfer with exactly one of three signals. That two-level structure is why describing Wishbone as valid/ready with renamed signals is wrong rather than merely imprecise.
- Related topic
Control Signals
Address and data are payload; they say what values are involved and nothing about what should happen to them. Control information is what makes a bus interpretable: a qualifier that says a request is real, a direction, lane enables, a completion and an error — each derived from a failure that occurs without it.
- Related topic
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.
- Related topic
ACK_I
The only mandatory termination. What a slave promises by asserting it, how wait states work without a wait signal, and why RULE 3.55 requires a master to keep working when a slave holds it asserted.
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.
