Wishbone · Module 5
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.
Every chapter so far has said which edge something happens on. None has said what happens between edges — and that is where a protocol-perfect design meets a synthesis tool.
How do all the handshake signals relate around clock edges, and what does that cost in silicon?
1. The Five Intervals
Every Wishbone transfer passes through the same five phases. Naming them gives the rest of the chapter something to hang on.
| Interval | Master obligation | Slave obligation |
|---|---|---|
| SETUP — before the first qualified edge | drive metadata, assert qualifiers | — |
| SAMPLE — the first qualified edge | — | observe CYC_I & STB_I |
| CONTINUATION — while unterminated | hold everything still (RULE 3.60) | work; withhold termination |
| TERMINATION — the answering edge | sample the termination; capture DAT_I | drive termination + DAT_O (RULE 3.65) |
| RELEASE — after termination | negate CYC_O, STB_O | negate termination (RULE 3.50) |
For a zero-wait-state transfer, CONTINUATION is empty — SAMPLE and TERMINATION are the same edge. That is the case OBSERVATION 3.40 describes, and it is where the timing pressure lives.
2. Simulation Time Versus Architectural Observation
This distinction is the one engineers most often blur, and it produces confident wrong statements in both directions.
In simulation time, signals transition whenever their drivers change. A combinational ACK_O goes high partway through a cycle, some delta after STB_O rose.
Architecturally, none of that is observed. Both sides sample at the rising edge of CLK_I, and the CLK_I signal description says inputs "are stable before the rising edge". What happens between edges is invisible to the protocol.
So "ACK_O asserts immediately" means two different things. Architecturally it means in the same cycle, sampled at the same edge that sampled the strobe. In circuit terms it means through a combinational path, which has a propagation delay that must fit inside the clock period.
3. The Loopback Path
Here is what a combinational termination actually builds, and the specification names it.
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."
All five stages sit between two flops in one clock period. The path is:
master flop → decode → slave logic → response merge → master flop setupChapter 3.6 §6 traced this same cone from the data-flow side and identified the response path as the structure that scales worst.
Two things make it grow.
Slave count. The decode fans out to every slave and the merge collects from every slave, so both ends widen as the system grows. Chapter 3.6 §6 identified the response path as the structure that scales badly.
Slave complexity. A slave whose termination depends on an internal comparison, a FIFO level or a permission check puts that logic inside the loop.
What OBSERVATION 3.40 buys in exchange: "The asynchronous assertion ... assures that the interface can accomplish one data transfer per clock cycle." Without it, the minimum transfer is two cycles.
And OBSERVATION 3.45 gives the escape: "...slave wait states are easiest implemented using a registered [ACK_O] signal."
4. The Four Canonical Timings
A — Basic completion, zero wait states
A: immediate termination
5 cyclesCONTINUATION is empty. The entire loopback of Figure 1 must resolve within cycle 2.
B — Delayed completion, registered ACK
B: registered termination with wait states
7 cyclesThe loopback is cut by the slave's output flop. The master-to-slave path ends at that flop; the slave-to-master path starts there. Neither is the full loop, so each has a full clock period.
The cost is one extra cycle minimum, even when the slave has nothing to wait for.
C and D — Holding and releasing
C, request held across several edges, is Figure 3's cycles 2–5: everything RULE 3.60 qualifies stays still, and the master learns nothing until the termination arrives.
D, release after completion, is the cycle after TERMINATION in both figures: the master negates its qualifiers, and the slave negates its termination in response per RULE 3.50 — OBSERVATION 3.10 calls that automatic.
5. The Timing Truth Table
One table covering the module, to be checked against every waveform in it.
Signal state in each interval:
| Interval | CYC | STB | ADR/WE/SEL | DAT_O (M) | ACK | DAT_I (M) |
|---|---|---|---|---|---|---|
| IDLE | 0 | 0 | meaningless | meaningless | 0 | meaningless |
| SETUP | 1 | 1 | valid | valid if write | 0 | — |
| SAMPLE | 1 | 1 | valid | valid if write | 0/1 | valid iff ACK |
| CONTINUATION | 1 | 1 | held | held | 0 | meaningless |
| TERMINATION | 1 | 1 | held | held | 1 | valid |
| RELEASE | 0 | 0 | meaningless | meaningless | 0→ | meaningless |
What each side does at that interval's edge:
| Interval | Master at the edge | Slave at the edge |
|---|---|---|
| IDLE | — | ignore everything (RULE 3.30) |
| SETUP | drive metadata and qualifiers | — |
| SAMPLE | check for a termination | observe the qualified request |
| CONTINUATION | wait; change nothing | work; withhold the termination |
| TERMINATION | capture DAT_I, record, release | drive termination + DAT_O |
| RELEASE | report completion once | negate the termination (RULE 3.50) |
Three rows deserve emphasis.
CONTINUATION's DAT_I is meaningless — RULE 3.65 ties the slave's read data to its termination, and there isn't one yet.
TERMINATION's DAT_I is valid for that cycle only, which is Chapter 5.6's whole subject.
IDLE's metadata is meaningless but not necessarily cleared. RULE 3.60 requires qualification, not clearing — Chapter 4.6 showed a master legally leaving stale write data on DAT_O during a read, and what that costs a careless slave.
6. RTL — The Same Slave, Both Ways
// ─────────────────────────────────────────────────────────────────────────
// wb_timing_slave — ONE slave, two termination styles, selected by a
// parameter. Functionally identical; timing profiles opposite.
//
// REGISTERED = 0 : combinational ACK_O. PERMISSION 3.30 explicitly
// allows the combinatorial STB_I -> ACK_O path, and
// OBSERVATION 3.40 notes it gives one transfer per
// clock. The whole Figure 1 loopback is in one period.
//
// REGISTERED = 1 : ACK_O comes from a flop. The loopback is cut, each
// half gets a full period, and every transfer costs one
// extra cycle. OBSERVATION 3.45 points at this form for
// wait states.
//
// NEITHER IS UNIVERSALLY CORRECT. The choice is a synthesis result, not a
// preference, and this module exists so both can be built and compared.
//
// Reset: SYNCHRONOUS, ACTIVE HIGH (RULES 2.30, 3.00).
// ─────────────────────────────────────────────────────────────────────────
module wb_timing_slave #(
parameter int unsigned OFF_AW = 4,
parameter int unsigned DW = 32,
parameter bit REGISTERED = 1'b0
) (
input logic clk_i,
input logic rst_i,
input logic cyc_i,
input logic stb_i,
input logic we_i,
input logic [OFF_AW-1:0] adr_i,
input logic [DW-1:0] dat_i,
input logic [DW/8-1:0] sel_i,
output logic [DW-1:0] dat_o,
output logic ack_o,
output logic [DW-1:0] reg0_o
);
localparam int unsigned NL = DW/8;
logic [DW-1:0] mem_q [16];
assign reg0_o = mem_q[0];
logic xfer;
assign xfer = cyc_i & stb_i; // RULES 3.30 & 3.35
// ── TERMINATION ───────────────────────────────────────────────────────
logic ack_comb, ack_q;
// Combinational form: PERMISSION 3.10's shape exactly — tied to the AND
// of STB_I and CYC_I. Note this slave has no ERR_O/RTY_O, which is one
// of that permission's two preconditions.
assign ack_comb = xfer;
// Registered form. The one-cycle delay is unavoidable: the flop cannot
// know about a transfer until the edge that samples it, so the earliest
// it can answer is the following cycle.
//
// ack_q is cleared when the transfer goes away, which is what keeps
// RULE 3.50 satisfied (terminations negate in response to STB_I) and
// stops a stale acknowledge outliving its transfer.
always_ff @(posedge clk_i) begin
if (rst_i) ack_q <= 1'b0;
else if (!xfer) ack_q <= 1'b0;
else ack_q <= ~ack_q; // one cycle on, then off
end
assign ack_o = REGISTERED ? ack_q : ack_comb;
// ── WRITE ACCEPTANCE ──────────────────────────────────────────────────
// Gated on ack_o in BOTH configurations. With REGISTERED = 1 the
// transfer is presented for two cycles, so Chapter 5.3's distinction
// between presented and accepted becomes load-bearing here — a write
// gated on xfer alone would execute twice.
logic write_ok;
assign write_ok = xfer & we_i & ack_o;
always_ff @(posedge clk_i) begin
if (rst_i) begin
for (int unsigned i = 0; i < 16; i++) mem_q[i] <= '0;
end else if (write_ok) begin
for (int unsigned n = 0; n < NL; n++) begin
if (sel_i[n]) mem_q[adr_i][n*8 +: 8] <= dat_i[n*8 +: 8];
end
end
end
// ── READ PATH ─────────────────────────────────────────────────────────
// RULE 3.65: qualified by the termination, whichever style produced it.
// In the REGISTERED case dat_o is still combinational from mem_q — only
// the ACKNOWLEDGE was registered. Registering the data too would be a
// further choice, and would move the read multiplexer out of the
// loopback as well.
always_comb begin
dat_o = '0;
if (xfer && !we_i && ack_o) dat_o = mem_q[adr_i];
end
endmoduleReading it
Purpose. Make the two timing styles a parameter so the same functional slave can be synthesised both ways and compared on a real report.
Interface. Identical in both configurations — a master cannot tell which it is talking to, which is why RULE 3.55 requires it to cope with either.
State. The register file, plus ack_q in the registered configuration.
Combinational behaviour. xfer, ack_comb, the output mux, write_ok, the read multiplexer. In the combinational configuration all of this is inside the Figure 1 loopback.
Sequential behaviour. The register file; ack_q when registered.
Timing. REGISTERED = 0 terminates in the presented cycle. REGISTERED = 1 terminates in the next, so every transfer takes two cycles.
Qualification. Every output contains xfer; the read path also contains ack_o, per RULE 3.65.
Reset. Synchronous, active high.
Failure modes. A registered acknowledge with no clearing path — ack_q here is cleared whenever xfer drops, which prevents a stale termination outliving its transfer.
Simplifications. The registered form toggles rather than counting, giving exactly one wait state. Module 9 owns wait states properly; this is the minimum needed to break the loopback.
7. Simulation — Both Configurations, Measured
wb_timing_slave was driven by Chapter 5.6's wb_completion_master through one write followed by one read, in each configuration:
combinational registered
busy cycles (1 wr + 1 rd) 2 4
cycles transfer presented 2 4
reg0 after the single write 0xc0ffee 0xc0ffee
read-back value 0xc0ffee 0xc0ffeeThe function is identical. Same value stored, same value read back. A master cannot distinguish the two by result — only by latency.
The registered form costs exactly one extra cycle per transfer: two transfers, two extra cycles. That is the price of cutting the loopback, paid unconditionally whether or not the slave had anything to wait for.
The row that matters most is reg0. In the registered configuration the transfer is presented for two cycles, so xfer is true twice — and the write still landed once, because write_ok contains ack_o. Remove that term and this configuration writes twice while the combinational one still writes once, which is the regression Section 12 describes: a purely timing change silently breaking a functional path nobody edited.
8. Choosing Between Them
There is no universally correct answer, and a candidate who asserts one is missing the point the specification is making with three consecutive observations.
Combinational is right when the system is small, the slave count is low, the target frequency is modest, and access latency matters — a tightly-coupled peripheral on a microcontroller-class SoC. You get OBSERVATION 3.40's one transfer per clock for free.
Registered is right when the slave count is high, the frequency target is aggressive, the slave's own decision logic is deep, or the fabric is hierarchical. You pay a cycle and get the frequency.
The decision procedure, which matters more than the answer:
Build it combinational first. It is simpler, faster per transfer, and often closes without difficulty.
Synthesise and read the critical path. If the loopback of Figure 1 is not the critical path, the question is settled — do not pay a cycle for a problem you do not have.
If it is critical, register the response and re-measure. The gain should be real and attributable.
Consider hierarchy before registering everything. A registered bridge between two segments cuts the loop once rather than adding a cycle to every slave.
What not to do is register reflexively. That is a cycle of latency on every access in the system, paid unconditionally, to fix a path that may not have been critical.
9. Failure Modes and Discriminating Evidence
Symptom: the design is functionally correct in simulation and fails timing in synthesis, on a path through the bus.
Candidate causes. The combinational loopback of Figure 1 is the critical path.
Discriminating evidence. Read the timing report's path, not just the slack number. A path that starts at a master's CYC_O/STB_O flop and ends at that same master's ACK_I/DAT_I setup, passing through decode, a slave and the response merge, is the loopback — and OBSERVATION 3.50 names exactly this.
Likely RTL location. Not a bug. The fix is architectural: register the termination, or go hierarchical.
Symptom: every access takes one more cycle than expected, system-wide.
Candidate causes. Terminations registered everywhere by default, without a timing justification.
Discriminating evidence. Compare measured access latency against the slave's own minimum. A uniform extra cycle across every peripheral, including trivial ones, indicates a policy rather than a requirement.
Likely RTL location. A house slave template. Check whether the combinational form was ever synthesised — often it was not.
Symptom: a registered acknowledge stays asserted after the strobe drops.
Candidate causes. ack_q has no clearing path when xfer goes away.
Discriminating evidence. ACK_O high with STB_I low — 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 appears somewhere else entirely.
Likely RTL location. The acknowledge register's reset/clear conditions.
Symptom: a slave works combinationally and double-writes when registered.
Candidate causes. The write is gated on xfer rather than on ack_o. Registering the acknowledge makes the transfer two cycles long, so Chapter 5.3's presented-versus-accepted distinction becomes live.
Discriminating evidence. The side-effect count equals the number of presented cycles. The bug appeared because latency was introduced, not because the write path changed.
Likely RTL location. The write enable.
10. Common Mistakes
"Combinational ACK means asynchronous handshaking."
Wrong mental model: a combinational path breaks the synchronous clocking model.
Concrete bug: none directly — but it leads to registering every termination unconditionally.
Observable evidence: uniformly doubled access latency with no timing justification.
Correct model: PERMISSION 3.30's parenthetical says "combinatorial logic path", and everything is still sampled at rising edges. A timing path changed; the clocking model did not.
"Registering the response is always safer."
Wrong mental model: more flops, fewer problems.
Concrete bug: a cycle added to every access in the system, and — if the slave's write path was gated on xfer — a doubled side effect that did not exist before.
Observable evidence: latency regression across all peripherals; new corruption in slaves nobody edited.
Correct model: registering is a tradeoff the specification describes in OBSERVATIONS 3.40 and 3.45. Pay the cycle where the timing report says you must.
"Protocol-correct means it will work."
Wrong mental model: conformance implies a working chip.
Concrete bug: a correct combinational design that cannot reach its target frequency.
Observable evidence: clean simulation, failing static timing analysis.
Correct model: they are separate questions. OBSERVATION 3.50 exists because the specification's authors knew a legal design could be unbuildable at speed — and a review that checks only conformance will pass it.
11. Interview Reasoning
Yes, explicitly. PERMISSION 3.30 allows the assertion of ACK_O, ERR_O and RTY_O to be asynchronous to CLK_I, and its parenthetical names the structure: a combinatorial logic path between STB_I and ACK_O.
What it buys is in OBSERVATION 3.40: one data transfer per clock cycle. Without it the minimum transfer is two cycles, because a flop cannot know about a request until the edge that samples it.
What it costs is in OBSERVATION 3.50: the loopback delay "from the MASTER to the SLAVE and back to the MASTER". The path runs master output flop → address decode → slave logic → response merge → master input flop setup, and all of it must fit in one clock period.
Why that path grows. The decode fans out to every slave and the merge collects from every slave, so both ends widen with slave count. Slave complexity adds to the middle. In a large, fast SoC it becomes the critical path.
The clarification I would insist on, because it is where most people go wrong: "asynchronous" here means not registered, not outside the clocking model. Both sides still sample only at rising edges. RULE 5.00 still holds, the interface still closes on a single Tpd,clk-su. What changed is a timing path, not the protocol's clocking.
How I would decide in practice. Build it combinational, synthesise, and read the critical path. If the loopback is not critical, keep it — do not spend a cycle on every access to solve a problem the tool says you do not have. If it is critical, register the termination, or cut the loop once with a hierarchical bridge rather than adding a cycle to every slave.
The trap to flag when registering. It makes the transfer two cycles long, so a slave whose write was gated on CYC_I & STB_I rather than on its own acknowledge starts writing twice. The bug appears because latency was added, not because the write path was touched — which is exactly the kind of change nobody re-reviews the slave for.
12. Understanding Check
13. What's Next
The timing model is now complete: five intervals, two legal termination styles, one loopback path, and a clear separation between protocol correctness and timing closure.
What remains is to gather the rules themselves — scattered across seven chapters and two modules — into something a designer can check a implementation against, with the specification requirements separated from the design decisions that merely look like them.
Which handshake obligations are Wishbone rules, which are good local policy, and how do you tell them apart?
Chapter 5.8 — Handshake Rules 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
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
CPU to Peripheral Communication
A CPU reaches hardware outside itself by reading and writing addressed locations, and a peripheral is hardware it cannot execute. Everything a driver does has to be expressed as a read or a write of a location the peripheral answers for — and once more than a couple of peripherals exist, wiring each one to the core separately stops scaling. That is the problem an on-chip bus is the answer to.
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.
