-------------------------------------------------------------
-- MSS copyright 2012
--	Filename:  SDRAM_DELAY.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 3
--	Date last modified: 1/11/13
-- Inheritance: 	DDR2_WRAPPER, 9-25-10
--
-- description: Programmable delay between input and output data streams through a DDR2 SDRAM
-- Features: Independent clocks on user and DDR2 sides.
-- Input data is discarded until the SDRAM is ready (after 200+us initialization).
-- Performance: 21 SDRAM CLKs for 24 complex samples >  100% of 120 MHz (Spartan-6) >  120 MSamples/s in real-time
--
-- Rev2 12/27/12 AZ
-- Corrected output timing (1clk off)
-- Added timeout in state machine
-- Increased write/read burst length to 12 (consistent with a maximum input sampling rate of > 120 MSamples/s)
-- Bug: sync_reset is to be used in CLK clock domain only, sync_reset2 to be used in CLK_DDR2G clock domain only
--
-- Rev 3 1/11/13 AZ
-- change DATA1_DELAY on the fly
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
--Library UNISIM;
--use UNISIM.vcomponents.all;

entity SDRAM_DELAY is
	Generic (
	PLATFORM: integer := 6;
		-- 5 = Xilinx Virtex-5
		-- 6 = Xilinx Spartan-6
	NSDRAM_BYTES: in integer := 8;
		-- number of data bytes on the SDRAM data bus 
		-- The same data width for both user data interface and DDR2 interface
		-- 2 = 16-bit word (IC, e.g. COM-1600)
		-- 4 = 32-bit word (ICs or partial DIMM/SODIMM)
		-- 8 = 64-bit word (DIMM/SODIMM, e.g. COM-1500)
	NCLKS: in integer := 2;
		-- number of differential clock pairs: 1 for IC, 2 for SODIMM
	ADDRESS_MAP: in std_logic_vector(4 downto 0) := "10000";
		-- the logical to physical address mapping can vary depending on the hardware.
		-- See DDR2 SDRAM hardware specifications.
		-- the most common mappings are described below:
		-- 00000: 1Gb x8 IC, column A[9:0], 8 banks BA[2:0], row A[13:0], 1 rank CS# 
		-- 00001: 1Gb x16 IC, column A[9:0], 8 banks BA[2:0], row A[12:0], 1 rank CS#
		-- 00010: 2Gb x8 IC, column A[9:0], 8 banks BA[2:0], row A[14:0], 1 rank CS#
		-- 00011: 2Gb x16 IC, column A[9:0], 8 banks BA[2:0], row A[13:0], 1 rank CS#
		-- 0xxxx: other ICs, reserved for future use
		-- 10000: 1GB DIMM/SODIMM, column A[9:0], 8 banks BA[2:0], row A[12:0], 2 ranks S0#/S1#
		-- 10001: 2GB DIMM/SODIMM, column A[9:0], 8 banks BA[2:0], row A[13:0], 2 ranks S0#/S1#
		-- 10010: 4GB DIMM/SODIMM, column A[9:0], 8 banks BA[2:0], row A[14:0], 2 ranks S0#/S1#
		-- 1xxxx: other DIMM/SODIMMs, reserved for future use
	CLOCK_CYCLES: in integer := 3;
		-- (CAS latency) -  (RAS-CAS-Delay time) -  (RAS precharge time)
		-- CL - tRCD - tRP
		-- Use CL = 3 for clock speed up to 200 MHz (400 MT/s).
		-- See DDR2 SDRAM hardware specifications.
		-- 3 =  3-3-3  DDR2-400
		-- 4 =  4-4-4  DDR2-533
		-- 5 =  5-5-5  DDR2-667
		-- 6 =  6-6-6  DDR2-800
	DDR2_CLK_FREQ: in integer := 1200;
		-- actual DDR2 clock frequency in 100KHz units (used to calculate timers within)
		-- For example: 1250 means a 125 MHz clock and a maximum throughput of 300 Mtransactions/s.
		-- The specified value can be significantly slower than the SDRAM DDR2 speed grade 
		-- (since the FPGA may be the bottleneck)
	RTDELAY_COARSE: in integer := 2
		-- goal: calibrate out signal round-trip delay. 
		-- Coarse settings: integer multiple of the 1/2 CLK period rounded up. 
		-- Fine calibration (within 1/2 CLK period) is automatic.
		-- Example Spartan-6 125 MHz: 
		--    Output delay for SDRAM_CKx: 4ns
		--    Input delay for SDRAM_DQSy: 3ns
		--    RTDELAY_COARSE = 7ns*2*125MHz =  1.75 rounded up to 2.
	);
    Port ( 
		--// CLK, RESET
		CLK: in std_logic;
			-- user-interface GLOBAL CLOCK. 
			-- Designer is responsible for instantiating an external BUFG.
		CLK_DDR2_REF: in std_logic; 
			-- DDR2 SDRAM reference clock. 125 MHz min (as per DDR2 standard) but very likely works at 120 MHz and even slightly lower.
			-- Does not have to be a global clock (it only goes to one destination: DCM).
		ASYNC_RESET: in std_logic;
			-- reset pulse, active high 
			-- Use of ASYNC_RESET is not mandatory.
			
		--// USER interface
		-- Input stream
		DATA1_IN: in std_logic_vector(31 downto 0);
			-- input samples (word width large enought for 2*16-bit complex samples)
		DATA1_IN_VALID: in std_logic;
			-- data valid qualifier
		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.

		-- Output stream
		DATA1_OUT: out std_logic_vector(31 downto 0);
			-- output samples (word width large enought for 2*16-bit complex samples)
		DATA1_OUT_VALID: out std_logic;
			-- data valid qualifier
		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.

		--// CONTROL
		DATA1_STARTADDR: in std_logic_vector(31 downto 0);
			-- DDR2 SDRAM start address (inclusive). Expressed in SDRAM words (not bytes).
			-- Must be a multiple of 4 SDRAM words (= multiple of 8 complex input samples)
			-- read at CONTROL_IN_VALID = '1'
		DATA1_CEILINGADDR: in std_logic_vector(31 downto 0);
			-- optional ceiling address (exclusive). Expressed in SDRAM words (not bytes).
			-- Must be a multiple of 4 SDRAM words (= multiple of 8 complex input samples)
			-- read at CONTROL_IN_VALID = '1'
		CONTROL_IN_VALID: in std_logic;
			-- control valid qualifier (typically 1 CLK-wide pulse)
		DATA1_DELAY: in std_logic_vector(31 downto 0);
			-- delay between SDRAM input stream and output stream. Expressed in SDRAM words (not bytes). 
			-- Must be a multiple of 4 SDRAM words (= multiple of 8 complex input samples)
			-- 0 delay is valid.
			-- DATA1_DELAY MUST be less than the memory window size(DATA1_CEILINGADDR - DATA1_STARTADDR)
			-- NEW: can change on the fly

	
		-- MONITORING
		-- Monitoring the address pointers
		DATA1_IN_ADDR: out std_logic_vector(31 downto 0);
		DATA1_OUT_ADDR: out std_logic_vector(31 downto 0);
		
		--// DDR2 SDRAM interface. 
		SDRAM_DQ: inout std_logic_vector((8*NSDRAM_BYTES - 1) downto 0);
			-- Bi-directional data lines. DDR
		SDRAM_DQS_P: inout std_logic_vector((NSDRAM_BYTES - 1) downto 0);
		SDRAM_DQS_N: inout std_logic_vector((NSDRAM_BYTES - 1) downto 0);
			-- Bi-directional data strobe lines (differential)

		SDRAM_ODT: out std_logic_vector(1 downto 0);
			--	On-Die Termination
		
		-- clocks
		SDRAM_CK_P: out std_logic_vector((NCLKS - 1) downto 0);
		SDRAM_CK_N: out std_logic_vector((NCLKS - 1) downto 0);
			-- clocks 0/1 (differential)
		SDRAM_CKE: out std_logic_vector((NCLKS - 1) downto 0);
			-- clock 0/1 enable
		SDRAM_CASN: out std_logic;
		SDRAM_RASN: out std_logic;
		SDRAM_WEN: out std_logic;
		SDRAM_SN: out std_logic_vector(1 downto 0);
			--	Chip Select # (rank 0/1)
		
		SDRAM_DM: out std_logic_vector((NSDRAM_BYTES - 1) downto 0);
			-- Input Data Mask
		
		-- Address signals
		SDRAM_BA: out std_logic_vector(2 downto 0);
		SDRAM_A: out std_logic_vector(15 downto 0); 
			-- Address lines. 
		

		--// Monitoring + Test points 
		SDRAM_DQ_DIR: out std_logic;  
		SDRAM_DQS_DIR: out std_logic;
			-- direction of the bi-directional bus SDRAM_DQ and SDRAM_DQS
			-- primarily for simulation use: when simulating a delay between FPGA and SDRAM
			-- high=input, low=output
		SDRAM_READY: out std_logic;
			-- '1' when SDRAM has been initialized
			
		SDRAM_TP: out std_logic_vector(10 downto 1)
			-- bit 0: '1' when the configuration and calibration phases are complete. 
			-- The SDRAM can now be used for read/write transactions.  
			-- If SDRAM_READY stays low, the main cause is likely RTDELAY_COARSE out of range.
		
 );
end entity;

architecture Behavioral of SDRAM_DELAY is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT BRAM_DP 
	 Generic (
		DATA_WIDTHA: integer := 32;
		ADDR_WIDTHA: integer := 9;
		DATA_WIDTHB: integer := 4;
		ADDR_WIDTHB: integer := 12
	);
	 Port ( 
		 -- Port A
		 CLKA   : in  std_logic;
		 WEA    : 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);
		  
		 -- Port B
		 CLKB   : in  std_logic;
		 WEB    : 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 DDR2_SDRAM_CONTROLLER
	Generic (
	PLATFORM: integer;
	NSDRAM_BYTES: in integer;
	NCLKS: in integer;
	ADDRESS_MAP: in std_logic_vector(4 downto 0);
	CLOCK_CYCLES: in integer;
	DDR2_CLK_FREQ: in integer;
	RTDELAY_COARSE: in integer
	);
	PORT(
		CLK_DDR2_REF: in std_logic; 
		ASYNC_RESET: in std_logic;
		CLK_DDR2G_OUT: out std_logic;
		START_ADDR : IN std_logic_vector(31 downto 0);
		TRANSACTION_REQ : IN std_logic_vector(1 downto 0);
		TRANSACTION_REQ_NO : IN std_logic_vector(3 downto 0);
		TRANSACTION_REQ_ACK : OUT std_logic;
		DATA_IN: in std_logic_vector((16*NSDRAM_BYTES - 1) downto 0);
		DATA_IN_CTS: out std_logic;
		DATA_OUT: out std_logic_vector((16*NSDRAM_BYTES - 1) downto 0);
		DATA_OUT_EN : OUT std_logic;
		SELF_REFRESH_REQ : IN std_logic;    
		SDRAM_DQ : INOUT std_logic_vector((8*NSDRAM_BYTES - 1) downto 0);
		SDRAM_DQS_P : INOUT std_logic_vector((NSDRAM_BYTES - 1) downto 0);
		SDRAM_DQS_N : INOUT std_logic_vector((NSDRAM_BYTES - 1) downto 0);      
		SDRAM_ODT : OUT std_logic_vector(1 downto 0);
		SDRAM_CK_P: out std_logic_vector((NCLKS - 1) downto 0);
		SDRAM_CK_N: out std_logic_vector((NCLKS - 1) downto 0);
		SDRAM_CKE: out std_logic_vector((NCLKS - 1) downto 0);
		SDRAM_CASN : OUT std_logic;
		SDRAM_RASN : OUT std_logic;
		SDRAM_WEN : OUT std_logic;
		SDRAM_SN: out std_logic_vector(1 downto 0);
		SDRAM_DM : OUT std_logic_vector((NSDRAM_BYTES - 1) downto 0);
		SDRAM_BA : OUT std_logic_vector(2 downto 0);
		SDRAM_A : OUT std_logic_vector(15 downto 0);
		SDRAM_READY: OUT std_logic;
		SDRAM_DQ_DIR: out std_logic;
		SDRAM_DQS_DIR: out std_logic;
		SDRAM_TP : OUT std_logic_vector(10 downto 1)
		);
	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 CLK_DDR2G: std_logic := '0';
signal RESET_CNTR: std_logic_vector(2 downto 0) := "000";
signal SYNC_RESET: std_logic := '0';
signal RESET_CNTR2: std_logic_vector(2 downto 0) := "000";
signal SYNC_RESET2: std_logic := '0';


--// DATA1_IN INPUT ELASTIC BUFFER ---------------------------------------------------
signal DATA1_IN_VALID2: std_logic := '0';
signal DATA1_STARTADDR_D: std_logic_vector(31 downto 0) := (others => '0');
signal DATA1_CEILINGADDR_D: std_logic_vector(31 downto 0) := (others => '0');
signal DATA1_DELAY_D: std_logic_vector(31 downto 0) := (others => '0');
signal DATA1_STARTADDR_D2: std_logic_vector(31 downto 0) := (others => '0');
signal DATA1_CEILINGADDR_D2: std_logic_vector(31 downto 0) := (others => '0');
signal WINDOW_SIZE: std_logic_vector(31 downto 0) := (others => '0');
signal CONTROL_IN_VALID_FLAG: std_logic := '0';
signal CONTROL_IN_VALID_FLAG_D: std_logic := '0';
signal CONTROL_IN_VALID_FLAG_D2: std_logic := '0';
signal CONTROL_CHANGE_PULSE_D2: std_logic := '0';
signal RAMB1_DOB1: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB1_DOB2: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB1_DOB3: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB1_DOB4: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB1_ADDRA0: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB1_ADDRA: std_logic_vector(8 downto 0) := (others => '0');
signal RAMB1_ADDRA_D: std_logic_vector(8 downto 0) := (others => '0');
signal RAMB1_ADDRA_D2: std_logic_vector(8 downto 0) := (others => '0');
signal RAMB1_ADDRA_D3: std_logic_vector(8 downto 0) := (others => '0');
signal RAMB1_WEA1: std_logic := '0';
signal RAMB1_WEA2: std_logic := '0';
signal RAMB1_WEA3: std_logic := '0';
signal RAMB1_WEA4: std_logic := '0';
signal COUNTER1_MOD8: std_logic_vector(2 downto 0) := "000";
signal RAMB1_ADDRA_IS_STABLE: std_logic := '0';
signal RAMB1_ADDRA_IS_STABLE_D: std_logic := '0';
signal RAMB1_ADDRB: std_logic_vector(8 downto 0) := (others => '0');
signal DATA1INBUF_EMPTY: std_logic;
signal RAMB1_SIZE: std_logic_vector(8 downto 0) := (others => '0');

