Skip to content

Commit e3afb5b

Browse files
authored
[Monitor + Interp] Wishbone subordinate example (#193)
* Add example Wishbone Verilog files * Add Wishbone subordinate protocol file * Fix Protocol so that interpreter works * add todo * Add TODOs to Wishbone protocol * Add comments * Update Verilator test-bench so that it works on arm64 Macs * Fix bugs in C++ testbench based on slides * Gitignore VCD files * Edit Wishbone protocols to also inspect LED state * Update wishbone.tx * More changes to test-bench + monitor * Update two versions of wishbone.prot to be in sync * fix typo * Update monitor version of Wishbone protocol * Update transaction file for interpreter * [Interp] Add transaction info to assert_eq error messages * Comments' * Add new --display-hex CLI flag to interpreter * Format nullary protocols better in the error msg * [skip ci] Remove outdated comment about interpreter only accepting 1 Verilog file * Standardize the two versions of the Wishbone protocol * Remove LED from monitor Wishbone protocol * Fix typo in monitor WB prot * Make interpreter version of WB protocol same as monitor's * Add comments to wishbone.tx * Add comments to wishbone.prot (both versions)
1 parent 2f028fe commit e3afb5b

File tree

12 files changed

+1096
-0
lines changed

12 files changed

+1096
-0
lines changed

monitor/tests/wishbone/reqwalker.vcd

Lines changed: 419 additions & 0 deletions
Large diffs are not rendered by default.

monitor/tests/wishbone/wishbone.err

Whitespace-only changes.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// trace 0
2+
trace {
3+
read(0, 0);
4+
write(0, 0);
5+
read(0, 3);
6+
read(0, 5);
7+
read(0, 7);
8+
read(0, 9);
9+
read(0, 11);
10+
read(0, 0);
11+
write(0, 0);
12+
read(0, 3);
13+
read(0, 5);
14+
read(0, 7);
15+
read(0, 9);
16+
read(0, 11);
17+
read(0, 0);
18+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// ARGS: --wave wishbone/reqwalker.vcd --instances TOP.reqwalker:WBSubordinate --sample-posedge TOP.reqwalker.i_clk
2+
3+
// Wishbone B4 (Pipeline mode) subordinate
4+
struct WBSubordinate {
5+
// Cycle is high anytime an active pipeline session is occurring
6+
in i_cyc: u1,
7+
8+
// Strobe is high when there is a request to the subordinate
9+
// (akin to Valid in AXI-Lite, i.e. they indicate the manager
10+
// has something to transfer)
11+
in i_stb: u1,
12+
13+
// Write-enable (true for write-requests)
14+
in i_we: u1,
15+
16+
// Address of the request
17+
in i_addr: u1,
18+
19+
// Data to be written
20+
in i_data: u32,
21+
22+
// Response from the subordinate, indicating that the request
23+
// has been fulfilled.
24+
out o_ack: u1,
25+
26+
// True on any cycle when the subordinate can't accept requests
27+
// False when a request can be accepted
28+
// (i.e. the opposite of Ready in AXI-Lite)
29+
out o_stall: u1,
30+
31+
// Data returned by the subordinate to the manager
32+
// This is valid only when ACK is true
33+
out o_data: u32,
34+
}
35+
36+
// Both cyc & stb are low when the subordinate is low,
37+
// everything else is DontCare
38+
#[idle]
39+
prot idle<DUT: WBSubordinate>() {
40+
DUT.i_cyc := 1'b0;
41+
DUT.i_stb := 1'b0;
42+
DUT.i_we := X;
43+
DUT.i_addr := X;
44+
DUT.i_data := X;
45+
step();
46+
}
47+
48+
// Writes a `data` value to the subordinate.
49+
// Wishbone says to hold all request signals while stalled (stall=1),
50+
// i.e. when the subordinate is busy processing a previous request.
51+
prot write<DUT: WBSubordinate>(in addr: u1, in data: u32) {
52+
DUT.i_cyc := 1'b1;
53+
DUT.i_stb := 1'b1;
54+
DUT.i_we := 1'b1;
55+
DUT.i_addr := addr;
56+
DUT.i_data := data;
57+
58+
// Wait till the subordinate Acks
59+
// Note that in the Verilog, after the subordinate acks,
60+
// `o_stall` is assigned combinationally (`o_stall = busy && i_we`),
61+
// so we don't need another while-loop to wait for `stall` to become 0
62+
while (DUT.o_ack == 1'b0) {
63+
step();
64+
}
65+
66+
// Data is updated combinationally in the same cycle as the ack,
67+
// so no separate cycle for data transfer is needed
68+
assert_eq(DUT.o_data, data);
69+
70+
// Set other inputs to DontCare
71+
// Note that the waveform produced by their C++ test-bench keeps
72+
// `cyc` and `stb` high, so we don't set `cyc` and `stb` to 0 here
73+
DUT.i_cyc := X;
74+
DUT.i_stb := X;
75+
DUT.i_we := X;
76+
DUT.i_addr := X;
77+
DUT.i_data := X;
78+
79+
step();
80+
}
81+
82+
// Reads a value from the subordinate
83+
// (the `data` is conveyed via output parameters)
84+
prot read<DUT: WBSubordinate>(in addr: u1, out data: u32) {
85+
DUT.i_cyc := 1'b1;
86+
DUT.i_stb := 1'b1;
87+
DUT.i_we := 1'b0;
88+
DUT.i_addr := addr;
89+
DUT.i_data := X;
90+
91+
// Wait for subordinate to Ack
92+
// (When we're reading, the write-enable is always 0,
93+
// but in the Verilog, `stall` is a boolean AND of `i_we` and another
94+
// signal, so `stall` is always 0 when we're reading, so we don't
95+
// need another while-loop to wait for `stall` to become 0)
96+
while (DUT.o_ack == 1'b0) {
97+
step();
98+
}
99+
100+
// Data is updated combinationally in the same cycle as the ack,
101+
// so no separate cycle for data transfer is needed
102+
assert_eq(DUT.o_data, data);
103+
104+
// Set other inputs to DontCare
105+
// Note that the waveform produced by their C++ test-bench keeps
106+
// `cyc` and `stb` high, so we don't set `cyc` and `stb` to 0 here
107+
DUT.i_cyc := X;
108+
DUT.i_stb := X;
109+
DUT.i_we := X;
110+
DUT.i_addr := X;
111+
112+
step();
113+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
obj_dir/*
2+
reqwalker_tb
3+
*.vcd

protocols/tests/wishbone/Makefile

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
################################################################################
2+
##
3+
## Filename: Makefile
4+
##
5+
## Project: Verilog Tutorial Example file
6+
##
7+
## Purpose: Builds the Verilator request-walker bus slave example
8+
##
9+
## Targets:
10+
##
11+
## The (default) or all target will build a verilator simulation for the
12+
## Request Walker.
13+
##
14+
## clean Removes all build products
15+
##
16+
## Creator: Dan Gisselquist, Ph.D.
17+
## Gisselquist Technology, LLC
18+
##
19+
################################################################################
20+
##
21+
## Written and distributed by Gisselquist Technology, LLC
22+
##
23+
## This program is hereby granted to the public domain.
24+
##
25+
## This program is distributed in the hope that it will be useful, but WITHOUT
26+
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
27+
## FITNESS FOR A PARTICULAR PURPOSE.
28+
##
29+
################################################################################
30+
##
31+
##
32+
.PHONY: all
33+
all: reqwalker_tb
34+
35+
VERILATOR=verilator
36+
VERILATOR_ROOT ?= $(shell bash -c 'verilator -V|grep VERILATOR_ROOT | head -1 | sed -e "s/^.*=\s*//"')
37+
VINC := $(VERILATOR_ROOT)/include
38+
39+
obj_dir/Vreqwalker.cpp: reqwalker.v
40+
$(VERILATOR) --trace -Wall -cc reqwalker.v
41+
42+
obj_dir/Vreqwalker__ALL.a: obj_dir/Vreqwalker.cpp
43+
make --no-print-directory -C obj_dir -f Vreqwalker.mk
44+
45+
reqwalker_tb: reqwalker.cpp obj_dir/Vreqwalker__ALL.a
46+
g++ -I$(VINC) -I obj_dir $(VINC)/verilated.cpp \
47+
$(VINC)/verilated_vcd_c.cpp \
48+
$(VINC)/verilated_threads.cpp reqwalker.cpp \
49+
obj_dir/Vreqwalker__ALL.a -o reqwalker_tb
50+
51+
.PHONY: clean
52+
clean:
53+
rm -rf obj_dir/ reqwalker_tb reqwalker.vcd reqwalker_cvr/ reqwalker_prf/
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
////////////////////////////////////////////////////////////////////////////////
2+
//
3+
// Filename: redqalker.cpp
4+
//
5+
// Project: Verilog Tutorial Example file
6+
//
7+
// Purpose: This is an example Verilator test bench driver file reqwalker
8+
// module.
9+
//
10+
// Creator: Dan Gisselquist, Ph.D.
11+
// Gisselquist Technology, LLC
12+
//
13+
////////////////////////////////////////////////////////////////////////////////
14+
//
15+
// Written and distributed by Gisselquist Technology, LLC
16+
//
17+
// This program is hereby granted to the public domain.
18+
//
19+
// This program is distributed in the hope that it will be useful, but WITHOUT
20+
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
21+
// FITNESS FOR A PARTICULAR PURPOSE.
22+
//
23+
////////////////////////////////////////////////////////////////////////////////
24+
//
25+
//
26+
#include <stdio.h>
27+
#include <stdlib.h>
28+
#include "Vreqwalker.h"
29+
#include "verilated.h"
30+
#include "verilated_vcd_c.h"
31+
32+
// Required by Verilator when not using SystemC
33+
double sc_time_stamp() { return 0; }
34+
35+
int tickcount = 0;
36+
Vreqwalker *tb;
37+
VerilatedVcdC *tfp;
38+
39+
void tick(void) {
40+
tickcount++;
41+
42+
tb->eval();
43+
if (tfp)
44+
tfp->dump(tickcount * 10 - 2);
45+
tb->i_clk = 1;
46+
tb->eval();
47+
if (tfp)
48+
tfp->dump(tickcount * 10);
49+
tb->i_clk = 0;
50+
tb->eval();
51+
if (tfp) {
52+
tfp->dump(tickcount * 10 + 5);
53+
tfp->flush();
54+
}
55+
}
56+
57+
unsigned wb_read(unsigned a) {
58+
tb->i_cyc = tb->i_stb = 1;
59+
tb->i_we = 0;
60+
tb->eval(); // update o_stall, which depends combinationally on i_we
61+
tb->i_addr= a;
62+
// Make the request
63+
while(tb->o_stall)
64+
tick();
65+
tick();
66+
tb->i_stb = 0;
67+
// Wait for the ACK
68+
while(!tb->o_ack)
69+
tick();
70+
// Idle the bus, and read the response
71+
tb->i_cyc = 0;
72+
return tb->o_data;
73+
}
74+
75+
void wb_write(unsigned a, unsigned v) {
76+
tb->i_cyc = tb->i_stb = 1;
77+
tb->i_we = 1;
78+
tb->eval(); // update o_stall, which depends combinationally on i_we
79+
tb->i_addr= a;
80+
tb->i_data= v;
81+
// Make the bus request
82+
while(tb->o_stall)
83+
tick();
84+
tick();
85+
tb->i_stb = 0;
86+
// Wait for the acknowledgement
87+
while(!tb->o_ack)
88+
tick();
89+
// Idle the bus and return
90+
tb->i_cyc = tb->i_stb = 0;
91+
}
92+
93+
int main(int argc, char **argv) {
94+
int last_led, last_state = 0, state = 0;
95+
96+
// Call commandArgs first!
97+
Verilated::commandArgs(argc, argv);
98+
99+
// Instantiate our design
100+
tb = new Vreqwalker;
101+
102+
// Generate a trace
103+
Verilated::traceEverOn(true);
104+
tfp = new VerilatedVcdC;
105+
tb->trace(tfp, 99);
106+
tfp->open("reqwalker.vcd");
107+
108+
last_led = tb->o_led;
109+
110+
// Read from the current state
111+
printf("Initial state is: 0x%02x\n",
112+
wb_read(0));
113+
114+
for(int cycle=0; cycle<2; cycle++) {
115+
// Wait five clocks
116+
for(int i=0; i<5; i++)
117+
tick();
118+
119+
// Start the LEDs cycling
120+
wb_write(0,0);
121+
tick();
122+
123+
while((state = wb_read(0))!=0) {
124+
if ((state != last_state)
125+
||(tb->o_led != last_led)) {
126+
printf("%6d: State #%2d ",
127+
tickcount, state);
128+
for(int j=0; j<6; j++) {
129+
if(tb->o_led & (1<<j))
130+
printf("O");
131+
else
132+
printf("-");
133+
} printf("\n");
134+
}
135+
136+
last_state = state;
137+
last_led = tb->o_led;
138+
139+
// Idle cycle between reads so the VCD captures i_stb=0,
140+
// making each transaction visible as a separate event to the monitor
141+
tb->i_cyc = tb->i_stb = 0;
142+
tick();
143+
}
144+
}
145+
146+
tfp->close();
147+
delete tfp;
148+
delete tb;
149+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[tasks]
2+
cvr
3+
prf
4+
5+
[options]
6+
cvr: mode cover
7+
prf: mode prove
8+
9+
[engines]
10+
smtbmc
11+
12+
[script]
13+
read -formal reqwalker.v
14+
prep -top reqwalker
15+
16+
[files]
17+
reqwalker.v

0 commit comments

Comments
 (0)