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