hw/ip/usb_fs_nb_pe/rtl/usb_fs_rx.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Copyright ETH Zurich.
3: // Copyright Luke Valenty (TinyFPGA project, https://github.com/tinyfpga/TinyFPGA-Bootloader).
4: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
5: // SPDX-License-Identifier: Apache-2.0
6:
7: module usb_fs_rx (
8: // A 48MHz clock is required to recover the clock from the incoming data.
9: input logic clk_i,
10: input logic rst_ni,
11: input logic link_reset_i,
12:
13: // EOP configuration
14: input logic cfg_eop_single_bit_i,
15:
16: // USB data+ and data- lines (synchronous)
17: input logic usb_d_i,
18: input logic usb_se0_i,
19:
20: // Transmit enable disables the receier
21: input logic tx_en_i,
22:
23: // pulse on every bit transition.
24: output logic bit_strobe_o,
25:
26: // Pulse on beginning of new packet.
27: output logic pkt_start_o,
28:
29: // Pulse on end of current packet.
30: output logic pkt_end_o,
31:
32: // Most recent packet decoded.
33: output logic [3:0] pid_o,
34: output logic [6:0] addr_o,
35: output logic [3:0] endp_o,
36: output logic [10:0] frame_num_o,
37:
38: // Pulse on valid data on rx_data.
39: output logic rx_data_put_o,
40: output logic [7:0] rx_data_o,
41:
42: // Most recent packet passes PID and CRC checks
43: output logic valid_packet_o,
44:
45: // Error detection
46: output logic crc_error_o,
47: output logic pid_error_o,
48: output logic bitstuff_error_o
49: );
50:
51: logic [6:0] bitstuff_history_q, bitstuff_history_d;
52: logic bitstuff_error;
53: logic bitstuff_error_q, bitstuff_error_d;
54:
55: //////////////////////
56: // usb receive path //
57: //////////////////////
58:
59: ///////////////////////////////////////
60: // line state recovery state machine //
61: ///////////////////////////////////////
62:
63: // The receive path doesn't currently use a differential reciever. because of
64: // this there is a chance that one of the differential pairs will appear to have
65: // changed to the new state while the other is still in the old state. the
66: // following state machine detects transitions and waits an extra sampling clock
67: // before decoding the state on the differential pair. this transition period
68: // will only ever last for one clock as long as there is no noise on the line.
69: // if there is enough noise on the line then the data may be corrupted and the
70: // packet will fail the data integrity checks.
71:
72: logic [2:0] line_state_q, line_state_d;
73: localparam logic [2:0] DT = 3'b100;
74: localparam logic [2:0] DJ = 3'b010;
75: localparam logic [2:0] DK = 3'b001;
76: localparam logic [2:0] SE0 = 3'b000;
77: localparam logic [2:0] SE1 = 3'b011;
78:
79: // Mute the input if we're transmitting
80: logic [1:0] dpair;
81: always_comb begin : proc_dpair_mute
82: if (tx_en_i) begin
83: dpair = DJ[1:0]; // J
84: end else begin
85: dpair = (usb_se0_i) ? 2'b00 : {usb_d_i, ~usb_d_i};
86: end
87: end
88:
89: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_line_state_q
90: if (!rst_ni) begin
91: line_state_q <= SE0;
92: end else begin
93: if (link_reset_i) begin
94: line_state_q <= SE0;
95: end else begin
96: line_state_q <= line_state_d;
97: end
98: end
99: end
100:
101: always_comb begin : proc_line_state_d
102: // Default assignment
103: line_state_d = line_state_q;
104:
105: if (line_state_q == DT) begin
106: // if we are in a transition state, then we can sample the pair and
107: // move to the next corresponding line state
108: line_state_d = {1'b0, dpair};
109:
110: end else begin
111: // if we are in a valid line state and the value of the pair changes,
112: // then we need to move to the transition state
113: if (dpair != line_state_q[1:0]) begin
114: line_state_d = DT;
115: end
116: end
117: end
118:
119: ////////////////////
120: // clock recovery //
121: ////////////////////
122:
123: // the DT state from the line state recovery state machine is used to align to
124: // transmit clock. the line state is sampled in the middle of the bit time.
125:
126: // example of signal relationships
127: // -------------------------------
128: // line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ
129: // line_state_valid ________----____________----____________----________----____
130: // bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2
131:
132:
133: logic [1:0] bit_phase_q, bit_phase_d;
134: logic line_state_valid;
135:
136: assign line_state_valid = (bit_phase_q == 2'd1);
137: assign bit_strobe_o = (bit_phase_q == 2'd2);
138:
139: // keep track of phase within each bit
140: assign bit_phase_d = (line_state_q == DT) ? 0 : bit_phase_q + 1;
141:
142: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bit_phase_q
143: if (!rst_ni) begin
144: bit_phase_q <= 0;
145: end else begin
146: if (link_reset_i) begin
147: bit_phase_q <= 0;
148: end else begin
149: bit_phase_q <= bit_phase_d;
150: end
151: end
152: end
153:
154:
155: //////////////////////
156: // packet detection //
157: //////////////////////
158:
159: // usb uses a sync to denote the beginning of a packet and two single-ended-0 to
160: // denote the end of a packet. this state machine recognizes the beginning and
161: // end of packets for subsequent layers to process.
162:
163: logic [11:0] line_history_q, line_history_d;
164: logic packet_valid_q, packet_valid_d;
165: logic see_eop, packet_start, packet_end;
166:
167: assign packet_start = packet_valid_d & ~packet_valid_q;
168: assign packet_end = ~packet_valid_d & packet_valid_q;
169:
170: // EOP detection is configurable for 1/2 bit periods of SE0.
171: // The standard (Table 7-7) mandates min = 82 ns = 1 bit period.
172: // We also trigger an EOP on seeing a bitstuff error.
173: assign see_eop = (cfg_eop_single_bit_i && line_history_q[1:0] == 2'b00)
174: || (line_history_q[3:0] == 4'b0000) || bitstuff_error_q;
175:
176: always_comb begin : proc_packet_valid_d
177: if (line_state_valid) begin
178: // check for packet start: KJKJKK, we use the last 6 bits
179: if (!packet_valid_q && line_history_q[11:0] == 12'b011001100101) begin
180: packet_valid_d = 1;
181: end
182:
183: // check for packet end: SE0 SE0
184: else if (packet_valid_q && see_eop) begin
185: packet_valid_d = 0;
186:
187: end else begin
188: packet_valid_d = packet_valid_q;
189: end
190: end else begin
191: packet_valid_d = packet_valid_q;
192: end
193: end
194:
195: // keep a history of the last two states on the line
196: assign line_history_d = line_state_valid ? {line_history_q[9:0], line_state_q[1:0]} : line_history_q;
197:
198: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_reg_pkt_line
199: if (!rst_ni) begin
200: packet_valid_q <= 0;
201: line_history_q <= 12'b101010101010; // all K
202: end else begin
203: if (link_reset_i) begin
204: packet_valid_q <= 0;
205: line_history_q <= 12'b101010101010; // all K
206: end else begin
207: packet_valid_q <= packet_valid_d;
208: line_history_q <= line_history_d;
209: end
210: end
211: end
212:
213:
214: /////////////////
215: // NRZI decode //
216: /////////////////
217:
218: // in order to ensure there are enough bit transitions for a receiver to recover
219: // the clock usb uses NRZI encoding.
220:
221: // https://en.wikipedia.org/wiki/Non-return-to-zero
222:
223: logic dvalid_raw;
224: logic din;
225:
226: always_comb begin
227: unique case (line_history_q[3:0])
228: 4'b0101 : din = 1;
229: 4'b0110 : din = 0;
230: 4'b1001 : din = 0;
231: 4'b1010 : din = 1;
232: default : din = 0;
233: endcase
234:
235: if (packet_valid_q && line_state_valid) begin
236: unique case (line_history_q[3:0])
237: 4'b0101 : dvalid_raw = 1;
238: 4'b0110 : dvalid_raw = 1;
239: 4'b1001 : dvalid_raw = 1;
240: 4'b1010 : dvalid_raw = 1;
241: default : dvalid_raw = 0;
242: endcase
243: end else begin
244: dvalid_raw = 0;
245: end
246: end
247:
248: //////////////////////////////////////////////////////
249: // Undo bit stuffing and detect bit stuffing errors //
250: //////////////////////////////////////////////////////
251:
252: always_comb begin : proc_bitstuff_history_d
253: if (packet_end) begin
254: bitstuff_history_d = '0;
255: end else if (dvalid_raw) begin
256: bitstuff_history_d = {bitstuff_history_q[5:0], din};
257: end else begin
258: bitstuff_history_d = bitstuff_history_q;
259: end
260: end
261:
262: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bitstuff_history_q
263: if (!rst_ni) begin
264: bitstuff_history_q <= 0;
265: end else begin
266: if (link_reset_i) begin
267: bitstuff_history_q <= 0;
268: end else begin
269: bitstuff_history_q <= bitstuff_history_d;
270: end
271: end
272: end
273:
274: logic dvalid;
275: assign dvalid = dvalid_raw && !(bitstuff_history_q[5:0] == 6'b111111);
276:
277: // 7 consecutive ones should not be seen on the bus
278: // USB spec, 7.1.9.1: "If the receiver sees seven
279: // consecutive ones anywhere in the packet, then a bit stuffing error
280: // has occurred and the packet should be ignored."
281: assign bitstuff_error = bitstuff_history_q == 7'b1111111;
282:
283: // remember the bitstuff errors
284: always_comb begin : proc_bistuff_error_d
285: bitstuff_error_d = bitstuff_error_q;
286: if (packet_start) begin
287: bitstuff_error_d = 0;
288: end else if (bitstuff_error && dvalid_raw) begin
289: bitstuff_error_d = 1;
290: end
291: end
292:
293: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bitstuff_error_q
294: if (!rst_ni) begin
295: bitstuff_error_q <= 0;
296: end else begin
297: bitstuff_error_q <= bitstuff_error_d;
298: end
299: end
300:
301: assign bitstuff_error_o = bitstuff_error_q && packet_end;
302:
303:
304: ////////////////////////
305: // save and check pid //
306: ////////////////////////
307:
308: // shift in the entire 8-bit pid with an additional 9th bit used as a sentinal.
309:
310: logic [8:0] full_pid_q, full_pid_d;
311: logic pid_valid, pid_complete;
312:
313: assign pid_valid = full_pid_q[4:1] == ~full_pid_q[8:5];
314: assign pid_complete = full_pid_q[0];
315:
316: always_comb begin : proc_full_pid_d
317: if (dvalid && !pid_complete) begin
318: full_pid_d = {din, full_pid_q[8:1]};
319: end else if (packet_start) begin
320: full_pid_d = 9'b100000000;
321: end else begin
322: full_pid_d = full_pid_q;
323: end
324: end
325:
326: ////////////////
327: // check crc5 //
328: ////////////////
329: logic [4:0] crc5_q, crc5_d;
330: logic crc5_valid, crc5_invert;
331: assign crc5_valid = crc5_q == 5'b01100;
332: assign crc5_invert = din ^ crc5_q[4];
333:
334: always_comb begin
335: crc5_d = crc5_q; // default value
336:
337: if (packet_start) begin
338: crc5_d = 5'b11111;
339: end
340:
341: if (dvalid && pid_complete) begin
342: crc5_d = {crc5_q[3:0], 1'b0} ^ ({5{crc5_invert}} & 5'b00101);
343: end
344: end
345:
346:
347: /////////////////
348: // check crc16 //
349: /////////////////
350: logic [15:0] crc16_q, crc16_d;
351: logic crc16_valid, crc16_invert;
352:
353: assign crc16_valid = crc16_q == 16'b1000000000001101;
354: assign crc16_invert = din ^ crc16_q[15];
355:
356: always_comb begin
357: crc16_d = crc16_q; // default value
358:
359: if (packet_start) begin
360: crc16_d = 16'b1111111111111111;
361: end
362:
363: if (dvalid && pid_complete) begin
364: crc16_d = {crc16_q[14:0], 1'b0} ^ ({16{crc16_invert}} & 16'b1000000000000101);
365: end
366: end
367:
368:
369: ////////////////////////////
370: // output control signals //
371: ////////////////////////////
372: logic pkt_is_token, pkt_is_data, pkt_is_handshake;
373: assign pkt_is_token = full_pid_q[2:1] == 2'b01;
374: assign pkt_is_data = full_pid_q[2:1] == 2'b11;
375: assign pkt_is_handshake = full_pid_q[2:1] == 2'b10;
376:
377:
378: // TODO: need to check for data packet babble
379: assign valid_packet_o = pid_valid && !bitstuff_error_q &&
380: ((pkt_is_handshake) ||
381: (pkt_is_data && crc16_valid) ||
382: (pkt_is_token && crc5_valid)
383: );
384:
385: // Detect CRC errors
386: assign crc_error_o = ((pkt_is_data && !crc16_valid) ||
387: (pkt_is_token && !crc5_valid)) && packet_end;
388:
389: // Detect PID errors
390: assign pid_error_o = !pid_valid && packet_end;
391:
392: logic [11:0] token_payload_q, token_payload_d;
393: logic token_payload_done;
394:
395: assign token_payload_done = token_payload_q[0];
396:
397: logic [6:0] addr_q, addr_d;
398: logic [3:0] endp_q, endp_d;
399: logic [10:0] frame_num_q, frame_num_d;
400:
401: always_comb begin
402: token_payload_d = token_payload_q; // default
403:
404: if (packet_start) begin
405: token_payload_d = 12'b100000000000;
406: end
407:
408: if (dvalid && pid_complete && pkt_is_token && !token_payload_done) begin
409: token_payload_d = {din, token_payload_q[11:1]};
410: end
411: end
412:
413: always_comb begin
414: // defaults
415: addr_d = addr_q;
416: endp_d = endp_q;
417: frame_num_d = frame_num_q;
418:
419: if (token_payload_done && pkt_is_token) begin
420: addr_d = token_payload_q[7:1];
421: endp_d = token_payload_q[11:8];
422: frame_num_d = token_payload_q[11:1];
423: end
424: end
425:
426: assign addr_o = addr_q;
427: assign endp_o = endp_q;
428: assign frame_num_o = frame_num_q;
429: assign pid_o = full_pid_q[4:1];
430:
431: assign pkt_start_o = packet_start;
432: assign pkt_end_o = packet_end;
433:
434:
435: /////////////////////////////////
436: // deserialize and output data //
437: /////////////////////////////////
438: //assign rx_data_put = dvalid && pid_complete && pkt_is_data;
439: logic [8:0] rx_data_buffer_q, rx_data_buffer_d;
440: logic rx_data_buffer_full;
441:
442: assign rx_data_buffer_full = rx_data_buffer_q[0];
443: assign rx_data_put_o = rx_data_buffer_full;
444: assign rx_data_o = rx_data_buffer_q[8:1];
445:
446: always_comb begin
447: rx_data_buffer_d = rx_data_buffer_q; // default
448:
449: if (packet_start || rx_data_buffer_full) begin
450: rx_data_buffer_d = 9'b100000000;
451: end
452:
453: if (dvalid && pid_complete && pkt_is_data) begin
454: rx_data_buffer_d = {din, rx_data_buffer_q[8:1]};
455: end
456: end
457:
458:
459: ///////////////
460: // Registers //
461: ///////////////
462: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_gp_regs
463: if (!rst_ni) begin
464: full_pid_q <= 0;
465: crc16_q <= 0;
466: crc5_q <= 0;
467: token_payload_q <= 0;
468: addr_q <= 0;
469: endp_q <= 0;
470: frame_num_q <= 0;
471: rx_data_buffer_q <= 0;
472: end else begin
473: if (link_reset_i) begin
474: full_pid_q <= 0;
475: crc16_q <= 0;
476: crc5_q <= 0;
477: token_payload_q <= 0;
478: addr_q <= 0;
479: endp_q <= 0;
480: frame_num_q <= 0;
481: rx_data_buffer_q <= 0;
482: end else begin
483: full_pid_q <= full_pid_d;
484: crc16_q <= crc16_d;
485: crc5_q <= crc5_d;
486: token_payload_q <= token_payload_d;
487: addr_q <= addr_d;
488: endp_q <= endp_d;
489: frame_num_q <= frame_num_d;
490: rx_data_buffer_q <= rx_data_buffer_d;
491: end
492: end
493: end
494:
495: endmodule // usb_fs_rx
496: