../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: