Wishbone · Module 24
Register Maps
RULE 2.15 demands port size, granularity, operand size and endianness — and none of them describe a map. Holes, mixed widths and alignment are the slave's own contract, and an alignment rule that looked right made single-lane writes illegal.
Chapter 23.3 built a register bank from a table of access policies, and that table was the right idea. It also quietly assumed three things that no real map gets to assume:
- every offset below N exists — real maps have holes
- every register is the full port size — real maps mix 8, 16 and 32-bit
- any
[SEL_O()]pattern is acceptable — real maps have alignment rules
This chapter is about the map itself rather than the registers in it: a document that says what is at each offset, how wide it is, and what happens at the addresses where nothing is. Module 25's DMA engine will be a client of exactly such a document, and so is every driver ever written.
A register map is the only part of a peripheral that another human being has to read. Everything else can be inferred from behaviour; the map cannot, because the parts that matter most are the parts that do nothing.
1. What B3 Requires, And What It Leaves You
RULE 2.00 makes a datasheet mandatory. RULE 2.15 then lists twelve things it must contain, and five of them touch this chapter:
RULE 2.15 item 7 — "The WISHBONE DATASHEET MUST indicate the port size. MUST be indicated as: 8-bit, 16-bit, 32-bit or 64-bit."
item 8 — "...MUST indicate the port granularity..."
item 9 — "...MUST indicate the maximum operand size. ...If the maximum operand size is unknown, then the maximum operand size shall be the same as the granularity."
item 10 — "...MUST indicate the data transfer ordering. The ordering MUST be indicated as BIG ENDIAN or LITTLE ENDIAN."
item 11 — "...MUST indicate the sequence of data transfer through the port. If the sequence of data transfer is not known, then the datasheet MUST indicate it as UNDEFINED."
Read those five together and notice what is missing. They describe the port. Not one of them says which offsets exist, what is at offset 4, or what happens if you write to offset 9. B3 specifies the pipe and says nothing about what is on the other end of it.
Two rules do touch data layout, and they are narrower than they look:
RULE 3.100 — "Data organization on 32-bit ports MUST conform to
organization32."RULE 3.90 — "Data organization MUST conform to the ordering indicated in
operands."
Those fix which byte lane a byte lives in. They say nothing about whether a 16-bit register may be read with a 32-bit access, because B3 has no concept of a register at all.
| the question | who answers it |
|---|---|
| which lane does byte 2 occupy? | RULE 3.100 |
| is this port big or little endian? | RULE 2.15 item 10 — you must say |
| which offsets exist? | you, and nothing checks you |
| what does a hole do? | you |
| may a 32-bit access hit a 16-bit register? | you |
| what is the maximum operand size? | RULE 2.15 item 9 — you must say |
2. The Running Map
Every rig in Module 24 uses one map, so that one document describes every measurement:
// offset policy width source what it is
// 0 RW 32 reg a plain control word
// 1 RO 32 counter a free-running counter
// 2 W1C 8 status an interrupt flag word
// 3 WO 32 reg a command strobe
// 4 RW 16 reg a narrow config word
// 5 -- -- -- RESERVED
// 6 RW 8 fifo a byte-wide data port
// 7 RO 16 reg a narrow identity word
// 8-15 -- -- -- RESERVEDOffset 5 is a hole in the middle, not at the end. That is deliberate. A map whose reserved space is all at the top is the easy case; a hole between two live registers is where decode logic and documentation drift apart.
The encoding packs width and policy into four bits per offset:
// entry = {width[1:0], policy[1:0]} W8=0 W16=1 W32=2 RSVD=3
// RW=0 RO=1 W1C=2 WO=3A hole is encoded as a width, not as a fifth policy. That is a design decision worth stating: reserved and zero bytes wide are the same statement, and putting them in the same field makes it impossible to write a table entry that is reserved and also read-write.
3. Every Offset Is Accounted For
The sweep is the completeness proof, and the total is the point of it:
off present policy width lanes what
0 yes RW 32 1111 implemented
1 yes RO 32 1111 implemented
2 yes W1C 8 0001 implemented
3 yes WO 32 1111 implemented
4 yes RW 16 0011 implemented
5 NO -- -- 0000 RESERVED
6 yes RW 8 0001 implemented
7 yes RO 16 0011 implemented
8 NO -- -- 0000 RESERVED
implemented 7 reserved 9 total 16
-> EVERY OFFSET IN THE WINDOW IS ACCOUNTED FOR.
That is not automatic. A map that simply stops
at the last implemented register leaves the rest
of its own window undefined, and the integrator
finds out by writing there.7 + 9 = 16. Not "7 registers and some spare room" — sixteen offsets, each with a defined answer.
A map that describes only what exists is half a map. The addresses where nothing exists are the ones a driver reaches by accident, and they are the only part of the document that a reader cannot discover by experiment without risking the very side effects the map is supposed to warn them about.
4. The Three Policies For A Hole
B3 says nothing about an offset inside your window that you did not implement. Three answers exist:
// 1. alias it - mirror a real register. Cheap decode, and the
// integrator discovers it by accident in year two.
// 2. read 0 / ack - silent. Writes vanish, reads look plausible.
// 3. read 0 / ERR - reported. <-- THIS MODULEPolicy 1 is the cheapest and the most dangerous. Decoding only the bits you need means offset 9 lands on offset 1, and the aliasing is invisible until somebody's driver writes a "harmless" scratch location and stops a timer. It is not a bug in any rule — B3's own Partial Address Decoding model encourages decoding only what you need:
"each SLAVE decodes only the range of addresses that it requires... The remaining address bits are decoded by the interconnection system."
Policy 2 is what most silicon does, and it is why "I wrote it and it didn't take" is a permanent fixture of peripheral bring-up.
Policy 3 is the only one that tells anybody, and it costs an [ERR_O] the master may not have a pin for — which Chapter 24.5 shows is its own failure mode. There is no free choice here, only a documented one.
5. Alignment, And A Rule I Got Wrong
Here is the version of the alignment rule this module shipped first, and it is wrong:
// ─── DO NOT SHIP THIS ───────────────────────────────────────────────
// The first alignment rule this module shipped. It is internally
// consistent, it reads correctly, and it makes a single-byte write to a
// 32-bit register ILLEGAL - which is the one thing RULE 3.60 puts
// [SEL_O()] on the bus to express. SIM D caught it on its first run.
// "a register must be accessed at its own width"
assign strict_ok = (width_o == W32) ? (sel_i == 4'b1111) :
(width_o == W16) ? ((sel_i == 4'b0011) ||
(sel_i == 4'b1100)) :
(width_o == W8) ? (sel_i == 4'b0001) : 1'b0;It reads correctly. It is internally consistent. And it makes a single-byte write to a 32-bit register illegal — which is precisely the thing [SEL_O()] exists to express. RULE 3.60 puts [SEL_O()] on the bus so a master can say "change one byte"; a slave that refuses is not enforcing a contract, it is breaking one.
SIM D found it on its first run: a lane-1 write to offset 0 came back as a misalignment error.
The correct question is not does the access match the register's width but does the access stay inside the register:
// sel_i & ~lanes is the set of lanes the master asked for that this
// register does not own. It must be empty.
logic in_own, nonzero;
assign in_own = ((sel_i & ~own) == {SW{1'b0}});
assign nonzero = (sel_i != {SW{1'b0}});Subset, not equality. The table becomes:
off width SEL_I strict loose
0 32 1111 ok ok
0 32 0011 ok ok
0 32 0001 ok ok
2 8 1111 ERR ok
2 8 0001 ok ok
4 16 1111 ERR ok
4 16 0011 ok ok
4 16 0001 ok okA 32-bit register accepts any sub-pattern; a narrow register refuses anything reaching past it. That preserves RULE 3.60's purpose and still catches the access that would read bytes the register does not have.
6. What A Loose Map Costs
STRICT_ALIGN off accepts any non-zero select and lets the lane mask clip it:
offset 4 is 16 bits wide. A 32-bit access:
STRICT_ALIGN=1 aligned=0 -> the slave ERRORs it
STRICT_ALIGN=0 aligned=1 -> the slave accepts it
lanes the register occupies: 0011
-> THE LOOSE MAP RETURNS HALF A REGISTER AND SAYS
NOTHING. The lane mask clips the access to 0011,
so the upper two bytes read as zero - which is
indistinguishable from a register whose upper
half is genuinely zero. Neither choice is more
conformant; RULE 2.15 item 9 obliges you to
state the maximum operand size either way.That last sentence is the whole argument. A driver reading
0x0000BEEFfrom a 32-bit access cannot tell whether the upper half is zero because the register is narrow or because the field is clear. The strict map turns that ambiguity into an error; the loose map turns it into a plausible number.
Neither is more conformant. RULE 2.15 item 9 obliges you to state the maximum operand size either way, and a datasheet that says maximum operand size: 16-bit has told the reader everything the strict check would have enforced — if they read it.
STRICT_ALIGN = 1 | STRICT_ALIGN = 0 | |
|---|---|---|
| 32-bit access to a 16-bit register | [ERR_O] | succeeds, returns half |
| single-lane write to a 32-bit register | succeeds | succeeds |
| cost | an [ERR_O] path and a comparator | silence |
| what the datasheet must still say | operand size (item 9) | operand size (item 9) |
| failure mode | a driver that worked elsewhere now errors | a field that reads as zero forever |
7. Where The Map Is Not The Decoder
One boundary worth drawing, because these two jobs look alike and belong in different modules.
Chapter 23.5's decoder answers which slave. This map answers what is inside one slave. The decoder works on a base/mask table across a whole address space; the map works on four address bits after the interconnect has already chosen this slave.
They fail differently, too. A decoder hole means no slave answers — a hang, unless a default port exists. A map hole means this slave answers and refuses. The first is an interconnect problem and the second is a datasheet problem, and conflating them produces a peripheral that hangs the bus instead of reporting a bad offset.
// Compared at FIVE bits, not four. N may legitimately be 16, and
// N[3:0] is then zero - a truncation that makes every offset fall
// outside the window and the whole map read as unimplemented. SIM A
// found this on its first run.
logic in_window;
assign in_window = ({1'b0, off_o} < N[4:0]);That comment records a real bug and the sim that caught it. N is 16 and N[3:0] is 0, so the first version of this module reported every offset as unimplemented and the whole map came back empty. A width truncation in a comparison is silent in every tool that will ever look at it.
8. The Datasheet This Map Produces
| RULE 2.15 item | value |
|---|---|
| 1 revision level | B3 |
| 2 interface type | SLAVE |
| 7 port size | 32-bit |
| 8 granularity | 8-bit |
| 9 maximum operand size | 32-bit |
| 10 data ordering | LITTLE ENDIAN |
| 11 transfer sequence | UNDEFINED — SINGLE cycles only |
| — signal polarity | active high, per RULE 2.30 |
| — reserved offsets | read 0, write [ERR_O] — local policy |
| — alignment | subset of the register's lanes — local policy |
RULE 2.30 is worth its line: "All WISHBONE interface signals MUST use active high logic." It is the one rule in this chapter that requires no judgement at all, and it is there because some tools and some houses default the other way.
9. What This Chapter Did Not Build
- No register behaviour. The map says a register is
W1C; Chapter 24.3 makes clearing work. - No read multiplexing. The map says offset 6 is a FIFO; Chapter 24.2 connects one.
- No termination. Nothing here drives
[ACK_O]. The map is combinational and has no clock at all — it is a document that happens to be synthesisable. - No runtime reconfiguration. The table is a parameter.
- No 64-bit port. RULE 3.95 governs that layout and this module is 32-bit throughout.
Next: Chapter 24.2 — Read Logic connects four different sources to one [DAT_O()], and runs into a rule no chapter in this curriculum has cited before — the one that says a read's data is only meaningful on the clock it is answered, and therefore so is everything the read caused.
Continue learning
Related tutorials
- Related topic
Address Maps
An address map is a contract with five signatories and only one of them is checked by a compiler. Measured at the four addresses per region where decode bugs live.
- Related topic
Alignment
The two address bits the bus does not carry become the select pattern. Measured across every offset and size, including the misaligned operand that fits in one transfer.
- 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.
