hw/ip/usb_fs_nb_pe/rtl/usb_fs_nb_out_pe.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Copyright Luke Valenty (TinyFPGA project)
3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
4: // SPDX-License-Identifier: Apache-2.0
5:
6: // USB Full Speed Non-Buffered Protocol Engine for OUT/SETUP endpoints
7: //
8: // Decode OUT/SETUP requests from host and accept data unless buffers are full
9: // (SETUP is a special form of OUT and starts a transaction sequence)
10: //
11: // Based on usb_fs_out_pe.v from the TinyFPGA-Bootloader project but
12: // this version contains no packet buffers
13:
14: module usb_fs_nb_out_pe #(
15: parameter int unsigned NumOutEps = 1,
16: parameter int unsigned MaxOutPktSizeByte = 32,
17: parameter int unsigned PktW = $clog2(MaxOutPktSizeByte),
18: parameter int unsigned OutEpW = $clog2(NumOutEps)
19: ) (
20: input logic clk_48mhz_i,
21: input logic rst_ni,
22: input logic link_reset_i,
23: input logic [6:0] dev_addr_i,
24:
25: ////////////////////////
26: // endpoint interface //
27: ////////////////////////
28: output logic [3:0] out_ep_current_o, // Other signals address to this ep, this signal will be stable for several cycles
29: output logic out_ep_data_put_o, // put the data (put addr advances after)
30: output logic [PktW - 1:0] out_ep_put_addr_o, // Offset to put data (0..pktlen)
31: output logic [7:0] out_ep_data_o,
32: output logic out_ep_newpkt_o, // new packed, current was set
33: output logic out_ep_acked_o, // good termination, device has acked
34: output logic out_ep_rollback_o, // bad termination, discard data
35: output logic [NumOutEps-1:0] out_ep_setup_o,
36: input logic [NumOutEps-1:0] out_ep_full_i, // Cannot accept data
37: input logic [NumOutEps-1:0] out_ep_stall_i, // Stalled
38: input logic [NumOutEps-1:0] out_ep_iso_i, // Configure endpoint in isochronous mode
39:
40: input logic [NumOutEps-1:0] data_toggle_clear_i, // Clear the data toggles for an EP
41:
42: /////////////
43: // rx path //
44: /////////////
45:
46: // Strobed on reception of packet.
47: input logic rx_pkt_start_i,
48: input logic rx_pkt_end_i,
49: input logic rx_pkt_valid_i,
50:
51: // Most recent packet received.
52: input logic [3:0] rx_pid_i,
53: input logic [6:0] rx_addr_i,
54: input logic [3:0] rx_endp_i,
55:
56: // rx_data is pushed into endpoint controller.
57: input logic rx_data_put_i,
58: input logic [7:0] rx_data_i,
59:
60:
61: /////////////
62: // tx path //
63: /////////////
64:
65: // Strobe to send new packet.
66: output logic tx_pkt_start_o,
67: input logic tx_pkt_end_i,
68: output logic [3:0] tx_pid_o
69: );
70:
71: // suppress warnings
72: logic unused_1;
73: assign unused_1 = tx_pkt_end_i;
74:
75: ////////////////////////////////
76: // out transfer state machine //
77: ////////////////////////////////
78: import usb_consts_pkg::*;
79:
80: typedef enum logic [2:0] {
81: StIdle,
82: StRcvdOut,
83: StRcvdDataStart,
84: StRcvdDataEnd,
85: StRcvdIsoDataEnd
86: } state_out_e;
87:
88: state_out_e out_xfr_state;
89: state_out_e out_xfr_state_next;
90:
91: logic out_xfr_start;
92: logic new_pkt_end;
93: logic rollback_data;
94:
95: // set when the endpoint buffer is unable to receive the out transfer
96: logic nak_out_transfer;
97:
98: // data toggle state
99: logic [NumOutEps - 1:0] data_toggle_q, data_toggle_d;
100:
101: // Make widths work
102: logic [OutEpW - 1 : 0] out_ep_index;
103: assign out_ep_index = out_ep_current_o[0 +: OutEpW];
104:
105: // Decode the rx token
106: logic token_received, out_token_received, setup_token_received;
107: logic invalid_packet_received, data_packet_received, non_data_packet_received;
108: logic bad_data_toggle;
109:
110: // 1: If the current transfer is a SETUP, 0: OUT
111: logic current_xfer_setup_q;
112:
113: // More syntax so can compare with enum
114: usb_pid_type_e rx_pid_type;
115: usb_pid_e rx_pid;
116: assign rx_pid_type = usb_pid_type_e'(rx_pid_i[1:0]);
117: assign rx_pid = usb_pid_e'(rx_pid_i);
118:
119: assign token_received =
120: rx_pkt_end_i &&
121: rx_pkt_valid_i &&
122: rx_pid_type == UsbPidTypeToken &&
123: rx_addr_i == dev_addr_i &&
124: rx_endp_i < NumOutEps;
125:
126: assign out_token_received =
127: token_received &&
128: rx_pid == UsbPidOut;
129:
130: assign setup_token_received =
131: token_received &&
132: rx_pid == UsbPidSetup;
133:
134: assign invalid_packet_received =
135: rx_pkt_end_i &&
136: !rx_pkt_valid_i;
137:
138: assign data_packet_received =
139: rx_pkt_end_i &&
140: rx_pkt_valid_i &&
141: ((rx_pid == UsbPidData0) || (rx_pid == UsbPidData1));
142:
143:
144: assign non_data_packet_received =
145: rx_pkt_end_i &&
146: rx_pkt_valid_i &&
147: !((rx_pid == UsbPidData0) || (rx_pid == UsbPidData1));
148:
149: assign bad_data_toggle =
150: data_packet_received &&
151: rx_pid_i[3] != data_toggle_q[rx_endp_i[0 +: OutEpW]]; // lint: rx_endp_i range was checked
152:
153:
154: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
155: if (!rst_ni) begin
156: out_ep_setup_o <= '0;
157: end else begin
158: if (setup_token_received) begin
159: out_ep_setup_o[rx_endp_i[0 +: OutEpW]] <= 1; // lint: rx_endp_i range was checked
160: end else if (out_token_received) begin
161: out_ep_setup_o[rx_endp_i[0 +: OutEpW]] <= 0; // lint: rx_endp_i range was checked
162: end
163: end
164: end
165:
166: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
167: if (!rst_ni) begin
168: out_ep_data_o <= 0;
169: end else begin
170: if (rx_data_put_i) begin
171: out_ep_data_o <= rx_data_i;
172: end
173: end
174: end
175:
176: ////////////////////////////////
177: // out transfer state machine //
178: ////////////////////////////////
179:
180: always_comb begin
181: out_ep_acked_o = 1'b0;
182: out_xfr_start = 1'b0;
183: out_xfr_state_next = out_xfr_state;
184: tx_pkt_start_o = 1'b0;
185: tx_pid_o = 4'b0000;
186: new_pkt_end = 1'b0;
187: rollback_data = 1'b0;
188:
189: unique case (out_xfr_state)
190: StIdle: begin
191: if (out_token_received || setup_token_received) begin
192: out_xfr_state_next = StRcvdOut;
193: out_xfr_start = 1'b1;
194: end else begin
195: out_xfr_state_next = StIdle;
196: end
197: end
198:
199: StRcvdOut: begin
200: if (rx_pkt_start_i) begin
201: out_xfr_state_next = StRcvdDataStart;
202: end else begin
203: out_xfr_state_next = StRcvdOut;
204: end
205: end
206:
207: StRcvdDataStart: begin
208: if (out_ep_iso_i[out_ep_index] && data_packet_received) begin
209: // ISO endpoint: Don't send a handshake, ignore toggle
210: out_xfr_state_next = StRcvdIsoDataEnd;
211: end else if (bad_data_toggle) begin
212: out_xfr_state_next = StIdle;
213: rollback_data = 1'b1;
214: tx_pkt_start_o = 1'b1;
215: tx_pid_o = {UsbPidAck}; // ACK by spec because this is most likely previous ACK was lost
216: end else if (invalid_packet_received || non_data_packet_received) begin
217: // in these cases eg bad CRC, send no response (not a NAK)
218: out_xfr_state_next = StIdle;
219: rollback_data = 1'b1;
220: end else if (data_packet_received) begin
221: out_xfr_state_next = StRcvdDataEnd;
222: end else begin
223: out_xfr_state_next = StRcvdDataStart;
224: end
225: end
226:
227: StRcvdDataEnd: begin
228: out_xfr_state_next = StIdle;
229: tx_pkt_start_o = 1'b1;
230:
231: if (out_ep_stall_i[out_ep_index] && !current_xfer_setup_q) begin // lint: out_ep_index range was checked
232: // We only send STALL for OUT transfers, not for SETUP transfers
233: tx_pid_o = {UsbPidStall}; // STALL
234: end else if (nak_out_transfer) begin
235: tx_pid_o = {UsbPidNak}; // NAK -- the endpoint could not accept the data at the moment
236: rollback_data = 1'b1;
237: end else begin
238: tx_pid_o = {UsbPidAck}; // ACK
239: new_pkt_end = 1'b1;
240: out_ep_acked_o = 1'b1;
241: end
242: end
243:
244: StRcvdIsoDataEnd: begin
245: out_xfr_state_next = StIdle;
246:
247: if (out_ep_stall_i[out_ep_index] && !current_xfer_setup_q) begin
248: // Send a STALL (something bad happened and the host needs to resolve it)
249: tx_pkt_start_o = 1'b1;
250: tx_pid_o = {UsbPidStall}; // STALL
251: end else if (nak_out_transfer) begin
252: // We got a valid packet, but can't store it (error that the software must resolve)
253: rollback_data = 1'b1;
254: end else begin
255: // We got a valid packet, but we don't send an ACK on the bus
256: new_pkt_end = 1'b1;
257: out_ep_acked_o = 1'b1;
258: end
259:
260: end
261:
262: default: out_xfr_state_next = StIdle;
263: endcase
264: end
265:
266: // could flop this if needed
267: assign out_ep_rollback_o = rollback_data;
268:
269: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
270: if (!rst_ni) begin
271: out_xfr_state <= StIdle;
272: end else begin
273: out_xfr_state <= link_reset_i ? StIdle : out_xfr_state_next;
274: end
275: end
276:
277: always_comb begin : proc_data_toggle_d
278: data_toggle_d = data_toggle_q;
279:
280: if (setup_token_received) begin
281: data_toggle_d[rx_endp_i[0 +: OutEpW]] = 1'b0; // lint: rx_endp_i range was checked
282: end else if (new_pkt_end) begin
283: data_toggle_d[out_ep_index] = ~data_toggle_q[out_ep_index]; // lint: range was checked
284: end
285:
286: data_toggle_d = data_toggle_d & ~data_toggle_clear_i;
287: end
288:
289: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
290: if (!rst_ni) begin
291: data_toggle_q <= '0; // All endpoints
292: end else if (link_reset_i) begin
293: data_toggle_q <= '0; // All endpoints
294: end else begin
295: data_toggle_q <= data_toggle_d;
296: end
297: end
298:
299: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
300: if (!rst_ni) begin
301: out_ep_newpkt_o <= 1'b0;
302: out_ep_current_o <= '0;
303: current_xfer_setup_q <= 1'b0;
304: end else begin
305: if (out_xfr_start) begin
306: out_ep_newpkt_o <= 1'b1;
307: out_ep_current_o <= rx_endp_i;
308: current_xfer_setup_q <= setup_token_received;
309: end else begin
310: out_ep_newpkt_o <= 1'b0;
311: end
312: end
313: end
314:
315: // put data strobe follows the rx strobe (which will latch the data)
316: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
317: if (!rst_ni) begin
318: out_ep_data_put_o <= 1'b0;
319: end else begin
320: out_ep_data_put_o <= ((out_xfr_state == StRcvdDataStart) && rx_data_put_i);
321: end
322: end
323:
324: // nack an OUT if any data comes in with the endpoint full
325: // Note that if there is a full size packet buffer this will only be all or nothing
326: // but in the case there was a FIFO with less than a max packet size free you
327: // could get lucky and the packet received be small and fit with no need to NAK
328: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
329: if (!rst_ni) begin
330: nak_out_transfer <= 1'b0;
331: end else begin
332: if ((out_xfr_state == StIdle) || (out_xfr_state == StRcvdOut)) begin
333: nak_out_transfer <= 1'b0;
334: end else if (out_ep_data_put_o && out_ep_full_i[out_ep_index]) begin // lint: range checked
335: nak_out_transfer <= 1'b1;
336: end
337: end
338: end
339:
340: // address increment whenever there is a data put unless
341: // -- already going to NAK transaction and replay things
342: // -- the address is at max packet size
343: // NOTE if more than max packet size received then data is lost
344: logic increment_addr;
345: assign increment_addr = !nak_out_transfer && (~&out_ep_put_addr_o) && out_ep_data_put_o;
346:
347: always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
348: if (!rst_ni) begin
349: out_ep_put_addr_o <= '0;
350: end else begin
351: if (out_xfr_state == StRcvdOut) begin
352: out_ep_put_addr_o <= '0;
353: end else if ((out_xfr_state == StRcvdDataStart) && increment_addr) begin
354: out_ep_put_addr_o <= out_ep_put_addr_o + 1;
355: end
356: end
357: end
358:
359: endmodule
360: