| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 | //-----------------------------------------------------------------//                       USB Serial Port//                            V0.1//                     Ultra-Embedded.com//                       Copyright 2020////                 Email: admin@ultra-embedded.com////                         License: LGPL//-----------------------------------------------------------------//// This source file may be used and distributed without         // restriction provided that this copyright statement is not    // removed from the file and that any derivative work contains  // the original copyright notice and the associated disclaimer. //// This source file is free software; you can redistribute it   // and/or modify it under the terms of the GNU Lesser General   // Public License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any   // later version.//// This source is distributed in the hope that it will be       // useful, but WITHOUT ANY WARRANTY; without even the implied   // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      // PURPOSE.  See the GNU Lesser General Public License for more // details.//// You should have received a copy of the GNU Lesser General    // Public License along with this source; if not, write to the // Free Software Foundation, Inc., 59 Temple Place, Suite 330, // Boston, MA  02111-1307  USA//-----------------------------------------------------------------//-----------------------------------------------------------------//                          Generated File//-----------------------------------------------------------------module ulpi_wrapper(    // Inputs     input           ulpi_clk60_i    ,input           ulpi_rst_i    ,input  [  7:0]  ulpi_data_out_i    ,input           ulpi_dir_i    ,input           ulpi_nxt_i    ,input  [  7:0]  utmi_data_out_i    ,input           utmi_txvalid_i    ,input  [  1:0]  utmi_op_mode_i    ,input  [  1:0]  utmi_xcvrselect_i    ,input           utmi_termselect_i    ,input           utmi_dppulldown_i    ,input           utmi_dmpulldown_i    // Outputs    ,output [  7:0]  ulpi_data_in_o    ,output          ulpi_stp_o    ,output [  7:0]  utmi_data_in_o    ,output          utmi_txready_o    ,output          utmi_rxvalid_o    ,output          utmi_rxactive_o    ,output          utmi_rxerror_o    ,output [  1:0]  utmi_linestate_o);//-----------------------------------------------------------------// Module: UTMI+ to ULPI Wrapper//// Description://   - Converts from UTMI interface to reduced pin count ULPI.//   - No support for low power mode.//   - I/O synchronous to 60MHz ULPI clock input (from PHY)//   - Tested against SMSC/Microchip USB3300 in device mode.//-----------------------------------------------------------------//-----------------------------------------------------------------// States//-----------------------------------------------------------------localparam STATE_W          = 2;localparam STATE_IDLE       = 2'd0;localparam STATE_CMD        = 2'd1;localparam STATE_DATA       = 2'd2;localparam STATE_REG        = 2'd3;reg [STATE_W-1:0]   state_q;//-----------------------------------------------------------------// Local Params//-----------------------------------------------------------------localparam REG_FUNC_CTRL = 8'h84;localparam REG_OTG_CTRL  = 8'h8a;localparam REG_TRANSMIT  = 8'h40;localparam REG_WRITE     = 8'h80;localparam REG_READ      = 8'hC0;//-----------------------------------------------------------------// UTMI Mode Select//-----------------------------------------------------------------reg         mode_update_q;reg [1:0]   xcvrselect_q;reg         termselect_q;reg [1:0]   opmode_q;reg         phy_reset_q;reg         mode_write_q;// Detect register write completionwire mode_complete_w = (state_q == STATE_REG &&                        mode_write_q         &&                         ulpi_nxt_i           &&                         !ulpi_dir_i);           // Not interrupted by a Rxalways @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)if (ulpi_rst_i)begin    mode_update_q   <= 1'b0;    xcvrselect_q    <= 2'b0;    termselect_q    <= 1'b0;    opmode_q        <= 2'b11;    phy_reset_q     <= 1'b1;endelsebegin    xcvrselect_q    <= utmi_xcvrselect_i;    termselect_q    <= utmi_termselect_i;    opmode_q        <= utmi_op_mode_i;    if (mode_update_q && mode_complete_w)    begin        mode_update_q <= 1'b0;        phy_reset_q   <= 1'b0;    end    else if (opmode_q     != utmi_op_mode_i     ||             termselect_q != utmi_termselect_i ||             xcvrselect_q != utmi_xcvrselect_i)        mode_update_q <= 1'b1;end//-----------------------------------------------------------------// UTMI OTG Control//-----------------------------------------------------------------reg otg_update_q;reg dppulldown_q;reg dmpulldown_q;reg otg_write_q;// Detect register write completionwire otg_complete_w  = (state_q == STATE_REG &&                        otg_write_q         &&                         ulpi_nxt_i           &&                         !ulpi_dir_i);           // Not interrupted by a Rxalways @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)if (ulpi_rst_i)begin    otg_update_q    <= 1'b0;    dppulldown_q    <= 1'b1;    dmpulldown_q    <= 1'b1;endelsebegin    dppulldown_q    <= utmi_dppulldown_i;    dmpulldown_q    <= utmi_dmpulldown_i;    if (otg_update_q && otg_complete_w)        otg_update_q <= 1'b0;    else if (dppulldown_q != utmi_dppulldown_i ||             dmpulldown_q != utmi_dmpulldown_i)        otg_update_q <= 1'b1;end//-----------------------------------------------------------------// Bus turnaround detect//-----------------------------------------------------------------reg ulpi_dir_q;always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)if (ulpi_rst_i)    ulpi_dir_q <= 1'b0;else    ulpi_dir_q <= ulpi_dir_i;wire turnaround_w = ulpi_dir_q ^ ulpi_dir_i;//-----------------------------------------------------------------// Rx - Tx delay//-----------------------------------------------------------------localparam TX_DELAY_W       = 3;localparam TX_START_DELAY   = 3'd7;reg [TX_DELAY_W-1:0] tx_delay_q;always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)if (ulpi_rst_i)    tx_delay_q <= {TX_DELAY_W{1'b0}};else if (utmi_rxactive_o)    tx_delay_q <= TX_START_DELAY;else if (tx_delay_q != {TX_DELAY_W{1'b0}})    tx_delay_q <= tx_delay_q - 1;wire tx_delay_complete_w = (tx_delay_q == {TX_DELAY_W{1'b0}});//-----------------------------------------------------------------// Tx Buffer - decouple UTMI Tx from PHY I/O//-----------------------------------------------------------------reg [7:0] tx_buffer_q[0:1];reg       tx_valid_q[0:1];reg       tx_wr_idx_q;reg       tx_rd_idx_q;wire      utmi_tx_ready_w;wire      utmi_tx_accept_w;always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)if (ulpi_rst_i)begin    tx_buffer_q[0] <= 8'b0;    tx_buffer_q[1] <= 8'b0;    tx_valid_q[0]  <= 1'b0;    tx_valid_q[1]  <= 1'b0;    tx_wr_idx_q    <= 1'b0;    tx_rd_idx_q    <= 1'b0;end    elsebegin    // Push    if (utmi_txvalid_i && utmi_txready_o)    begin        tx_buffer_q[tx_wr_idx_q] <= utmi_data_out_i;        tx_valid_q[tx_wr_idx_q]  <= 1'b1;        tx_wr_idx_q <= tx_wr_idx_q + 1'b1;    end    // Pop    if (utmi_tx_ready_w && utmi_tx_accept_w)    begin        tx_valid_q[tx_rd_idx_q]  <= 1'b0;        tx_rd_idx_q <= tx_rd_idx_q + 1'b1;    endend// Tx buffer space (only accept after Rx->Tx turnaround delay)assign utmi_txready_o  = ~tx_valid_q[tx_wr_idx_q] & tx_delay_complete_w;assign utmi_tx_ready_w = tx_valid_q[tx_rd_idx_q];wire [7:0] utmi_tx_data_w = tx_buffer_q[tx_rd_idx_q];//-----------------------------------------------------------------// Implementation//-----------------------------------------------------------------// Xilinx placement pragmas://synthesis attribute IOB of ulpi_data_q is "TRUE"//synthesis attribute IOB of ulpi_stp_q is "TRUE"reg [7:0]           ulpi_data_q;reg                 ulpi_stp_q;reg [7:0]           data_q;reg                 utmi_rxvalid_q;reg                 utmi_rxerror_q;reg                 utmi_rxactive_q;reg [1:0]           utmi_linestate_q;reg [7:0]           utmi_data_q;always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)if (ulpi_rst_i)begin    state_q             <= STATE_IDLE;    ulpi_data_q         <= 8'b0;    data_q              <= 8'b0;    ulpi_stp_q          <= 1'b1;    utmi_rxvalid_q      <= 1'b0;    utmi_rxerror_q      <= 1'b0;    utmi_rxactive_q     <= 1'b0;    utmi_linestate_q    <= 2'b0;    utmi_data_q         <= 8'b0;    mode_write_q        <= 1'b0;    otg_write_q         <= 1'b0;endelsebegin    ulpi_stp_q          <= 1'b0;    utmi_rxvalid_q      <= 1'b0;    // Turnaround: Input + NXT - set RX_ACTIVE    if (turnaround_w && ulpi_dir_i && ulpi_nxt_i)    begin        utmi_rxactive_q <= 1'b1;        // Register write - abort        if (state_q == STATE_REG)        begin            state_q       <= STATE_IDLE;            ulpi_data_q   <= 8'b0;  // IDLE        end    end    // Turnaround: Input -> Output - reset RX_ACTIVE    else if (turnaround_w && !ulpi_dir_i)    begin        utmi_rxactive_q <= 1'b0;        // Register write - abort        if (state_q == STATE_REG)        begin            state_q       <= STATE_IDLE;            ulpi_data_q   <= 8'b0;  // IDLE        end    end    // Non-turnaround cycle    else if (!turnaround_w)    begin        //-----------------------------------------------------------------        // Input: RX_CMD (status)        //-----------------------------------------------------------------        if (ulpi_dir_i && !ulpi_nxt_i)        begin            // Phy status            utmi_linestate_q <= ulpi_data_out_i[1:0];            case (ulpi_data_out_i[5:4])            2'b00:            begin                utmi_rxactive_q <= 1'b0;                utmi_rxerror_q  <= 1'b0;            end            2'b01:             begin                utmi_rxactive_q <= 1'b1;                utmi_rxerror_q  <= 1'b0;            end            2'b11:            begin                utmi_rxactive_q <= 1'b1;                utmi_rxerror_q  <= 1'b1;            end            default:                ; // HOST_DISCONNECTED            endcase        end        //-----------------------------------------------------------------        // Input: RX_DATA        //-----------------------------------------------------------------        else if (ulpi_dir_i && ulpi_nxt_i)        begin            utmi_rxvalid_q  <= 1'b1;            utmi_data_q     <= ulpi_data_out_i;        end        //-----------------------------------------------------------------        // Output        //-----------------------------------------------------------------        else if (!ulpi_dir_i)        begin                    // IDLE: Pending mode update            if ((state_q == STATE_IDLE) && mode_update_q)            begin                data_q        <= {1'b0, 1'b1, phy_reset_q, opmode_q, termselect_q, xcvrselect_q};                ulpi_data_q   <= REG_FUNC_CTRL;                otg_write_q   <= 1'b0;                mode_write_q  <= 1'b1;                state_q       <= STATE_CMD;            end            // IDLE: Pending OTG control update            else if ((state_q == STATE_IDLE) && otg_update_q)            begin                data_q        <= {5'b0, dmpulldown_q, dppulldown_q, 1'b0};                ulpi_data_q   <= REG_OTG_CTRL;                otg_write_q   <= 1'b1;                mode_write_q  <= 1'b0;                state_q       <= STATE_CMD;            end            // IDLE: Pending transmit            else if ((state_q == STATE_IDLE) && utmi_tx_ready_w)            begin                ulpi_data_q <= REG_TRANSMIT | {4'b0, utmi_tx_data_w[3:0]};                state_q     <= STATE_DATA;            end            // Command            else if ((state_q == STATE_CMD) && ulpi_nxt_i)            begin                // Write Register                state_q     <= STATE_REG;                ulpi_data_q <= data_q;            end            // Data (register write)            else if (state_q == STATE_REG && ulpi_nxt_i)            begin                state_q       <= STATE_IDLE;                ulpi_data_q   <= 8'b0;  // IDLE                ulpi_stp_q    <= 1'b1;                otg_write_q   <= 1'b0;                mode_write_q  <= 1'b0;            end            // Data            else if (state_q == STATE_DATA && ulpi_nxt_i)            begin                // End of packet                if (!utmi_tx_ready_w)                begin                    state_q       <= STATE_IDLE;                    ulpi_data_q   <= 8'b0;  // IDLE                    ulpi_stp_q    <= 1'b1;                end                else                begin                    state_q        <= STATE_DATA;                    ulpi_data_q    <= utmi_tx_data_w;                end            end        end    endend// Accept from bufferassign utmi_tx_accept_w = ((state_q == STATE_IDLE) && !(mode_update_q || otg_update_q || turnaround_w) && !ulpi_dir_i) ||                          (state_q == STATE_DATA && ulpi_nxt_i && !ulpi_dir_i);//-----------------------------------------------------------------// Assignments//-----------------------------------------------------------------// ULPI Interfaceassign ulpi_data_in_o       = ulpi_data_q;assign ulpi_stp_o           = ulpi_stp_q;// UTMI Interfaceassign utmi_linestate_o     = utmi_linestate_q;assign utmi_data_in_o       = utmi_data_q;assign utmi_rxerror_o       = utmi_rxerror_q;assign utmi_rxactive_o      = utmi_rxactive_q;assign utmi_rxvalid_o       = utmi_rxvalid_q;endmodule
 |