///////////////////////////////////////////////////////////////////// //// //// //// Packet Assembler //// //// Assembles Token and Data USB packets //// //// //// //// Author: Rudolf Usselmann //// //// rudi@asics.ws //// //// //// //// //// //// Downloaded from: http://www.opencores.org/cores/usb/ //// //// //// ///////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2000-2003 Rudolf Usselmann //// //// www.asics.ws //// //// rudi@asics.ws //// //// //// //// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// //// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// //// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// //// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// //// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// //// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// //// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// //// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// //// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// //// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// //// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// //// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// //// POSSIBILITY OF SUCH DAMAGE. //// //// //// ///////////////////////////////////////////////////////////////////// // CVS Log // // $Id: usbf_pa.v,v 1.6 2003/10/17 02:36:57 rudi Exp $ // // $Date: 2003/10/17 02:36:57 $ // $Revision: 1.6 $ // $Author: rudi $ // $Locker: $ // $State: Exp $ // // Change History: // $Log: usbf_pa.v,v $ // Revision 1.6 2003/10/17 02:36:57 rudi // - Disabling bit stuffing and NRZI encoding during speed negotiation // - Now the core can send zero size packets // - Fixed register addresses for some of the higher endpoints // (conversion between decimal/hex was wrong) // - The core now does properly evaluate the function address to // determine if the packet was intended for it. // - Various other minor bugs and typos // // Revision 1.5 2001/11/04 12:22:45 rudi // // - Fixed previous fix (brocke something else ...) // - Majore Synthesis cleanup // // Revision 1.4 2001/09/24 01:15:28 rudi // // Changed reset to be active high async. // // Revision 1.3 2001/09/19 14:38:57 rudi // // Fixed TxValid handling bug. // // Revision 1.2 2001/08/10 08:48:33 rudi // // - Changed IO names to be more clear. // - Uniquifyed define names to be core specific. // // Revision 1.1 2001/08/03 05:30:09 rudi // // // 1) Reorganized directory structure // // Revision 1.0 2001/03/07 09:17:12 rudi // // // Changed all revisions to revision 1.0. This is because OpenCores CVS // interface could not handle the original '0.1' revision .... // // Revision 0.1.0.1 2001/02/28 08:10:54 rudi // Initial Release // // `include "usbf_defines.v" module usbf_pa( clk, rst, // UTMI TX I/F tx_data, tx_valid, tx_valid_last, tx_ready, tx_first, // Protocol Engine Interface send_token, token_pid_sel, send_data, data_pid_sel, send_zero_length, // IDMA Interface tx_data_st, rd_next ); input clk, rst; // UTMI TX Interface output [7:0] tx_data; output tx_valid; output tx_valid_last; input tx_ready; output tx_first; // Protocol Engine Interface input send_token; input [1:0] token_pid_sel; input send_data; input [1:0] data_pid_sel; input send_zero_length; // IDMA Interface input [7:0] tx_data_st; output rd_next; /////////////////////////////////////////////////////////////////// // // Local Wires and Registers // parameter [4:0] // synopsys enum state IDLE = 5'b00001, DATA = 5'b00010, CRC1 = 5'b00100, CRC2 = 5'b01000, WAIT = 5'b10000; reg [4:0] /* synopsys enum state */ state, next_state; // synopsys state_vector state reg last; reg rd_next; reg [7:0] token_pid, data_pid; // PIDs from selectors reg [7:0] tx_data_d; reg [7:0] tx_data_data; reg dsel; reg tx_valid_d; reg send_token_r; reg [7:0] tx_spec_data; reg crc_sel1, crc_sel2; reg tx_first_r; reg send_data_r; wire crc16_clr; reg [15:0] crc16; wire [15:0] crc16_next; wire [15:0] crc16_rev; wire crc16_add; reg send_data_r2; reg tx_valid_r; reg tx_valid_r1; reg zero_length_r; reg send_zero_length_r; /////////////////////////////////////////////////////////////////// // // Misc Logic // always @(posedge clk) send_zero_length_r <= send_zero_length; `ifdef USBF_ASYNC_RESET always @(posedge clk or negedge rst) `else always @(posedge clk) `endif if(!rst) zero_length_r <= 1'b0; else if(last) zero_length_r <= 1'b0; else if(crc16_clr) zero_length_r <= send_zero_length_r; always @(posedge clk) tx_valid_r1 <= tx_valid; always @(posedge clk) tx_valid_r <= tx_valid_r1; `ifdef USBF_ASYNC_RESET always @(posedge clk or negedge rst) `else always @(posedge clk) `endif if(!rst) send_token_r <= 1'b0; else if(send_token) send_token_r <= 1'b1; else if(tx_ready) send_token_r <= 1'b0; // PID Select always @(token_pid_sel) case(token_pid_sel) // synopsys full_case parallel_case 2'd0: token_pid = { ~`USBF_T_PID_ACK, `USBF_T_PID_ACK}; 2'd1: token_pid = { ~`USBF_T_PID_NACK, `USBF_T_PID_NACK}; 2'd2: token_pid = {~`USBF_T_PID_STALL, `USBF_T_PID_STALL}; 2'd3: token_pid = { ~`USBF_T_PID_NYET, `USBF_T_PID_NYET}; endcase always @(data_pid_sel) case(data_pid_sel) // synopsys full_case parallel_case 2'd0: data_pid = { ~`USBF_T_PID_DATA0, `USBF_T_PID_DATA0}; 2'd1: data_pid = { ~`USBF_T_PID_DATA1, `USBF_T_PID_DATA1}; 2'd2: data_pid = { ~`USBF_T_PID_DATA2, `USBF_T_PID_DATA2}; 2'd3: data_pid = { ~`USBF_T_PID_MDATA, `USBF_T_PID_MDATA}; endcase // Data path Muxes always @(send_token or send_token_r or token_pid or tx_data_data) if(send_token || send_token_r) tx_data_d = token_pid; else tx_data_d = tx_data_data; always @(dsel or tx_data_st or tx_spec_data) if(dsel) tx_data_data = tx_spec_data; else tx_data_data = tx_data_st; always @(crc_sel1 or crc_sel2 or data_pid or crc16_rev) if(!crc_sel1 && !crc_sel2) tx_spec_data = data_pid; else if(crc_sel1) tx_spec_data = crc16_rev[15:8]; // CRC 1 else tx_spec_data = crc16_rev[7:0]; // CRC 2 assign tx_data = tx_data_d; // TX Valid assignment assign tx_valid_last = send_token | last; assign tx_valid = tx_valid_d; always @(posedge clk) tx_first_r <= send_token | send_data; assign tx_first = (send_token | send_data) & ! tx_first_r; // CRC Logic always @(posedge clk) send_data_r <= send_data; always @(posedge clk) send_data_r2 <= send_data_r; assign crc16_clr = send_data & !send_data_r; assign crc16_add = !zero_length_r & (send_data_r & !send_data_r2) | (rd_next & !crc_sel1); always @(posedge clk) if(crc16_clr) crc16 <= 16'hffff; else if(crc16_add) crc16 <= crc16_next; usbf_crc16 u1( .crc_in( crc16 ), .din( {tx_data_st[0], tx_data_st[1], tx_data_st[2], tx_data_st[3], tx_data_st[4], tx_data_st[5], tx_data_st[6], tx_data_st[7]} ), .crc_out( crc16_next ) ); assign crc16_rev[15] = ~crc16[8]; assign crc16_rev[14] = ~crc16[9]; assign crc16_rev[13] = ~crc16[10]; assign crc16_rev[12] = ~crc16[11]; assign crc16_rev[11] = ~crc16[12]; assign crc16_rev[10] = ~crc16[13]; assign crc16_rev[9] = ~crc16[14]; assign crc16_rev[8] = ~crc16[15]; assign crc16_rev[7] = ~crc16[0]; assign crc16_rev[6] = ~crc16[1]; assign crc16_rev[5] = ~crc16[2]; assign crc16_rev[4] = ~crc16[3]; assign crc16_rev[3] = ~crc16[4]; assign crc16_rev[2] = ~crc16[5]; assign crc16_rev[1] = ~crc16[6]; assign crc16_rev[0] = ~crc16[7]; /////////////////////////////////////////////////////////////////// // // Transmit/Encode state machine // `ifdef USBF_ASYNC_RESET always @(posedge clk or negedge rst) `else always @(posedge clk) `endif if(!rst) state <= IDLE; else state <= next_state; always @(state or send_data or tx_ready or tx_valid_r or send_zero_length_r) begin next_state = state; // Default don't change current state tx_valid_d = 1'b0; dsel = 1'b0; rd_next = 1'b0; last = 1'b0; crc_sel1 = 1'b0; crc_sel2 = 1'b0; case(state) // synopsys full_case parallel_case IDLE: begin if(send_zero_length_r && send_data) begin tx_valid_d = 1'b1; next_state = WAIT; dsel = 1'b1; end else if(send_data) // Send DATA packet begin tx_valid_d = 1'b1; next_state = DATA; dsel = 1'b1; end end DATA: begin if(tx_ready && tx_valid_r) rd_next = 1'b1; tx_valid_d = 1'b1; if(!send_data && tx_ready && tx_valid_r) begin dsel = 1'b1; crc_sel1 = 1'b1; next_state = CRC1; end end WAIT: // In case of early tx_ready ... begin crc_sel1 = 1'b1; dsel = 1'b1; tx_valid_d = 1'b1; next_state = CRC1; end CRC1: begin dsel = 1'b1; tx_valid_d = 1'b1; if(tx_ready) begin last = 1'b1; crc_sel2 = 1'b1; next_state = CRC2; end else begin tx_valid_d = 1'b1; crc_sel1 = 1'b1; end end CRC2: begin dsel = 1'b1; crc_sel2 = 1'b1; if(tx_ready) begin next_state = IDLE; end else begin last = 1'b1; end end endcase end endmodule