|
@@ -34,42 +34,303 @@
|
|
|
// Boston, MA 02111-1307 USA
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
-module usb_cdc_core
|
|
|
+// Multiport CDC interface
|
|
|
+//
|
|
|
+// Each channel contains the following registers seen from the CPU:
|
|
|
+//
|
|
|
+// 0 - RW - FIFO read/write data register
|
|
|
+// 1 - RW - watermark control
|
|
|
+// 3:1 - transmit FIFO low watermark (resets to 1/4)
|
|
|
+// 7:5 - transmit FIFO high watermark (resets to 3/4)
|
|
|
+// 11:9 - receive FIFO low watermark (resets to 1/4)
|
|
|
+// 15:13 - receive FIFO high watermark (resets to 3/4)
|
|
|
+// 2 - RO - status register (some bits W1C)
|
|
|
+// 0 - transmit FIFO empty
|
|
|
+// 1 - transmit FIFO <= low watermark
|
|
|
+// 2 - transmit FIFO >= high watermark
|
|
|
+// 3 - transmit FIFO full
|
|
|
+// 4 - receive FIFO empty
|
|
|
+// 5 - receive FIFO <= low watermark
|
|
|
+// 6 - receive FIFO >= high watermark
|
|
|
+// 7 - receive FIFO full
|
|
|
+// 8 - receive FIFO not empty after two USB frames
|
|
|
+// 9 - BREAK received (sticky, W1C)
|
|
|
+// 10 - USB device configured
|
|
|
+// 3 - RW - interrupt enable register
|
|
|
+// * - mask of corresponding status bits
|
|
|
+
|
|
|
+module usb_cdc_channel
|
|
|
+ #(parameter [3:0] data_ep_num = 4'd1,
|
|
|
+ parameter [3:0] intr_ep_num = data_ep_num+1'b1)
|
|
|
(
|
|
|
- // Inputs
|
|
|
- input clk_i
|
|
|
- ,input rst_i
|
|
|
- ,input enable_i
|
|
|
- ,input [ 7:0] utmi_data_in_i
|
|
|
- ,input utmi_txready_i
|
|
|
- ,input utmi_rxvalid_i
|
|
|
- ,input utmi_rxactive_i
|
|
|
- ,input utmi_rxerror_i
|
|
|
- ,input [ 1:0] utmi_linestate_i
|
|
|
- ,input inport_valid_i
|
|
|
- ,input [ 7:0] inport_data_i
|
|
|
- ,input outport_accept_i
|
|
|
-
|
|
|
- // Outputs
|
|
|
- ,output [ 7:0] utmi_data_out_o
|
|
|
- ,output utmi_txvalid_o
|
|
|
- ,output [ 1:0] utmi_op_mode_o
|
|
|
- ,output [ 1:0] utmi_xcvrselect_o
|
|
|
- ,output utmi_termselect_o
|
|
|
- ,output utmi_dppulldown_o
|
|
|
- ,output utmi_dmpulldown_o
|
|
|
- ,output inport_accept_o
|
|
|
- ,output outport_valid_o
|
|
|
- ,output [ 7:0] outport_data_o
|
|
|
- ,output outport_break_o,
|
|
|
-
|
|
|
// CPU bus
|
|
|
+ input rst_n,
|
|
|
input sys_clk,
|
|
|
input cpu_valid,
|
|
|
- input [15:0] cpu_addr,
|
|
|
+ input [1:0] cpu_addr,
|
|
|
output [31:0] cpu_rdata,
|
|
|
input [31:0] cpu_wdata,
|
|
|
- input [3:0] cpu_wstrb
|
|
|
+ input cpu_wstrb,
|
|
|
+ output irq,
|
|
|
+
|
|
|
+ // Core FIFO interface
|
|
|
+ input clk_i,
|
|
|
+ input rst_i,
|
|
|
+ usb_endpoint.dstr data_ep,
|
|
|
+ usb_endpoint.dstr intr_ep,
|
|
|
+
|
|
|
+ // Control signals
|
|
|
+ input recv_break_i,
|
|
|
+ output recv_break_o, // sys_clk domain, reflects the status register
|
|
|
+
|
|
|
+ // USB status
|
|
|
+ input usb_configured,
|
|
|
+
|
|
|
+ // Top of frame strobe *in sys_clk domain*
|
|
|
+ input start_of_frame_s
|
|
|
+ );
|
|
|
+
|
|
|
+ localparam fifo_size = 511;
|
|
|
+ localparam fifo_bits = $clog2(fifo_size);
|
|
|
+ localparam packet_bits = 6;
|
|
|
+ localparam packet_size = 1 << packet_bits;
|
|
|
+
|
|
|
+ // Up to four bits per watermark, but all are not necessarily
|
|
|
+ // implemented
|
|
|
+ localparam water_bits = 3;
|
|
|
+
|
|
|
+ wire fifo_access = cpu_valid & cpu_addr == 2'b00;
|
|
|
+ reg fifo_access_q;
|
|
|
+ reg fifo_read_q;
|
|
|
+
|
|
|
+ always @(posedge sys_clk)
|
|
|
+ begin
|
|
|
+ fifo_access_q <= fifo_access;
|
|
|
+ fifo_read_q <= fifo_access & ~cpu_wstrb;
|
|
|
+ end
|
|
|
+
|
|
|
+ wire txempty;
|
|
|
+ wire txfull;
|
|
|
+ wire [fifo_bits-1:0] txused;
|
|
|
+ wire [water_bits:0] txused_msb = txused[fifo_bits-1:fifo_bits-water_bits];
|
|
|
+ wire inport_empty_w;
|
|
|
+ reg inport_valid_q;
|
|
|
+
|
|
|
+ cdc_fifo txfifo (
|
|
|
+ .wrclk ( sys_clk ),
|
|
|
+ .data ( cpu_wdata[7:0] ),
|
|
|
+ .wrreq ( fifo_access & ~fifo_access_q & cpu_wstrb ),
|
|
|
+ .wrempty ( txempty ),
|
|
|
+ .wrfull ( txfull ),
|
|
|
+ .wrusedw ( txused ),
|
|
|
+
|
|
|
+ .rdclk ( clk_i ),
|
|
|
+ .q ( data_ep.d.tx_data ),
|
|
|
+ .rdreq ( ~inport_valid_q | data_ep.u.tx_data_accept ),
|
|
|
+ .rdempty ( inport_empty_w ),
|
|
|
+ .rdfull ( ),
|
|
|
+ .rdusedw ( )
|
|
|
+ );
|
|
|
+
|
|
|
+ always @(posedge clk_i or posedge rst_i)
|
|
|
+ if (rst_i)
|
|
|
+ inport_valid_q <= 1'b0;
|
|
|
+ else if ( ~inport_empty_w )
|
|
|
+ inport_valid_q <= 1'b1;
|
|
|
+ else if ( data_ep.u.tx_data_accept )
|
|
|
+ inport_valid_q <= 1'b0;
|
|
|
+
|
|
|
+ assign data_ep.d.tx_data_valid = inport_valid_q;
|
|
|
+ assign data_ep.d.tx_ready = inport_valid_q;
|
|
|
+ assign data_ep.d.tx_data_strb = inport_valid_q;
|
|
|
+
|
|
|
+ // Must terminate a transfer at the max packet size
|
|
|
+ reg [packet_bits-1:0] inport_cnt_q;
|
|
|
+ wire inport_last_w = inport_empty_w | &inport_cnt_q;
|
|
|
+
|
|
|
+ always @(posedge clk_i or posedge rst_i)
|
|
|
+ if (rst_i)
|
|
|
+ inport_cnt_q <= 'd0;
|
|
|
+ else if (inport_last_w & data_ep.u.tx_data_accept)
|
|
|
+ inport_cnt_q <= 'd0;
|
|
|
+ else if (inport_valid_q & data_ep.u.tx_data_accept)
|
|
|
+ inport_cnt_q <= inport_cnt_q + 1'b1;
|
|
|
+
|
|
|
+ assign data_ep.d.tx_data_last = inport_last_w;
|
|
|
+
|
|
|
+ wire [7:0] rdata_fifo;
|
|
|
+ wire rxempty;
|
|
|
+ wire rxfull;
|
|
|
+ wire [fifo_bits-1:0] rxused;
|
|
|
+ wire [water_bits:0] rxused_msb = rxused[fifo_bits-1:fifo_bits-water_bits];
|
|
|
+ wire [fifo_bits-1:0] outport_used_w;
|
|
|
+
|
|
|
+ wire outport_valid_w = data_ep.u.rx_valid & data_ep.uc.rx_strb;
|
|
|
+
|
|
|
+ assign data_ep.d.rx_space = outport_used_w <= fifo_size - packet_size;
|
|
|
+
|
|
|
+ cdc_fifo rxfifo (
|
|
|
+ .rdclk ( sys_clk ),
|
|
|
+ .q ( rdata_fifo ),
|
|
|
+ .rdreq ( fifo_access & ~fifo_access_q & ~cpu_wstrb ),
|
|
|
+ .rdempty ( rxempty ),
|
|
|
+ .rdfull ( rxfull ),
|
|
|
+ .rdusedw ( rxused ),
|
|
|
+
|
|
|
+ .wrclk ( clk_i ),
|
|
|
+ .data ( data_ep.uc.rx_data ),
|
|
|
+ .wrreq ( outport_valid_w ),
|
|
|
+ .wrempty ( ),
|
|
|
+ .wrfull ( ),
|
|
|
+ .wrusedw ( outport_used_w )
|
|
|
+ );
|
|
|
+
|
|
|
+ // Queued data wakeup
|
|
|
+ reg [1:0] had_rxdata;
|
|
|
+
|
|
|
+ always @(posedge sys_clk)
|
|
|
+ begin
|
|
|
+ if (start_of_frame_s)
|
|
|
+ had_rxdata <= { had_rxdata[0], 1'b1 };
|
|
|
+ if (rxempty)
|
|
|
+ had_rxdata <= 2'b00;
|
|
|
+ end
|
|
|
+
|
|
|
+ wire [15:0] status_mask = 16'b0000_0111_1111_1111; // Implemented bit mask
|
|
|
+ reg [15:0] irq_mask;
|
|
|
+ wire [ 3:0] water_mask = 4'b1111 << (4-water_bits);
|
|
|
+ wire [15:0] water_ctl_mask = {4{water_mask}};
|
|
|
+ reg [15:0] water_ctl;
|
|
|
+
|
|
|
+ wire recv_break_s;
|
|
|
+ reg recv_break_q;
|
|
|
+
|
|
|
+ synchronizer #(.width(1)) break_synchro
|
|
|
+ (
|
|
|
+ .rst_n ( rst_n ),
|
|
|
+ .clk ( sys_clk ),
|
|
|
+ .d ( recv_break_i ),
|
|
|
+ .q ( recv_break_s )
|
|
|
+ );
|
|
|
+
|
|
|
+ always @(negedge rst_n or posedge sys_clk)
|
|
|
+ if (~rst_n)
|
|
|
+ begin
|
|
|
+ water_ctl <= 16'h8787 & water_ctl_mask;
|
|
|
+ irq_mask <= 16'b0;
|
|
|
+ recv_break_q <= 1'b0;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ if (recv_break_s)
|
|
|
+ recv_break_q <= 1'b1;
|
|
|
+
|
|
|
+ if (cpu_valid & cpu_wstrb)
|
|
|
+ case (cpu_addr)
|
|
|
+ 2'b01: water_ctl <= cpu_wdata[15:0] & water_ctl_mask;
|
|
|
+ 2'b10: if (cpu_wdata[9]) recv_break_q <= 1'b0;
|
|
|
+ 2'b11: irq_mask <= cpu_wdata[15:0] & status_mask;
|
|
|
+ default: /* do nothing */;
|
|
|
+ endcase // case (cpu_addr)
|
|
|
+ end // else: !if(~rst_n)
|
|
|
+
|
|
|
+ assign recv_break_o = recv_break_q; // Available to external logic
|
|
|
+
|
|
|
+ tri0 [15:0] status;
|
|
|
+ assign status[0] = txempty;
|
|
|
+ assign status[1] = (txused_msb <= water_ctl[3:4-water_bits]);
|
|
|
+ assign status[2] = (txused_msb >= water_ctl[7:8-water_bits]);
|
|
|
+ assign status[3] = txfull;
|
|
|
+
|
|
|
+ assign status[4] = rxempty;
|
|
|
+ assign status[5] = (rxused_msb <= water_ctl[11:12-water_bits]);
|
|
|
+ assign status[6] = (rxused_msb >= water_ctl[15:16-water_bits]);
|
|
|
+ assign status[7] = rxfull;
|
|
|
+
|
|
|
+ assign status[8] = had_rxdata[1];
|
|
|
+ assign status[9] = recv_break_q;
|
|
|
+ assign status[10] = usb_configured;
|
|
|
+
|
|
|
+ assign irq = |(status & irq_mask);
|
|
|
+
|
|
|
+ always @(*)
|
|
|
+ case (cpu_addr)
|
|
|
+ 2'b00: cpu_rdata = { 24'b0, rdata_fifo };
|
|
|
+ 2'b01: cpu_rdata = { 16'b0, water_ctl };
|
|
|
+ 2'b10: cpu_rdata = { 16'b0, status };
|
|
|
+ 2'b11: cpu_rdata = { 16'b0, irq_mask };
|
|
|
+ default: cpu_rdata = 32'bx;
|
|
|
+ endcase // case (cpu_addr)
|
|
|
+
|
|
|
+ // Channel configurations
|
|
|
+ assign data_ep.c.ep_num = data_ep_num;
|
|
|
+ assign data_ep.c.ep_mask = 4'b1111;
|
|
|
+ assign intr_ep.c.ep_num = intr_ep_num;
|
|
|
+ assign intr_ep.c.ep_mask = 4'b1111;
|
|
|
+
|
|
|
+ // Data channel endpoint: unused signals
|
|
|
+ assign data_ep.d.ep_iso = 1'b0;
|
|
|
+ assign data_ep.d.cfg_int_rx = 1'b0;
|
|
|
+ assign data_ep.d.cfg_int_tx = 1'b0;
|
|
|
+ assign data_ep.d.ep_stall = 1'b0;
|
|
|
+
|
|
|
+ // Notification channel endpoint: currently never used at all
|
|
|
+ assign intr_ep.d.ep_iso = 1'b0;
|
|
|
+ assign intr_ep.d.cfg_int_rx = 1'b0;
|
|
|
+ assign intr_ep.d.cfg_int_tx = 1'b0;
|
|
|
+ assign intr_ep.d.ep_stall = 1'b0;
|
|
|
+ assign intr_ep.d.tx_ready = 1'b0;
|
|
|
+ assign intr_ep.d.tx_data_valid = 1'b0;
|
|
|
+ assign intr_ep.d.tx_data_strb = 1'b0;
|
|
|
+ assign intr_ep.d.tx_data = 8'bx;
|
|
|
+ assign intr_ep.d.tx_data_last = 1'b0;
|
|
|
+ assign intr_ep.d.rx_space = 1'b0;
|
|
|
+
|
|
|
+endmodule // usb_cdc_channel
|
|
|
+
|
|
|
+module usb_cdc_core
|
|
|
+ #( parameter [2:0] channels = 3'd1 )
|
|
|
+ (
|
|
|
+ // Inputs
|
|
|
+ input clk_i,
|
|
|
+ input rst_i,
|
|
|
+ input enable_i,
|
|
|
+ input [ 7:0] utmi_data_in_i,
|
|
|
+ input utmi_txready_i,
|
|
|
+ input utmi_rxvalid_i,
|
|
|
+ input utmi_rxactive_i,
|
|
|
+ input utmi_rxerror_i,
|
|
|
+ input [ 1:0] utmi_linestate_i,
|
|
|
+ //input inport_valid_i,
|
|
|
+ //input [ 7:0] inport_data_i,
|
|
|
+ //input outport_accept_i,
|
|
|
+
|
|
|
+ // Outputs
|
|
|
+ output [ 7:0] utmi_data_out_o,
|
|
|
+ output utmi_txvalid_o,
|
|
|
+ output [ 1:0] utmi_op_mode_o,
|
|
|
+ output [ 1:0] utmi_xcvrselect_o,
|
|
|
+ output utmi_termselect_o,
|
|
|
+ output utmi_dppulldown_o,
|
|
|
+ output utmi_dmpulldown_o,
|
|
|
+ output [channels-1:0] recv_break_o,
|
|
|
+
|
|
|
+ //output inport_accept_o,
|
|
|
+ //output outport_valid_o,
|
|
|
+ //output [ 7:0] outport_data_o,
|
|
|
+ //output outport_break_o,
|
|
|
+
|
|
|
+ // CPU bus
|
|
|
+ input rst_n,
|
|
|
+ input sys_clk,
|
|
|
+ input cpu_valid_cdc,
|
|
|
+ input cpu_valid_usbdesc,
|
|
|
+ input [31:0] cpu_addr,
|
|
|
+ output [31:0] cpu_rdata_cdc,
|
|
|
+ output [31:0] cpu_rdata_usbdesc,
|
|
|
+ input [31:0] cpu_wdata,
|
|
|
+ input [3:0] cpu_wstrb,
|
|
|
+ output [channels-1:0] irq
|
|
|
);
|
|
|
|
|
|
parameter USB_SPEED_HS = "False"; // True or False
|
|
@@ -168,7 +429,7 @@ module usb_cdc_core
|
|
|
wire usb_reset_w;
|
|
|
reg [6:0] device_addr_q;
|
|
|
|
|
|
- localparam endpoint_channels = 4;
|
|
|
+ localparam endpoint_channels = channels*2 + 1;
|
|
|
usb_endpoint usb_ep [0:endpoint_channels-1] ();
|
|
|
|
|
|
wire utmi_chirp_en_w;
|
|
@@ -391,13 +652,15 @@ module usb_cdc_core
|
|
|
//-----------------------------------------------------------------
|
|
|
// Core
|
|
|
//-----------------------------------------------------------------
|
|
|
+ wire start_of_frame_w; // Or reset, but close enough
|
|
|
+
|
|
|
usbf_device_core #(.endpoint_channels(endpoint_channels))
|
|
|
u_core
|
|
|
(
|
|
|
.clk_i(clk_i),
|
|
|
.rst_i(rst_i),
|
|
|
|
|
|
- .intr_o(),
|
|
|
+ .intr_o(start_of_frame_w),
|
|
|
|
|
|
// UTMI interface
|
|
|
.utmi_data_o(utmi_data_out_o),
|
|
@@ -519,8 +782,7 @@ module usb_cdc_core
|
|
|
reg [15:0] desc_base_addr_r;
|
|
|
reg [15:0] desc_len_r;
|
|
|
|
|
|
- reg rx_break_q;
|
|
|
- reg rx_break_r;
|
|
|
+ reg [7:0] rx_break_r;
|
|
|
|
|
|
reg addressed_q;
|
|
|
reg addressed_r;
|
|
@@ -546,13 +808,14 @@ module usb_cdc_core
|
|
|
|
|
|
always @ *
|
|
|
begin
|
|
|
- ctrl_stall_r = 1'b0;
|
|
|
- ctrl_ack_r = 1'b0;
|
|
|
- device_addr_r = device_addr_q;
|
|
|
- addressed_r = addressed_q;
|
|
|
- configured_r = configured_q;
|
|
|
- set_with_data_r = set_with_data_q;
|
|
|
- rx_break_r = 1'b0;
|
|
|
+ ctrl_stall_r = 1'b0;
|
|
|
+ ctrl_ack_r = 1'b0;
|
|
|
+ ctrl_send_data_r = 1'b0;
|
|
|
+ device_addr_r = device_addr_q;
|
|
|
+ addressed_r = addressed_q;
|
|
|
+ configured_r = configured_q;
|
|
|
+ set_with_data_r = set_with_data_q;
|
|
|
+ rx_break_r = 8'b0;
|
|
|
|
|
|
if (setup_valid_q)
|
|
|
begin
|
|
@@ -596,15 +859,10 @@ module usb_cdc_core
|
|
|
begin
|
|
|
$display("SET_CONF: Configuration %x", wValue_w);
|
|
|
|
|
|
- if (wValue_w == 16'd0)
|
|
|
- begin
|
|
|
- configured_r = 1'b0;
|
|
|
- ctrl_ack_r = setup_set_w && setup_no_data_w;
|
|
|
- end
|
|
|
// Only support one configuration for now
|
|
|
- else if (wValue_w == 16'd1)
|
|
|
+ if (wValue_w < 16'd2)
|
|
|
begin
|
|
|
- configured_r = 1'b1;
|
|
|
+ configured_r = wValue_w[0];
|
|
|
ctrl_ack_r = setup_set_w && setup_no_data_w;
|
|
|
end
|
|
|
else
|
|
@@ -615,14 +873,16 @@ module usb_cdc_core
|
|
|
$display("GET_INTERFACE");
|
|
|
ctrl_stall_r = 1'b1;
|
|
|
end
|
|
|
+//`ifdef HANDLE_SET_INTERFACE
|
|
|
`REQ_SET_INTERFACE:
|
|
|
begin
|
|
|
$display("SET_INTERFACE: %x %x", wValue_w, wIndex_w);
|
|
|
- if (wValue_w == 16'd0 && wIndex_w == 16'd0)
|
|
|
+ if (wValue_w == 16'd0 && wIndex_w < (channels << 1))
|
|
|
ctrl_ack_r = setup_set_w && setup_no_data_w;
|
|
|
else
|
|
|
ctrl_stall_r = 1'b1;
|
|
|
end
|
|
|
+//`endif
|
|
|
default:
|
|
|
begin
|
|
|
ctrl_stall_r = 1'b1;
|
|
@@ -647,7 +907,7 @@ module usb_cdc_core
|
|
|
end
|
|
|
`CDC_SEND_BREAK:
|
|
|
begin
|
|
|
- rx_break_r = (wValue_w != 16'd0);
|
|
|
+ rx_break_r[wIndex_w[3:1]] = wIndex_w[0] & |wValue_w;
|
|
|
end
|
|
|
default:
|
|
|
begin
|
|
@@ -672,7 +932,6 @@ module usb_cdc_core
|
|
|
addressed_q <= 1'b0;
|
|
|
configured_q <= 1'b0;
|
|
|
set_with_data_q <= 1'b0;
|
|
|
- rx_break_q <= 1'b0;
|
|
|
end
|
|
|
else if (usb_reset_w)
|
|
|
begin
|
|
@@ -680,7 +939,6 @@ module usb_cdc_core
|
|
|
addressed_q <= 1'b0;
|
|
|
configured_q <= 1'b0;
|
|
|
set_with_data_q <= 1'b0;
|
|
|
- rx_break_q <= 1'b0;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
@@ -688,7 +946,6 @@ module usb_cdc_core
|
|
|
addressed_q <= addressed_r;
|
|
|
configured_q <= configured_r;
|
|
|
set_with_data_q <= set_with_data_r;
|
|
|
- rx_break_q <= rx_break_r;
|
|
|
end
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
@@ -874,126 +1131,85 @@ module usb_cdc_core
|
|
|
assign usb_ep[0].d.tx_data_last = ctrl_txlast_q;
|
|
|
assign usb_ep[0].d.ep_stall = ctrl_txstall_q;
|
|
|
|
|
|
+ // Unused endpoint 0 signals
|
|
|
+ assign usb_ep[0].d.ep_iso = 1'b0;
|
|
|
+ assign usb_ep[0].d.cfg_int_rx = 1'b0;
|
|
|
+ assign usb_ep[0].d.cfg_int_tx = 1'b0;
|
|
|
+
|
|
|
//-----------------------------------------------------------------
|
|
|
// Descriptor ROM
|
|
|
//-----------------------------------------------------------------
|
|
|
+ wire [7:0] rdata_usbdesc;
|
|
|
+
|
|
|
usb_desc_rom
|
|
|
u_rom
|
|
|
(
|
|
|
- .clk (clk_i),
|
|
|
- .usb_addr (desc_addr_r),
|
|
|
- .usb_rdata (desc_data_w),
|
|
|
+ .clk ( clk_i ),
|
|
|
+ .usb_addr ( desc_addr_r ),
|
|
|
+ .usb_rdata ( desc_data_w ),
|
|
|
|
|
|
// CPU interface for modifications
|
|
|
- .cpu_clk (sys_clk),
|
|
|
- .cpu_addr (cpu_addr),
|
|
|
- .cpu_rdata (cpu_rdata[7:0]),
|
|
|
- .cpu_wdata (cpu_wdata[7:0]),
|
|
|
- .cpu_wren (cpu_valid & cpu_wstrb[0])
|
|
|
+ .cpu_clk ( sys_clk ),
|
|
|
+ .cpu_addr ( cpu_addr[17:2] ),
|
|
|
+ .cpu_rdata ( cpu_rdata_usbdesc[7:0] ),
|
|
|
+ .cpu_wdata ( cpu_wdata[7:0] ),
|
|
|
+ .cpu_wren ( cpu_valid_usbdesc & cpu_wstrb[0] )
|
|
|
);
|
|
|
- assign cpu_rdata[31:8] = 24'bx;
|
|
|
-
|
|
|
- //-----------------------------------------------------------------
|
|
|
- // Unused Endpoint Downstream Signals
|
|
|
- //-----------------------------------------------------------------
|
|
|
-
|
|
|
- assign usb_ep[0].d.ep_iso = 1'b0;
|
|
|
- assign usb_ep[0].d.cfg_int_rx = 1'b0;
|
|
|
- assign usb_ep[0].d.cfg_int_tx = 1'b0;
|
|
|
|
|
|
- // EP1: unused
|
|
|
- assign usb_ep[1].d.ep_iso = 1'b0;
|
|
|
- assign usb_ep[1].d.cfg_int_rx = 1'b0;
|
|
|
- assign usb_ep[1].d.cfg_int_tx = 1'b0;
|
|
|
- assign usb_ep[1].d.ep_stall = 1'b1;
|
|
|
- assign usb_ep[1].d.tx_ready = 1'b0;
|
|
|
- assign usb_ep[1].d.tx_data_valid = 1'b0;
|
|
|
- assign usb_ep[1].d.tx_data_strb = 1'b0;
|
|
|
- assign usb_ep[1].d.tx_data = 8'bx;
|
|
|
- assign usb_ep[1].d.tx_data_last = 1'b0;
|
|
|
- assign usb_ep[1].d.rx_space = 1'b0;
|
|
|
-
|
|
|
- // EP2: data channel
|
|
|
- assign usb_ep[2].d.ep_iso = 1'b0;
|
|
|
- assign usb_ep[2].d.cfg_int_rx = 1'b0;
|
|
|
- assign usb_ep[2].d.cfg_int_tx = 1'b0;
|
|
|
- assign usb_ep[2].d.ep_stall = 1'b0;
|
|
|
-
|
|
|
- // EP3: notification output
|
|
|
- assign usb_ep[3].d.ep_iso = 1'b0;
|
|
|
- assign usb_ep[3].d.cfg_int_rx = 1'b0;
|
|
|
- assign usb_ep[3].d.cfg_int_tx = 1'b0;
|
|
|
- assign usb_ep[3].d.ep_stall = 1'b0;
|
|
|
- assign usb_ep[3].d.tx_ready = 1'b0;
|
|
|
- assign usb_ep[3].d.tx_data_valid = 1'b0;
|
|
|
- assign usb_ep[3].d.tx_data_strb = 1'b0;
|
|
|
- assign usb_ep[3].d.tx_data = 8'bx;
|
|
|
- assign usb_ep[3].d.tx_data_last = 1'b0;
|
|
|
- assign usb_ep[3].d.rx_space = 1'b0;
|
|
|
+ assign cpu_rdata_usbdesc[31:8] = 24'b0;
|
|
|
|
|
|
//-----------------------------------------------------------------
|
|
|
- // Stream endpoint channel configuration
|
|
|
+ // Channel streaming interfaces and CPU interfaces
|
|
|
//-----------------------------------------------------------------
|
|
|
- assign usb_ep[1].c.ep_num = 4'd1;
|
|
|
- assign usb_ep[1].c.ep_mask = 4'b1111;
|
|
|
- assign usb_ep[2].c.ep_num = 4'd2;
|
|
|
- assign usb_ep[2].c.ep_mask = 4'b1111;
|
|
|
- assign usb_ep[3].c.ep_num = 4'd3;
|
|
|
- assign usb_ep[3].c.ep_mask = 4'b1111;
|
|
|
|
|
|
- //-----------------------------------------------------------------
|
|
|
- // Stream I/O
|
|
|
- //-----------------------------------------------------------------
|
|
|
- reg inport_valid_q;
|
|
|
- reg [7:0] inport_data_q;
|
|
|
- reg [10:0] inport_cnt_q;
|
|
|
- reg outport_break_q;
|
|
|
+ wire start_of_frame_ws;
|
|
|
+ reg start_of_frame_q;
|
|
|
|
|
|
- always @ (posedge clk_i or posedge rst_i)
|
|
|
- if (rst_i)
|
|
|
- begin
|
|
|
- inport_valid_q <= 1'b0;
|
|
|
- inport_data_q <= 8'b0;
|
|
|
- end
|
|
|
- else if (inport_accept_o)
|
|
|
- begin
|
|
|
- inport_valid_q <= inport_valid_i;
|
|
|
- inport_data_q <= inport_data_i;
|
|
|
- end
|
|
|
+ synchronizer #(.width(1))
|
|
|
+ sof_sync (
|
|
|
+ .rst_n ( 1'b1 ),
|
|
|
+ .clk ( sys_clk ),
|
|
|
+ .d ( start_of_frame_w ),
|
|
|
+ .q ( start_of_frame_ws )
|
|
|
+ );
|
|
|
|
|
|
- wire [10:0] max_packet_w = usb_hs_w ? 11'd511 : 11'd63;
|
|
|
- wire inport_last_w = !inport_valid_i || (inport_cnt_q == max_packet_w);
|
|
|
+ always @(posedge sys_clk)
|
|
|
+ start_of_frame_q <= start_of_frame_ws;
|
|
|
|
|
|
- always @ (posedge clk_i or posedge rst_i)
|
|
|
- if (rst_i)
|
|
|
- inport_cnt_q <= 11'b0;
|
|
|
- else if (inport_last_w && usb_ep[2].u.tx_data_accept)
|
|
|
- inport_cnt_q <= 11'b0;
|
|
|
- else if (inport_valid_q && usb_ep[2].u.tx_data_accept)
|
|
|
- inport_cnt_q <= inport_cnt_q + 11'd1;
|
|
|
-
|
|
|
- assign usb_ep[2].d.tx_data_valid = inport_valid_q;
|
|
|
- assign usb_ep[2].d.tx_ready = inport_valid_q;
|
|
|
- assign usb_ep[2].d.tx_data_strb = inport_valid_q;
|
|
|
- assign usb_ep[2].d.tx_data = inport_data_q;
|
|
|
- assign usb_ep[2].d.tx_data_last = inport_last_w;
|
|
|
+ wire start_of_frame_s = start_of_frame_ws & ~start_of_frame_q;
|
|
|
|
|
|
- assign inport_accept_o = !inport_valid_q | usb_ep[2].u.tx_data_accept;
|
|
|
+ tri0 [31:0] rdata_chan[0:7];
|
|
|
|
|
|
- assign outport_valid_o = usb_ep[2].u.rx_valid && usb_ep[2].uc.rx_strb;
|
|
|
- assign outport_data_o = usb_ep[2].uc.rx_data;
|
|
|
- assign usb_ep[2].d.rx_space = outport_accept_i;
|
|
|
-
|
|
|
- always @(posedge clk_i or posedge rst_i)
|
|
|
- if (rst_i)
|
|
|
- outport_break_q <= 1'b0;
|
|
|
- else
|
|
|
- outport_break_q <= rx_break_q |
|
|
|
- (outport_break_q &
|
|
|
- ~setup_set_w &
|
|
|
- ~outport_valid_o &
|
|
|
- ~(inport_valid_q & usb_ep[2].u.tx_data_accept));
|
|
|
+ generate
|
|
|
+ genvar cn;
|
|
|
+ for (cn = 0; cn < channels; cn++)
|
|
|
+ begin : chan
|
|
|
+ usb_cdc_channel #(.data_ep_num ( cn*2+1 ),
|
|
|
+ .intr_ep_num ( cn*2+2 ))
|
|
|
+ cchan (
|
|
|
+ .rst_n ( rst_n ),
|
|
|
+ .sys_clk ( sys_clk ),
|
|
|
+ .cpu_valid ( cpu_valid_cdc & cpu_addr[6:4] == cn ),
|
|
|
+ .cpu_addr ( cpu_addr[3:2] ),
|
|
|
+ .cpu_rdata ( rdata_chan[cn] ),
|
|
|
+ .cpu_wdata ( cpu_wdata ),
|
|
|
+ .cpu_wstrb ( cpu_wstrb[0] ),
|
|
|
+ .irq ( irq[cn] ),
|
|
|
+
|
|
|
+ .clk_i ( clk_i ),
|
|
|
+ .rst_i ( rst_i ),
|
|
|
+ .data_ep ( usb_ep[cn*2+1].dstr ),
|
|
|
+ .intr_ep ( usb_ep[cn*2+2].dstr ),
|
|
|
+
|
|
|
+ .usb_configured ( configured_q ),
|
|
|
+
|
|
|
+ .recv_break_i ( rx_break_r[cn] ),
|
|
|
+ .recv_break_o ( recv_break_o[cn] ),
|
|
|
+ .start_of_frame_s ( start_of_frame_s )
|
|
|
+ );
|
|
|
+ end // block: chan
|
|
|
+ endgenerate
|
|
|
|
|
|
- assign outport_break_o = outport_break_q;
|
|
|
+ assign cpu_rdata_cdc = rdata_chan[cpu_addr[6:4]];
|
|
|
|
|
|
endmodule
|