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