module usbf_pl(	clk, rst,

		// UTMI Interface
		rx_data, rx_valid, rx_active, rx_err,
		tx_data, tx_valid, tx_valid_last, tx_ready,
		tx_first, tx_valid_out,
		mode_hs, usb_reset, usb_suspend, usb_attached,

		// memory interface
		madr, mdout, mdin, mwe, mreq, mack,

		// Register File Interface
		fa, idin,
		ep_sel, match,
		dma_in_buf_sz1, dma_out_buf_avail,
		buf0_rl, buf0_set, buf1_set,
		uc_bsel_set, uc_dpd_set,

		int_buf1_set, int_buf0_set, int_upid_set,
		int_crc16_set, int_to_set, int_seqerr_set,
		out_to_small, csr, buf0, buf1,

		// Misc
		frm_nat,
		pid_cs_err, nse_err,
		crc5_err
		);

parameter	SSRAM_HADR = 14;

// UTMI Interface
input		clk, rst;
input	[7:0]	rx_data;
input		rx_valid, rx_active, rx_err;
output	[7:0]	tx_data;
output		tx_valid;
output		tx_valid_last;
input		tx_ready;
output		tx_first;
input		tx_valid_out;
input		mode_hs;	// High Speed Mode
input		usb_reset;	// USB Reset
input		usb_suspend;	// USB Suspend
input		usb_attached;	// Attached to USB

// Memory Arbiter Interface
output	[SSRAM_HADR:0]	madr;		// word address
output	[31:0]	mdout;
input	[31:0]	mdin;
output		mwe;
output		mreq;
input		mack;

// Register File interface
input	[6:0]	fa;		// Function Address (as set by the controller)
output	[31:0]	idin;		// Data Input
output	[3:0]	ep_sel;		// Endpoint Number Input
input		match;		// Endpoint Matched
input		dma_in_buf_sz1;
input		dma_out_buf_avail;
output		nse_err;	// no such endpoint error

output		buf0_rl;	// Reload Buf 0 with original values
output		buf0_set;	// Write to buf 0
output		buf1_set;	// Write to buf 1
output		uc_bsel_set;	// Write to the uc_bsel field
output		uc_dpd_set;	// Write to the uc_dpd field
output		int_buf1_set;	// Set buf1 full/empty interrupt
output		int_buf0_set;	// Set buf0 full/empty interrupt
output		int_upid_set;	// Set unsupported PID interrupt
output		int_crc16_set;	// Set CRC16 error interrupt
output		int_to_set;	// Set time out interrupt
output		int_seqerr_set;	// Set PID sequence error interrupt
output		out_to_small;	// OUT packet was to small for DMA operation

input	[31:0]	csr;		// Internal CSR Output
input	[31:0]	buf0;		// Internal Buf 0 Output
input	[31:0]	buf1;		// Internal Buf 1 Output

// Misc
output		pid_cs_err;	// pid checksum error
output		crc5_err;	// crc5 error
output	[31:0]	frm_nat;

///////////////////////////////////////////////////////////////////
//
// Local Wires and Registers
//

// Packet Disassembler Interface
wire		clk, rst;
wire	[7:0]	rx_data;
wire		pid_OUT, pid_IN, pid_SOF, pid_SETUP;
wire		pid_DATA0, pid_DATA1, pid_DATA2, pid_MDATA;
wire		pid_ACK, pid_NACK, pid_STALL, pid_NYET;
wire		pid_PRE, pid_ERR, pid_SPLIT, pid_PING;
wire	[6:0]	token_fadr;
wire		token_valid;
wire		crc5_err;
wire	[10:0]	frame_no;
wire	[7:0]	rx_data_st;
wire		rx_data_valid;
wire		rx_data_done;
wire		crc16_err;
wire		rx_seq_err;

// Packet Assembler Interface
wire		send_token;
wire	[1:0]	token_pid_sel;
wire		send_data;
wire	[1:0]	data_pid_sel;
wire	[7:0]	tx_data_st;
wire		rd_next;

// IDMA Interface
wire		rx_dma_en;	// Allows the data to be stored
wire		tx_dma_en;	// Allows for data to be retrieved
wire		abort;		// Abort Transfer (time_out, crc_err or rx_error)
wire		idma_done;	// DMA is done
wire	[SSRAM_HADR + 2:0]	adr;		// Byte Address
wire	[13:0]	size;		// Size in bytes
wire	[10:0]	sizu_c;		// Up and Down counting size registers, used
				// to update
wire	[13:0]	buf_size;	// Actual buffer size
wire		dma_en;		// external dma enabled

// Memory Arbiter Interface
wire	[SSRAM_HADR:0]	madr;	// word address
wire	[31:0]	mdout;
wire	[31:0]	mdin;
wire		mwe;
wire		mreq;
wire		mack;

// Local signals
wire		pid_bad, pid_bad1, pid_bad2;

reg		hms_clk;	// 0.5 Micro Second Clock
reg	[4:0]	hms_cnt;
reg	[10:0]	frame_no_r;	// Current Frame Number register
wire		frame_no_we;
reg		frame_no_same;	// Indicates current and prev. frame numbers
				// are equal
reg	[3:0]	mfm_cnt;	// Micro Frame Counter
reg	[11:0]	sof_time;	// Time since last sof
reg		clr_sof_time;
wire		fsel;		// This Function is selected
wire		match_o;

reg		frame_no_we_r;

///////////////////////////////////////////////////////////////////
//
// Misc Logic
//

// PIDs we should never receive
assign pid_bad1 = pid_ACK | pid_NACK | pid_STALL | pid_NYET | pid_PRE |
			pid_ERR | pid_SPLIT;

// PIDs we should never get in full speed mode (high speed mode only)
assign pid_bad2 = !mode_hs & pid_PING;

// All bad pids
assign pid_bad = pid_bad1 | pid_bad2;

assign match_o = !pid_bad & fsel & match & token_valid & !crc5_err;

// Frame Number (from SOF token)
assign frame_no_we = token_valid & !crc5_err & pid_SOF;

always @(posedge clk)
	frame_no_we_r <= frame_no_we;

`ifdef USBF_ASYNC_RESET
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
	if(!rst)		frame_no_r <= 11'h0;
	else
	if(frame_no_we_r)	frame_no_r <= frame_no;

// Micro Frame Counter
always @(posedge clk)
	frame_no_same <= frame_no_we & (frame_no_r == frame_no);

`ifdef USBF_ASYNC_RESET
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
	if(!rst)		mfm_cnt <= 4'h0;
	else
	if(frame_no_we_r && !frame_no_same)
				mfm_cnt <= 4'h0;
	else
	if(frame_no_same)	mfm_cnt <= mfm_cnt + 4'h1;

//SOF delay counter
always @(posedge clk)
	clr_sof_time <= frame_no_we;

always @(posedge clk)
	if(clr_sof_time)	sof_time <= 12'h0;
	else
	if(hms_clk)		sof_time <= sof_time + 12'h1;

assign frm_nat = {mfm_cnt, 1'b0, frame_no_r, 4'h0, sof_time};

// 0.5 Micro Seconds Clock Generator
`ifdef USBF_ASYNC_RESET
always @(posedge clk or negedge rst)
`else
always @(posedge clk)
`endif
	if(!rst)				hms_cnt <= 5'h0;
	else
	if(hms_clk || frame_no_we_r)		hms_cnt <= 5'h0;
	else					hms_cnt <= hms_cnt + 5'h1;

always @(posedge clk)
	hms_clk <= (hms_cnt == `USBF_HMS_DEL);

///////////////////////////////////////////////////////////////////

// This function is addressed
assign fsel = (token_fadr == fa);

///////////////////////////////////////////////////////////////////
//
// Module Instantiations
//

//Packet Decoder
usbf_pd	u0(	.clk(			clk			),
		.rst(			rst			),
		.rx_data(		rx_data			),
		.rx_valid(		rx_valid		),
		.rx_active(		rx_active		),
		.rx_err(		rx_err			),
		.pid_OUT(		pid_OUT			),
		.pid_IN(		pid_IN			),
		.pid_SOF(		pid_SOF			),
		.pid_SETUP(		pid_SETUP		),
		.pid_DATA0(		pid_DATA0		),
		.pid_DATA1(		pid_DATA1		),
		.pid_DATA2(		pid_DATA2		),
		.pid_MDATA(		pid_MDATA		),
		.pid_ACK(		pid_ACK			),
		.pid_NACK(		pid_NACK		),
		.pid_STALL(		pid_STALL		),
		.pid_NYET(		pid_NYET		),
		.pid_PRE(		pid_PRE			),
		.pid_ERR(		pid_ERR			),
		.pid_SPLIT(		pid_SPLIT		),
		.pid_PING(		pid_PING		),
		.pid_cks_err(		pid_cs_err		),
		.token_fadr(		token_fadr		),
		.token_endp(		ep_sel			),
		.token_valid(		token_valid		),
		.crc5_err(		crc5_err		),
		.frame_no(		frame_no		),
		.rx_data_st(		rx_data_st		),
		.rx_data_valid(		rx_data_valid		),
		.rx_data_done(		rx_data_done		),
		.crc16_err(		crc16_err		),
		.seq_err(		rx_seq_err		)
		);

// Packet Assembler
usbf_pa	u1(	.clk(			clk			),
		.rst(			rst			),
		.tx_data(		tx_data			),
		.tx_valid(		tx_valid		),
		.tx_valid_last(		tx_valid_last		),
		.tx_ready(		tx_ready		),
		.tx_first(		tx_first		),
		.send_token(		send_token		),
		.token_pid_sel(		token_pid_sel		),
		.send_data(		send_data		),
		.data_pid_sel(		data_pid_sel		),
		.send_zero_length(	send_zero_length	),
		.tx_data_st(		tx_data_st		),
		.rd_next(		rd_next			)
		);

// Internal DMA / Memory Arbiter Interface
usbf_idma #(SSRAM_HADR)
	u2(	.clk(			clk			),
		.rst(			rst			),
		.rx_data_st(		rx_data_st		),
		.rx_data_valid(		rx_data_valid		),
		.rx_data_done(		rx_data_done		),
		.send_data(		send_data		),
		.tx_data_st(		tx_data_st		),
		.rd_next(		rd_next			),
		.rx_dma_en(		rx_dma_en		),
		.tx_dma_en(		tx_dma_en		),
		.abort(			abort			),
		.idma_done(		idma_done		),
		.adr(			adr			),
		.size(			size			),
		.buf_size(		buf_size		),
		.dma_en(		dma_en			),
		.send_zero_length(	send_zero_length	),
		.madr(			madr			),
		.sizu_c(		sizu_c			),
		.mdout(			mdout			),
		.mdin(			mdin			),
		.mwe(			mwe			),
		.mreq(			mreq			),
		.mack(			mack			)
		);

// Protocol Engine
usbf_pe #(SSRAM_HADR)
	u3(	.clk(			clk			),
		.rst(			rst			),
		.tx_valid(		tx_valid_out		),
		.rx_active(		rx_active		),
		.pid_OUT(		pid_OUT			),
		.pid_IN(		pid_IN			),
		.pid_SOF(		pid_SOF			),
		.pid_SETUP(		pid_SETUP		),
		.pid_DATA0(		pid_DATA0		),
		.pid_DATA1(		pid_DATA1		),
		.pid_DATA2(		pid_DATA2		),
		.pid_MDATA(		pid_MDATA		),
		.pid_ACK(		pid_ACK			),
		.pid_NACK(		pid_NACK		),
		.pid_STALL(		pid_STALL		),
		.pid_NYET(		pid_NYET		),
		.pid_PRE(		pid_PRE			),
		.pid_ERR(		pid_ERR			),
		.pid_SPLIT(		pid_SPLIT		),
		.pid_PING(		pid_PING		),
		.mode_hs(		mode_hs			),
		.token_valid(		token_valid		),
		.crc5_err(		crc5_err		),
		.rx_data_valid(		rx_data_valid		),
		.rx_data_done(		rx_data_done		),
		.crc16_err(		crc16_err		),
		.send_token(		send_token		),
		.token_pid_sel(		token_pid_sel		),
		.data_pid_sel(		data_pid_sel		),
		.send_zero_length(	send_zero_length	),
		.rx_dma_en(		rx_dma_en		),
		.tx_dma_en(		tx_dma_en		),
		.abort(			abort			),
		.idma_done(		idma_done		),
		.adr(			adr			),
		.size(			size			),
		.buf_size(		buf_size		),
		.sizu_c(		sizu_c			),
		.dma_en(		dma_en			),
		.fsel(			fsel			),
		.idin(			idin			),
		.ep_sel(		ep_sel			),
		.match(			match_o			),
		.dma_in_buf_sz1(	dma_in_buf_sz1		),
		.dma_out_buf_avail(	dma_out_buf_avail	),
		.nse_err(		nse_err			),
		.buf0_rl(		buf0_rl			),
		.buf0_set(		buf0_set		),
		.buf1_set(		buf1_set		),
		.uc_bsel_set(		uc_bsel_set		),
		.uc_dpd_set(		uc_dpd_set		),
		.int_buf1_set(		int_buf1_set		),
		.int_buf0_set(		int_buf0_set		),
		.int_upid_set(		int_upid_set		),
		.int_crc16_set(		int_crc16_set		),
		.int_to_set(		int_to_set		),
		.int_seqerr_set(	int_seqerr_set		),
		.out_to_small(		out_to_small		),
		.csr(			csr			),
		.buf0(			buf0			),
		.buf1(			buf1			)
		);

endmodule