hw/ip/usbdev/rtl/usbdev.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 (usbdev).
   6: //
   7: //
   8: 
   9: 
  10: module usbdev (
  11:   input  logic       clk_i,
  12:   input  logic       rst_ni,
  13:   input  logic       clk_usb_48mhz_i, // use usb_ prefix for signals in this clk
  14:   input  logic       rst_usb_ni, // async reset, with relase sync to clk_usb_48_mhz_i
  15: 
  16:   // Register interface
  17:   input  tlul_pkg::tl_h2d_t tl_i,
  18:   output tlul_pkg::tl_d2h_t tl_o,
  19: 
  20:   // USB Interface
  21:   input  logic       cio_usb_d_i,
  22:   input  logic       cio_usb_dp_i,
  23:   input  logic       cio_usb_dn_i,
  24: 
  25:   output logic       cio_usb_d_o,
  26:   output logic       cio_usb_se0_o,
  27:   output logic       cio_usb_dp_o,
  28:   output logic       cio_usb_dn_o,
  29:   output logic       cio_usb_oe_o,
  30: 
  31:   output logic       cio_usb_tx_mode_se_o,
  32:   input  logic       cio_usb_sense_i,
  33:   output logic       cio_usb_pullup_en_o,
  34:   output logic       cio_usb_suspend_o,
  35: 
  36:   // Interrupts
  37:   output logic       intr_pkt_received_o, // Packet received
  38:   output logic       intr_pkt_sent_o, // Packet sent
  39:   output logic       intr_connected_o,
  40:   output logic       intr_disconnected_o,
  41:   output logic       intr_host_lost_o,
  42:   output logic       intr_link_reset_o,
  43:   output logic       intr_link_suspend_o,
  44:   output logic       intr_link_resume_o,
  45:   output logic       intr_av_empty_o,
  46:   output logic       intr_rx_full_o,
  47:   output logic       intr_av_overflow_o,
  48:   output logic       intr_link_in_err_o,
  49:   output logic       intr_rx_crc_err_o,
  50:   output logic       intr_rx_pid_err_o,
  51:   output logic       intr_rx_bitstuff_err_o,
  52:   output logic       intr_frame_o
  53: );
  54: 
  55:   import usbdev_reg_pkg::*;
  56: 
  57:   // Could make SramDepth, MaxPktSizeByte, AVFifoDepth and RXFifoDepth
  58:   // module parameters but may need to fix register def for the first two
  59:   localparam int SramDw = 32; // Places packing bytes to SRAM assume this
  60:   localparam int SramDepth = 512; // 2kB, SRAM Width is DW
  61:   localparam int MaxPktSizeByte = 64;
  62: 
  63:   localparam int SramAw = $clog2(SramDepth);
  64:   localparam int SizeWidth = $clog2(MaxPktSizeByte);
  65:   localparam int NBuf = (SramDepth * SramDw) / (MaxPktSizeByte * 8);
  66:   localparam int NBufWidth = $clog2(NBuf);
  67: 
  68:   // AV fifo just stores buffer numbers
  69:   localparam int AVFifoWidth = NBufWidth;
  70:   localparam int AVFifoDepth = 4;
  71: 
  72:   // RX fifo stores              buf# +  size(0-MaxPktSizeByte)  + EP# + Type
  73:   localparam int RXFifoWidth = NBufWidth + (1+SizeWidth)         +  4  + 1;
  74:   localparam int RXFifoDepth = 4;
  75: 
  76:   // Number of endpoints
  77:   localparam int NEndpoints = usbdev_reg_pkg::NEndpoints;
  78: 
  79:   usbdev_reg2hw_t reg2hw;
  80:   usbdev_hw2reg_t hw2reg;
  81: 
  82:   tlul_pkg::tl_h2d_t tl_sram_h2d [1];
  83:   tlul_pkg::tl_d2h_t tl_sram_d2h [1];
  84: 
  85:   // Dual-port SRAM Interface: Refer prim_ram_2p_wrapper.sv
  86:   logic              mem_a_req;
  87:   logic              mem_a_write;
  88:   logic [SramAw-1:0] mem_a_addr;
  89:   logic [SramDw-1:0] mem_a_wdata;
  90:   logic              mem_a_rvalid;
  91:   logic [SramDw-1:0] mem_a_rdata;
  92:   logic [1:0]        mem_a_rerror;
  93: 
  94:   logic              usb_mem_b_req;
  95:   logic              usb_mem_b_write;
  96:   logic [SramAw-1:0] usb_mem_b_addr;
  97:   logic [SramDw-1:0] usb_mem_b_wdata;
  98:   logic [SramDw-1:0] usb_mem_b_rdata;
  99: 
 100:   logic              usb_clr_devaddr;
 101:   logic              usb_event_av_empty, event_av_overflow, usb_event_rx_full;
 102:   logic              event_av_empty, event_rx_full;
 103:   logic              usb_event_link_reset, usb_event_link_suspend, usb_event_link_resume;
 104:   logic              usb_event_host_lost, usb_event_disconnect, usb_event_connect;
 105:   logic              usb_event_rx_crc_err, usb_event_rx_pid_err;
 106:   logic              usb_event_rx_bitstuff_err;
 107:   logic              usb_event_in_err;
 108:   logic              usb_event_frame;
 109: 
 110:   logic              event_link_reset, event_link_suspend, event_link_resume;
 111:   logic              event_host_lost, event_disconnect, event_connect;
 112:   logic              event_rx_crc_err, event_rx_pid_err;
 113:   logic              event_rx_bitstuff_err;
 114:   logic              event_in_err;
 115:   logic              event_frame;
 116: 
 117:   // CDC signals
 118:   logic [10:0]       usb_frame;
 119:   logic [2:0]        usb_link_state;
 120:   logic              usb_enable;
 121:   logic [6:0]        usb_device_addr;
 122: 
 123:   logic                  usb_data_toggle_clear_en;
 124:   logic [NEndpoints-1:0] usb_data_toggle_clear;
 125: 
 126: 
 127:   /////////////////////////////////
 128:   // USB IO after CDC & muxing   //
 129:   /////////////////////////////////
 130:   logic usb_rx_d;
 131:   logic usb_rx_se0;
 132:   logic usb_tx_d;
 133:   logic usb_tx_se0;
 134:   logic usb_tx_oe;
 135:   logic usb_pwr_sense;
 136:   logic usb_pullup_en;
 137: 
 138:   /////////////////////////////
 139:   // Receive interface fifos //
 140:   /////////////////////////////
 141: 
 142:   logic              av_fifo_wready;
 143:   logic              event_pkt_received;
 144:   logic              usb_av_rvalid, usb_av_rready;
 145:   logic              usb_rx_wvalid, usb_rx_wready;
 146:   logic              rx_fifo_rvalid;
 147: 
 148:   logic [AVFifoWidth - 1:0] usb_av_rdata;
 149:   logic [RXFifoWidth - 1:0] usb_rx_wdata, rx_rdata_raw, rx_rdata;
 150: 
 151:   assign event_av_overflow = reg2hw.avbuffer.qe & (~av_fifo_wready);
 152:   assign hw2reg.usbstat.av_full.d = ~av_fifo_wready;
 153:   assign hw2reg.usbstat.rx_empty.d = ~rx_fifo_rvalid;
 154: 
 155:   prim_fifo_async #(
 156:     .Width(AVFifoWidth),
 157:     .Depth(AVFifoDepth)
 158:   ) usbdev_avfifo (
 159:     .clk_wr_i  (clk_i),
 160:     .rst_wr_ni (rst_ni),
 161: 
 162:     .wvalid    (reg2hw.avbuffer.qe),
 163:     .wready    (av_fifo_wready),
 164:     .wdata     (reg2hw.avbuffer.q),
 165:     .wdepth    (hw2reg.usbstat.av_depth.d),
 166: 
 167:     .clk_rd_i  (clk_usb_48mhz_i),
 168:     .rst_rd_ni (rst_usb_ni),
 169:     .rvalid    (usb_av_rvalid),
 170:     .rready    (usb_av_rready),
 171:     .rdata     (usb_av_rdata),
 172:     .rdepth    () // only using empty
 173:   );
 174: 
 175:   prim_fifo_async #(
 176:     .Width(RXFifoWidth),
 177:     .Depth(RXFifoDepth)
 178:   ) usbdev_rxfifo (
 179:     .clk_wr_i  (clk_usb_48mhz_i),
 180:     .rst_wr_ni (rst_usb_ni),
 181: 
 182:     .wvalid    (usb_rx_wvalid),
 183:     .wready    (usb_rx_wready),
 184:     .wdata     (usb_rx_wdata),
 185:     .wdepth    (),
 186: 
 187:     .clk_rd_i  (clk_i),
 188:     .rst_rd_ni (rst_ni),
 189:     .rvalid    (rx_fifo_rvalid),
 190:     .rready    (reg2hw.rxfifo.buffer.re),
 191:     .rdata     (rx_rdata_raw),
 192:     .rdepth    (hw2reg.usbstat.rx_depth.d)
 193:   );
 194: 
 195:   // Return all zero if the FIFO is empty (instead of X)
 196:   assign rx_rdata = rx_fifo_rvalid ? rx_rdata_raw : '0;
 197:   assign hw2reg.rxfifo.ep.d = rx_rdata[16:13];
 198:   assign hw2reg.rxfifo.setup.d = rx_rdata[12];
 199:   assign hw2reg.rxfifo.size.d = rx_rdata[11:5];
 200:   assign hw2reg.rxfifo.buffer.d = rx_rdata[4:0];
 201:   assign event_pkt_received = rx_fifo_rvalid;
 202:   logic [2:0]               unused_re;
 203:   assign unused_re = {reg2hw.rxfifo.ep.re, reg2hw.rxfifo.setup.re, reg2hw.rxfifo.size.re};
 204: 
 205:   ////////////////////////////////////
 206:   // IN (Transmit) interface config //
 207:   ////////////////////////////////////
 208:   logic [NBufWidth-1:0]  usb_in_buf [NEndpoints];
 209:   logic [SizeWidth:0]    usb_in_size [NEndpoints];
 210:   logic [3:0]            usb_in_endpoint;
 211:   logic [NEndpoints-1:0] usb_in_rdy;
 212:   logic [NEndpoints-1:0] clear_rdybit, set_sentbit, update_pend;
 213:   logic                  usb_setup_received, setup_received, usb_set_sent, set_sent;
 214:   logic [NEndpoints-1:0] ep_iso;
 215:   logic [NEndpoints-1:0] enable_setup, enable_out, ep_stall;
 216:   logic [NEndpoints-1:0] usb_enable_setup, usb_enable_out, usb_ep_stall;
 217:   logic [NEndpoints-1:0] in_rdy_async;
 218:   logic [3:0]            usb_out_endpoint;
 219: 
 220:   // RX enables
 221:   always_comb begin : proc_map_rxenable
 222:     for (int i = 0; i < NEndpoints; i++) begin
 223:       enable_setup[i] = reg2hw.rxenable_setup[i].q;
 224:       enable_out[i]   = reg2hw.rxenable_out[i].q;
 225:     end
 226:   end
 227: 
 228:   // STALL for both directions
 229:   always_comb begin : proc_map_stall
 230:     for (int i = 0; i < NEndpoints; i++) begin
 231:       ep_stall[i] = reg2hw.stall[i];
 232:     end
 233:   end
 234: 
 235:   prim_flop_2sync #(
 236:     .Width(3*NEndpoints)
 237:   ) usbdev_sync_ep_cfg (
 238:     .clk_i  (clk_usb_48mhz_i),
 239:     .rst_ni (rst_usb_ni),
 240:     .d      ({enable_setup, enable_out, ep_stall}),
 241:     .q      ({usb_enable_setup, usb_enable_out, usb_ep_stall})
 242:   );
 243: 
 244:   // CDC: ok, quasi-static
 245:   always_comb begin : proc_map_iso
 246:     for (int i = 0; i < NEndpoints; i++) begin
 247:       ep_iso[i] = reg2hw.iso[i].q;
 248:     end
 249:   end
 250: 
 251:   // CDC: flop_2sync for ready bit covers others so assigns are ok
 252:   always_comb begin : proc_map_buf_size
 253:     for (int i = 0; i < NEndpoints; i++) begin
 254:       usb_in_buf[i]  = reg2hw.configin[i].buffer.q;
 255:       usb_in_size[i] = reg2hw.configin[i].size.q;
 256:     end
 257:   end
 258: 
 259:   always_comb begin : proc_map_rdy_reg2hw
 260:     for (int i = 0; i < NEndpoints; i++) begin
 261:       in_rdy_async[i] = reg2hw.configin[i].rdy.q;
 262:     end
 263:   end
 264: 
 265:   prim_flop_2sync #(
 266:     .Width (NEndpoints)
 267:   ) usbdev_rdysync (
 268:     .clk_i  (clk_usb_48mhz_i),
 269:     .rst_ni (rst_usb_ni),
 270:     .d      (in_rdy_async),
 271:     .q      (usb_in_rdy)
 272:   );
 273: 
 274:   // CDC: We synchronize the qe (write pulse) and assume that the
 275:   // rest of the register remains stable
 276:   prim_pulse_sync usbdev_data_toggle_clear (
 277:     .clk_src_i   (clk_i),
 278:     .clk_dst_i   (clk_usb_48mhz_i),
 279:     .rst_src_ni  (rst_ni),
 280:     .rst_dst_ni  (rst_usb_ni),
 281:     .src_pulse_i (reg2hw.data_toggle_clear[0].qe),
 282:     .dst_pulse_o (usb_data_toggle_clear_en)
 283:   );
 284: 
 285:   always_comb begin : proc_usb_data_toggle_clear
 286:     usb_data_toggle_clear = '0;
 287:     for (int i = 0; i < NEndpoints; i++) begin
 288:       if (usb_data_toggle_clear_en) begin
 289:         usb_data_toggle_clear[i] = reg2hw.data_toggle_clear[i].q;
 290:       end
 291:     end
 292:   end
 293: 
 294:   // Clear of ready and set of sent is a pulse in USB clock domain
 295:   // but needs to ensure register bit is cleared/set in TLUL domain
 296:   // usbdev_pulsesync takes pulse in clk_src to pulse in clk_dst
 297:   prim_pulse_sync usbdev_setsent (
 298:     .clk_src_i   (clk_usb_48mhz_i),
 299:     .clk_dst_i   (clk_i),
 300:     .rst_src_ni  (rst_usb_ni),
 301:     .rst_dst_ni  (rst_ni),
 302:     .src_pulse_i (usb_set_sent),
 303:     .dst_pulse_o (set_sent)
 304:   );
 305: 
 306:   always_comb begin
 307:     set_sentbit = '0;
 308:     if (set_sent) begin
 309:       // synchronization of set_sent ensures usb_endpoint is stable
 310:       set_sentbit[usb_in_endpoint] = 1; // lint: usb_in_endpoint range was checked
 311:     end
 312:   end
 313: 
 314:   always_comb begin : proc_map_sent
 315:     for (int i = 0; i < NEndpoints; i++) begin
 316:       hw2reg.in_sent[i].de = set_sentbit[i];
 317:       hw2reg.in_sent[i].d  = 1'b1;
 318:     end
 319:   end
 320: 
 321:   // Event (pulse) synchronization
 322:   prim_pulse_sync usbdev_sync_in_err (
 323:     .clk_src_i   (clk_usb_48mhz_i),
 324:     .clk_dst_i   (clk_i),
 325:     .rst_src_ni  (rst_usb_ni),
 326:     .rst_dst_ni  (rst_ni),
 327:     .src_pulse_i (usb_event_in_err),
 328:     .dst_pulse_o (event_in_err)
 329:   );
 330: 
 331:   prim_pulse_sync usbdev_outrdyclr (
 332:     .clk_src_i   (clk_usb_48mhz_i),
 333:     .clk_dst_i   (clk_i),
 334:     .rst_src_ni  (rst_usb_ni),
 335:     .rst_dst_ni  (rst_ni),
 336:     .src_pulse_i (usb_setup_received),
 337:     .dst_pulse_o (setup_received)
 338:   );
 339: 
 340:   prim_pulse_sync sync_usb_event_rx_crc_err (
 341:     .clk_src_i   (clk_usb_48mhz_i),
 342:     .clk_dst_i   (clk_i),
 343:     .rst_src_ni  (rst_usb_ni),
 344:     .rst_dst_ni  (rst_ni),
 345:     .src_pulse_i (usb_event_rx_crc_err),
 346:     .dst_pulse_o (event_rx_crc_err)
 347:   );
 348: 
 349:   prim_pulse_sync sync_usb_event_rx_pid_err (
 350:     .clk_src_i   (clk_usb_48mhz_i),
 351:     .clk_dst_i   (clk_i),
 352:     .rst_src_ni  (rst_usb_ni),
 353:     .rst_dst_ni  (rst_ni),
 354:     .src_pulse_i (usb_event_rx_pid_err),
 355:     .dst_pulse_o (event_rx_pid_err)
 356:   );
 357: 
 358:   prim_pulse_sync sync_usb_event_rx_bitstuff_err (
 359:     .clk_src_i   (clk_usb_48mhz_i),
 360:     .clk_dst_i   (clk_i),
 361:     .rst_src_ni  (rst_usb_ni),
 362:     .rst_dst_ni  (rst_ni),
 363:     .src_pulse_i (usb_event_rx_bitstuff_err),
 364:     .dst_pulse_o (event_rx_bitstuff_err)
 365:   );
 366: 
 367:   prim_pulse_sync sync_usb_event_frame (
 368:     .clk_src_i   (clk_usb_48mhz_i),
 369:     .clk_dst_i   (clk_i),
 370:     .rst_src_ni  (rst_usb_ni),
 371:     .rst_dst_ni  (rst_ni),
 372:     .src_pulse_i (usb_event_frame),
 373:     .dst_pulse_o (event_frame)
 374:   );
 375: 
 376:   logic event_link_reset_q;
 377: 
 378:   always_ff @(posedge clk_usb_48mhz_i or negedge rst_usb_ni) begin
 379:     if (!rst_usb_ni) begin
 380:       event_link_reset_q <= 0;
 381:     end else begin
 382:       event_link_reset_q <= event_link_reset;
 383:     end
 384:   end
 385: 
 386:   always_comb begin
 387:     clear_rdybit = '0;
 388:     update_pend  = '0;
 389:     if (event_link_reset && !event_link_reset_q) begin
 390:       clear_rdybit = {NEndpoints{1'b1}};
 391:       update_pend  = {NEndpoints{1'b1}};
 392:     end else begin
 393:       // Clear pending when a SETUP is received
 394:       // CDC: usb_out_endpoint is synchronized implicitly by
 395:       // setup_received, as it is stable
 396:       clear_rdybit[usb_out_endpoint] = setup_received;
 397:       update_pend[usb_out_endpoint]  = setup_received;
 398: 
 399:       // Clear when a IN transmission was sucessful
 400:       // CDC: usb_in_endpoint is synchronzied implicitly by
 401:       // set_sent
 402:       clear_rdybit[usb_in_endpoint] = set_sent;
 403:     end
 404:   end
 405: 
 406:   always_comb begin : proc_map_rdy_hw2reg
 407:     for (int i = 0; i < NEndpoints; i++) begin
 408:       hw2reg.configin[i].rdy.de = clear_rdybit[i];
 409:       hw2reg.configin[i].rdy.d  = 1'b0;
 410:     end
 411:   end
 412: 
 413:   // Update the pending bit by copying the ready bit that is about to clear
 414:   always_comb begin : proc_map_pend
 415:     for (int i = 0; i < NEndpoints; i++) begin
 416:       hw2reg.configin[i].pend.de = update_pend[i];
 417:       hw2reg.configin[i].pend.d  = reg2hw.configin[i].rdy.q | reg2hw.configin[i].pend.q;
 418:     end
 419:   end
 420: 
 421:   ////////////////////////////////////////////////////////
 422:   // USB interface -- everything is in USB clock domain //
 423:   ////////////////////////////////////////////////////////
 424: 
 425:   usbdev_usbif #(
 426:     .NEndpoints     (NEndpoints),
 427:     .AVFifoWidth    (AVFifoWidth),
 428:     .RXFifoWidth    (RXFifoWidth),
 429:     .MaxPktSizeByte (MaxPktSizeByte),
 430:     .NBuf           (NBuf),
 431:     .SramAw         (SramAw)
 432:   ) usbdev_impl (
 433:     .clk_48mhz_i          (clk_usb_48mhz_i),
 434:     .rst_ni               (rst_usb_ni),
 435: 
 436:     // Pins
 437:     .usb_d_i              (usb_rx_d),
 438:     .usb_se0_i            (usb_rx_se0),
 439:     .usb_oe_o             (usb_tx_oe),
 440:     .usb_d_o              (usb_tx_d),
 441:     .usb_se0_o            (usb_tx_se0),
 442:     .usb_sense_i          (usb_pwr_sense),
 443:     .usb_pullup_en_o      (usb_pullup_en),
 444: 
 445:     // receive side
 446:     .rx_setup_i           (usb_enable_setup),
 447:     .rx_out_i             (usb_enable_out),
 448:     .rx_stall_i           (usb_ep_stall),
 449:     .av_rvalid_i          (usb_av_rvalid),
 450:     .av_rready_o          (usb_av_rready),
 451:     .av_rdata_i           (usb_av_rdata),
 452:     .event_av_empty_o     (usb_event_av_empty),
 453: 
 454:     .rx_wvalid_o          (usb_rx_wvalid),
 455:     .rx_wready_i          (usb_rx_wready),
 456:     .rx_wdata_o           (usb_rx_wdata),
 457:     .event_rx_full_o      (usb_event_rx_full),
 458:     .setup_received_o     (usb_setup_received),
 459:     .out_endpoint_o       (usb_out_endpoint),  // will be stable for several cycles
 460: 
 461:     // transmit side
 462:     .in_buf_i             (usb_in_buf[usb_in_endpoint]),  // lint: usb_in_endpoint range was checked
 463:     .in_size_i            (usb_in_size[usb_in_endpoint]),  // lint: usb_in_endpoint range was checked
 464:     .in_stall_i           (usb_ep_stall),
 465:     .in_rdy_i             (usb_in_rdy),
 466:     .set_sent_o           (usb_set_sent),
 467:     .in_endpoint_o        (usb_in_endpoint),
 468: 
 469:     // memory
 470:     .mem_req_o            (usb_mem_b_req),
 471:     .mem_write_o          (usb_mem_b_write),
 472:     .mem_addr_o           (usb_mem_b_addr),
 473:     .mem_wdata_o          (usb_mem_b_wdata),
 474:     .mem_rdata_i          (usb_mem_b_rdata),
 475: 
 476:     // control
 477:     .enable_i             (usb_enable),
 478:     .devaddr_i            (usb_device_addr),
 479:     .clr_devaddr_o        (usb_clr_devaddr),
 480:     .ep_iso_i             (ep_iso), // cdc ok, quasi-static
 481:     .cfg_eop_single_bit_i (reg2hw.phy_config.eop_single_bit.q), // cdc ok: quasi-static
 482:     .tx_osc_test_mode_i   (1'b0), // cdc ok: quasi-static & testmode only
 483:     .data_toggle_clear_i  (usb_data_toggle_clear),
 484: 
 485:     // status
 486:     .frame_o              (usb_frame),
 487:     .frame_start_o        (usb_event_frame),
 488:     .link_state_o         (usb_link_state),
 489:     .link_disconnect_o    (usb_event_disconnect),
 490:     .link_connect_o       (usb_event_connect),
 491:     .link_reset_o         (usb_event_link_reset),
 492:     .link_suspend_o       (usb_event_link_suspend),
 493:     .link_resume_o        (usb_event_link_resume),
 494:     .host_lost_o          (usb_event_host_lost),
 495:     .link_in_err_o        (usb_event_in_err),
 496:     .rx_crc_err_o         (usb_event_rx_crc_err),
 497:     .rx_pid_err_o         (usb_event_rx_pid_err),
 498:     .rx_bitstuff_err_o    (usb_event_rx_bitstuff_err)
 499:   );
 500: 
 501:   /////////////////////////////////
 502:   // Control signal / status CDC //
 503:   /////////////////////////////////
 504: 
 505:   // USB clk -> sys clk
 506:   prim_flop_2sync #(
 507:     .Width      (3+11)
 508:   ) cdc_usb_to_sys (
 509:     .clk_i  (clk_i),
 510:     .rst_ni (rst_ni),
 511:     .d      ({usb_link_state,              usb_frame}),
 512:     .q      ({hw2reg.usbstat.link_state.d, hw2reg.usbstat.frame.d})
 513:   );
 514: 
 515:   // sys clk -> USB clk
 516:   prim_flop_2sync #(
 517:     .Width      (1+7)
 518:   ) cdc_sys_to_usb (
 519:     .clk_i  (clk_usb_48mhz_i),
 520:     .rst_ni (rst_usb_ni),
 521:     .d      ({reg2hw.usbctrl.enable.q, reg2hw.usbctrl.device_address.q}),
 522:     .q      ({usb_enable,              usb_device_addr})
 523:   );
 524: 
 525:   // CDC for event signals (arguably they are there for a long time so would be ok)
 526:   // Just want a pulse to ensure only one interrupt for an event
 527:   usbdev_flop_2syncpulse #(.Width(5)) syncevent (
 528:     .clk_i  (clk_i),
 529:     .rst_ni (rst_ni),
 530:     .d      ({usb_event_disconnect, usb_event_link_reset, usb_event_link_suspend,
 531:               usb_event_host_lost, usb_event_connect}),
 532:     .q      ({event_disconnect, event_link_reset, event_link_suspend,
 533:               event_host_lost, event_connect})
 534:   );
 535: 
 536:   // Resume is a single pulse so needs pulsesync
 537:   prim_pulse_sync usbdev_resume (
 538:     .clk_src_i   (clk_usb_48mhz_i),
 539:     .clk_dst_i   (clk_i),
 540:     .rst_src_ni  (rst_usb_ni),
 541:     .rst_dst_ni  (rst_ni),
 542:     .src_pulse_i (usb_event_link_resume),
 543:     .dst_pulse_o (event_link_resume)
 544:   );
 545: 
 546:   assign hw2reg.usbstat.host_lost.d = event_host_lost;
 547: 
 548:   // resets etc cause the device address to clear
 549:   prim_pulse_sync usbdev_devclr (
 550:     .clk_src_i   (clk_usb_48mhz_i),
 551:     .clk_dst_i   (clk_i),
 552:     .rst_src_ni  (rst_usb_ni),
 553:     .rst_dst_ni  (rst_ni),
 554:     .src_pulse_i (usb_clr_devaddr),
 555:     .dst_pulse_o (hw2reg.usbctrl.device_address.de)
 556:   );
 557:   assign hw2reg.usbctrl.device_address.d = '0;
 558: 
 559:   // AV empty is a single pulse so needs pulsesync
 560:   prim_pulse_sync sync_usb_event_av_empty (
 561:     .clk_src_i   (clk_usb_48mhz_i),
 562:     .clk_dst_i   (clk_i),
 563:     .rst_src_ni  (rst_usb_ni),
 564:     .rst_dst_ni  (rst_ni),
 565:     .src_pulse_i (usb_event_av_empty),
 566:     .dst_pulse_o (event_av_empty)
 567:   );
 568: 
 569:   // RX full is a single pulse so needs pulsesync
 570:   prim_pulse_sync sync_usb_event_rx_full (
 571:     .clk_src_i   (clk_usb_48mhz_i),
 572:     .clk_dst_i   (clk_i),
 573:     .rst_src_ni  (rst_usb_ni),
 574:     .rst_dst_ni  (rst_ni),
 575:     .src_pulse_i (usb_event_rx_full),
 576:     .dst_pulse_o (event_rx_full)
 577:   );
 578: 
 579:   // Clear the stall flag when a SETUP is received
 580: 
 581:   // CDC: usb_out_endpoint is synchronized implicitly by
 582:   // setup_received, as it is stable
 583:   always_comb begin : proc_stall_tieoff
 584:     for (int i = 0; i < NEndpoints; i++) begin
 585:       hw2reg.stall[i].d  = 1'b0;
 586:       if (setup_received && usb_out_endpoint == 4'(i)) begin
 587:         hw2reg.stall[i].de = 1'b1;
 588:       end else begin
 589:         hw2reg.stall[i].de = 1'b0;
 590:       end
 591:     end
 592:   end
 593: 
 594:   logic        unused_mem_a_rerror_d;
 595: 
 596:   // TL-UL to SRAM adapter
 597:   tlul_adapter_sram #(
 598:     .SramAw(SramAw),
 599:     .ByteAccess(0)
 600:   ) u_tlul2sram (
 601:     .clk_i    (clk_i),
 602:     .rst_ni   (rst_ni),
 603: 
 604:     .tl_i     (tl_sram_h2d [0]),
 605:     .tl_o     (tl_sram_d2h [0]),
 606: 
 607:     .req_o    (mem_a_req),
 608:     .gnt_i    (mem_a_req),  //Always grant when request
 609:     .we_o     (mem_a_write),
 610:     .addr_o   (mem_a_addr),
 611:     .wdata_o  (mem_a_wdata),
 612:     .wmask_o  (),           // Not used
 613:     .rdata_i  (mem_a_rdata),
 614:     .rvalid_i (mem_a_rvalid),
 615:     .rerror_i (mem_a_rerror)
 616:   );
 617: 
 618:   assign unused_mem_a_rerror_d = mem_a_rerror[1] ; // Only uncorrectable error
 619: 
 620:   // SRAM Wrapper
 621:   prim_ram_2p_async_adv #(
 622:     .Depth (SramDepth),
 623:     .Width (SramDw),    // 32 x 512 --> 2kB
 624:     .CfgW  (8),
 625: 
 626:     .EnableECC           (0), // No Protection
 627:     .EnableParity        (0),
 628:     .EnableInputPipeline (0),
 629:     .EnableOutputPipeline(0),
 630: 
 631:     // large memory, implement with SRAMs
 632:     .MemT ("SRAM")
 633:   ) u_memory_2p (
 634:     .clk_a_i    (clk_i),
 635:     .clk_b_i    (clk_usb_48mhz_i),
 636:     .rst_a_ni   (rst_ni),
 637:     .rst_b_ni   (rst_usb_ni),
 638:     .a_req_i    (mem_a_req),
 639:     .a_write_i  (mem_a_write),
 640:     .a_addr_i   (mem_a_addr),
 641:     .a_wdata_i  (mem_a_wdata),
 642:     .a_rvalid_o (mem_a_rvalid),
 643:     .a_rdata_o  (mem_a_rdata),
 644:     .a_rerror_o (mem_a_rerror),
 645: 
 646:     .b_req_i    (usb_mem_b_req),
 647:     .b_write_i  (usb_mem_b_write),
 648:     .b_addr_i   (usb_mem_b_addr),
 649:     .b_wdata_i  (usb_mem_b_wdata),
 650:     .b_rvalid_o (),
 651:     .b_rdata_o  (usb_mem_b_rdata),
 652:     .b_rerror_o (),
 653: 
 654:     .cfg_i      (8'h0)
 655:   );
 656: 
 657:   // Register module
 658:   usbdev_reg_top u_reg (
 659:     .clk_i,
 660:     .rst_ni,
 661: 
 662:     .tl_i (tl_i),
 663:     .tl_o (tl_o),
 664: 
 665:     .tl_win_o (tl_sram_h2d),
 666:     .tl_win_i (tl_sram_d2h),
 667: 
 668:     .reg2hw,
 669:     .hw2reg,
 670:     .devmode_i (1'b1)
 671:   );
 672: 
 673:   prim_intr_hw #(.Width(1)) intr_hw_pkt_received (
 674:     .event_intr_i           (event_pkt_received),
 675:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.pkt_received.q),
 676:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.pkt_received.q),
 677:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.pkt_received.qe),
 678:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.pkt_received.q),
 679:     .hw2reg_intr_state_de_o (hw2reg.intr_state.pkt_received.de),
 680:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.pkt_received.d),
 681:     .intr_o                 (intr_pkt_received_o)
 682:   );
 683: 
 684:   prim_intr_hw #(.Width(1)) intr_hw_pkt_sent (
 685:     .event_intr_i           (set_sent),
 686:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.pkt_sent.q),
 687:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.pkt_sent.q),
 688:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.pkt_sent.qe),
 689:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.pkt_sent.q),
 690:     .hw2reg_intr_state_de_o (hw2reg.intr_state.pkt_sent.de),
 691:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.pkt_sent.d),
 692:     .intr_o                 (intr_pkt_sent_o)
 693:   );
 694: 
 695:   prim_intr_hw #(.Width(1)) intr_disconnected (
 696:     .event_intr_i           (event_disconnect),
 697:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.disconnected.q),
 698:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.disconnected.q),
 699:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.disconnected.qe),
 700:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.disconnected.q),
 701:     .hw2reg_intr_state_de_o (hw2reg.intr_state.disconnected.de),
 702:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.disconnected.d),
 703:     .intr_o                 (intr_disconnected_o)
 704:   );
 705: 
 706:   prim_intr_hw #(.Width(1)) intr_connected (
 707:     .event_intr_i           (event_connect),
 708:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.connected.q),
 709:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.connected.q),
 710:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.connected.qe),
 711:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.connected.q),
 712:     .hw2reg_intr_state_de_o (hw2reg.intr_state.connected.de),
 713:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.connected.d),
 714:     .intr_o                 (intr_connected_o)
 715:   );
 716: 
 717:   prim_intr_hw #(.Width(1)) intr_host_lost (
 718:     .event_intr_i           (event_host_lost),
 719:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.host_lost.q),
 720:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.host_lost.q),
 721:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.host_lost.qe),
 722:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.host_lost.q),
 723:     .hw2reg_intr_state_de_o (hw2reg.intr_state.host_lost.de),
 724:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.host_lost.d),
 725:     .intr_o                 (intr_host_lost_o)
 726:   );
 727: 
 728:   prim_intr_hw #(.Width(1)) intr_link_reset (
 729:     .event_intr_i           (event_link_reset),
 730:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.link_reset.q),
 731:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.link_reset.q),
 732:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.link_reset.qe),
 733:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.link_reset.q),
 734:     .hw2reg_intr_state_de_o (hw2reg.intr_state.link_reset.de),
 735:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.link_reset.d),
 736:     .intr_o                 (intr_link_reset_o)
 737:   );
 738: 
 739:   prim_intr_hw #(.Width(1)) intr_link_suspend (
 740:     .event_intr_i           (event_link_suspend),
 741:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.link_suspend.q),
 742:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.link_suspend.q),
 743:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.link_suspend.qe),
 744:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.link_suspend.q),
 745:     .hw2reg_intr_state_de_o (hw2reg.intr_state.link_suspend.de),
 746:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.link_suspend.d),
 747:     .intr_o                 (intr_link_suspend_o)
 748:   );
 749: 
 750:   prim_intr_hw #(.Width(1)) intr_link_resume (
 751:     .event_intr_i           (event_link_resume),
 752:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.link_resume.q),
 753:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.link_resume.q),
 754:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.link_resume.qe),
 755:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.link_resume.q),
 756:     .hw2reg_intr_state_de_o (hw2reg.intr_state.link_resume.de),
 757:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.link_resume.d),
 758:     .intr_o                 (intr_link_resume_o)
 759:   );
 760: 
 761:   prim_intr_hw #(.Width(1)) intr_av_empty (
 762:     .event_intr_i           (event_av_empty),
 763:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.av_empty.q),
 764:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.av_empty.q),
 765:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.av_empty.qe),
 766:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.av_empty.q),
 767:     .hw2reg_intr_state_de_o (hw2reg.intr_state.av_empty.de),
 768:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.av_empty.d),
 769:     .intr_o                 (intr_av_empty_o)
 770:   );
 771: 
 772:   prim_intr_hw #(.Width(1)) intr_rx_full (
 773:     .event_intr_i           (event_rx_full),
 774:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rx_full.q),
 775:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.rx_full.q),
 776:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rx_full.qe),
 777:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.rx_full.q),
 778:     .hw2reg_intr_state_de_o (hw2reg.intr_state.rx_full.de),
 779:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.rx_full.d),
 780:     .intr_o                 (intr_rx_full_o)
 781:   );
 782: 
 783:   prim_intr_hw #(.Width(1)) intr_av_overflow (
 784:     .event_intr_i           (event_av_overflow),
 785:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.av_overflow.q),
 786:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.av_overflow.q),
 787:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.av_overflow.qe),
 788:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.av_overflow.q),
 789:     .hw2reg_intr_state_de_o (hw2reg.intr_state.av_overflow.de),
 790:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.av_overflow.d),
 791:     .intr_o                 (intr_av_overflow_o)
 792:   );
 793: 
 794:   prim_intr_hw #(.Width(1)) intr_link_in_err (
 795:     .event_intr_i           (event_in_err),
 796:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.link_in_err.q),
 797:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.link_in_err.q),
 798:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.link_in_err.qe),
 799:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.link_in_err.q),
 800:     .hw2reg_intr_state_de_o (hw2reg.intr_state.link_in_err.de),
 801:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.link_in_err.d),
 802:     .intr_o                 (intr_link_in_err_o)
 803:   );
 804: 
 805:   prim_intr_hw #(.Width(1)) intr_rx_crc_err (
 806:     .event_intr_i           (event_rx_crc_err),
 807:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rx_crc_err.q),
 808:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.rx_crc_err.q),
 809:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rx_crc_err.qe),
 810:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.rx_crc_err.q),
 811:     .hw2reg_intr_state_de_o (hw2reg.intr_state.rx_crc_err.de),
 812:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.rx_crc_err.d),
 813:     .intr_o                 (intr_rx_crc_err_o)
 814:   );
 815: 
 816:   prim_intr_hw #(.Width(1)) intr_rx_pid_err (
 817:     .event_intr_i           (event_rx_pid_err),
 818:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rx_pid_err.q),
 819:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.rx_pid_err.q),
 820:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rx_pid_err.qe),
 821:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.rx_pid_err.q),
 822:     .hw2reg_intr_state_de_o (hw2reg.intr_state.rx_pid_err.de),
 823:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.rx_pid_err.d),
 824:     .intr_o                 (intr_rx_pid_err_o)
 825:   );
 826: 
 827:   prim_intr_hw #(.Width(1)) intr_rx_bitstuff_err (
 828:     .event_intr_i           (event_rx_bitstuff_err),
 829:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.rx_bitstuff_err.q),
 830:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.rx_bitstuff_err.q),
 831:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.rx_bitstuff_err.qe),
 832:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.rx_bitstuff_err.q),
 833:     .hw2reg_intr_state_de_o (hw2reg.intr_state.rx_bitstuff_err.de),
 834:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.rx_bitstuff_err.d),
 835:     .intr_o                 (intr_rx_bitstuff_err_o)
 836:   );
 837: 
 838:   prim_intr_hw #(.Width(1)) intr_frame (
 839:     .event_intr_i           (event_frame),
 840:     .reg2hw_intr_enable_q_i (reg2hw.intr_enable.frame.q),
 841:     .reg2hw_intr_test_q_i   (reg2hw.intr_test.frame.q),
 842:     .reg2hw_intr_test_qe_i  (reg2hw.intr_test.frame.qe),
 843:     .reg2hw_intr_state_q_i  (reg2hw.intr_state.frame.q),
 844:     .hw2reg_intr_state_de_o (hw2reg.intr_state.frame.de),
 845:     .hw2reg_intr_state_d_o  (hw2reg.intr_state.frame.d),
 846:     .intr_o                 (intr_frame_o)
 847:   );
 848: 
 849:   /////////////////////////////////
 850:   // USB IO Muxing               //
 851:   /////////////////////////////////
 852: 
 853:   usbdev_iomux i_usbdev_iomux (
 854:     .clk_i                  (clk_i),
 855:     .rst_ni                 (rst_ni),
 856:     .clk_usb_48mhz_i        (clk_usb_48mhz_i),
 857:     .rst_usb_ni             (rst_usb_ni),
 858:     .rx_differential_mode_i (reg2hw.phy_config.rx_differential_mode),
 859:     .tx_differential_mode_i (reg2hw.phy_config.tx_differential_mode),
 860:     .sys_reg2hw_config_i    (reg2hw.phy_config),
 861:     .sys_usb_sense_o        (hw2reg.usbstat.usb_sense.d),
 862: 
 863:     // Chip IO
 864:     .cio_usb_d_i            (cio_usb_d_i),
 865:     .cio_usb_dp_i           (cio_usb_dp_i),
 866:     .cio_usb_dn_i           (cio_usb_dn_i),
 867:     .cio_usb_d_o            (cio_usb_d_o),
 868:     .cio_usb_se0_o          (cio_usb_se0_o),
 869:     .cio_usb_dp_o           (cio_usb_dp_o),
 870:     .cio_usb_dn_o           (cio_usb_dn_o),
 871:     .cio_usb_oe_o           (cio_usb_oe_o),
 872:     .cio_usb_tx_mode_se_o   (cio_usb_tx_mode_se_o),
 873:     .cio_usb_sense_i        (cio_usb_sense_i),
 874:     .cio_usb_pullup_en_o    (cio_usb_pullup_en_o),
 875:     .cio_usb_suspend_o      (cio_usb_suspend_o),
 876: 
 877:     // Internal interface
 878:     .usb_rx_d_o             (usb_rx_d),
 879:     .usb_rx_se0_o           (usb_rx_se0),
 880:     .usb_tx_d_i             (usb_tx_d),
 881:     .usb_tx_se0_i           (usb_tx_se0),
 882:     .usb_tx_oe_i            (usb_tx_oe),
 883:     .usb_pwr_sense_o        (usb_pwr_sense),
 884:     .usb_pullup_en_i        (usb_pullup_en),
 885:     .usb_suspend_i          (usb_event_link_suspend)
 886:   );
 887: 
 888: endmodule
 889: