OpenFPGA/openfpga_flow/benchmarks/iwls2005/usb_funct/rtl/usbf_pa.v

387 lines
10 KiB
Verilog

/////////////////////////////////////////////////////////////////////
//// ////
//// 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