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: