387 lines
10 KiB
Verilog
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
|
|
|