Wishbone · Module 7
ACK Timing
A write slave's acknowledge ends the transfer; it is not a write-enable. Separating protocol termination from internal commit is what lets a slave register its response — and what makes a stale-context bug possible.
Both slaves so far committed on the same edge they acknowledged, because that is the policy Chapter 7.1 declared. This chapter takes that coincidence apart.
When should a write slave acknowledge, and how does its termination relate to the state update?
1. What a Write Acknowledge Promises
On a read, ACK_O carries a coherence promise about data travelling back — RULE 3.65 ties the slave's DAT_O to its termination (Chapter 6.4).
A write acknowledge carries no data at all. Its promise is different and, in one way, larger:
The transfer is over, and this slave has taken responsibility for the payload it was presented.
Four things must hold when it asserts, and each breaks differently:
| Must be true | Broken by | Symptom |
|---|---|---|
| this transfer is addressed to me | acknowledging without the select | wrong slave responds; two acknowledges merge |
| a transfer exists | ACK_O tied high, or gated on STB_I alone | completions with no request |
| the write is legal here | a missing writability check | read-only register silently overwritten |
| the payload will be committed correctly | a commit using stale context | ACK with the wrong register changed |
The fourth row is this chapter's. It cannot happen in a slave whose commit and acknowledge are one event — there is nothing stored to go stale. It becomes possible the moment the response is registered, and Section 4 builds one that gets it wrong.
What the acknowledge does not promise. That the value was sensible, that the device has finished acting on it, or that a downstream effect has completed. Chapter 4.10 §1 made the general point; for a write it means a slave with an internal write buffer may legitimately acknowledge on acceptance rather than on the data reaching its final destination.
2. Three Legal Shapes
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.45 — "...slave wait states are easiest implemented using a registered [ACK_O] signal."
| Shape | ACK_O | Commit | Cost |
|---|---|---|---|
| Combinational | same cycle as the request | same edge | long loopback |
| Registered, commit-then-ack | next cycle | the cycle before the ack | +1 cycle; needs stored context |
| Registered, ack-with-commit | next cycle | same edge as the ack | +1 cycle; needs stored context |
All three are conformant. The specification constrains only the termination; the commit column is entirely design policy.
The second row is the interesting one, and it is not a mistake. A slave that captures the request, commits it, and acknowledges afterwards has a perfectly defensible policy — it acknowledges only once the state change has actually happened. A property written as "state changes only when ACK_I was asserted" fails on that correct design, which is exactly why Chapter 7.1 §11 insisted properties be written against the slave's own commit term.
3. RTL — Registered Response, Done Correctly
// ─────────────────────────────────────────────────────────────────────────
// wb_write_ack_reg — registered write response with preserved context.
//
// PURPOSE. Break the combinational loopback by putting a flop between the
// request and the response. The cost is one cycle per write. The NEW
// obligation — and the reason this module is longer than Chapter 7.1's —
// is that a registered response must REMEMBER WHAT IT IS COMMITTING.
//
// ── DECLARED COMMIT POLICY (LOCAL, and DIFFERENT from Chapter 7.1) ────
// This slave CAPTURES the whole write payload at the edge it first sees
// a qualified write, COMMITS from that captured copy on the next edge,
// and returns ACK_O in that same second cycle.
//
// So commit and ACK are still one edge here — but both are one cycle
// LATER than the request, and both are driven from STORED context
// rather than from the bus. That stored context is the new risk.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_write_ack_reg #(
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 [OFF_AW-1:0] adr_i,
input logic [DW-1:0] dat_i,
input logic [DW/8-1:0] sel_i,
output logic ack_o,
output logic err_o,
output logic [DW-1:0] control_o,
output logic [DW-1:0] outdata_o
);
localparam int unsigned NL = DW/8;
localparam logic [OFF_AW-1:0] O_CTRL = 4'd2;
localparam logic [OFF_AW-1:0] O_OUT = 4'd6;
localparam logic [OFF_AW-1:0] O_ID = 4'd4;
logic [DW-1:0] ctrl_q, outdata_q;
assign control_o = ctrl_q;
assign outdata_o = outdata_q;
logic xfer;
assign xfer = cyc_i & stb_i; // RULES 3.30 & 3.35
// ── CAPTURED REQUEST CONTEXT ──────────────────────────────────────────
// pend_q says a response is owed. The other four registers are the
// PAYLOAD COPY. All five load in the same edge, from the same cycle's
// inputs, so they cannot describe different transactions.
logic pend_q;
logic [OFF_AW-1:0] off_q;
logic [DW-1:0] dat_q;
logic [DW/8-1:0] sel_q;
logic we_q;
logic writable_q;
always_comb begin
unique case (off_q)
O_CTRL, O_OUT: writable_q = 1'b1;
default: writable_q = 1'b0;
endcase
end
logic known_q;
always_comb begin
unique case (off_q)
O_CTRL, O_OUT, O_ID: known_q = 1'b1;
default: known_q = 1'b0;
endcase
end
// ── TERMINATION ───────────────────────────────────────────────────────
// Asserted only while a response is pending AND the master is still
// presenting a transfer. The second term matters: without it this slave
// would drive a termination into a bus that is no longer asking, which
// RULES 3.30 and 3.35 forbid and which corrupts the NEXT master's
// transfer in a shared fabric.
logic legal_q;
assign legal_q = known_q & ~(we_q & ~writable_q);
assign ack_o = pend_q & xfer & legal_q;
assign err_o = pend_q & xfer & ~legal_q;
// ── THE COMMIT ────────────────────────────────────────────────────────
// Driven from the CAPTURED context — off_q, dat_q, sel_q, we_q — not
// from the bus. That single choice is the correctness of this module:
//
// from the copy : the write committed is the write that was accepted
// from the bus : the write committed is whatever is on the wires NOW
//
// With a conformant master the two are identical, because RULE 3.60 and
// §3.2.2 require the payload to hold still. Committing from the copy
// means this slave is coherent BY CONSTRUCTION rather than by relying
// on someone else's conformance.
logic commit;
assign commit = ack_o & we_q;
always_ff @(posedge clk_i) begin
if (rst_i) begin
pend_q <= 1'b0;
off_q <= '0;
dat_q <= '0;
sel_q <= '0;
we_q <= 1'b0;
ctrl_q <= '0;
outdata_q <= '0;
end else begin
if (!pend_q) begin
// Capture the whole transaction in one edge.
if (xfer) begin
pend_q <= 1'b1;
off_q <= adr_i;
dat_q <= dat_i;
sel_q <= sel_i;
we_q <= ~(~we_i); // explicit copy of we_i
end
end else begin
// The response was presented this cycle; clear the pending flag so
// a held strobe cannot produce a second acknowledge for the same
// request, and so a stale response cannot outlive its transfer.
pend_q <= 1'b0;
end
if (commit) begin
unique case (off_q)
O_CTRL: for (int unsigned n = 0; n < NL; n++)
if (sel_q[n]) ctrl_q[n*8 +: 8] <= dat_q[n*8 +: 8];
O_OUT: for (int unsigned n = 0; n < NL; n++)
if (sel_q[n]) outdata_q[n*8 +: 8] <= dat_q[n*8 +: 8];
default: ;
endcase
end
end
end
endmodule// ─────────────────────────────────────────────────────────────────────────
// wb_write_ack_stale — THE LOST-CONTEXT BUG, isolated for simulation.
//
// NOT A REFERENCE DESIGN. Identical to wb_write_ack_reg except that the
// commit reads the BUS — adr_i, dat_i, sel_i — instead of the captured
// copy. Every other line, including the acknowledge, is unchanged.
//
// Against a conformant master the two are the same, because RULE 3.60 and
// §3.2.2 require the payload to hold still. The bug is therefore INVISIBLE
// in a well-behaved system, and appears only when paired with a master
// that moves its payload — at which point it commits a transaction that
// was never requested, and acknowledges it.
// ─────────────────────────────────────────────────────────────────────────
module wb_write_ack_stale #(
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 [OFF_AW-1:0] adr_i,
input logic [DW-1:0] dat_i,
input logic [DW/8-1:0] sel_i,
output logic ack_o,
output logic err_o,
output logic [DW-1:0] control_o,
output logic [DW-1:0] outdata_o
);
localparam int unsigned NL = DW/8;
localparam logic [OFF_AW-1:0] O_CTRL = 4'd2;
localparam logic [OFF_AW-1:0] O_OUT = 4'd6;
logic [DW-1:0] ctrl_q, outdata_q;
assign control_o = ctrl_q;
assign outdata_o = outdata_q;
logic xfer; assign xfer = cyc_i & stb_i;
logic pend_q, we_q;
logic [OFF_AW-1:0] off_q;
logic writable_q;
always_comb begin
unique case (off_q)
O_CTRL, O_OUT: writable_q = 1'b1;
default: writable_q = 1'b0;
endcase
end
assign ack_o = pend_q & xfer & writable_q;
assign err_o = pend_q & xfer & ~writable_q;
logic commit; assign commit = ack_o & we_q;
always_ff @(posedge clk_i) begin
if (rst_i) begin
pend_q <= 1'b0; off_q <= '0; we_q <= 1'b0;
ctrl_q <= '0; outdata_q <= '0;
end else begin
if (!pend_q) begin
if (xfer) begin pend_q <= 1'b1; off_q <= adr_i; we_q <= we_i; end
end else begin
pend_q <= 1'b0;
end
// ── THE BUG: adr_i / dat_i / sel_i, not off_q / dat_q / sel_q ────
if (commit) begin
unique case (adr_i)
O_CTRL: for (int unsigned n = 0; n < NL; n++)
if (sel_i[n]) ctrl_q[n*8 +: 8] <= dat_i[n*8 +: 8];
O_OUT: for (int unsigned n = 0; n < NL; n++)
if (sel_i[n]) outdata_q[n*8 +: 8] <= dat_i[n*8 +: 8];
default: ;
endcase
end
end
end
endmoduleReading the pair
Purpose. Both turn a qualified write into a committed register and a termination, one cycle after the request. The first commits from a captured copy; the second reads the bus.
Interface. Identical Wishbone slave interfaces. A master cannot tell them apart — which is why RULE 3.55 requires it to work with either, and why the bug is an integration hazard rather than a local defect.
State. wb_write_ack_reg: the pending flag plus a four-field payload copy, plus the two registers. The stale variant keeps only the offset and direction — the three registers it is missing are the bug.
Combinational logic. xfer, writability and legality from the stored offset, the two exclusive terminations, and commit.
Sequential logic. Capture when idle; clear the pending flag once answered; the masked load on commit.
Write start. The edge at which pend_q sets — the slave's own manufactured start event.
Address. off_q in the correct slave, adr_i in the broken one.
Write data. dat_q versus dat_i. Byte enables. sel_q versus sel_i.
Commit. ack_o & we_q — the declared policy, one cycle after the request.
ACK. Asserted in the second cycle, and only while the master is still presenting.
Waiting. Exactly one wait state. Chapter 7.4 generalises to N.
Reset. Synchronous, active high. Clearing pend_q prevents a response surviving a reset.
Failure modes. Section 6.
Simplifications. we_q <= ~(~we_i) is written that way only to make the copy explicit against the stale variant's we_q <= we_i; they are identical and the double negation would be removed in production. O_ID appears in the legality check but has no commit path, since it is read-only.
4. Waveform — Commit and Acknowledge, One Cycle Late
Registered write response
7 cyclesEdge-by-edge, and note there are now two significant edges rather than one.
Before edge 2. The master presents the whole payload. The slave is idle — pend_q low, ack_o low, because the acknowledge requires pend_q.
At edge 2 — the capture edge. The slave samples a qualified transfer and loads off_q, dat_q, sel_q, we_q and pend_q. Nothing has been committed and nothing acknowledged. The master sees no termination and holds.
Between edges 2 and 3. The master's payload must still be coherent — §3.2.2 requires it until the edge after the strobe negates, and the correct slave no longer depends on that, while the stale one does.
At edge 3 — the commit and termination edge. ack_o is asserted through the cycle, so the master samples it here; in the same instant commit loads ctrl_q from the captured copy.
After edge 3. CONTROL reads 0x0000000F, the master has released, and ACK_O falls with the strobe per RULE 3.50.
Compare Chapter 7.1's Figure 2, where all of this happened at one edge. The same transfer, the same result, one more cycle — and one more register's worth of state that can be wrong.
5. Simulation — Latency, and the Stale-Context Trap
Both slaves, correct payload, conformant master:
=== combinational vs registered write response ===
combinational registered
writes issued 3 3
total busy cycles 3 6
cycles per write 1 2
CONTROL after 0x0000000f 0x0000000f 0x0000000f
OUTPUT after 0xdeadbeef 0xdeadbeef 0xdeadbeef
commit events 3 3Identical results, double the cycles, and exactly one commit per write in both — three writes, three commits.
The stale-context slave, paired with a master that moves its payload:
=== lost context: registered slave + drifting payload ===
requested word 2 (CONTROL) data 0x0000000f sel 1111
payload at the commit edge word 6 (OUTPUT) data 0xdeadbeef
slave's remembered offset 2
slave's committed offset 6
CONTROL after 0x00000000 (never written)
OUTPUT after 0xdeadbeef (never requested)
terminated with ACKThe slave acknowledged a write to CONTROL and committed one to OUTPUT_DATA. It remembered the right offset — off_q is 2 — and committed to a different one, because the commit read the bus.
Neither the master nor the slave reported anything wrong. The master issued one write and received one ACK; the client was told the write to CONTROL succeeded. CONTROL was never touched and a register the software never addressed now holds a value it never asked for.
Note which component is at fault, because it is not obvious. The master violated RULE 3.60 by moving its payload. But the slave is the one that turned a protocol violation into silent, permanent, mis-targeted state — and a slave committing from its captured copy would have written CONTROL correctly despite the master's bug. Correct-by-construction beats correct-if-my-partner-behaves.
6. Failure Modes and Discriminating Evidence
Symptom: ACK returned and a different register changed.
Candidate causes. A registered slave committing from the bus rather than from its captured context, combined with something that moved the payload.
Discriminating evidence. Compare the slave's stored offset against what its commit actually indexed in the commit cycle. A difference is conclusive, and it is one port connection.
Likely RTL location. The commit's address/data/select sources.
Property. P3 in Section 8.
Symptom: ACK returned and no register changed.
Candidate causes. The commit term omits we_q, so a read satisfies it — or sel_q was zero, or the target is read-only and should have errored.
Discriminating evidence. Check ERR_O first. Then check SEL_O. Then check whether commit asserted at all. The three are distinguishable in that order and the first two are free.
Symptom: one write produces two acknowledges.
Candidate causes. The pending flag is not cleared, so a held strobe re-triggers the response.
Discriminating evidence. ACK_O asserted in two consecutive cycles with an unchanged address. Whether that is a bug depends on the master — PERMISSION 3.35 lets a slave hold ACK_O and RULE 3.55 requires masters to cope — but for a write it is worse than for a read, because a second acknowledge may accompany a second commit.
Likely RTL location. The pending flag's clearing condition.
Symptom: a registered response arrives after the master released.
Candidate causes. The termination is derived from pend_q without checking that a transfer is still presented.
Discriminating evidence. ACK_O asserted with STB_I negated — a RULE 3.50 violation, contradicting OBSERVATION 3.10's "automatically negate". In a shared fabric it completes the next master's transfer, so the symptom appears elsewhere.
Likely RTL location. The termination expression. wb_write_ack_reg includes xfer for exactly this.
Symptom: the design works combinationally and breaks when the response is registered.
Candidate causes. Registering the acknowledge made the transfer two cycles long, so a commit gated on the presented request now fires twice.
Discriminating evidence. Count commits against completed writes. The bug appeared because latency was introduced, not because the commit path changed — Chapter 7.4 measures it.
7. The Timing Trade
The combinational write path is a loop the specification names:
OBSERVATION 3.50 — "In large high speed designs the asynchronous assertion of [ACK_O], [ERR_O], and [RTY_O] could lead to unacceptable delay times, caused by the loopback delay from the MASTER to the SLAVE and back to the MASTER."
master flop → decode → slave qualification → ACK_O → response merge → master flopA write's loop is shorter than a read's. Chapter 6.4 §3 traced the read version, which additionally carries a read multiplexer and a full data-width merge on the return leg. A write returns one bit, so the return leg is narrow — which means the combinational form often closes on writes when it would not on reads.
What the commit costs is separate and usually not the problem. The register load is a sequential path — DAT_I through the byte mask to a flop's D input — and it is cut by the flop itself. It does not participate in the loopback at all. Conflating the two is common and leads people to register the response when the timing pressure was actually on the data path, or vice versa.
The decision procedure. Build combinational, synthesise, and read the critical path. If the loopback is not critical, keep it. If it is, register the response — and budget the new correctness obligation, which Section 8's P3 is.
8. Verification
// ─────────────────────────────────────────────────────────────────────────
// wb_write_ack_checker — write-side termination properties.
//
// P1 and P2 are SPECIFICATION (RULES 3.35 and 3.50). P3 is a DESIGN
// OBLIGATION that EXISTS ONLY for a registered slave — a combinational one
// stores no context and cannot violate it. P4 is LOCAL POLICY.
// ─────────────────────────────────────────────────────────────────────────
module wb_write_ack_checker #(
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 ack_o,
input logic err_o,
// white-box, registered slaves only
input logic pend_q,
input logic commit,
input logic [OFF_AW-1:0] off_q, // the remembered offset
input logic [OFF_AW-1:0] commit_off // what the commit actually indexed
);
default disable iff (rst_i);
// P1 — SPECIFICATION (RULE 3.35). The termination is a RESPONSE to a
// qualified transfer. Catches a tied-high ACK_O, one derived from
// STB_I alone, and a registered response that outlives its request.
property p_ack_is_a_response;
@(posedge clk_i) (ack_o || err_o) |-> (cyc_i && stb_i);
endproperty
a_ack_is_a_response : assert property (p_ack_is_a_response)
else $error("RULE 3.35: termination asserted without CYC_I & STB_I");
// P2 — SPECIFICATION (RULE 3.50, OBSERVATION 3.10), contrapositive form.
property p_ack_negates_with_stb;
@(posedge clk_i) !stb_i |-> (!ack_o && !err_o);
endproperty
a_ack_negates_with_stb : assert property (p_ack_negates_with_stb)
else $error("RULE 3.50: termination asserted with STB_I negated");
// P3 — DESIGN OBLIGATION, REGISTERED SLAVES ONLY. The transaction
// committed is the transaction that was accepted. Stated as: at a
// commit, the indexed offset equals the remembered one.
//
// This property has no meaning for a combinational slave, which has
// no off_q to compare against. Registering a response to break a
// timing path therefore ADDS a correctness obligation — a trade
// worth making deliberately rather than by habit.
property p_commit_matches_context;
@(posedge clk_i) commit |-> (commit_off == off_q);
endproperty
a_commit_matches_context : assert property (p_commit_matches_context)
else $error("registered slave committed a different transaction");
// P4 — LOCAL POLICY. At most one commit per pending response: the
// pending flag is cleared, so a held strobe cannot re-trigger.
property p_one_commit_per_pend;
@(posedge clk_i) commit |=> !commit;
endproperty
a_one_commit_per_pend : assert property (p_one_commit_per_pend)
else $error("LOCAL: a second commit followed the first");
endmoduleP3 is this chapter's contribution to the verification plan, and its most interesting property is that it does not apply to every slave. A combinational write slave is coherent by construction.
That is the general shape worth carrying beyond Wishbone: adding state to break a timing path adds an invariant, and the invariant is that the state stays consistent with what it describes. Chapter 6.4 §12 reached the same conclusion from the read side; on a write the cost of violating it is permanent rather than a wrong answer.
Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection; both slaves are elaborated and the simulations in Section 5 were run.
9. Common Mistakes
"ACK writes the register."
Wrong mental model: the termination is a write-enable.
Concrete bug: no RTL bug directly — but a property written from this model fires on a correct commit-then-ack slave, and the over-correction moves a real commit event to satisfy a broken checker.
Observable evidence: an assertion failing on a design that is behaving exactly as its datasheet says.
Correct model: ACK_O is a protocol termination. The commit is a declared internal policy, and properties about it must be written against the design's own term.
"Registered responses are safer."
Wrong mental model: flops reduce risk.
Concrete bug: the lost-context slave — a failure mode that cannot exist in the combinational version, and which Section 5 measured committing to the wrong register with a clean ACK.
Observable evidence: a register the software never addressed holding a value, with no error anywhere.
Correct model: a registered response must remember what it is committing. It buys timing closure and costs a cycle plus a new invariant.
"If the master violates the protocol, the resulting corruption is the master's fault."
Wrong mental model: conformance assigns blame cleanly.
Concrete bug: a slave that commits from the bus. Paired with a drifting master it mis-targets state; paired with a conformant one it is invisible.
Observable evidence: a slave that passes every test it has and corrupts state in one particular integration.
Correct model: a design that is correct only while its partner behaves is a latent integration failure. Committing from the captured copy costs three registers and removes the dependency.
10. Interview Reasoning
Because the commit happens in a different cycle from the request, and by then the bus may be showing something else.
A combinational write slave has no such problem. Its acknowledge and its commit are functions of the inputs present right now, so they necessarily describe the same transaction. There is nothing to preserve because nothing is deferred.
A registered slave defers by at least a cycle. At the moment it commits it must know which offset, what data and which byte lanes it was asked about — and there are two places to get them. The captured copy, loaded when the request arrived. Or the bus.
Against a conformant master the two are identical, because RULE 3.60 qualifies the payload with STB_O and §3.2.2 requires it valid until the edge after the strobe negates. So the bug is invisible in a well-behaved system — which is exactly what makes it dangerous. It passes every unit test until it meets a specific partner.
What happens when it does. I measured it: the slave was asked to write CONTROL with 0x0000000F, remembered offset 2 correctly, and committed to offset 6 with 0xDEADBEEF — because the payload had moved by the commit cycle. It returned ACK. CONTROL was never written; OUTPUT_DATA holds a value nobody requested. No error anywhere.
The part I would emphasise in a review. The master violated the protocol, but the slave is what converted a protocol violation into silent, permanent, mis-targeted state. A slave committing from its own copy writes CONTROL correctly despite the master's bug. That is the difference between correct-by-construction and correct-if-my-partner-behaves, and it costs three registers.
And the verification consequence. P3 — at a commit, the indexed offset equals the remembered one — only exists for registered slaves. Choosing to register a response to close timing is not just a cycle of latency; it adds an invariant that has to be written, bound and budgeted.
11. Understanding Check
12. What's Next
The termination is now a design decision with a declared policy behind it, and the registered form carries a new invariant.
Both registered slaves inserted exactly one cycle. Real peripherals take longer — and while they do, the master is holding a payload that will mutate the device the moment the slave is ready.
What must remain true while a write waits for the slave?
Chapter 7.4 — Wait States answers it. The full path is on the Wishbone curriculum index.
Continue learning
Related tutorials
- Related topic
ACK Generation
A read slave's acknowledge promises that the accompanying data is the right value for the right request. Building it combinationally or from a register is a timing decision with a correctness cost.
- Related topic
Address Space
An address is a number until a decoder turns it into a target selection and a local offset. Range comparison and mask comparison are different engineering choices with different costs; exhaustive, mutually exclusive decode is a property to be proved rather than assumed; and a flat decoder's critical path is what eventually forces a hierarchy.
- 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
The Slave Interface
A Wishbone slave never initiates. It observes a qualified request, interprets a local offset, and ends the transfer with exactly one of three terminations. Everything that makes it reusable comes from what it refuses to know: its own base address, the topology, and which master is asking.
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.
