| ////////////////////////////////////////////////////////////////////////////// |
| // SPDX-FileCopyrightText: 2021 , Dinesh Annayya |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // SPDX-License-Identifier: Apache-2.0 |
| // SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org> |
| // |
| //----------------------------------------------------------------- |
| // USB Full Speed Host |
| // V0.6 |
| // Ultra-Embedded.com |
| // Copyright 2015-2020 |
| // |
| // Email: admin@ultra-embedded.com |
| // |
| // License: GPL |
| // If you would like a version with a more permissive license for |
| // use in closed source commercial applications please contact me |
| // for details. |
| //----------------------------------------------------------------- |
| // |
| // This file is open source HDL; you can redistribute it and/or |
| // modify it under the terms of the GNU General Public License as |
| // published by the Free Software Foundation; either version 2 of |
| // the License, or (at your option) any later version. |
| // |
| // This file 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 General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public |
| // License along with this file; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| // USA |
| //----------------------------------------------------------------- |
| |
| //----------------------------------------------------------------- |
| // Generated File |
| //----------------------------------------------------------------- |
| |
| module usbh_sie |
| //----------------------------------------------------------------- |
| // Params |
| //----------------------------------------------------------------- |
| #( |
| parameter USB_CLK_FREQ = 48000000 |
| ) |
| //----------------------------------------------------------------- |
| // Ports |
| //----------------------------------------------------------------- |
| ( |
| // Inputs |
| input clk_i, |
| input rstn_i, |
| input start_i, |
| input in_transfer_i, |
| input sof_transfer_i, |
| input resp_expected_i, |
| input [ 7:0] token_pid_i, |
| input [ 6:0] token_dev_i, |
| input [ 3:0] token_ep_i, |
| input [ 15:0] data_len_i, |
| input data_idx_i, |
| input [ 7:0] tx_data_i, |
| input utmi_txready_i, |
| input [ 7:0] utmi_data_i, |
| input utmi_rxvalid_i, |
| input utmi_rxactive_i, |
| input [ 1:0] utmi_linestate_i, |
| |
| // Outputs |
| output ack_o, |
| output tx_pop_o, |
| output [ 7:0] rx_data_o, |
| output rx_push_o, |
| output tx_done_o, |
| output rx_done_o, |
| output crc_err_o, |
| output timeout_o, |
| output [ 7:0] response_o, |
| output [ 15:0] rx_count_o, |
| output idle_o, |
| output [ 7:0] utmi_data_o, |
| output utmi_txvalid_o |
| ); |
| |
| |
| |
| //----------------------------------------------------------------- |
| // Registers / Wires |
| //----------------------------------------------------------------- |
| logic start_ack_q; |
| |
| // Status |
| logic status_tx_done_q; |
| logic status_rx_done_q; |
| logic status_crc_err_q; |
| logic status_timeout_q; |
| logic [7:0] status_response_q; |
| |
| logic [15:0] byte_count_q; |
| logic in_transfer_q; |
| |
| logic [8:0] last_tx_time_q; |
| |
| logic send_data1_q; |
| logic send_sof_q; |
| logic send_ack_q; |
| |
| // CRC16 |
| logic [15:0] crc_sum_q; |
| logic [15:0] crc_out_w; |
| logic [7:0] crc_data_in_w; |
| |
| // CRC5 |
| logic [4:0] crc5_out_w; |
| wire [4:0] crc5_next_w = crc5_out_w ^ 5'h1F; |
| |
| logic [15:0] token_q; |
| |
| logic wait_resp_q; |
| |
| logic [3:0] state_q; |
| |
| //----------------------------------------------------------------- |
| // Definitions |
| //----------------------------------------------------------------- |
| localparam RX_TIMEOUT = (USB_CLK_FREQ == 60000000) ? 9'd511 : 9'd255; |
| // 2 FS bit times (x5 CLKs @ 60MHz, x4 CLKs @ 48MHz) |
| localparam TX_IFS = (USB_CLK_FREQ == 60000000) ? 4'd10 : 4'd7; |
| |
| localparam PID_OUT = 8'hE1; |
| localparam PID_IN = 8'h69; |
| localparam PID_SOF = 8'hA5; |
| localparam PID_SETUP = 8'h2D; |
| |
| localparam PID_DATA0 = 8'hC3; |
| localparam PID_DATA1 = 8'h4B; |
| |
| localparam PID_ACK = 8'hD2; |
| localparam PID_NAK = 8'h5A; |
| localparam PID_STALL = 8'h1E; |
| |
| // States |
| localparam STATE_IDLE = 4'd0; |
| localparam STATE_RX_DATA = 4'd1; |
| localparam STATE_TX_PID = 4'd2; |
| localparam STATE_TX_DATA = 4'd3; |
| localparam STATE_TX_CRC1 = 4'd4; |
| localparam STATE_TX_CRC2 = 4'd5; |
| localparam STATE_TX_TOKEN1 = 4'd6; |
| localparam STATE_TX_TOKEN2 = 4'd7; |
| localparam STATE_TX_TOKEN3 = 4'd8; |
| localparam STATE_TX_ACKNAK = 4'd9; |
| localparam STATE_TX_WAIT = 4'd10; |
| localparam STATE_RX_WAIT = 4'd11; |
| localparam STATE_TX_IFS = 4'd12; |
| |
| //----------------------------------------------------------------- |
| // Wires |
| //----------------------------------------------------------------- |
| // Rx data |
| logic [7:0] rx_data_w; |
| logic data_ready_w; |
| logic crc_byte_w; |
| logic rx_active_w; |
| logic rx_active_rise_w; |
| |
| // Tx/Rx -> Tx IFS timeout |
| logic ifs_busy_w; |
| |
| // Response timeout (no response after 500uS from transmit) |
| wire rx_resp_timeout_w = (last_tx_time_q >= RX_TIMEOUT) & wait_resp_q; |
| |
| // CRC16 error on received data |
| wire crc_error_w = (state_q == STATE_RX_DATA) && !rx_active_w && in_transfer_q && |
| (status_response_q == PID_DATA0 || status_response_q == PID_DATA1) && |
| (crc_sum_q != 16'hB001); |
| |
| //----------------------------------------------------------------- |
| // State Machine |
| //----------------------------------------------------------------- |
| logic [3:0] next_state_r; |
| |
| always @ * |
| begin |
| next_state_r = state_q; |
| |
| //----------------------------------------- |
| // Tx State Machine |
| //----------------------------------------- |
| case (state_q) |
| |
| //----------------------------------------- |
| // TX_TOKEN1 (byte 1 of token) |
| //----------------------------------------- |
| STATE_TX_TOKEN1 : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| next_state_r = STATE_TX_TOKEN2; |
| end |
| //----------------------------------------- |
| // TX_TOKEN2 (byte 2 of token) |
| //----------------------------------------- |
| STATE_TX_TOKEN2 : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| next_state_r = STATE_TX_TOKEN3; |
| end |
| //----------------------------------------- |
| // TX_TOKEN3 (byte 3 of token) |
| //----------------------------------------- |
| STATE_TX_TOKEN3 : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| begin |
| // SOF - no data packet |
| if (send_sof_q) |
| next_state_r = STATE_TX_IFS; |
| // IN - wait for data |
| else if (in_transfer_q) |
| next_state_r = STATE_RX_WAIT; |
| // OUT/SETUP - Send data or ZLP |
| else |
| next_state_r = STATE_TX_IFS; |
| end |
| end |
| //----------------------------------------- |
| // TX_IFS |
| //----------------------------------------- |
| STATE_TX_IFS : |
| begin |
| // IFS expired |
| if (~ifs_busy_w) |
| begin |
| // SOF - no data packet |
| if (send_sof_q) |
| next_state_r = STATE_IDLE; |
| // OUT/SETUP - Send data or ZLP |
| else |
| next_state_r = STATE_TX_PID; |
| end |
| end |
| //----------------------------------------- |
| // TX_PID |
| //----------------------------------------- |
| STATE_TX_PID : |
| begin |
| // Last data byte sent? |
| if (utmi_txready_i && (byte_count_q == 16'b0)) |
| next_state_r = STATE_TX_CRC1; |
| else if (utmi_txready_i) |
| next_state_r = STATE_TX_DATA; |
| end |
| //----------------------------------------- |
| // TX_DATA |
| //----------------------------------------- |
| STATE_TX_DATA : |
| begin |
| // Last data byte sent? |
| if (utmi_txready_i && (byte_count_q == 16'b0)) |
| next_state_r = STATE_TX_CRC1; |
| end |
| //----------------------------------------- |
| // TX_CRC1 (first byte) |
| //----------------------------------------- |
| STATE_TX_CRC1 : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| next_state_r = STATE_TX_CRC2; |
| end |
| //----------------------------------------- |
| // TX_CRC (second byte) |
| //----------------------------------------- |
| STATE_TX_CRC2 : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| begin |
| // If a response is expected |
| if (wait_resp_q) |
| next_state_r = STATE_RX_WAIT; |
| // No response expected (e.g ISO transfer) |
| else |
| next_state_r = STATE_IDLE; |
| end |
| end |
| //----------------------------------------- |
| // STATE_TX_WAIT |
| //----------------------------------------- |
| STATE_TX_WAIT : |
| begin |
| // Waited long enough? |
| if (~ifs_busy_w) |
| next_state_r = STATE_TX_ACKNAK; |
| end |
| //----------------------------------------- |
| // STATE_TX_ACKNAK |
| //----------------------------------------- |
| STATE_TX_ACKNAK : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| next_state_r = STATE_IDLE; |
| end |
| //----------------------------------------- |
| // STATE_RX_WAIT |
| //----------------------------------------- |
| STATE_RX_WAIT : |
| begin |
| // Data received? |
| if (data_ready_w) |
| next_state_r = STATE_RX_DATA; |
| // Waited long enough? |
| else if (rx_resp_timeout_w) |
| next_state_r = STATE_IDLE; |
| end |
| //----------------------------------------- |
| // RX_DATA |
| //----------------------------------------- |
| STATE_RX_DATA : |
| begin |
| // Receive complete |
| if (~rx_active_w) |
| begin |
| // Send ACK but incoming data had CRC error, do not ACK |
| if (send_ack_q && crc_error_w) |
| next_state_r = STATE_IDLE; |
| // Send an ACK response without CPU interaction? |
| else if (send_ack_q && (status_response_q == PID_DATA0 || status_response_q == PID_DATA1)) |
| next_state_r = STATE_TX_WAIT; |
| else |
| next_state_r = STATE_IDLE; |
| end |
| end |
| //----------------------------------------- |
| // IDLE / RECEIVE BEGIN |
| //----------------------------------------- |
| STATE_IDLE : |
| begin |
| // Token transfer request |
| if (start_i) |
| next_state_r = STATE_TX_TOKEN1; |
| end |
| default : |
| ; |
| endcase |
| end |
| |
| // Update state |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| state_q <= STATE_IDLE; |
| else |
| state_q <= next_state_r; |
| |
| //----------------------------------------------------------------- |
| // Tx Token |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| token_q <= 16'h0000; |
| else if (state_q == STATE_IDLE) |
| token_q <= {token_dev_i, token_ep_i, 5'b0}; |
| // PID of token sent, capture calculated CRC for token packet |
| else if (state_q == STATE_TX_TOKEN1 && utmi_txready_i) |
| token_q[4:0] <= crc5_next_w; |
| |
| //----------------------------------------------------------------- |
| // Tx EOP - detect end of transmit (token, data or ACK/NAK) |
| //----------------------------------------------------------------- |
| reg [1:0] utmi_linestate_q; |
| reg se0_detect_q; |
| reg wait_eop_q; |
| |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| utmi_linestate_q <= 2'b0; |
| else |
| utmi_linestate_q <= utmi_linestate_i; |
| |
| // SE0 filtering (2 cycles FS) |
| wire se0_detect_w = (utmi_linestate_q == 2'b00 && utmi_linestate_i == 2'b00); |
| |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| se0_detect_q <= 1'b0; |
| else |
| se0_detect_q <= se0_detect_w; |
| |
| // TODO: This needs updating for HS USB... |
| wire eop_detected_w = se0_detect_q & (utmi_linestate_i != 2'b00); |
| |
| // End of transmit detection |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| wait_eop_q <= 1'b0; |
| else if (eop_detected_w) |
| wait_eop_q <= 1'b0; |
| else if ((state_q == STATE_TX_CRC2 && next_state_r != STATE_TX_CRC2) || |
| (state_q == STATE_TX_TOKEN3 && next_state_r != STATE_TX_TOKEN3) || |
| (state_q == STATE_TX_ACKNAK && next_state_r != STATE_TX_ACKNAK)) |
| wait_eop_q <= 1'b1; |
| else if (rx_active_rise_w) |
| wait_eop_q <= 1'b1; |
| |
| localparam TX_IFS_W = 4; |
| reg [TX_IFS_W-1:0] tx_ifs_q; |
| |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| tx_ifs_q <= {(TX_IFS_W){1'b0}}; |
| // Start counting down from last Tx or EOP being detected at end of Rx |
| else if (wait_eop_q || eop_detected_w) |
| tx_ifs_q <= TX_IFS; |
| // Decrement IFS counter |
| else if (tx_ifs_q != {(TX_IFS_W){1'b0}}) |
| tx_ifs_q <= tx_ifs_q - 1; |
| |
| assign ifs_busy_w = wait_eop_q || (tx_ifs_q != {(TX_IFS_W){1'b0}}); |
| |
| //----------------------------------------------------------------- |
| // Tx Timer |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| last_tx_time_q <= 9'd0; |
| // Start counting from last Tx |
| else if (state_q == STATE_IDLE || (utmi_txvalid_o && utmi_txready_i)) |
| last_tx_time_q <= 9'd0; |
| // Increment the Tx timeout |
| else if (last_tx_time_q != RX_TIMEOUT) |
| last_tx_time_q <= last_tx_time_q + 9'd1; |
| |
| //----------------------------------------------------------------- |
| // Transmit / Receive counter |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| byte_count_q <= 16'h0000; |
| // New transfer request (not automatic SOF request) |
| else if (state_q == STATE_IDLE && start_i && !sof_transfer_i) |
| byte_count_q <= data_len_i; |
| else if (state_q == STATE_RX_WAIT) |
| byte_count_q <= 16'h0000; |
| // Transmit byte |
| else if ((state_q == STATE_TX_PID || state_q == STATE_TX_DATA) && utmi_txready_i) |
| begin |
| // Count down data left to send |
| if (byte_count_q != 16'd0) |
| byte_count_q <= byte_count_q - 16'd1; |
| end |
| // Received byte |
| else if (state_q == STATE_RX_DATA && data_ready_w && !crc_byte_w) |
| byte_count_q <= byte_count_q + 16'd1; |
| |
| //----------------------------------------------------------------- |
| // Transfer start ack |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| start_ack_q <= 1'b0; |
| // First byte of PID sent, ack transfer request |
| else if (state_q == STATE_TX_TOKEN1 && utmi_txready_i) |
| start_ack_q <= 1'b1; |
| else |
| start_ack_q <= 1'b0; |
| |
| //----------------------------------------------------------------- |
| // Record request details |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| begin |
| in_transfer_q <= 1'b0; |
| send_ack_q <= 1'b0; |
| send_data1_q <= 1'b0; |
| send_sof_q <= 1'b0; |
| end |
| // Start of new request |
| else if (state_q == STATE_IDLE && start_i) |
| begin |
| // Transfer request |
| // e.g. (H)SOF [sof_transfer_i] |
| // (H)OUT + (H)DATA + (F)ACK/NACK/STALL [data_len_i >= 0 && !in_transfer_i] |
| // (H)IN + (F)DATA + (H)ACK [in_transfer_i] |
| // (H)IN + (F)NAK/STALL [in_transfer_i] |
| in_transfer_q <= in_transfer_i; |
| |
| // Send ACK in response to IN DATA |
| send_ack_q <= in_transfer_i && resp_expected_i; |
| |
| // DATA0/1 |
| send_data1_q <= data_idx_i; |
| |
| send_sof_q <= sof_transfer_i; |
| end |
| |
| //----------------------------------------------------------------- |
| // Response expected |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| wait_resp_q <= 1'b0; |
| // Incoming data |
| else if (state_q == STATE_RX_WAIT && data_ready_w) |
| wait_resp_q <= 1'b0; |
| else if (state_q == STATE_IDLE && start_i) |
| wait_resp_q <= resp_expected_i; |
| |
| //----------------------------------------------------------------- |
| // Status |
| //----------------------------------------------------------------- |
| always @ (posedge clk_i or negedge rstn_i) |
| begin |
| if (!rstn_i) |
| begin |
| status_response_q <= 8'h00; |
| status_timeout_q <= 1'b0; |
| status_rx_done_q <= 1'b0; |
| status_tx_done_q <= 1'b0; |
| end |
| else |
| begin |
| case (state_q) |
| |
| //----------------------------------------- |
| // RX_WAIT |
| //----------------------------------------- |
| STATE_RX_WAIT : |
| begin |
| // Store response PID |
| if (data_ready_w) |
| status_response_q <= rx_data_w; |
| |
| // Waited long enough? |
| if (rx_resp_timeout_w) |
| status_timeout_q <= 1'b1; |
| |
| status_tx_done_q <= 1'b0; |
| end |
| //----------------------------------------- |
| // RX_DATA |
| //----------------------------------------- |
| STATE_RX_DATA : |
| begin |
| // Receive complete |
| if (!utmi_rxactive_i) |
| status_rx_done_q <= 1'b1; |
| else |
| status_rx_done_q <= 1'b0; |
| end |
| //----------------------------------------- |
| // TX_CRC (second byte) |
| //----------------------------------------- |
| STATE_TX_CRC2 : |
| begin |
| // Data sent? |
| if (utmi_txready_i && !wait_resp_q) |
| begin |
| // Transfer now complete |
| status_tx_done_q <= 1'b1; |
| end |
| end |
| //----------------------------------------- |
| // IDLE / RECEIVE BEGIN |
| //----------------------------------------- |
| STATE_IDLE : |
| begin |
| // Transfer request |
| // e.g. (H)SOF [sof_transfer_i] |
| // (H)OUT + (H)DATA + (F)ACK/NACK/STALL [data_len_i >= 0 && !in_transfer_i] |
| // (H)IN + (F)DATA + (H)ACK [in_transfer_i] |
| // (H)IN + (F)NAK/STALL [in_transfer_i] |
| if (start_i && !sof_transfer_i) // (not automatic SOF request) |
| begin |
| // Clear status |
| status_response_q <= 8'h00; |
| status_timeout_q <= 1'b0; |
| end |
| |
| status_rx_done_q <= 1'b0; |
| status_tx_done_q <= 1'b0; |
| end |
| //----------------------------------------- |
| // DEFAULT |
| //----------------------------------------- |
| default : |
| begin |
| status_rx_done_q <= 1'b0; |
| status_tx_done_q <= 1'b0; |
| end |
| endcase |
| end |
| end |
| |
| |
| //----------------------------------------------------------------- |
| // Data delay (to strip the CRC16 trailing bytes) |
| //----------------------------------------------------------------- |
| reg [31:0] data_buffer_q; |
| reg [3:0] data_valid_q; |
| reg [3:0] rx_active_q; |
| |
| wire shift_en_w = (utmi_rxvalid_i & utmi_rxactive_i) || !utmi_rxactive_i; |
| |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| data_buffer_q <= 32'b0; |
| else if (shift_en_w) |
| data_buffer_q <= {utmi_data_i, data_buffer_q[31:8]}; |
| |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| data_valid_q <= 4'b0; |
| else if (shift_en_w) |
| data_valid_q <= {(utmi_rxvalid_i & utmi_rxactive_i), data_valid_q[3:1]}; |
| else |
| data_valid_q <= {data_valid_q[3:1], 1'b0}; |
| |
| reg [1:0] data_crc_q; |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| data_crc_q <= 2'b0; |
| else if (shift_en_w) |
| data_crc_q <= {!utmi_rxactive_i, data_crc_q[1]}; |
| |
| always @ (posedge clk_i or negedge rstn_i) |
| if (!rstn_i) |
| rx_active_q <= 4'b0; |
| else |
| rx_active_q <= {utmi_rxactive_i, rx_active_q[3:1]}; |
| |
| assign rx_data_w = data_buffer_q[7:0]; |
| assign data_ready_w = data_valid_q[0]; |
| assign crc_byte_w = data_crc_q[0]; |
| assign rx_active_w = rx_active_q[0]; |
| |
| assign rx_active_rise_w = !rx_active_q[3] && utmi_rxactive_i; |
| |
| //----------------------------------------------------------------- |
| // CRC |
| //----------------------------------------------------------------- |
| |
| // CRC16 (Data) |
| usbh_crc16 |
| u_crc16 |
| ( |
| .crc_i(crc_sum_q), |
| .data_i(crc_data_in_w), |
| .crc_o(crc_out_w) |
| ); |
| |
| // CRC5 (Token) |
| usbh_crc5 |
| u_crc5 |
| ( |
| .crc_i(5'h1F), |
| .data_i(token_q[15:5]), |
| .crc_o(crc5_out_w) |
| ); |
| |
| // CRC control / check |
| always @ (posedge clk_i or negedge rstn_i) |
| begin |
| if (!rstn_i) |
| begin |
| crc_sum_q <= 16'hFFFF; |
| status_crc_err_q <= 1'b0; |
| end |
| else |
| begin |
| case (state_q) |
| //----------------------------------------- |
| // TX_PID |
| //----------------------------------------- |
| STATE_TX_PID : |
| begin |
| // First byte is PID (not CRC'd), reset CRC16 |
| crc_sum_q <= 16'hFFFF; |
| end |
| //----------------------------------------- |
| // TX_DATA |
| //----------------------------------------- |
| STATE_TX_DATA : |
| begin |
| // Data sent? |
| if (utmi_txready_i) |
| begin |
| // Next CRC start value |
| crc_sum_q <= crc_out_w; |
| end |
| end |
| //----------------------------------------- |
| // RX_WAIT |
| //----------------------------------------- |
| STATE_RX_WAIT : |
| begin |
| // Reset CRC16 |
| crc_sum_q <= 16'hFFFF; |
| end |
| //----------------------------------------- |
| // RX_DATA |
| //----------------------------------------- |
| STATE_RX_DATA : |
| begin |
| // Data received? |
| if (data_ready_w) |
| begin |
| // Next CRC start value |
| crc_sum_q <= crc_out_w; |
| end |
| // Receive complete |
| else if (!rx_active_w) |
| begin |
| // If some data received, check CRC |
| if (crc_error_w) |
| status_crc_err_q <= 1'b1; |
| else |
| status_crc_err_q <= 1'b0; |
| end |
| end |
| |
| //----------------------------------------- |
| // IDLE / RECEIVE BEGIN |
| //----------------------------------------- |
| STATE_IDLE : |
| begin |
| // Start transfer request |
| if (start_i && !sof_transfer_i) |
| begin |
| // Clear error flag! |
| status_crc_err_q <= 1'b0; |
| end |
| end |
| default : |
| ; |
| endcase |
| end |
| end |
| |
| //----------------------------------------------------------------- |
| // Assignments |
| //----------------------------------------------------------------- |
| wire [15:0] token_rev_w; |
| |
| genvar i; |
| generate |
| for (i=0; i < 16; i=i+1) |
| begin : LOOP |
| assign token_rev_w[i] = token_q[15-i]; |
| end |
| endgenerate |
| |
| reg utmi_txvalid_r; |
| reg [7:0] utmi_data_r; |
| |
| always @ * |
| begin |
| if (state_q == STATE_TX_CRC1) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = crc_sum_q[7:0] ^ 8'hFF; |
| end |
| else if (state_q == STATE_TX_CRC2) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = crc_sum_q[15:8] ^ 8'hFF; |
| end |
| else if (state_q == STATE_TX_TOKEN1) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = token_pid_i; |
| end |
| else if (state_q == STATE_TX_TOKEN2) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = token_rev_w[7:0]; |
| end |
| else if (state_q == STATE_TX_TOKEN3) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = token_rev_w[15:8]; |
| end |
| else if (state_q == STATE_TX_PID) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = send_data1_q ? PID_DATA1 : PID_DATA0; |
| end |
| else if (state_q == STATE_TX_ACKNAK) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = PID_ACK; |
| end |
| else if (state_q == STATE_TX_DATA) |
| begin |
| utmi_txvalid_r = 1'b1; |
| utmi_data_r = tx_data_i; |
| end |
| else |
| begin |
| utmi_txvalid_r = 1'b0; |
| utmi_data_r = 8'b0; |
| end |
| end |
| |
| assign utmi_txvalid_o = utmi_txvalid_r; |
| assign utmi_data_o = utmi_data_r; |
| |
| // Push incoming data into FIFO (not PID or CRC) |
| assign rx_data_o = rx_data_w; |
| assign rx_push_o = (state_q != STATE_IDLE && state_q != STATE_RX_WAIT) & data_ready_w & !crc_byte_w; |
| |
| assign crc_data_in_w = (state_q == STATE_RX_DATA) ? rx_data_w : tx_data_i; |
| |
| assign rx_count_o = byte_count_q; |
| assign idle_o = (state_q == STATE_IDLE); |
| |
| assign ack_o = start_ack_q; |
| |
| assign tx_pop_o = state_q == STATE_TX_DATA && utmi_txready_i; |
| |
| assign tx_done_o = status_tx_done_q; |
| assign rx_done_o = status_rx_done_q; |
| assign crc_err_o = status_crc_err_q; |
| assign timeout_o = status_timeout_q; |
| assign response_o = status_response_q; |
| |
| |
| |
| endmodule |