../src/lowrisc_ip_usb_fs_nb_pe_0.1/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; // transition state
74: localparam logic [2:0] DJ = 3'b010; // J - idle line state
75: // localparam logic [2:0] DK = 3'b001; // K - inverse of J
76: localparam logic [2:0] SE0 = 3'b000; // single-ended 0 - end of packet or detached
77: // localparam logic [2:0] SE1 = 3'b011; // single-ended 1 - illegal
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]} :
197: line_history_q;
198:
199: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_reg_pkt_line
200: if (!rst_ni) begin
201: packet_valid_q <= 0;
202: line_history_q <= 12'b101010101010; // all K
203: end else begin
204: if (link_reset_i) begin
205: packet_valid_q <= 0;
206: line_history_q <= 12'b101010101010; // all K
207: end else begin
208: packet_valid_q <= packet_valid_d;
209: line_history_q <= line_history_d;
210: end
211: end
212: end
213:
214:
215: /////////////////
216: // NRZI decode //
217: /////////////////
218:
219: // in order to ensure there are enough bit transitions for a receiver to recover
220: // the clock usb uses NRZI encoding.
221:
222: // https://en.wikipedia.org/wiki/Non-return-to-zero
223:
224: logic dvalid_raw;
225: logic din;
226:
227: always_comb begin
228: unique case (line_history_q[3:0])
229: 4'b0101 : din = 1;
230: 4'b0110 : din = 0;
231: 4'b1001 : din = 0;
232: 4'b1010 : din = 1;
233: default : din = 0;
234: endcase
235:
236: if (packet_valid_q && line_state_valid) begin
237: unique case (line_history_q[3:0])
238: 4'b0101 : dvalid_raw = 1;
239: 4'b0110 : dvalid_raw = 1;
240: 4'b1001 : dvalid_raw = 1;
241: 4'b1010 : dvalid_raw = 1;
242: default : dvalid_raw = 0;
243: endcase
244: end else begin
245: dvalid_raw = 0;
246: end
247: end
248:
249: //////////////////////////////////////////////////////
250: // Undo bit stuffing and detect bit stuffing errors //
251: //////////////////////////////////////////////////////
252:
253: always_comb begin : proc_bitstuff_history_d
254: if (packet_end) begin
255: bitstuff_history_d = '0;
256: end else if (dvalid_raw) begin
257: bitstuff_history_d = {bitstuff_history_q[5:0], din};
258: end else begin
259: bitstuff_history_d = bitstuff_history_q;
260: end
261: end
262:
263: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bitstuff_history_q
264: if (!rst_ni) begin
265: bitstuff_history_q <= 0;
266: end else begin
267: if (link_reset_i) begin
268: bitstuff_history_q <= 0;
269: end else begin
270: bitstuff_history_q <= bitstuff_history_d;
271: end
272: end
273: end
274:
275: logic dvalid;
276: assign dvalid = dvalid_raw && !(bitstuff_history_q[5:0] == 6'b111111);
277:
278: // 7 consecutive ones should not be seen on the bus
279: // USB spec, 7.1.9.1: "If the receiver sees seven
280: // consecutive ones anywhere in the packet, then a bit stuffing error
281: // has occurred and the packet should be ignored."
282: assign bitstuff_error = bitstuff_history_q == 7'b1111111;
283:
284: // remember the bitstuff errors
285: always_comb begin : proc_bistuff_error_d
286: bitstuff_error_d = bitstuff_error_q;
287: if (packet_start) begin
288: bitstuff_error_d = 0;
289: end else if (bitstuff_error && dvalid_raw) begin
290: bitstuff_error_d = 1;
291: end
292: end
293:
294: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_bitstuff_error_q
295: if (!rst_ni) begin
296: bitstuff_error_q <= 0;
297: end else begin
298: bitstuff_error_q <= bitstuff_error_d;
299: end
300: end
301:
302: assign bitstuff_error_o = bitstuff_error_q && packet_end;
303:
304:
305: ////////////////////////
306: // save and check pid //
307: ////////////////////////
308:
309: // shift in the entire 8-bit pid with an additional 9th bit used as a sentinal.
310:
311: logic [8:0] full_pid_q, full_pid_d;
312: logic pid_valid, pid_complete;
313:
314: assign pid_valid = full_pid_q[4:1] == ~full_pid_q[8:5];
315: assign pid_complete = full_pid_q[0];
316:
317: always_comb begin : proc_full_pid_d
318: if (dvalid && !pid_complete) begin
319: full_pid_d = {din, full_pid_q[8:1]};
320: end else if (packet_start) begin
321: full_pid_d = 9'b100000000;
322: end else begin
323: full_pid_d = full_pid_q;
324: end
325: end
326:
327: ////////////////
328: // check crc5 //
329: ////////////////
330: logic [4:0] crc5_q, crc5_d;
331: logic crc5_valid, crc5_invert;
332: assign crc5_valid = crc5_q == 5'b01100;
333: assign crc5_invert = din ^ crc5_q[4];
334:
335: always_comb begin
336: crc5_d = crc5_q; // default value
337:
338: if (packet_start) begin
339: crc5_d = 5'b11111;
340: end
341:
342: if (dvalid && pid_complete) begin
343: crc5_d = {crc5_q[3:0], 1'b0} ^ ({5{crc5_invert}} & 5'b00101);
344: end
345: end
346:
347:
348: /////////////////
349: // check crc16 //
350: /////////////////
351: logic [15:0] crc16_q, crc16_d;
352: logic crc16_valid, crc16_invert;
353:
354: assign crc16_valid = crc16_q == 16'b1000000000001101;
355: assign crc16_invert = din ^ crc16_q[15];
356:
357: always_comb begin
358: crc16_d = crc16_q; // default value
359:
360: if (packet_start) begin
361: crc16_d = 16'b1111111111111111;
362: end
363:
364: if (dvalid && pid_complete) begin
365: crc16_d = {crc16_q[14:0], 1'b0} ^ ({16{crc16_invert}} & 16'b1000000000000101);
366: end
367: end
368:
369:
370: ////////////////////////////
371: // output control signals //
372: ////////////////////////////
373: logic pkt_is_token, pkt_is_data, pkt_is_handshake;
374: assign pkt_is_token = full_pid_q[2:1] == 2'b01;
375: assign pkt_is_data = full_pid_q[2:1] == 2'b11;
376: assign pkt_is_handshake = full_pid_q[2:1] == 2'b10;
377:
378:
379: // TODO: need to check for data packet babble
380: assign valid_packet_o = pid_valid && !bitstuff_error_q &&
381: ((pkt_is_handshake) ||
382: (pkt_is_data && crc16_valid) ||
383: (pkt_is_token && crc5_valid)
384: );
385:
386: // Detect CRC errors
387: assign crc_error_o = ((pkt_is_data && !crc16_valid) ||
388: (pkt_is_token && !crc5_valid)) && packet_end;
389:
390: // Detect PID errors
391: assign pid_error_o = !pid_valid && packet_end;
392:
393: logic [11:0] token_payload_q, token_payload_d;
394: logic token_payload_done;
395:
396: assign token_payload_done = token_payload_q[0];
397:
398: logic [6:0] addr_q, addr_d;
399: logic [3:0] endp_q, endp_d;
400: logic [10:0] frame_num_q, frame_num_d;
401:
402: always_comb begin
403: token_payload_d = token_payload_q; // default
404:
405: if (packet_start) begin
406: token_payload_d = 12'b100000000000;
407: end
408:
409: if (dvalid && pid_complete && pkt_is_token && !token_payload_done) begin
410: token_payload_d = {din, token_payload_q[11:1]};
411: end
412: end
413:
414: always_comb begin
415: // defaults
416: addr_d = addr_q;
417: endp_d = endp_q;
418: frame_num_d = frame_num_q;
419:
420: if (token_payload_done && pkt_is_token) begin
421: addr_d = token_payload_q[7:1];
422: endp_d = token_payload_q[11:8];
423: frame_num_d = token_payload_q[11:1];
424: end
425: end
426:
427: assign addr_o = addr_q;
428: assign endp_o = endp_q;
429: assign frame_num_o = frame_num_q;
430: assign pid_o = full_pid_q[4:1];
431:
432: assign pkt_start_o = packet_start;
433: assign pkt_end_o = packet_end;
434:
435:
436: /////////////////////////////////
437: // deserialize and output data //
438: /////////////////////////////////
439: //assign rx_data_put = dvalid && pid_complete && pkt_is_data;
440: logic [8:0] rx_data_buffer_q, rx_data_buffer_d;
441: logic rx_data_buffer_full;
442:
443: assign rx_data_buffer_full = rx_data_buffer_q[0];
444: assign rx_data_put_o = rx_data_buffer_full;
445: assign rx_data_o = rx_data_buffer_q[8:1];
446:
447: always_comb begin
448: rx_data_buffer_d = rx_data_buffer_q; // default
449:
450: if (packet_start || rx_data_buffer_full) begin
451: rx_data_buffer_d = 9'b100000000;
452: end
453:
454: if (dvalid && pid_complete && pkt_is_data) begin
455: rx_data_buffer_d = {din, rx_data_buffer_q[8:1]};
456: end
457: end
458:
459:
460: ///////////////
461: // Registers //
462: ///////////////
463: always_ff @(posedge clk_i or negedge rst_ni) begin : proc_gp_regs
464: if (!rst_ni) begin
465: full_pid_q <= 0;
466: crc16_q <= 0;
467: crc5_q <= 0;
468: token_payload_q <= 0;
469: addr_q <= 0;
470: endp_q <= 0;
471: frame_num_q <= 0;
472: rx_data_buffer_q <= 0;
473: end else begin
474: if (link_reset_i) begin
475: full_pid_q <= 0;
476: crc16_q <= 0;
477: crc5_q <= 0;
478: token_payload_q <= 0;
479: addr_q <= 0;
480: endp_q <= 0;
481: frame_num_q <= 0;
482: rx_data_buffer_q <= 0;
483: end else begin
484: full_pid_q <= full_pid_d;
485: crc16_q <= crc16_d;
486: crc5_q <= crc5_d;
487: token_payload_q <= token_payload_d;
488: addr_q <= addr_d;
489: endp_q <= endp_d;
490: frame_num_q <= frame_num_d;
491: rx_data_buffer_q <= rx_data_buffer_d;
492: end
493: end
494: end
495:
496: endmodule // usb_fs_rx
497: