123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- //-----------------------------------------------------------------
- // 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
- //-----------------------------------------------------------------
- //`define USB_RANDOM_CORRUPT 6
- //-----------------------------------------------------------------
- // Generated File
- //-----------------------------------------------------------------
- module usbf_sie_tx
- (
- // Inputs
- input clk_i
- ,input rst_i
- ,input enable_i
- ,input chirp_i
- ,input utmi_txready_i
- ,input tx_valid_i
- ,input [ 7:0] tx_pid_i
- ,input data_valid_i
- ,input data_strb_i
- ,input [ 7:0] data_i
- ,input data_last_i
- // Outputs
- ,output [ 7:0] utmi_data_o
- ,output utmi_txvalid_o
- ,output tx_accept_o
- ,output data_accept_o
- );
- //-----------------------------------------------------------------
- // Defines:
- //-----------------------------------------------------------------
- `include "usbf_defs.v"
- localparam STATE_W = 3;
- localparam STATE_TX_IDLE = 3'd0;
- localparam STATE_TX_PID = 3'd1;
- localparam STATE_TX_DATA = 3'd2;
- localparam STATE_TX_CRC1 = 3'd3;
- localparam STATE_TX_CRC2 = 3'd4;
- localparam STATE_TX_DONE = 3'd5;
- localparam STATE_TX_CHIRP = 3'd6;
- reg [STATE_W-1:0] state_q;
- reg [STATE_W-1:0] next_state_r;
- //-----------------------------------------------------------------
- // Request Type
- //-----------------------------------------------------------------
- reg data_pid_q;
- reg data_zlp_q;
- always @ (posedge clk_i or posedge rst_i)
- if (rst_i)
- begin
- data_pid_q <= 1'b0;
- data_zlp_q <= 1'b0;
- end
- else if (!enable_i)
- begin
- data_pid_q <= 1'b0;
- data_zlp_q <= 1'b0;
- end
- else if (tx_valid_i && tx_accept_o)
- begin
- case (tx_pid_i)
- `PID_MDATA, `PID_DATA2, `PID_DATA0, `PID_DATA1:
- begin
- data_pid_q <= 1'b1;
- data_zlp_q <= data_valid_i && (data_strb_i == 1'b0) && data_last_i;
- end
- default :
- begin
- data_pid_q <= 1'b0;
- data_zlp_q <= 1'b0;
- end
- endcase
- end
- else if (next_state_r == STATE_TX_CRC1)
- begin
- data_pid_q <= 1'b0;
- data_zlp_q <= 1'b0;
- end
- assign tx_accept_o = (state_q == STATE_TX_IDLE);
- //-----------------------------------------------------------------
- // Next state
- //-----------------------------------------------------------------
- always @ *
- begin
- next_state_r = state_q;
- //-----------------------------------------
- // State Machine
- //-----------------------------------------
- case (state_q)
- //-----------------------------------------
- // IDLE
- //-----------------------------------------
- STATE_TX_IDLE :
- begin
- if (chirp_i)
- next_state_r = STATE_TX_CHIRP;
- else if (tx_valid_i)
- next_state_r = STATE_TX_PID;
- end
- //-----------------------------------------
- // TX_PID
- //-----------------------------------------
- STATE_TX_PID :
- begin
- // Data accepted
- if (utmi_txready_i)
- begin
- if (data_zlp_q)
- next_state_r = STATE_TX_CRC1;
- else if (data_pid_q)
- next_state_r = STATE_TX_DATA;
- else
- next_state_r = STATE_TX_DONE;
- end
- end
- //-----------------------------------------
- // TX_DATA
- //-----------------------------------------
- STATE_TX_DATA :
- begin
- // Data accepted
- if (utmi_txready_i)
- begin
- // Generate CRC16 at end of packet
- if (data_last_i)
- next_state_r = STATE_TX_CRC1;
- end
- 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)
- next_state_r = STATE_TX_DONE;
- end
- //-----------------------------------------
- // TX_DONE
- //-----------------------------------------
- STATE_TX_DONE :
- begin
- // Data sent?
- if (!utmi_txvalid_o || utmi_txready_i)
- next_state_r = STATE_TX_IDLE;
- end
- //-----------------------------------------
- // TX_CHIRP
- //-----------------------------------------
- STATE_TX_CHIRP :
- begin
- if (!chirp_i)
- next_state_r = STATE_TX_IDLE;
- end
- default :
- ;
- endcase
- // USB reset but not chirping...
- if (!enable_i && !chirp_i)
- next_state_r = STATE_TX_IDLE;
- end
- // Update state
- always @ (posedge clk_i or posedge rst_i)
- if (rst_i)
- state_q <= STATE_TX_IDLE;
- else
- state_q <= next_state_r;
- //-----------------------------------------------------------------
- // Data Input
- //-----------------------------------------------------------------
- reg input_valid_r;
- reg [7:0] input_byte_r;
- reg input_last_r;
- always @ *
- begin
- input_valid_r = data_strb_i & data_pid_q;
- input_byte_r = data_i;
- input_last_r = data_last_i;
- end
- reg data_accept_r;
- always @ *
- begin
- if (state_q == STATE_TX_DATA)
- data_accept_r = utmi_txready_i;
- else if (state_q == STATE_TX_PID && data_zlp_q)
- data_accept_r = utmi_txready_i;
- else
- data_accept_r = 1'b0;
- end
- assign data_accept_o = data_accept_r;
- //-----------------------------------------------------------------
- // CRC16: Generate CRC16 on outgoing data
- //-----------------------------------------------------------------
- reg [15:0] crc_sum_q;
- wire [15:0] crc_out_w;
- reg crc_err_q;
- `ifdef USB_RANDOM_CORRUPT
- reg [`USB_RANDOM_CORRUPT-1:0] corrupt_ctr_q;
- always @(posedge clk_i)
- corrupt_ctr_q <= corrupt_ctr_q + 1'b1;
- wire corrupt_tx = !corrupt_ctr_q;
- `else
- wire corrupt_tx = 1'b0;
- `endif
- usbf_crc16
- u_crc16
- (
- .crc_in_i(crc_sum_q),
- .din_i(utmi_data_o),
- .crc_out_o(crc_out_w)
- );
- always @ (posedge clk_i or posedge rst_i)
- if (rst_i)
- crc_sum_q <= 16'hFFFF;
- else if (state_q == STATE_TX_IDLE)
- crc_sum_q <= 16'hFFFF ^ corrupt_tx;
- else if (state_q == STATE_TX_DATA && utmi_txvalid_o && utmi_txready_i)
- crc_sum_q <= crc_out_w;
- //-----------------------------------------------------------------
- // Output
- //-----------------------------------------------------------------
- reg valid_q;
- reg [7:0] data_q;
- always @ (posedge clk_i or posedge rst_i)
- if (rst_i)
- begin
- valid_q <= 1'b0;
- data_q <= 8'b0;
- end
- else if (!enable_i)
- begin
- valid_q <= 1'b0;
- data_q <= 8'b0;
- end
- else if (tx_valid_i && tx_accept_o)
- begin
- valid_q <= 1'b1;
- data_q <= tx_pid_i;
- end
- else if (utmi_txready_i)
- begin
- valid_q <= 1'b0;
- data_q <= 8'b0;
- end
- reg utmi_txvalid_r;
- reg [7:0] utmi_data_r;
- always @ *
- begin
- if (state_q == STATE_TX_CHIRP)
- begin
- utmi_txvalid_r = 1'b1;
- utmi_data_r = 8'b0;
- end
- else if (state_q == STATE_TX_CRC1)
- begin
- utmi_txvalid_r = 1'b1;
- utmi_data_r = crc_sum_q[7:0] ^ 8'hFF;
- end
- else if (state_q == STATE_TX_CRC2)
- begin
- utmi_txvalid_r = 1'b1;
- utmi_data_r = crc_sum_q[15:8] ^ 8'hFF;
- end
- else if (state_q == STATE_TX_DATA)
- begin
- utmi_txvalid_r = data_valid_i;
- utmi_data_r = data_i;
- end
- else
- begin
- utmi_txvalid_r = valid_q;
- utmi_data_r = data_q;
- end
- end
- assign utmi_txvalid_o = utmi_txvalid_r;
- assign utmi_data_o = utmi_data_r;
- endmodule
|