OpenCores
URL https://opencores.org/ocsvn/usb_host_core/usb_host_core/trunk

Subversion Repositories usb_host_core

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /usb_host_core/trunk
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/rtl/usbh_crc5.v
0,0 → 1,59
//-----------------------------------------------------------------
// USB Full Speed Host
// V0.1
// Ultra-Embedded.com
// Copyright 2015
//
// 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
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: 5-bit CRC used by USB tokens
//-----------------------------------------------------------------
module usbh_crc5
(
input [4:0] crc_i,
input [10:0] data_i,
output [4:0] crc_o
);
 
//-----------------------------------------------------------------
// Implementation
//-----------------------------------------------------------------
assign crc_o[0] = data_i[10] ^ data_i[9] ^ data_i[6] ^ data_i[5] ^ data_i[3] ^ data_i[0] ^
crc_i[0] ^ crc_i[3] ^ crc_i[4];
 
assign crc_o[1] = data_i[10] ^ data_i[7] ^ data_i[6] ^ data_i[4] ^ data_i[1] ^
crc_i[0] ^ crc_i[1] ^ crc_i[4];
 
assign crc_o[2] = data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[7] ^ data_i[6] ^ data_i[3] ^ data_i[2] ^ data_i[0] ^
crc_i[0] ^ crc_i[1] ^ crc_i[2] ^ crc_i[3] ^ crc_i[4];
 
assign crc_o[3] = data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[7] ^ data_i[4] ^ data_i[3] ^ data_i[1] ^
crc_i[1] ^ crc_i[2] ^ crc_i[3] ^ crc_i[4];
 
assign crc_o[4] = data_i[10] ^ data_i[9] ^ data_i[8] ^ data_i[5] ^ data_i[4] ^ data_i[2] ^
crc_i[2] ^ crc_i[3] ^ crc_i[4];
 
endmodule
/rtl/usbh_crc16.v
0,0 → 1,69
//-----------------------------------------------------------------
// USB Full Speed Host
// V0.1
// Ultra-Embedded.com
// Copyright 2015
//
// 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
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: 16-bit CRC used by USB data packets
//-----------------------------------------------------------------
module usbh_crc16
(
input [15:0] crc_i,
input [7:0] data_i,
output [15:0] crc_o
);
 
//-----------------------------------------------------------------
// Implementation
//-----------------------------------------------------------------
assign crc_o[15] = data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^
data_i[5] ^ data_i[6] ^ data_i[7] ^ crc_i[7] ^ crc_i[6] ^
crc_i[5] ^ crc_i[4] ^ crc_i[3] ^ crc_i[2] ^
crc_i[1] ^ crc_i[0];
assign crc_o[14] = data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^
data_i[6] ^ crc_i[6] ^ crc_i[5] ^ crc_i[4] ^
crc_i[3] ^ crc_i[2] ^ crc_i[1] ^ crc_i[0];
assign crc_o[13] = data_i[6] ^ data_i[7] ^ crc_i[7] ^ crc_i[6];
assign crc_o[12] = data_i[5] ^ data_i[6] ^ crc_i[6] ^ crc_i[5];
assign crc_o[11] = data_i[4] ^ data_i[5] ^ crc_i[5] ^ crc_i[4];
assign crc_o[10] = data_i[3] ^ data_i[4] ^ crc_i[4] ^ crc_i[3];
assign crc_o[9] = data_i[2] ^ data_i[3] ^ crc_i[3] ^ crc_i[2];
assign crc_o[8] = data_i[1] ^ data_i[2] ^ crc_i[2] ^ crc_i[1];
assign crc_o[7] = data_i[0] ^ data_i[1] ^ crc_i[15] ^ crc_i[1] ^ crc_i[0];
assign crc_o[6] = data_i[0] ^ crc_i[14] ^ crc_i[0];
assign crc_o[5] = crc_i[13];
assign crc_o[4] = crc_i[12];
assign crc_o[3] = crc_i[11];
assign crc_o[2] = crc_i[10];
assign crc_o[1] = crc_i[9];
assign crc_o[0] = data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^
data_i[6] ^ data_i[7] ^ crc_i[8] ^ crc_i[7] ^ crc_i[6] ^
crc_i[5] ^ crc_i[4] ^ crc_i[3] ^ crc_i[2] ^
crc_i[1] ^ crc_i[0];
 
endmodule
/rtl/usbh.v
0,0 → 1,420
//-----------------------------------------------------------------
// USB Full Speed Host
// V0.1
// Ultra-Embedded.com
// Copyright 2015
//
// 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
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: Basic USB host interface
//-----------------------------------------------------------------
module usbh
 
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
parameter TX_FIFO_DEPTH = 64,
parameter TX_FIFO_ADDR_W = 6,
parameter RX_FIFO_DEPTH = 64,
parameter RX_FIFO_ADDR_W = 6
)
 
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
// Clocking (48MHz) & Reset
input clk_i,
input rst_i,
 
// Interrupt output
output intr_o,
// Peripheral Interface (from CPU)
input [7:0] addr_i,
input [31:0] data_i,
output [31:0] data_o,
input we_i,
input stb_i,
 
// UTMI Interface
output [7:0] utmi_data_o,
output utmi_txvalid_o,
input utmi_txready_i,
input [7:0] utmi_data_i,
input utmi_rxvalid_i,
input utmi_rxactive_i,
input utmi_rxerror_i,
input [1:0] utmi_linestate_i,
 
output usb_rst_o
);
 
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
// SOF
reg [10:0] sof_value_q;
reg [15:0] sof_time_q;
reg sof_irq_q;
 
reg transfer_req_ack_q;
 
// Requests for transfers
wire ctrl_sof_en_w;
wire ctrl_in_transfer_w;
wire ctrl_resp_expected_w;
wire ctrl_data_idx_w;
wire [15:0] ctrl_tx_count_w;
wire [7:0] ctrl_token_pid_w;
wire [10:0] ctrl_token_data_w;
 
wire [7:0] fifo_tx_data_w;
wire fifo_tx_pop_w;
 
wire [7:0] fifo_rx_data_w;
wire fifo_rx_push_w;
 
wire [7:0] ctrl_fifo_tx_data_w;
wire ctrl_fifo_tx_push_w;
wire ctrl_fifo_tx_flush_w;
 
wire [7:0] ctrl_fifo_rx_data_w;
wire ctrl_fifo_rx_pop_w;
 
wire ctrl_start_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;
 
//-----------------------------------------------------------------
// Definitions
//-----------------------------------------------------------------
localparam [15:0] SOF_ZERO = 0;
localparam [15:0] SOF_INC = 1;
localparam [15:0] SOF_THRESHOLD = 48000;
 
localparam [15:0] EOF1_THRESHOLD = (50 * 4); // EOF1 + some margin
localparam [15:0] MAX_XFER_SIZE = (TX_FIFO_DEPTH > RX_FIFO_DEPTH) ? TX_FIFO_DEPTH : RX_FIFO_DEPTH;
localparam [15:0] MAX_XFER_PERIOD = ((MAX_XFER_SIZE + 6) * 10 * 4); // Max packet transfer time (+ margin)
localparam [15:0] SOF_GAURD_LOW = (20 * 4);
localparam [15:0] SOF_GAURD_HIGH = SOF_THRESHOLD - EOF1_THRESHOLD - MAX_XFER_PERIOD;
 
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;
 
//-----------------------------------------------------------------
// SIE
//-----------------------------------------------------------------
usbh_sie
u_sie
(
// Clock (48MHz) & reset
.clk_i(clk_i),
.rst_i(rst_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(ctrl_tx_count_w),
.data_idx_i(ctrl_data_idx_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_o),
.utmi_txvalid_o(utmi_txvalid_o),
.utmi_txready_i(utmi_txready_i),
.utmi_data_i(utmi_data_i),
.utmi_rxvalid_i(utmi_rxvalid_i),
.utmi_rxactive_i(utmi_rxactive_i)
);
 
//-----------------------------------------------------------------
// Peripheral Interface
//-----------------------------------------------------------------
usbh_periph
u_pif
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.intr_o(intr_o),
 
// Peripheral Interface (from CPU)
.addr_i(addr_i),
.data_i(data_i),
.data_o(data_o),
.we_i(we_i),
.stb_i(stb_i),
 
// UTMI interface
.utmi_linestate_i(utmi_linestate_i),
.utmi_rxerror_i(utmi_rxerror_i),
 
// Control
.sie_start_o(ctrl_start_w),
.sie_sof_en_o(ctrl_sof_en_w),
.sie_rst_o(usb_rst_o),
.sie_token_pid_o(ctrl_token_pid_w),
.sie_token_data_o(ctrl_token_data_w),
.sie_tx_count_o(ctrl_tx_count_w),
.sie_data_idx_o(ctrl_data_idx_w),
.sie_in_transfer_o(ctrl_in_transfer_w),
.sie_resp_expected_o(ctrl_resp_expected_w),
 
// FIFO
.sie_tx_data_o(ctrl_fifo_tx_data_w),
.sie_tx_push_o(ctrl_fifo_tx_push_w),
.sie_tx_flush_o(ctrl_fifo_tx_flush_w),
.sie_rx_pop_o(ctrl_fifo_rx_pop_w),
.sie_rx_data_i(ctrl_fifo_rx_data_w),
 
// Status
.sie_rx_crc_err_i(status_crc_err_w),
.sie_rx_resp_timeout_i(status_timeout_w),
.sie_rx_resp_pid_i(status_response_w),
.sie_rx_count_i(status_rx_count_w),
.sie_rx_idle_i(status_sie_idle_w),
.sie_req_ack_i(transfer_req_ack_q),
.sie_sof_time_i(sof_time_q),
.sie_rx_done_i(status_rx_done_w),
.sie_tx_done_i(status_tx_done_w),
.sie_sof_irq_i(sof_irq_q)
);
 
//-----------------------------------------------------------------
// Tx FIFO (Host -> Device)
//-----------------------------------------------------------------
usbh_fifo
#(
.DEPTH(TX_FIFO_DEPTH),
.ADDR_W(TX_FIFO_ADDR_W)
)
u_fifo_tx
(
.clk_i(clk_i),
.rst_i(rst_i),
 
.data_i(ctrl_fifo_tx_data_w),
.push_i(ctrl_fifo_tx_push_w),
 
.flush_i(ctrl_fifo_tx_flush_w),
 
.full_o(),
.empty_o(),
 
.data_o(fifo_tx_data_w),
.pop_i(fifo_tx_pop_w)
);
 
//-----------------------------------------------------------------
// Rx FIFO (Device -> Host)
//-----------------------------------------------------------------
usbh_fifo
#(
.DEPTH(RX_FIFO_DEPTH),
.ADDR_W(RX_FIFO_ADDR_W)
)
u_fifo_rx
(
.clk_i(clk_i),
.rst_i(rst_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(ctrl_fifo_rx_data_w),
.pop_i(ctrl_fifo_rx_pop_w)
);
 
//-----------------------------------------------------------------
// Assignments
//-----------------------------------------------------------------
assign send_sof_w = (sof_time_q == SOF_THRESHOLD && ctrl_sof_en_w) & status_sie_idle_w;
assign sof_gaurd_band_w = (sof_time_q <= SOF_GAURD_LOW || sof_time_q >= SOF_GAURD_HIGH);
assign clear_to_send_w = (~sof_gaurd_band_w | ~ctrl_sof_en_w) & status_sie_idle_w;
 
assign token_pid_w = sof_transfer_q ? PID_SOF : ctrl_token_pid_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]} :
ctrl_token_data_w[10:4];
 
assign token_ep_w = sof_transfer_q ?
{sof_value_q[7], sof_value_q[8], sof_value_q[9], sof_value_q[10]} :
ctrl_token_data_w[3:0];
 
//-----------------------------------------------------------------
// Control logic
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
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 (ctrl_start_w)
begin
// Flush un-used previous Rx data
fifo_flush_q <= 1'b1;
 
// Start transfer
in_transfer_q <= ctrl_in_transfer_w;
resp_expected_q <= ctrl_resp_expected_w;
transfer_start_q <= 1'b1;
sof_transfer_q <= 1'b0;
transfer_req_ack_q <= 1'b1;
end
end
end
end
 
//-----------------------------------------------------------------
// SOF Frame Number
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
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 (sof_time_q != SOF_THRESHOLD)
sof_time_q <= sof_time_q + SOF_INC;
 
sof_irq_q <= 1'b0;
end
end
 
endmodule
 
/rtl/usbh_sie.v
0,0 → 1,775
//-----------------------------------------------------------------
// USB Full Speed Host
// V0.1
// Ultra-Embedded.com
// Copyright 2015
//
// 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
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: USB host serial interface engine
//-----------------------------------------------------------------
module usbh_sie
(
// Clocking (48MHz) & Reset
input clk_i,
input rst_i,
 
// Control
input start_i,
input in_transfer_i,
input sof_transfer_i,
input resp_expected_i,
output ack_o,
 
// Token packet
input [7:0] token_pid_i,
input [6:0] token_dev_i,
input [3:0] token_ep_i,
 
// Data packet
input [15:0] data_len_i,
input data_idx_i,
 
// Tx Data FIFO
input [7:0] tx_data_i,
output tx_pop_o,
 
// Rx Data FIFO
output [7:0] rx_data_o,
output rx_push_o,
 
// Status
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,
 
// UTMI Interface
output [7:0] utmi_data_o,
output utmi_txvalid_o,
input utmi_txready_i,
input [7:0] utmi_data_i,
input utmi_rxvalid_i,
input utmi_rxactive_i
);
 
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
reg start_ack_q;
reg tx_pop_q;
 
// Status
reg status_tx_done_q;
reg status_rx_done_q;
reg status_crc_err_q;
reg status_timeout_q;
reg [7:0] status_response_q;
 
reg utmi_txvalid_q;
 
reg pid_byte_q;
reg [15:0] byte_count_q;
reg in_transfer_q;
 
reg [2:0] rx_time_q;
reg rx_time_en_q;
reg [7:0] last_tx_time_q;
 
reg send_data1_q;
reg send_sof_q;
reg send_ack_q;
 
// CRC16
reg [15:0] crc_sum_q;
wire [15:0] crc_out_w;
wire [7:0] crc_data_in_w;
 
// CRC5
wire [4:0] crc5_out_w;
wire [4:0] crc5_next_w = crc5_out_w ^ 5'h1F;
 
reg [15:0] token_q;
 
reg wait_resp_q;
 
//-----------------------------------------------------------------
// Definitions
//-----------------------------------------------------------------
localparam RX_TIMEOUT = 8'd255; // ~5uS
 
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_DATA = 4'd2;
localparam STATE_TX_CRC = 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 RX_TIME_ZERO = 3'd0;
localparam RX_TIME_INC = 3'd1;
localparam RX_TIME_READY = 3'd7; // 2-bit times
 
//-----------------------------------------------------------------
// Wires
//-----------------------------------------------------------------
 
// New byte received
wire data_ready_w = (utmi_rxvalid_i & utmi_rxactive_i);
 
