hw/ip/usbdev/rtl/usbdev_usbif.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // USB Full-Speed Device Interface core internals
   6: //
   7: //
   8: 
   9: // This module runs on the 48MHz USB clock
  10: module usbdev_usbif  #(
  11:   parameter int NEndpoints = 12,
  12:   parameter int AVFifoWidth = 4,
  13:   parameter int RXFifoWidth = 4,
  14:   parameter int MaxPktSizeByte = 64,
  15:   parameter int NBuf = 4,
  16:   parameter int SramAw = 4,
  17:   localparam int NBufWidth = $clog2(NBuf), // derived parameter
  18:   localparam int PktW = $clog2(MaxPktSizeByte) // derived parameter
  19: ) (
  20:   input  logic                     clk_48mhz_i, // 48MHz USB clock
  21:   input  logic                     rst_ni,
  22: 
  23:   // Pins (synchronous)
  24:   input  logic                     usb_d_i,
  25:   input  logic                     usb_se0_i,
  26: 
  27:   output logic                     usb_d_o,
  28:   output logic                     usb_se0_o,
  29:   output logic                     usb_oe_o,
  30: 
  31:   output logic                     usb_pullup_en_o,
  32:   input  logic                     usb_sense_i,
  33: 
  34:   // receive (OUT or SETUP) side
  35:   input  logic [NEndpoints-1:0]    rx_setup_i,
  36:   input  logic [NEndpoints-1:0]    rx_out_i,
  37:   input  logic [NEndpoints-1:0]    rx_stall_i,
  38:   input  logic                     av_rvalid_i,
  39:   output logic                     av_rready_o,
  40:   input  logic [AVFifoWidth - 1: 0]av_rdata_i,
  41:   output logic                     event_av_empty_o,
  42: 
  43:   output logic                     rx_wvalid_o,
  44:   input  logic                     rx_wready_i,
  45:   output logic [RXFifoWidth - 1:0] rx_wdata_o,
  46:   output logic                     event_rx_full_o,
  47:   output logic                     setup_received_o,
  48:   output [3:0]                     out_endpoint_o,
  49: 
  50:   // transmit (IN) side
  51:   input  logic [NBufWidth - 1:0]   in_buf_i,
  52:   input  logic [PktW:0]            in_size_i,
  53:   input  logic [NEndpoints-1:0]    in_stall_i,
  54:   input  logic [NEndpoints-1:0]    in_rdy_i,
  55:   output logic                     set_sent_o,
  56:   output [3:0]                     in_endpoint_o,
  57: 
  58:   // memory interface
  59:   output logic                     mem_req_o,
  60:   output logic                     mem_write_o,
  61:   output logic [SramAw-1:0]        mem_addr_o,
  62:   output logic [31:0]              mem_wdata_o,
  63:   input  logic [31:0]              mem_rdata_i,
  64: 
  65:   // control
  66:   input  logic                     enable_i,
  67:   input  logic [6:0]               devaddr_i,
  68:   output logic                     clr_devaddr_o,
  69:   input  logic [NEndpoints-1:0]    ep_iso_i,
  70:   input  logic                     cfg_eop_single_bit_i, // 1: detect a single SE0 bit as EOP
  71:   input  logic                     tx_osc_test_mode_i, // Oscillator test mode (constantly output JK)
  72:   input  logic [NEndpoints-1:0]    data_toggle_clear_i, // Clear the data toggles for an EP
  73: 
  74:   // status
  75:   output logic                     frame_start_o,
  76:   output logic [10:0]              frame_o,
  77:   output logic [2:0]               link_state_o,
  78:   output logic                     link_disconnect_o,
  79:   output logic                     link_connect_o,
  80:   output logic                     link_reset_o,
  81:   output logic                     link_suspend_o,
  82:   output logic                     link_resume_o,
  83:   output logic                     link_in_err_o,
  84:   output logic                     host_lost_o,
  85:   output logic                     rx_crc_err_o,
  86:   output logic                     rx_pid_err_o,
  87:   output logic                     rx_bitstuff_err_o
  88: );
  89: 
  90:   assign usb_pullup_en_o = enable_i;
  91: 
  92: 
  93:   // OUT or SETUP direction
  94:   logic [PktW:0]                     out_max_used_d, out_max_used_q;
  95:   logic [PktW-1:0]                   out_ep_put_addr;
  96:   logic [7:0]                        out_ep_data;
  97: 
  98:   logic [3:0]                        out_ep_current;
  99:   logic                              out_ep_data_put, out_ep_acked, out_ep_rollback;
 100:   logic                              current_setup, all_out_blocked, out_ep_newpkt;
 101:   logic [NEndpoints-1:0]             out_ep_setup, out_ep_full, out_ep_stall;
 102:   logic [NEndpoints-1:0]             setup_blocked, out_blocked;
 103:   logic [31:0]                       wdata;
 104:   logic                              mem_read;
 105:   logic [SramAw-1:0]                 mem_waddr, mem_raddr;
 106:   logic                              link_reset;
 107:   logic                              sof_valid;
 108: 
 109:   assign out_endpoint_o = out_ep_current;
 110:   assign link_reset_o   = link_reset;
 111:   assign clr_devaddr_o  = ~enable_i | link_reset;
 112:   assign frame_start_o  = sof_valid;
 113: 
 114:   always_comb begin
 115:     if (out_ep_acked || out_ep_rollback) begin
 116:       out_max_used_d = 0;
 117: 
 118:     end else if (out_ep_data_put) begin
 119:       // In the normal case 
 120:       // Following all ones out_max_used_q will get 1,00..00 and 1,00..01 to cover
 121:       // one and two bytes of the CRC overflowing, then stick at 1,00..01
 122:       if (out_max_used_q < MaxPktSizeByte - 1) begin
 123:         out_max_used_d = out_ep_put_addr;
 124:       end else if (out_max_used_q < MaxPktSizeByte + 1) begin
 125:         out_max_used_d = out_max_used_q + 1;
 126:       end else begin
 127:         out_max_used_d = out_max_used_q;
 128:       end
 129: 
 130:     end else begin
 131:       out_max_used_d = out_max_used_q;
 132:     end
 133:   end // always_comb
 134: 
 135:   // don't write if the address has wrapped (happens for two CRC bytes after max data)
 136:   logic std_write_d, std_write_q;
 137:   assign std_write_d = out_ep_data_put & ((out_max_used_q < MaxPktSizeByte - 1) & (out_ep_put_addr[1:0] == 2'b11));
 138: 
 139: 
 140:   always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
 141:     if (!rst_ni) begin
 142:       out_max_used_q <= '0;
 143:       wdata          <= '0;
 144:       std_write_q    <= 1'b0;
 145:     end else begin
 146:       out_max_used_q <= out_max_used_d;
 147:       std_write_q    <= std_write_d;
 148:       if (out_ep_data_put) begin
 149:         unique case (out_ep_put_addr[1:0])
 150:           0: begin
 151:             wdata[7:0] <= out_ep_data;
 152:           end
 153:           1: begin
 154:             wdata[15:8] <= out_ep_data;
 155:           end
 156:           2: begin
 157:             wdata[23:16] <= out_ep_data;
 158:           end
 159:           3: begin
 160:             wdata[31:24] <= out_ep_data;
 161:           end
 162:         endcase
 163:       end
 164:     end
 165:   end // always_ff @ (posedge clk_48mhz_i)
 166: 
 167:   // need extra write at end if packet not multiple of 4 bytes
 168:   assign mem_write_o = std_write_q |
 169:                        (~out_max_used_q[PktW] & (out_max_used_q[1:0] != 2'b11) & out_ep_acked);
 170:   assign mem_waddr = {av_rdata_i, out_max_used_q[PktW-1:2]};
 171:   assign mem_wdata_o = wdata;
 172:   assign mem_addr_o = mem_write_o ? mem_waddr : mem_raddr;
 173:   assign mem_req_o = mem_read | mem_write_o;
 174:   assign current_setup = out_ep_setup[out_ep_current];  // lint: out_ep_current range was checked
 175: 
 176:   logic [PktW:0] out_max_minus1;
 177:   // -2 for CRC bytes but +1 for zero-based address to size
 178:   assign out_max_minus1 = out_max_used_q - 1;
 179: 
 180:   assign rx_wdata_o = {
 181:       out_ep_current,
 182:       current_setup,
 183:       out_max_minus1,
 184:       av_rdata_i
 185:   };
 186:   assign rx_wvalid_o = out_ep_acked & ~all_out_blocked;
 187:   // Pop the available fifo after the write that used the previous value
 188:   always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
 189:     if (!rst_ni) begin
 190:       av_rready_o <= 1'b0;
 191:     end else begin
 192:       av_rready_o <= rx_wvalid_o;
 193:     end
 194:   end
 195: 
 196:   // full here covers the software blocking by clearing the enable
 197:   assign setup_blocked = out_ep_setup & ~rx_setup_i;
 198:   assign out_blocked = ~out_ep_setup & ~rx_out_i;
 199:   // full also covers being blocked because the hardware can't take any transaction
 200:   assign all_out_blocked = (~rx_wready_i) | (~av_rvalid_i);
 201:   // These are used to raise appropriate interrupt
 202:   assign event_av_empty_o = out_ep_newpkt & (~av_rvalid_i);
 203:   assign event_rx_full_o = out_ep_newpkt & (~rx_wready_i);
 204: 
 205:   assign out_ep_full = {NEndpoints{all_out_blocked}} | setup_blocked | out_blocked;
 206:   assign out_ep_stall = rx_stall_i;
 207: 
 208:   // Need to clear IN read if a SETUP is received because it may use the IN channel
 209:   // This will not trigger, if the AV Buffer is empty, in that case we have replied
 210:   // with a NAK, which is illegal anyway
 211:   assign setup_received_o = current_setup & rx_wvalid_o;
 212: 
 213:   // IN (device to host) transfers
 214:   logic in_ep_acked, in_ep_data_get, in_data_done, in_ep_newpkt, pkt_start_rd;
 215:   logic [NEndpoints-1:0] in_ep_data_done;
 216:   logic [PktW-1:0] in_ep_get_addr;
 217:   logic [7:0]      in_ep_data;
 218: 
 219:   // The protocol engine will automatically generate done for a full-length packet
 220:   // Note: this does the correct thing for sending zero length packets
 221:   assign in_data_done = {1'b0, in_ep_get_addr} == in_size_i;
 222:   always_comb begin
 223:     in_ep_data_done = '0;
 224:     in_ep_data_done[in_endpoint_o] = in_data_done;  // lint: in_endpoint_o range was checked
 225:   end
 226: 
 227:   // Need extra read at start of packet to get the first word of data
 228:   // Delay by one cycle from the in_endpoint update
 229:   always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
 230:     if (!rst_ni) begin
 231:       pkt_start_rd <= 1'b0;
 232:     end else begin
 233:       pkt_start_rd <= in_ep_newpkt;
 234:     end
 235:   end
 236: 
 237:   assign mem_raddr = {in_buf_i,in_ep_get_addr[PktW-1:2]};
 238:   assign mem_read = pkt_start_rd | (in_ep_data_get & (in_ep_get_addr[1:0] == 2'b0));
 239: 
 240:   assign in_ep_data = in_ep_get_addr[1] ?
 241:                       (in_ep_get_addr[0] ? mem_rdata_i[31:24] : mem_rdata_i[23:16]) :
 242:                       (in_ep_get_addr[0] ? mem_rdata_i[15:8]  : mem_rdata_i[7:0]);
 243:   assign set_sent_o = in_ep_acked;
 244: 
 245:   logic [10:0]     frame_index_raw;
 246: 
 247:   usb_fs_nb_pe #(
 248:     .NumOutEps      (NEndpoints),
 249:     .NumInEps       (NEndpoints),
 250:     .MaxPktSizeByte (MaxPktSizeByte)
 251:   ) u_usb_fs_nb_pe (
 252:     .clk_48mhz_i           (clk_48mhz_i),
 253:     .rst_ni                (rst_ni),
 254:     .link_reset_i          (link_reset),
 255: 
 256:     .cfg_eop_single_bit_i  (cfg_eop_single_bit_i),
 257:     .tx_osc_test_mode_i    (tx_osc_test_mode_i),
 258:     .data_toggle_clear_i   (data_toggle_clear_i),
 259: 
 260:     .usb_d_i               (usb_d_i),
 261:     .usb_se0_i             (usb_se0_i),
 262:     .usb_d_o               (usb_d_o),
 263:     .usb_se0_o             (usb_se0_o),
 264:     .usb_oe_o              (usb_oe_o),
 265: 
 266:     .dev_addr_i            (devaddr_i),
 267: 
 268:     // out endpoint interfaces
 269:     .out_ep_current_o      (out_ep_current),
 270:     .out_ep_newpkt_o       (out_ep_newpkt),
 271:     .out_ep_data_put_o     (out_ep_data_put),
 272:     .out_ep_put_addr_o     (out_ep_put_addr),
 273:     .out_ep_data_o         (out_ep_data),
 274:     .out_ep_acked_o        (out_ep_acked),
 275:     .out_ep_rollback_o     (out_ep_rollback),
 276:     .out_ep_setup_o        (out_ep_setup),
 277:     .out_ep_full_i         (out_ep_full),
 278:     .out_ep_stall_i        (out_ep_stall),
 279:     .out_ep_iso_i          (ep_iso_i),
 280: 
 281:     // in endpoint interfaces
 282:     .in_ep_current_o       (in_endpoint_o),
 283:     .in_ep_rollback_o      (link_in_err_o),
 284:     .in_ep_acked_o         (in_ep_acked),
 285:     .in_ep_get_addr_o      (in_ep_get_addr),
 286:     .in_ep_data_get_o      (in_ep_data_get),
 287:     .in_ep_newpkt_o        (in_ep_newpkt),
 288:     .in_ep_stall_i         (in_stall_i),
 289:     .in_ep_has_data_i      (in_rdy_i),
 290:     .in_ep_data_i          (in_ep_data),
 291:     .in_ep_data_done_i     (in_ep_data_done),
 292:     .in_ep_iso_i           (ep_iso_i),
 293: 
 294:     // error signals
 295:     .rx_crc_err_o          (rx_crc_err_o),
 296:     .rx_pid_err_o          (rx_pid_err_o),
 297:     .rx_bitstuff_err_o     (rx_bitstuff_err_o),
 298: 
 299:     // sof interface
 300:     .sof_valid_o           (sof_valid),
 301:     .frame_index_o         (frame_index_raw)
 302:   );
 303: 
 304:   // us_tick ticks for one cycle every us
 305:   logic [5:0]   ns_cnt;
 306:   logic         us_tick;
 307: 
 308:   assign us_tick = (ns_cnt == 6'd48);
 309:   always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
 310:     if (!rst_ni) begin
 311:       ns_cnt <= '0;
 312:     end else begin
 313:       if (us_tick) begin
 314:         ns_cnt <= '0;
 315:       end else begin
 316:         ns_cnt <= ns_cnt + 1'b1;
 317:       end
 318:     end
 319:   end
 320: 
 321:   // Capture frame number (host sends evert 1ms)
 322:   always_ff @(posedge clk_48mhz_i or negedge rst_ni) begin
 323:     if (!rst_ni) begin
 324:       frame_o <= '0;
 325:     end else begin
 326:       if (sof_valid) begin
 327:         frame_o <= frame_index_raw;
 328:       end
 329:     end
 330:   end
 331: 
 332:   usbdev_linkstate u_usbdev_linkstate (
 333:     .clk_48mhz_i       (clk_48mhz_i),
 334:     .rst_ni            (rst_ni),
 335:     .us_tick_i         (us_tick),
 336:     .usb_sense_i       (usb_sense_i),
 337:     .usb_rx_d_i        (usb_d_i),
 338:     .usb_rx_se0_i      (usb_se0_i),
 339:     .sof_valid_i       (sof_valid),
 340:     .link_disconnect_o (link_disconnect_o),
 341:     .link_connect_o    (link_connect_o),
 342:     .link_reset_o      (link_reset),
 343:     .link_suspend_o    (link_suspend_o),
 344:     .link_resume_o     (link_resume_o),
 345:     .link_state_o      (link_state_o),
 346:     .host_lost_o       (host_lost_o)
 347:   );
 348: 
 349: 
 350: endmodule
 351: