Skip to content
VLSI Mentor

Wishbone · Module 29

Open Hardware Projects

A hand-written two-bit mux, a generated arbiter-and-decoder, and a formally-verified B4 pipelined crossbar with a starvation timeout — compared factually, with no winner declared.

Three projects. Three interconnects. One protocol family, and almost nothing else in common.

This chapter is not a directory and not a ranking. The objective is a single observation, made three times with evidence:

The specification constrains far less than people assume, and the space it leaves is where the engineering happens.

1. What We Inspected

projectrepositorycommitdatelicencestatus
SERV / servantgithub.com/olofk/servf200eb2e2026-08-25ISC; Apache-2.0 on servileactive, not archived
LiteXgithub.com/enjoy-digital/litexdce79bf92026-09-21BSD-2-Clauseactive, not archived
WB2AXIP / wbxbargithub.com/ZipCPU/wb2axip2e8d3bc22026-06-02Apache-2.0active, not archived

All three inspected 2026-09-22, and all three are the canonical upstream repositories — not forks or mirrors, checked against the GitHub API on the same date. The first two are the deep cases of 29.1 and 29.2; this chapter adds the third and sets them side by side.

2. The Third Project States Its Own Profile

wbxbar.v opens by saying what it is, which saves a great deal of guessing:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Purpose:	A Configurable wishbone cross-bar interconnect, conforming
//		to the WB-B4 pipeline specification, as described on the
//	ZipCPU blog.

ORIGINAL SOURCE EXCERPT — ZipCPU/wb2axip, rtl/wbxbar.v, commit 2e8d3bc2.

And its port list proves it, because it carries signals B3 Classic does not have:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
		output	wire	[NM-1:0]	o_mstall,

ORIGINAL SOURCE EXCERPT — same file.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
		input	wire	[NS-1:0]	i_sstall, i_sack,

ORIGINAL SOURCE EXCERPT — same file.

STALL does not exist in B3 Classic. In Classic, a slave that needs time withholds its termination and the phase simply stays open — that is the entire mechanism, and Module 9 is built on it. A STALL wire is a different contract: it says whether a new request is accepted this clock, independently of when any earlier one is answered.

This is the boundary that matters most when reading unfamiliar source. Everything Modules 5 through 9 taught about "the phase is open until its termination arrives" is a statement about B3 Classic. Carry it into a pipelined interface and you will conclude, confidently and wrongly, that an acknowledgement belongs to whatever is currently on the address lines.

The one consequence worth measuring:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== LAB F - PROFILE BOUNDARY ===

  eight operations, a three-clock target, one parameter

  profile        issued  acked  max outstanding  clocks
  B3 Classic          8      8                1      41
  pipelined           8      8                4      20

OUR MEASUREMENT, from a VLSI Mentor reconstruction — not from running wbxbar.

In Classic, max outstanding is 1 by construction. Not by choice, not by implementation quality: a phase is a request held until its termination, so there is nowhere for a second one to be. In the pipelined model the depth is whatever somebody chose. wbxbar's own header says:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//	LGMAXBURST can be set to control the maximum number of outstanding
//	transactions.  An LGMAXBURST of 6 will allow 63 outstanding
//	transactions.

ORIGINAL SOURCE EXCERPT — same file.

Do not read the clock counts as a performance comparison. They are two different protocols answering the same eight requests. The numbers differ because the contracts differ.

3. Three Answers To The Starvation Question

Chapter 28.4 asked what you would do about a master that waits forever, and noted that B3 mandates no arbitration algorithm at all. Here is what three projects actually did.

SERV/servant does not arbitrate in any general sense. Its arbiter merges two ports belonging to one CPU, with a fixed winner:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   assign o_wb_mem_adr = i_wb_cpu_ibus_stb ? i_wb_cpu_ibus_adr : i_wb_cpu_dbus_adr;

ORIGINAL SOURCE EXCERPT — olofk/serv, servile/servile_arbiter.v, commit f200eb2e.

Starvation is not a question this design has, because there is only one requester with two mouths and the file states they are never both open.

LiteX uses round-robin, with the grant advancing either freely or per transaction:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
        # connect bus requests to round-robin selector
        reqs = [m.cyc for m in masters]
        self.comb += self.rr.request.eq(Cat(*reqs))

ORIGINAL SOURCE EXCERPT — enjoy-digital/litex, litex/soc/interconnect/wishbone.py, commit dce79bf9.

Round-robin bounds the service interval as a local policy, not as a protocol property.

wbxbar does something neither of the others does — it makes starvation an error:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//	OPT_STARVATION_TIMEOUT, if set, applies the OPT_TIMEOUT counter to
//	how long a particular master waits for arbitration.  If the master is
//	"starved", a bus error will be returned.

ORIGINAL SOURCE EXCERPT — ZipCPU/wb2axip, rtl/wbxbar.v, commit 2e8d3bc2.

That is a genuinely different position. LiteX prevents starvation structurally; wbxbar permits it, detects it, and converts it into something the master can act on. Both are defensible. Neither is required by Wishbone, and a system that needs one and installs the other has a requirements problem, not a protocol problem.

Note also how differently the two timeouts answer. LiteX's watchdog synthesises an ACK with all-ones data. wbxbar's returns a bus error and aborts the cycle:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
//	OPT_TIMEOUT, if set to a non-zero value, is a number of clock periods
//	to wait for a slave to respond.  Should the timeout expire and the
//	slave not respond, a bus error will be returned and the slave will
//	be issued a bus abort signal (CYC will be dropped).

ORIGINAL SOURCE EXCERPT — same file.

Same problem, opposite answers, and the reason is architectural: wbxbar can afford ERR because its masters are expected to handle it, and LiteX's ACK is the conservative choice for a framework that must work with masters which may not.

4. The Comparison

SERV / servantLiteXwbxbar
inspected revisionf200eb2edce79bf92e8d3bc2
profileClassic-style, no STALLClassic-style, no STALLWB-B4 pipelined (stated)
mastersone CPU, two portsN, parameterisedNM, default 4
slavesRAM + one aggregate portM, parameterisedNS, default 8
topologyfixed mux + I/D mergeshared or crossbarcrossbar
decodeADR[31:30], two bitsper-slave function, CYC-gatedSLAVE_ADDR / SLAVE_MASK arrays
arbitrationfixed, instruction winsround-robin, two modesper-slave, with grant tracking
response steeringlive selector, licensed by a commentlive grant, or per-transactionper-master grant state
ERRNOT PRESENTpresent, ORed across slavespresent, and generated by timeouts
RTYNOT PRESENTNOT FOUND in the inspected fileNOT VERIFIED
timeoutNOT PRESENTwatchdog → synthesised ACKOPT_TIMEOUT → bus error + abort
starvationnot applicableprevented by round-robinOPT_STARVATION_TIMEOUT → error
registered outputsnoregister=True on the decoderOPT_DBLBUFFER
verification evidencetestbenches exist; NOT inspectedNOT INSPECTEDformal properties in-file
outstanding transfers11up to 63 at LGMAXBURST=6

No column of that table is a score. Read it as three engineering positions, each coherent with the system around it — and each a trade-off somebody made deliberately:

projectwhat it costswhat it buys
SERV / servantno way to signal an error, no room in the mapan interconnect of two combinational modules
LiteXone shared interface everything queues onany master and slave count, from one declaration
wbxbarpipelined state, outstanding-transfer tracking, a wider port listdepth, per-slave concurrency, and failures that report themselves
The three inspected topologies drawn side by side. The first is a fixed path: one CPU with two request ports meets a mux that splits on two address bits, then an arbiter that merges instruction and data traffic onto a single memory port, with a second port for everything else. The second is a generated shared interconnect: several masters arbitrate onto one shared interface which is then decoded to several slaves, with a watchdog observing the shared interface. The third is a pipelined crossbar: each master has its own decode into a row of access interfaces, and each slave has its own arbiter over a column of them, so there is no single shared interface anywhere, and every port carries a stall signal that the first two do not have.servantfixed path2-bit mux + I/Dmergeno ERR, no RTY, notimeoutRAM + oneaggregate port2 targetsLiteXgeneratedarbiter to ONEinterfacethen decode; watchdog onthe shared sideM slavesCYC-gatedwbxbarWB-B4 pipelineddecode per master,arbiter per slaveno shared interfaceNS slavesSTALL on every portsame protocolfamilythree different answersto ownership, failureand depth12

5. The Verification Row Is Not Decoration

wbxbar carries its properties in the same file as the logic:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
`ifdef	FORMAL

ORIGINAL SOURCE EXCERPT — same file.

and among them, an invariant that should look familiar:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
			assert((grant[N][NS-1:0] & grant[iN][NS-1:0])==0);

ORIGINAL SOURCE EXCERPT — same file.

Two masters may not hold the same slave's grant simultaneously — a one-hot ownership property, asserted rather than assumed. Chapter 26.2 argued that an assertion nobody has seen fail is an assertion nobody has tested; a formally-proved one is a stronger statement than either.

SOURCE FACT: the file contains FORMAL-guarded assertions including grant exclusivity. NOT VERIFIED: we did not run the proofs. We are reporting that the properties exist and what one of them says.

6. The Crossbar Question, Measured

wbxbar is a crossbar. LiteX offers one. The tempting sentence is "a crossbar is faster", and it is not a sentence the structure supports on its own.

A crossbar removes the single shared interface that transfers would otherwise queue on. Whether that is worth anything depends entirely on whether the traffic is going to different places:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  THE MEASURED CONCLUSION
  With disjoint destinations the crossbar had two transfers
  selected on 4 clocks and the shared interface on 0,
  finishing in 21 clocks against 25.
  With both masters aimed at ONE slave the crossbar had
  0 concurrent clocks and finished in 25, against 25.

OUR MEASUREMENT, from a VLSI Mentor reconstruction of the inspected LiteX classes.

21 against 25 with disjoint destinations. 25 against 25 with a shared one. The architectural statement is the topology permits two transfers to proceed independently. The performance statement needs a workload, and with the wrong workload the answer is zero.

That is the honest form of the claim, and it is also the useful one: it tells you what to measure before choosing.

7. What Not To Generalize

Do not transfer timing assumptions across profiles. wbxbar is B4 pipelined and says so. Reading it with Classic habits produces wrong conclusions about which acknowledgement belongs to which request.

Do not read the table as a maturity ranking. SERV's missing ERR is not a gap; it is an absent requirement. wbxbar's starvation timeout is not over-engineering; it is a different system's need.

Do not infer deployment from any of this. Three maintained open-source repositories is exactly what we verified. Stars, age and conference appearances are not deployment evidence, and we are not claiming any.

Do not assume the defaults are what anybody ships. OPT_TIMEOUT defaults to 0 — disabled — in the inspected source. Every one of these knobs has a default and a reason somebody might change it.

Do not treat "no RTY" as three identical findings. For SERV it is a verified absence in the inspected files. For LiteX it is NOT FOUND in the one file we read, which is a weaker statement about a 1,147-line module inside a much larger framework. For wbxbar it is NOT VERIFIED, because we did not look. Those are three different epistemic positions and collapsing them into one row would be the exact failure this chapter is trying to avoid.

8. What To Carry Forward

  • Establish the profile before reading the timing. If the port list has STALL, your Classic intuitions are about a different contract.
  • B3 leaves arbitration, timeout, error policy and topology to you — and three projects took three different routes through that space.
  • A timeout that answers ACK and a timeout that answers ERR solve the same problem for different masters. Which is right depends on what your master can handle.
  • "Faster" needs a workload. 21 versus 25, or 25 versus 25, from the same two topologies.
  • Properties in the file are evidence. Grant exclusivity asserted beats grant exclusivity assumed.

Chapter 29.4 goes back to the smallest systems and asks what they are actually good for.

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.