blob: 91073ccb441a261e9422923b6d2fa435e423e5a2 [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// 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
//-----------------------------------------------------------------
`include "usbh_host_defs.v"
//-----------------------------------------------------------------
// Module: USB Host IP
//-----------------------------------------------------------------
module usbh_core
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
parameter USB_CLK_FREQ = 60000000
)
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
// Inputs
input logic clk_i,
input logic rstn_i,
// Reg Bus Interface Signal
input logic reg_cs,
input logic reg_wr,
input logic [5:0] reg_addr,
input logic [31:0] reg_wdata,
input logic [3:0] reg_be,
// Outputs
output logic [31:0] reg_rdata,
output logic reg_ack,
// UTMI Input
input logic [7:0] utmi_data_in_i,
input logic utmi_txready_i,
input logic utmi_rxvalid_i,
input logic utmi_rxactive_i,
input logic utmi_rxerror_i,
input logic [1:0] utmi_linestate_i,
// UTMI Outputs
output logic intr_o,
output logic [7:0] utmi_data_out_o,
output logic utmi_txvalid_o,
output logic [1:0] utmi_op_mode_o,
output logic [1:0] utmi_xcvrselect_o,
output logic utmi_termselect_o,
output logic utmi_dppulldown_o,
output logic utmi_dmpulldown_o
);
reg [31:0] reg_rdata_r;
wire [15:0] usb_status_sof_time_in_w;
wire usb_status_rx_error_in_w;
wire [1:0] usb_status_linestate_bits_in_w;
wire usb_irq_sts_device_detect_in_w;
wire usb_irq_sts_err_in_w;
wire usb_irq_sts_done_in_w;
wire usb_irq_sts_sof_in_w;
wire usb_rx_stat_start_pend_in_w;
wire usb_rx_stat_crc_err_in_w;
wire usb_rx_stat_resp_timeout_in_w;
wire usb_rx_stat_idle_in_w;
wire [7:0] usb_rx_stat_resp_bits_in_w;
wire [15:0] usb_rx_stat_count_bits_in_w;
wire [7:0] usb_rd_data_data_in_w;
//-----------------------------------------------------------------------
// Read path mux
//-----------------------------------------------------------------------
logic cfg_wr;
always @ (posedge clk_i or negedge rstn_i)
begin : preg_out_Seq
if (rstn_i == 1'b0) begin
reg_rdata [31:0] <= 32'h0000_0000;
reg_ack <= 1'b0;
cfg_wr <= 1'b0;
end else if (reg_cs && (reg_wr == 0) && !reg_ack) begin
reg_rdata [31:0] <= reg_rdata_r [31:0];
reg_ack <= 1'b1;
end else if (reg_cs && (reg_wr == 1) && !reg_ack) begin
reg_ack <= 1'b1;
cfg_wr <= 1'b1;
end else begin
reg_ack <= 1'b0;
cfg_wr <= 1'b0;
end
end
//-----------------------------------------------------------------
// Register usb_ctrl
//-----------------------------------------------------------------
reg usb_ctrl_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_wr_q <= 1'b1;
else
usb_ctrl_wr_q <= 1'b0;
// usb_ctrl_tx_flush [auto_clr]
reg usb_ctrl_tx_flush_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_tx_flush_q <= 1'd`USB_CTRL_TX_FLUSH_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_tx_flush_q <= reg_wdata[`USB_CTRL_TX_FLUSH_R];
else
usb_ctrl_tx_flush_q <= 1'd`USB_CTRL_TX_FLUSH_DEFAULT;
wire usb_ctrl_tx_flush_out_w = usb_ctrl_tx_flush_q;
// usb_ctrl_phy_dmpulldown [internal]
reg usb_ctrl_phy_dmpulldown_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_phy_dmpulldown_q <= 1'd`USB_CTRL_PHY_DMPULLDOWN_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_phy_dmpulldown_q <= reg_wdata[`USB_CTRL_PHY_DMPULLDOWN_R];
wire usb_ctrl_phy_dmpulldown_out_w = usb_ctrl_phy_dmpulldown_q;
// usb_ctrl_phy_dppulldown [internal]
reg usb_ctrl_phy_dppulldown_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_phy_dppulldown_q <= 1'd`USB_CTRL_PHY_DPPULLDOWN_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_phy_dppulldown_q <= reg_wdata[`USB_CTRL_PHY_DPPULLDOWN_R];
wire usb_ctrl_phy_dppulldown_out_w = usb_ctrl_phy_dppulldown_q;
// usb_ctrl_phy_termselect [internal]
reg usb_ctrl_phy_termselect_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_phy_termselect_q <= 1'd`USB_CTRL_PHY_TERMSELECT_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_phy_termselect_q <= reg_wdata[`USB_CTRL_PHY_TERMSELECT_R];
wire usb_ctrl_phy_termselect_out_w = usb_ctrl_phy_termselect_q;
// usb_ctrl_phy_xcvrselect [internal]
reg [1:0] usb_ctrl_phy_xcvrselect_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_phy_xcvrselect_q <= 2'd`USB_CTRL_PHY_XCVRSELECT_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_phy_xcvrselect_q <= reg_wdata[`USB_CTRL_PHY_XCVRSELECT_R];
wire [1:0] usb_ctrl_phy_xcvrselect_out_w = usb_ctrl_phy_xcvrselect_q;
// usb_ctrl_phy_opmode [internal]
reg [1:0] usb_ctrl_phy_opmode_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_phy_opmode_q <= 2'd`USB_CTRL_PHY_OPMODE_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_phy_opmode_q <= reg_wdata[`USB_CTRL_PHY_OPMODE_R];
wire [1:0] usb_ctrl_phy_opmode_out_w = usb_ctrl_phy_opmode_q;
// usb_ctrl_enable_sof [internal]
reg usb_ctrl_enable_sof_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_ctrl_enable_sof_q <= 1'd`USB_CTRL_ENABLE_SOF_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_CTRL))
usb_ctrl_enable_sof_q <= reg_wdata[`USB_CTRL_ENABLE_SOF_R];
wire usb_ctrl_enable_sof_out_w = usb_ctrl_enable_sof_q;
//-----------------------------------------------------------------
// Register usb_status
//-----------------------------------------------------------------
reg usb_status_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_status_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_STATUS))
usb_status_wr_q <= 1'b1;
else
usb_status_wr_q <= 1'b0;
//-----------------------------------------------------------------
// Register usb_irq_ack
//-----------------------------------------------------------------
reg usb_irq_ack_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_ack_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_ACK))
usb_irq_ack_wr_q <= 1'b1;
else
usb_irq_ack_wr_q <= 1'b0;
// usb_irq_ack_device_detect [auto_clr]
reg usb_irq_ack_device_detect_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_ack_device_detect_q <= 1'd`USB_IRQ_ACK_DEVICE_DETECT_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_ACK))
usb_irq_ack_device_detect_q <= reg_wdata[`USB_IRQ_ACK_DEVICE_DETECT_R];
else
usb_irq_ack_device_detect_q <= 1'd`USB_IRQ_ACK_DEVICE_DETECT_DEFAULT;
wire usb_irq_ack_device_detect_out_w = usb_irq_ack_device_detect_q;
// usb_irq_ack_err [auto_clr]
reg usb_irq_ack_err_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_ack_err_q <= 1'd`USB_IRQ_ACK_ERR_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_ACK))
usb_irq_ack_err_q <= reg_wdata[`USB_IRQ_ACK_ERR_R];
else
usb_irq_ack_err_q <= 1'd`USB_IRQ_ACK_ERR_DEFAULT;
wire usb_irq_ack_err_out_w = usb_irq_ack_err_q;
// usb_irq_ack_done [auto_clr]
reg usb_irq_ack_done_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_ack_done_q <= 1'd`USB_IRQ_ACK_DONE_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_ACK))
usb_irq_ack_done_q <= reg_wdata[`USB_IRQ_ACK_DONE_R];
else
usb_irq_ack_done_q <= 1'd`USB_IRQ_ACK_DONE_DEFAULT;
wire usb_irq_ack_done_out_w = usb_irq_ack_done_q;
// usb_irq_ack_sof [auto_clr]
reg usb_irq_ack_sof_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_ack_sof_q <= 1'd`USB_IRQ_ACK_SOF_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_ACK))
usb_irq_ack_sof_q <= reg_wdata[`USB_IRQ_ACK_SOF_R];
else
usb_irq_ack_sof_q <= 1'd`USB_IRQ_ACK_SOF_DEFAULT;
wire usb_irq_ack_sof_out_w = usb_irq_ack_sof_q;
//-----------------------------------------------------------------
// Register usb_irq_sts
//-----------------------------------------------------------------
reg usb_irq_sts_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_sts_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_STS))
usb_irq_sts_wr_q <= 1'b1;
else
usb_irq_sts_wr_q <= 1'b0;
//-----------------------------------------------------------------
// Register usb_irq_mask
//-----------------------------------------------------------------
reg usb_irq_mask_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_mask_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_MASK))
usb_irq_mask_wr_q <= 1'b1;
else
usb_irq_mask_wr_q <= 1'b0;
// usb_irq_mask_device_detect [internal]
reg usb_irq_mask_device_detect_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_mask_device_detect_q <= 1'd`USB_IRQ_MASK_DEVICE_DETECT_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_MASK))
usb_irq_mask_device_detect_q <= reg_wdata[`USB_IRQ_MASK_DEVICE_DETECT_R];
wire usb_irq_mask_device_detect_out_w = usb_irq_mask_device_detect_q;
// usb_irq_mask_err [internal]
reg usb_irq_mask_err_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_mask_err_q <= 1'd`USB_IRQ_MASK_ERR_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_MASK))
usb_irq_mask_err_q <= reg_wdata[`USB_IRQ_MASK_ERR_R];
wire usb_irq_mask_err_out_w = usb_irq_mask_err_q;
// usb_irq_mask_done [internal]
reg usb_irq_mask_done_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_mask_done_q <= 1'd`USB_IRQ_MASK_DONE_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_MASK))
usb_irq_mask_done_q <= reg_wdata[`USB_IRQ_MASK_DONE_R];
wire usb_irq_mask_done_out_w = usb_irq_mask_done_q;
// usb_irq_mask_sof [internal]
reg usb_irq_mask_sof_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_irq_mask_sof_q <= 1'd`USB_IRQ_MASK_SOF_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_IRQ_MASK))
usb_irq_mask_sof_q <= reg_wdata[`USB_IRQ_MASK_SOF_R];
wire usb_irq_mask_sof_out_w = usb_irq_mask_sof_q;
//-----------------------------------------------------------------
// Register usb_xfer_data
//-----------------------------------------------------------------
reg usb_xfer_data_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_data_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_DATA))
usb_xfer_data_wr_q <= 1'b1;
else
usb_xfer_data_wr_q <= 1'b0;
// usb_xfer_data_tx_len [internal]
reg [15:0] usb_xfer_data_tx_len_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_data_tx_len_q <= 16'd`USB_XFER_DATA_TX_LEN_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_DATA))
usb_xfer_data_tx_len_q <= reg_wdata[`USB_XFER_DATA_TX_LEN_R];
wire [15:0] usb_xfer_data_tx_len_out_w = usb_xfer_data_tx_len_q;
//-----------------------------------------------------------------
// Register usb_xfer_token
//-----------------------------------------------------------------
reg usb_xfer_token_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_wr_q <= 1'b1;
else
usb_xfer_token_wr_q <= 1'b0;
// usb_xfer_token_start [clearable]
reg usb_xfer_token_start_q;
wire usb_xfer_token_start_ack_in_w;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_start_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_start_q <= reg_wdata[`USB_XFER_TOKEN_START_R];
else if (usb_xfer_token_start_ack_in_w)
usb_xfer_token_start_q <= 1'b0;
wire usb_xfer_token_start_out_w = usb_xfer_token_start_q;
// usb_xfer_token_in [internal]
reg usb_xfer_token_in_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_in_q <= 1'd`USB_XFER_TOKEN_IN_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_in_q <= reg_wdata[`USB_XFER_TOKEN_IN_R];
wire usb_xfer_token_in_out_w = usb_xfer_token_in_q;
// usb_xfer_token_ack [internal]
reg usb_xfer_token_ack_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_ack_q <= 1'd`USB_XFER_TOKEN_ACK_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_ack_q <= reg_wdata[`USB_XFER_TOKEN_ACK_R];
wire usb_xfer_token_ack_out_w = usb_xfer_token_ack_q;
// usb_xfer_token_pid_datax [internal]
reg usb_xfer_token_pid_datax_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_pid_datax_q <= 1'd`USB_XFER_TOKEN_PID_DATAX_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_pid_datax_q <= reg_wdata[`USB_XFER_TOKEN_PID_DATAX_R];
wire usb_xfer_token_pid_datax_out_w = usb_xfer_token_pid_datax_q;
// usb_xfer_token_pid_bits [internal]
reg [7:0] usb_xfer_token_pid_bits_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_pid_bits_q <= 8'd`USB_XFER_TOKEN_PID_BITS_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_pid_bits_q <= reg_wdata[`USB_XFER_TOKEN_PID_BITS_R];
wire [7:0] usb_xfer_token_pid_bits_out_w = usb_xfer_token_pid_bits_q;
// usb_xfer_token_dev_addr [internal]
reg [6:0] usb_xfer_token_dev_addr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_dev_addr_q <= 7'd`USB_XFER_TOKEN_DEV_ADDR_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_dev_addr_q <= reg_wdata[`USB_XFER_TOKEN_DEV_ADDR_R];
wire [6:0] usb_xfer_token_dev_addr_out_w = usb_xfer_token_dev_addr_q;
// usb_xfer_token_ep_addr [internal]
reg [3:0] usb_xfer_token_ep_addr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_xfer_token_ep_addr_q <= 4'd`USB_XFER_TOKEN_EP_ADDR_DEFAULT;
else if (cfg_wr && (reg_addr[5:0] == `USB_XFER_TOKEN))
usb_xfer_token_ep_addr_q <= reg_wdata[`USB_XFER_TOKEN_EP_ADDR_R];
wire [3:0] usb_xfer_token_ep_addr_out_w = usb_xfer_token_ep_addr_q;
//-----------------------------------------------------------------
// Register usb_rx_stat
//-----------------------------------------------------------------
reg usb_rx_stat_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_rx_stat_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_RX_STAT))
usb_rx_stat_wr_q <= 1'b1;
else
usb_rx_stat_wr_q <= 1'b0;
//-----------------------------------------------------------------
// Retime write data
//-----------------------------------------------------------------
reg [31:0] wr_data_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
wr_data_q <= 32'b0;
else if (cfg_wr)
wr_data_q <= reg_wdata;
//-----------------------------------------------------------------
// Register usb_wr_data
//-----------------------------------------------------------------
reg usb_wr_data_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_wr_data_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_WR_DATA))
usb_wr_data_wr_q <= 1'b1;
else
usb_wr_data_wr_q <= 1'b0;
// usb_wr_data_data [external]
wire [7:0] usb_wr_data_data_out_w = wr_data_q[`USB_WR_DATA_DATA_R];
//-----------------------------------------------------------------
// Read mux
//-----------------------------------------------------------------
always @ *
begin
reg_rdata_r = 32'b0;
case (reg_addr[5:0])
`USB_CTRL:
begin
reg_rdata_r[`USB_CTRL_PHY_DMPULLDOWN_R] = usb_ctrl_phy_dmpulldown_q;
reg_rdata_r[`USB_CTRL_PHY_DPPULLDOWN_R] = usb_ctrl_phy_dppulldown_q;
reg_rdata_r[`USB_CTRL_PHY_TERMSELECT_R] = usb_ctrl_phy_termselect_q;
reg_rdata_r[`USB_CTRL_PHY_XCVRSELECT_R] = usb_ctrl_phy_xcvrselect_q;
reg_rdata_r[`USB_CTRL_PHY_OPMODE_R] = usb_ctrl_phy_opmode_q;
reg_rdata_r[`USB_CTRL_ENABLE_SOF_R] = usb_ctrl_enable_sof_q;
end
`USB_STATUS:
begin
reg_rdata_r[`USB_STATUS_SOF_TIME_R] = usb_status_sof_time_in_w;
reg_rdata_r[`USB_STATUS_RX_ERROR_R] = usb_status_rx_error_in_w;
reg_rdata_r[`USB_STATUS_LINESTATE_BITS_R] = usb_status_linestate_bits_in_w;
end
`USB_IRQ_STS:
begin
reg_rdata_r[`USB_IRQ_STS_DEVICE_DETECT_R] = usb_irq_sts_device_detect_in_w;
reg_rdata_r[`USB_IRQ_STS_ERR_R] = usb_irq_sts_err_in_w;
reg_rdata_r[`USB_IRQ_STS_DONE_R] = usb_irq_sts_done_in_w;
reg_rdata_r[`USB_IRQ_STS_SOF_R] = usb_irq_sts_sof_in_w;
end
`USB_IRQ_MASK:
begin
reg_rdata_r[`USB_IRQ_MASK_DEVICE_DETECT_R] = usb_irq_mask_device_detect_q;
reg_rdata_r[`USB_IRQ_MASK_ERR_R] = usb_irq_mask_err_q;
reg_rdata_r[`USB_IRQ_MASK_DONE_R] = usb_irq_mask_done_q;
reg_rdata_r[`USB_IRQ_MASK_SOF_R] = usb_irq_mask_sof_q;
end
`USB_XFER_DATA:
begin
reg_rdata_r[`USB_XFER_DATA_TX_LEN_R] = usb_xfer_data_tx_len_q;
end
`USB_XFER_TOKEN:
begin
reg_rdata_r[`USB_XFER_TOKEN_IN_R] = usb_xfer_token_in_q;
reg_rdata_r[`USB_XFER_TOKEN_ACK_R] = usb_xfer_token_ack_q;
reg_rdata_r[`USB_XFER_TOKEN_PID_DATAX_R] = usb_xfer_token_pid_datax_q;
reg_rdata_r[`USB_XFER_TOKEN_PID_BITS_R] = usb_xfer_token_pid_bits_q;
reg_rdata_r[`USB_XFER_TOKEN_DEV_ADDR_R] = usb_xfer_token_dev_addr_q;
reg_rdata_r[`USB_XFER_TOKEN_EP_ADDR_R] = usb_xfer_token_ep_addr_q;
end
`USB_RX_STAT:
begin
reg_rdata_r[`USB_RX_STAT_START_PEND_R] = usb_rx_stat_start_pend_in_w;
reg_rdata_r[`USB_RX_STAT_CRC_ERR_R] = usb_rx_stat_crc_err_in_w;
reg_rdata_r[`USB_RX_STAT_RESP_TIMEOUT_R] = usb_rx_stat_resp_timeout_in_w;
reg_rdata_r[`USB_RX_STAT_IDLE_R] = usb_rx_stat_idle_in_w;
reg_rdata_r[`USB_RX_STAT_RESP_BITS_R] = usb_rx_stat_resp_bits_in_w;
reg_rdata_r[`USB_RX_STAT_COUNT_BITS_R] = usb_rx_stat_count_bits_in_w;
end
`USB_RD_DATA:
begin
reg_rdata_r[`USB_RD_DATA_DATA_R] = usb_rd_data_data_in_w;
end
default :
reg_rdata_r = 32'b0;
endcase
end
//-----------------------------------------------------------------
// Register usb_rd_data
//-----------------------------------------------------------------
reg usb_rd_data_wr_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_rd_data_wr_q <= 1'b0;
else if (cfg_wr && (reg_addr[5:0] == `USB_RD_DATA))
usb_rd_data_wr_q <= 1'b1;
else
usb_rd_data_wr_q <= 1'b0;
wire usb_rd_data_rd_req_w = reg_cs & (reg_wr==0) & (!reg_ack) & (reg_addr[5:0] == `USB_RD_DATA);
wire usb_wr_data_wr_req_w = usb_wr_data_wr_q;
wire usb_rd_data_wr_req_w = usb_rd_data_wr_q;
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
// SOF
reg [10:0] sof_value_q;
reg [15:0] sof_time_q;
reg sof_irq_q;
reg transfer_req_ack_q;
wire [7:0] fifo_tx_data_w;
wire fifo_tx_pop_w;
wire [7:0] fifo_rx_data_w;
wire fifo_rx_push_w;
reg fifo_flush_q;
wire [7:0] token_pid_w;
wire [6:0] token_dev_w;
wire [3:0] token_ep_w;
reg transfer_start_q;
reg in_transfer_q;
reg sof_transfer_q;
reg resp_expected_q;
wire transfer_ack_w;
wire status_crc_err_w;
wire status_timeout_w;
wire [7:0] status_response_w;
wire [15:0] status_rx_count_w;
wire status_sie_idle_w;
wire status_tx_done_w;
wire status_rx_done_w;
wire send_sof_w;
wire sof_gaurd_band_w;
wire clear_to_send_w;
reg usb_err_q;
reg intr_done_q;
reg intr_sof_q;
reg intr_err_q;
//-----------------------------------------------------------------
// Definitions
//-----------------------------------------------------------------
localparam SOF_ZERO = 0;
localparam SOF_INC = 1;
localparam SOF_THRESHOLD = (USB_CLK_FREQ/1000)-1;
localparam CLKS_PER_BIT = (USB_CLK_FREQ / 12000000); // input clks per FS bit time
localparam EOF1_THRESHOLD = (50 * CLKS_PER_BIT); // EOF1 + some margin
localparam MAX_XFER_SIZE = 64;
localparam MAX_XFER_PERIOD = ((MAX_XFER_SIZE + 6) * 10 * CLKS_PER_BIT); // Max packet transfer time (+ margin)
localparam SOF_GAURD_LOW = (20 * CLKS_PER_BIT);
localparam SOF_GAURD_HIGH = SOF_THRESHOLD - EOF1_THRESHOLD - MAX_XFER_PERIOD;
localparam PID_SOF = 8'hA5;
//-----------------------------------------------------------------
// SIE
//-----------------------------------------------------------------
usbh_sie
#( .USB_CLK_FREQ(USB_CLK_FREQ) )
u_sie
(
// Clock & reset
.clk_i(clk_i),
.rstn_i(rstn_i),
// Control
.start_i(transfer_start_q),
.in_transfer_i(in_transfer_q),
.sof_transfer_i(sof_transfer_q),
.resp_expected_i(resp_expected_q),
.ack_o(transfer_ack_w),
// Token packet
.token_pid_i(token_pid_w),
.token_dev_i(token_dev_w),
.token_ep_i(token_ep_w),
// Data packet
.data_len_i(usb_xfer_data_tx_len_out_w),
.data_idx_i(usb_xfer_token_pid_datax_out_w),
// Tx Data FIFO
.tx_data_i(fifo_tx_data_w),
.tx_pop_o(fifo_tx_pop_w),
// Rx Data FIFO
.rx_data_o(fifo_rx_data_w),
.rx_push_o(fifo_rx_push_w),
// Status
.rx_done_o(status_rx_done_w),
.tx_done_o(status_tx_done_w),
.crc_err_o(status_crc_err_w),
.timeout_o(status_timeout_w),
.response_o(status_response_w),
.rx_count_o(status_rx_count_w),
.idle_o(status_sie_idle_w),
// UTMI Interface
.utmi_data_o(utmi_data_out_o),
.utmi_txvalid_o(utmi_txvalid_o),
.utmi_txready_i(utmi_txready_i),
.utmi_data_i(utmi_data_in_i),
.utmi_rxvalid_i(utmi_rxvalid_i),
.utmi_rxactive_i(utmi_rxactive_i),
.utmi_linestate_i(utmi_linestate_i)
);
//-----------------------------------------------------------------
// Peripheral Interface
//-----------------------------------------------------------------
assign usb_status_sof_time_in_w = sof_time_q;
assign usb_status_rx_error_in_w = usb_err_q;
assign usb_status_linestate_bits_in_w = utmi_linestate_i;
assign usb_irq_sts_err_in_w = intr_err_q;
assign usb_irq_sts_done_in_w = intr_done_q;
assign usb_irq_sts_sof_in_w = intr_sof_q;
assign usb_rx_stat_start_pend_in_w = usb_xfer_token_start_out_w;
assign usb_rx_stat_crc_err_in_w = status_crc_err_w;
assign usb_rx_stat_resp_timeout_in_w = status_timeout_w;
assign usb_rx_stat_idle_in_w = status_sie_idle_w;
assign usb_rx_stat_resp_bits_in_w = status_response_w;
assign usb_rx_stat_count_bits_in_w = status_rx_count_w;
assign usb_xfer_token_start_ack_in_w = transfer_req_ack_q;
assign utmi_op_mode_o = usb_ctrl_phy_opmode_out_w;
assign utmi_xcvrselect_o = usb_ctrl_phy_xcvrselect_out_w;
assign utmi_termselect_o = usb_ctrl_phy_termselect_out_w;
assign utmi_dppulldown_o = usb_ctrl_phy_dppulldown_out_w;
assign utmi_dmpulldown_o = usb_ctrl_phy_dmpulldown_out_w;
//-----------------------------------------------------------------
// Tx FIFO (Host -> Device)
//-----------------------------------------------------------------
usbh_fifo
u_fifo_tx
(
.clk_i(clk_i),
.rstn_i(rstn_i),
.data_i(usb_wr_data_data_out_w),
.push_i(usb_wr_data_wr_req_w),
.flush_i(usb_ctrl_tx_flush_out_w),
.full_o(),
.empty_o(),
.data_o(fifo_tx_data_w),
.pop_i(fifo_tx_pop_w)
);
//-----------------------------------------------------------------
// Rx FIFO (Device -> Host)
//-----------------------------------------------------------------
usbh_fifo
u_fifo_rx
(
.clk_i(clk_i),
.rstn_i(rstn_i),
// Receive from UTMI interface
.data_i(fifo_rx_data_w),
.push_i(fifo_rx_push_w),
.flush_i(fifo_flush_q),
.full_o(),
.empty_o(),
.data_o(usb_rd_data_data_in_w),
.pop_i(usb_rd_data_rd_req_w)
);
//-----------------------------------------------------------------
// Assignments
//-----------------------------------------------------------------
assign send_sof_w = ({16'b0, sof_time_q} == SOF_THRESHOLD && usb_ctrl_enable_sof_out_w) & status_sie_idle_w;
assign sof_gaurd_band_w = ({16'b0, sof_time_q} <= SOF_GAURD_LOW || {16'b0, sof_time_q} >= SOF_GAURD_HIGH);
assign clear_to_send_w = (~sof_gaurd_band_w | ~usb_ctrl_enable_sof_out_w) & status_sie_idle_w;
assign token_pid_w = sof_transfer_q ? PID_SOF : usb_xfer_token_pid_bits_out_w;
assign token_dev_w = sof_transfer_q ?
{sof_value_q[0], sof_value_q[1], sof_value_q[2],
sof_value_q[3], sof_value_q[4], sof_value_q[5], sof_value_q[6]} :
{usb_xfer_token_dev_addr_out_w[0], usb_xfer_token_dev_addr_out_w[1], usb_xfer_token_dev_addr_out_w[2], usb_xfer_token_dev_addr_out_w[3], usb_xfer_token_dev_addr_out_w[4], usb_xfer_token_dev_addr_out_w[5], usb_xfer_token_dev_addr_out_w[6]};
assign token_ep_w = sof_transfer_q ?
{sof_value_q[7], sof_value_q[8], sof_value_q[9], sof_value_q[10]} :
{usb_xfer_token_ep_addr_out_w[0], usb_xfer_token_ep_addr_out_w[1], usb_xfer_token_ep_addr_out_w[2], usb_xfer_token_ep_addr_out_w[3]};
//-----------------------------------------------------------------
// Control logic
//-----------------------------------------------------------------
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
begin
fifo_flush_q <= 1'b0;
transfer_start_q <= 1'b0;
sof_transfer_q <= 1'b0;
transfer_req_ack_q <= 1'b0;
in_transfer_q <= 1'b0;
resp_expected_q <= 1'b0;
end
else
begin
// Transfer in progress?
if (transfer_start_q)
begin
// Transfer accepted
if (transfer_ack_w)
transfer_start_q <= 1'b0;
fifo_flush_q <= 1'b0;
transfer_req_ack_q <= 1'b0;
end
// Time to send another SOF token?
else if (send_sof_w)
begin
// Start transfer
in_transfer_q <= 1'b0;
resp_expected_q <= 1'b0;
transfer_start_q <= 1'b1;
sof_transfer_q <= 1'b1;
end
// Not in SOF gaurd band region or SOF disabled?
else if (clear_to_send_w)
begin
// Transfer request
if (usb_xfer_token_start_out_w)
begin
// Flush un-used previous Rx data
fifo_flush_q <= 1'b1;
// Start transfer
in_transfer_q <= usb_xfer_token_in_out_w;
resp_expected_q <= usb_xfer_token_ack_out_w;
transfer_start_q <= 1'b1;
sof_transfer_q <= 1'b0;
transfer_req_ack_q <= 1'b1;
end
end
end
//-----------------------------------------------------------------
// SOF Frame Number
//-----------------------------------------------------------------
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
begin
sof_value_q <= 11'd0;
sof_time_q <= SOF_ZERO;
sof_irq_q <= 1'b0;
end
// Time to send another SOF token?
else if (send_sof_w)
begin
sof_time_q <= SOF_ZERO;
sof_value_q <= sof_value_q + 11'd1;
// Start of frame interrupt
sof_irq_q <= 1'b1;
end
else
begin
// Increment the SOF timer
if ({16'b0, sof_time_q} != SOF_THRESHOLD)
sof_time_q <= sof_time_q + SOF_INC;
sof_irq_q <= 1'b0;
end
//-----------------------------------------------------------------
// Record Errors
//-----------------------------------------------------------------
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
usb_err_q <= 1'b0;
// Clear error
else if (usb_ctrl_wr_q)
usb_err_q <= 1'b0;
// Record bus errors
else if (utmi_rxerror_i)
usb_err_q <= 1'b1;
//-----------------------------------------------------------------
// Interrupts
//-----------------------------------------------------------------
reg err_cond_q;
reg intr_q;
reg device_det_q;
always @ (posedge clk_i or negedge rstn_i)
if (!rstn_i)
begin
intr_done_q <= 1'b0;
intr_sof_q <= 1'b0;
intr_err_q <= 1'b0;
err_cond_q <= 1'b0;
device_det_q <= 1'b0;
intr_q <= 1'b0;
end
else
begin
if (status_rx_done_w || status_tx_done_w)
intr_done_q <= 1'b1;
else if (usb_irq_ack_done_out_w)
intr_done_q <= 1'b0;
if (sof_irq_q)
intr_sof_q <= 1'b1;
else if (usb_irq_ack_sof_out_w)
intr_sof_q <= 1'b0;
if ((status_crc_err_w || status_timeout_w) && (!err_cond_q))
intr_err_q <= 1'b1;
else if (usb_irq_ack_err_out_w)
intr_err_q <= 1'b0;
// Line state != SE0
if (utmi_linestate_i != 2'b0)
device_det_q <= 1'b1;
else if (usb_irq_ack_device_detect_out_w)
device_det_q <= 1'b0;
err_cond_q <= (status_crc_err_w | status_timeout_w);
intr_q <= (intr_done_q & usb_irq_mask_done_out_w) |
(intr_err_q & usb_irq_mask_err_out_w) |
(intr_sof_q & usb_irq_mask_sof_out_w) |
(device_det_q & usb_irq_mask_device_detect_out_w);
end
assign usb_irq_sts_device_detect_in_w = 1'b0;
assign intr_o = intr_q;
endmodule