//-----------------------------------------------------------------------------
//
// (c) Copyright 2010-2011 Xilinx, Inc. All rights reserved.
//
// This file contains confidential and proprietary information
// of Xilinx, Inc. and is protected under U.S. and
// international copyright and other intellectual property
// laws.
//
// DISCLAIMER
// This disclaimer is not a license and does not grant any
// rights to the materials distributed herewith. Except as
// otherwise provided in a valid license issued to you by
// Xilinx, and to the maximum extent permitted by applicable
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
// (2) Xilinx shall not be liable (whether in contract or tort,
// including negligence, or under any other theory of
// liability) for any loss or damage of any kind or nature
// related to, arising under or in connection with these
// materials, including for any direct, or any indirect,
// special, incidental, or consequential loss or damage
// (including loss of data, profits, goodwill, or any type of
// loss or damage suffered as a result of any action brought
// by a third party) even if such damage or loss was
// reasonably foreseeable or Xilinx had been advised of the
// possibility of the same.
//
// CRITICAL APPLICATIONS
// Xilinx products are not designed or intended to be fail-
// safe, or for use in any application requiring fail-safe
// performance, such as life-support or safety devices or
// systems, Class III medical devices, nuclear facilities,
// applications related to the deployment of airbags, or any
// other applications that could lead to death, personal
// injury, or severe property or environmental damage
// (individually and collectively, "Critical
// Applications"). Customer assumes the sole risk and
// liability of any use of Xilinx products in Critical
// Applications, subject only to applicable laws and
// regulations governing limitations on product liability.
//
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
// PART OF THIS FILE AT ALL TIMES.
//
//-----------------------------------------------------------------------------
// Project    : Series-7 Integrated Block for PCI Express
// File       : PIO_EP.v
// Version    : 3.3
//
// Description: Endpoint Programmed I/O module.
//              Consists of Receive and Transmit modules and a Memory Aperture
//
//------------------------------------------------------------------------------

`timescale 1ps/1ps

(* DowngradeIPIdentifiedWarnings = "yes" *)
module PIO_EP #(
	parameter C_DATA_WIDTH = 64,            // RX/TX interface data width

	// Do not override parameters below this line
	parameter KEEP_WIDTH = C_DATA_WIDTH / 8,              // TSTRB width
	parameter TCQ        = 1
) (

	input                         clk,
	input                         rst_n,

	// AXIS TX
	input                         s_axis_tx_tready,
	output  [C_DATA_WIDTH-1:0]    s_axis_tx_tdata,
	output  [KEEP_WIDTH-1:0]      s_axis_tx_tkeep,
	output                        s_axis_tx_tlast,
	output                        s_axis_tx_tvalid,
	output                        tx_src_dsc,

	//AXIS RX
	input   [C_DATA_WIDTH-1:0]    m_axis_rx_tdata,
	input   [KEEP_WIDTH-1:0]      m_axis_rx_tkeep,
	input                         m_axis_rx_tlast,
	input                         m_axis_rx_tvalid,
	output                        m_axis_rx_tready,
	input   [21:0]                m_axis_rx_tuser,

	output                        req_compl,
	output                        compl_done,

	input   [15:0]                cfg_completer_id,

	output                        Led1_o,
	output                        Led2_o,
	output                        Led3_o,
	output                        Led4_o,

	output  RstForFpga_o,
	
	output  TmsgCsSpiM_o,
	output  TmsgClkSpiM_o,
	output  TmsgMosiSpiM_o,
	output  TmsgMosi1_io,
	output  TmsgMosi2_o,
	output  TmsgMosi3_o,
	output  SpiMode_o,

	output  LmkACsSpiM_o,
	output  LmkBCsSpiM_o,
	output  LmkAClkSpiM_o,
	output  LmkAMosiSpiM_o,

	output	Pe1CsSpiM_o,
	output	Pe1MosiSpiM_o,
	output	Pe2CsSpiM_o,
	output	Pe2MosiSpiM_o,
	output	PeClkSpiM_o,

	input   RfLd_i,

	output	Mod_o,
	output	LrGpio_o,
	output	HrGpio_o
);

		// Local wires

		wire  [10:0]      rd_addr;
		wire  [3:0]       rd_be;
		wire  [31:0]      rd_data;

		wire  [10:0]      wr_addr;
		wire  [7:0]       wr_be;
		(* DONT_TOUCH = "yes" *) wire  [31:0]      wr_data;
		wire              wr_en;
		wire              wr_busy;

		wire              req_compl_int;
		wire              req_compl_wd;
		wire              compl_done_int;

		wire  [2:0]       req_tc;
		wire              req_td;
		wire              req_ep;
		wire  [1:0]       req_attr;
		wire  [9:0]       req_len;
		wire  [15:0]      req_rid;
		wire  [7:0]       req_tag;
		wire  [7:0]       req_be;
		wire  [12:0]      req_addr;
		
		wire LmkAClkSpiM;
		wire LmkAMosiSpiM;
		
		wire lmkAFifoEmpty;
		
		wire LmkBClkSpiM;
		wire LmkBMosiSpiM;
		

		wire valDataToFifoLmkA;
		wire valDataToFifoLmkB;
		wire valDataToTxFifo;
		wire valDataToFifoAttPe1;
		wire valDataToFifoAttPe2;
		wire valDataToCfgReg;

		wire pe1ClkSpiM;
		wire pe2ClkSpiM;

		wire spiPe1Busy;
		wire spiPe2Busy;

		wire clk10;
		wire clk50;

		wire widthSpiTmsg;
		wire spiMode;
		wire tmsgClk;
		wire spiClk;

		reg [31:0] cfgReg;

		assign Led1_o = ~rd_data[3];  
		assign Led2_o = ~rd_data[2];
		assign Led3_o = ~rd_data[1];
		assign Led4_o = ~rd_data[0];
		
		assign LmkAClkSpiM_o = (lmkAFifoEmpty)? LmkBClkSpiM : LmkAClkSpiM;
		assign LmkAMosiSpiM_o = (lmkAFifoEmpty)? LmkBMosiSpiM:LmkAMosiSpiM;

		assign PeClkSpiM_o = (~Pe1CsSpiM_o)? pe1ClkSpiM : pe2ClkSpiM;

		assign RstForFpga_o = cfgReg[0];
		assign widthSpiTmsg = cfgReg[1];
		assign Mod_o 		= cfgReg[2];
		assign LrGpio_o 	= cfgReg[3];
		assign HrGpio_o		= cfgReg[4];
		assign spiMode 		= cfgReg[5];
		assign tmsgClk 		= cfgReg[6];
		
		assign SpiMode_o 	= spiMode;
		
		//Latch configuration data from PCIe
		always @(posedge clk) begin
			if(~rst_n) begin
				cfgReg <= 0;
			end 
			else if (valDataToCfgReg) begin
					cfgReg <= wr_data;
			end
		end
		

		// SPI clock generation
		BUFGMUX #(
			
		) BUFGMUX_inst (
			.I0(clk10),
			.I1(clk50),
			.S(tmsgClk),
			.O(spiClk)
		);

		//
		// ENDPOINT MEMORY : 8KB memory aperture implemented in FPGA BlockRAM(*)
		//

		PIO_EP_MEM_ACCESS  #(
			 .TCQ( TCQ )
			 ) EP_MEM_inst (
			
			.clk(clk),               // I
			.rst_n(rst_n),           // I
			
			// Read Port
			
			.rd_addr(rd_addr),     // I [10:0]
			.rd_be(rd_be),         // I [3:0]
			.rd_data(rd_data),     // O [31:0]
			
			// Write Port
			
			.wr_addr(wr_addr),     // I [10:0]
			.wr_be(wr_be),         // I [7:0]
			.wr_data(wr_data),     // I [31:0]
			.wr_en(wr_en),         // I
			.wr_busy(wr_busy),      // O
			.RfLd_i (RfLd_i)
			);

		//
		// Local-Link Receive Controller
		//

	PIO_RX_ENGINE #(
		.C_DATA_WIDTH( C_DATA_WIDTH ),
		.KEEP_WIDTH( KEEP_WIDTH ),
		.TCQ( TCQ )

	) EP_RX_inst (

		.clk(clk),                              // I
		.rst_n(rst_n),                          // I

		// AXIS RX
		.m_axis_rx_tdata( m_axis_rx_tdata ),    // I
		.m_axis_rx_tkeep( m_axis_rx_tkeep ),    // I
		.m_axis_rx_tlast( m_axis_rx_tlast ),    // I
		.m_axis_rx_tvalid( m_axis_rx_tvalid ),  // I
		.m_axis_rx_tready( m_axis_rx_tready ),  // O
		.m_axis_rx_tuser ( m_axis_rx_tuser ),   // I

		// Handshake with Tx engine
		.req_compl(req_compl_int),              // O
		.req_compl_wd(req_compl_wd),            // O
		.compl_done(compl_done_int),            // I

		.req_tc(req_tc),                        // O [2:0]
		.req_td(req_td),                        // O
		.req_ep(req_ep),                        // O
		.req_attr(req_attr),                    // O [1:0]
		.req_len(req_len),                      // O [9:0]
		.req_rid(req_rid),                      // O [15:0]
		.req_tag(req_tag),                      // O [7:0]
		.req_be(req_be),                        // O [7:0]
		.req_addr(req_addr),                    // O [12:0]
																						
		// Memory Write Port                    
		.wr_addr(wr_addr),                      // O [10:0]
		.wr_be(wr_be),
		.wr_data_msb(wr_data),                  // O [31:0]
		.wr_en(wr_en),                          // O
		.wr_busy(wr_busy),                       // I
		
		.ValDataToTxFifo_o  	(valDataToTxFifo),
		.ValDataToFifoLmkB_o	(valDataToFifoLmkB),
		.ValDataToFifoLmkA_o	(valDataToFifoLmkA),
		.ValDataToFifoAttPe1_o	(valDataToFifoAttPe1), 
		.ValDataToFifoAttPe2_o	(valDataToFifoAttPe2),
		.ValDataToCfgReg_o   	(valDataToCfgReg)                                   
	);

		//
		// Local-Link Transmit Controller
		//

	PIO_TX_ENGINE #(
		.C_DATA_WIDTH( C_DATA_WIDTH ),
		.KEEP_WIDTH( KEEP_WIDTH ),
		.TCQ( TCQ )
	)EP_TX_inst(

		.clk(clk),                                  // I
		.rst_n(rst_n),                              // I

		// AXIS Tx
		.s_axis_tx_tready( s_axis_tx_tready ),      // I
		.s_axis_tx_tdata( s_axis_tx_tdata ),        // O
		.s_axis_tx_tkeep( s_axis_tx_tkeep ),        // O
		.s_axis_tx_tlast( s_axis_tx_tlast ),        // O
		.s_axis_tx_tvalid( s_axis_tx_tvalid ),      // O
		.tx_src_dsc( tx_src_dsc ),                  // O

		// Handshake with Rx engine
		.req_compl(req_compl_int),                // I
		.req_compl_wd(req_compl_wd),              // I
		.compl_done(compl_done_int),                // 0

		.req_tc(req_tc),                          // I [2:0]
		.req_td(req_td),                          // I
		.req_ep(req_ep),                          // I
		.req_attr(req_attr),                      // I [1:0]
		.req_len(req_len),                        // I [9:0]
		.req_rid(req_rid),                        // I [15:0]
		.req_tag(req_tag),                        // I [7:0]
		.req_be(req_be),                          // I [7:0]
		.req_addr(req_addr),                      // I [12:0]

		// Read Port

		.rd_addr(rd_addr),                        // O [10:0]
		.rd_be(rd_be),                            // O [3:0]
		.rd_data(rd_data),                        // I [31:0]

		.completer_id(cfg_completer_id)           // I [15:0]

		);

		PllSpi PllSpi
		(
			// Clock out ports
			.clk_out1(clk10),     // output clk_out1
			.clk_out2(clk50),	 // output clk_out2
			// Clock in ports
			.clk_in1(clk)           // input clk_in1
		);      

		LmkWrapperA #(
		.IN_WIDTH     (24),
		.WR_NUM       (1),
		.OUT_WIDTH    (24),
		.DATA_WIDTH   (24)
		) LmkAWrapper(
		.WrClk_i      (clk),
		.RdClk_i      (clk10),
		.Rst_i        (~rst_n),
		.Data_i       (wr_data[23:0]),
		.Val_i        (valDataToFifoLmkA),
		.LmkAFifoEmpty_o(lmkAFifoEmpty),
		.Ss_o         (LmkACsSpiM_o),
		.Sck_o        (LmkAClkSpiM),
		.Mosi_o       (LmkAMosiSpiM)
		);
		
		
		LmkWrapperB #(
		.IN_WIDTH     (24),
		.WR_NUM       (1),
		.OUT_WIDTH    (24),
		.DATA_WIDTH   (24)
		) LmkBWrapper(
		.WrClk_i      (clk),
		.RdClk_i      (clk10),
		.Rst_i        (~rst_n),
		.Data_i       (wr_data[23:0]),
		.LmkAFifoEmpty_i(lmkAFifoEmpty),
		.Val_i        (valDataToFifoLmkB),
		.Ss_o         (LmkBCsSpiM_o),
		.Sck_o        (LmkBClkSpiM),
		.Mosi_o       (LmkBMosiSpiM)
		);
		
		SbTmsgWrapper #(
		.IN_WIDTH     		(32),
		.WR_NUM       		(1),
		.OUT_WIDTH    		(32),
		.DATA_MAX_WIDTH   (32)
		) SbTmsgWrapper(
		.WrClk_i      		(clk),
		.RdClk_i      		(spiClk),
		.Rst_i        		(~rst_n),
		.Data_i       		(wr_data[31:0]),
		.Val_i        		(valDataToTxFifo),
		.WidthCurrent_i 	((widthSpiTmsg)? 7'd32 : 7'd24),
		.SpiMode_i			(spiMode),
		.Ss_o         		(TmsgCsSpiM_o),
		.Sck_o        		(TmsgClkSpiM_o),
		.Mosi_o       		(TmsgMosiSpiM_o),
		.Mosi1_io			(TmsgMosi1_io),
		.Mosi2_o			(TmsgMosi2_o),
		.Mosi3_o			(TmsgMosi3_o)
		);

		AttPeWrapper #(
		.IN_WIDTH     (8),
		.WR_NUM       (1),
		.OUT_WIDTH    (8),
		.DATA_WIDTH   (8)
		) AttPe1Wrapper(
		.WrClk_i      (clk),
		.RdClk_i      (clk10),
		.Rst_i        (~rst_n),
		.SpiBusy_i	  (spiPe2Busy),
		.Data_i       (wr_data[7:0]),
		.Val_i        (valDataToFifoAttPe1),
		.SpiBusy_o	  (spiPe1Busy),
		.Ss_o         (Pe1CsSpiM_o),
		.Sck_o        (pe1ClkSpiM),
		.Mosi_o       (Pe1MosiSpiM_o)
		);

		AttPeWrapper #(
		.IN_WIDTH     (8),
		.WR_NUM       (1),
		.OUT_WIDTH    (8),
		.DATA_WIDTH   (8)
		) AttPe2Wrapper(
		.WrClk_i      (clk),
		.RdClk_i      (clk10),
		.Rst_i        (~rst_n),
		.SpiBusy_i	  (spiPe1Busy),
		.Data_i       (wr_data[7:0]),
		.Val_i        (valDataToFifoAttPe2),
		.SpiBusy_o	  (spiPe2Busy),
		.Ss_o         (Pe2CsSpiM_o),
		.Sck_o        (pe2ClkSpiM),
		.Mosi_o       (Pe2MosiSpiM_o)
		);

	assign req_compl  = req_compl_int;
	assign compl_done = compl_done_int;

endmodule // PIO_EP

