Wishbone · Module 19
RISC-V SoCs
Wishbone B3 contains the word CPU zero times and no interrupt signal at all — so this chapter builds the two seams that a conformant bus and a conformant processor still do not give you, and measures one whole system running across both.
Eighteen chapters of this module have built a bus. This one attaches a processor to it, and the first thing to establish is that the specification you have been reading does not describe how.
RISC-V specifies instructions. Wishbone specifies a bus. Neither specifies the wire between them — and that wire is where the work is.
1. Four Things People Call "The Bus" That Are Not The Bus
When an engineer says "the RISC-V core is on the Wishbone bus," four separate things are being asserted, and only one of them is in B3.
| what was said | what it actually is | specified by |
|---|---|---|
| the core fetches instructions over Wishbone | a request interface on the core, converted | nobody |
| the core takes a trap when a load fails | an exception model in the ISA, triggered by a bus signal | RISC-V, but the trigger is undictated |
| the timer interrupts the core | a wire that is not part of Wishbone at all | nobody |
| the core writes a peripheral register | this one — a Wishbone WRITE cycle | B3 |
Three of the four are yours. The fourth is the only one where quoting a rule number settles an argument.
2. The Two Seams
Every system in this chapter has exactly two boundaries that matter, and confusing them is the single most productive source of integration bugs in this whole curriculum.
Everything in the middle column is published RTL from Modules 16 and 17, instantiated byte-for-byte unchanged. The irq edge crosses the whole figure because it crosses nothing on the bus.
SEAM 1 is the core's native request interface meeting Wishbone. No specification describes it. The core's designer documented their side; B3 documents the other side; the converter between them is a module somebody has to write, and this module writes two of them.
SEAM 2 is a peripheral's registers meeting Wishbone. B3 describes the cycle. It says nothing about what a register does when you write it — whether a bit is read-only, whether writing a one clears it, whether the write has a side effect, or which byte lanes reach which field.
The bus in the middle is the part that is finished. Chapter 17.5's arbiter and Chapter 16.4's split tree are instantiated here unchanged, byte for byte, and neither is touched again.
3. The System This Module Measures
// ─────────────────────────────────────────────────────────────────────────
// m19_soc — the teaching SoC. Two seams, one bus, five slaves.
//
// core ifetch ─ wb_ifetch_adapter ─┐
// core dbus ─ wb_dbus_adapter ──┼─ wb_owner_arb3 ─ wb_split2 tree
// DMA ────────────────────┘ (M17) (M16)
//
// ├── boot ROM word 0x000..0x0FF
// ├── RAM word 0x400..0x4FF
// ├── timer word 0x800..0x803
// ├── GPIO word 0xA00..0xA03
// └── CSR bank word 0xC00..0xC03
//
// timer irq ──┐
// GPIO irq ──┴──────────────────── core irq_i NOT ON THE BUS
//
// Everything between the adapters and the slaves is published RTL from
// earlier modules, reused unchanged: wb_owner_arb3 from Chapter 17.5,
// wb_split2 from Chapter 16.4, wb_teaching_dma from Chapter 16.1. Module 19
// adds the two adapters at one seam and the register-bearing slaves at the
// other, and touches nothing in between.Five slaves, three masters, and a byte-to-word boundary that exists in exactly two files.
// ── BYTE ADDRESSES ABOVE, WORD ADDRESSES BELOW ──────────────────────────
// The core issues 32-bit BYTE addresses. The bus is WORD-addressed with
// AW = 12, which is Chapter 12.1's convention and, as it happens, LiteX's
// default too - its Wishbone Interface declares adr_width=30 for a 32-bit
// data width. The adapters divide by four. The boundary is in exactly two
// modules and nowhere else.
//
// byte 0x0000..0x03FF -> word 0x000..0x0FF boot ROM
// byte 0x1000..0x13FF -> word 0x400..0x4FF RAM
// byte 0x2000..0x200F -> word 0x800..0x803 timer
// byte 0x2800..0x280F -> word 0xA00..0xA03 GPIO
// byte 0x3000..0x300F -> word 0xC00..0xC03 CSR bank
//
// ── THERE IS NO UNMAPPED REGION, AND THAT IS A CHOICE ───────────────────
// The split tree is a dense binary decode: every address reaches some
// slave. A sparse map with holes needs a default slave, which is
// Chapter 12.6's subject and is not rebuilt here. The error cases in this
// module come from slaves refusing requests that are wrong for them - a
// write to the ROM, a write to a read-only register - which is where a
// real error usually comes from anyway.4. One Request, One Transfer
The smallest claim worth making about a seam is that it does not invent or destroy work. A core asks for one instruction; the bus performs one transfer; one answer comes back.
SIM A measures exactly that, and the ROM is written so the value returned names the word the fetch actually reached — ROM[i] = 0x10000000 + i. A fetch that lands on the wrong word returns a number that says so.
=== SIM A - one bus transfer per instruction fetch ===
boot ROM at byte 0x0000, word 0x000. ROM[i] = 0x10000000+i,
so the value names the word the fetch actually reached.
fetch byte addr word addr data returned
0x00000000 0x000 0x10000000
0x00000004 0x001 0x10000001
0x00000008 0x002 0x10000002
0x0000000c 0x003 0x10000003
SEAM 1, instruction port
core requests accepted 4
bus transfers terminated 4
answers returned to core 4
requests dropped 0
request moved while pending 0
SEL did not match the size 0
word address != byte/4 0
trap without error, or back 0
ROM reads 4 ROM writes refused 0Every violation counter is zero, and each of them is a separate accusation the instrument was capable of making. The wb_seam_probe that produced those lines recomputes SEL from the core's own request and compares it with what the adapter drove; it recomputes the word address as byte/4 and compares; it watches for a request that was accepted and then withdrawn. Section 7 of Chapter 19.5 runs the same probe against six systems in which those counters are not zero.
5. The Core Is Two Masters, Not One
A processor that fetches instructions and performs loads is two independent requesters, and on a single shared bus they compete.
=== SIM B - fetch and data, two masters, one bus ===
the core asks for an instruction and a load on the same
clock. They are two Wishbone masters and Chapter 17.5's
arbiter decides between them.
clk ifetch busy dbus busy owner bus adr ACK
1 0 0 - 0x000 0
2 0 0 - 0x000 0
3 1 1 - 0x000 0
4 1 1 - 0x000 0
5 1 1 DBUS 0x402 1
6 1 0 DBUS 0x402 0
7 1 0 IF 0x004 1
8 0 0 IF 0x004 0
9 0 0 - 0x000 0
instruction returned 0x10000004 from the ROM
load returned 0xaaaa0002 from the RAM
seam violations ifetch 0 dbus 0
transfers ifetch 1 dbus 1
-> two streams, two signatures, neither corrupted the
other. The interconnect is Module 17's, unchanged.Look at clocks 3 through 8. Both ports go busy on the same clock. The data port wins clock 5, the fetch port gets clock 7, and neither request was damaged by the delay. Nothing in this chapter arbitrates anything — that is wb_owner_arb3 from Chapter 17.5, instantiated and left alone.
This is also why the word "the CPU's bus interface" is misleading in the singular. Most RISC-V cores expose their fetch and data paths separately, and the ones that do not have multiplexed them internally, which is the same decision made one level up.
6. What a Whole Run Looks Like
Here is the system in §3 doing a plausible day's work in one simulation: boot from ROM, fill RAM, configure and start a DMA, keep fetching and writing registers while the DMA copies, take a timer interrupt, and service it.
=== SIM I - the whole system, one run ===
three masters: instruction fetch, load/store, DMA.
five slaves behind a split tree. ROM answers with one
wait state, the peripheral leg with two.
boot fetched 4 words from ROM: 0x10000000 0x10000001 0x10000002 0x10000003
fill wrote 4 words to RAM RAM writes so far 4
timer RELOAD 40, CTRL enable+irq_en reloads 1
dma src word 0x400 dst word 0x408 len 4, started
work 6 more fetches and 6 CSR writes issued while
the DMA was moving words (dma words 4)
dma done, 4 words copied
IRQ raised at bus clock 570, with no transfer of any
kind required to deliver it. irqs seen by the
core: 1 timer expiries: 1
svc read STATUS 0x00000001
svc wrote 1 to bit 0 at bus clock 586 irq now 0
check destination words, read back by the core
0xd0000000 expected 0xd0000000
0xd0000001 expected 0xd0000001
0xd0000002 expected 0xd0000002
0xd0000003 expected 0xd0000003Three numbers in there are the whole module.
The interrupt arrived at bus clock 570 with no transfer required to deliver it. Servicing it took two ordinary Wishbone accesses — a read of STATUS and a write of a one to bit zero — and the line went down. And the DMA moved four words that the core then read back correctly, while the core was itself using the bus throughout.
7. What RISC-V Actually Specifies, and What It Does Not
RISC-V specifies an instruction set and a memory model. It does not specify a bus, a bus width, a byte-enable encoding, an address map, a reset vector value, an interrupt wire, or a peripheral. A conformant RISC-V core and a conformant Wishbone slave can be wired together and not work, with neither of them wrong.
This is not a defect in either specification. It is the division of labour that makes both of them reusable. But it has a consequence that the rest of this module is about: the correctness argument for the join lives in your design, not in a rule number — and therefore it has to be measured, because there is nothing to cite.
8. Where This Module Goes
| chapter | seam | the question |
|---|---|---|
| 19.2 LiteX | both | what a generator decides for you, and what it leaves open |
| 19.3 Open hardware systems | 1 | three real cores, three different native interfaces, each documented only by itself |
| 19.4 CPU integration | 1 | byte enables, misalignment, errors, stall-versus-wait, and the interrupt |
| 19.5 Peripheral integration | 2 | register policies, side effects, decode, and the DATASHEET obligation |
Continue learning
Related tutorials
- Related topic
SoC Communication
Six chapters built the pieces; this one assembles them into a working fabric and traces three real accesses through it. The result works, and reading the nine unwritten rules a third party would need is what makes the case for a published protocol concrete rather than theoretical.
- Related topic
Data Flow
One Wishbone access, followed through every block in both directions: what the master drives, where the address changes form, which signals are broadcast and which are decoded, and how read data and termination find their way back to exactly one requester.
- 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.
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.
