Wishbone · Module 6
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.
Chapter 6.3 showed that read data is valid for exactly one cycle, and that the termination defines which one. This chapter is about producing that termination.
Chapter 5.4 already covered what ACK means in the handshake — a response rather than an advertised readiness, sampled as a level, with RULE 3.55 constraining the master. This chapter owns the read-specific question: what a read slave must have ready before it may acknowledge, and what building that acknowledge two different ways costs.
When should a read slave acknowledge, and what must be true when it does?
1. What a Read Slave Must Have Before It May Acknowledge
RULE 3.35 makes the termination a response to the AND of CYC_I and STB_I — that is the existence requirement, and every slave in this course satisfies it with a single xfer term.
RULE 3.65 ties the slave's DAT_O to that termination — that is the coherence requirement, and it is the read-specific one.
Reading them together: a slave may assert ACK_O only in a cycle where it is also driving the correct value. The acknowledge and the data are one statement, not two. A slave that produces them from different logic, or on different schedules, can make them disagree — and a master obeying RULE 3.65 will faithfully capture the wrong value.
Three legal shapes, and their trade-offs:
| Shape | ACK_O asserts | Data path | Cost |
|---|---|---|---|
| Combinational | same cycle as the request | register → mux → DAT_O, all in-cycle | long loopback (6.3 §4) |
| Registered, one cycle | cycle after | slave captures the request, answers next cycle | +1 cycle every read |
| Registered, variable | when ready | as above, with a latency source | +N cycles; Chapter 6.5 |
PERMISSION 3.30 explicitly allows the first — "the assertion of [ACK_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 points at the second for wait states. Neither is preferred by the specification.
2. RTL — Two Slaves, Same Function
// ─────────────────────────────────────────────────────────────────────────
// wb_read_ack_comb — combinational read response.
//
// PURPOSE. The shape Chapters 6.1 and 6.3 have used, stated minimally so
// its timing structure is visible. ack_o and dat_o are produced by the same
// combinational logic in the same cycle, which is what makes them coherent
// by construction: there is no stored state that could disagree.
//
// PERMISSION 3.30 allows the combinatorial STB_I -> ACK_O path directly.
// OBSERVATION 3.40 credits it with one data transfer per clock cycle.
// OBSERVATION 3.50 names its cost: the master-to-slave-and-back loopback.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_read_ack_comb #(
parameter int unsigned OFF_AW = 3,
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,
output logic [DW-1:0] dat_o,
output logic ack_o,
output logic err_o,
input logic [DW-1:0] input_data_i,
input logic [7:0] flags_i
);
logic [DW-1:0] count_q;
logic xfer;
assign xfer = cyc_i & stb_i; // RULES 3.30 & 3.35
logic [DW-1:0] mux_value;
logic known_off;
wb_read_mux #(.OFF_AW(OFF_AW), .DW(DW)) u_mux (
.off_i(adr_i),
.status_i({24'd0, flags_i}),
.count_i(count_q),
.ctrl_i('0),
.input_data_i(input_data_i),
.value_o(mux_value),
.known_o(known_off)
);
// ── COHERENT BY CONSTRUCTION ──────────────────────────────────────────
// Both outputs derive from the SAME combinational inputs in the SAME
// cycle. There is no way for the acknowledge to describe a different
// request than the data does, because neither is remembered.
assign err_o = xfer & (~known_off | we_i);
assign ack_o = xfer & known_off & ~we_i;
assign dat_o = ack_o ? mux_value : '0; // RULE 3.65
always_ff @(posedge clk_i) begin
if (rst_i) count_q <= '0;
else count_q <= count_q + 32'd1;
end
endmodule// ─────────────────────────────────────────────────────────────────────────
// wb_read_ack_reg — registered read response, done correctly.
//
// PURPOSE. Break the combinational loopback by putting a flop between the
// request and the response. The cost is one cycle per read. The NEW
// obligation — and the whole reason this module is longer than the
// combinational one — is that a registered response must REMEMBER WHAT IT
// IS ANSWERING.
//
// A combinational slave cannot get the context wrong because it holds no
// context. This one holds an offset, and if that offset and the returned
// data ever disagree, the master captures a coherent-looking wrong value.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_read_ack_reg #(
parameter int unsigned OFF_AW = 3,
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,
output logic [DW-1:0] dat_o,
output logic ack_o,
output logic err_o,
input logic [DW-1:0] input_data_i,
input logic [7:0] flags_i
);
logic [DW-1:0] count_q;
logic xfer;
assign xfer = cyc_i & stb_i;
// ── CAPTURED REQUEST CONTEXT ──────────────────────────────────────────
// pend_q says a response is owed. off_q remembers WHICH offset it is
// owed for. Both are loaded from the same cycle's inputs, so they cannot
// describe different requests.
logic pend_q;
logic [OFF_AW-1:0] off_q;
logic was_read_q;
// ── THE RESPONSE ──────────────────────────────────────────────────────
// The multiplexer is driven by off_q — the REMEMBERED offset — not by
// adr_i. That single choice is the correctness of this module:
//
// driven by off_q : the data matches the request being answered
// driven by adr_i : the data matches whatever is on the bus NOW
//
// With a well-behaved master the two are identical, because RULE 3.60
// requires the address to hold still. Driving from off_q means this
// slave stays coherent even against a master that violates it — and,
// more importantly, it is coherent BY CONSTRUCTION rather than by
// relying on someone else's conformance.
logic [DW-1:0] mux_value;
logic known_off;
wb_read_mux #(.OFF_AW(OFF_AW), .DW(DW)) u_mux (
.off_i(off_q),
.status_i({24'd0, flags_i}),
.count_i(count_q),
.ctrl_i('0),
.input_data_i(input_data_i),
.value_o(mux_value),
.known_o(known_off)
);
// The termination is asserted only while a response is pending AND the
// master is still presenting a transfer. The second term matters: if the
// master somehow withdrew, this slave must not terminate into a bus that
// is no longer asking (RULES 3.30, 3.35).
assign ack_o = pend_q & xfer & known_off & ~was_read_q ? 1'b0 :
pend_q & xfer & known_off & was_read_q;
assign err_o = pend_q & xfer & (~known_off | ~was_read_q);
assign dat_o = ack_o ? mux_value : '0; // RULE 3.65
always_ff @(posedge clk_i) begin
if (rst_i) begin
pend_q <= 1'b0;
off_q <= '0;
was_read_q <= 1'b0;
count_q <= '0;
end else begin
count_q <= count_q + 32'd1;
if (!pend_q) begin
// Capture the request. From here the response is determined by
// off_q alone, regardless of what the bus does next.
if (xfer) begin
pend_q <= 1'b1;
off_q <= adr_i;
was_read_q <= ~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 clear it too if the master withdrew, so a stale
// response cannot outlive its transfer (RULE 3.50).
pend_q <= 1'b0;
end
end
end
endmoduleReading the pair
Purpose. Both turn a read request into a value and a termination. The first does it in-cycle; the second does it one cycle later, with the loopback cut.
Interface. Identical Wishbone slave interfaces. A master cannot tell them apart except by latency — which is precisely why RULE 3.55 requires it to work with either.
State. Combinational: only the free-running counter. Registered: the counter plus pend_q, off_q and was_read_q — the request context, which is the new state and the new risk.
Combinational logic. Combinational slave: xfer, the mux, two terminations, the RULE 3.65 gate. Registered slave: the same, but the mux is driven from off_q rather than adr_i.
Sequential logic. Registered slave: capture the request when idle, clear the pending flag once answered.
Read start. Combinational: no start event — the response is a function of the inputs. Registered: the edge at which pend_q sets.
Address. Combinational: adr_i directly. Registered: off_q, the remembered copy.
Data return. Both gate dat_o with ack_o per RULE 3.65.
ACK. Combinational: same cycle. Registered: the following cycle, and only while the master is still presenting.
Capture. Not here — the master's, at the termination edge.
Waiting. The registered slave inserts exactly one wait state. Chapter 6.5 generalises to N.
Reset. Synchronous, active high. The registered slave clears pend_q, which is what prevents a response surviving a reset.
Failure modes. Section 5.
Simplifications. CONTROL is tied to zero in both, since this chapter is about the termination rather than the register file. Neither implements writes.
3. The Timing Trade, Concretely
The combinational read path is the longest loop in a Wishbone system, because the return leg carries data as well as a termination:
master flop → decode → slave mux → DAT_O gate → response merge → master flopEvery stage is inside one clock period. OBSERVATION 3.50 names this — "the loopback delay from the MASTER to the SLAVE and back to the MASTER" — and it grows with slave count at both ends, since the decode fans out and the merge collects.
The registered read path cuts the loop at the slave's flop:
master flop → decode → slave flop (leg 1)
slave flop → mux → gate → merge → master flop (leg 2)Each leg gets a full period. The cost is one cycle of latency on every read, paid whether or not the timing needed it.
Combinational vs registered read response
7 cyclesRead the two ACK traces against the two STB traces. The combinational slave's acknowledge is asserted in the cycle the request is presented — Chapter 5.7's CONTINUATION interval is empty, and the whole loopback resolves inside cycle 2. The registered slave's request is captured at the edge ending cycle 2 and answered in cycle 3.
Both DAT_I traces show the value for exactly one cycle, coincident with their own acknowledge — RULE 3.65 holding in both.
The decision procedure, which matters more than the answer:
Build it combinational. Simpler, one transfer per clock, and it often closes without difficulty.
Synthesise and read the critical path — the path, not just the slack number. If the loopback is not critical, the question is settled; do not spend a cycle on every read to fix a problem the tool says you do not have.
If it is critical, consider hierarchy before registering every slave. A registered bridge between two segments cuts the loop once, rather than adding a cycle to every peripheral.
Then register the response where it is genuinely needed, and re-measure.
What not to do is register reflexively. That is a cycle on every read in the system, unconditionally — and, as Section 4 shows, it introduces a failure mode that did not previously exist.
4. The Failure a Registered Response Creates
// ─────────────────────────────────────────────────────────────────────────
// wb_read_ack_stale — THE LOST-CONTEXT BUG, isolated for simulation.
//
// NOT A REFERENCE DESIGN. Identical to wb_read_ack_reg except for ONE
// port connection: the read multiplexer is driven from adr_i — the bus
// address RIGHT NOW — instead of from off_q, the remembered offset.
//
// Against a conformant master the two are the same, because RULE 3.60
// requires ADR_O to hold still for the transfer's duration. The bug is
// therefore INVISIBLE in a well-behaved system.
//
// It appears the moment the address moves during an outstanding read —
// which Chapter 6.2 showed a walking master doing — and it converts that
// master's bug into a COHERENT-LOOKING wrong answer: the slave
// acknowledges, and the data it returns belongs to a different register
// than the one the transfer was for.
// ─────────────────────────────────────────────────────────────────────────
module wb_read_ack_stale #(
parameter int unsigned OFF_AW = 3,
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,
output logic [DW-1:0] dat_o,
output logic ack_o,
output logic err_o,
input logic [DW-1:0] input_data_i,
input logic [7:0] flags_i
);
logic [DW-1:0] count_q;
logic xfer; assign xfer = cyc_i & stb_i;
logic pend_q;
logic [OFF_AW-1:0] off_q;
logic was_read_q;
logic [DW-1:0] mux_value;
logic known_off;
// ── THE BUG: off_i is adr_i, not off_q ────────────────────────────────
wb_read_mux #(.OFF_AW(OFF_AW), .DW(DW)) u_mux (
.off_i(adr_i), // <-- should be off_q
.status_i({24'd0, flags_i}),
.count_i(count_q),
.ctrl_i('0),
.input_data_i(input_data_i),
.value_o(mux_value),
.known_o(known_off)
);
assign ack_o = pend_q & xfer & known_off & was_read_q;
assign err_o = pend_q & xfer & (~known_off | ~was_read_q);
assign dat_o = ack_o ? mux_value : '0;
always_ff @(posedge clk_i) begin
if (rst_i) begin
pend_q <= 1'b0; off_q <= '0; was_read_q <= 1'b0; count_q <= '0;
end else begin
count_q <= count_q + 32'd1;
if (!pend_q) begin
if (xfer) begin
pend_q <= 1'b1; off_q <= adr_i; was_read_q <= ~we_i;
end
end else begin
pend_q <= 1'b0;
end
end
end
endmoduleThe bug is one port connection, and it is invisible against any conformant master. That is what makes it worth showing: it is a latent incompatibility rather than an outright defect, and it only manifests when paired with a different component's bug.
Why that combination is dangerous. Chapter 6.2 showed a walking master receiving an error, because the address it drifted to was unmapped. Pair it with this slave and the outcome is worse: the slave has a valid remembered request, acknowledges it, and returns data from the drifted address. The master gets ACK and a plausible value from the wrong register — no error anywhere, and nothing in the trace flagging a problem.
5. Failure Modes and Discriminating Evidence
Symptom: ACK arrives with the wrong register's data, and the address on the bus was correct throughout.
Candidate causes. A registered slave whose multiplexer is driven from the live bus rather than the remembered offset — combined with something that moved the address. Or a multiplexer case arm that is simply wrong.
Discriminating evidence. Compare the slave's remembered offset against its multiplexer input in the acknowledged cycle. If they differ, the context was lost; if they agree and the data is still wrong, the fault is the case arm (Chapter 6.3).
Likely RTL location. The multiplexer's offset port.
Property. P3 in Section 7.
Symptom: a read completes but the data is garbage, only with a registered slave.
Candidate causes. The acknowledge is asserted before the registered data has settled — the two produced on different schedules.
Discriminating evidence. Check whether ACK_O and a correct DAT_O coincide. If the acknowledge leads the data by a cycle, they are generated independently, which is the coherence failure RULE 3.65 exists to prevent.
Likely RTL location. Separate state machines for the termination and the data path — a structure worth rejecting in review on its own.
Symptom: a slave acknowledges transfers addressed elsewhere.
Candidate causes. ACK_O derived without the per-slave select, or tied high.
Discriminating evidence. Check CYC_I and STB_I at that slave in the acknowledging cycle. Either negated is a direct RULE 3.35 violation. Chapter 6.2's decode gates STB per slave precisely so this cannot happen at the fabric level.
Property. P1.
Symptom: one read produces two acknowledges.
Candidate causes. A registered slave whose 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 a master counting terminations will double-count.
Likely RTL location. The pending flag's clearing condition.
Property. P2.
Symptom: a registered response arrives after the master gave up.
Candidate causes. The slave terminates based on its own pending flag 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 this corrupts the next master's transfer, so the symptom surfaces elsewhere.
Likely RTL location. The termination expression — wb_read_ack_reg includes xfer in ack_o for exactly this reason.
6. Simulation — Latency and Coherence, Measured
Both slaves answered the same sequence of reads from Chapter 6.1's wb_read_master.
=== SIMULATION - combinational vs registered read response ===
combinational registered
reads issued 5 5
total busy cycles 5 10
cycles per read 1 2
STATUS (0x000000a5) 0x000000a5 0x000000a5
COUNT (moving) 0x00000007 0x00000008
INPUT_DATA (0xcafebabe) 0xcafebabe 0xcafebabe
ID (0x57420601) 0x57420601 0x57420601
values matching expectation 4/4 4/4Identical results, double the cycles. Every fixed value matched in both, and the registered slave took exactly one extra cycle per read.
COUNT differs between them and that is correct — it is a free-running counter, so a read that completes a cycle later legitimately returns a later value. A test that compared COUNT across the two implementations would report a false failure, which is a useful reminder that moving values need different assertions than fixed ones.
The lost-context slave was then paired with Chapter 6.2's walking master, reading INPUT_DATA at word 3 so that the drifted address lands on word 4 — ID, a register that is implemented:
=== lost context + walking address ===
requested word 3 (INPUT_DATA = 0xcafebabe)
slave's remembered offset 3
slave's mux input at ACK 4
value returned 0x57420601
terminated with ACKThe slave remembered the right request — offset 3 — and returned the contents of offset 4. It terminated with ACK, so the master recorded a successful read of INPUT_DATA and stored ID's value.
Neither component reported anything wrong, and the master's view is of a completely normal read.
7. Verification
// ─────────────────────────────────────────────────────────────────────────
// wb_read_ack_checker — read-side termination properties.
//
// P1 and P2 are SPECIFICATION (RULES 3.35 and 3.50). P3 is a DESIGN
// OBLIGATION that only EXISTS for a registered slave — a combinational one
// holds no context and cannot violate it. That is worth noting: choosing a
// registered response adds a property to the verification plan.
// ─────────────────────────────────────────────────────────────────────────
module wb_read_ack_checker #(
parameter int unsigned OFF_AW = 3,
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 ack_o,
input logic err_o,
input logic [DW-1:0] dat_o,
// white-box, registered slaves only
input logic pend_q,
input logic [OFF_AW-1:0] off_q,
input logic [OFF_AW-1:0] mux_off // what the mux is actually indexing
);
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). Terminations are
// negated in response to STB_I negating. 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 data returned
// describes the request being answered. Stated as: while a response
// is pending, the multiplexer indexes the REMEMBERED offset.
//
// This property has no meaning for a combinational slave, which has
// no off_q to compare against. Adding a register to break a timing
// path therefore ADDS a correctness obligation — a trade worth
// making deliberately rather than by habit.
property p_response_matches_request;
@(posedge clk_i) (pend_q && ack_o) |-> (mux_off == off_q);
endproperty
a_response_matches_request : assert property (p_response_matches_request)
else $error("registered response answered from the wrong offset");
// P4 — SPECIFICATION (RULE 3.65), restated for the read path: no
// termination, no data. Protects the shared return path.
property p_data_qualified;
@(posedge clk_i) (!ack_o && !err_o) |-> (dat_o == '0);
endproperty
a_data_qualified : assert property (p_data_qualified)
else $error("RULE 3.65: read data driven without a termination");
endmoduleP3 is the chapter's contribution to the verification plan, and its most interesting property is that it does not apply to every slave. A combinational read slave is coherent by construction — there is nothing remembered, so nothing can be remembered wrongly.
Registering a response to fix timing therefore adds a property, not just a cycle. That belongs in the decision of Section 3: the trade is latency and a new obligation against frequency.
Tooling limitation. Icarus Verilog has no SVA support and cannot execute any of these. They are reviewed by inspection; all three slaves are elaborated and the simulations in Section 6 were run.
8. Common Mistakes
"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.
Observable evidence: ACK with a plausible wrong value, only when paired with a master that moves its address.
Correct model: a registered response must remember what it is answering, and that memory is new state that can be wrong. It buys timing closure and costs a cycle plus a correctness obligation.
"ACK just means the slave is done."
Wrong mental model: the termination and the data are separate statements.
Concrete bug: a slave whose acknowledge and read data are produced by different logic on different schedules.
Observable evidence: ACK coinciding with data that is a cycle stale, or with garbage.
Correct model: RULE 3.65 makes them one statement. The acknowledge asserts that this data is this request's answer.
"A slave can acknowledge as soon as it sees STB_I."
Wrong mental model: the strobe is the only qualifier that matters.
Concrete bug: an acknowledge without the per-slave select, or without CYC_I — a RULE 3.35 violation that works point-to-point and fails in a shared fabric.
Observable evidence: transfers completing that were addressed to a different peripheral; merged read data.
Correct model: RULE 3.35 requires the AND of CYC_I and STB_I, and the interconnect gates STB per slave so exactly one sees a qualified transfer.
9. Interview Reasoning
Because the response is produced in a different cycle from the request, and by then the bus may be showing something else.
A combinational slave has no such problem. Its acknowledge and its data are functions of the inputs present right now, so they necessarily describe the same request. There is no context to preserve because nothing is deferred.
A registered slave defers the answer by at least a cycle. At the moment it responds it must know which offset it was asked about — and there are two places it can get that from. The remembered copy, captured when the request arrived. Or the address currently on the bus.
Against a conformant master the two are identical, because RULE 3.60 requires ADR_O to be qualified by STB_O and therefore held still for the transfer's duration. So the bug is invisible in a well-behaved system, which is exactly what makes it dangerous — it passes every test until it meets a specific partner.
What happens when it does. Pair a lost-context slave with a master that moves its address mid-transfer — Chapter 6.2's walking master — and the slave acknowledges a request it correctly remembers while returning data from wherever the address drifted to. The master receives ACK, a success status, and the wrong register's contents. No error is raised anywhere. The measured run showed exactly this: remembered offset 4, mux input 5, wrong value, status OK.
Why I would still call the slave wrong rather than just the master. Driving the multiplexer from the remembered offset is coherent by construction — it does not depend on another component's conformance. A design that is correct only while its partner behaves is a latent integration failure, and in this case the fix is one port connection.
The broader point for a design review. Registering a response to close timing is a reasonable decision, and it is not free in two separate ways: a cycle of latency, and a new correctness obligation that has to be verified. Property P3 exists only for registered slaves — the combinational version cannot fail it, because it has nothing to compare.
10. Understanding Check
11. What's Next
The termination is now a read-side design decision rather than a given: coherent by construction or coherent by careful bookkeeping, immediate or registered, with the trade made against a timing report.
Both registered forms above insert exactly one cycle of delay. Real peripherals are not so uniform — a value may take several cycles to produce, and during that time the whole transfer sits waiting on the bus.
What happens when the slave cannot complete the read immediately, and what must stay coherent while it cannot?
Chapter 6.5 — Wait States answers it. The full path is on the Wishbone curriculum index.
Continue learning
Related tutorials
- Related topic
Timing Relationships
A combinational ACK gives one transfer per clock and creates a master-to-slave-and-back path in a single cycle; a registered ACK closes timing and costs a cycle. The specification describes both and prefers neither.
- Related topic
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.
- 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.
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.
