Skip to content
VLSI Mentor

Wishbone · Module 19

LiteX

What a SoC generator settles that B3 leaves open — word addressing as a default, a separate narrow CSR bus with a named Wishbone bridge, and a CPU base class whose fields are an inventory of unspecified things.

Chapter 19.1 established that two boundaries in a RISC-V Wishbone system are specified by nobody. A SoC generator is a codebase that has already decided all of them, for every core it supports, and written the decisions down. That makes it unusually good reading.

What does LiteX settle that Wishbone B3 leaves open — and what does it still leave to you?

1. LiteX Is Not a Bus. It Is a Generator.

LiteX assembles SoCs from Python descriptions. Wishbone is one of the buses it can emit. The useful observation is not that LiteX "uses Wishbone" — it is that a generator must answer every open question at generation time, because there is no human in the loop to answer it later.

Three of its answers are worth reading against B3 directly.

2. Word Addressing, Made Explicit

From litex/soc/interconnect/wishbone.py, the Wishbone Interface defaults are data_width=32, adr_width=30, with sel_width = data_width//8.

Thirty address bits for a 32-bit data path is the word-addressing convention stated as a default. Two bits are gone, permanently, before any address map is written. They did not disappear — they moved into sel.

This is Chapter 12.1's convention, and it is the single most common source of confusion when a byte-addressing core meets a Wishbone slave. The teaching SoC in this module makes the same choice and confines the division to exactly two modules:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── 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

The comment is doing real work there. If the byte-to-word boundary lives in more than one place, the two places will eventually disagree, and the symptom will be a peripheral that responds to the wrong address rather than anything that looks like an addressing bug.

3. A Separate Bus For Registers, With an Explicit Bridge

This is the decision that surprises people, and it is the one worth the most.

LiteX does not hang every peripheral register directly off Wishbone. It has litex/soc/interconnect/csr_bus.py, whose own docstring describes it as:

"The CSR Bus is a lightweight and low-bandwidth bus design for accessing Configuration and Status Registers (CSRs)."

Its signals are adr, re, we, dat_w, dat_rnot CYC, STB, ACK, SEL. And litex/soc/interconnect/wishbone.py contains class Wishbone2CSR(LiteXModule): an explicit, named bridge between the two.

Two ways to reach peripheral registers. The upper path, as LiteX generates it, runs the CPU onto a Wishbone bus, past RAM, into an explicitly named Wishbone-to-CSR bridge, and then onto a separate narrow CSR bus carrying adr, re, we, dat_w and dat_r to the register banks. The lower path, used by this module's teaching SoC, runs the same CPU through a Wishbone arbiter and split tree directly onto register banks that are themselves Wishbone slaves, with no bridge and no second bus. Both are legal; they differ in where the complexity sits.CPULiteX shapeWishbonememory trafficWishbone2CSRan explicit bridgeCSR busadr re we dat_wdat_rcorethis moduleWishbonearbiter + splitregister banksWishbone slavesnarrowerno bridge12

Neither row is more correct. The upper one spends a bridge to avoid carrying SEL, ERR and cycle framing into every eight-bit configuration register; the lower one spends that apparatus to keep every register access visible as a Wishbone cycle, which is what makes Chapter 19.5 measurable.

This module's teaching SoC makes the opposite choice, deliberately: its register banks are Wishbone slaves directly, so that every register access in Chapter 19.5 is a Wishbone cycle you can watch. That is a teaching choice, not a better one, and stating which is which is the point of the exercise.

4. The Name Collision, Settled Once

"CSR" means two unrelated things in a RISC-V Wishbone system, and they are both in scope for this module.

a RISC-V CSRa peripheral CSR
reached bya csrrw-class instructiona load or store
livesinside the coreon the bus
appears on any busneveryes
specified bythe RISC-V privileged ISAthe peripheral's datasheet
examplemtvec, mstatusa timer's RELOAD register

