|
@@ -9,26 +9,26 @@
|
|
|
// License: LGPL
|
|
|
//-----------------------------------------------------------------
|
|
|
//
|
|
|
-// This source file may be used and distributed without
|
|
|
-// restriction provided that this copyright statement is not
|
|
|
-// removed from the file and that any derivative work contains
|
|
|
-// the original copyright notice and the associated disclaimer.
|
|
|
+// This source file may be used and distributed without
|
|
|
+// restriction provided that this copyright statement is not
|
|
|
+// removed from the file and that any derivative work contains
|
|
|
+// the original copyright notice and the associated disclaimer.
|
|
|
//
|
|
|
-// This source file is free software; you can redistribute it
|
|
|
-// and/or modify it under the terms of the GNU Lesser General
|
|
|
-// Public License as published by the Free Software Foundation;
|
|
|
-// either version 2.1 of the License, or (at your option) any
|
|
|
+// This source file is free software; you can redistribute it
|
|
|
+// and/or modify it under the terms of the GNU Lesser General
|
|
|
+// Public License as published by the Free Software Foundation;
|
|
|
+// either version 2.1 of the License, or (at your option) any
|
|
|
// later version.
|
|
|
//
|
|
|
-// This source is distributed in the hope that it will be
|
|
|
-// useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
|
-// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
-// PURPOSE. See the GNU Lesser General Public License for more
|
|
|
+// This source is distributed in the hope that it will be
|
|
|
+// useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
|
+// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
+// PURPOSE. See the GNU Lesser General Public License for more
|
|
|
// details.
|
|
|
//
|
|
|
-// You should have received a copy of the GNU Lesser General
|
|
|
-// Public License along with this source; if not, write to the
|
|
|
-// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
|
+// You should have received a copy of the GNU Lesser General
|
|
|
+// Public License along with this source; if not, write to the
|
|
|
+// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
|
// Boston, MA 02111-1307 USA
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
@@ -37,6 +37,12 @@
|
|
|
//-----------------------------------------------------------------
|
|
|
|
|
|
package usb_endpoint_types;
|
|
|
+ // Endpoint channel configuration (normally static)
|
|
|
+ typedef struct {
|
|
|
+ logic [3:0] ep_num;
|
|
|
+ logic [3:0] ep_mask;
|
|
|
+ } usb_ep_c_t;
|
|
|
+
|
|
|
// Downstream data
|
|
|
typedef struct {
|
|
|
logic ep_stall;
|
|
@@ -49,13 +55,15 @@ package usb_endpoint_types;
|
|
|
logic tx_data_strb;
|
|
|
logic [7:0] tx_data;
|
|
|
logic tx_data_last;
|
|
|
- } d_t;
|
|
|
+ } usb_ep_d_t;
|
|
|
|
|
|
// Per-endpoint upstream data
|
|
|
typedef struct {
|
|
|
+ logic ep_selected;
|
|
|
logic rx_valid;
|
|
|
logic tx_data_accept;
|
|
|
- } u_t;
|
|
|
+ } usb_ep_u_t;
|
|
|
+
|
|
|
// Upstream data, shared between all endpoints; included here
|
|
|
// to make the interface complete. If suitable for the upstream
|
|
|
// device core, however, they do not need to be multiplexed.
|
|
@@ -65,67 +73,80 @@ package usb_endpoint_types;
|
|
|
logic rx_strb;
|
|
|
logic rx_last;
|
|
|
logic rx_crc_err;
|
|
|
- } uc_t;
|
|
|
+ logic [3:0] ep_select; // Currently selected endpoint
|
|
|
+ logic ep_select_rx; // Selected for read
|
|
|
+ } usb_ep_uc_t;
|
|
|
endpackage
|
|
|
|
|
|
interface usb_endpoint;
|
|
|
import usb_endpoint_types::*;
|
|
|
-
|
|
|
- d_t d;
|
|
|
- u_t u;
|
|
|
- uc_t uc;
|
|
|
+
|
|
|
+ usb_ep_c_t c;
|
|
|
+ usb_ep_d_t d;
|
|
|
+ usb_ep_u_t u;
|
|
|
+ usb_ep_uc_t uc;
|
|
|
|
|
|
// Upstream interface (toward application)
|
|
|
modport ustr (
|
|
|
- input d,
|
|
|
- output u,
|
|
|
- output uc
|
|
|
+ input c,
|
|
|
+ input d,
|
|
|
+ output u,
|
|
|
+ output uc
|
|
|
);
|
|
|
|
|
|
// Downstream interface (toward PHY)
|
|
|
modport dstr (
|
|
|
- output d,
|
|
|
- input u,
|
|
|
- input uc
|
|
|
+ output c,
|
|
|
+ output d,
|
|
|
+ input u,
|
|
|
+ input uc
|
|
|
);
|
|
|
endinterface // usb_endpoint
|
|
|
|
|
|
module usbf_endpoint_mux
|
|
|
- #(parameter endpoints = 4, epbits = 4)
|
|
|
+ #(parameter endpoint_channels = 4)
|
|
|
(
|
|
|
- input valid_i,
|
|
|
- input [epbits-1:0] ep_select_i,
|
|
|
- usb_endpoint.ustr ep_u [0:endpoints-1],
|
|
|
- usb_endpoint.dstr ep_d
|
|
|
+ input valid_i,
|
|
|
+ input [3:0] ep_select_i,
|
|
|
+ input ep_select_rx_i,
|
|
|
+ usb_endpoint.ustr ep_u [0:endpoint_channels-1],
|
|
|
+ usb_endpoint.dstr ep_d
|
|
|
);
|
|
|
|
|
|
import usb_endpoint_types::*;
|
|
|
|
|
|
- wire [endpoints-1:0] selected = valid_i << ep_select_i;
|
|
|
-
|
|
|
// Quartus seems to need these intermediate variables
|
|
|
// to be able to use structures here.
|
|
|
- d_t u_d [0:endpoints-1];
|
|
|
- u_t ep_d_u;
|
|
|
- uc_t ep_d_uc;
|
|
|
+ usb_ep_d_t u_d [0:endpoint_channels-1];
|
|
|
+ usb_ep_u_t ep_d_u;
|
|
|
+ usb_ep_uc_t ep_d_uc;
|
|
|
+
|
|
|
+ logic [endpoint_channels-1:-1] selected;
|
|
|
+ assign selected[-1] = ~valid_i; // If not valid, prevents selection
|
|
|
|
|
|
always_comb
|
|
|
begin
|
|
|
- ep_d_u = ep_d.u;
|
|
|
- ep_d_uc = ep_d.uc;
|
|
|
-
|
|
|
+ ep_d_u = ep_d.u;
|
|
|
+ ep_d_u.ep_selected = 1'b1;
|
|
|
+ ep_d_uc = ep_d.uc;
|
|
|
+
|
|
|
+ ep_d.c = '{ default:'bx }; // Irrelevant
|
|
|
ep_d.d = '{ default:'b0 };
|
|
|
- for (int j = 0; j < endpoints; j++)
|
|
|
+ for (int j = 0; j < endpoint_channels; j++)
|
|
|
if (selected[j])
|
|
|
ep_d.d = u_d[j];
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
generate
|
|
|
- genvar i;
|
|
|
- for (i = 0; i < endpoints; i++)
|
|
|
+ genvar i;
|
|
|
+ for (i = 0; i < endpoint_channels; i++)
|
|
|
begin : mux
|
|
|
always_comb
|
|
|
begin
|
|
|
+ selected[i] = ~|selected[i-1:-1] &&
|
|
|
+ ((ep_select_i & ep_u[i].c.ep_mask) ==
|
|
|
+ ep_u[i].c.ep_num);
|
|
|
+
|
|
|
ep_u[i].uc = ep_d_uc;
|
|
|
if (selected[i])
|
|
|
ep_u[i].u = ep_d_u;
|
|
@@ -139,7 +160,7 @@ module usbf_endpoint_mux
|
|
|
endmodule
|
|
|
|
|
|
module usbf_device_core
|
|
|
- #(parameter endpoints = 4)
|
|
|
+ #(parameter endpoint_channels = 1)
|
|
|
(
|
|
|
// Inputs
|
|
|
input clk_i
|
|
@@ -155,7 +176,7 @@ module usbf_device_core
|
|
|
,input reg_int_en_sof_i
|
|
|
,input reg_sts_rst_clr_i
|
|
|
,input [ 6:0] reg_dev_addr_i
|
|
|
-
|
|
|
+
|
|
|
// Outputs
|
|
|
,output intr_o
|
|
|
,output [ 7:0] utmi_data_o
|
|
@@ -164,11 +185,11 @@ module usbf_device_core
|
|
|
,output [ 10:0] reg_sts_frame_num_o
|
|
|
|
|
|
// Endpoint interfaces
|
|
|
- ,usb_endpoint.ustr ep[0:endpoints-1]
|
|
|
+ ,usb_endpoint.ustr ep[0:endpoint_channels-1]
|
|
|
);
|
|
|
|
|
|
genvar e;
|
|
|
-
|
|
|
+
|
|
|
//-----------------------------------------------------------------
|
|
|
// Defines:
|
|
|
//-----------------------------------------------------------------
|
|
@@ -199,7 +220,7 @@ module usbf_device_core
|
|
|
begin
|
|
|
if (!se0_cnt_q[`USB_RESET_CNT_W-1])
|
|
|
se0_cnt_q <= se0_cnt_q + `USB_RESET_CNT_W'd1;
|
|
|
- end
|
|
|
+ end
|
|
|
else
|
|
|
se0_cnt_q <= `USB_RESET_CNT_W'b0;
|
|
|
|
|
@@ -234,17 +255,17 @@ module usbf_device_core
|
|
|
|
|
|
reg tx_data_valid_r;
|
|
|
reg tx_data_strb_r;
|
|
|
- reg [7:0] tx_data_r;
|
|
|
- reg tx_data_last_r;
|
|
|
+ reg [7:0] tx_data_r;
|
|
|
+ reg tx_data_last_r;
|
|
|
wire tx_data_accept_w;
|
|
|
-
|
|
|
- wire [7:0] rx_data_w;
|
|
|
- wire rx_strb_w;
|
|
|
- wire rx_last_w;
|
|
|
+
|
|
|
+ wire [7:0] rx_data_w;
|
|
|
+ wire rx_strb_w;
|
|
|
+ wire rx_last_w;
|
|
|
wire rx_crc_err_w;
|
|
|
|
|
|
- reg tx_valid_q;
|
|
|
- reg [7:0] tx_pid_q;
|
|
|
+ reg tx_valid_q;
|
|
|
+ reg [7:0] tx_pid_q;
|
|
|
wire tx_accept_w;
|
|
|
|
|
|
reg rx_space_q;
|
|
@@ -260,8 +281,8 @@ module usbf_device_core
|
|
|
reg rx_setup_q;
|
|
|
|
|
|
// Note: these registers are forced to zero for invalid endpoints
|
|
|
- reg [usb_ep_max:0] out_data_bit_q;
|
|
|
- reg [usb_ep_max:0] in_data_bit_q;
|
|
|
+ reg [usb_ep_max:0] out_data_bit_q;
|
|
|
+ reg [usb_ep_max:0] in_data_bit_q;
|
|
|
|
|
|
reg [`USB_DEV_W-1:0] current_addr_q;
|
|
|
|
|
@@ -270,18 +291,19 @@ module usbf_device_core
|
|
|
//-----------------------------------------------------------------
|
|
|
usb_endpoint ept (); // Endpoint selected by token
|
|
|
|
|
|
- usbf_endpoint_mux #(.endpoints(endpoints), .epbits(`USB_EP_W))
|
|
|
+ usbf_endpoint_mux #(.endpoint_channels(endpoint_channels))
|
|
|
u_endpoint_mux
|
|
|
(
|
|
|
.valid_i ( ~rst_i & ~usb_rst_w ),
|
|
|
.ep_select_i ( token_ep_w ),
|
|
|
+ .ep_select_rx_i ( token_pid_w == `PID_IN || token_pid_w == `PID_PING ),
|
|
|
.ep_u ( ep ),
|
|
|
.ep_d ( ept.dstr )
|
|
|
);
|
|
|
|
|
|
assign ep_stall_r = ept.d.ep_stall;
|
|
|
assign ep_iso_r = ept.d.ep_iso;
|
|
|
-
|
|
|
+
|
|
|
//-----------------------------------------------------------------
|
|
|
// SIE - TX
|
|
|
//-----------------------------------------------------------------
|
|
@@ -290,20 +312,20 @@ module usbf_device_core
|
|
|
(
|
|
|
.clk_i(clk_i),
|
|
|
.rst_i(rst_i),
|
|
|
-
|
|
|
+
|
|
|
.enable_i(~usb_rst_w),
|
|
|
.chirp_i(reg_chirp_en_i),
|
|
|
-
|
|
|
+
|
|
|
// UTMI Interface
|
|
|
.utmi_data_o(utmi_data_o),
|
|
|
.utmi_txvalid_o(utmi_txvalid_o),
|
|
|
.utmi_txready_i(utmi_txready_i),
|
|
|
-
|
|
|
+
|
|
|
// Request
|
|
|
.tx_valid_i(tx_valid_q),
|
|
|
.tx_pid_i(tx_pid_q),
|
|
|
.tx_accept_o(tx_accept_w),
|
|
|
-
|
|
|
+
|
|
|
// Data
|
|
|
.data_valid_i(tx_data_valid_r),
|
|
|
.data_strb_i(tx_data_strb_r),
|
|
@@ -328,33 +350,33 @@ module usbf_device_core
|
|
|
(
|
|
|
.clk_i(clk_i),
|
|
|
.rst_i(rst_i),
|
|
|
-
|
|
|
+
|
|
|
.enable_i(~usb_rst_w && ~reg_chirp_en_i),
|
|
|
-
|
|
|
+
|
|
|
// UTMI Interface
|
|
|
.utmi_data_i(utmi_data_i),
|
|
|
.utmi_rxvalid_i(utmi_rxvalid_i),
|
|
|
.utmi_rxactive_i(utmi_rxactive_i),
|
|
|
-
|
|
|
+
|
|
|
.current_addr_i(current_addr_q),
|
|
|
-
|
|
|
+
|
|
|
.pid_o(token_pid_w),
|
|
|
-
|
|
|
+
|
|
|
.frame_valid_o(frame_valid_w),
|
|
|
.frame_number_o(reg_sts_frame_num_o),
|
|
|
-
|
|
|
+
|
|
|
.token_valid_o(token_valid_w),
|
|
|
.token_addr_o(token_dev_w),
|
|
|
.token_ep_o(token_ep_w),
|
|
|
.token_crc_err_o(),
|
|
|
-
|
|
|
+
|
|
|
.handshake_valid_o(rx_handshake_w),
|
|
|
-
|
|
|
+
|
|
|
.data_valid_o(rx_data_valid_w),
|
|
|
.data_strb_o(rx_strb_w),
|
|
|
.data_o(rx_data_w),
|
|
|
.data_last_o(rx_last_w),
|
|
|
-
|
|
|
+
|
|
|
.data_complete_o(rx_data_complete_w),
|
|
|
.data_crc_err_o(rx_crc_err_w)
|
|
|
);
|
|
@@ -374,7 +396,7 @@ module usbf_device_core
|
|
|
assign ept.uc.rx_strb = rx_strb_w;
|
|
|
assign ept.uc.rx_last = rx_last_w;
|
|
|
assign ept.uc.rx_crc_err = rx_crc_err_w;
|
|
|
-
|
|
|
+
|
|
|
//-----------------------------------------------------------------
|
|
|
// Next state
|
|
|
//-----------------------------------------------------------------
|
|
@@ -533,7 +555,7 @@ module usbf_device_core
|
|
|
|
|
|
//-----------------------------------------
|
|
|
// USB Bus Reset (HOST->DEVICE)
|
|
|
- //-----------------------------------------
|
|
|
+ //-----------------------------------------
|
|
|
if (usb_rst_w && !reg_chirp_en_i)
|
|
|
next_state_r = STATE_RX_IDLE;
|
|
|
end
|
|
@@ -719,7 +741,7 @@ module usbf_device_core
|
|
|
wire ep0_tx_zlp_w = ep[0].d.tx_data_valid & ~ep[0].d.tx_data_strb &
|
|
|
ep[0].d.tx_data_last & ep[0].u.tx_data_accept;
|
|
|
|
|
|
- reg sent_status_zlp_q;
|
|
|
+ reg sent_status_zlp_q;
|
|
|
|
|
|
always @ (posedge clk_i or posedge rst_i)
|
|
|
if (rst_i)
|
|
@@ -751,8 +773,8 @@ module usbf_device_core
|
|
|
//-----------------------------------------------------------------
|
|
|
// Endpoint data bit toggle
|
|
|
//-----------------------------------------------------------------
|
|
|
- reg new_out_bit_r;
|
|
|
- reg new_in_bit_r;
|
|
|
+ reg new_out_bit_r;
|
|
|
+ reg new_in_bit_r;
|
|
|
|
|
|
always @ *
|
|
|
begin
|
|
@@ -829,11 +851,8 @@ module usbf_device_core
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
- if ((token_ep_w < endpoints) && ~usb_rst_w)
|
|
|
- begin
|
|
|
- out_data_bit_q[token_ep_w] <= new_out_bit_r;
|
|
|
- in_data_bit_q [token_ep_w] <= new_in_bit_r;
|
|
|
- end
|
|
|
+ out_data_bit_q[token_ep_w] <= new_out_bit_r;
|
|
|
+ in_data_bit_q [token_ep_w] <= new_in_bit_r;
|
|
|
end // else: !if(rst_i)
|
|
|
|
|
|
assign out_data_bit_r = out_data_bit_q[token_ep_w];
|
|
@@ -876,7 +895,7 @@ module usbf_device_core
|
|
|
intr_q <= 1'b1;
|
|
|
// Tx complete
|
|
|
else if (state_q == STATE_TX_DATA_COMPLETE && cfg_int_tx_r)
|
|
|
- intr_q <= 1'b1;
|
|
|
+ intr_q <= 1'b1;
|
|
|
else
|
|
|
intr_q <= 1'b0;
|
|
|
|