|  | @@ -0,0 +1,1116 @@
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +//                       USB Serial Port
 | 
	
		
			
				|  |  | +//                            V0.1
 | 
	
		
			
				|  |  | +//                     Ultra-Embedded.com
 | 
	
		
			
				|  |  | +//                       Copyright 2020
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +//                 Email: admin@ultra-embedded.com
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +//                         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 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 
 | 
	
		
			
				|  |  | +// 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, 
 | 
	
		
			
				|  |  | +// Boston, MA  02111-1307  USA
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +//                          Generated File
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +module usb_cdc_core
 | 
	
		
			
				|  |  | +(
 | 
	
		
			
				|  |  | +    // 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
 | 
	
		
			
				|  |  | +);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +parameter USB_SPEED_HS = "False"; // True or False
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Defines
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Device class
 | 
	
		
			
				|  |  | +`define DEV_CLASS_RESERVED              8'h00
 | 
	
		
			
				|  |  | +`define DEV_CLASS_AUDIO                 8'h01
 | 
	
		
			
				|  |  | +`define DEV_CLASS_COMMS                 8'h02
 | 
	
		
			
				|  |  | +`define DEV_CLASS_HID                   8'h03
 | 
	
		
			
				|  |  | +`define DEV_CLASS_MONITOR               8'h04
 | 
	
		
			
				|  |  | +`define DEV_CLASS_PHY_IF                8'h05
 | 
	
		
			
				|  |  | +`define DEV_CLASS_POWER                 8'h06
 | 
	
		
			
				|  |  | +`define DEV_CLASS_PRINTER               8'h07
 | 
	
		
			
				|  |  | +`define DEV_CLASS_STORAGE               8'h08
 | 
	
		
			
				|  |  | +`define DEV_CLASS_HUB                   8'h09
 | 
	
		
			
				|  |  | +`define DEV_CLASS_TMC                   8'hFE
 | 
	
		
			
				|  |  | +`define DEV_CLASS_VENDOR_CUSTOM         8'hFF
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Standard requests (via SETUP packets)
 | 
	
		
			
				|  |  | +`define REQ_GET_STATUS                  8'h00
 | 
	
		
			
				|  |  | +`define REQ_CLEAR_FEATURE               8'h01
 | 
	
		
			
				|  |  | +`define REQ_SET_FEATURE                 8'h03
 | 
	
		
			
				|  |  | +`define REQ_SET_ADDRESS                 8'h05
 | 
	
		
			
				|  |  | +`define REQ_GET_DESCRIPTOR              8'h06
 | 
	
		
			
				|  |  | +`define REQ_SET_DESCRIPTOR              8'h07
 | 
	
		
			
				|  |  | +`define REQ_GET_CONFIGURATION           8'h08
 | 
	
		
			
				|  |  | +`define REQ_SET_CONFIGURATION           8'h09
 | 
	
		
			
				|  |  | +`define REQ_GET_INTERFACE               8'h0A
 | 
	
		
			
				|  |  | +`define REQ_SET_INTERFACE               8'h0B
 | 
	
		
			
				|  |  | +`define REQ_SYNC_FRAME                  8'h0C
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Descriptor types
 | 
	
		
			
				|  |  | +`define DESC_DEVICE                     8'h01
 | 
	
		
			
				|  |  | +`define DESC_CONFIGURATION              8'h02
 | 
	
		
			
				|  |  | +`define DESC_STRING                     8'h03
 | 
	
		
			
				|  |  | +`define DESC_INTERFACE                  8'h04
 | 
	
		
			
				|  |  | +`define DESC_ENDPOINT                   8'h05
 | 
	
		
			
				|  |  | +`define DESC_DEV_QUALIFIER              8'h06
 | 
	
		
			
				|  |  | +`define DESC_OTHER_SPEED_CONF           8'h07
 | 
	
		
			
				|  |  | +`define DESC_IF_POWER                   8'h08
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Endpoints
 | 
	
		
			
				|  |  | +`define ENDPOINT_DIR_MASK               8'h80
 | 
	
		
			
				|  |  | +`define ENDPOINT_DIR_R                  7
 | 
	
		
			
				|  |  | +`define ENDPOINT_DIR_IN                 1'b1
 | 
	
		
			
				|  |  | +`define ENDPOINT_DIR_OUT                1'b0
 | 
	
		
			
				|  |  | +`define ENDPOINT_ADDR_MASK              8'h7F
 | 
	
		
			
				|  |  | +`define ENDPOINT_TYPE_MASK              8'h3
 | 
	
		
			
				|  |  | +`define ENDPOINT_TYPE_CONTROL           0
 | 
	
		
			
				|  |  | +`define ENDPOINT_TYPE_ISO               1
 | 
	
		
			
				|  |  | +`define ENDPOINT_TYPE_BULK              2
 | 
	
		
			
				|  |  | +`define ENDPOINT_TYPE_INTERRUPT         3
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Device Requests (bmRequestType)
 | 
	
		
			
				|  |  | +`define USB_RECIPIENT_MASK              8'h1F
 | 
	
		
			
				|  |  | +`define USB_RECIPIENT_DEVICE            8'h00
 | 
	
		
			
				|  |  | +`define USB_RECIPIENT_INTERFACE         8'h01
 | 
	
		
			
				|  |  | +`define USB_RECIPIENT_ENDPOINT          8'h02
 | 
	
		
			
				|  |  | +`define USB_REQUEST_TYPE_MASK           8'h60
 | 
	
		
			
				|  |  | +`define USB_STANDARD_REQUEST            8'h00
 | 
	
		
			
				|  |  | +`define USB_CLASS_REQUEST               8'h20
 | 
	
		
			
				|  |  | +`define USB_VENDOR_REQUEST              8'h40
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// USB device addresses are 7-bits
 | 
	
		
			
				|  |  | +`define USB_ADDRESS_MASK                8'h7F
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// USB Feature Selectors
 | 
	
		
			
				|  |  | +`define USB_FEATURE_ENDPOINT_STATE      16'h0000
 | 
	
		
			
				|  |  | +`define USB_FEATURE_REMOTE_WAKEUP       16'h0001
 | 
	
		
			
				|  |  | +`define USB_FEATURE_TEST_MODE           16'h0002
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// String Descriptors
 | 
	
		
			
				|  |  | +`define UNICODE_LANGUAGE_STR_ID         8'd0
 | 
	
		
			
				|  |  | +`define MANUFACTURER_STR_ID             8'd1
 | 
	
		
			
				|  |  | +`define PRODUCT_NAME_STR_ID             8'd2
 | 
	
		
			
				|  |  | +`define SERIAL_NUM_STR_ID               8'd3
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +`define CDC_ENDPOINT_BULK_OUT           1
 | 
	
		
			
				|  |  | +`define CDC_ENDPOINT_BULK_IN            2
 | 
	
		
			
				|  |  | +`define CDC_ENDPOINT_INTR_IN            3
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +`define CDC_SEND_ENCAPSULATED_COMMAND   8'h00
 | 
	
		
			
				|  |  | +`define CDC_GET_ENCAPSULATED_RESPONSE   8'h01
 | 
	
		
			
				|  |  | +`define CDC_GET_LINE_CODING             8'h21
 | 
	
		
			
				|  |  | +`define CDC_SET_LINE_CODING             8'h20
 | 
	
		
			
				|  |  | +`define CDC_SET_CONTROL_LINE_STATE      8'h22
 | 
	
		
			
				|  |  | +`define CDC_SEND_BREAK                  8'h23
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Descriptor ROM offsets / sizes
 | 
	
		
			
				|  |  | +`define ROM_DESC_DEVICE_ADDR            8'd0
 | 
	
		
			
				|  |  | +`define ROM_DESC_DEVICE_SIZE            16'd18
 | 
	
		
			
				|  |  | +`define ROM_DESC_CONF_ADDR              8'd18
 | 
	
		
			
				|  |  | +`define ROM_DESC_CONF_SIZE              16'd67
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_LANG_ADDR          8'd85
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_LANG_SIZE          16'd4
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_MAN_ADDR           8'd89
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_MAN_SIZE           16'd30
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_PROD_ADDR          8'd119
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_PROD_SIZE          16'd30
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_SERIAL_ADDR        8'd149
 | 
	
		
			
				|  |  | +`define ROM_DESC_STR_SERIAL_SIZE        16'd14
 | 
	
		
			
				|  |  | +`define ROM_CDC_LINE_CODING_ADDR        8'd163
 | 
	
		
			
				|  |  | +`define ROM_CDC_LINE_CODING_SIZE        16'd7
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Wires
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +wire         usb_reset_w;
 | 
	
		
			
				|  |  | +reg  [6:0]   device_addr_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire         usb_ep0_tx_rd_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep0_tx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep0_tx_empty_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire         usb_ep0_rx_wr_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep0_rx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep0_rx_full_w;
 | 
	
		
			
				|  |  | +wire         usb_ep1_tx_rd_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep1_tx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep1_tx_empty_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire         usb_ep1_rx_wr_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep1_rx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep1_rx_full_w;
 | 
	
		
			
				|  |  | +wire         usb_ep2_tx_rd_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep2_tx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep2_tx_empty_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire         usb_ep2_rx_wr_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep2_rx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep2_rx_full_w;
 | 
	
		
			
				|  |  | +wire         usb_ep3_tx_rd_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep3_tx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep3_tx_empty_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire         usb_ep3_rx_wr_w;
 | 
	
		
			
				|  |  | +wire [7:0]   usb_ep3_rx_data_w;
 | 
	
		
			
				|  |  | +wire         usb_ep3_rx_full_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Rx SIE Interface (shared)
 | 
	
		
			
				|  |  | +wire        rx_strb_w;
 | 
	
		
			
				|  |  | +wire [7:0]  rx_data_w;
 | 
	
		
			
				|  |  | +wire        rx_last_w;
 | 
	
		
			
				|  |  | +wire        rx_crc_err_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// EP0 Rx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep0_rx_space_w;
 | 
	
		
			
				|  |  | +wire        ep0_rx_valid_w;
 | 
	
		
			
				|  |  | +wire        ep0_rx_setup_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// EP0 Tx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep0_tx_ready_w;
 | 
	
		
			
				|  |  | +wire        ep0_tx_data_valid_w;
 | 
	
		
			
				|  |  | +wire        ep0_tx_data_strb_w;
 | 
	
		
			
				|  |  | +wire [7:0]  ep0_tx_data_w;
 | 
	
		
			
				|  |  | +wire        ep0_tx_data_last_w;
 | 
	
		
			
				|  |  | +wire        ep0_tx_data_accept_w;
 | 
	
		
			
				|  |  | +wire        ep0_tx_stall_w;
 | 
	
		
			
				|  |  | +// EP1 Rx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep1_rx_space_w;
 | 
	
		
			
				|  |  | +wire        ep1_rx_valid_w;
 | 
	
		
			
				|  |  | +wire        ep1_rx_setup_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// EP1 Tx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep1_tx_ready_w;
 | 
	
		
			
				|  |  | +wire        ep1_tx_data_valid_w;
 | 
	
		
			
				|  |  | +wire        ep1_tx_data_strb_w;
 | 
	
		
			
				|  |  | +wire [7:0]  ep1_tx_data_w;
 | 
	
		
			
				|  |  | +wire        ep1_tx_data_last_w;
 | 
	
		
			
				|  |  | +wire        ep1_tx_data_accept_w;
 | 
	
		
			
				|  |  | +wire        ep1_tx_stall_w;
 | 
	
		
			
				|  |  | +// EP2 Rx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep2_rx_space_w;
 | 
	
		
			
				|  |  | +wire        ep2_rx_valid_w;
 | 
	
		
			
				|  |  | +wire        ep2_rx_setup_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// EP2 Tx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep2_tx_ready_w;
 | 
	
		
			
				|  |  | +wire        ep2_tx_data_valid_w;
 | 
	
		
			
				|  |  | +wire        ep2_tx_data_strb_w;
 | 
	
		
			
				|  |  | +wire [7:0]  ep2_tx_data_w;
 | 
	
		
			
				|  |  | +wire        ep2_tx_data_last_w;
 | 
	
		
			
				|  |  | +wire        ep2_tx_data_accept_w;
 | 
	
		
			
				|  |  | +wire        ep2_tx_stall_w;
 | 
	
		
			
				|  |  | +// EP3 Rx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep3_rx_space_w;
 | 
	
		
			
				|  |  | +wire        ep3_rx_valid_w;
 | 
	
		
			
				|  |  | +wire        ep3_rx_setup_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// EP3 Tx SIE Interface
 | 
	
		
			
				|  |  | +wire        ep3_tx_ready_w;
 | 
	
		
			
				|  |  | +wire        ep3_tx_data_valid_w;
 | 
	
		
			
				|  |  | +wire        ep3_tx_data_strb_w;
 | 
	
		
			
				|  |  | +wire [7:0]  ep3_tx_data_w;
 | 
	
		
			
				|  |  | +wire        ep3_tx_data_last_w;
 | 
	
		
			
				|  |  | +wire        ep3_tx_data_accept_w;
 | 
	
		
			
				|  |  | +wire        ep3_tx_stall_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire utmi_chirp_en_w;
 | 
	
		
			
				|  |  | +wire usb_hs_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Transceiver Control (high speed)
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +generate 
 | 
	
		
			
				|  |  | +if (USB_SPEED_HS == "True")
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +localparam STATE_W                       = 3;
 | 
	
		
			
				|  |  | +localparam STATE_IDLE                    = 3'd0;
 | 
	
		
			
				|  |  | +localparam STATE_WAIT_RST                = 3'd1;
 | 
	
		
			
				|  |  | +localparam STATE_SEND_CHIRP_K            = 3'd2;
 | 
	
		
			
				|  |  | +localparam STATE_WAIT_CHIRP_JK           = 3'd3;
 | 
	
		
			
				|  |  | +localparam STATE_FULLSPEED               = 3'd4;
 | 
	
		
			
				|  |  | +localparam STATE_HIGHSPEED               = 3'd5;
 | 
	
		
			
				|  |  | +reg [STATE_W-1:0] state_q;
 | 
	
		
			
				|  |  | +reg [STATE_W-1:0] next_state_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 60MHz clock rate
 | 
	
		
			
				|  |  | +`define USB_RST_W  20
 | 
	
		
			
				|  |  | +reg [`USB_RST_W-1:0] usb_rst_time_q;
 | 
	
		
			
				|  |  | +reg [7:0]            chirp_count_q;
 | 
	
		
			
				|  |  | +reg [1:0]            last_linestate_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +localparam DETACH_TIME    = 20'd60000;  // 1ms -> T0
 | 
	
		
			
				|  |  | +localparam ATTACH_FS_TIME = 20'd180000; // T0 + 3ms = T1
 | 
	
		
			
				|  |  | +localparam CHIRPK_TIME    = 20'd246000; // T1 + ~1ms
 | 
	
		
			
				|  |  | +localparam HS_RESET_TIME  = 20'd600000; // T0 + 10ms = T9
 | 
	
		
			
				|  |  | +localparam HS_CHIRP_COUNT = 8'd5;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg [  1:0]  utmi_op_mode_r;
 | 
	
		
			
				|  |  | +reg [  1:0]  utmi_xcvrselect_r;
 | 
	
		
			
				|  |  | +reg          utmi_termselect_r;
 | 
	
		
			
				|  |  | +reg          utmi_dppulldown_r;
 | 
	
		
			
				|  |  | +reg          utmi_dmpulldown_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ *
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    next_state_r = state_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Default - disconnect
 | 
	
		
			
				|  |  | +    utmi_op_mode_r    = 2'd1;
 | 
	
		
			
				|  |  | +    utmi_xcvrselect_r = 2'd0;
 | 
	
		
			
				|  |  | +    utmi_termselect_r = 1'b0;
 | 
	
		
			
				|  |  | +    utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +    utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    case (state_q)
 | 
	
		
			
				|  |  | +    STATE_IDLE:
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // Detached
 | 
	
		
			
				|  |  | +        if (enable_i && usb_rst_time_q >= DETACH_TIME)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_WAIT_RST;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    STATE_WAIT_RST:
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // Assert FS mode, check for SE0 (T0)
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd1;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b1;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Wait for SE0 (T1), send device chirp K
 | 
	
		
			
				|  |  | +        if (usb_rst_time_q >= ATTACH_FS_TIME)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_SEND_CHIRP_K;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    STATE_SEND_CHIRP_K:
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // Send chirp K
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd2;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b1;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // End of device chirp K (T2)
 | 
	
		
			
				|  |  | +        if (usb_rst_time_q >= CHIRPK_TIME)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_WAIT_CHIRP_JK;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    STATE_WAIT_CHIRP_JK:
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // Stop sending chirp K and wait for downstream port chirps
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd2;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b1;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Required number of chirps detected, move to HS mode (T7)
 | 
	
		
			
				|  |  | +        if (chirp_count_q >= HS_CHIRP_COUNT)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_HIGHSPEED;
 | 
	
		
			
				|  |  | +        // Time out waiting for chirps, fallback to FS mode
 | 
	
		
			
				|  |  | +        else if (usb_rst_time_q >= HS_RESET_TIME)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_FULLSPEED;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    STATE_FULLSPEED:
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd1;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b1;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // USB reset detected...
 | 
	
		
			
				|  |  | +        if (usb_rst_time_q >= HS_RESET_TIME && usb_reset_w)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_WAIT_RST;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    STATE_HIGHSPEED:
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // Enter HS mode
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Long SE0 - could be reset or suspend
 | 
	
		
			
				|  |  | +        // TODO: Should revert to FS mode and check...
 | 
	
		
			
				|  |  | +        if (usb_rst_time_q >= HS_RESET_TIME && usb_reset_w)
 | 
	
		
			
				|  |  | +            next_state_r = STATE_WAIT_RST;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    default:
 | 
	
		
			
				|  |  | +        ;
 | 
	
		
			
				|  |  | +    endcase
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Update state
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +    state_q   <= STATE_IDLE;
 | 
	
		
			
				|  |  | +else
 | 
	
		
			
				|  |  | +    state_q   <= next_state_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Time since T0 (start of HS reset)
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +    usb_rst_time_q <= `USB_RST_W'b0;
 | 
	
		
			
				|  |  | +// Entering wait for reset state
 | 
	
		
			
				|  |  | +else if (next_state_r == STATE_WAIT_RST && state_q != STATE_WAIT_RST)
 | 
	
		
			
				|  |  | +    usb_rst_time_q <=  `USB_RST_W'b0;
 | 
	
		
			
				|  |  | +// Waiting for reset, reset count on line state toggle
 | 
	
		
			
				|  |  | +else if (state_q == STATE_WAIT_RST && (utmi_linestate_i != 2'b00))
 | 
	
		
			
				|  |  | +    usb_rst_time_q <=  `USB_RST_W'b0;
 | 
	
		
			
				|  |  | +else if (usb_rst_time_q != {(`USB_RST_W){1'b1}})
 | 
	
		
			
				|  |  | +    usb_rst_time_q <= usb_rst_time_q + `USB_RST_W'd1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +    last_linestate_q   <= 2'b0;
 | 
	
		
			
				|  |  | +else
 | 
	
		
			
				|  |  | +    last_linestate_q   <= utmi_linestate_i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Chirp counter
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +    chirp_count_q   <= 8'b0;
 | 
	
		
			
				|  |  | +else if (state_q == STATE_SEND_CHIRP_K)
 | 
	
		
			
				|  |  | +    chirp_count_q   <= 8'b0;
 | 
	
		
			
				|  |  | +else if (state_q == STATE_WAIT_CHIRP_JK && (last_linestate_q != utmi_linestate_i) && chirp_count_q != 8'hFF)
 | 
	
		
			
				|  |  | +    chirp_count_q   <= chirp_count_q + 8'd1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign utmi_op_mode_o    = utmi_op_mode_r;
 | 
	
		
			
				|  |  | +assign utmi_xcvrselect_o = utmi_xcvrselect_r;
 | 
	
		
			
				|  |  | +assign utmi_termselect_o = utmi_termselect_r;
 | 
	
		
			
				|  |  | +assign utmi_dppulldown_o = utmi_dppulldown_r;
 | 
	
		
			
				|  |  | +assign utmi_dmpulldown_o = utmi_dmpulldown_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign utmi_chirp_en_w   = (state_q == STATE_SEND_CHIRP_K);
 | 
	
		
			
				|  |  | +assign usb_hs_w          = (state_q == STATE_HIGHSPEED);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +else
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Transceiver Control
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +reg [  1:0]  utmi_op_mode_r;
 | 
	
		
			
				|  |  | +reg [  1:0]  utmi_xcvrselect_r;
 | 
	
		
			
				|  |  | +reg          utmi_termselect_r;
 | 
	
		
			
				|  |  | +reg          utmi_dppulldown_r;
 | 
	
		
			
				|  |  | +reg          utmi_dmpulldown_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ *
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    if (enable_i)
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd1;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b1;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        utmi_op_mode_r    = 2'd1;
 | 
	
		
			
				|  |  | +        utmi_xcvrselect_r = 2'd0;
 | 
	
		
			
				|  |  | +        utmi_termselect_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dppulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +        utmi_dmpulldown_r = 1'b0;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign utmi_op_mode_o    = utmi_op_mode_r;
 | 
	
		
			
				|  |  | +assign utmi_xcvrselect_o = utmi_xcvrselect_r;
 | 
	
		
			
				|  |  | +assign utmi_termselect_o = utmi_termselect_r;
 | 
	
		
			
				|  |  | +assign utmi_dppulldown_o = utmi_dppulldown_r;
 | 
	
		
			
				|  |  | +assign utmi_dmpulldown_o = utmi_dmpulldown_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign utmi_chirp_en_w   = 1'b0;
 | 
	
		
			
				|  |  | +assign usb_hs_w          = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +endgenerate
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Core
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +usbf_device_core
 | 
	
		
			
				|  |  | +u_core
 | 
	
		
			
				|  |  | +(
 | 
	
		
			
				|  |  | +    .clk_i(clk_i),
 | 
	
		
			
				|  |  | +    .rst_i(rst_i),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    .intr_o(),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // UTMI interface
 | 
	
		
			
				|  |  | +    .utmi_data_o(utmi_data_out_o),
 | 
	
		
			
				|  |  | +    .utmi_data_i(utmi_data_in_i),
 | 
	
		
			
				|  |  | +    .utmi_txvalid_o(utmi_txvalid_o),
 | 
	
		
			
				|  |  | +    .utmi_txready_i(utmi_txready_i),
 | 
	
		
			
				|  |  | +    .utmi_rxvalid_i(utmi_rxvalid_i),
 | 
	
		
			
				|  |  | +    .utmi_rxactive_i(utmi_rxactive_i),
 | 
	
		
			
				|  |  | +    .utmi_rxerror_i(utmi_rxerror_i),
 | 
	
		
			
				|  |  | +    .utmi_linestate_i(utmi_linestate_i),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    .reg_chirp_en_i(utmi_chirp_en_w),
 | 
	
		
			
				|  |  | +    .reg_int_en_sof_i(1'b0),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    .reg_dev_addr_i(device_addr_q),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Rx SIE Interface (shared)
 | 
	
		
			
				|  |  | +    .rx_strb_o(rx_strb_w),
 | 
	
		
			
				|  |  | +    .rx_data_o(rx_data_w),
 | 
	
		
			
				|  |  | +    .rx_last_o(rx_last_w),
 | 
	
		
			
				|  |  | +    .rx_crc_err_o(rx_crc_err_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP0 Config
 | 
	
		
			
				|  |  | +    .ep0_iso_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep0_stall_i(ep0_tx_stall_w),
 | 
	
		
			
				|  |  | +    .ep0_cfg_int_rx_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep0_cfg_int_tx_i(1'b0),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP0 Rx SIE Interface
 | 
	
		
			
				|  |  | +    .ep0_rx_setup_o(ep0_rx_setup_w),
 | 
	
		
			
				|  |  | +    .ep0_rx_valid_o(ep0_rx_valid_w),
 | 
	
		
			
				|  |  | +    .ep0_rx_space_i(ep0_rx_space_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP0 Tx SIE Interface
 | 
	
		
			
				|  |  | +    .ep0_tx_ready_i(ep0_tx_ready_w),
 | 
	
		
			
				|  |  | +    .ep0_tx_data_valid_i(ep0_tx_data_valid_w),
 | 
	
		
			
				|  |  | +    .ep0_tx_data_strb_i(ep0_tx_data_strb_w),
 | 
	
		
			
				|  |  | +    .ep0_tx_data_i(ep0_tx_data_w),
 | 
	
		
			
				|  |  | +    .ep0_tx_data_last_i(ep0_tx_data_last_w),
 | 
	
		
			
				|  |  | +    .ep0_tx_data_accept_o(ep0_tx_data_accept_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP1 Config
 | 
	
		
			
				|  |  | +    .ep1_iso_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep1_stall_i(ep1_tx_stall_w),
 | 
	
		
			
				|  |  | +    .ep1_cfg_int_rx_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep1_cfg_int_tx_i(1'b0),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP1 Rx SIE Interface
 | 
	
		
			
				|  |  | +    .ep1_rx_setup_o(ep1_rx_setup_w),
 | 
	
		
			
				|  |  | +    .ep1_rx_valid_o(ep1_rx_valid_w),
 | 
	
		
			
				|  |  | +    .ep1_rx_space_i(ep1_rx_space_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP1 Tx SIE Interface
 | 
	
		
			
				|  |  | +    .ep1_tx_ready_i(ep1_tx_ready_w),
 | 
	
		
			
				|  |  | +    .ep1_tx_data_valid_i(ep1_tx_data_valid_w),
 | 
	
		
			
				|  |  | +    .ep1_tx_data_strb_i(ep1_tx_data_strb_w),
 | 
	
		
			
				|  |  | +    .ep1_tx_data_i(ep1_tx_data_w),
 | 
	
		
			
				|  |  | +    .ep1_tx_data_last_i(ep1_tx_data_last_w),
 | 
	
		
			
				|  |  | +    .ep1_tx_data_accept_o(ep1_tx_data_accept_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP2 Config
 | 
	
		
			
				|  |  | +    .ep2_iso_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep2_stall_i(ep2_tx_stall_w),
 | 
	
		
			
				|  |  | +    .ep2_cfg_int_rx_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep2_cfg_int_tx_i(1'b0),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP2 Rx SIE Interface
 | 
	
		
			
				|  |  | +    .ep2_rx_setup_o(ep2_rx_setup_w),
 | 
	
		
			
				|  |  | +    .ep2_rx_valid_o(ep2_rx_valid_w),
 | 
	
		
			
				|  |  | +    .ep2_rx_space_i(ep2_rx_space_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP2 Tx SIE Interface
 | 
	
		
			
				|  |  | +    .ep2_tx_ready_i(ep2_tx_ready_w),
 | 
	
		
			
				|  |  | +    .ep2_tx_data_valid_i(ep2_tx_data_valid_w),
 | 
	
		
			
				|  |  | +    .ep2_tx_data_strb_i(ep2_tx_data_strb_w),
 | 
	
		
			
				|  |  | +    .ep2_tx_data_i(ep2_tx_data_w),
 | 
	
		
			
				|  |  | +    .ep2_tx_data_last_i(ep2_tx_data_last_w),
 | 
	
		
			
				|  |  | +    .ep2_tx_data_accept_o(ep2_tx_data_accept_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP3 Config
 | 
	
		
			
				|  |  | +    .ep3_iso_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep3_stall_i(ep3_tx_stall_w),
 | 
	
		
			
				|  |  | +    .ep3_cfg_int_rx_i(1'b0),
 | 
	
		
			
				|  |  | +    .ep3_cfg_int_tx_i(1'b0),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP3 Rx SIE Interface
 | 
	
		
			
				|  |  | +    .ep3_rx_setup_o(ep3_rx_setup_w),
 | 
	
		
			
				|  |  | +    .ep3_rx_valid_o(ep3_rx_valid_w),
 | 
	
		
			
				|  |  | +    .ep3_rx_space_i(ep3_rx_space_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // EP3 Tx SIE Interface
 | 
	
		
			
				|  |  | +    .ep3_tx_ready_i(ep3_tx_ready_w),
 | 
	
		
			
				|  |  | +    .ep3_tx_data_valid_i(ep3_tx_data_valid_w),
 | 
	
		
			
				|  |  | +    .ep3_tx_data_strb_i(ep3_tx_data_strb_w),
 | 
	
		
			
				|  |  | +    .ep3_tx_data_i(ep3_tx_data_w),
 | 
	
		
			
				|  |  | +    .ep3_tx_data_last_i(ep3_tx_data_last_w),
 | 
	
		
			
				|  |  | +    .ep3_tx_data_accept_o(ep3_tx_data_accept_w),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Status
 | 
	
		
			
				|  |  | +    .reg_sts_rst_clr_i(1'b1),
 | 
	
		
			
				|  |  | +    .reg_sts_rst_o(usb_reset_w),
 | 
	
		
			
				|  |  | +    .reg_sts_frame_num_o()
 | 
	
		
			
				|  |  | +);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign ep0_rx_space_w = 1'b1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// USB: Setup packet capture (limited to 8 bytes for USB-FS)
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +reg [7:0] setup_packet_q[0:7];
 | 
	
		
			
				|  |  | +reg [2:0] setup_wr_idx_q;
 | 
	
		
			
				|  |  | +reg       setup_frame_q;
 | 
	
		
			
				|  |  | +reg       setup_valid_q;
 | 
	
		
			
				|  |  | +reg       setup_data_q;
 | 
	
		
			
				|  |  | +reg       status_ready_q; // STATUS response received
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    setup_packet_q[0]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[1]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[2]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[3]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[4]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[5]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[6]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[7]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_wr_idx_q     <= 3'b0;
 | 
	
		
			
				|  |  | +    setup_valid_q      <= 1'b0;
 | 
	
		
			
				|  |  | +    setup_frame_q      <= 1'b0;
 | 
	
		
			
				|  |  | +    setup_data_q       <= 1'b0;
 | 
	
		
			
				|  |  | +    status_ready_q     <= 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +// SETUP token received
 | 
	
		
			
				|  |  | +else if (ep0_rx_setup_w)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    setup_packet_q[0]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[1]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[2]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[3]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[4]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[5]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[6]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_packet_q[7]  <= 8'b0;
 | 
	
		
			
				|  |  | +    setup_wr_idx_q     <= 3'b0;
 | 
	
		
			
				|  |  | +    setup_valid_q      <= 1'b0;
 | 
	
		
			
				|  |  | +    setup_frame_q      <= 1'b1;
 | 
	
		
			
				|  |  | +    setup_data_q       <= 1'b0;
 | 
	
		
			
				|  |  | +    status_ready_q     <= 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +// Valid DATA for setup frame
 | 
	
		
			
				|  |  | +else if (ep0_rx_valid_w && rx_strb_w)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    setup_packet_q[setup_wr_idx_q] <= rx_data_w;
 | 
	
		
			
				|  |  | +    setup_wr_idx_q      <= setup_wr_idx_q + 3'd1;
 | 
	
		
			
				|  |  | +    setup_valid_q       <= setup_frame_q && rx_last_w;
 | 
	
		
			
				|  |  | +    setup_data_q        <= !setup_frame_q && rx_last_w;
 | 
	
		
			
				|  |  | +    if (rx_last_w)
 | 
	
		
			
				|  |  | +        setup_frame_q   <= 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +// Detect STATUS stage (ACK for SETUP GET requests)
 | 
	
		
			
				|  |  | +// TODO: Not quite correct .... 
 | 
	
		
			
				|  |  | +else if (ep0_rx_valid_w && !rx_strb_w && rx_last_w)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    setup_valid_q       <= 1'b0;
 | 
	
		
			
				|  |  | +    status_ready_q      <= 1'b1;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +else
 | 
	
		
			
				|  |  | +    setup_valid_q       <= 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// SETUP request decode
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +wire [7:0]  bmRequestType_w = setup_packet_q[0];
 | 
	
		
			
				|  |  | +wire [7:0]  bRequest_w      = setup_packet_q[1];
 | 
	
		
			
				|  |  | +wire [15:0] wValue_w        = {setup_packet_q[3], setup_packet_q[2]};
 | 
	
		
			
				|  |  | +wire [15:0] wIndex_w        = {setup_packet_q[5], setup_packet_q[4]};
 | 
	
		
			
				|  |  | +wire [15:0] wLength         = {setup_packet_q[7], setup_packet_q[6]};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire setup_get_w            = setup_valid_q && (bmRequestType_w[`ENDPOINT_DIR_R] == `ENDPOINT_DIR_IN);
 | 
	
		
			
				|  |  | +wire setup_set_w            = setup_valid_q && (bmRequestType_w[`ENDPOINT_DIR_R] == `ENDPOINT_DIR_OUT);
 | 
	
		
			
				|  |  | +wire setup_no_data_w        = setup_set_w && (wLength == 16'b0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// For REQ_GET_DESCRIPTOR
 | 
	
		
			
				|  |  | +wire [7:0]  bDescriptorType_w  = setup_packet_q[3];
 | 
	
		
			
				|  |  | +wire [7:0]  bDescriptorIndex_w = setup_packet_q[2];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Process setup request
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +reg        ctrl_stall_r; // Send STALL
 | 
	
		
			
				|  |  | +reg        ctrl_ack_r;   // Send STATUS (ZLP)
 | 
	
		
			
				|  |  | +reg [15:0] ctrl_get_len_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg [7:0]  desc_addr_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg        addressed_q;
 | 
	
		
			
				|  |  | +reg        addressed_r;
 | 
	
		
			
				|  |  | +reg [6:0]  device_addr_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg        configured_q;
 | 
	
		
			
				|  |  | +reg        configured_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg        set_with_data_q;
 | 
	
		
			
				|  |  | +reg        set_with_data_r;
 | 
	
		
			
				|  |  | +wire       data_status_zlp_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ *
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    ctrl_stall_r    = 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_get_len_r  = 16'b0;
 | 
	
		
			
				|  |  | +    ctrl_ack_r      = 1'b0;
 | 
	
		
			
				|  |  | +    desc_addr_r     = 8'b0;
 | 
	
		
			
				|  |  | +    device_addr_r   = device_addr_q;
 | 
	
		
			
				|  |  | +    addressed_r     = addressed_q;
 | 
	
		
			
				|  |  | +    configured_r    = configured_q;
 | 
	
		
			
				|  |  | +    set_with_data_r = set_with_data_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (setup_valid_q)
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        set_with_data_r = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        case (bmRequestType_w & `USB_REQUEST_TYPE_MASK)
 | 
	
		
			
				|  |  | +        `USB_STANDARD_REQUEST:
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            case (bRequest_w)
 | 
	
		
			
				|  |  | +            `REQ_GET_STATUS:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("GET_STATUS");
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_CLEAR_FEATURE:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("CLEAR_FEATURE");
 | 
	
		
			
				|  |  | +                ctrl_ack_r = setup_set_w && setup_no_data_w;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_SET_FEATURE:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("SET_FEATURE");
 | 
	
		
			
				|  |  | +                ctrl_ack_r = setup_set_w && setup_no_data_w;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_SET_ADDRESS:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("SET_ADDRESS: Set device address %d", wValue_w[6:0]);
 | 
	
		
			
				|  |  | +                ctrl_ack_r    = setup_set_w && setup_no_data_w;
 | 
	
		
			
				|  |  | +                device_addr_r = wValue_w[6:0];
 | 
	
		
			
				|  |  | +                addressed_r   = 1'b1;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_GET_DESCRIPTOR:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("GET_DESCRIPTOR: Type %d", bDescriptorType_w);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                case (bDescriptorType_w)
 | 
	
		
			
				|  |  | +                `DESC_DEVICE:
 | 
	
		
			
				|  |  | +                begin
 | 
	
		
			
				|  |  | +                    desc_addr_r    = `ROM_DESC_DEVICE_ADDR;
 | 
	
		
			
				|  |  | +                    ctrl_get_len_r = `ROM_DESC_DEVICE_SIZE;
 | 
	
		
			
				|  |  | +                end
 | 
	
		
			
				|  |  | +                `DESC_CONFIGURATION:
 | 
	
		
			
				|  |  | +                begin
 | 
	
		
			
				|  |  | +                    desc_addr_r    = `ROM_DESC_CONF_ADDR;
 | 
	
		
			
				|  |  | +                    ctrl_get_len_r = `ROM_DESC_CONF_SIZE;
 | 
	
		
			
				|  |  | +                end
 | 
	
		
			
				|  |  | +                `DESC_STRING:
 | 
	
		
			
				|  |  | +                begin
 | 
	
		
			
				|  |  | +                    case (bDescriptorIndex_w)
 | 
	
		
			
				|  |  | +                    `UNICODE_LANGUAGE_STR_ID:
 | 
	
		
			
				|  |  | +                    begin
 | 
	
		
			
				|  |  | +                        desc_addr_r    = `ROM_DESC_STR_LANG_ADDR;
 | 
	
		
			
				|  |  | +                        ctrl_get_len_r = `ROM_DESC_STR_LANG_SIZE;
 | 
	
		
			
				|  |  | +                    end
 | 
	
		
			
				|  |  | +                    `MANUFACTURER_STR_ID:
 | 
	
		
			
				|  |  | +                    begin
 | 
	
		
			
				|  |  | +                        desc_addr_r    = `ROM_DESC_STR_MAN_ADDR;
 | 
	
		
			
				|  |  | +                        ctrl_get_len_r = `ROM_DESC_STR_MAN_SIZE;
 | 
	
		
			
				|  |  | +                    end
 | 
	
		
			
				|  |  | +                    `PRODUCT_NAME_STR_ID:
 | 
	
		
			
				|  |  | +                    begin
 | 
	
		
			
				|  |  | +                        desc_addr_r    = `ROM_DESC_STR_PROD_ADDR;
 | 
	
		
			
				|  |  | +                        ctrl_get_len_r = `ROM_DESC_STR_PROD_SIZE;
 | 
	
		
			
				|  |  | +                    end
 | 
	
		
			
				|  |  | +                    `SERIAL_NUM_STR_ID:
 | 
	
		
			
				|  |  | +                    begin
 | 
	
		
			
				|  |  | +                        desc_addr_r    = `ROM_DESC_STR_SERIAL_ADDR;
 | 
	
		
			
				|  |  | +                        ctrl_get_len_r = `ROM_DESC_STR_SERIAL_SIZE;
 | 
	
		
			
				|  |  | +                    end
 | 
	
		
			
				|  |  | +                    default:
 | 
	
		
			
				|  |  | +                        ;
 | 
	
		
			
				|  |  | +                    endcase
 | 
	
		
			
				|  |  | +                end
 | 
	
		
			
				|  |  | +                default:
 | 
	
		
			
				|  |  | +                    ;
 | 
	
		
			
				|  |  | +                endcase
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_GET_CONFIGURATION:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("GET_CONF");
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_SET_CONFIGURATION:
 | 
	
		
			
				|  |  | +            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)
 | 
	
		
			
				|  |  | +                begin
 | 
	
		
			
				|  |  | +                    configured_r = 1'b1;
 | 
	
		
			
				|  |  | +                    ctrl_ack_r   = setup_set_w && setup_no_data_w;
 | 
	
		
			
				|  |  | +                end
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                    ctrl_stall_r = 1'b1;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_GET_INTERFACE:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("GET_INTERFACE");
 | 
	
		
			
				|  |  | +                ctrl_stall_r = 1'b1;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            `REQ_SET_INTERFACE:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("SET_INTERFACE: %x %x", wValue_w, wIndex_w);
 | 
	
		
			
				|  |  | +                if (wValue_w == 16'd0 && wIndex_w == 16'd0)
 | 
	
		
			
				|  |  | +                    ctrl_ack_r   = setup_set_w && setup_no_data_w;
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                    ctrl_stall_r = 1'b1;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            default:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                ctrl_stall_r = 1'b1;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            endcase
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +        `USB_VENDOR_REQUEST:
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            // None supported
 | 
	
		
			
				|  |  | +            ctrl_stall_r = 1'b1;
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +        `USB_CLASS_REQUEST:
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            case (bRequest_w)
 | 
	
		
			
				|  |  | +            `CDC_GET_LINE_CODING:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                $display("CDC_GET_LINE_CODING");
 | 
	
		
			
				|  |  | +                desc_addr_r    = `ROM_CDC_LINE_CODING_ADDR;
 | 
	
		
			
				|  |  | +                ctrl_get_len_r = `ROM_CDC_LINE_CODING_SIZE;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            default:
 | 
	
		
			
				|  |  | +            begin
 | 
	
		
			
				|  |  | +                ctrl_ack_r      = setup_set_w && setup_no_data_w;
 | 
	
		
			
				|  |  | +                set_with_data_r = setup_set_w && !setup_no_data_w;
 | 
	
		
			
				|  |  | +            end
 | 
	
		
			
				|  |  | +            endcase
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +        default:
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            ctrl_stall_r = 1'b1;
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +        endcase
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    else if (data_status_zlp_w)
 | 
	
		
			
				|  |  | +        set_with_data_r = 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    device_addr_q   <= 7'b0;
 | 
	
		
			
				|  |  | +    addressed_q     <= 1'b0;
 | 
	
		
			
				|  |  | +    configured_q    <= 1'b0;
 | 
	
		
			
				|  |  | +    set_with_data_q <= 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +else if (usb_reset_w)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    device_addr_q   <= 7'b0;
 | 
	
		
			
				|  |  | +    addressed_q     <= 1'b0;
 | 
	
		
			
				|  |  | +    configured_q    <= 1'b0;
 | 
	
		
			
				|  |  | +    set_with_data_q <= 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +else
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    device_addr_q   <= device_addr_r;
 | 
	
		
			
				|  |  | +    addressed_q     <= addressed_r;
 | 
	
		
			
				|  |  | +    configured_q    <= configured_r;
 | 
	
		
			
				|  |  | +    set_with_data_q <= set_with_data_r;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// SETUP response
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +reg        ctrl_sending_q;
 | 
	
		
			
				|  |  | +reg [15:0] ctrl_send_idx_q;
 | 
	
		
			
				|  |  | +reg [15:0] ctrl_send_len_q;
 | 
	
		
			
				|  |  | +wire       ctrl_send_zlp_w = ctrl_sending_q && (ctrl_send_len_q != wLength);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg        ctrl_sending_r;
 | 
	
		
			
				|  |  | +reg [15:0] ctrl_send_idx_r;
 | 
	
		
			
				|  |  | +reg [15:0] ctrl_send_len_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg        ctrl_txvalid_q;
 | 
	
		
			
				|  |  | +reg [7:0]  ctrl_txdata_q;
 | 
	
		
			
				|  |  | +reg        ctrl_txstrb_q;
 | 
	
		
			
				|  |  | +reg        ctrl_txlast_q;
 | 
	
		
			
				|  |  | +reg        ctrl_txstall_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg        ctrl_txvalid_r;
 | 
	
		
			
				|  |  | +reg [7:0]  ctrl_txdata_r;
 | 
	
		
			
				|  |  | +reg        ctrl_txstrb_r;
 | 
	
		
			
				|  |  | +reg        ctrl_txlast_r;
 | 
	
		
			
				|  |  | +reg        ctrl_txstall_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +wire       ctrl_send_accept_w = ep0_tx_data_accept_w || !ep0_tx_data_valid_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +reg [7:0]  desc_addr_q;
 | 
	
		
			
				|  |  | +wire[7:0]  desc_data_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ *
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    ctrl_sending_r  = ctrl_sending_q;
 | 
	
		
			
				|  |  | +    ctrl_send_idx_r = ctrl_send_idx_q;
 | 
	
		
			
				|  |  | +    ctrl_send_len_r = ctrl_send_len_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ctrl_txvalid_r  = ctrl_txvalid_q;
 | 
	
		
			
				|  |  | +    ctrl_txdata_r   = ctrl_txdata_q;
 | 
	
		
			
				|  |  | +    ctrl_txstrb_r   = ctrl_txstrb_q;
 | 
	
		
			
				|  |  | +    ctrl_txlast_r   = ctrl_txlast_q;
 | 
	
		
			
				|  |  | +    ctrl_txstall_r  = ctrl_txstall_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // New SETUP request
 | 
	
		
			
				|  |  | +    if (setup_valid_q)
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // Send STALL
 | 
	
		
			
				|  |  | +        if (ctrl_stall_r)
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            ctrl_txvalid_r  = 1'b1;
 | 
	
		
			
				|  |  | +            ctrl_txstrb_r   = 1'b0;
 | 
	
		
			
				|  |  | +            ctrl_txlast_r   = 1'b1;
 | 
	
		
			
				|  |  | +            ctrl_txstall_r  = 1'b1;
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +        // Send STATUS response (ZLP)
 | 
	
		
			
				|  |  | +        else if (ctrl_ack_r)
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            ctrl_txvalid_r  = 1'b1;
 | 
	
		
			
				|  |  | +            ctrl_txstrb_r   = 1'b0;
 | 
	
		
			
				|  |  | +            ctrl_txlast_r   = 1'b1;
 | 
	
		
			
				|  |  | +            ctrl_txstall_r  = 1'b0;
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +        else
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            ctrl_sending_r  = setup_get_w && !ctrl_stall_r;
 | 
	
		
			
				|  |  | +            ctrl_send_idx_r = 16'b0;
 | 
	
		
			
				|  |  | +            ctrl_send_len_r = ctrl_get_len_r;
 | 
	
		
			
				|  |  | +            ctrl_txstall_r  = 1'b0;
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    // Abort control send when STATUS received
 | 
	
		
			
				|  |  | +    else if (status_ready_q)
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        ctrl_sending_r  = 1'b0;
 | 
	
		
			
				|  |  | +        ctrl_send_idx_r = 16'b0;
 | 
	
		
			
				|  |  | +        ctrl_send_len_r = 16'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        ctrl_txvalid_r  = 1'b0;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    // Send STATUS response (ZLP)
 | 
	
		
			
				|  |  | +    else if (set_with_data_q && setup_data_q)
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        ctrl_txvalid_r  = 1'b1;
 | 
	
		
			
				|  |  | +        ctrl_txstrb_r   = 1'b0;
 | 
	
		
			
				|  |  | +        ctrl_txlast_r   = 1'b1;
 | 
	
		
			
				|  |  | +        ctrl_txstall_r  = 1'b0;
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    else if (ctrl_sending_r && ctrl_send_accept_w)
 | 
	
		
			
				|  |  | +    begin
 | 
	
		
			
				|  |  | +        // TODO: Send ZLP on exact multiple lengths...
 | 
	
		
			
				|  |  | +        ctrl_txvalid_r  = 1'b1;
 | 
	
		
			
				|  |  | +        ctrl_txdata_r   = desc_data_w;
 | 
	
		
			
				|  |  | +        ctrl_txstrb_r   = 1'b1;
 | 
	
		
			
				|  |  | +        ctrl_txlast_r   = usb_hs_w ? (ctrl_send_idx_r[5:0] == 6'b111111) : (ctrl_send_idx_r[2:0] == 3'b111);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Increment send index
 | 
	
		
			
				|  |  | +        ctrl_send_idx_r = ctrl_send_idx_r + 16'd1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // TODO: Detect need for ZLP
 | 
	
		
			
				|  |  | +        if (ctrl_send_idx_r == wLength)
 | 
	
		
			
				|  |  | +        begin
 | 
	
		
			
				|  |  | +            ctrl_sending_r = 1'b0;
 | 
	
		
			
				|  |  | +            ctrl_txlast_r  = 1'b1;
 | 
	
		
			
				|  |  | +        end
 | 
	
		
			
				|  |  | +    end
 | 
	
		
			
				|  |  | +    else if (ctrl_send_accept_w)
 | 
	
		
			
				|  |  | +        ctrl_txvalid_r  = 1'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign data_status_zlp_w = set_with_data_q && setup_data_q && ctrl_send_accept_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +always @ (posedge clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    ctrl_sending_q  <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_send_idx_q <= 16'b0;
 | 
	
		
			
				|  |  | +    ctrl_send_len_q <= 16'b0;
 | 
	
		
			
				|  |  | +    ctrl_txvalid_q  <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_txdata_q   <= 8'b0;
 | 
	
		
			
				|  |  | +    ctrl_txstrb_q   <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_txlast_q   <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_txstall_q  <= 1'b0;
 | 
	
		
			
				|  |  | +    desc_addr_q     <= 8'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +else if (usb_reset_w)
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    ctrl_sending_q  <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_send_idx_q <= 16'b0;
 | 
	
		
			
				|  |  | +    ctrl_send_len_q <= 16'b0;
 | 
	
		
			
				|  |  | +    ctrl_txvalid_q  <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_txdata_q   <= 8'b0;
 | 
	
		
			
				|  |  | +    ctrl_txstrb_q   <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_txlast_q   <= 1'b0;
 | 
	
		
			
				|  |  | +    ctrl_txstall_q  <= 1'b0;
 | 
	
		
			
				|  |  | +    desc_addr_q     <= 8'b0;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +else
 | 
	
		
			
				|  |  | +begin
 | 
	
		
			
				|  |  | +    ctrl_sending_q  <= ctrl_sending_r;
 | 
	
		
			
				|  |  | +    ctrl_send_idx_q <= ctrl_send_idx_r;
 | 
	
		
			
				|  |  | +    ctrl_send_len_q <= ctrl_send_len_r;
 | 
	
		
			
				|  |  | +    ctrl_txvalid_q  <= ctrl_txvalid_r;
 | 
	
		
			
				|  |  | +    ctrl_txdata_q   <= ctrl_txdata_r;
 | 
	
		
			
				|  |  | +    ctrl_txstrb_q   <= ctrl_txstrb_r;
 | 
	
		
			
				|  |  | +    ctrl_txlast_q   <= ctrl_txlast_r;
 | 
	
		
			
				|  |  | +    ctrl_txstall_q  <= ctrl_txstall_r;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (setup_valid_q)
 | 
	
		
			
				|  |  | +        desc_addr_q     <= desc_addr_r;
 | 
	
		
			
				|  |  | +    else if (ctrl_sending_r && ctrl_send_accept_w)
 | 
	
		
			
				|  |  | +        desc_addr_q     <= desc_addr_q + 8'd1;
 | 
	
		
			
				|  |  | +end
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign ep0_tx_ready_w      = ctrl_txvalid_q;
 | 
	
		
			
				|  |  | +assign ep0_tx_data_valid_w = ctrl_txvalid_q;
 | 
	
		
			
				|  |  | +assign ep0_tx_data_strb_w  = ctrl_txstrb_q;
 | 
	
		
			
				|  |  | +assign ep0_tx_data_w       = ctrl_txdata_q;
 | 
	
		
			
				|  |  | +assign ep0_tx_data_last_w  = ctrl_txlast_q;
 | 
	
		
			
				|  |  | +assign ep0_tx_stall_w      = ctrl_txstall_q;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Descriptor ROM
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +usb_desc_rom
 | 
	
		
			
				|  |  | +u_rom
 | 
	
		
			
				|  |  | +(
 | 
	
		
			
				|  |  | +    .hs_i(usb_hs_w),
 | 
	
		
			
				|  |  | +    .addr_i(desc_addr_q),
 | 
	
		
			
				|  |  | +    .data_o(desc_data_w)
 | 
	
		
			
				|  |  | +);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Unused Endpoints
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +assign ep1_tx_ready_w      = 1'b0;
 | 
	
		
			
				|  |  | +assign ep1_tx_data_valid_w = 1'b0;
 | 
	
		
			
				|  |  | +assign ep1_tx_data_strb_w  = 1'b0;
 | 
	
		
			
				|  |  | +assign ep1_tx_data_w       = 8'b0;
 | 
	
		
			
				|  |  | +assign ep1_tx_data_last_w  = 1'b0;
 | 
	
		
			
				|  |  | +assign ep1_tx_stall_w      = 1'b0;
 | 
	
		
			
				|  |  | +assign ep3_tx_ready_w      = 1'b0;
 | 
	
		
			
				|  |  | +assign ep3_tx_data_valid_w = 1'b0;
 | 
	
		
			
				|  |  | +assign ep3_tx_data_strb_w  = 1'b0;
 | 
	
		
			
				|  |  | +assign ep3_tx_data_w       = 8'b0;
 | 
	
		
			
				|  |  | +assign ep3_tx_data_last_w  = 1'b0;
 | 
	
		
			
				|  |  | +assign ep3_tx_stall_w      = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign ep2_rx_space_w      = 1'b0;
 | 
	
		
			
				|  |  | +assign ep3_rx_space_w      = 1'b0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +// Stream I/O
 | 
	
		
			
				|  |  | +//-----------------------------------------------------------------
 | 
	
		
			
				|  |  | +reg        inport_valid_q;
 | 
	
		
			
				|  |  | +reg [7:0]  inport_data_q;
 | 
	
		
			
				|  |  | +reg [10:0] inport_cnt_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
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +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 clk_i or posedge rst_i)
 | 
	
		
			
				|  |  | +if (rst_i)
 | 
	
		
			
				|  |  | +    inport_cnt_q  <= 11'b0;
 | 
	
		
			
				|  |  | +else if (inport_last_w && ep2_tx_data_accept_w)
 | 
	
		
			
				|  |  | +    inport_cnt_q  <= 11'b0;
 | 
	
		
			
				|  |  | +else if (inport_valid_q && ep2_tx_data_accept_w)
 | 
	
		
			
				|  |  | +    inport_cnt_q  <= inport_cnt_q + 11'd1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign ep2_tx_data_valid_w = inport_valid_q;
 | 
	
		
			
				|  |  | +assign ep2_tx_data_w       = inport_data_q;
 | 
	
		
			
				|  |  | +assign ep2_tx_ready_w      = ep2_tx_data_valid_w;
 | 
	
		
			
				|  |  | +assign ep2_tx_data_strb_w  = ep2_tx_data_valid_w;
 | 
	
		
			
				|  |  | +assign ep2_tx_data_last_w  = inport_last_w;
 | 
	
		
			
				|  |  | +assign inport_accept_o     = !inport_valid_q | ep2_tx_data_accept_w;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +assign outport_valid_o  = ep1_rx_valid_w && rx_strb_w;
 | 
	
		
			
				|  |  | +assign outport_data_o   = rx_data_w;
 | 
	
		
			
				|  |  | +assign ep1_rx_space_w   = outport_accept_i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +endmodule
 |