-------------------------------------------------------------
-- MSS copyright 2015-2016
--	Filename:  DDR3_WRAPPER.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 2
--	Date last modified: 3/5/17
-- Inheritance: 	N/A
--
-- description: VHDL driver to interface the FPGA with a DDR3 DIMM/SODIMM module.
-- Pre-synthesis configuration settings are selected by parameters in the Generic.


-- Features: autoincrement address, address rewind, start/ceiling address boundaries,
-- concurrent read/write.
-- Independent clocks on user and DDR3 sides.
-- Fixed DDR3 clocks: 330-400 MHz / 660-800 MSamples/s on Artix-7 -1. Use MIG 7 series to change as per target FPGA.
-- MIG 7 series IP automatically manages SDRAM: memory initialization, calibration, periodic refresh, etc.
-- See Xilinx ug586_7series_MIS p81,p162,etc
-- IMNPORTANT: DDR3_WRAPPER conducts only one read OR one write transaction at any given time. 
-- Any read/write multitasking must be handled by the instantiating party (by avoiding long read or write transactions)
--
-- Rev 1 12/26/16 AZ
-- Accelerated reporting of output elastic buffer DATA1_OUT_EMPTY (previously 2 CLKs later). No need to do so.
--
-- variant: clocks generated externally to minimize the number of MMCMs. 2/11/17
--
-- Rev 2 3/5/17 AZ 
-- Corrected bug related to stop reading
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity DDR3_WRAPPER is
	Generic (
	RAMB_ADDR_WIDTH: in integer := 9;
		-- block RAM address width(equivalent to selecting the block RAM size)
		-- data width is always 513
		-- For CLK at 125 MHz and MIG_UI_CLKg = 83.3 MHz, select 6(or 7???) (because of the latency in reporting 
		-- the input flow control information DATA1_IN_CTS
	DDR3_NRANKS: integer := 2;	-- number of ranks , 1GB = 1, 8GB = 2
	DDR3_NADDRBITS: integer := 16;	-- number of address bits, 1GB = 14, 8GB = 16
		-- MIG must be configured accordingly
	APP_NADDRBITS: integer := 30;		
		-- number of application address bits (address of 64-bit words), 
		-- in accordance with memory size 28(1GB),30(8GB)
	SIMULATION: std_logic := '0'
		-- 1 during simulation, 0 for release	
	);
    Port ( 
		--// CLK, RESET
		CLK: in std_logic;
			-- user-interface GLOBAL CLOCK. 
			-- Designer is responsible for instantiating an external BUFG.
		SYNC_RESET: in std_logic;
			-- CLK-synchronous reset
		CLK200: in std_logic; 
			-- 200 MHz processing clock from 25 MHz reference. not global
			-- for use by MIG for generating I/O delays
		CLK333p3: in std_logic; 
			-- 333.33 MHz from 25 Mhz reference. not global 
		PLL_LOCKED_IN: in std_logic;
			-- external PLL generating the CLK200 and CLK333p3 report lock status
			
		--// USER interface
		-- The user interface is designed for flexibility and efficiency. The user can 
		-- (a) write to/read from any random single address
		-- (b) write to/read from a burst-size address (here 8). 
		-- (c) between a start and ceiling address with address autoincrement.
		-- (d) continuously between start and ceiling addresses, with address autoincrement and address rewind when reaching the ceiling.
		-- CHANNEL1 INPUT
		DATA1_IN: in std_logic_vector(511 downto 0);
			-- Eight input data words (because burst length is BL=8)
		DATA1_IN_VALID: in std_logic;
			-- enable qualifier for DATA1_IN
		DATA1_IN_CTS: out std_logic;
			-- Clear to send: flow control signal indicating that the input elastic buffer has room for more 
			-- user data. Always check CTS before sending additional data words.
		DATA1_IN_SETADDR: in std_logic;
			-- 1 CLK pulse to set the start and ceiling addresses and the mode (i.e. start of write transaction)
			-- USAGE: Addresses must be defined at least ONE CLK prior to the first data word.
		DATA1_IN_STARTADDR: in std_logic_vector(31 downto 0);
			-- DDR3 SDRAM start address (inclusive). Expressed in 64-bit SDRAM words (not bytes).
			-- latched in when DATA1_IN_SETADDR = '1'
		DATA1_IN_CEILINGADDR: in std_logic_vector(31 downto 0);
			-- optional ceiling address (EXCLUSIVE). Expressed in 64-bit SDRAM words (not bytes).
			-- latched in when DATA1_IN_SETADDR = '1'
			-- Usage depends on the mode (single shot or continuous).
			-- In continuous mode, the actual address will be automatically rewound to the start address.
			-- In single shot mode, input data words will be discarded when the actual address exceeds this ceiling.
			-- IMPORTANT: In order to avoid truncating the last few words, start/ceiling distance should be a multiple of BL8
		DATA1_IN_MODE: in std_logic_vector(1 downto 0);
			-- 00 = fixed address. Disable address autoincrement.
			-- 01 = continous mode: auto-increment address from start address to ceiling address -1, then rewind to start address.
			-- 10 = single-shot mode: auto-increment address from start address to ceiling address -1, then discard subsequent data words.
			-- 11 = stop writing immediately
		WRITE_COMMAND_COMPLETE: out std_logic := '1';
			-- '0' immediately after the DATA1_IN_SETADDR pulse, '1' when the last memory address is written to.
			-- = acknowledgement
			-- Usage: because of the latency of data propagating through dual-port RAMs, do not use this flag to ensure
			-- the correct number of input words. Instead, count the number of input words to ensure consistency with 
			-- the specified address range DATA1_IN_SETADDR/DATA1_IN_CEILINGADDR

		-- CHANNEL1 OUTPUT
		DATA1_OUT: out std_logic_vector(511 downto 0);
			-- Eight output data words (because burst length is BL=8)
		DATA1_OUT_VALID: out std_logic;
			-- data valid qualifier. 2 CLKs after DATA1_OUT_CTS when not DATA1_OUT_EMPTY
		DATA1_OUT_CTS: in std_logic;
			-- Clear to send: flow control signal. User requests data from the output elastic buffer.
		DATA1_OUT_EMPTY: out std_logic;
			-- output elastic buffer is empty.
		DATA1_OUT_SETADDR: in std_logic;
			-- 1 CLK pulse to set the start and ceiling addresses = start of read transaction
			-- USAGE: user must wait until the end of the previous transaction
		DATA1_OUT_STARTADDR: in std_logic_vector(31 downto 0);
			-- DDR3 start address. 
		DATA1_OUT_CEILINGADDR: in std_logic_vector(31 downto 0);
			-- Ceiling address (exclusive). Expressed in SDRAM words (not bytes).
			-- Usage depends on the mode (single shot or continuous).
			-- In continuous mode, the actual address will be automatically rewound to the start address.
			-- In single shot mode, no data words will be read past the ceiling address.
		DATA1_OUT_MODE: in std_logic_vector(1 downto 0);
			-- 00 = fixed address. Disable autoincrement.
			-- 01 = continous mode: auto-increment address from start address to ceiling address-1, then rewind to start address.
			-- 10 = single-shot mode: auto-increment address from start address to ceiling address-1, then stop reading transaction.
			-- 11 = stop reading immediately
		
		--// DDR3 SDRAM DIMM/SODIMM. 1.5 V
		-- Inouts
		ddr3_dq                        : inout std_logic_vector(63 downto 0);
		ddr3_dqs_p                     : inout std_logic_vector(7 downto 0);
		ddr3_dqs_n                     : inout std_logic_vector(7 downto 0);

		-- Outputs
		ddr3_addr                      : out   std_logic_vector((DDR3_NADDRBITS-1) downto 0);
		ddr3_ba                        : out   std_logic_vector(2 downto 0);
		ddr3_ras_n                     : out   std_logic;
		ddr3_cas_n                     : out   std_logic;
		ddr3_we_n                      : out   std_logic;
		ddr3_reset_n                   : out   std_logic;
		ddr3_ck_p                      : out   std_logic_vector((DDR3_NRANKS-1) downto 0);
		ddr3_ck_n                      : out   std_logic_vector((DDR3_NRANKS-1) downto 0);
		ddr3_cke                       : out   std_logic_vector((DDR3_NRANKS-1) downto 0);
		ddr3_cs_n                      : out   std_logic_vector((DDR3_NRANKS-1) downto 0);
		ddr3_odt                       : out   std_logic_vector((DDR3_NRANKS-1) downto 0);
		ddr3_dm                        : out   std_logic_vector(7 downto 0);
		

		--// Monitoring + Test points 
		DATA1_IN_ADDR: out std_logic_vector(31 downto 0);
		DATA1_OUT_ADDR: out std_logic_vector(31 downto 0);
			-- Monitoring the address pointers at the DDR3 SDRAM interface (both synchronous with CLK)
			-- Usage: cannot be read immediately after sending a read or write command, as it takes time for 
			-- the current addresses to propagate through the clock domains.
		MEMORY_RDY_OUT: out std_logic;
			-- '1' when the DDR3 SDRAM is ready to operate (all clocks stable, memory is reset/initialized/calibrated)
			-- commands received before the memory is ready may not be acted upon properly.
		TP: out std_logic_vector(20 downto 1)
	
 );
end entity;

architecture Behavioral of DDR3_WRAPPER is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT BRAM_DP2
	 GENERIC(
		DATA_WIDTHA: integer;
		ADDR_WIDTHA: integer;
		DATA_WIDTHB: integer;
		ADDR_WIDTHB: integer
	 );
	 PORT(
		CSA : IN std_logic;
		CLKA   : in  std_logic;
		WEA    : in  std_logic;
		OEA : IN std_logic;
		ADDRA  : in  std_logic_vector(ADDR_WIDTHA-1 downto 0);
		DIA   : in  std_logic_vector(DATA_WIDTHA-1 downto 0);
		DOA  : out std_logic_vector(DATA_WIDTHA-1 downto 0);
		CSB : IN std_logic;
		CLKB   : in  std_logic;
		WEB    : in  std_logic;
		OEB : IN std_logic;
		ADDRB  : in  std_logic_vector(ADDR_WIDTHB-1 downto 0);
		DIB   : in  std_logic_vector(DATA_WIDTHB-1 downto 0);
		DOB  : out std_logic_vector(DATA_WIDTHB-1 downto 0)
		  );
	 END COMPONENT;

   component mig_7series_0
	port (
		 ddr3_dq       : inout std_logic_vector(63 downto 0);
		 ddr3_dqs_p    : inout std_logic_vector(7 downto 0);
		 ddr3_dqs_n    : inout std_logic_vector(7 downto 0);

		 ddr3_addr     : out   std_logic_vector((DDR3_NADDRBITS-1) downto 0);
		 ddr3_ba       : out   std_logic_vector(2 downto 0);
		 ddr3_ras_n    : out   std_logic;
		 ddr3_cas_n    : out   std_logic;
		 ddr3_we_n     : out   std_logic;
		 ddr3_reset_n  : out   std_logic;
		 ddr3_ck_p     : out   std_logic_vector((DDR3_NRANKS - 1) downto 0);
		 ddr3_ck_n     : out   std_logic_vector((DDR3_NRANKS - 1) downto 0);
		 ddr3_cke      : out   std_logic_vector((DDR3_NRANKS - 1) downto 0);
		 ddr3_cs_n     : out   std_logic_vector((DDR3_NRANKS - 1) downto 0);
		 ddr3_dm       : out   std_logic_vector(7 downto 0);
		 ddr3_odt      : out   std_logic_vector((DDR3_NRANKS - 1) downto 0);
		 app_addr                  : in    std_logic_vector((APP_NADDRBITS - 1) downto 0);
		 app_cmd                   : in    std_logic_vector(2 downto 0);
		 app_en                    : in    std_logic;
		 app_wdf_data              : in    std_logic_vector(511 downto 0);
		 app_wdf_end               : in    std_logic;
		 app_wdf_mask         : in    std_logic_vector(63 downto 0);
		 app_wdf_wren              : in    std_logic;
		 app_rd_data               : out   std_logic_vector(511 downto 0);
		 app_rd_data_end           : out   std_logic;
		 app_rd_data_valid         : out   std_logic;
		 app_rdy                   : out   std_logic;
		 app_wdf_rdy               : out   std_logic;
		 app_sr_req                : in    std_logic;
		 app_ref_req               : in    std_logic;
		 app_zq_req                : in    std_logic;
		 app_sr_active             : out   std_logic;
		 app_ref_ack               : out   std_logic;
		 app_zq_ack                : out   std_logic;
		 ui_clk                    : out   std_logic;
		 ui_clk_sync_rst           : out   std_logic;
		 init_calib_complete       : out   std_logic;
		 -- System Clock Ports
		 sys_clk_i                      : in    std_logic;
		 -- Reference Clock Ports
		 clk_ref_i                                : in    std_logic;
		sys_rst                     : in    std_logic
		);
    end component;
	 
	 
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- NOTATIONS: 
-- _E as one-CLK early sample
-- _D as one-CLK delayed sample
-- _D2 as two-CLKs delayed sample
-- _X as (sign-)extended precision

--// CLK & RESETS ---------
signal CLK200g: std_logic := '0';
signal CLK333p3g: std_logic := '0';
signal ASYNC_RESETn: std_logic := '0';
signal SYNC_RESET100n: std_logic := '0';
signal MIG_UI_CLKg: std_logic := '0';
signal MIG_UI_CLK_SYNC_RST: std_logic := '0';

--// DATA1_IN INPUT ELASTIC BUFFER ---------------------------------------------------
signal WRITE_TRANSACTION_PENDING: std_logic := '0';
signal WRITE_TRANSACTION_PENDING_D: std_logic := '0';
signal WRITE_TRANSACTION_PENDING_D2: std_logic := '0';
signal DATA1_IN_CEILINGADDR_D: std_logic_vector(31 downto 0) := (others => '0'); 
signal RAMB1_DIA1: std_logic_vector(514 downto 0) := (others => '0');
signal RAMB1_DOB1: std_logic_vector(514 downto 0) := (others => '0');
signal RAMB1_ADDRA: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB1_ADDRA_D: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB1_ADDRA_D2: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB1_ADDRA_D3: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal COUNTER1_MOD8: unsigned(2 downto 0) := "000";
signal RAMB1_ADDRA_IS_STABLE: std_logic := '0';
signal RAMB1_ADDRA_IS_STABLE_D: std_logic := '0';
signal RAMB1_ADDRB: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB1_ADDRB0: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB1_ADDRB_INC: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB1_WEA: std_logic := '0';
signal DATA1INBUF_EMPTY: std_logic := '0';
signal RAMB1_SIZE: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal DATA1_IN_CTS_local: std_logic := '0';
signal DATA1_ADDR_DATAn: std_logic := '0';

--// DATA1_OUT OUTPUT ELASTIC BUFFER ---------------------------------------------------
signal READ_TRANSACTION_PENDING: std_logic := '0';
signal DATA1_OUT_SETADDR_TOGGLE: std_logic := '0';
signal DATA1_OUT_SETADDR_TOGGLE_D: std_logic := '0';
signal DATA1_OUT_SETADDR_TOGGLE_D2: std_logic := '0';
signal DATA1_OUT_SETADDR_TOGGLE_D3: std_logic := '0';
signal DATA1_OUT_STARTADDR_D: unsigned(31 downto 0) := (others => '0');
signal DATA1_OUT_STARTADDR_D2: unsigned(31 downto 0) := (others => '0');
signal DATA1_OUT_CEILINGADDR_D: unsigned(31 downto 0) := (others => '0');
signal DATA1_OUT_CEILINGADDR_D2: unsigned(31 downto 0) := (others => '0');
signal DATA1_OUT_MODE_D: std_logic_vector(1 downto 0) := (others => '0');
signal DATA1_OUT_MODE_D2: std_logic_vector(1 downto 0) := (others => '0');
signal RAMB2_DIA1: std_logic_vector(511 downto 0) := (others => '0');
signal RAMB2_DOB1: std_logic_vector(511 downto 0) := (others => '0');
signal RAMB2_ADDRA: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB2_ADDRA_D: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB2_ADDRA_D2: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal RAMB2_ADDRA_D3: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal COUNTER2_MOD8: unsigned(2 downto 0) := (others => '0');
signal RAMB2_ADDRA_IS_STABLE: std_logic := '0';
signal RAMB2_ADDRA_IS_STABLE_D: std_logic := '0';
signal RAMB2_ADDRB: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '1');
signal RAMB2_SIZE: unsigned((RAMB_ADDR_WIDTH-1) downto 0) := (others => '0');
signal DATA1OUTBUF_FULL: std_logic := '0';
signal DATA1_OUT_VALID_E: std_logic := '0';
signal DATA1_OUT_EMPTY_local: std_logic := '0';


--// TRANSACTION SCHEDULER ---------------------------------------------------
signal EVENT1: std_logic := '0';
signal EVENT2: std_logic := '0';
signal EVENT2_D: std_logic := '0';
signal EVENT2_D2: std_logic := '0';
signal EVENT2_D3: std_logic := '0';
signal EVENT3: std_logic := '0';
signal EVENT3_D: std_logic := '0';
signal EVENT3_D2: std_logic := '0';
signal EVENT3_D3: std_logic := '0';
signal EVENT4: std_logic := '0';
signal EVENT5: std_logic := '0';
signal EVENT6: std_logic := '0';
signal EVENT7: std_logic := '0';
signal EVENT7_D: std_logic := '0';
signal EVENT8: std_logic := '0';
signal EVENT8_D: std_logic := '0';
signal EVENT10: std_logic := '0';
signal EVENT11A: std_logic := '0';
signal EVENT11B: std_logic := '0';
signal EVENT11C: std_logic := '0';
signal EVENT11D: std_logic := '0';
signal STATE: integer range 0 to 3 := 0;
signal STATE_TIMER: integer range 0 to 100 := 0;
signal DATA1_IN_STARTADDR3: unsigned(31 downto 0) := (others => '0');
signal DATA1_IN_CEILINGADDR3: unsigned(31 downto 0) := (others => '0');
signal DATA1_IN_MODE3: std_logic_vector(1 downto 0) := (others => '0');
signal WR_ADDR: unsigned(31 downto 0) := (others => '0');
signal WR_ADDR_PLUS8: unsigned(31 downto 0) := (others => '0');
signal WR_ADDR_STABLE: std_logic := '0';
signal WR_ADDR_STABLE0: std_logic := '0';
signal RD_ADDR: unsigned(31 downto 0) := (others => '0');
signal RD_ADDR_NEXT: unsigned(31 downto 0) := (others => '0');
signal RD_ADDR_PLUS8: unsigned(31 downto 0) := (others => '0');
signal RD_ADDR_STABLE: std_logic := '0';
signal RD_ADDR_STABLE0: std_logic := '0';

--//------ SDRAM CONTROLLER ------------------------------------
signal app_addr                    : std_logic_vector((APP_NADDRBITS - 1) downto 0) := (others => '0');
signal app_cmd                     : std_logic_vector(2 downto 0) := (others => '0');
signal app_en                      : std_logic := '0';
signal app_wdf_data                : std_logic_vector(511 downto 0) := (others => '0');
signal app_wdf_end                 : std_logic := '0';
signal app_wdf_wren                : std_logic := '0';
signal app_rd_data                 : std_logic_vector(511 downto 0) := (others => '0');
signal app_rd_data_end             : std_logic := '0';
signal app_rd_data_valid           : std_logic := '0';
signal app_rd_data_valid0           : std_logic := '0';
signal app_rdy                     : std_logic := '0';
signal app_rdy0                     : std_logic := '0';
signal app_rdy_d                     : std_logic := '0';
signal app_wdf_rdy                 : std_logic := '0';
signal app_wdf_rdy0                 : std_logic := '0';
signal app_ref_ack                 : std_logic := '0';
signal app_zq_ack                  : std_logic := '0';
signal app_wdf_mask                : std_logic_vector(63 downto 0) := (others => '0');
signal init_calib_complete_i       : std_logic := '0';
signal init_calib_complete_i0       : std_logic := '0';
signal app_rdy_df                     : std_logic := '0';

--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

--//-- CLOCKS --------------------------------
-- monitoring
MONITORING_001: process(CLK)
begin
	if rising_edge(CLK) then
		-- memory ready
		MEMORY_RDY_OUT <= PLL_LOCKED_IN and (not(MIG_UI_CLK_SYNC_RST)) and init_calib_complete_i;
	end if;
end process;

BUFG_001: BUFG port map(I => CLK200, O=> CLK200g);
BUFG_002: BUFG port map(I => CLK333p3, O=> CLK333p3g);

-- convert reset pulse to step 
RESET_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			ASYNC_RESETn <= '1';
		end if;
	end if;
end process;

-- make a reset synchronous with CLK333p3g
RESET_GEN_002: process(CLK333p3g)
begin
	if rising_edge(CLK333p3g) then
		SYNC_RESET100n <= ASYNC_RESETn and PLL_LOCKED_IN;
	end if;
end process;

--// DATA1_IN INPUT ELASTIC BUFFERS ---------------------------------------------------
-- A-side = user side
-- B-side = DDR3 memory side

-- freeze ceiling address and reclock CTS
RECLOCK_001: process(CLK)
begin
	if rising_edge(CLK) then
		DATA1_IN_CTS <= DATA1_IN_CTS_local;
		
		if(DATA1_IN_SETADDR = '1') then
			DATA1_IN_CEILINGADDR_D <= DATA1_IN_CEILINGADDR;
		end if;
	end if;
end process;

-- write pointer management. Move pointer immediately after writing a cell.
RAMB1_WPTRA_001: process(CLK)
begin
	if rising_edge(CLK) then
		COUNTER1_MOD8 <= COUNTER1_MOD8 + 1;

		-- Move write pointer immediately after writing to the input elastic buffer.
		-- Two cases: writing data or storing the start/ceiling addresses in the input elastic buffer.
		if(SYNC_RESET = '1') then
			RAMB1_ADDRA <= (others => '0');
		elsif(DATA1_IN_SETADDR = '1') or (DATA1_IN_VALID = '1') then
			RAMB1_ADDRA <= RAMB1_ADDRA + 1;
		end if;
		
		-- update copy of write pointer once every 8 clocks
		if(COUNTER1_MOD8 = 7) then
			RAMB1_ADDRA_D <= RAMB1_ADDRA;
		end if;
		
		if(COUNTER1_MOD8 < 6) then
			-- safe to reclock RAMB1_ADDRA_D with another unrelated clock
			RAMB1_ADDRA_IS_STABLE <= '1';
		else
			RAMB1_ADDRA_IS_STABLE <= '0';
		end if;
		
	end if;
end process;


RAMB1_DIA1(63 downto 0) <= DATA1_IN_STARTADDR & DATA1_IN_CEILINGADDR when (DATA1_IN_SETADDR = '1') else
				  DATA1_IN(63 downto 0);
RAMB1_DIA1(511 downto 64) <= DATA1_IN(511 downto 64);
RAMB1_DIA1(513 downto 512) <= DATA1_IN_MODE;
RAMB1_DIA1(514) <= DATA1_IN_SETADDR;	-- extra bit (MSb) to distinguish between data and address range.
					-- mux start address, ceiling address and input data word
RAMB1_WEA <= '1' when (DATA1_IN_SETADDR = '1') or (DATA1_IN_VALID = '1') else '0';

-- cross clock domain from CLK to MIG_UI_CLKg
RAMB_001: BRAM_DP2 
GENERIC MAP(
	DATA_WIDTHA => 515,		
	ADDR_WIDTHA => RAMB_ADDR_WIDTH,
	DATA_WIDTHB => 515,		 
	ADDR_WIDTHB => RAMB_ADDR_WIDTH
)
PORT MAP(
    CSA => '1',
    CLKA => CLK,
    WEA => RAMB1_WEA,
	 OEA => '0',
    ADDRA => std_logic_vector(RAMB1_ADDRA),  
    DIA => RAMB1_DIA1,
    DOA => open,
    CSB => '1',
    CLKB => MIG_UI_CLKg,
    WEB => '0',
	 OEB => '1',
    ADDRB => std_logic_vector(RAMB1_ADDRB0),
    DIB => (others => '0'),
    DOB => RAMB1_DOB1
);

DATA1_ADDR_DATAn <= RAMB1_DOB1(514);	-- valid only when buffer is not empty (DATA1INBUF_EMPTY = '0')

-- reclock RAMB1_ADDRA_D with DDR3 SDRAM clock when safe
RAMB1_WPTRA_002: process(MIG_UI_CLKg, RAMB1_ADDRA_IS_STABLE, RAMB1_ADDRA_D)
begin
	if rising_edge(MIG_UI_CLKg) then
		RAMB1_ADDRA_D2 <= RAMB1_ADDRA_D;
		RAMB1_ADDRA_IS_STABLE_D <= RAMB1_ADDRA_IS_STABLE;
	
		if(RAMB1_ADDRA_IS_STABLE_D = '1') then
			RAMB1_ADDRA_D3 <= RAMB1_ADDRA_D2;
		end if;
	end if;
end process;

-- compute used space in input elastic buffer
RAMB1_SIZE <= RAMB1_ADDRA_D3 - RAMB1_ADDRB;
DATA1INBUF_EMPTY <= '1' when (RAMB1_SIZE = 0) else '0';	

-- request data from the input connector if buffer is less than 3/4 full
DATA1_IN_CTS_local <= '1' when (RAMB1_SIZE((RAMB1_SIZE'left) downto (RAMB1_SIZE'left -1)) /= "11") else '0'; -- (synchronous with MIG_UI_CLKg)

-- read pointer management
RAMB1_ADDRB_INC <= RAMB1_ADDRB + 1;
RAMB1_RPTRB_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if(STATE = 0) then
			-- no transaction until the SDRAM is initialized and ready.
			RAMB1_ADDRB <= (others => '0'); -- points to the next address to read
		elsif (EVENT1 = '1') then
			-- capturing two 32-bit addresses (start + ceiling) and mode. move to follow-on data
			RAMB1_ADDRB <= RAMB1_ADDRB_INC;
		elsif (EVENT2 = '1') or (EVENT3 = '1') then
			-- send write command to MIG. Move to next address or data.
			RAMB1_ADDRB <= RAMB1_ADDRB_INC;
		end if;
	end if;
end process;
RAMB1_ADDRB0 <= RAMB1_ADDRB_INC when (EVENT1 = '1') or (EVENT2 = '1') or (EVENT3 = '1') else RAMB1_ADDRB;	-- lookup next location without waiting

-- is write transaction complete?
WRITE_CMD_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if(EVENT1 = '1') then	
			-- new write command
			if(RAMB1_DOB1(513 downto 512) = "11") then
				-- stop writing immediately
				WRITE_TRANSACTION_PENDING <= '0';
			else
				-- new write mode (fixed address, single shot mode, continuous mode) 
				WRITE_TRANSACTION_PENDING <= '1';
			end if;
		elsif(EVENT5 = '1') then 
			-- previous transaction acknowledged
			if (DATA1_IN_MODE3 = "10") and (WR_ADDR >= DATA1_IN_CEILINGADDR3(WR_ADDR'left downto 0)) then
				-- single-shot mode: reached ceiling. we are done. 
				WRITE_TRANSACTION_PENDING <= '0';
			elsif(DATA1_IN_MODE3 = "00")  then
				-- single burst length write. we are done.
				WRITE_TRANSACTION_PENDING <= '0';
			end if;
		end if;
	end if;
end process;	

WRITE_CMD_002: process(CLK)
begin
	if rising_edge(CLK) then
		WRITE_TRANSACTION_PENDING_D <= WRITE_TRANSACTION_PENDING;
		WRITE_TRANSACTION_PENDING_D2 <= WRITE_TRANSACTION_PENDING_D;
		
		if(SYNC_RESET = '1') then
			WRITE_COMMAND_COMPLETE <= '1';
		elsif(DATA1_IN_SETADDR = '1') then
			WRITE_COMMAND_COMPLETE <= '0';
		elsif(WRITE_TRANSACTION_PENDING_D = '0') and (WRITE_TRANSACTION_PENDING_D2 = '1') then
			WRITE_COMMAND_COMPLETE <= '1';
		end if;
	end if;
end process;	
	
	
	

--// DATA1_OUT OUTPUT ELASTIC BUFFERS ---------------------------------------------------
-- A-side = user side
-- B-side = DDR3 memory side

-- Latch in the read command
READ_CMD_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(DATA1_OUT_SETADDR = '1') then
			DATA1_OUT_SETADDR_TOGGLE <= not DATA1_OUT_SETADDR_TOGGLE;
			DATA1_OUT_STARTADDR_D <= unsigned(DATA1_OUT_STARTADDR);
			DATA1_OUT_CEILINGADDR_D <= unsigned(DATA1_OUT_CEILINGADDR);
			DATA1_OUT_MODE_D <= DATA1_OUT_MODE;
		end if;
	end if;
end process;

-- glitch-free transfer from the user CLK domain to the SDRAM DDR3 clock domain
READ_CMD_002: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		DATA1_OUT_SETADDR_TOGGLE_D <= DATA1_OUT_SETADDR_TOGGLE;
		DATA1_OUT_SETADDR_TOGGLE_D2 <= DATA1_OUT_SETADDR_TOGGLE_D;
		DATA1_OUT_SETADDR_TOGGLE_D3 <= DATA1_OUT_SETADDR_TOGGLE_D2;
		if(MIG_UI_CLK_SYNC_RST = '1') or (EVENT11A = '1') or (EVENT11B = '1') or (EVENT11D = '1') then	
			-- three conditions terminate the read cycle.
			-- fixed address mode. one burst length only. ready for next transaction
			-- single shot mode: reached the ceiling address
			-- immediate stop reading
			READ_TRANSACTION_PENDING <= '0';
		elsif(EVENT6 = '1') then	
			-- new start/ceiling read boundaries. Reclock when stable.
			READ_TRANSACTION_PENDING <= '1';
			DATA1_OUT_STARTADDR_D2 <= DATA1_OUT_STARTADDR_D;
			DATA1_OUT_CEILINGADDR_D2 <= DATA1_OUT_CEILINGADDR_D;
			DATA1_OUT_MODE_D2 <= DATA1_OUT_MODE_D;
		end if;
	end if;
end process;

-- write pointer management. Move pointer immediately after writing a cell.
RAMB2_WPTRA_001: process(MIG_UI_CLKg)
begin
	if falling_edge(MIG_UI_CLKg) then	-- FALLING EDGE !!!!!!!!!
		COUNTER2_MOD8 <= COUNTER2_MOD8 + 1;

		if(MIG_UI_CLK_SYNC_RST = '1') or (EVENT6 = '1') then	
			-- flush output elastic buffer at start of read transaction
			RAMB2_ADDRA <= (others => '0');
		elsif(app_rd_data_valid = '1') then	-- better read at falling edge
			RAMB2_ADDRA <= RAMB2_ADDRA + 1;
		end if;

		-- update copy of write pointer once every 8 clocks
		if(COUNTER2_MOD8 = 7) then
			RAMB2_ADDRA_D <= RAMB2_ADDRA;
		end if;
		
		if(COUNTER2_MOD8 < 6) then
			-- safe to reclock RAMB2_ADDRA_D with another unrelated clock
			RAMB2_ADDRA_IS_STABLE <= '1';
		else
			RAMB2_ADDRA_IS_STABLE <= '0';
		end if;

	end if;
end process;

-- cross clock domain from MIG_UI_CLKg to CLK 
RAMB2_DIA1 <= app_rd_data;
RAMB_002: BRAM_DP2 
GENERIC MAP(
	DATA_WIDTHA => 512,		
	ADDR_WIDTHA => RAMB_ADDR_WIDTH,
	DATA_WIDTHB => 512,		 
	ADDR_WIDTHB => RAMB_ADDR_WIDTH
)
PORT MAP(
    CSA => '1',
    CLKA => not MIG_UI_CLKg,
    WEA => app_rd_data_valid,
	 OEA => '0',
    ADDRA => std_logic_vector(RAMB2_ADDRA),  
    DIA => RAMB2_DIA1,
    DOA => open,
    CSB => '1',
    CLKB => CLK,
    WEB => '0',
	 OEB => '1',
    ADDRB => std_logic_vector(RAMB2_ADDRB),
    DIB => (others => '0'),
    DOB => RAMB2_DOB1
);

DATA1_OUT <= RAMB2_DOB1;

-- reclock RAMB2_ADDRA_D with CLK clock when safe
RAMB2_WPTRA_002: process(CLK)
begin
	if rising_edge(CLK) then
		RAMB2_ADDRA_D2 <= RAMB2_ADDRA_D;
		RAMB2_ADDRA_IS_STABLE_D <= RAMB2_ADDRA_IS_STABLE;
	
		if(RAMB2_ADDRA_IS_STABLE_D = '1') then
			RAMB2_ADDRA_D3 <= RAMB2_ADDRA_D2;
		end if;
	end if;
end process;

-- compute used space in input elastic buffer
RAMB2_SIZE <= RAMB2_ADDRA_D3 + not(RAMB2_ADDRB);
DATA1_OUT_EMPTY_local <= '1' when (RAMB2_SIZE = 0) else '0';

DATA1_OUT_EMPTY <= DATA1_OUT_EMPTY_local;

-- request read data from memory if elastic buffer is less than 3/4 full
DATA1OUTBUF_FULL_GEN: process(CLK)
begin
	if rising_edge(CLK) then
		if(RAMB2_SIZE((RAMB2_SIZE'left) downto (RAMB2_SIZE'left -1)) = "11") then
			DATA1OUTBUF_FULL <= '1';
		else
			DATA1OUTBUF_FULL <= '0';
		end if;
	end if;
end process;

-- read pointer management
RAMB2_RPTRB_002: process(CLK)
begin
	if rising_edge(CLK) then
		DATA1_OUT_VALID <= DATA1_OUT_VALID_E; 	-- it takes one CLK to read data from the RAMB
		
		if(SYNC_RESET = '1') or (DATA1_OUT_SETADDR = '1') or (DATA1_OUT_SETADDR_TOGGLE /= DATA1_OUT_SETADDR_TOGGLE_D3) then
			-- flush output elastic buffer at start of read transaction
			-- Trick: wait until both addresses (A and B) have been reset.
			RAMB2_ADDRB <= (others => '1');
			DATA1_OUT_VALID_E <= '0';
		elsif(DATA1_OUT_CTS = '1') and (DATA1_OUT_EMPTY_local = '0') then
			RAMB2_ADDRB <= RAMB2_ADDRB + 1;
			DATA1_OUT_VALID_E <= '1';
		else
			DATA1_OUT_VALID_E <= '0';
		end if;
	end if;
end process;

--// TRANSACTION SCHEDULER ---------------------------------------------------
-- state 0: awaiting clocks readiness and calibration completion
-- state 1: awaiting write data
-- state 2: awaiting confirmation of successful write
-- state 3: awaiting confirmation of successful read

EVENT1 <= '1' when (STATE /= 0) and (DATA1INBUF_EMPTY = '0') and (DATA1_ADDR_DATAn = '1') else '0';
	-- capture start/ceiling addresses and mode at the start of a write sequence
EVENT2 <= '1' when (STATE = 1) and (DATA1INBUF_EMPTY = '0') and (DATA1_ADDR_DATAn = '0') else '0';
	-- write transaction starts
EVENT3 <= '1' when (STATE = 2) and (app_rdy = '1') and ((app_rdy_d = '0') or (EVENT2_D = '1') or (EVENT3_D = '1')) and (DATA1INBUF_EMPTY = '0') and (DATA1_ADDR_DATAn = '0') else '0';	
	-- previous write command was accepted. next write transaction starts
EVENT4 <= '1' when (STATE = 2) and (app_rdy = '1') and ((DATA1INBUF_EMPTY = '1') or (DATA1_ADDR_DATAn = '1')) else '0';
	-- previous write command was accepted. No other data to write.
EVENT5 <= '1' when (STATE = 2) and (app_wdf_rdy = '1') else '0';
	-- previous write data was accepted
EVENT6 <= '1' when (DATA1_OUT_SETADDR_TOGGLE_D /= DATA1_OUT_SETADDR_TOGGLE_D2) else '0';
	-- capture start/ceiling addresses and mode at the start of a read sequence
EVENT7 <= '1' when (STATE = 1) and (READ_TRANSACTION_PENDING = '1') and (DATA1OUTBUF_FULL = '0') else '0';
	-- read transaction starts
--EVENT8 <= '1' when (STATE = 3) and (app_rdy = '1') and ((app_rdy_d = '0') or (EVENT7_D = '1') or (EVENT8_D = '1')) and (READ_TRANSACTION_PENDING = '1') and (DATA1OUTBUF_FULL = '0') else '0';
--	-- triggers read transaction
EVENT8 <= '1' when (STATE = 3) and (EVENT10 = '1') and ((DATA1_OUT_MODE_D2 = "01") or (DATA1_OUT_MODE_D2 = "10"))  and 
	(DATA1OUTBUF_FULL = '0') else '0';
	-- triggers next read transaction 
EVENT10 <= '1' when (app_en = '1') and (app_rdy = '1') and (app_cmd = "001") else '0';
	-- read command is accepted. 
EVENT11A <= '1' when (STATE = 3) and (EVENT10 = '1') and (DATA1_OUT_MODE_D2 = "00") else '0';
	-- read cycle termination: fixed address mode. one burst length only.
EVENT11B <= '1' when (STATE = 3) and (EVENT10 = '1') and 
	(RD_ADDR_PLUS8 >= DATA1_OUT_CEILINGADDR_D2(RD_ADDR'left downto 0)) and 
	(DATA1_OUT_MODE_D2 = "10") else '0';
	-- read cycle termination: single shot mode: reached the ceiling address
EVENT11C <= '1' when (STATE = 3) and (EVENT10 = '1') and (DATA1OUTBUF_FULL = '1') else '0';
	-- temporary end of read cycle, until output buffer has room again. In the mean time
	-- SDRAM can be used for write cycles.
--EVENT11D <= '1' when (DATA1_OUT_MODE_D2 = "11") else '0';
-- test test test
EVENT11D <= '1' when (STATE = 3) and (EVENT10 = '1') and (DATA1_OUT_MODE_D2 = "11") else '0';

	-- immediate read termination command

	
SCHEDULER_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		EVENT2_D <= EVENT2;
		EVENT3_D <= EVENT3;
		EVENT7_D <= EVENT7;
		EVENT8_D <= EVENT8;
		app_rdy_d <= app_rdy;
		
		if(MIG_UI_CLK_SYNC_RST = '1') then
			-- no transaction until MIG is ready
			STATE <= 0;
		elsif(STATE = 0) and (init_calib_complete_i = '1') then
			-- calibration is complete. We can now do read/write transactions
			STATE <= 1;
		elsif (EVENT7 = '1') then
			-- send read command to MIG
			STATE <= 3;
			STATE_TIMER <= 10;	-- timeout in case no response from SDRAM
		elsif (EVENT11A = '1') or (EVENT11B = '1') or (EVENT11C = '1') or (EVENT11D = '1') then
			-- successful previous read command. No other data to read or no room in output buffer,
			-- or immediate read termination
			STATE <= 1;
		elsif (EVENT8 = '1') then
			-- successful previous read command. send next read command to MIG
			-- if/elsif order is important. Place read termination conditions before this one.
			--STATE <= 3;
			STATE_TIMER <= 10;	-- timeout in case no response from SDRAM
		elsif (EVENT2 = '1') then
			-- send write command to MIG
			STATE <= 2;
			STATE_TIMER <= 10;	-- timeout in case no response from SDRAM
		elsif (EVENT3 = '1')  then
			--  successful previous write command. More data waiting. Send next write command to MIG
			STATE_TIMER <= 10;	-- timeout in case no response from SDRAM
		elsif (EVENT4 = '1')  then
			-- successful previous write command. No other data to write.
			STATE <= 1;
		elsif (STATE = 2) and (STATE_TIMER = 0) then
			-- timeout waiting for a write confirmation from MIG
			STATE <= 1;
		elsif (STATE = 3) and (STATE_TIMER = 0) then
			-- timeout waiting for a read confirmation from MIG
			STATE <= 1;
		elsif (STATE = 2) or (STATE = 3) then
			STATE_TIMER <= STATE_TIMER - 1;

		end if;	
	end if;
end process;

-- latch in start/ceiling write addresses
START_CEILING_ADDR_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if (EVENT1 = '1') then
			-- write transaction starts with two 32-bit addresses (start + ceiling) and mode
			DATA1_IN_STARTADDR3 <= unsigned(RAMB1_DOB1(63 downto 32));
			DATA1_IN_CEILINGADDR3 <= unsigned(RAMB1_DOB1(31 downto 0));
			-- mode 
			DATA1_IN_MODE3 <= RAMB1_DOB1(513 downto 512);
		end if;
	end if;
end process;

-- manage SDRAM write addresses
WR_ADDR_PLUS8 <= WR_ADDR + 8;	-- because BL8
WR_ADDR_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if (EVENT1 = '1') then
			-- initialize write address
			WR_ADDR <= unsigned(RAMB1_DOB1(63 downto 32));
		elsif(EVENT2 = '1') or (EVENT3 = '1') then 
			-- prepare next address
			if (WR_ADDR_PLUS8 >= DATA1_IN_CEILINGADDR3(WR_ADDR'left downto 0)) and (DATA1_IN_MODE3 = "01") then
				-- reached the ceiling address. Rewind to start address.
				WR_ADDR <= DATA1_IN_STARTADDR3;
			elsif (DATA1_IN_MODE3 = "01") or (DATA1_IN_MODE3 = "10") then
				-- auto-increment
				WR_ADDR <= WR_ADDR_PLUS8;
			end if;
		end if;
	end if;
end process;
-- detect no-change periods when we can reclock WR_ADDR with CLK for monitoring purposes
WR_ADDR_002: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if(EVENT1 = '1') or (EVENT2 = '1') or (EVENT3 = '1') then
			-- WR_ADDR is changing
			WR_ADDR_STABLE0 <= '0';
		else
			WR_ADDR_STABLE0 <= '1';
		end if;
	end if;
end process;
WR_ADDR_STABLE <= '0' when (EVENT1 = '1') or (EVENT2 = '1') or (EVENT3 = '1') else WR_ADDR_STABLE0;
-- reclock monitoring with CLK
WR_ADDR_003: process(CLK)
begin
	if rising_edge(CLK) then
		if (WR_ADDR_STABLE = '1') then 
			DATA1_IN_ADDR <= std_logic_vector(WR_ADDR);	-- for monitoring purposes
		end if;
	end if;
end process;

-- manage SDRAM read addresses
-- RD_ADDR = NEXT ADDRESS to read from
RD_ADDR_PLUS8 <= RD_ADDR + 8;	-- because BL8

RD_ADDR_NEXT_001: process(RD_ADDR, RD_ADDR_PLUS8, DATA1_OUT_MODE_D2, DATA1_OUT_CEILINGADDR_D2, DATA1_OUT_STARTADDR_D2)
begin
	if (DATA1_OUT_MODE_D2 = "01") and (RD_ADDR_PLUS8 >= DATA1_OUT_CEILINGADDR_D2(RD_ADDR'left downto 0)) then
		-- continuous mode. About to hit the ceiling. rewind
		RD_ADDR_NEXT <= DATA1_OUT_STARTADDR_D2;
	else
		RD_ADDR_NEXT <= RD_ADDR_PLUS8;
		-- auto-increment
	end if;
end process;
		

RD_ADDR_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if (EVENT6 = '1') then
			-- initialize read address
			RD_ADDR <= DATA1_OUT_STARTADDR_D;
		elsif(EVENT10 = '1') then
			-- previous read command is accepted. 
			-- next address. 
			RD_ADDR <= RD_ADDR_NEXT;
		end if;
	end if;
end process;



-- detect no-change periods when we can reclock RD_ADDR with CLK for monitoring purposes
RD_ADDR_002: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if(EVENT6 = '1') or (EVENT7 = '1') or (EVENT8 = '1') then
			-- RD_ADDR is changing
			RD_ADDR_STABLE0 <= '0';
		else
			RD_ADDR_STABLE0 <= '1';
		end if;
	end if;
end process;
RD_ADDR_STABLE <= '0' when (EVENT6 = '1') or (EVENT7 = '1') or (EVENT8 = '1') else RD_ADDR_STABLE0;
-- reclock monitoring with CLK
RD_ADDR_003: process(CLK)
begin
	if rising_edge(CLK) then
		if (RD_ADDR_STABLE = '1') then 
			DATA1_OUT_ADDR <= std_logic_vector(RD_ADDR);	-- for monitoring purposes
		end if;
	end if;
end process;

-- MIG commands
-- Mirrors the STATE machine generation
-- conditions order is important
MIG_COMMANDS_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if(MIG_UI_CLK_SYNC_RST = '1') then
			app_en <= '0';
		elsif(STATE = 0) and (init_calib_complete_i = '1') then
			app_en <= '0';
		elsif (EVENT7 = '1') then
			-- send read command to MIG
			app_en <= '1';
			app_addr <= std_logic_vector(RD_ADDR(app_addr'left downto 0));
			app_cmd <= "001";	-- read
		elsif (EVENT11A = '1') or (EVENT11B = '1') or (EVENT11C = '1') or (EVENT11D = '1') then
			-- successful previous read command. No other data to read or no room in output buffer,
			-- or immediate read termination
			app_en <= '0';
		elsif (EVENT8 = '1') then
			-- send follow-on read command to MIG
			app_en <= '1';
			app_addr <= std_logic_vector(RD_ADDR_NEXT(app_addr'left downto 0));
			app_cmd <= "001";	-- read
		elsif (EVENT2 = '1') or (EVENT3 = '1') then
			-- send write command to MIG
			app_en <= '1';
			app_addr <= std_logic_vector(WR_ADDR(app_addr'left downto 0));
			app_cmd <= "000";	-- write
--		elsif ((STATE = 2) or (STATE = 3)) and (app_rdy = '1') then
		elsif  (app_rdy = '1') then	-- test test test
			-- read/write command was accepted 
			app_en <= '0';
		end if;
	end if;
end process;

-- MIG write data
MIG_WR_DATA_001: process(MIG_UI_CLKg)
begin
	if rising_edge(MIG_UI_CLKg) then
		if (EVENT2 = '1') or (EVENT3 = '1') then
			-- send write data to MIG
			app_wdf_wren <= '1';
			app_wdf_data <= RAMB1_DOB1(511 downto 0);
		elsif (EVENT5 = '1') then
			-- write data was accepted
			app_wdf_wren <= '0';
		end if;
	end if;
end process;
app_wdf_end <= app_wdf_wren;	-- 1:4 clock, no difference between _end and _wren

--//------ SDRAM CONTROLLER ------------------------------------
-- configured mig_7series_0_mig.vhd as: 
-- (default) auto refresh

app_wdf_mask <= (others => '0');
	-- no mask

	-- 1GB,4GB,8GB SODIMM case
u_mig_7series_0 : mig_7series_0
port map (
	-- Memory interface ports
	ddr3_addr                      => ddr3_addr,
	ddr3_ba                        => ddr3_ba,
	ddr3_cas_n                     => ddr3_cas_n,
	ddr3_ck_n                      => ddr3_ck_n,
	ddr3_ck_p                      => ddr3_ck_p,
	ddr3_cke                       => ddr3_cke,
	ddr3_ras_n                     => ddr3_ras_n,
	ddr3_reset_n                   => ddr3_reset_n,
	ddr3_we_n                      => ddr3_we_n,
	ddr3_dq                        => ddr3_dq,
	ddr3_dqs_n                     => ddr3_dqs_n,
	ddr3_dqs_p                     => ddr3_dqs_p,
	ddr3_cs_n                      => ddr3_cs_n,
	ddr3_dm                        => ddr3_dm,
	ddr3_odt                       => ddr3_odt,
	-- Application interface ports
	app_addr                       => app_addr,
	app_cmd                        => app_cmd,
	app_en                         => app_en,
	app_wdf_data                   => app_wdf_data,
	app_wdf_end                    => app_wdf_end,
	app_wdf_wren                   => app_wdf_wren,
	app_rd_data                    => app_rd_data,
	app_rd_data_end                => app_rd_data_end,
	app_rd_data_valid              => app_rd_data_valid0,
	app_rdy                        => app_rdy0,
	app_wdf_rdy                    => app_wdf_rdy0,
	app_sr_req                     => '0',
	app_ref_req                    => '0',	-- auto refresh
	app_zq_req                     => '0',
	app_sr_active                  => open,
	app_ref_ack                    => open,
	app_zq_ack                     => app_zq_ack,
	ui_clk                         => MIG_UI_CLKg,	-- global
	ui_clk_sync_rst                => MIG_UI_CLK_SYNC_RST,
	app_wdf_mask                   => app_wdf_mask,	
	init_calib_complete            => init_calib_complete_i0,
	-- System Clock Ports
	sys_clk_i                       => CLK333p3g,
	-- Reference Clock Ports
	clk_ref_i                      => CLK200g,	-- reference clock. Must be 200 MHz
	sys_rst                        => SYNC_RESET100n	-- active low
);


-- NEW  12/27/16
-- reclock outputs at falling edge of MIG_UI_CLKg
RECLOCK_002: process(MIG_UI_CLKg)
begin
	if falling_edge(MIG_UI_CLKg) then
		app_rdy_df <= app_rdy0;
	end if;
end process;

-- because calibration takes so long, bypass mig_7series_0()
BYPASS_001: if(SIMULATION = '1') generate
	init_calib_complete_i <= '1';
	app_wdf_rdy <= '1';	-- max speed
	app_rdy <= '1';	-- max speed
--	app_wdf_rdy <= (not(event2_d)) and (not(event2_d2)) and (not(event2_d3)) and (not(event3_d)) and (not(event3_d2)) and (not(event3_d3));
--	app_rdy <= (not(event2_d)) and (not(event2_d2)) and (not(event2_d3)) and (not(event3_d)) and (not(event3_d2)) and (not(event3_d3))
--		;--and (not(event7_d)) ;
	app_rd_data_valid <= (event7_d or event8_d ) and app_rdy_d;
	
	reclock_111: process(MIG_UI_CLKg)
	begin
		if rising_edge(MIG_UI_CLKg) then
			event2_d2 <= event2_d;
			event2_d3 <= event2_d2;
			event3_d2 <= event3_d;
			event3_d3 <= event3_d2;
		end if;
	end process;
end generate;
NOBYPASS_001: if(SIMULATION = '0') generate
	app_wdf_rdy <= app_wdf_rdy0;
	init_calib_complete_i <= init_calib_complete_i0;
	app_rdy <= app_rdy_df;
	app_rd_data_valid <= app_rd_data_valid0;
end generate;

--// TEST POINTS ---------
--TP(1) <= CLK333p3g; 	-- check phase noise with a spectrum analyzer
--TP(3) <= init_calib_complete_i;
--TP(4) <= MIG_UI_CLK_SYNC_RST;
--TP(5) <= app_en;
----TP(2) <= app_wdf_data(0);
----TP(3) <= app_rd_data(0);
----TP(4) <= RAMB2_ADDRA(0);
----TP(5) <= RAMB2_ADDRB(0);
--TP(6) <= app_rdy;
--TP(7) <= app_wdf_rdy;
--TP(8) <= app_rd_data_valid;
--TP(9) <= '1' when (STATE = 1) else '0';
--TP(10) <= '1' when (STATE = 3) else '0';
--TP(13) <= SYNC_RESET;
--TP(14) <= ASYNC_RESETn;
--TP(15) <= SYNC_RESET100n;

--TP_OUT: process(CLK)
--begin
--	if rising_edge(CLK) then
--		TP(1) <= EVENT7;
----		TP(2) <= EVENT8;
--		TP(2) <= EVENT10;
--		if(STATE = 0) then	-- RECALIBRATION????
--			TP(3) <= '1';
--		else
--			TP(3) <= '0';
--		end if;
--		if(STATE = 1) then
--			TP(4) <= '1';
--		else
--			TP(4) <= '0';
--		end if;
--		TP(5) <= app_rd_data_valid;
--		TP(6) <= DATA1OUTBUF_FULL;	-- OVERFLOW???
--		TP(7) <= DATA1_OUT_EMPTY_local; -- OVERFLOW??
--		TP(8) <= RAMB2_ADDRA(0);
--		TP(9) <= RAMB2_ADDRB(0);
--		TP(10) <= MIG_UI_CLK_SYNC_RST;
--		TP(11) <= init_calib_complete_i0;
--	end if;
--end process;
-- test test test

TP_OUT: process(MIG_UI_CLKg)
begin
	if rising_edge(CLK) then
		if(STATE = 1) then
			TP(1) <= '1';
		else
			TP(1) <= '0';
		end if;
		if(STATE = 3) then
			TP(2) <= '1';
		else
			TP(2) <= '0';
		end if;
		TP(3) <= EVENT8;
		TP(4) <= EVENT10;
		if(STATE_TIMER = 0) then	
			TP(5) <= '1';
		else
			TP(5) <= '0';
		end if;
		TP(6) <= EVENT11D;
	end if;
end process;


--TP(12) <= EVENT2;
--TP(13) <= EVENT3;
--TP(14) <= EVENT4;
--TP(15) <= EVENT5;
--TP(16) <= EVENT6;
--TP(17) <= EVENT7;
--TP(18) <= EVENT8;
--TP(19) <= EVENT9;
--TP(20) <= DATA1_OUT_VALID_E;
--TP(1) <= CLKREF_IN; 
--TP(2) <= MIG_UI_CLKg; 
--TP(3) <= CLK200g; 
--TP(5) <= CLK; 
end Behavioral;