Everything in Module 19 called CSR is the second kind. The first kind never leaves the core and therefore never reaches a seam. The register bank built for this module states the collision in its own header rather than assuming the reader will infer it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── THE NAME COLLISION, STATED ONCE ─────────────────────────────────────
// "CSR" here means a memory-mapped peripheral register bank, which is how
// SoC generators use the term - LiteX has a whole csr_bus.py whose own
// docstring calls it "a lightweight and low-bandwidth bus design for
// accessing Configuration and Status Registers (CSRs)", and it is a
// SEPARATE BUS from Wishbone with its own adr/re/we/dat_w/dat_r signals,
// bridged by an explicit Wishbone2CSR module.
//
// A RISC-V Control and Status Register is a DIFFERENT THING with the same
// name: it is reached by instruction, lives inside the core, and never
// appears on any bus. Neither this module nor anything else in Module 19
// is about those.

5. The CPU Base Class Is a List of Unspecified Things

litex/soc/cores/cpu/__init__.py defines a CPU base class. Its fields are, in effect, an inventory of everything neither RISC-V nor Wishbone covers:

fieldwhat it iswho specifies it
periph_buses / memory_busesthe core has more than one bus port, and they are different liststhe core's author
interrupts = {}a named map of interrupt linesnobody — see 19.4
mem_map = {"csr": 0x82000000}where register space landsthe integrator
reset_address_checkwhether the core will boot from where you put the ROMthe core's author

Read that list again as a specification gap report. Every one of those fields exists because two conformant specifications left the question open and somebody had to fill it in per core. periph_buses and memory_buses being separate lists is Chapter 19.1 §5's measurement written as a data structure: a core is more than one master.

6. What a Generator Cannot Decide For You

A generator settles the plumbing. It does not settle what a register does.

SIM H exercises four access policies in one 32-bit-wide register bank — the policies a generator emits code for but does not choose:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  === SIM H - four access policies, one register bank ===
    the CSR bank at byte 0x3000 decodes only two offset bits,
    which is B3's Partial Address Decoding: "each SLAVE
    decodes only the range of addresses that it requires...
    The remaining address bits are decoded by the
    interconnection system."  Two wait states on this leg.

      access                 pol   result   expected     verdict
      write SCRATCH word     RW    ok       0x11223344  (write)      PASS
      read  SCRATCH          RW    ok       0x11223344  0x11223344   PASS
      write SCRATCH byte+1   RW    ok       0x1122ee44  (write)      PASS
      read  SCRATCH again    RW    ok       0x1122ee44  0x1122ee44   PASS
      write IDENT            RO    ERR      0x00000000  (write)      PASS
      read  IDENT            RO    ok       0xc5b00001  0xc5b00001   PASS
      read  COMMAND          WO    ok       0x00000000  0x00000000   PASS

Every row there is local register policy. The bus performed an ordinary WRITE cycle in each case. What differed was the slave's reaction: storage, refusal, a counter, or nothing at all. Chapter 19.5 takes each of these apart.

Note row five. A write to the read-only IDENT register was answered ERR_O, and the bank counted it. That is a legal Wishbone termination carrying a purely local meaning — and per RULE 2.15 item 4, B3's only requirement about it is that the datasheet say when it happens.

7. Partial Address Decoding, Which B3 Endorses

The bank above decodes only the two address bits it needs. That is not laziness; B3 lists it as a feature:

"each SLAVE decodes only the range of addresses that it requires... The remaining address bits are decoded by the interconnection system."

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ── PARTIAL ADDRESS DECODING ────────────────────────────────────────────
// This slave decodes only the two offset bits it needs. B3 lists that as a
// feature - "each SLAVE decodes only the range of addresses that it
// requires... The remaining address bits are decoded by the interconnection
// system." CSR_ALIAS is this module decoding one bit too few.

And it is the origin of one of this module's six seeded defects. CSR_ALIAS is the same decoder with one bit too few — a slave that decodes adr[0] but not adr[1], so every register becomes two registers. Chapter 19.5 §7 measures what that actually breaks, and the answer is more than one thing, which is what makes it hard to find.

8. The Lesson, Stated Generally

B3 settlesa generator settlesyou still settle
cycle framing, termination, signal stabilityaddress width convention, bridges, bus topology, which peripheral sits wherewhat each register does when written
what a slave may assert and whenwhich core connects to which bus portwhat your core does with ERR_I
that SEL_O is qualified by STB_Osel_width = data_width//8which lanes a half-word at offset 2 asserts

The third column is the one that does not get smaller when you adopt a generator. It is Chapter 19.4 and Chapter 19.5.

Continue learning

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.