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: