Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dd6b328
Add example Wishbone Verilog files
ngernest Feb 19, 2026
1782cae
Add Wishbone subordinate protocol file
ngernest Feb 20, 2026
cbd0937
Fix Protocol so that interpreter works
ngernest Feb 20, 2026
2cccfc1
add todo
ngernest Feb 20, 2026
fe379a4
Add TODOs to Wishbone protocol
ngernest Feb 20, 2026
69716db
Merge remote-tracking branch 'origin/main' into wishbone_example
ngernest Feb 24, 2026
b648c25
Add comments
ngernest Feb 24, 2026
2b08966
Update Verilator test-bench so that it works on arm64 Macs
ngernest Feb 24, 2026
5b78742
Fix bugs in C++ testbench based on slides
ngernest Feb 24, 2026
78dfd79
Gitignore VCD files
ngernest Feb 24, 2026
29bb3db
Edit Wishbone protocols to also inspect LED state
ngernest Feb 24, 2026
f8207ae
Update wishbone.tx
ngernest Feb 24, 2026
0cc9796
More changes to test-bench + monitor
ngernest Feb 24, 2026
ed517da
Update two versions of wishbone.prot to be in sync
ngernest Feb 24, 2026
9a6639e
fix typo
ngernest Feb 24, 2026
17cefb4
Update monitor version of Wishbone protocol
ngernest Feb 26, 2026
92fb6ed
Update transaction file for interpreter
ngernest Feb 26, 2026
320ea5c
[Interp] Add transaction info to assert_eq error messages
ngernest Feb 26, 2026
623e597
Comments'
ngernest Feb 26, 2026
4d6f982
Add new --display-hex CLI flag to interpreter
ngernest Feb 26, 2026
0d9feda
Format nullary protocols better in the error msg
ngernest Feb 26, 2026
fd487b1
[skip ci] Remove outdated comment about interpreter only accepting 1 …
ngernest Feb 26, 2026
47a3dfe
Standardize the two versions of the Wishbone protocol
ngernest Feb 26, 2026
e97eb2f
Merge remote-tracking branch 'origin/worktree-assert-eq-transaction-i…
ngernest Feb 26, 2026
8cdbeeb
Remove LED from monitor Wishbone protocol
ngernest Feb 26, 2026
8ba9986
Fix typo in monitor WB prot
ngernest Feb 26, 2026
de6caca
Make interpreter version of WB protocol same as monitor's
ngernest Feb 26, 2026
1249411
Merge remote-tracking branch 'origin/main' into wishbone_example
ngernest Feb 26, 2026
bb24ff9
Add comments to wishbone.tx
ngernest Feb 26, 2026
c834c16
Add comments to wishbone.prot (both versions)
ngernest Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
419 changes: 419 additions & 0 deletions monitor/tests/wishbone/reqwalker.vcd

Large diffs are not rendered by default.

Empty file.
18 changes: 18 additions & 0 deletions monitor/tests/wishbone/wishbone.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// trace 0
trace {
read(0, 0);
write(0, 0);
read(0, 3);
read(0, 5);
read(0, 7);
read(0, 9);
read(0, 11);
read(0, 0);
write(0, 0);
read(0, 3);
read(0, 5);
read(0, 7);
read(0, 9);
read(0, 11);
read(0, 0);
}
113 changes: 113 additions & 0 deletions monitor/tests/wishbone/wishbone.prot
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// ARGS: --wave wishbone/reqwalker.vcd --instances TOP.reqwalker:WBSubordinate --sample-posedge TOP.reqwalker.i_clk

// Wishbone B4 (Pipeline mode) subordinate
struct WBSubordinate {
// Cycle is high anytime an active pipeline session is occurring
in i_cyc: u1,

// Strobe is high when there is a request to the subordinate
// (akin to Valid in AXI-Lite, i.e. they indicate the manager
// has something to transfer)
in i_stb: u1,

// Write-enable (true for write-requests)
in i_we: u1,

// Address of the request
in i_addr: u1,

// Data to be written
in i_data: u32,

// Response from the subordinate, indicating that the request
// has been fulfilled.
out o_ack: u1,

// True on any cycle when the subordinate can't accept requests
// False when a request can be accepted
// (i.e. the opposite of Ready in AXI-Lite)
out o_stall: u1,

// Data returned by the subordinate to the manager
// This is valid only when ACK is true
out o_data: u32,
}