--// DATA1_OUT OUTPUT ELASTIC BUFFER ---------------------------------------------------
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_STARTADDR_D: std_logic_vector(31 downto 0)  := (others => '0');
signal DATA1_OUT_CEILINGADDR_D: std_logic_vector(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(31 downto 0)  := (others => '0');
signal RAMB2_DIA2: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DIA3: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DIA4: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DOB1: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB2_DOB2: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DOB3: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DOB4: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB2_DOB1_D: std_logic_vector(31 downto 0) := (others => '0');
signal RAMB2_DOB2_D: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DOB3_D: std_logic_vector(31 downto 0)  := (others => '0');
signal RAMB2_DOB4_D: std_logic_vector(31 downto 0) := (others => '0');

signal RAMB2_ADDRA0: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_ADDRA: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_ADDRA_D: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_ADDRA_D2: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_ADDRA_D3: std_logic_vector(10 downto 0) := (others => '0');
signal COUNTER2_MOD8: std_logic_vector(2 downto 0) := "000";
signal RAMB2_ADDRA_IS_STABLE: std_logic := '0';
signal RAMB2_ADDRA_IS_STABLE_D: std_logic := '0';
signal RAMB2_ADDRB0: std_logic_vector(8 downto 0) := (others => '0');
signal RAMB2_ADDRB: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_ADDRB_D: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_ADDRB_D2: std_logic_vector(10 downto 0) := (others => '0');
signal RAMB2_SIZE: std_logic_vector(10 downto 0);
signal DATA1_OUT_EMPTY_LOCAL: std_logic := '0';
signal DATA1_OUT_VALID_E: std_logic := '0';
signal DATA1_OUT_VALID_E2: std_logic := '0';
signal DATA1_OUT_VALID_E3: std_logic := '0';

--// TRANSACTION SCHEDULER ---------------------------------------------------
signal STATE: std_logic_vector(3 downto 0) := "0000";
signal EVENT1: std_logic := '0';
signal EVENT2: std_logic := '0';
signal EVENT3: std_logic := '0';
signal EVENT4: std_logic := '0';
signal EVENT5: std_logic := '0';
signal EVENT6: std_logic := '0';
signal EVENT7: std_logic := '0';
constant TIMER1_TIMEOUT: integer := 1000;
signal TIMER1: integer range 0 to TIMER1_TIMEOUT := 0;
signal WBURST_START_ADDR : std_logic_vector(31 downto 0) := x"00000000";
signal RBURST_START_ADDR : std_logic_vector(31 downto 0) := x"00000000";
signal WBURST_START_ADDR_PLUS4 : std_logic_vector(31 downto 0);
signal RBURST_START_ADDR_PLUS4 : std_logic_vector(31 downto 0);
signal BURST_START_ADDR : std_logic_vector(31 downto 0) := x"00000000";
signal TRANSACTION_REQ: std_logic_vector(1 downto 0) := "00";
signal TRANSACTION_REQ_NO: std_logic_vector(3 downto 0) := "0000";
signal TRANSACTION_REQ_ACK: std_logic := '0';

signal DATA1_IN_STARTADDR2: std_logic_vector(31 downto 0) := x"00000000";


--//------ SDRAM CONTROLLER ------------------------------------
signal CONTROLLER_DATA_IN: std_logic_vector(127 downto 0):= (others => '0');
signal CONTROLLER_DATA_IN_CTS: std_logic := '0';
signal CONTROLLER_DATA_OUT: std_logic_vector(127 downto 0):= (others => '0');
signal CONTROLLER_DATA_OUT_EN : std_logic := '0';
signal SDRAM_READY_local: std_logic := '0';
signal SDRAM_READY_D: std_logic := '0';
signal SDRAM_READY_D2: std_logic := '0';
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

--// SYNCHRONOUS RESETS  ---------------------------------------------------
-- internally-generated reset to correctly position the read/write pointers (as a user may forget to do so).
SYNC_RESET_GEN: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		RESET_CNTR <= (others => '0');
	elsif rising_edge(CLK) then
		if(RESET_CNTR(2) = '0') then
			RESET_CNTR <= RESET_CNTR + 1;
		end if;
	end if;
end process;
SYNC_RESET <= not RESET_CNTR(2);


SYNC_RESET2_GEN: process(SYNC_RESET, CLK_DDR2G)
begin
	if(SYNC_RESET = '1') then
		RESET_CNTR2 <= (others => '0');
	elsif rising_edge(CLK_DDR2G) then
		if(RESET_CNTR2(2) = '0') then
			RESET_CNTR2 <= RESET_CNTR2 + 1;
		end if;
	end if;
end process;
SYNC_RESET2 <= not RESET_CNTR2(2);

-- freeze configuration (start/ceiling addresses, not delay which can change at any time)
RECLOCK_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') or (CONTROL_IN_VALID = '1') then
			CONTROL_IN_VALID_FLAG <= not CONTROL_IN_VALID_FLAG;
			DATA1_STARTADDR_D <= DATA1_STARTADDR;
			DATA1_CEILINGADDR_D <= DATA1_CEILINGADDR;
		end if;
	end if;
end process;

-- reclock with CLK_DDR2G
-- Watch out for convoluted logic. Powerup Reset -> CLK_DDR2G is reset in DDR2 controller -> missing the control change flag after powerup
-- Solution: generate a second CONTROL_CHANGE_PULSE_D2 when SDRAM is ready
RECLOCK_002: process(CLK_DDR2G, DATA1_STARTADDR_D, DATA1_CEILINGADDR_D, DATA1_DELAY)
begin
	if rising_edge(CLK_DDR2G) then
		CONTROL_IN_VALID_FLAG_D <= CONTROL_IN_VALID_FLAG;
		CONTROL_IN_VALID_FLAG_D2 <= CONTROL_IN_VALID_FLAG_D;
		SDRAM_READY_D <= SDRAM_READY_local;
		SDRAM_READY_D2 <= SDRAM_READY_D;
		DATA1_DELAY_D <= DATA1_DELAY;
		WINDOW_SIZE <= DATA1_CEILINGADDR_D2 - DATA1_STARTADDR_D2;
		
		if(CONTROL_IN_VALID_FLAG_D2 /= CONTROL_IN_VALID_FLAG_D) or 
		(SDRAM_READY_D2 /= SDRAM_READY_D) then
			-- configuration has changed
			DATA1_STARTADDR_D2 <= DATA1_STARTADDR_D;
			DATA1_CEILINGADDR_D2 <= DATA1_CEILINGADDR_D;
			CONTROL_CHANGE_PULSE_D2 <= '1';
		else
			CONTROL_CHANGE_PULSE_D2 <= '0';
		end if;
	end if;
end process;



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

-- Input data is discarded until the SDRAM is ready (after 200+us initialization) and DATA_IN is defined
DATA1_IN_VALID2 <= DATA1_IN_VALID when (SDRAM_READY_local = '1') and (DATA1_IN(31) /= 'X') else '0';

-- 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.
		-- Expressed as integer multiple of 32-bit input samples
		if(SYNC_RESET = '1') then
			RAMB1_ADDRA0 <= (others => '0');
		elsif(DATA1_IN_VALID2 = '1') then
			RAMB1_ADDRA0 <= RAMB1_ADDRA0 + 1;
		end if;
		
		-- update copy of write pointer once every 8 clocks
		-- change units to 32/64/128-bit DDR words addresses
		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_IN1: if(NSDRAM_BYTES = 2) generate
	-- Use 1 BRAM to achieve the burst speed required by the SDRAM controller (32-bit per CLK_DDR2G)
	RAMB1_WEA1 <= DATA1_IN_VALID2;
	RAMB1_ADDRA <= RAMB1_ADDRA0(8 downto 0);	-- change units to 32/64/128-bit words address
end generate;
RAMB1_IN2: if(NSDRAM_BYTES = 4) generate
	-- Use 2 BRAMs in parallel to achieve the burst speed required by the SDRAM controller (64-bit per CLK_DDR2G)
	RAMB1_WEA1 <= DATA1_IN_VALID2 when (RAMB1_ADDRA0(0) = '0') else '0';
	RAMB1_WEA2 <= DATA1_IN_VALID2 when (RAMB1_ADDRA0(0) = '1') else '0';
	RAMB1_ADDRA <= RAMB1_ADDRA0(9 downto 1);	-- change units to 32/64/128-bit words address
end generate;
RAMB1_IN3: if(NSDRAM_BYTES = 8) generate
	-- Use 4 BRAMs in parallel to achieve the burst speed required by the SDRAM controller (128-bit per CLK_DDR2G)
	RAMB1_WEA1 <= DATA1_IN_VALID2 when (RAMB1_ADDRA0(1 downto 0) = "00") else '0';
	RAMB1_WEA2 <= DATA1_IN_VALID2 when (RAMB1_ADDRA0(1 downto 0) = "01") else '0';
	RAMB1_WEA3 <= DATA1_IN_VALID2 when (RAMB1_ADDRA0(1 downto 0) = "10") else '0';
	RAMB1_WEA4 <= DATA1_IN_VALID2 when (RAMB1_ADDRA0(1 downto 0) = "11") else '0';
	RAMB1_ADDRA <= RAMB1_ADDRA0(10 downto 2);	-- change units to 32/64/128-bit words address
end generate;


RAMB1_1 : BRAM_DP
generic map (
	DATA_WIDTHA => 32,
	ADDR_WIDTHA => 9,
	DATA_WIDTHB => 32,
	ADDR_WIDTHB => 9
)
port map(
	DOA => open,     
	DOB => RAMB1_DOB1,  
	ADDRA => RAMB1_ADDRA,  
	ADDRB => RAMB1_ADDRB,   
	CLKA => CLK,     
	CLKB => CLK_DDR2G,     
	DIA => DATA1_IN,       
	DIB => x"00000000",       
	WEA => RAMB1_WEA1,       
	WEB => '0'       
);

RAMB1_2: if(NSDRAM_BYTES = 4) or (NSDRAM_BYTES = 8) generate
	RAMB1_2b : BRAM_DP
	generic map (
		DATA_WIDTHA => 32,
		ADDR_WIDTHA => 9,
		DATA_WIDTHB => 32,
		ADDR_WIDTHB => 9
	)
	port map(
		DOA => open,     
		DOB => RAMB1_DOB2,  
		ADDRA => RAMB1_ADDRA,  
		ADDRB => RAMB1_ADDRB,   
		CLKA => CLK,     
		CLKB => CLK_DDR2G,     
		DIA => DATA1_IN,       
		DIB => x"00000000",       
		WEA => RAMB1_WEA2,       
		WEB => '0'       
	);
end generate;

RAMB1_34: if(NSDRAM_BYTES = 8) generate
	RAMB1_3 : BRAM_DP
	generic map (
		DATA_WIDTHA => 32,
		ADDR_WIDTHA => 9,
		DATA_WIDTHB => 32,
		ADDR_WIDTHB => 9
	)
	port map(
		DOA => open,     
		DOB => RAMB1_DOB3,  
		ADDRA => RAMB1_ADDRA,  
		ADDRB => RAMB1_ADDRB,   
		CLKA => CLK,     
		CLKB => CLK_DDR2G,     
		DIA => DATA1_IN,       
		DIB => x"00000000",       
		WEA => RAMB1_WEA3,       
		WEB => '0'       
	);

	RAMB1_4 : BRAM_DP
	generic map (
		DATA_WIDTHA => 32,
		ADDR_WIDTHA => 9,
		DATA_WIDTHB => 32,
		ADDR_WIDTHB => 9
	)
	port map(
		DOA => open,     
		DOB => RAMB1_DOB4,  
		ADDRA => RAMB1_ADDRA,  
		ADDRB => RAMB1_ADDRB,   
		CLKA => CLK,     
		CLKB => CLK_DDR2G,     
		DIA => DATA1_IN,       
		DIB => x"00000000",       
		WEA => RAMB1_WEA4,       
		WEB => '0'       
	);
end generate;

-- reclock RAMB1_ADDRA_D with DDR2 SDRAM clock when safe
RAMB1_WPTRA_002: process(CLK_DDR2G, RAMB1_ADDRA_IS_STABLE, RAMB1_ADDRA_D)
begin
	if rising_edge(CLK_DDR2G) 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 + not(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 <= '1' when (RAMB1_SIZE(8 downto 7) /= "11") else '0';

-- read pointer management
RAMB1_RPTRB_001: process(CLK_DDR2G)
begin
	if rising_edge(CLK_DDR2G) then
		if(SDRAM_READY_local = '0') or (SYNC_RESET2 = '1') then
			-- no transaction until the SDRAM is initialized and ready.
			RAMB1_ADDRB <= (others => '1'); 
		elsif (CONTROLLER_DATA_IN_CTS = '1') and (DATA1INBUF_EMPTY = '0') then
			-- burst read transaction 
			-- Never read past the write pointer 
			RAMB1_ADDRB <= RAMB1_ADDRB + 1;
		end if;
	end if;
end process;


----// DATA1_OUT OUTPUT ELASTIC BUFFERS ---------------------------------------------------


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

		-- units: 32/64/128-bit DDR words addresses
		if(SYNC_RESET2 = '1') then
			RAMB2_ADDRA0 <= (others => '0');
		elsif(CONTROLLER_DATA_OUT_EN = '1') then
			RAMB2_ADDRA0 <= RAMB2_ADDRA0 + 1;
		end if;

		-- update copy of write pointer once every 8 clocks
		-- convert units to 32-bit output samples
		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;

RAMB2_ADDRA1: if(NSDRAM_BYTES = 2) generate
	-- Use 1 BRAM to achieve the burst speed required by the SDRAM controller (32-bit per CLK_DDR2G)
	RAMB2_ADDRA <= RAMB2_ADDRA0;	-- change units to 32-bit words address
end generate;
RAMB2_ADDRA2: if(NSDRAM_BYTES = 4) generate
	-- Use 2 BRAMs in parallel to achieve the burst speed required by the SDRAM controller (64-bit per CLK_DDR2G)
	RAMB2_ADDRA <= RAMB2_ADDRA0(9 downto 0) & "0";	-- change units to 32-bit words address
end generate;
RAMB2_ADDRA3: if(NSDRAM_BYTES = 8) generate
	-- Use 4 BRAMs in parallel to achieve the burst speed required by the SDRAM controller (128-bit per CLK_DDR2G)
	RAMB2_ADDRA <= RAMB2_ADDRA0(8 downto 0) & "00";	-- change units to 32-bit words address
end generate;


RAMB2_1 : BRAM_DP
generic map (
	DATA_WIDTHA => 32,
	ADDR_WIDTHA => 9,
	DATA_WIDTHB => 32,
	ADDR_WIDTHB => 9
)
port map(
	DOA => open,     
	DOB => RAMB2_DOB1,  
	ADDRA => RAMB2_ADDRA0(8 downto 0),  
	ADDRB => RAMB2_ADDRB0,   
	CLKA => CLK_DDR2G,     
	CLKB => CLK,     
	DIA => RAMB2_DIA1,       
	DIB => x"00000000",       
	WEA => CONTROLLER_DATA_OUT_EN,       
	WEB => '0'       
);

RAMB2_2: if(NSDRAM_BYTES = 4) or (NSDRAM_BYTES = 8) generate
	RAMB2_2b : BRAM_DP
	generic map (
		DATA_WIDTHA => 32,
		ADDR_WIDTHA => 9,
		DATA_WIDTHB => 32,
		ADDR_WIDTHB => 9
	)
	port map(
		DOA => open,     
		DOB => RAMB2_DOB2,  
		ADDRA => RAMB2_ADDRA0(8 downto 0),  
		ADDRB => RAMB2_ADDRB0,   
		CLKA => CLK_DDR2G,     
		CLKB => CLK,     
		DIA => RAMB2_DIA2,       
		DIB => x"00000000",       
		WEA => CONTROLLER_DATA_OUT_EN,       
		WEB => '0'       
	);
end generate;

RAMB2_34: if(NSDRAM_BYTES = 8) generate
	RAMB2_3 : BRAM_DP
	generic map (
		DATA_WIDTHA => 32,
		ADDR_WIDTHA => 9,
		DATA_WIDTHB => 32,
		ADDR_WIDTHB => 9
	)
	port map(
		DOA => open,     
		DOB => RAMB2_DOB3,  
		ADDRA => RAMB2_ADDRA0(8 downto 0),  
		ADDRB => RAMB2_ADDRB0,   
		CLKA => CLK_DDR2G,     
		CLKB => CLK,     
		DIA => RAMB2_DIA3,       
		DIB => x"00000000",       
		WEA => CONTROLLER_DATA_OUT_EN,       
		WEB => '0'       
	);

	RAMB2_4 : BRAM_DP
	generic map (
		DATA_WIDTHA => 32,
		ADDR_WIDTHA => 9,
		DATA_WIDTHB => 32,
		ADDR_WIDTHB => 9
	)
	port map(
		DOA => open,     
		DOB => RAMB2_DOB4,  
		ADDRA => RAMB2_ADDRA0(8 downto 0),  
		ADDRB => RAMB2_ADDRB0,   
		CLKA => CLK_DDR2G,     
		CLKB => CLK,     
		DIA => RAMB2_DIA4,       
		DIB => x"00000000",       
		WEA => CONTROLLER_DATA_OUT_EN,       
		WEB => '0'       
	);
end generate;

-- reclock RAMB2_ADDRA_D with CLK clock when safe
RAMB2_WPTRA_002: process(CLK, RAMB2_ADDRA_IS_STABLE, RAMB2_ADDRA_D)
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. Units = 32-bit samples
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;


-- read pointer management
RAMB2_RPTRB_002: process(CLK)
begin
	if rising_edge(CLK) then
		DATA1_OUT_VALID_E2 <= DATA1_OUT_VALID_E3; 	-- it takes one CLK to read data from the RAMB + 1 clock in follow-on mux
		RAMB2_ADDRB_D <= RAMB2_ADDRB;
		
		if(SYNC_RESET = '1') then	-- 12/28/12 AZ
			RAMB2_ADDRB <= (others => '1');
			DATA1_OUT_VALID_E3 <= '0';
		elsif(DATA1_OUT_CTS = '1') and (DATA1_OUT_EMPTY_LOCAL = '0') then
			RAMB2_ADDRB <= RAMB2_ADDRB + 1;
			DATA1_OUT_VALID_E3 <= '1';
		else
			DATA1_OUT_VALID_E3 <= '0';
		end if;
	end if;
end process;

-- convert read addresses representation from 32-bit samples to 32/64/128-bit samples
RAMB2_ADDRB1: if(NSDRAM_BYTES = 2) generate
	RAMB2_ADDRB0 <= RAMB2_ADDRB(8 downto 0);	

	-- mux data from up to 4 RAM blocks into one 32-bit wide data output
	RAMB2_DATA1_OUT_002: process(CLK)
	begin
		if rising_edge(CLK) then
			DATA1_OUT_VALID <= DATA1_OUT_VALID_E2;
			if(DATA1_OUT_VALID_E2 = '1') then
				DATA1_OUT <= RAMB2_DOB1;
			end if;
		end if;
	end process;
end generate;
RAMB2_ADDRB2: if(NSDRAM_BYTES = 4) generate
	-- Use 2 BRAMs in parallel 
	RAMB2_ADDRB0 <= RAMB2_ADDRB(9 downto 1);	

	-- mux data from up to 4 RAM blocks into one 32-bit wide data output
	RAMB2_DATA1_OUT_002: process(CLK)
	begin
		if rising_edge(CLK) then
			DATA1_OUT_VALID_E <= DATA1_OUT_VALID_E2;
			DATA1_OUT_VALID <= DATA1_OUT_VALID_E;
			RAMB2_ADDRB_D2 <= RAMB2_ADDRB_D;

			-- reclock RAMB output
			if(DATA1_OUT_VALID_E2 = '1') then
				RAMB2_DOB1_D <= RAMB2_DOB1;
				RAMB2_DOB2_D <= RAMB2_DOB2;
			end if;
			-- mux
			if(DATA1_OUT_VALID_E = '1') then
				case RAMB2_ADDRB_D2(0 downto 0) is
					when "0" => DATA1_OUT <= RAMB2_DOB1_D;
					when others => DATA1_OUT <= RAMB2_DOB2_D;
				end case;
			end if;
		end if;
	end process;
end generate;
RAMB2_ADDRB3: if(NSDRAM_BYTES = 8) generate
	-- Use 4 BRAMs in parallel 
	RAMB2_ADDRB0 <= RAMB2_ADDRB(10 downto 2);	
	
	-- mux data from up to 4 RAM blocks into one 32-bit wide data output
	RAMB2_DATA1_OUT_002: process(CLK)
	begin
		if rising_edge(CLK) then
			DATA1_OUT_VALID_E <= DATA1_OUT_VALID_E2;
			DATA1_OUT_VALID <= DATA1_OUT_VALID_E;
			RAMB2_ADDRB_D2 <= RAMB2_ADDRB_D;

			-- reclock RAMB output
			if(DATA1_OUT_VALID_E2 = '1') then
				RAMB2_DOB1_D <= RAMB2_DOB1;
				RAMB2_DOB2_D <= RAMB2_DOB2;
				RAMB2_DOB3_D <= RAMB2_DOB3;
				RAMB2_DOB4_D <= RAMB2_DOB4;
			end if;
			-- mux
			if(DATA1_OUT_VALID_E = '1') then
				case RAMB2_ADDRB_D2(1 downto 0) is
					when "00" => DATA1_OUT <= RAMB2_DOB1_D;
					when "01" => DATA1_OUT <= RAMB2_DOB2_D;
					when "10" => DATA1_OUT <= RAMB2_DOB3_D;
					when others => DATA1_OUT <= RAMB2_DOB4_D;
				end case;
			end if;
		end if;
	end process;
end generate;

--// TRANSACTION SCHEDULER ---------------------------------------------------
-- state 0: idle
-- state 1: request 1st BL=4 write burst
-- state 2: request 2nd BL=4 write burst
-- state 3: request 3rd BL=4 write burst
-- state 6: request 1st BL=4 read burst
-- state 7: request 2nd BL=4 read burst
-- state 8: request 3rd BL=4 read burst

EVENT1 <= '1' when (STATE = 0) and (RAMB1_SIZE >= 6)  else '0';
	-- burst write trigger event. 1/3 burst
	-- enough data for at least three BL=4 bursts (6 DDR words, 24 32-bit samples)
EVENT2 <= '1' when (STATE = 1) and (TRANSACTION_REQ_ACK = '1')  else '0';
	-- burst write trigger event. 2/3 burst
EVENT3 <= '1' when (STATE = 2) and (TRANSACTION_REQ_ACK = '1')  else '0';
	-- burst write trigger event. 3/3 burst
EVENT4 <= '1' when (STATE = 3) and (TRANSACTION_REQ_ACK = '1')  else '0';
	-- burst read trigger event. 1/3 burst
EVENT5 <= '1' when (STATE = 6) and (TRANSACTION_REQ_ACK = '1')  else '0';
	-- burst read trigger event. 2/3 burst
EVENT6 <= '1' when (STATE = 7) and (TRANSACTION_REQ_ACK = '1') else '0';
	-- burst read trigger event. 3/3 burst
EVENT7 <= '1' when (STATE = 8) and (TRANSACTION_REQ_ACK = '1') else '0';
	-- read complete. Back to idle.
SCHEDULER_001: process(CLK_DDR2G)
begin
	if rising_edge(CLK_DDR2G) then
		if(SDRAM_READY_local = '0') or (SYNC_RESET2 = '1') then
			-- no transaction until the SDRAM is initialized and ready.
			STATE <= conv_std_logic_vector(0,STATE'LENGTH);  
			TRANSACTION_REQ <= "00";
			TRANSACTION_REQ_NO <= (others => '0');
			TIMER1 <= 0;	-- expired
		elsif (EVENT1 = '1') then
			-- enough data for at least two BL=4 bursts (4 DDR words, 16 32-bit samples). define burst start address
			-- Initiate an SDRAM write transaction
			STATE <= conv_std_logic_vector(1,STATE'LENGTH);  
			TRANSACTION_REQ <= "10";	-- 10 = burst write
			TRANSACTION_REQ_NO <= TRANSACTION_REQ_NO + 1;
			BURST_START_ADDR <= WBURST_START_ADDR;	-- burst write start address
			TIMER1 <= TIMER1_TIMEOUT;
		elsif (EVENT2 = '1') then
			-- 1st burst write transaction request acknowledged.
			-- queue 2nd burst write transaction
			TRANSACTION_REQ_NO <= TRANSACTION_REQ_NO + 1;
			BURST_START_ADDR <= WBURST_START_ADDR;	-- burst write start address
			STATE <= conv_std_logic_vector(2,STATE'LENGTH);  
			TIMER1 <= TIMER1_TIMEOUT;
		elsif (EVENT3 = '1') then
			-- 2nd burst write transaction request acknowledged.
			-- queue 3rd burst write transaction
			TRANSACTION_REQ_NO <= TRANSACTION_REQ_NO + 1;
			BURST_START_ADDR <= WBURST_START_ADDR;	-- burst write start address
			STATE <= conv_std_logic_vector(3,STATE'LENGTH);  
			TIMER1 <= TIMER1_TIMEOUT;
		elsif (EVENT4 = '1') then
			-- 3rd burst write transaction request acknowledged.
			-- start 1st burst read transaction
			STATE <= conv_std_logic_vector(6,STATE'LENGTH); 
			TRANSACTION_REQ <= "01";	-- 01 = burst read
			TRANSACTION_REQ_NO <= TRANSACTION_REQ_NO + 1;
			BURST_START_ADDR <= RBURST_START_ADDR;	-- burst read start address
			TIMER1 <= TIMER1_TIMEOUT;
		elsif (EVENT5 = '1') then
			-- 1st burst read transaction request acknowledged.
			STATE <= conv_std_logic_vector(7,STATE'LENGTH); 
			-- queue next burst read transaction
			TRANSACTION_REQ_NO <= TRANSACTION_REQ_NO + 1;
			BURST_START_ADDR <= RBURST_START_ADDR;	-- burst read start address
			TIMER1 <= TIMER1_TIMEOUT;
		elsif (EVENT6 = '1') then
			-- 2nd burst read transaction request acknowledged.
			STATE <= conv_std_logic_vector(8,STATE'LENGTH); 
			-- queue next burst read transaction
			TRANSACTION_REQ_NO <= TRANSACTION_REQ_NO + 1;
			BURST_START_ADDR <= RBURST_START_ADDR;	-- burst read start address
			TIMER1 <= TIMER1_TIMEOUT;
		elsif (EVENT7 = '1') then
			-- 3rd burst read transaction request acknowledged. Back to idle
			STATE <= conv_std_logic_vector(0,STATE'LENGTH); 
			TRANSACTION_REQ <= "00";
			TIMER1 <= 0;	-- expired
		elsif(TIMER1 = 1) then
			-- Abnormal timer expiration. Back to idle
			STATE <= conv_std_logic_vector(0,STATE'LENGTH); 
			TRANSACTION_REQ <= "00";
			TIMER1 <= 0;	-- expired
		elsif(TIMER1 > 0) then
			TIMER1 <= TIMER1 - 1;
		end if;	
	end if;
end process;

-- 4-word write burst start address in SDRAM 
-- Looking ahead: increment as soon as we are sending a burst write request
WBURST_START_ADDR_PLUS4 <= WBURST_START_ADDR + 4;

WBURST_START_ADDR_GEN: process(CLK_DDR2G)
begin
	if rising_edge(CLK_DDR2G) then
		if(SYNC_RESET2 = '1') or (CONTROL_CHANGE_PULSE_D2 = '1') then
			WBURST_START_ADDR <= DATA1_STARTADDR_D2;
		elsif (EVENT1 = '1') or (EVENT2 = '1') or (EVENT3 = '1') then
			-- burst write transaction request event.
			if (WBURST_START_ADDR_PLUS4 >= DATA1_CEILINGADDR_D2) then
				-- continuous mode. reached the ceiling address -> rewind to start address.
				WBURST_START_ADDR <= DATA1_STARTADDR_D2;
			else
				-- autoincrement
				WBURST_START_ADDR <= WBURST_START_ADDR_PLUS4;  -- Burst length BL = 4;
			end if;
		end if; 
	end if;
end process;
DATA1_IN_ADDR <= WBURST_START_ADDR;	-- for monitoring purposes

-- Looking ahead: increment as soon as we are sending a burst read request
RBURST_START_ADDR_PLUS4 <= RBURST_START_ADDR + 4;
RBURST_START_ADDR_GEN: process(CLK_DDR2G)
begin
	if rising_edge(CLK_DDR2G) then
		if (EVENT1 = '1') then
			-- get ready for reading (while writing). step 1: position read pointer relative to the write pointer
			RBURST_START_ADDR <= WBURST_START_ADDR - DATA1_DELAY_D;
		elsif (EVENT2 = '1') and (RBURST_START_ADDR(31) = '1') then
			-- get ready for reading (while writing). step 2: negative addr. add modulo.
			RBURST_START_ADDR <= RBURST_START_ADDR + WINDOW_SIZE;
		elsif (EVENT3 = '1') and (RBURST_START_ADDR < DATA1_STARTADDR_D2) then
			-- get ready for reading (while writing). step 3: read pointer is below floor address. add modulo
			RBURST_START_ADDR <= RBURST_START_ADDR + WINDOW_SIZE;
		elsif (EVENT4 = '1') or (EVENT5 = '1')  then
			-- burst read transaction request event.
			if (RBURST_START_ADDR_PLUS4 >= DATA1_CEILINGADDR_D2) then
				-- continuous mode. reached the ceiling address -> rewind to start address.
				RBURST_START_ADDR <= DATA1_STARTADDR_D2;
			else
				-- autoincrement
				RBURST_START_ADDR <= RBURST_START_ADDR_PLUS4;  -- Burst length BL = 4;
			end if;
		end if;
	end if;
end process;
DATA1_OUT_ADDR <= RBURST_START_ADDR;	-- for monitoring purposes


--//------ SDRAM CONTROLLER ------------------------------------
CDIN_002: if(NSDRAM_BYTES = 2) generate
	CDIN_002b: process(RAMB1_DOB1, CONTROLLER_DATA_OUT)
	begin
		CONTROLLER_DATA_IN(31 downto 0) <= RAMB1_DOB1;
		RAMB2_DIA1 <= CONTROLLER_DATA_OUT(31 downto 0);
	end process;
end generate;
CDIN_003: if(NSDRAM_BYTES = 4) generate
	CDIN_003b: process(RAMB1_DOB1, RAMB1_DOB2, CONTROLLER_DATA_OUT)
	begin
		CONTROLLER_DATA_IN(31 downto 0) <= RAMB1_DOB1;
		CONTROLLER_DATA_IN(63 downto 32) <= RAMB1_DOB2;
		RAMB2_DIA1 <= CONTROLLER_DATA_OUT(31 downto 0);
		RAMB2_DIA2 <= CONTROLLER_DATA_OUT(63 downto 32);
	end process;
end generate;
CDIN_004: if(NSDRAM_BYTES = 8) generate
	CDIN_004b: process(RAMB1_DOB1, RAMB1_DOB2, RAMB1_DOB3, RAMB1_DOB4, CONTROLLER_DATA_OUT)
	begin
		CONTROLLER_DATA_IN(31 downto 0) <= RAMB1_DOB1;
		CONTROLLER_DATA_IN(63 downto 32) <= RAMB1_DOB2;
		CONTROLLER_DATA_IN(95 downto 64) <= RAMB1_DOB3;
		CONTROLLER_DATA_IN(127 downto 96) <= RAMB1_DOB4;
		RAMB2_DIA1 <= CONTROLLER_DATA_OUT(31 downto 0);
		RAMB2_DIA2 <= CONTROLLER_DATA_OUT(63 downto 32);
		RAMB2_DIA3 <= CONTROLLER_DATA_OUT(95 downto 64);
		RAMB2_DIA4 <= CONTROLLER_DATA_OUT(127 downto 96);
	end process;
end generate;


Inst_DDR2_SDRAM_CONTROLLER: DDR2_SDRAM_CONTROLLER 
generic map(
	PLATFORM => PLATFORM,
	NSDRAM_BYTES => NSDRAM_BYTES,
	NCLKS => NCLKS,
	ADDRESS_MAP => ADDRESS_MAP,
	CLOCK_CYCLES => CLOCK_CYCLES,
	DDR2_CLK_FREQ => DDR2_CLK_FREQ,	
	RTDELAY_COARSE => RTDELAY_COARSE
)
PORT MAP(	---------------------------------- USER SIDE
	CLK_DDR2_REF => CLK_DDR2_REF,
	ASYNC_RESET => ASYNC_RESET,	-- don't use SYNC_RESET2 here (circular logic, would block CLK_DDR2G )
	CLK_DDR2G_OUT => CLK_DDR2G,
	START_ADDR => BURST_START_ADDR,
	TRANSACTION_REQ => TRANSACTION_REQ,
	TRANSACTION_REQ_NO => TRANSACTION_REQ_NO,
	TRANSACTION_REQ_ACK => TRANSACTION_REQ_ACK,
	DATA_IN => CONTROLLER_DATA_IN,
	DATA_IN_CTS => CONTROLLER_DATA_IN_CTS,
	DATA_OUT => CONTROLLER_DATA_OUT,
	DATA_OUT_EN => CONTROLLER_DATA_OUT_EN,
	SELF_REFRESH_REQ => '0',
	SDRAM_DQ => SDRAM_DQ,  ------------------------ SDRAM SIDE
	SDRAM_DQS_P => SDRAM_DQS_P,
	SDRAM_DQS_N => SDRAM_DQS_N,
	SDRAM_ODT => SDRAM_ODT,
	SDRAM_CK_P => SDRAM_CK_P,
	SDRAM_CK_N => SDRAM_CK_N,
	SDRAM_CKE => SDRAM_CKE,
	SDRAM_CASN => SDRAM_CASN,
	SDRAM_RASN => SDRAM_RASN,
	SDRAM_WEN => SDRAM_WEN,
	SDRAM_SN => SDRAM_SN,	
	SDRAM_DM => SDRAM_DM,
	SDRAM_BA => SDRAM_BA,
	SDRAM_A => SDRAM_A,
	SDRAM_READY => SDRAM_READY_local,
	SDRAM_DQ_DIR => SDRAM_DQ_DIR,
	SDRAM_DQS_DIR => SDRAM_DQS_DIR,
	SDRAM_TP => open
);

-- monitor SDRAM readiness
SDRAM_READY <= SDRAM_READY_local;


--// TEST POINTS ---------
SDRAM_TP(1) <= SDRAM_READY_local;
SDRAM_TP(2) <= WBURST_START_ADDR(2);
SDRAM_TP(3) <= RBURST_START_ADDR(2);
SDRAM_TP(4) <= WBURST_START_ADDR(8);
SDRAM_TP(5) <= RBURST_START_ADDR(8);
--SDRAM_TP(6) <= '1' when (STATE = 0) else '0';
--SDRAM_TP(7) <= '1' when (STATE = 6) else '0';
--SDRAM_TP(8) <= '1' when (STATE = 7) else '0';
--SDRAM_TP(9) <= EVENT1;

end Behavioral;

