@@ -27,6 +27,7 @@ struct WBManager {
2727 in i_wb_data: u32,
2828}
2929
30+
3031prot reset<DUT: WBManager>() {
3132 DUT.i_reset := 1'b1;
3233
@@ -51,136 +52,127 @@ prot idle<DUT: WBManager>() {
5152 step();
5253}
5354
54- // Sets the Wishbone bus address to `addr`.
55- // Sends a CMD_SUB_ADDR command where the "opcode" is i_cmd_word[33:32] = 2'b10:
56- // i_cmd_word[31:2] = addr (30-bit absolute address)
57- // i_cmd_word[1] = 0
58- // i_cmd_word[0] = 0
59- //
60- // The manager echoes the new address back on the response channel one cycle
61- // after the command is accepted. Specifically, after one cycle,
62- // `o_rsp_stb` is set to 1 and `o_rsp_word` contains the address.
63- //
64- // response format in `o_rsp_word`: { 2'b10, addr[29:0], 1'b0, !inc }
65- // where:
66- // - RSP_SUB_ADDR = 2'b10 is the "opcode" for the response
67- // - `inc` is an internal variable in the Verilog module.
68- // When i_cmd_word[0]=0, inc=1, so !inc=0, i.e. the response is {2'b10, addr, 2'b00}.
69- prot set_address<DUT: WBManager>(in addr: u30) {
55+ // This protocol writes a 32-bit `data` word to the Wishbone bus at `addr`,
56+ // assuming that the subordinate does not stall (i_wb_stall = 0 throughout).
57+ // Under the hood, this corresponds to a "set address" command (`CMD_SUB_ADDR`),
58+ // followed immediately by a "write" command (`CMD_SUB_WR`).
59+ // (The two commands can be issued back to back, since updating the address
60+ // only updates the address and doesn't affect `cyc` or `stb`, and the latter
61+ // is what governs when `read` / `write` protocols can fire.)
62+ // State progression:
63+ // 1. IDLE: send CMD_SUB_ADDR, step -> address updated
64+ // 2. IDLE: send CMD_SUB_WR, step -> cyc=1, stb=1, we=1 (bus request starts)
65+ // 3. BUS REQUEST (cyc=1, stb=1, we=1): subordinate accepts (stall=0), step
66+ // 4. BUS WAIT (cyc=1, stb=0): subordinate acknowledges (ack=1), step
67+ // 5. IDLE (cyc=0): RSP_WRITE_ACKNOWLEDGEMENT = {2'b01, 32'x0} on response channel
68+ prot write<DUT: WBManager>(in addr: u30, in data: u32) {
69+ // Issue a "set address" command (`CMD_SUB_ADDR`)
70+ // In `i_cmd_word`, we have:
71+ // - bits[33:32] = 2'b10 (opcode for `CMD_SUB_ADDR`)
72+ // - bits[31:2] = the actual address
7073 DUT.i_reset := 1'b0;
7174 DUT.i_cmd_stb := 1'b1;
72-
73- // bit[33:32]=2'b10 (CMD_SUB_ADDR), bits[31:2]=addr, bit[1]=0 (absolute), bit[0]=0 (auto-increment)
7475 DUT.i_cmd_word := 30'b10 + addr + 30'b0;
7576 DUT.i_wb_stall := 1'b0;
7677 DUT.i_wb_ack := 1'b0;
7778 DUT.i_wb_err := 1'b0;
7879 assert_eq(DUT.o_cmd_busy, 1'b0);
79- step();
80+ step(); // Address is updated in the Verilog during this step
8081
81- // At this point, in the Verilog, `o_wb_addr` and `newaddr` are updated.
82- // TODO: figure out how to express address increment since our langauge
83- // doesn't have addition
84- DUT.i_cmd_stb := 1'b0;
85- step();
86-
87- // Manager echoes the new address back on the response channel
88- assert_eq(DUT.o_rsp_stb, 1'b1);
89- assert_eq(DUT.o_rsp_word, 30'b10 + addr + 30'b0);
90- step();
91- }
92-
93- // Writes a 32-bit `data` word to the Wishbone bus at the current address.
94- // Sends the CMD_SUB_WR "opcode" (i_cmd_word[33:32] = 2'b01) with `data` in bits [31:0].
95- // This assumes the subordinate does not stall (i_wb_stall = 0 throughout).
96- //
97- // State machine progression:
98- // IDLE -> issue command -> step
99- // BUS REQUEST (cyc=1, stb=1, we=1): subordinate accepts immediately (stall=0) -> step
100- // BUS WAIT (cyc=1, stb=0): subordinate acknowledges (ack=1) -> step
101- // IDLE (cyc=0): RSP_WRITE_ACKNOWLEDGEMENT = {2'b01, 32'x0} on response channel
102- prot write<DUT: WBManager>(in data: u32) {
103- // IDLE: issue write command
104- DUT.i_reset := 1'b0;
82+ // Issue a write command immediately by setting `stb = 1`
83+ // (`o_cmd_busy = 0` since `cyc = 0`)
84+ // In `i_cmd_word`, we have:
85+ // - bits[33:32] = 2'b01 (opcode for `CMD_SUB_WR`)
86+ // - bits[31:0] = data
10587 DUT.i_cmd_stb := 1'b1;
10688 DUT.i_cmd_word := 32'x1 + data;
107- DUT.i_wb_stall := 1'b0;
108- DUT.i_wb_ack := 1'b0;
109- DUT.i_wb_err := 1'b0;
11089 assert_eq(DUT.o_cmd_busy, 1'b0);
111- step();
90+ assert_eq(DUT.o_wb_addr, addr);
91+ step(); // cyc=1, stb=1, we=1; address echo arrives on rsp channel simultaneously
11292
113- // BUS REQUEST: manager asserts cyc=1, stb=1, we=1
93+ // BUS REQUEST: up to now, the manager has asserted cyc=1, stb=1, we=1
94+ // The manager now sets `stb = 0` (since the subordinate doesn't stall)
11495 DUT.i_cmd_stb := 1'b0;
115- assert_eq(DUT.o_wb_cyc, 1'b1);
116- assert_eq(DUT.o_wb_stb, 1'b1);
117- assert_eq(DUT.o_wb_we, 1'b1);
96+ assert_eq(DUT.o_wb_cyc, 1'b1);
97+ assert_eq(DUT.o_wb_stb, 1'b1);
98+ assert_eq(DUT.o_wb_we, 1'b1);
11899 assert_eq(DUT.o_cmd_busy, 1'b1);
119- // stall=0, so manager will drop `o_wb_stb` after this step
120100 step();
121101
122- // BUS WAIT: stb has dropped (request accepted), cyc still high
102+ // BUS WAIT: We now have `stb = 0` (the request has been accepted)
103+ // `cyc` is still 1 since we're still in the same session
123104 assert_eq(DUT.o_wb_cyc, 1'b1);
124105 assert_eq(DUT.o_wb_stb, 1'b0);
125106 // Subordinate acknowledges the write
126107 DUT.i_wb_ack := 1'b1;
127108 step();
128109
129110 // IDLE: cyc dropped, write acknowledged on response channel
130- assert_eq(DUT.o_wb_cyc, 1'b0);
111+ assert_eq(DUT.o_wb_cyc, 1'b0);
131112 assert_eq(DUT.o_cmd_busy, 1'b0);
132- assert_eq(DUT.o_rsp_stb, 1'b1);
133-
113+ assert_eq(DUT.o_rsp_stb, 1'b1);
134114 // RSP_WRITE_ACKNOWLEDGEMENT = { RSP_SUB_ACK(2'b01), 32'x0 }
135115 assert_eq(DUT.o_rsp_word, 32'x1 + 32'x0);
136116 DUT.i_wb_ack := 1'b0;
137117 step();
138118}
139119
140- // Reads a 32-bit word from the Wishbone bus at the current address.
141- // `rdata` is the value provided by the subordinate (driven on i_wb_data).
142- // Sends CMD_SUB_RD (i_cmd_word[33:32] = 2'b00).
143- // Assumes the subordinate does not stall (i_wb_stall = 0 throughout).
144- //
120+ // This protocol reads a 32-bit word from the Wishbone bus at `addr`,
121+ // where `rdata` is the value provided by the subordinate (driven on i_wb_data)
122+ // (this is why `rdata` is an input parameter).
123+ // Like the `write` protocol above, we issue two commands back to back,
124+ // first by setting the address via `CMD_SUB_ADDR`
125+ // then by performing a read (`CMD_SUB_RD`)//
145126// State progression:
146- // IDLE -> issue command -> step
147- // BUS REQUEST (cyc=1, stb=1, we=0): subordinate accepts immediately (stall=0) -> step
148- // BUS WAIT (cyc=1, stb=0): subordinate acknowledges with data (ack=1) -> step
149- // IDLE (cyc=0): { RSP_SUB_DATA(2'b00), rdata } on response channel
150- prot read<DUT: WBManager>(in rdata: u32) {
151- // IDLE: issue read command (lower 32 bits are ignored by the manager)
127+ // 1. IDLE: send CMD_SUB_ADDR, step -> addr latched, newaddr=1
128+ // 2. IDLE: send CMD_SUB_RD, step -> cyc=1, stb=1, we=0 (bus cycle starts)
129+ // 3. BUS REQUEST (cyc=1, stb=1, we=0): subordinate accepts (stall=0), step
130+ // 4. BUS WAIT (cyc=1, stb=0): subordinate acknowledges with data (ack=1), step
131+ // 5. IDLE (cyc=0): Send response
132+ prot read<DUT: WBManager>(in addr: u30, in rdata: u32) {
133+ // Set the bus address
152134 DUT.i_reset := 1'b0;
153135 DUT.i_cmd_stb := 1'b1;
154- DUT.i_cmd_word := 34'x0 ;
136+ DUT.i_cmd_word := 30'b10 + addr + 30'b0 ;
155137 DUT.i_wb_stall := 1'b0;
156138 DUT.i_wb_ack := 1'b0;
157139 DUT.i_wb_err := 1'b0;
158140 DUT.i_wb_data := rdata;
159141 assert_eq(DUT.o_cmd_busy, 1'b0);
160- step();
142+ step();
143+
144+ // Issue read command immediately
145+ // In `i_cmd_word`, we have `bits[33:32]=2'b00 (opcode for CMD_SUB_RD)`
146+ // and the lower 32 bits are ignored by the manager (i.e. all zeroes)
147+ DUT.i_cmd_stb := 1'b1;
148+ DUT.i_cmd_word := 34'x0;
149+ assert_eq(DUT.o_cmd_busy, 1'b0);
150+ assert_eq(DUT.o_wb_addr, addr);
151+ step();
161152
162- // BUS REQUEST: manager asserts cyc=1, stb=1, we=0
153+ // BUS REQUEST: manager DUT has asserted cyc=1, stb=1, we=0
163154 DUT.i_cmd_stb := 1'b0;
164155 assert_eq(DUT.o_wb_cyc, 1'b1);
165156 assert_eq(DUT.o_wb_stb, 1'b1);
166157 assert_eq(DUT.o_wb_we, 1'b0);
167158 assert_eq(DUT.o_cmd_busy, 1'b1);
168- // stall=0, so manager will drop stb after this step
159+ // We currently have stall=0, so the manager sets ` stb = 0` after this step
169160 step();
170161
171- // BUS WAIT: stb has dropped (request accepted), cyc still high
162+ // BUS WAIT: The manager sets ` stb = 0` (request accepted), cyc still high
172163 assert_eq(DUT.o_wb_cyc, 1'b1);
173164 assert_eq(DUT.o_wb_stb, 1'b0);
174165 // Subordinate acknowledges with read data
175166 DUT.i_wb_ack := 1'b1;
176167 DUT.i_wb_data := rdata;
177168 step();
178169
179- // IDLE: cyc dropped, read data on response channel
170+ // IDLE: `cyc` becomes 0 (to indicate the end of a session)
171+ // The read data is conveyed via the response
180172 assert_eq(DUT.o_wb_cyc, 1'b0);
181173 assert_eq(DUT.o_cmd_busy, 1'b0);
182174 assert_eq(DUT.o_rsp_stb, 1'b1);
183- // { RSP_SUB_DATA( 2'b00), rdata }
175+ // response format is { 2'b00 (opcode for RSP_SUB_DATA ), rdata }
184176 assert_eq(DUT.o_rsp_word, 32'x0 + rdata);
185177 DUT.i_wb_ack := 1'b0;
186178 step();
0 commit comments