// Both cyc & stb are low when the subordinate is low,
// everything else is DontCare
#[idle]
prot idle<DUT: WBSubordinate>() {
DUT.i_cyc := 1'b0;
DUT.i_stb := 1'b0;
DUT.i_we := X;
DUT.i_addr := X;
DUT.i_data := X;
step();
}

// Writes a `data` value to the subordinate.
// Wishbone says to hold all request signals while stalled (stall=1),
// i.e. when the subordinate is busy processing a previous request.
prot write<DUT: WBSubordinate>(in addr: u1, in data: u32) {
DUT.i_cyc := 1'b1;
DUT.i_stb := 1'b1;
DUT.i_we := 1'b1;
DUT.i_addr := addr;
DUT.i_data := data;

// Wait till the subordinate Acks
// Note that in the Verilog, after the subordinate acks,
// `o_stall` is assigned combinationally (`o_stall = busy && i_we`),
// so we don't need another while-loop to wait for `stall` to become 0
while (DUT.o_ack == 1'b0) {
step();
}

// Data is updated combinationally in the same cycle as the ack,
// so no separate cycle for data transfer is needed
assert_eq(DUT.o_data, data);

// Set other inputs to DontCare
// Note that the waveform produced by their C++ test-bench keeps
// `cyc` and `stb` high, so we don't set `cyc` and `stb` to 0 here
DUT.i_cyc := X;
DUT.i_stb := X;
DUT.i_we := X;
DUT.i_addr := X;
DUT.i_data := X;

step();
}

// Reads a value from the subordinate
// (the `data` is conveyed via output parameters)
prot read<DUT: WBSubordinate>(in addr: u1, out data: u32) {
DUT.i_cyc := 1'b1;
DUT.i_stb := 1'b1;
DUT.i_we := 1'b0;
DUT.i_addr := addr;
DUT.i_data := X;

// Wait for subordinate to Ack
// (When we're reading, the write-enable is always 0,
// but in the Verilog, `stall` is a boolean AND of `i_we` and another
// signal, so `stall` is always 0 when we're reading, so we don't
// need another while-loop to wait for `stall` to become 0)
while (DUT.o_ack == 1'b0) {
step();
}

// Data is updated combinationally in the same cycle as the ack,
// so no separate cycle for data transfer is needed
assert_eq(DUT.o_data, data);

// Set other inputs to DontCare
// Note that the waveform produced by their C++ test-bench keeps
// `cyc` and `stb` high, so we don't set `cyc` and `stb` to 0 here
DUT.i_cyc := X;
DUT.i_stb := X;
DUT.i_we := X;
DUT.i_addr := X;

step();
}
3 changes: 3 additions & 0 deletions protocols/tests/wishbone/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
obj_dir/*
reqwalker_tb
*.vcd
53 changes: 53 additions & 0 deletions protocols/tests/wishbone/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
################################################################################
##
## Filename: Makefile
##
## Project: Verilog Tutorial Example file
##
## Purpose: Builds the Verilator request-walker bus slave example
##
## Targets:
##
## The (default) or all target will build a verilator simulation for the
## Request Walker.
##
## clean Removes all build products
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
##
################################################################################
##
## Written and distributed by Gisselquist Technology, LLC
##
## This program is hereby granted to the public domain.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
## FITNESS FOR A PARTICULAR PURPOSE.
##
################################################################################
##
##
.PHONY: all
all: reqwalker_tb

VERILATOR=verilator
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e "s/^.*=\s*//"')
VINC := $(VERILATOR_ROOT)/include

obj_dir/Vreqwalker.cpp: reqwalker.v
$(VERILATOR) --trace -Wall -cc reqwalker.v

obj_dir/Vreqwalker__ALL.a: obj_dir/Vreqwalker.cpp
make --no-print-directory -C obj_dir -f Vreqwalker.mk

reqwalker_tb: reqwalker.cpp obj_dir/Vreqwalker__ALL.a
g++ -I$(VINC) -I obj_dir $(VINC)/verilated.cpp \
$(VINC)/verilated_vcd_c.cpp \
$(VINC)/verilated_threads.cpp reqwalker.cpp \
obj_dir/Vreqwalker__ALL.a -o reqwalker_tb

.PHONY: clean
clean:
rm -rf obj_dir/ reqwalker_tb reqwalker.vcd reqwalker_cvr/ reqwalker_prf/
149 changes: 149 additions & 0 deletions protocols/tests/wishbone/reqwalker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: redqalker.cpp
//
// Project: Verilog Tutorial Example file
//
// Purpose: This is an example Verilator test bench driver file reqwalker
// module.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Written and distributed by Gisselquist Technology, LLC
//
// This program is hereby granted to the public domain.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
#include <stdlib.h>
#include "Vreqwalker.h"
#include "verilated.h"
#include "verilated_vcd_c.h"

// Required by Verilator when not using SystemC
double sc_time_stamp() { return 0; }

int tickcount = 0;
Vreqwalker *tb;
VerilatedVcdC *tfp;

void tick(void) {
tickcount++;

tb->eval();
if (tfp)
tfp->dump(tickcount * 10 - 2);
tb->i_clk = 1;
tb->eval();
if (tfp)
tfp->dump(tickcount * 10);
tb->i_clk = 0;
tb->eval();
if (tfp) {
tfp->dump(tickcount * 10 + 5);
tfp->flush();
}
}

unsigned wb_read(unsigned a) {
tb->i_cyc = tb->i_stb = 1;
tb->i_we = 0;
tb->eval(); // update o_stall, which depends combinationally on i_we
tb->i_addr= a;
// Make the request
while(tb->o_stall)
tick();
tick();
tb->i_stb = 0;
// Wait for the ACK
while(!tb->o_ack)
tick();
// Idle the bus, and read the response
tb->i_cyc = 0;
return tb->o_data;
}

void wb_write(unsigned a, unsigned v) {
tb->i_cyc = tb->i_stb = 1;
tb->i_we = 1;
tb->eval(); // update o_stall, which depends combinationally on i_we
tb->i_addr= a;
tb->i_data= v;
// Make the bus request
while(tb->o_stall)
tick();
tick();
tb->i_stb = 0;
// Wait for the acknowledgement
while(!tb->o_ack)
tick();
// Idle the bus and return
tb->i_cyc = tb->i_stb = 0;
}

int main(int argc, char **argv) {
int last_led, last_state = 0, state = 0;

// Call commandArgs first!
Verilated::commandArgs(argc, argv);

// Instantiate our design
tb = new Vreqwalker;

// Generate a trace
Verilated::traceEverOn(true);
tfp = new VerilatedVcdC;
tb->trace(tfp, 99);
tfp->open("reqwalker.vcd");

last_led = tb->o_led;

// Read from the current state
printf("Initial state is: 0x%02x\n",
wb_read(0));

for(int cycle=0; cycle<2; cycle++) {
// Wait five clocks
for(int i=0; i<5; i++)
tick();

// Start the LEDs cycling
wb_write(0,0);
tick();

while((state = wb_read(0))!=0) {
if ((state != last_state)
||(tb->o_led != last_led)) {
printf("%6d: State #%2d ",
tickcount, state);
for(int j=0; j<6; j++) {
if(tb->o_led & (1<<j))
printf("O");
else
printf("-");
} printf("\n");
}

last_state = state;
last_led = tb->o_led;

// Idle cycle between reads so the VCD captures i_stb=0,
// making each transaction visible as a separate event to the monitor
tb->i_cyc = tb->i_stb = 0;
tick();
}
}

tfp->close();
delete tfp;
delete tb;
}
17 changes: 17 additions & 0 deletions protocols/tests/wishbone/reqwalker.sby
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[tasks]
cvr
prf

[options]
cvr: mode cover
prf: mode prove

[engines]
smtbmc

[script]
read -formal reqwalker.v
prep -top reqwalker

[files]
reqwalker.v
Loading