// 2-bit times after last RX (inter-packet delay)?
wire autoresp_thresh_w = send_ack_q & rx_time_en_q & (rx_time_q == RX_TIME_READY);
 
// Response timeout (no response after 500uS from transmit)
wire rx_resp_timeout_w = (last_tx_time_q >= RX_TIMEOUT) & wait_resp_q;
 
//-----------------------------------------------------------------
// State Machine
//-----------------------------------------------------------------
 
// Current state
reg [3:0] state_q;
reg [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_IDLE;
// 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_DATA;
end
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_CRC;
end
//-----------------------------------------
// TX_CRC (generate)
//-----------------------------------------
STATE_TX_CRC :
begin
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 (autoresp_thresh_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 (~utmi_rxvalid_i & ~utmi_rxactive_i)
begin
// Send an ACK/NAK response without CPU interaction?
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 rst_i or posedge clk_i)
if (rst_i == 1'b1)
state_q <= STATE_IDLE;
else
state_q <= next_state_r;
 
//-----------------------------------------------------------------
// Tx Enable
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
utmi_txvalid_q <= 1'b0;
end
else
begin
case (state_q)
 
//-----------------------------------------
// TX_TOKEN1 (byte 1 of token)
//-----------------------------------------
STATE_TX_TOKEN1 :
begin
utmi_txvalid_q <= 1'b1;
end
//-----------------------------------------
// TX_TOKEN3 (byte 3 of token)
//-----------------------------------------
STATE_TX_TOKEN3 :
begin
// Data sent?
if (utmi_txready_i)
utmi_txvalid_q <= 1'b0;
end
//-----------------------------------------
// TX_DATA
//-----------------------------------------
STATE_TX_DATA :
begin
// Tx active
utmi_txvalid_q <= 1'b1;
end
//-----------------------------------------
// TX_CRC (second byte)
//-----------------------------------------
STATE_TX_CRC2 :
begin
// Data sent?
if (utmi_txready_i)
utmi_txvalid_q <= 1'b0;
end
//-----------------------------------------
// STATE_TX_ACKNAK
//-----------------------------------------
STATE_TX_ACKNAK :
begin
// Data sent?
if (utmi_txready_i)
utmi_txvalid_q <= 1'b0;
else
utmi_txvalid_q <= 1'b1;
end
 
default :
;
endcase
end
end
 
//-----------------------------------------------------------------
// Tx Token
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
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 Timer
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
last_tx_time_q <= 8'd0;
// Start counting from last Tx
else if (state_q == STATE_IDLE || utmi_txvalid_q)
last_tx_time_q <= 8'd0;
// Increment the Tx timeout
else if (last_tx_time_q != RX_TIMEOUT)
last_tx_time_q <= last_tx_time_q + 8'd1;
 
//-----------------------------------------------------------------
// Transmit / Receive counter
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
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;
// Transmit byte
else if (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_WAIT || state_q == STATE_RX_DATA) && data_ready_w)
byte_count_q <= byte_count_q + 16'd1;
 
// Recognise first byte in the Tx data packet
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
pid_byte_q <= 1'b0;
// New transfer request, first byte sent in TX_DATA state is the PID
else if (state_q == STATE_IDLE && start_i)
pid_byte_q <= 1'b1;
// Transmit byte
else if (state_q == STATE_TX_DATA && utmi_txready_i)
pid_byte_q <= 1'b0;
 
//-----------------------------------------------------------------
// Transfer start ack
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
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 rst_i or posedge clk_i )
if (rst_i == 1'b1)
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 delay timer
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
rx_time_q <= RX_TIME_ZERO;
rx_time_en_q <= 1'b0;
end
else if (state_q == STATE_IDLE)
begin
rx_time_q <= RX_TIME_ZERO;
rx_time_en_q <= 1'b0;
end
// Receive complete
else if (state_q == STATE_RX_DATA && !utmi_rxactive_i)
begin
// Reset time since end of last data byte
rx_time_q <= RX_TIME_ZERO;
rx_time_en_q <= 1'b1;
end
// Increment timer if enabled (and less than the threshold)
else if (rx_time_en_q && rx_time_q != RX_TIME_READY)
rx_time_q <= rx_time_q + RX_TIME_INC;
 
// Response expected
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
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 rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
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 <= utmi_data_i;
 
// 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
 
//-----------------------------------------------------------------
// FIFO access
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
tx_pop_q <= 1'b0;
// Data byte unload (not PID)
else if (state_q == STATE_TX_DATA && utmi_txready_i && !pid_byte_q)
tx_pop_q <= 1'b1;
else
tx_pop_q <= 1'b0;
 
//-----------------------------------------------------------------
// 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 rst_i or posedge clk_i )
begin
if (rst_i == 1'b1)
begin
crc_sum_q <= 16'hFFFF;
status_crc_err_q <= 1'b0;
end
else
begin
case (state_q)
//-----------------------------------------
// TX_DATA
//-----------------------------------------
STATE_TX_DATA :
begin
// Data sent?
if (utmi_txready_i)
begin
// First byte is PID (not CRC'd), reset CRC16
if (pid_byte_q)
crc_sum_q <= 16'hFFFF;
// Next CRC start value
else
crc_sum_q <= crc_out_w;
end
end
//-----------------------------------------
// TX_CRC (generate)
//-----------------------------------------
STATE_TX_CRC :
begin
// Next CRC start value
crc_sum_q <= crc_sum_q ^ 16'hFFFF;
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 (utmi_rxactive_i == 1'b0)
begin
// If some data received, check CRC
if (crc_sum_q != 16'hB001 && in_transfer_q && byte_count_q != 16'd1)
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
 
// Transmit data
assign utmi_data_o = (state_q == STATE_TX_CRC1) ? crc_sum_q[7:0] :
(state_q == STATE_TX_CRC2) ? crc_sum_q[15:8] :
(state_q == STATE_TX_TOKEN1) ? token_pid_i :
(state_q == STATE_TX_TOKEN2) ? token_rev_w[7:0] :
(state_q == STATE_TX_TOKEN3) ? token_rev_w[15:8] :
(state_q == STATE_TX_DATA && pid_byte_q && send_data1_q) ? PID_DATA1 :
(state_q == STATE_TX_DATA && pid_byte_q && ~send_data1_q) ? PID_DATA0 :
(state_q == STATE_TX_ACKNAK) ? PID_ACK :
tx_data_i;
assign utmi_txvalid_o = utmi_txvalid_q;
 
// Push incoming data into FIFO (not PID or CRC)
assign rx_data_o = utmi_data_i;
assign rx_push_o = (state_q != STATE_IDLE && state_q != STATE_RX_WAIT) & data_ready_w;
 
assign crc_data_in_w = (state_q == STATE_RX_DATA || state_q == STATE_RX_WAIT) ? utmi_data_i : 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 = tx_pop_q;
 
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
/rtl/usbh_fifo.v
0,0 → 1,124
//-----------------------------------------------------------------
// USB Full Speed Host
// V0.1
// Ultra-Embedded.com
// Copyright 2015
//
// 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
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: USB FIFO - simple FIFO
//-----------------------------------------------------------------
module usbh_fifo
 
//-----------------------------------------------------------------
// Params
//-----------------------------------------------------------------
#(
parameter WIDTH = 8,
parameter DEPTH = 4,
parameter ADDR_W = 2
)
 
//-----------------------------------------------------------------
// Ports
//-----------------------------------------------------------------
(
input clk_i,
input rst_i,
 
input [WIDTH-1:0] data_i,
input push_i,
 
output full_o,
output empty_o,
 
output [WIDTH-1:0] data_o,
input pop_i,
 
input flush_i
);
 
//-----------------------------------------------------------------
// Defs / Params
//-----------------------------------------------------------------
localparam COUNT_W = ADDR_W + 1;
 
//-----------------------------------------------------------------
// Registers
//-----------------------------------------------------------------
reg [WIDTH-1:0] ram [DEPTH-1:0];
reg [ADDR_W-1:0] rd_ptr_q;
reg [ADDR_W-1:0] wr_ptr_q;
reg [COUNT_W-1:0] count_q;
 
//-----------------------------------------------------------------
// Sequential
//-----------------------------------------------------------------
always @ (posedge clk_i or posedge rst_i)
begin
if (rst_i)
begin
count_q <= {(COUNT_W) {1'b0}};
rd_ptr_q <= {(ADDR_W) {1'b0}};
wr_ptr_q <= {(ADDR_W) {1'b0}};
end
else if (flush_i)
begin
count_q <= {(COUNT_W) {1'b0}};
rd_ptr_q <= {(ADDR_W) {1'b0}};
wr_ptr_q <= {(ADDR_W) {1'b0}};
end
else
begin
// Push
if (push_i && !full_o)
begin
ram[wr_ptr_q] <= data_i;
wr_ptr_q <= wr_ptr_q + 1;
end
 
// Pop
if (pop_i && !empty_o)
rd_ptr_q <= rd_ptr_q + 1;
 
// Count up
if ((push_i && !full_o) && !(pop_i && !empty_o))
count_q <= count_q + 1;
// Count down
else if (!(push_i && !full_o) && (pop_i && !empty_o))
count_q <= count_q - 1;
end
end
 
//-------------------------------------------------------------------
// Assignments
//-------------------------------------------------------------------
assign full_o = (count_q == DEPTH);
assign empty_o = (count_q == 0);
 
assign data_o = ram[rd_ptr_q];
 
endmodule
/rtl/usbh_periph.v
0,0 → 1,376
//-----------------------------------------------------------------
// USB Full Speed Host
// V0.1
// Ultra-Embedded.com
// Copyright 2015
//
// 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
//-----------------------------------------------------------------
 
//-----------------------------------------------------------------
// Module: Peripheral interface for USB host
//-----------------------------------------------------------------
module usbh_periph
(
// Clocking (48MHz) & Reset
input clk_i,
input rst_i,
 
output intr_o,
 
// Peripheral Interface (from CPU)
input [7:0] addr_i,
input [31:0] data_i,
output [31:0] data_o,
input we_i,
input stb_i,
 
// UTMI interface
input [1:0] utmi_linestate_i,
input utmi_rxerror_i,
 
// Control
output sie_start_o,
output sie_sof_en_o,
output sie_rst_o,
output [7:0] sie_token_pid_o,
output [10:0] sie_token_data_o,
output [15:0] sie_tx_count_o,
output sie_data_idx_o,
output sie_in_transfer_o,
output sie_resp_expected_o,
 
// FIFO
output [7:0] sie_tx_data_o,
output sie_tx_push_o,
output sie_tx_flush_o,
output sie_rx_pop_o,
input [7:0] sie_rx_data_i,
 
// Status
input sie_rx_crc_err_i,
input [7:0] sie_rx_resp_pid_i,
input sie_rx_resp_timeout_i,
input [15:0] sie_rx_count_i,
input sie_rx_idle_i,
input sie_req_ack_i,
input [15:0] sie_sof_time_i,
input sie_rx_done_i,
input sie_tx_done_i,
input sie_sof_irq_i
);
 
//-----------------------------------------------------------------
// Peripheral Memory Map
//-----------------------------------------------------------------
`define USB_CTRL 8'h00
`define USB_TX_FLUSH 2
`define USB_ENABLE_SOF 1
`define USB_RESET_ACTIVE 0
`define USB_STATUS 8'h00
`define USB_STAT_SOF_TIME 31:16
`define USB_STAT_RX_ERROR 2
`define USB_STAT_LINESTATE_BITS 1:0
`define USB_IRQ 8'h04
`define USB_IRQ_MASK 8'h08
`define USB_IRQ_SOF 0
`define USB_IRQ_DONE 1
`define USB_IRQ_ERR 2
`define USB_XFER_DATA 8'h0c
`define USB_XFER_DATA_TX_LEN 15:0
`define USB_XFER_TOKEN 8'h10
`define USB_XFER_START 31
`define USB_XFER_IN 30
`define USB_XFER_ACK 29
`define USB_XFER_PID_DATAX 28
`define USB_XFER_PID_BITS 23:16
`define USB_RX_STAT 8'h14
`define USB_RX_STAT_START_PEND 31
`define USB_RX_STAT_CRC_ERR 30
`define USB_RX_STAT_RESP_TIMEOUT 29
`define USB_RX_STAT_IDLE 28
`define USB_RX_STAT_RESP_BITS 23:16
`define USB_RX_STAT_COUNT_BITS 15:0
`define USB_WR_DATA 8'h18
`define USB_RD_DATA 8'h18
 
//-----------------------------------------------------------------
// Registers / Wires
//-----------------------------------------------------------------
reg usb_err_q;
 
reg intr_done_q;
reg intr_sof_q;
reg intr_err_q;
 
// Interrupt Mask
reg intr_mask_done_q;
reg intr_mask_sof_q;
reg intr_mask_err_q;
 
// Control
reg sie_start_q;
reg sie_sof_en_q;
reg sie_rst_q;
reg [7:0] sie_token_pid_q;
reg [10:0] sie_token_data_q;
reg [15:0] sie_tx_count_q;
reg sie_data_idx_q;
reg sie_in_transfer_q;
reg sie_resp_expected_q;
 
// FIFO
reg [7:0] sie_tx_data_q;
reg sie_tx_push_q;
reg sie_tx_flush_q;
reg sie_rx_pop_q;
 
//-----------------------------------------------------------------
// Control
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
sie_sof_en_q <= 1'b0;
sie_rst_q <= 1'b0;
sie_tx_flush_q <= 1'b0;
end
// IO Write Cycle
else if (we_i && stb_i && (addr_i == `USB_CTRL))
begin
sie_rst_q <= data_i[`USB_RESET_ACTIVE];
sie_sof_en_q <= data_i[`USB_ENABLE_SOF];
sie_tx_flush_q <= data_i[`USB_TX_FLUSH];
end
else
sie_tx_flush_q <= 1'b0;
 
//-----------------------------------------------------------------
// Data FIFO Write
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
sie_tx_data_q <= 8'h00;
sie_tx_push_q <= 1'b0;
end
// IO Write Cycle
else if (we_i && stb_i && (addr_i == `USB_WR_DATA))
begin
sie_tx_data_q <= data_i[7:0];
sie_tx_push_q <= 1'b1;
end
else
sie_tx_push_q <= 1'b0;
 
//-----------------------------------------------------------------
// Tx Length
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
sie_tx_count_q <= 16'h0000;
// IO Write Cycle
else if (we_i && stb_i && (addr_i == `USB_XFER_DATA))
sie_tx_count_q <= data_i[`USB_XFER_DATA_TX_LEN];
 
//-----------------------------------------------------------------
// Tx Token
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
sie_start_q <= 1'b0;
sie_in_transfer_q <= 1'b0;
sie_resp_expected_q<= 1'b0;
sie_token_pid_q <= 8'h00;
sie_token_data_q <= 11'h000;
sie_data_idx_q <= 1'b0;
end
// IO Write Cycle
else if (we_i && stb_i && (addr_i == `USB_XFER_TOKEN))
begin
sie_start_q <= data_i[`USB_XFER_START];
sie_in_transfer_q <= data_i[`USB_XFER_IN];
sie_resp_expected_q<= data_i[`USB_XFER_ACK];
sie_data_idx_q <= data_i[`USB_XFER_PID_DATAX];
sie_token_pid_q <= data_i[`USB_XFER_PID_BITS];
sie_token_data_q <= { data_i[9], data_i[10], data_i[11], data_i[12], data_i[13], data_i[14], data_i[15],
data_i[5], data_i[6], data_i[7], data_i[8] };
end
else if (sie_req_ack_i)
sie_start_q <= 1'b0;
 
//-----------------------------------------------------------------
// Interrupt Masks
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
intr_mask_done_q <= 1'b0;
intr_mask_sof_q <= 1'b0;
intr_mask_err_q <= 1'b0;
end
// IO Write Cycle
else if (we_i && stb_i && (addr_i == `USB_IRQ_MASK))
begin
intr_mask_done_q <= data_i[`USB_IRQ_DONE];
intr_mask_sof_q <= data_i[`USB_IRQ_SOF];
intr_mask_err_q <= data_i[`USB_IRQ_ERR];
end
 
//-----------------------------------------------------------------
// Record Errors
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
usb_err_q <= 1'b0;
// Clear error
else if (we_i && stb_i && (addr_i == `USB_XFER_TOKEN || addr_i == `USB_CTRL))
usb_err_q <= 1'b0;
// Record bus errors
else if (utmi_rxerror_i)
usb_err_q <= 1'b1;
 
//-----------------------------------------------------------------
// Data FIFO Read
//-----------------------------------------------------------------
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
sie_rx_pop_q <= 1'b0;
// IO Read Cycle
else if (~we_i && stb_i && (addr_i == `USB_RD_DATA))
sie_rx_pop_q <= 1'b1;
else
sie_rx_pop_q <= 1'b0;
 
assign sie_start_o = sie_start_q;
assign sie_sof_en_o = sie_sof_en_q;
assign sie_rst_o = sie_rst_q;
assign sie_token_pid_o = sie_token_pid_q;
assign sie_token_data_o = sie_token_data_q;
assign sie_tx_count_o = sie_tx_count_q;
assign sie_data_idx_o = sie_data_idx_q;
assign sie_in_transfer_o = sie_in_transfer_q;
assign sie_resp_expected_o = sie_resp_expected_q;
assign sie_tx_data_o = sie_tx_data_q;
assign sie_tx_push_o = sie_tx_push_q;
assign sie_tx_flush_o = sie_tx_flush_q;
assign sie_rx_pop_o = sie_rx_pop_q;
 
//-----------------------------------------------------------------
// Peripheral Registers (Read)
//-----------------------------------------------------------------
reg [31:0] data_r;
 
always @ *
begin
data_r = 32'h00000000;
 
case (addr_i)
 
`USB_STATUS :
begin
data_r[`USB_STAT_SOF_TIME] = sie_sof_time_i;
data_r[`USB_STAT_RX_ERROR] = usb_err_q;
data_r[`USB_STAT_LINESTATE_BITS] = utmi_linestate_i;
end
 
`USB_RX_STAT :
begin
data_r[`USB_RX_STAT_START_PEND] = sie_start_o;
data_r[`USB_RX_STAT_CRC_ERR] = sie_rx_crc_err_i;
data_r[`USB_RX_STAT_RESP_TIMEOUT] = sie_rx_resp_timeout_i;
data_r[`USB_RX_STAT_IDLE] = sie_rx_idle_i;
data_r[`USB_RX_STAT_RESP_BITS] = sie_rx_resp_pid_i;
data_r[`USB_RX_STAT_COUNT_BITS] = sie_rx_count_i;
end
 
`USB_RD_DATA :
data_r = {24'h000000, sie_rx_data_i};
 
`USB_IRQ :
begin
data_r[`USB_IRQ_DONE] = intr_done_q;
data_r[`USB_IRQ_SOF] = intr_sof_q;
data_r[`USB_IRQ_ERR] = intr_err_q;
end
 
`USB_IRQ_MASK :
begin
data_r[`USB_IRQ_DONE] = intr_mask_done_q;
data_r[`USB_IRQ_SOF] = intr_mask_sof_q;
data_r[`USB_IRQ_ERR] = intr_mask_err_q;
end
 
default :
data_r = 32'h00000000;
endcase
end
 
assign data_o = data_r;
 
//-----------------------------------------------------------------
// Interrupts
//-----------------------------------------------------------------
reg err_cond_q;
reg intr_q;
 
always @ (posedge rst_i or posedge clk_i )
if (rst_i == 1'b1)
begin
intr_done_q <= 1'b0;
intr_sof_q <= 1'b0;
intr_err_q <= 1'b0;
err_cond_q <= 1'b0;
 
intr_q <= 1'b0;
end
else
begin
if (sie_rx_done_i || sie_tx_done_i)
intr_done_q <= 1'b1;
else if (we_i && stb_i && (addr_i == `USB_IRQ) && data_i[`USB_IRQ_DONE])
intr_done_q <= 1'b0;
 
if (sie_sof_irq_i)
intr_sof_q <= 1'b1;
else if (we_i && stb_i && (addr_i == `USB_IRQ) && data_i[`USB_IRQ_SOF])
intr_sof_q <= 1'b0;
 
if ((sie_rx_crc_err_i || sie_rx_resp_timeout_i) && (!err_cond_q))
intr_err_q <= 1'b1;
else if (we_i && stb_i && (addr_i == `USB_IRQ) && data_i[`USB_IRQ_ERR])
intr_err_q <= 1'b0;
 
err_cond_q <= (sie_rx_crc_err_i | sie_rx_resp_timeout_i);
 
intr_q <= (intr_done_q & intr_mask_done_q) |
(intr_err_q & intr_mask_err_q) |
(intr_sof_q & intr_mask_sof_q);
end
 
assign intr_o = intr_q;
 
endmodule
/docs/registers.md
0,0 → 1,74
##### Register Map
 
| Offset | Name | Description |
| ------ | --------------- | --------------------------------------------------- |
| 0x00 | USB_CTRL | [Write] Control of USB reset, SOF and Tx FIFO flush |
| 0x00 | USB_STATUS | [Read] line state, Rx error status and frame time |
| 0x04 | USB_IRQ_ACK | [Write] Acknowledge IRQ by setting relevant bit |
| 0x04 | USB_IRQ_STS | [Read] Interrupt status |
| 0x08 | USB_IRQ_MASK | [Read/Write] Interrupt mask |
| 0x0c | USB_XFER_DATA | [Write] Tx payload transfer length |
| 0x10 | USB_XFER_TOKEN | [Write] Transfer control info (direction, type) |
| 0x14 | USB_RX_STAT | [Read] Transfer status (Rx length, error, idle) |
| 0x18 | USB_WR_DATA | [Write] Tx FIFO address for write data |
| 0x18 | USB_RD_DATA | [Read] Tx FIFO address for read data |
 
 
##### Register: USB_CTRL
 
| Bits | Name | Description |
| ---- | ------------------- | ------------------------------------------------ |
| 2 | USB_TX_FLUSH | Flush Tx FIFO |
| 1 | USB_ENABLE_SOF | Enable SOF (start of frame) packet generation |
| 0 | USB_RESET_ACTIVE | 1 = assert USB reset state, 0 = normal |
 
##### Register: USB_STATUS
 
| Bits | Name | Description |
| ----- | ----------------------- | ------------------------------------------- |
| 31:16 | USB_STAT_SOF_TIME | Current frame time (0 - 47999) |
| 2 | USB_STAT_RX_ERROR | Rx error detected (UTMI). Clear on new xfer.|
| 1:0 | USB_STAT_LINESTATE_BITS | Line state (1 = D-, 1 = D+) |
 
##### Register: USB_IRQ_ACK / USB_IRQ_STS / USB_IRQ_MASK
 
| Bits | Name | Description |
| ---- | -------------- | ----------------------------------------------------- |
| 2 | USB_IRQ_ERR | Interrupt on error conditions. |
| 1 | USB_IRQ_DONE | Interrupt on transfer completion |
| 0 | USB_IRQ_SOF | Interrupt on start of frame |
 
##### Register: USB_XFER_DATA
 
| Bits | Name | Description |
| ----- | ----------------------- | ------------------------------------------- |
| 15:0 | USB_XFER_DATA_TX_LEN | Tx transfer data length |
 
##### Register: USB_XFER_TOKEN
 
| Bits | Name | Description |
| ----- | ------------------ | ------------------------------------------------ |
| 31 | USB_XFER_START | Transfer start request |
| 30 | USB_XFER_IN | IN transfer (1) or OUT transfer (0) |
| 29 | USB_XFER_ACK | Send ACK in response to IN data |
| 28 | USB_XFER_PID_DATAX | DATA1 (1) or DATA0 (0) |
| 23:16 | USB_XFER_PID_BITS | Token PID (SETUP=0x2d, OUT=0xE1 or IN=0x69) |
| 15:9 | USB_XFER_DEV_ADDR | Device address |
| 8:5 | USB_XFER_EP_ADDR | Endpoint address |
 
##### Register: USB_RX_STAT
 
| Bits | Name | Description |
| ----- | ------------------------ | ------------------------------------------ |
| 31 | USB_RX_STAT_START_PEND | Transfer start pending |
| 30 | USB_RX_STAT_CRC_ERR | CRC error detected |
| 29 | USB_RX_STAT_RESP_TIMEOUT | Response timeout detected (no response) |
| 28 | USB_RX_STAT_IDLE | SIE idle |
| 23:16 | USB_RX_STAT_RESP_BITS | Received response PID |
| 15:0 | USB_RX_STAT_COUNT_BITS | Received data count |
 
##### Register: USB_WR_DATA / USB_RD_DATA
 
| Bits | Name | Description |
| ----- | ---- | -------------------------------------------------------------- |
| 7:0 | DATA | Data byte |

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.