../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: