module usbf_top(// WISHBONE Interface
		clk_i, rst_i, wb_addr_i, wb_data_i, wb_data_o,
		wb_ack_o, wb_we_i, wb_stb_i, wb_cyc_i, inta_o, intb_o,
		dma_req_o, dma_ack_i, susp_o, resume_req_i,

		// UTMI Interface
		phy_clk_pad_i, phy_rst_pad_o,
		DataOut_pad_o, TxValid_pad_o, TxReady_pad_i,

		RxValid_pad_i, RxActive_pad_i, RxError_pad_i,
		DataIn_pad_i, XcvSelect_pad_o, TermSel_pad_o,
		SuspendM_pad_o, LineState_pad_i,

		OpMode_pad_o, usb_vbus_pad_i,
		VControl_Load_pad_o, VControl_pad_o, VStatus_pad_i,

		// Buffer Memory Interface
		sram_adr_o, sram_data_i, sram_data_o, sram_re_o, sram_we_o

		);

parameter	SSRAM_HADR = `USBF_SSRAM_HADR;
input		clk_i;
input		rst_i;
input	[`USBF_UFC_HADR:0]	wb_addr_i;
input	[31:0]	wb_data_i;
output	[31:0]	wb_data_o;
output		wb_ack_o;
input		wb_we_i;
input		wb_stb_i;
input		wb_cyc_i;
output		inta_o;
output		intb_o;
output	[15:0]	dma_req_o;
input	[15:0]	dma_ack_i;
output		susp_o;
input		resume_req_i;

input		phy_clk_pad_i;
output		phy_rst_pad_o;

output	[7:0]	DataOut_pad_o;
output		TxValid_pad_o;
input		TxReady_pad_i;

input	[7:0]	DataIn_pad_i;
input		RxValid_pad_i;
input		RxActive_pad_i;
input		RxError_pad_i;

output		XcvSelect_pad_o;
output		TermSel_pad_o;
output		SuspendM_pad_o;
input	[1:0]	LineState_pad_i;
output	[1:0]	OpMode_pad_o;
input		usb_vbus_pad_i;
output		VControl_Load_pad_o;
output	[3:0]	VControl_pad_o;
input	[7:0]	VStatus_pad_i;

output	[SSRAM_HADR:0]	sram_adr_o;
input	[31:0]	sram_data_i;
output	[31:0]	sram_data_o;
output		sram_re_o;
output		sram_we_o;

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

// UTMI Interface
wire	[7:0]	rx_data;
wire		rx_valid, rx_active, rx_err;
wire	[7:0]	tx_data;
wire		tx_valid;
wire		tx_ready;
wire		tx_first;
wire		tx_valid_last;

// Misc UTMI USB status
wire		mode_hs;	// High Speed Mode
wire		usb_reset;	// USB Reset
wire		usb_suspend;	// USB Sleep
wire		usb_attached;	// Attached to USB
wire		resume_req;	// Resume Request

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

// Wishbone Memory interface
wire	[`USBF_UFC_HADR:0]	ma_adr;
wire	[31:0]	ma2wb_d;
wire	[31:0]	wb2ma_d;
wire		ma_we;
wire		ma_req;
wire		ma_ack;

// WISHBONE Register File interface
wire		rf_re;
wire		rf_we;
wire	[31:0]	wb2rf_d;
wire	[31:0]	rf2wb_d;

// Internal Register File Interface
wire	[6:0]	funct_adr;	// This functions address (set by controller)
wire	[31:0]	idin;		// Data Input
wire	[3:0]	ep_sel;		// Endpoint Number Input
wire		match;		// Endpoint Matched
wire		dma_in_buf_sz1;
wire		dma_out_buf_avail;
wire		buf0_rl;	// Reload Buf 0 with original values
wire		buf0_set;	// Write to buf 0
wire		buf1_set;	// Write to buf 1
wire		uc_bsel_set;	// Write to the uc_bsel field
wire		uc_dpd_set;	// Write to the uc_dpd field
wire		int_buf1_set;	// Set buf1 full/empty interrupt
wire		int_buf0_set;	// Set buf0 full/empty interrupt
wire		int_upid_set;	// Set unsupported PID interrupt
wire		int_crc16_set;	// Set CRC16 error interrupt
wire		int_to_set;	// Set time out interrupt
wire		int_seqerr_set;	// Set PID sequence error interrupt
wire		out_to_small;	// OUT packet was to small for DMA operation
wire	[31:0]	csr;		// Internal CSR Output
wire	[31:0]	buf0;		// Internal Buf 0 Output
wire	[31:0]	buf1;		// Internal Buf 1 Output
wire	[31:0]	frm_nat;	// Frame Number and Time Register
wire		nse_err;	// No Such Endpoint Error
wire		pid_cs_err;	// PID CS error
wire		crc5_err;	// CRC5 Error
wire		rf_resume_req;	// Resume Request From main CSR

reg		susp_o;
reg	[1:0]	LineState_r;	// Added to make a full synchronizer
reg	[7:0]	VStatus_r;	// Added to make a full synchronizer

///////////////////////////////////////////////////////////////////
//
// Misc Logic
//
assign rst = rst_i;
assign phy_rst_pad_o = rst_i;
assign resume_req = resume_req_i;

always @(posedge clk_i)
	susp_o <= usb_suspend;

always @(posedge phy_clk_pad_i)		// First Stage Synchronizer
	LineState_r <= LineState_pad_i;

always @(posedge phy_clk_pad_i)		// First Stage Synchronizer
	VStatus_r <= VStatus_pad_i;

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

reg		resume_req_r;
reg		suspend_clr_wr;
wire		suspend_clr;

always @(posedge clk_i)
	suspend_clr_wr <= suspend_clr;

`ifdef USBF_ASYNC_RESET
always @(posedge clk_i or negedge rst)
`else
always @(posedge clk_i)
`endif
	if(!rst)		resume_req_r <= 1'b0;
	else
	if(suspend_clr_wr)	resume_req_r <= 1'b0;
	else
	if(resume_req)		resume_req_r <= 1'b1;


// UTMI Interface
usbf_utmi_if	u0(
		.phy_clk(	phy_clk_pad_i	),
		.rst(		rst		),
		.DataOut(	DataOut_pad_o	),
		.TxValid(	TxValid_pad_o	),
		.TxReady(	TxReady_pad_i	),
		.RxValid(	RxValid_pad_i	),
		.RxActive(	RxActive_pad_i	),
		.RxError(	RxError_pad_i	),
		.DataIn(	DataIn_pad_i	),
		.XcvSelect(	XcvSelect_pad_o	),
		.TermSel(	TermSel_pad_o	),
		.SuspendM(	SuspendM_pad_o	),
		.LineState(	LineState_pad_i	),
		.OpMode(	OpMode_pad_o	),
		.usb_vbus(	usb_vbus_pad_i	),
		.rx_data(	rx_data		),
		.rx_valid(	rx_valid	),
		.rx_active(	rx_active	),
		.rx_err(	rx_err		),
		.tx_data(	tx_data		),
		.tx_valid(	tx_valid	),
		.tx_valid_last(	tx_valid_last	),
		.tx_ready(	tx_ready	),
		.tx_first(	tx_first	),
		.mode_hs(	mode_hs		),
		.usb_reset(	usb_reset	),
		.usb_suspend(	usb_suspend	),
		.usb_attached(	usb_attached	),
		.resume_req(	resume_req_r	),
		.suspend_clr(	suspend_clr	)
		);

// Protocol Layer
usbf_pl #(SSRAM_HADR)
	u1(	.clk(			phy_clk_pad_i		),
		.rst(			rst			),
		.rx_data(		rx_data			),
		.rx_valid(		rx_valid		),
		.rx_active(		rx_active		),
		.rx_err(		rx_err			),
		.tx_data(		tx_data			),
		.tx_valid(		tx_valid		),
		.tx_valid_last(		tx_valid_last		),
		.tx_ready(		tx_ready		),
		.tx_first(		tx_first		),
		.tx_valid_out(		TxValid_pad_o		),
		.mode_hs(		mode_hs			),
		.usb_reset(		usb_reset		),
		.usb_suspend(		usb_suspend		),
		.usb_attached(		usb_attached		),
		.madr(			madr			),
		.mdout(			mdout			),
		.mdin(			mdin			),
		.mwe(			mwe			),
		.mreq(			mreq			),
		.mack(			mack			),
		.fa(			funct_adr		),
		.dma_in_buf_sz1(	dma_in_buf_sz1		),
		.dma_out_buf_avail(	dma_out_buf_avail	),
		.idin(			idin			),
		.ep_sel(		ep_sel			),
		.match(			match			),
		.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			),
		.frm_nat(		frm_nat			),
		.pid_cs_err(		pid_cs_err		),
		.nse_err(		nse_err			),
		.crc5_err(		crc5_err		)
		);

// Memory Arbiter
usbf_mem_arb	#(SSRAM_HADR)
	u2(	.phy_clk(	phy_clk_pad_i	),
		.wclk(		clk_i		),
		.rst(		rst		),

		.sram_adr(	sram_adr_o	),
		.sram_din(	sram_data_i	),
		.sram_dout(	sram_data_o	),
		.sram_re(	sram_re_o	),
		.sram_we(	sram_we_o	),

		.madr(		madr		),
		.mdout(		mdin		),
		.mdin(		mdout		),
		.mwe(		mwe		),
		.mreq(		mreq		),
		.mack(		mack		),

		.wadr(		ma_adr[SSRAM_HADR + 2:2]	),
		.wdout(		ma2wb_d		),
		.wdin(		wb2ma_d		),
		.wwe(		ma_we		),
		.wreq(		ma_req		),
		.wack(		ma_ack		)
		);

// Register File 
usbf_rf u4(	.clk(			phy_clk_pad_i		),
		.wclk(			clk_i			),
		.rst(			rst			),

		.adr(			ma_adr[8:2]		),
		.re(			rf_re			),
		.we(			rf_we			),
		.din(			wb2rf_d			),
		.dout(			rf2wb_d			),

		.inta(			inta_o			),
		.intb(			intb_o			),
		.dma_req(		dma_req_o		),
		.dma_ack(		dma_ack_i		),
		.idin(			idin			),
		.ep_sel(		ep_sel			),
		.match(			match			),
		.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			),
		.funct_adr(		funct_adr		),
		.dma_in_buf_sz1(	dma_in_buf_sz1		),
		.dma_out_buf_avail(	dma_out_buf_avail	),
		.frm_nat(		frm_nat			),
		.utmi_vend_stat(	VStatus_r		),
		.utmi_vend_ctrl(	VControl_pad_o		),
		.utmi_vend_wr(		VControl_Load_pad_o	),
		.line_stat(		LineState_r		),
		.usb_attached(		usb_attached		),
		.mode_hs(		mode_hs			),
		.suspend(		usb_suspend		),
		.attached(		usb_attached		),
		.usb_reset(		usb_reset		),
		.pid_cs_err(		pid_cs_err		),
		.nse_err(		nse_err			),
		.crc5_err(		crc5_err		),
		.rx_err(		rx_err			),
		.rf_resume_req(		rf_resume_req		)
		);


// WISHBONE Interface
usbf_wb	u5(	.phy_clk(	phy_clk_pad_i	),
		.wb_clk(	clk_i		),
		.rst(		rst		),
		.wb_addr_i(	wb_addr_i	),
		.wb_data_i(	wb_data_i	),
		.wb_data_o(	wb_data_o	),
		.wb_ack_o(	wb_ack_o	),
		.wb_we_i(	wb_we_i		),
		.wb_stb_i(	wb_stb_i	),
		.wb_cyc_i(	wb_cyc_i	),

		.ma_adr(	ma_adr		),
		.ma_dout(	wb2ma_d		),
		.ma_din(	ma2wb_d		),
		.ma_we(		ma_we		),
		.ma_req(	ma_req		),
		.ma_ack(	ma_ack		),

		.rf_re(		rf_re		),
		.rf_we(		rf_we		),
		.rf_dout(	wb2rf_d		),
		.rf_din(	rf2wb_d		)
		);


///////////////////////////////////////////////////////////////////
//
// Initialization
// This section does not add any functionality. It is only provided
// to make sure that the core is configured properly and to provide
// configuration information for simulations.
//

// synopsys translate_off
integer 	ep_cnt, ep_cnt2;
reg	[15:0]	ep_check;
initial
   begin
	$display("\n");
	ep_cnt = 1;
	ep_cnt2 = 0;
	ep_check = 0;

`ifdef	USBF_HAVE_EP1	
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP2	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP3	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP4	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP5	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP6	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP7	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP8	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP9	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP10	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP11	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP12	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP13	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP14	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif
ep_cnt2 = ep_cnt2 + 1;
`ifdef	USBF_HAVE_EP15	
	if(!ep_check[ep_cnt2-1])
		$display("ERROR: USBF_TOP: Endpoint %0d not defined but endpoint %0d defined", ep_cnt2, ep_cnt2+1);
	ep_cnt = ep_cnt + 1;
	ep_check[ep_cnt2] = 1;
`endif

	$display("");
	$display("INFO: USB Function core instantiated (%m)");
	$display("      Supported Endpoints: %0d (0 through %0d)",ep_cnt, ep_cnt-1);
	$display("      WISHBONE Address bus size: A%0d:0", `USBF_UFC_HADR );
	$display("      SSRAM Address bus size: A%0d:0", SSRAM_HADR );
	$display("      Buffer Memory Size: %0d bytes", (1<<SSRAM_HADR+1) * 4 );
	$display("");

   end

// synopsys translate_on

endmodule