Wishbone · Module 16
Why Multiple Masters Exist
The same four-word copy performed twice — by the CPU and by a second initiator — with the bus traffic counted both times, and the specification's own definition of a master.
Chapter 15.4 used two masters as laboratory equipment. They were there to compete, and nothing more was said about why a real system would have them.
Why not simply let the CPU perform every bus operation?
1. The Copy, and Who Performs It
Take the smallest useful piece of real work: move four words from one place to another.
In a single-master system the sequence is fixed. The CPU reads a word, the CPU writes it, the CPU reads the next, the CPU writes that. Eight bus transfers, and eight decisions the processor had to make and wait for.
Nothing here is wrong. The transfers are ordinary single reads and single writes, each with its own CYC_O, STB_O and ACK_I, exactly as Chapter 5.8 specified. A four-word copy is not a protocol problem.
It is an architectural one. The processor is the only thing in the system that can initiate a transfer, so every byte that moves anywhere moves because the processor personally asked for it. While it is doing that, it is not doing anything else.
The fix is not a faster CPU or a wider bus. It is a second device that can ask.
2. RTL — A CPU-Like Master and Its Client Contract
The master below is used unchanged in all four chapters of this module. Its interesting feature is not the Wishbone port — that is Chapter 3.3's material — but the client interface above it.
// ─────────────────────────────────────────────────────────────────────────
// wb_cpu_master — a CPU-like Wishbone MASTER driven by a local client.
//
// The client contract is deliberately NOT Wishbone. A client presents one
// request on req_i and the master answers with a one-clock done_o. That
// separation is the whole point of the module: there is a request layer
// above the bus, and it has its own state.
//
// req_i ........ one-clock request pulse (ignored while busy_o)
// busy_o ....... the master holds accepted work
// done_o ....... one-clock completion pulse; ok/err/rty say which
// hold_i ....... keep CYC_O asserted between requests
//
// hold_i is PERMISSION 3.05 made controllable: "MASTER interfaces MAY
// assert [CYC_O] indefinitely." RECOMMENDATION 3.05 advises against it -
// "Keeping [CYC_O] asserted may lead to arbitration problems" - and
// Chapter 16.4 measures exactly that problem. Neither is a RULE.
//
// LOCK_O is passed straight through from the client (req_lock_i). Its
// meaning was established in Module 15 and is not re-derived here.
// ─────────────────────────────────────────────────────────────────────────
module wb_cpu_master #(
parameter int unsigned AW = 12,
parameter int unsigned DW = 32,
parameter int unsigned SW = DW/8
) (
input logic clk_i,
input logic rst_i,
// client side - LOCAL, not Wishbone
input logic req_i,
input logic req_we_i,
input logic [AW-1:0] req_adr_i,
input logic [DW-1:0] req_dat_i,
input logic [SW-1:0] req_sel_i,
input logic req_lock_i,
input logic hold_i,
output logic busy_o,
output logic done_o,
output logic ok_o,
output logic err_o,
output logic rty_o,
output logic [DW-1:0] rdat_o,
// Wishbone MASTER port
output logic cyc_o,
output logic stb_o,
output logic lock_o,
output logic we_o,
output logic [AW-1:0] adr_o,
output logic [DW-1:0] dat_o,
output logic [SW-1:0] sel_o,
input logic [DW-1:0] dat_i,
input logic ack_i,
input logic err_i,
input logic rty_i
);
typedef enum logic [1:0] { S_IDLE, S_XFER, S_WRAP } state_e;
state_e st_q;
logic we_q, lk_q;
logic [AW-1:0] adr_q;
logic [DW-1:0] dat_q;
logic [SW-1:0] sel_q;
logic term;
assign term = ack_i || err_i || rty_i;
always_ff @(posedge clk_i) begin
if (rst_i) begin
st_q <= S_IDLE;
we_q <= 1'b0; lk_q <= 1'b0;
adr_q <= '0; dat_q <= '0; sel_q <= '0;
rdat_o <= '0;
ok_o <= 1'b0; err_o <= 1'b0; rty_o <= 1'b0;
end else begin
case (st_q)
S_IDLE: if (req_i) begin
we_q <= req_we_i; adr_q <= req_adr_i;
dat_q <= req_dat_i; sel_q <= req_sel_i; lk_q <= req_lock_i;
ok_o <= 1'b0; err_o <= 1'b0; rty_o <= 1'b0;
st_q <= S_XFER;
end
// The master presents its transfer and waits. It is NOT told
// whether it owns the shared path: from here the only observable
// difference between "waiting for ownership" and "waiting for a
// slow slave" is that no termination arrives. That symmetry is
// why Chapter 16.3 instruments the interconnect instead.
S_XFER: if (term) begin
ok_o <= ack_i;
err_o <= err_i;
rty_o <= rty_i;
rdat_o <= dat_i;
st_q <= S_WRAP;
end
S_WRAP: st_q <= S_IDLE;
default: st_q <= S_IDLE;
endcase
end
end
assign busy_o = (st_q != S_IDLE);
assign done_o = (st_q == S_WRAP);
// CYC_O spans the transfer (RULE 3.25). hold_i extends it beyond the
// transfer, which PERMISSION 3.05 allows and RECOMMENDATION 3.05
// advises against.
assign cyc_o = (st_q == S_XFER) || hold_i;
assign stb_o = (st_q == S_XFER);
assign lock_o = (st_q == S_XFER) && lk_q;
assign we_o = we_q;
assign adr_o = adr_q;
assign dat_o = dat_q;
assign sel_o = sel_q;
endmoduleReading it
req_i, busy_o and done_o are not Wishbone signals and are not meant to be. They are how something inside the CPU asks this port to perform a transfer. The specification says nothing about them because they are entirely local, and that is the point: there is a request layer above the bus, and it has its own state.
Watch the two layers come apart. A client pulses req_i; the master latches the request and enters S_XFER; CYC_O rises the clock after that. For one clock the master holds accepted work and is presenting nothing on the bus at all. Chapter 16.2 counts those clocks, because they are the difference between having work and asking for the bus.
hold_i is the one control that needs justifying. It keeps CYC_O asserted between requests, which PERMISSION 3.05 explicitly allows — "MASTER interfaces MAY assert [CYC_O] indefinitely." RECOMMENDATION 3.05 advises against it. Chapter 16.4 measures what happens when a master takes the permission, and neither the permission nor the recommendation is a rule.
lock_o is passed straight through from the client. Its meaning was established and measured in Module 15 and is not re-derived here.
One line in S_XFER is worth pausing on. The master waits for a termination and has no other input. It cannot tell the difference between "I do not own the shared bus yet" and "the slave is slow." In both cases nothing comes back. That symmetry is why Chapter 16.3 instruments the interconnect rather than the master.
3. Simulation — SIM A: The CPU Performs Every Transfer
Four words moved by one master, with nothing else on the bus.
=== SIM A - the CPU performs every transfer ===
copy 4 words: 0x010..0x013 -> 0x020..0x023
step client request bus transfer value
0 read src+0 ACK adr 0x010 0xaaaa0010
1 write dst+0 ACK adr 0x020 0xaaaa0010
2 read src+1 ACK adr 0x011 0xaaaa0011
3 write dst+1 ACK adr 0x021 0xaaaa0011
4 read src+2 ACK adr 0x012 0xaaaa0012
5 write dst+2 ACK adr 0x022 0xaaaa0012
6 read src+3 ACK adr 0x013 0xaaaa0013
7 write dst+3 ACK adr 0x023 0xaaaa0013
CPU client requests issued 8
Wishbone transfers on bus 8
DMA transfers on bus 0
shared RAM writes 4
destination after the copy
0x020 = 0xaaaa0010
0x021 = 0xaaaa0011
0x022 = 0xaaaa0012
0x023 = 0xaaaa0013Reading it
Eight client requests, eight bus transfers, four words changed. The arithmetic is exactly what the single-master model predicts: one read and one write per word, and no transfer that the CPU did not personally issue.
The value column is the whole story of a copy performed by a third party. Each read produces a word; the next write carries it. The CPU is holding the data between the two, which means it is also holding the state of the copy — which word is next, how many remain.
shared RAM writes 4 comes from the memory's own counter, not the bus. It agrees with the four write transfers, which is the uninteresting case and worth noting for that reason: when nothing is competing, the resource's view and the bus's view are the same. Chapter 16.3 shows them disagreeing.
Do not read this as a benchmark. No claim is made here about speed. Eight transfers is eight transfers however they are issued, and Module 22 owns performance. The finding is about responsibility, not throughput — this processor cannot stop supervising the copy until the copy is finished.
4. RTL — A Device With Two Wishbone Interfaces
This is the module that makes the architectural point, and its port list makes it before any logic runs.
// ─────────────────────────────────────────────────────────────────────────
// wb_teaching_dma — the smallest thing that is honestly a second MASTER.
//
// THIS IS NOT A DMA CONTROLLER DESIGN. Descriptors, scatter-gather, burst
// sizing, alignment handling, interrupt generation, channel priority and
// error recovery are Module 25's subject and none of them is here. What is
// here is the one architectural fact Module 16 needs:
//
// THE SAME DEVICE HAS A SLAVE INTERFACE AND A MASTER INTERFACE.
//
// The configuration registers are a SLAVE: the CPU writes them over the
// bus, exactly as it writes any peripheral. The transfer engine is a
// MASTER: it generates its own bus cycles. The specification's glossary
// draws the line by capability, not by role in the conversation -
// MASTER: "A WISHBONE interface that is capable of generating bus cycles."
// SLAVE: "A WISHBONE interface that is capable of receiving bus cycles."
// so a device with both is two interfaces, not a contradiction.
//
// And the reason it exists at all, in the specification's own glossary
// entry for DMA Unit: "A device for transferring data between a device and
// memory without interrupting program flow."
//
// CONFIG REGISTERS (slave port, word-addressed, 2 bits):
// 0 SRC source word address
// 1 DST destination word address
// 2 LEN number of words (0 is legal and transfers nothing)
// 3 CTRL write bit0 = start; read returns {fail, busy, words_done}
//
// TRANSFER ENGINE (master port): for i in 0..LEN-1, read SRC+i then write
// DST+i. CYC_O is negated between the read and the write and between
// words, so the engine's tenure on a shared bus is one transfer long.
// ─────────────────────────────────────────────────────────────────────────
module wb_teaching_dma #(
parameter int unsigned AW = 12,
parameter int unsigned DW = 32,
parameter int unsigned SW = DW/8
) (
input logic clk_i,
input logic rst_i,
// -- configuration SLAVE port --
input logic c_cyc_i,
input logic c_stb_i,
input logic c_we_i,
input logic [1:0] c_adr_i,
input logic [DW-1:0] c_dat_i,
output logic [DW-1:0] c_dat_o,
output logic c_ack_o,
output logic c_err_o,
// -- transfer-engine MASTER port --
output logic cyc_o,
output logic stb_o,
output logic lock_o,
output logic we_o,
output logic [AW-1:0] adr_o,
output logic [DW-1:0] dat_o,
output logic [SW-1:0] sel_o,
input logic [DW-1:0] dat_i,
input logic ack_i,
input logic err_i,
input logic rty_i,
// -- observation --
output logic busy_o,
output logic done_o, // one-clock pulse at end of transfer
output logic failed_o, // sticky: a phase terminated ERR/RTY
output logic [15:0] words_done_o
);
typedef enum logic [2:0] {
D_IDLE, D_READ, D_GAP, D_WRITE, D_STEP, D_END
} dstate_e;
dstate_e st_q;
logic [AW-1:0] src_q, dst_q;
logic [15:0] len_q, idx_q;
logic [DW-1:0] hold_q; // the word read, waiting to be written
logic fail_q;
logic term;
assign term = ack_i || err_i || rty_i;
assign busy_o = (st_q != D_IDLE);
assign done_o = (st_q == D_END);
assign failed_o = fail_q;
assign words_done_o = idx_q;
// -- configuration slave --
// A plain single-clock slave. It refuses configuration writes while the
// engine is running, which is LOCAL POLICY: the specification does not
// require it. ERR_O is the honest answer because the request is wrong
// for the current state rather than deferred - Chapter 11.2 draws that
// line and it holds here.
logic c_xfer, c_refuse;
assign c_xfer = c_cyc_i && c_stb_i;
assign c_refuse = c_xfer && c_we_i && busy_o;
assign c_ack_o = c_xfer && !c_refuse;
assign c_err_o = c_refuse;
logic start_pulse;
assign start_pulse = c_ack_o && c_we_i && (c_adr_i == 2'd3) && c_dat_i[0];
always_comb begin
case (c_adr_i)
2'd0: c_dat_o = {{(DW-AW){1'b0}}, src_q};
2'd1: c_dat_o = {{(DW-AW){1'b0}}, dst_q};
2'd2: c_dat_o = {{(DW-16){1'b0}}, len_q};
default: c_dat_o = {14'd0, fail_q, busy_o, words_done_o};
endcase
end
always_ff @(posedge clk_i) begin
if (rst_i) begin
st_q <= D_IDLE;
src_q <= '0; dst_q <= '0; len_q <= '0; idx_q <= '0;
hold_q <= '0; fail_q <= 1'b0;
end else begin
if (c_ack_o && c_we_i) begin
case (c_adr_i)
2'd0: src_q <= c_dat_i[AW-1:0];
2'd1: dst_q <= c_dat_i[AW-1:0];
2'd2: len_q <= c_dat_i[15:0];
default: ; // CTRL stores nothing
endcase
end
case (st_q)
// LEN = 0 is decided here, before any address arithmetic, so no
// counter is ever decremented below zero and no phase is issued.
D_IDLE: if (start_pulse) begin
idx_q <= 16'd0;
fail_q <= 1'b0;
// Icarus rejects an enum-valued ternary without a cast, so the
// branch is written out. Same meaning, no cast needed.
if (len_q == 16'd0) st_q <= D_END;
else st_q <= D_READ;
end
D_READ: if (term) begin
hold_q <= dat_i;
if (ack_i) st_q <= D_GAP;
else begin fail_q <= 1'b1; st_q <= D_END; end
end
// One clock with CYC_O negated. The engine holds accepted work and
// presents no bus request at all - the clock Chapter 16.2 counts to
// separate a pending request from an asserted CYC_O.
D_GAP: st_q <= D_WRITE;
D_WRITE: if (term) begin
if (ack_i) st_q <= D_STEP;
else begin fail_q <= 1'b1; st_q <= D_END; end
end
D_STEP: begin
idx_q <= idx_q + 16'd1;
if ((idx_q + 16'd1) == len_q) st_q <= D_END;
else st_q <= D_READ;
end
D_END: st_q <= D_IDLE;
default: st_q <= D_IDLE;
endcase
end
end
logic reading, writing;
assign reading = (st_q == D_READ);
assign writing = (st_q == D_WRITE);
assign cyc_o = reading || writing;
assign stb_o = reading || writing;
assign lock_o = 1'b0; // this engine claims no atomicity
assign we_o = writing;
assign adr_o = writing ? (dst_q + idx_q[AW-1:0]) : (src_q + idx_q[AW-1:0]);
assign dat_o = hold_q;
assign sel_o = {SW{1'b1}};
endmoduleReading it
Count the Wishbone ports: there are two, and they face opposite directions.
The configuration port is a slave. c_cyc_i, c_stb_i, c_adr_i — inputs, because this port receives bus cycles. The CPU writes SRC, DST, LEN and CTRL exactly as it writes any peripheral register, through the same interconnect, with the same handshake. From the CPU's point of view the DMA engine is a peripheral.
The transfer-engine port is a master. cyc_o, stb_o, adr_o — outputs, because this port generates bus cycles. From the interconnect's point of view the DMA engine is a second CPU. Both statements are true simultaneously and neither is a contradiction, because the glossary defines the roles per interface rather than per device.
The engine is deliberately small. No descriptors, no scatter-gather, no burst sizing, no alignment handling, no interrupt, no channel priority. Those are Module 25's subject. What is here is the minimum that honestly generates bus cycles: read SRC+i, write DST+i, repeat.
Three details in the state machine matter later.
D_GAP is one clock with CYC_O negated, between the read and the write. The engine is holding a word it has read and has not yet written, and it is presenting nothing. It has work and no bus request — the clock Chapter 16.2 counts.
LEN = 0 is decided in D_IDLE, before any address arithmetic. No counter is decremented below zero and no phase is issued; the engine goes straight to D_END. Transfer-count zero is a real case and getting it wrong is the classic unsigned-underflow bug in a length counter.
The configuration slave refuses writes while the engine is running, with ERR_O. That is LOCAL POLICY — no rule requires it. ERR rather than RTY is the honest choice by Chapter 11.2's test: the request is wrong for the device's state, not deferred until later, and retrying it will get the same answer until software stops the engine.
5. Simulation — SIM B: The Same Copy, A Different Initiator
Same four words, same destination, same memory. The CPU writes four registers and then stops touching the bus.
=== SIM B - a second master performs the same copy ===
the CPU writes four configuration registers and starts it
configuration SRC 0x010 DST 0x020 LEN 4
start written; CPU issues no further bus requests
DMA bus activity
# dir address data
0 read 0x010 0xaaaa0010
1 write 0x020 0xaaaa0010
2 read 0x011 0xaaaa0011
3 write 0x021 0xaaaa0011
4 read 0x012 0xaaaa0012
5 write 0x022 0xaaaa0012
6 read 0x013 0xaaaa0013
7 write 0x023 0xaaaa0013
CPU client requests issued 4 (configuration only)
DMA transfers on bus 8
CPU-side clocks without a bus request 27
DMA words completed 4
DMA failed 0
destination after the copy
0x020 = 0xaaaa0010
0x021 = 0xaaaa0011
0x022 = 0xaaaa0012
0x023 = 0xaaaa0013Reading it
Four client requests, and the copy still happened. The CPU wrote SRC, DST, LEN and CTRL and issued nothing else. The eight transfers that moved the data were issued by a different device.
Read the address column of the DMA log against SIM A's. They are the same eight addresses in the same order carrying the same eight words. The bus cannot tell the two runs apart — and that is exactly right, because the protocol has no concept of who is talking. A slave sees CYC_I, STB_I, ADR_I and answers. Nothing in a Wishbone transfer identifies its originator.
CPU-side clocks without a bus request: 27 is the measurement that needs the most care. It is a count of clocks on which the CPU's Wishbone port was idle while the DMA was transferring — nothing more. This testbench has no processor and executes no instructions. It is not a claim that 27 instructions retired, and the teaching RTL cannot support such a claim. What it does show is that the CPU's bus interface was free, which is the architectural precondition for the processor doing something else.
DMA words completed 4, DMA failed 0 come from the engine's own status register — the same register the CPU would poll. The engine reports its own progress, which it must, because nothing on the bus reports it.
6. What Changed, and What Did Not
The work did not change. The transfer count did not change. The data did not change.
What changed is which device holds the state of the operation. In SIM A the CPU knows which word is next and is blocked on finding out; in SIM B the DMA knows, and the CPU knows only that a transfer is in progress.
The diagram makes the asymmetry visible. On the top path there is one arrow and it carries everything. On the bottom path there are two arrows, and they are different kinds of arrow: one is configuration, one is data movement, and only the second is on the critical path of the copy.
It also makes the cost visible. The bottom path has a second device that can start a transfer at a moment the CPU did not choose. Everything in the remaining three chapters follows from that sentence.
7. Where Second Masters Come From
The DMA engine is the clearest example, not the only one. Anything that independently initiates transfers is a master:
| device | why it initiates | what it usually also has |
|---|---|---|
| DMA engine | moves payload without the CPU supervising each word | a slave port for its registers |
| debug / trace unit | reads memory and registers while software runs | a host-side link, not a bus port |
| accelerator | fetches operands and stores results itself | a slave port for its command queue |
| display or video engine | reads a framebuffer on a timing deadline | a slave port for its mode registers |
| network engine | moves packet buffers as frames arrive | descriptor rings in shared memory |
| a second processor | runs its own program | whatever that program touches |
The pattern in the right-hand column is worth more than the list. Almost every one of these devices has both interfaces, for the same reason the DMA does: software has to configure it, and then it has to work without software.
What none of them is, is "a smarter slave". A slave that could start transfers would not be a slave; it would be a device with two interfaces, which is what these are.
8. What the Specification Says About Multiple Masters
Less than you might expect, and it says it deliberately.
Multi-master is a listed feature, not an accident:
Multiprocessing (multi-MASTER) capabilities. This allows for a wide variety of System-on-Chip configurations.
And it is a stated design objective:
to create an architecture with a MASTER/SLAVE topology. Furthermore, the system must be capable of supporting multiple MASTERs and multiple SLAVEs with an efficient arbitration mechanism.
Read that "must" carefully. It appears in the Objectives section — it is a requirement the authors placed on the specification they were writing, not a conformance requirement on your design. No numbered RULE anywhere in B3 requires a system to support more than one master, and a point-to-point system with exactly one is entirely conformant.
The arbitration question is handed to you, in one sentence, in the feature list:
Arbitration methodology is defined by the end user (priority arbiter, round-robin arbiter, etc.).
That sentence governs the rest of this module. Every ownership policy shown from here on is a choice, clearly labelled as one. Module 17 is where the choosing is studied.
And the topology question is handed to you too:
Supports various IP core interconnection means, including: Point-to-point / Shared bus / Crossbar switch / Data flow interconnection / Off chip
Five named options. Module 16 uses a shared bus because it is the smallest thing that creates the problem. It is one of five, and "multi-master" does not imply any of the other four.
9. Common Mistakes
"The DMA is a slave, because the CPU configures it."
What is true: its configuration registers are a slave interface, and the CPU does write them.
Why it is wrong: the device also has a master interface, and the glossary defines the roles per interface — "capable of generating bus cycles" versus "capable of receiving bus cycles". Configuration is a conversation on one port; data movement is a conversation on the other. In this chapter's RTL you can count the ports.
"A DMA engine makes the system faster."
What is true: it often does, and that is usually why it is there.
Why it is a bad thing to say here: SIM A and SIM B issued the same eight transfers. Nothing about the bus got faster. What changed is which device was occupied — and whether that helps depends on what else the processor had to do, what the memory latency is, and what else is contending. Module 22 is where that gets measured, and a claim about throughput needs numbers this chapter did not take.
"Adding a master means adding a bus."
Why it is wrong: SIM B added a master and the shared path is unchanged. The five interconnection means in the specification are alternatives, and a shared bus with two masters is the first and simplest of them.
"The slave knows which master is talking to it."
Why it is wrong: there is no originator field in a Wishbone transfer. The memory in SIM A and SIM B saw identical traffic. LOCK_I tells a slave it is "accessed by a single MASTER only" — it does not say which one. If you need a slave to know, you build that yourself, with an address window per master or a user-defined tag.
"Two masters means two transfers can be in flight."
Why it is wrong: two masters can have two pending local requests. The shared path carries one transfer. Chapter 16.2 keeps those two things in separate columns, and Chapter 16.3 explains why collapsing them is the most expensive mistake in this module.
10. Interview Reasoning
"Why does a DMA engine need a master interface?"
Because it initiates transfers. A slave interface can only answer. The moment a device has to decide, on its own, to read from address X, it needs a port that can assert CYC_O and STB_O — and by the specification's definition, that port is a master interface.
"Can one device have both a Wishbone master and a Wishbone slave interface?"
Yes, and it is the normal case for any offload engine. The registers are a slave; the engine is a master. They are two independent Wishbone interfaces on one piece of silicon, and they may sit on different parts of the interconnect.
"Does Wishbone define how masters are arbitrated?"
No. "Arbitration methodology is defined by the end user." The only numbered identifiers in B3 that mention arbitration are advisory — RECOMMENDATION 3.05 and OBSERVATION 3.40 — and neither tells an arbiter what to choose.
"You are told a copy is corrupted only when network traffic is present. Where do you look first?"
At whether the network engine is a master. If it is, there are two initiators and the corruption is very likely in how the shared path is routed between them rather than in either device. Chapter 16.3 measures three ways that goes wrong, all of which are invisible with one master and all of which are protocol-conformant.
11. Understanding Check
A system has one CPU, one DMA engine, one RAM and one UART. How many Wishbone master interfaces are in it?
Two — the CPU's and the DMA's transfer engine. The DMA's configuration port, the RAM and the UART are slaves. Count ports that can assert CYC_O, not devices.
In SIM B, the memory answered eight transfers. How many of them came from the CPU?
None. The CPU issued four transfers, all of them to the DMA's configuration registers, which are a different slave. The eight transfers the memory answered were the DMA's.
Your DMA's LEN register is written with 0 and the engine is started. What should happen?
Nothing should be transferred and the engine should report itself done. The RTL in Section 4 decides this in D_IDLE before any address arithmetic, precisely so that no counter is decremented from zero and no phase is issued. A length counter that is tested after the first transfer will move one word too many.
Someone proposes removing the DMA's configuration slave port and setting SRC, DST and LEN with parameters instead. What breaks?
Nothing in this chapter's simulations — they would still run. What breaks is the ability to reconfigure it at run time, which is the only reason the device is programmable. It is a legitimate design for a fixed-function engine, and it would stop being a device with two interfaces.
12. What's Next
Two devices can now both initiate transfers. In SIM B only one of them was doing it at a time, and that was arranged.
What happens on the clock they both want the bus?
Chapter 16.2 — CPU + DMA Systems puts them in contention on purpose, and separates the four things that were comfortably identical while only one master was running: a local request, ownership of the shared path, a Wishbone transfer, and an effect on a resource.
Continue learning
Related tutorials
- Related topic
CPU + DMA Systems
Two initiators in contention, with the clocks counted in four columns: holding work, asking for the bus, owning it, and being answered. Contention cost two clocks out of twenty-one.
- 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.
- Related topic
Memory-Mapped IO
Memory-mapped I/O does not turn a peripheral into memory. It gives the peripheral's registers addresses in the processor's address space, so an ordinary load or store selects them. The address then does two jobs — name the target, name the register inside it — and the map that assigns them is a contract between software and RTL.
- Related topic
OpenCores Origins
Wishbone was written by Wade Peterson at Silicore Corporation and placed in the public domain; OpenCores published revision B3 in 2002 and took over its stewardship the same year. The engineering question behind that history is why a community of independent IP authors needed an interconnection convention at all — and what the public-domain decision was protecting against.
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.
