----------------------------------------------------------------------------------
-- Company:         Alpha-Data Parallel Systems Ltd.
-- Engineer:        AS
--
-- Create Date:     14:26:00 09/11/2006
-- Design Name:     DDR2 SDRAM Aplha Data Wrapper
-- Module Name:     ddr2_ad_wrap_small - Behavioral
-- Project Name:
-- Target Devices:  Virtex 4
-- Tool versions:
-- Description:     Provides a 64 bit user interface to the DDR2 SDRAMS (physically 32 bits).
--                  Optimizes memory read and write requests for bursting DDR2 memory
--                  by determining if the input addresses and commands are sequential. When
--                  burst are possible, this wrapper combines 2 read or 2 write requests
--                  into a single DDR2 command.  The DDR2 commands are then passed to the
--                  Xilinx (Mig) generated DDR2 controller (64 bits).  The controller uses
--                  the Direct clocking scheme for performance at 200MHz.

--                  For single writes (64 bits),  
--                  the wrapper masks the upper 64 bits passed to the DDR2 controller.
--                  For all reads, this wrapper has a read command FIFO to keep track of
--                  the read request (2 combined, or single). When the read data is received
--                  from the DDR2 controller, the wrapper will output the 64 bit reads according
--                  to the number of read commands that were combined (1 or 2).
--
--                  When flush is asserted with r, causes un-processed read commands to be returned with
--                  the qv flag deasserted. This is typically tied to lblast and terminates the
--                  read prefetch.
--
--                  Instantiates modified Mig Controller (mem_interface_small_top)
--                  Instantiates asynchronous FIFOs for the user interface

--
-- Revision:
-- 
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.std_logic_misc.all;
use IEEE.numeric_std.all;

library UNISIM;
use UNISIM.VComponents.all;

entity ddr2_ad_wrap_small is
  generic (
    use_chipscope : in boolean := false);
  port (
    -- User Interface --
    clk              : in    std_logic;
    flush            : in    std_logic;
    w                : in    std_logic;
    r                : in    std_logic;
    a                : in    std_logic_vector (27 downto 0);
    d                : in    std_logic_vector (63 downto 0);
    dm               : in    std_logic_vector (7 downto 0);
    q                : out   std_logic_vector (63 downto 0);
    qv               : out   std_logic;
    rd_en            : in    std_logic;
    rd_ready         : out   std_logic;
    full             : out   std_logic;
    empty            : out   std_logic;
    error            : out   std_logic;
    -- DDR2 Interface --
    cntrl_DDR2_DQ    : inout std_logic_vector(31 downto 0);
    cntrl_DDR2_A     : out   std_logic_vector(12 downto 0);
    cntrl_DDR2_BA    : out   std_logic_vector(2 downto 0);
    cntrl_DDR2_RAS_N : out   std_logic;
    cntrl_DDR2_CAS_N : out   std_logic;
    cntrl_DDR2_WE_N  : out   std_logic;
    cntrl_DDR2_CS_N  : out   std_logic;
    cntrl_DDR2_ODT   : out   std_logic;
    cntrl_DDR2_CKE   : out   std_logic;
    cntrl_DDR2_DM    : out   std_logic_vector(3 downto 0);
    cntrl_DDR2_DQS   : inout std_logic_vector(3 downto 0);
    cntrl_DDR2_DQS_N : inout std_logic_vector(3 downto 0);
    cntrl_DDR2_CK    : out   std_logic_vector(1 downto 0);
    cntrl_DDR2_CK_N  : out   std_logic_vector(1 downto 0);
    -- Infrastructure Interface --
    CNTL_CLK         : in    std_logic;
    CNTL_CLK90       : in    std_logic;
    CNTL_CLK_ID1     : in    std_logic;
    CNTL_CLK_ID2     : in    std_logic;
    CNTL_CLK_ID3     : in    std_logic;
    CNTL_CLK_ID4     : in    std_logic;
    SYS_RST          : in    std_logic;
    SYS_RST_90       : in    std_logic;
    idelay_ctrl_rdy  : in    std_logic;
    SYS_RST_ID       : in    std_logic;
    control1         : in    std_logic_vector(35 downto 0);
    control2         : in    std_logic_vector(35 downto 0);
    status           : out   std_logic_vector(31 downto 0)
    );
end ddr2_ad_wrap_small;
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
architecture Behavioral of ddr2_ad_wrap_small is

-- mem_interface_small_top signals --
  signal WDF_ALMOST_FULL    : std_logic;
  signal WDF_ALMOST_FULL_r  : std_logic;
  signal WAF_ALMOST_FULL    : std_logic;
  signal WAF_ALMOST_FULL_r  : std_logic;
  signal READ_DATA_VALID    : std_logic;
  signal APP_WDF_WREN       : std_logic;
  signal APP_WAF_WREN       : std_logic;
  signal APP_WAF_ADDR       : std_logic_vector(35 downto 0);
  signal READ_DATA_FIFO_OUT : std_logic_vector(63 downto 0);
  signal APP_WDF_DATA       : std_logic_vector(63 downto 0);
  signal APP_MASK_DATA      : std_logic_vector(7 downto 0);

-- ad_wrap signals --
  signal ext_a,ext_a1,ext_a2          : std_logic_vector(31 downto 0);
  signal cmd_queue_rst  : std_logic;
  signal qv_i           : std_logic;
  signal clear_counter  : std_logic_vector(11 downto 0);
  signal rd_cmd_count   : std_logic_vector(11 downto 0);
  signal cmd,cmd1,cmd2            : std_logic_vector(3 downto 0);
  signal wait_read_data : std_logic;
  signal usr_af_wren,usr_af_wren1,usr_af_wren2    : std_logic;

  type pipereg1 is array(3 downto 0) of std_logic_vector(27 downto 0);
  type pipereg2 is array(3 downto 0) of std_logic_vector(3 downto 0);

  signal usr_addr    : pipereg1;
  signal usr_addr_in : std_logic_vector(27 downto 0);
  signal usr_cmd     : pipereg2;
  signal usr_cmd_in  : std_logic_vector(3 downto 0);
  signal cmd_control : std_logic_vector(3 downto 0);
  signal usr_data_r  : std_logic_vector(63 downto 0);
  signal usr_data_in : std_logic_vector(63 downto 0);
  signal usr_dm_r    : std_logic_vector(7 downto 0);
  signal usr_dm_in   : std_logic_vector(7 downto 0);

  type state_type is (st1_cmd_adv, st2_read64, st3_read64_hold, st4_read128, st5_read128_hold,
                      st6_write64, st7_write64_hold, st8_write128, st9_write128_hold,
                      st10_ready);

  signal state, next_state : state_type;
  signal hold              : std_logic;
  signal SM_mask_data_i    : std_logic_vector(7 downto 0);
  signal same_block        : std_logic;
  signal hold_command      : std_logic_vector(3 downto 0);

  signal usr_af_almost_full   : std_logic;
  signal usr_af_almost_full_r : std_logic;
  signal usr_AF_RDEN          : std_logic;

  signal pipeline_en   : std_logic;
  signal pipeline_en_i : std_logic;

  signal usr_AF_empty          : std_logic;
  signal usr_AF_almost_empty   : std_logic;
  signal usr_AF_empty_r        : std_logic;
  signal usr_wdf_almost_full   : std_logic;
  signal usr_wdf_almost_full_r : std_logic;
  signal usr_WDF_RDEN          : std_logic;
  signal wdf_rden_ctrl         : std_logic;

  signal App_WDF_wren_i : std_logic;
  signal App_WAF_wren_i : std_logic;

  signal cmdF_rd_cmd          : std_logic;
  signal cmdF_rd_cmd_i        : std_logic;
  signal usr_cmdF_wren        : std_logic;
  signal usr_cmdF_wren_i      : std_logic;
  signal read_cmd_fifo_full   : std_logic;
  signal read_cmd_fifo_full_r : std_logic;

  signal rd_burst_data         : std_logic;
  signal empty_pipe            : std_logic;
  signal empty_done            : std_logic;
  signal empty_done_v          : std_logic_vector(2 downto 0);
  signal usr_rdf_almost_full   : std_logic;
  signal usr_rdf_almost_full_r : std_logic;

  signal usr_RDF_wren  : std_logic;
  signal usr_RDF_rden  : std_logic;
  signal usr_cmdF_rden : std_logic;
  signal usr_rdf_empty : std_logic_vector(1 downto 0);

  signal cmdF_rd_cmd_dly   : std_logic;
  signal usr_RDF_Valid     : std_logic;
  signal RDF_cycle_1       : std_logic;
  signal usr_rdf_data      : std_logic_vector(63 downto 0);
  signal read_data_valid_r : std_logic;
  signal READ_DATA0        : std_logic_vector(63 downto 0);
  signal unconnected1      : std_logic_vector (31 downto 0);
  signal state_vec         : std_logic_vector (3 downto 0);

--------------------------------------------------------------------------
-- Component declarations --
--------------------------------------------------------------------------
  component mem_interface_small_top_0
    generic (use_chipscope : in boolean);
    port (
      clk_0             : in std_logic;
      clk_90            : in std_logic;
      clk_50            : in std_logic;
      ref_clk           : in std_logic;
      sys_rst           : in std_logic;
      sys_rst90         : in std_logic;
      sys_rst_ref_clk_1 : in std_logic;

      idelay_ctrl_rdy : in    std_logic;
      DDR2_RAS_N      : out   std_logic;
      DDR2_CAS_N      : out   std_logic;
      DDR2_WE_N       : out   std_logic;
      DDR2_ODT        : out   std_logic_vector(0 downto 0);
      DDR2_CKE        : out   std_logic_vector(0 downto 0);
      DDR2_CS_N       : out   std_logic_vector(0 downto 0);
      DDR2_DQ         : inout std_logic_vector(31 downto 0);
      DDR2_DQS        : inout std_logic_vector(3 downto 0);
      DDR2_DQS_N      : inout std_logic_vector(3 downto 0);
      DDR2_DM         : out   std_logic_vector(3 downto 0);

      DDR2_CK            : out std_logic_vector(1 downto 0);
      DDR2_CK_N          : out std_logic_vector(1 downto 0);
      DDR2_BA            : out std_logic_vector(2 downto 0);
      DDR2_A             : out std_logic_vector(12 downto 0);
      WDF_ALMOST_FULL    : out std_logic;
      AF_ALMOST_FULL     : out std_logic;
      BURST_LENGTH       : out std_logic_vector(2 downto 0);
      READ_DATA_VALID    : out std_logic;
      READ_DATA_FIFO_OUT : out std_logic_vector(63 downto 0);
      APP_AF_ADDR        : in  std_logic_vector(35 downto 0);
      APP_AF_WREN        : in  std_logic;
      APP_WDF_DATA       : in  std_logic_vector(63 downto 0);
      APP_MASK_DATA      : in  std_logic_vector(7 downto 0);
      APP_WDF_WREN       : in  std_logic;
      CLK_TB             : out std_logic;
      RESET_TB           : out std_logic;
      chip_scope_control : in  std_logic_vector(35 downto 0);
      error              : out std_logic
      );
  end component;

-- FIFO component declarations, generated using fifo workaround perl script with FIFO16 patch --

-- 36 bit by 512 deep FIFO16 primitive based FIFO, asynchronous, first-word fall through, 
-- almostfull threshold = 15, rdclk > wrclk 
  component async_fifo16
    port (
      ALMOSTEMPTY : out std_logic;  -- Set high when 5 locations are left to output
      ALMOSTFULL  : out std_logic;  -- Set high when 15 empty locations remain open
      DO          : out std_logic_vector(31 downto 0);
      DOP         : out std_logic_vector(3 downto 0);
      EMPTY       : out std_logic;
      FULL        : out std_logic;
      RDCOUNT     : out std_logic_vector(11 downto 0);
      RDERR       : out std_logic;
      WRCOUNT     : out std_logic_vector(11 downto 0);
      WRERR       : out std_logic;
      DI          : in  std_logic_vector(31 downto 0);
      DIP         : in  std_logic_vector(3 downto 0);
      RDCLK       : in  std_logic;
      RDEN        : in  std_logic;
      RST         : in  std_logic;
      WRCLK       : in  std_logic;
      WREN        : in  std_logic
      ); 
  end component;

-- 36 bit by 512 deep FIFO16 primitive based FIFO, asynchronous, NON first-word fall through, 
-- almostfull threshold = 15, rdclk > wrclk
  component async_fifo16_wdf
    port (
      ALMOSTEMPTY : out std_logic;
      ALMOSTFULL  : out std_logic;  -- Set high when 15 empty locations remain open
      DO          : out std_logic_vector(31 downto 0);
      DOP         : out std_logic_vector(3 downto 0);
      EMPTY       : out std_logic;
      FULL        : out std_logic;
      RDCOUNT     : out std_logic_vector(11 downto 0);
      RDERR       : out std_logic;
      WRCOUNT     : out std_logic_vector(11 downto 0);
      WRERR       : out std_logic;
      DI          : in  std_logic_vector(31 downto 0);
      DIP         : in  std_logic_vector(3 downto 0);
      RDCLK       : in  std_logic;
      RDEN        : in  std_logic;
      RST         : in  std_logic;
      WRCLK       : in  std_logic;
      WREN        : in  std_logic
      ); 
  end component;

-- 36 bit by 512 deep FIFO16 primitive based FIFO, asynchronous, non first-word fall through, rdclk < wrclk
  component async_fifo_rd
    port (
      ALMOSTEMPTY : out std_logic;  -- Set high when 15 locations are left to output
      ALMOSTFULL  : out std_logic;  -- Set high when 288 empty locations remain open
      DO          : out std_logic_vector(31 downto 0);
      DOP         : out std_logic_vector(3 downto 0);
      EMPTY       : out std_logic;
      FULL        : out std_logic;
      RDCOUNT     : out std_logic_vector(11 downto 0);
      RDERR       : out std_logic;
      WRCOUNT     : out std_logic_vector(11 downto 0);
      WRERR       : out std_logic;
      DI          : in  std_logic_vector(31 downto 0);
      DIP         : in  std_logic_vector(3 downto 0);
      RDCLK       : in  std_logic;
      RDEN        : in  std_logic;
      RST         : in  std_logic;
      WRCLK       : in  std_logic;
      WREN        : in  std_logic); 
  end component;

-- 1 Bit by 512 Deep, Distributed RAM based FIFO, asynchronous, first-word fall through
-- Prog full set to 16 entries left open
  component read_cmd_store_fifo
    port (
      din       : in  std_logic_vector(0 downto 0);
      rd_clk    : in  std_logic;
      rd_en     : in  std_logic;
      rst       : in  std_logic;
      wr_clk    : in  std_logic;
      wr_en     : in  std_logic;
      prog_full : out std_logic;
      dout      : out std_logic_vector(0 downto 0);
      empty     : out std_logic;
      full      : out std_logic);
  end component;


-- ChipScope --
  signal trig0 : std_logic_vector (254 downto 0);

  component ila
    port(
      control : in std_logic_vector(35 downto 0);
      clk     : in std_logic;
      trig0   : in std_logic_vector(254 downto 0));
  end component;

------------------------------------------------------------------------------
------------------------------------------------------------------------------

  signal fifo_full : std_logic_vector(5 downto 0);
  signal overflow  : std_logic_vector(5 downto 0);
  component sync_fifo_deep
    generic (
      width : natural := 2);
    port (
      clk     : in  std_logic;
      rst     : in  std_logic;
      wadv    : in  std_logic;
      wdata   : in  std_logic_vector(width-1 downto 0);
      wnfull  : out std_logic;
      wfull   : out std_logic;
      hfull   : out std_logic;
      radv    : in  std_logic;
      rdata   : out std_logic_vector(width-1 downto 0);
      rdw_out : out std_logic_vector(width-1 downto 0);
      rempty  : out std_logic;
      rnempty : out std_logic
      );
  end component;

  component af_fifo
    port (
      din          : in  std_logic_vector(35 downto 0);
      rd_clk       : in  std_logic;
      rd_en        : in  std_logic;
      rst          : in  std_logic;
      wr_clk       : in  std_logic;
      wr_en        : in  std_logic;
      dout         : out std_logic_vector(35 downto 0);
      empty        : out std_logic;
      almost_empty : out std_logic;
      full         : out std_logic;
      prog_full    : out std_logic);
  end component;

  component async_fifo64
    port (
      din       : in  std_logic_vector(63 downto 0);
      rd_clk    : in  std_logic;
      rd_en     : in  std_logic;
      rst       : in  std_logic;
      wr_clk    : in  std_logic;
      wr_en     : in  std_logic;
      dout      : out std_logic_vector(63 downto 0);
      empty     : out std_logic;
      prog_full : out std_logic;
      full      : out std_logic);
  end component;
  signal full_count : std_logic_vector(4 downto 0) := "00000";

  signal af_wcount, af_rcount, rf_rcount : std_logic_vector(7 downto 0);

begin

--
-- Decode the command inputs r and w, and set the user interface full flag
--


--    cmd <= "0100" when (w AND (NOT r)) = '1' else
--           "0101" when (r AND (NOT w)) = '1' else
--           "0000";
--    usr_af_wren <= '1' when (w OR r) = '1' else '0';

  empty <= usr_af_empty;
  
  fifo_flag_reg : process (clk)
  begin
    if (clk'event and clk = '1') then
      usr_af_almost_full_r  <= usr_af_almost_full;
      usr_wdf_almost_full_r <= usr_wdf_almost_full;
      full                  <= usr_af_almost_full_r or usr_wdf_almost_full_r or OR_reduce(full_count);

      if usr_af_almost_full = '1' or usr_wdf_almost_full = '1' then
        full_count <= "11111";
      elsif OR_reduce(full_count) = '1' then
        full_count <= full_count-1;
      end if;

      if (w and (not r)) = '1' then
        cmd1 <= "0100";
      elsif (r and (not w)) = '1' then
        cmd1 <= "0101";
      else
        cmd1 <= "0000";
      end if;
      if (w or r) = '1' then
        usr_af_wren1 <= '1';
      else
        usr_af_wren1 <= '0';
      end if;
      ext_a1 <= EXT(a, 32);
      cmd <= cmd1;
      usr_af_wren <= usr_af_wren1;
      ext_a <= ext_a1;
      cmd2 <= cmd1;
      usr_af_wren2 <= usr_af_wren1;
      ext_a2 <= ext_a1;
    end if;
  end process;


  --
  -- User interface read data fifo control signal, always active when not in reset or empty
  --  2 parallel fifos hold the 64 bits of data, in order to prevent the data falling through 1
  --  before the other, both empty flags must be '0' before a read is performed.
  --

  rd_ready     <= '1'   when usr_rdf_empty = "00" and SYS_RST = '0' else '0';
  usr_RDF_rden <= rd_en when usr_rdf_empty = "00"                   else '0';

--
-- User Interface, command queue reset. Causes read prefetch data to not be valid after flush is asserted.
--
  qv_proc : process (clk)
  begin
    if (clk'event and clk = '1') then
      if sys_rst = '1' then
        qv_i           <= '0';
        cmd_queue_rst  <= '0';
        wait_read_data <= '0';
      else
        qv_i <= usr_RDF_rden;

        if flush = '1' and r = '1' then
          cmd_queue_rst  <= '1';
          wait_read_data <= '1';
        elsif cmd_queue_rst = '1' and r = '1' then
          cmd_queue_rst <= cmd_queue_rst;
        else
          cmd_queue_rst <= '0';

          if cmd_queue_rst = '0' and clear_counter = x"000" then
            wait_read_data <= '0';
          end if;
        end if;
      end if;
    end if;
  end process;

  qv <= qv_i when wait_read_data = '0' else '0';

--
-- Read Command counter, to determine the number of prefetched read commands to ignore
-- when flush is asserted
--

  RD_COUNT : process (clk)
  begin
    if (clk'event and clk = '1') then
      if SYS_RST = '1' then
        clear_counter <= (others => '0');
        rd_cmd_count  <= (others => '0');
      else
        if r = '1' then
          if usr_RDF_rden = '1' then
            rd_cmd_count <= rd_cmd_count;
          else
            rd_cmd_count <= rd_cmd_count + 1;
          end if;
        elsif usr_RDF_rden = '1' and rd_cmd_count /= x"000" then
          rd_cmd_count <= rd_cmd_count - 1;
        else
          rd_cmd_count <= rd_cmd_count;
        end if;

        if cmd_queue_rst = '1' then
          if usr_RDF_rden = '1' then
            clear_counter <= rd_cmd_count - 1;
          else
            clear_counter <= rd_cmd_count;
          end if;
        elsif usr_RDF_rden = '1' and wait_read_data = '1' and clear_counter /= x"000" then
          clear_counter <= clear_counter - 1;
        end if;
      end if;
    end if;
  end process;

  -- 
  -- Connect the Command, Address, Data and DataMask to the Memory interface 
  --

  App_WDF_wren  <= App_WDF_wren_i;
  APP_WAF_WREN  <= App_WAF_wren_i;
  APP_WAF_ADDR  <= usr_cmd(3) & "00000" & usr_addr(3)(27 downto 12) & '0' & usr_addr(3)(11 downto 3) & '0';
  App_WDF_data  <= usr_data_r;
  App_MASK_DATA <= usr_dm_r or SM_MASK_DATA_i;

--------------------------------------------------------------------------------
-- Main Ad_Wrap state machine
--   Provides the control signals to the user interface FIFO's. Provides the 
--    controls for the pipelined address, data and control signals to the DDR2 
--    mem_interface. Controls the Read_cmd_store_fifo to determine the amount of 
--    data requested per read command. 
--------------------------------------------------------------------------------

  State_Cntl : process (cntl_clk)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      if (SYS_RST = '1') then
        state       <= st10_ready;
        pipeline_en <= '0';
      else
        state       <= next_state;
        pipeline_en <= pipeline_en_i;
      end if;
    end if;
  end process;


  Command_encode : process (state)
  begin
    case state is
      when st1_cmd_adv =>
        App_WDF_wren_i  <= '0';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '0';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"1";

      when st2_read64 =>
        App_WDF_wren_i  <= '0';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '1';
        usr_cmdF_wren_i <= '1';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"2";

      when st3_read64_hold =>
        App_WDF_wren_i  <= '0';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '0';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"3";

      when st4_read128 =>
        App_WDF_wren_i  <= '0';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '1';
        usr_cmdF_wren_i <= '1';
        cmdF_rd_cmd_i   <= '1';
        state_vec       <= x"4";

      when st5_read128_hold =>
        App_WDF_wren_i  <= '0';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '0';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '1';
        state_vec       <= x"5";

      when st6_write64 =>
        App_WDF_wren_i  <= '1';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '1';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"6";

      when st7_write64_hold =>
        App_WDF_wren_i  <= '1';
        SM_MASK_DATA_i  <= x"ff";
        App_WAF_wren_i  <= '0';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"7";

      when st8_write128 =>
        App_WDF_wren_i  <= '1';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '1';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"8";

      when st9_write128_hold =>
        App_WDF_wren_i  <= '1';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '0';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"9";

      when st10_ready =>
        App_WDF_wren_i  <= '0';
        SM_MASK_DATA_i  <= x"00";
        App_WAF_wren_i  <= '0';
        usr_cmdF_wren_i <= '0';
        cmdF_rd_cmd_i   <= '0';
        state_vec       <= x"A";

    end case;
  end process;

--
-- Sequential address / command comparrison
--
  seq_check_proc : process (CNTL_CLK)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      if SYS_RST = '1' then
        same_block <= '0';
      else
        if pipeline_en = '1' then
          if usr_cmd(0) = usr_cmd(1) and usr_addr(0)(27 downto 4) = usr_addr(1)(27 downto 4) then
            same_block <= '1';
          else
            same_block <= '0';
          end if;
        end if;
      end if;
    end if;
  end process;

  cmd_control <= same_block & usr_cmd(2)(2 downto 0);
  

  NEXT_STATE_DECODE : process (state, CNTL_CLK_ID1, cmd_control, empty_pipe, usr_af_empty_r,
                              hold_command, hold)
  begin
    case state is
      when st1_cmd_adv =>

        case cmd_control is
          when "0101" =>
            next_state    <= st2_read64;
            pipeline_en_i <= '0';

          when "1101" =>
            next_state    <= st4_read128;
            pipeline_en_i <= '1';

          when "0100" =>
            next_state    <= st6_write64;
            pipeline_en_i <= '0';

          when "1100" =>
            next_state    <= st8_write128;
            pipeline_en_i <= '1';

          when others =>
            next_state    <= st1_cmd_adv;
            pipeline_en_i <= '1';
        end case;



      when st2_read64 =>
        next_state    <= st3_read64_hold;
        pipeline_en_i <= '1';

      when st3_read64_hold =>

        case cmd_control is
          when "0101" =>
            next_state    <= st2_read64;
            pipeline_en_i <= '0';

          when "1101" =>
            next_state    <= st4_read128;
            pipeline_en_i <= '1';

          when "0100" =>
            next_state    <= st6_write64;
            pipeline_en_i <= '0';

          when "1100" =>
            next_state    <= st8_write128;
            pipeline_en_i <= '1';

          when others =>
            next_state    <= st10_ready;
            pipeline_en_i <= '0';
        end case;


      when st4_read128 =>
        next_state    <= st5_read128_hold;
        pipeline_en_i <= '1';

      when st5_read128_hold =>
        case cmd_control is
          when "0101" =>
            next_state    <= st2_read64;
            pipeline_en_i <= '0';

          when "1101" =>
            next_state    <= st4_read128;
            pipeline_en_i <= '1';

          when "0100" =>
            next_state    <= st6_write64;
            pipeline_en_i <= '0';

          when "1100" =>
            next_state    <= st8_write128;
            pipeline_en_i <= '1';

          when others =>
            next_state    <= st10_ready;
            pipeline_en_i <= '0';
        end case;

      when st6_write64 =>
        next_state    <= st7_write64_hold;
        pipeline_en_i <= '1';

      when st7_write64_hold =>
        case cmd_control is
          when "0101" =>
            next_state    <= st2_read64;
            pipeline_en_i <= '0';

          when "1101" =>
            next_state    <= st4_read128;
            pipeline_en_i <= '1';

          when "0100" =>
            next_state    <= st6_write64;
            pipeline_en_i <= '0';

          when "1100" =>
            next_state    <= st8_write128;
            pipeline_en_i <= '1';

          when others =>
            next_state    <= st10_ready;
            pipeline_en_i <= '0';
        end case;

      when st8_write128 =>
        next_state    <= st9_write128_hold;
        pipeline_en_i <= '1';


      when st9_write128_hold =>
        case cmd_control is
          when "0101" =>
            next_state    <= st2_read64;
            pipeline_en_i <= '0';

          when "1101" =>
            next_state    <= st4_read128;
            pipeline_en_i <= '1';

          when "0100" =>
            next_state    <= st6_write64;
            pipeline_en_i <= '0';

          when "1100" =>
            next_state    <= st8_write128;
            pipeline_en_i <= '1';

          when others =>
            next_state    <= st10_ready;
            pipeline_en_i <= '0';
        end case;

      when st10_ready =>
        if USR_AF_EMPTY_r = '1' or empty_pipe = '1' or hold = '1' then
          next_state    <= st10_ready;
          pipeline_en_i <= '0';
--            elsif CNTL_CLK_ID1 = '0' then
--                next_state <= st10_ready;
--                pipeline_en_i <= '0';
        else
          next_state    <= st1_cmd_adv;
          pipeline_en_i <= '1';
        end if;
        
      when others =>
        next_state    <= st10_ready;
        pipeline_en_i <= '0';
        
    end case;
  end process;


--
-- Registers needed for the state machine signals, and pipelines for the 
--  commands, address, and write data
--

  Fifo_regs : process (CNTL_CLK)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      WDF_ALMOST_FULL_r    <= WDF_ALMOST_FULL;
      WAF_ALMOST_FULL_r    <= WAF_ALMOST_FULL;
      usr_cmdF_wren        <= usr_cmdF_wren_i;
      cmdF_rd_cmd          <= cmdF_rd_cmd_i;
      read_cmd_fifo_full_r <= read_cmd_fifo_full;
    end if;
  end process;

--sr_af_empty_r <= usr_af_empty;
  
  SM_regs : process (CNTL_CLK)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      if SYS_RST = '1' then
        usr_cmd    <= (others => (others => '0'));
        empty_pipe <= '0';
        empty_done <= '0';

      else

        -- FIFO flags are slow paths, registering them helps timing   
        usr_rdf_almost_full_r <= usr_rdf_almost_full;

        hold           <= WDF_ALMOST_FULL_r or WAF_ALMOST_FULL_r or usr_rdf_almost_full_r or read_cmd_fifo_full_r;
        usr_af_empty_r <= usr_af_empty or (usr_af_almost_empty and usr_af_rden);

        if (hold = '1' or usr_af_empty_r = '1') then
          empty_pipe <= '1';
        elsif empty_done = '1' then
          empty_pipe <= '0';
        end if;

        if pipeline_en = '1' then
          if usr_af_empty_r = '0' and empty_pipe = '0' then
            usr_cmd(0)  <= usr_cmd_in;
            usr_addr(0) <= usr_addr_in;
          else
            usr_cmd(0)  <= (others => '0');
            usr_addr(0) <= (others => '0');
          end if;

          for i in 1 to 3 loop
            usr_addr(i) <= usr_addr(i-1);
            usr_cmd(i)  <= usr_cmd(i-1);
          end loop;

          hold_command <= cmd_control;
          
        end if;

        if pipeline_en = '1' then
          usr_data_r <= usr_data_in;
          usr_dm_r   <= usr_dm_in;
        end if;

        for i in 0 to 2 loop
          if usr_cmd(i)(2) = '0' then
            empty_done_v(i) <= '0';
          else
            empty_done_v(i) <= '1';
          end if;
        end loop;

        if empty_done_v = 0 then
          empty_done <= '1';
        else
          empty_done <= '0';
        end if;
      end if;
    end if;
  end process;

--
-- RD_DATA_Register Process 
--  Data from DDR2 mem_interface is clocked on CNTL_CLK
--

  RD_DATA_Register : process (CNTL_CLK)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      if SYS_RST = '1' then
        read_data_valid_r <= '0';
        usr_cmdF_rden     <= '0';
        READ_DATA0        <= (others => '0');
      else
        if usr_cmdF_rden = '1' then
          usr_cmdF_rden <= '0';
        elsif read_data_valid_r = '1' then
          usr_cmdF_rden <= '1';
        else
          usr_cmdF_rden <= '0';
        end if;

        read_data_valid_r <= read_data_valid;

        if read_data_valid = '1' then
          READ_DATA0 <= READ_DATA_FIFO_OUT;
        end if;
      end if;
    end if;
  end process;

--
-- Read Data Decode process, passes the requested amount of data to the read data fifo
--
  rd_burst_data <= cmdF_rd_cmd_dly;

  Rd_Data_Decode : process (CNTL_CLK)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      if SYS_RST = '1' then
        usr_RDF_Data  <= (others => '0');
        usr_RDF_Valid <= '1';
        usr_RDF_wren  <= '0';
        RDF_cycle_1   <= '1';
      else
        if read_data_valid_r = '1' then
          
          if RDF_cycle_1 = '1' then
            usr_RDF_Data <= READ_DATA0;
            usr_RDF_wren <= '1';
            RDF_cycle_1  <= '0';
            
          elsif RDF_cycle_1 = '0' then
            RDF_cycle_1 <= '1';
            if rd_burst_data = '1' then
              usr_RDF_Data <= READ_DATA0;
              usr_RDF_wren <= '1';
            else
              usr_RDF_wren <= '0';
            end if;
          end if;
        else
          usr_RDF_wren <= '0';
          RDF_cycle_1  <= '1';
        end if;
      end if;
    end if;
  end process;

  usr_af_rden <= pipeline_en when (empty_pipe = '0' and usr_af_empty_r = '0') else '0';


  wdf_rden_control : process (CNTL_CLK)
  begin
    if (CNTL_CLK'event and CNTL_CLK = '1') then
      if pipeline_en = '1' then
        if usr_cmd(0) = x"4" then
          wdf_rden_ctrl <= '1';
        else
          wdf_rden_ctrl <= '0';
        end if;
      elsif wdf_rden_ctrl = '1' and pipeline_en = '0' then
        wdf_rden_ctrl <= '1';
      else
        wdf_rden_ctrl <= '0';
      end if;
    end if;
  end process;


  usr_WDF_RDEN <= pipeline_en when (wdf_rden_ctrl = '1') else '0';


--
-- FIFO instances
--

--ext_a <= EXT(a, 32);

--    Addr_FIFO : async_fifo16              -- 512 entries by 36 bits
--       port map (
--          ALMOSTEMPTY => open,
--          ALMOSTFULL => usr_af_almost_full,
--          DO(27 downto 0) => usr_addr_in,
--          DO(31 downto 28) => unconnected1(23 downto 20),
--          DOP => usr_cmd_in,
--          EMPTY => usr_af_empty,
--          FULL => fifo_full(0),
--          RDCOUNT => open,
--          RDERR => open,
--          WRCOUNT => open,
--          WRERR => open,
--          DI => ext_a,
--          DIP => cmd,
--          RDCLK => CNTL_CLK,
--          RDEN => usr_AF_RDEN,
--          RST => SYS_RST,
--          WRCLK => clk,
--          WREN => usr_af_wren
--            );

  Addr_FIFO : af_fifo
    port map (
      din(31 downto 0)   => ext_a,
      din(35 downto 32)  => cmd,
      rd_clk             => CNTL_CLK,
      rd_en              => usr_AF_RDEN,
      rst                => sys_rst,
      wr_clk             => clk,
      wr_en              => usr_af_wren,
      dout(27 downto 0)  => usr_addr_in,
      dout(31 downto 28) => open,
      dout(35 downto 32) => usr_cmd_in,
      empty              => usr_af_empty,
      almost_empty       => usr_af_almost_empty,
      full               => fifo_full(0),
      prog_full          => usr_af_almost_full);                

--       Wr_Data_FIFO1 : async_fifo16_wdf              -- 512 entries by 36 bits
--       port map (
--          ALMOSTEMPTY => open,
--          ALMOSTFULL => usr_wdf_almost_full,
--          DO => usr_data_in(31 downto 0),
--          DOP => usr_dm_in(3 downto 0),
--          EMPTY => open,
--          FULL => fifo_full(1),
--          RDCOUNT => open,
--          RDERR => open,
--          WRCOUNT => open,
--          WRERR => open,
--          DI => d(31 downto 0),
--          DIP => dm(3 downto 0),
--          RDCLK => CNTL_CLK,
--          RDEN => usr_WDF_RDEN,
--          RST => SYS_RST,
--          WRCLK => clk,
--          WREN => w
--            );

--    Wr_Data_FIFO2 : async_fifo16_wdf              -- 512 entries by 36 bits
--       port map (
--          ALMOSTEMPTY => open,
--          ALMOSTFULL => open,
--          DO => usr_data_in(63 downto 32),
--          DOP => usr_dm_in(7 downto 4),
--          EMPTY => open,
--          FULL => fifo_full(2),
--          RDCOUNT => open,
--          RDERR => open,
--          WRCOUNT => open,
--          WRERR => open,
--          DI => d(63 downto 32),
--          DIP => dm(7 downto 4),
--          RDCLK => CNTL_CLK,
--          RDEN => usr_WDF_RDEN,
--          RST => SYS_RST,
--          WRCLK => clk,
--          WREN => w
--            );
  WR_Data_FIFO : async_fifo64
    port map (
      din       => d,
      rd_clk    => CNTL_CLK,
      rd_en     => usr_WDF_rden,
      rst       => SYS_RST,
      wr_clk    => clk,
      wr_en     => w,
      dout      => usr_data_in,
      empty     => open,
      prog_full => usr_wdf_almost_full,
      full      => fifo_full(1));

  usr_dm_in <= (others => '0');

--    Rd_Data_FIFO1 : async_fifo_rd              -- 512 entries by 36 bits
--       port map (
--          ALMOSTEMPTY => open,
--          ALMOSTFULL => usr_rdf_almost_full,
--          DO => q(31 downto 0),
--          DOP => open,
--          EMPTY => usr_rdf_empty(0),
--          FULL => fifo_full(3),
--          RDCOUNT => open,
--          RDERR => open,
--          WRCOUNT => open,
--          WRERR => open,
--          DI => usr_rdf_Data(31 downto 0),
--          DIP => "0000",
--          RDCLK => clk,
--          RDEN => usr_RDF_rden,
--          RST => SYS_RST,
--          WRCLK => CNTL_CLK,
--          WREN => usr_RDF_wren
--       );

--    Rd_Data_FIFO2 : async_fifo_rd              -- 512 entries by 36 bits
--       port map (
--          ALMOSTEMPTY => open,
--          ALMOSTFULL => open,
--          DO => q(63 downto 32),
--          DOP => open,
--          EMPTY => usr_rdf_empty(1),
--          FULL => fifo_full(4),
--          RDCOUNT => open,
--          RDERR => open,
--          WRCOUNT => open,
--          WRERR => open,
--          DI => usr_RDF_Data(63 downto 32),
--          DIP => "0000",
--          RDCLK => clk,
--          RDEN => usr_RDF_rden,
--          RST => SYS_RST,
--          WRCLK => CNTL_CLK,
--          WREN => usr_RDF_wren
--       );
  RD_Data_FIFO : async_fifo64
    port map (
      din       => usr_RDF_Data,
      rd_clk    => clk,
      rd_en     => usr_RDF_rden,
      rst       => SYS_RST,
      wr_clk    => CNTL_CLK,
      wr_en     => usr_RDF_wren,
      dout      => q,
      empty     => usr_rdf_empty(0),
      prog_full => open,
      full      => fifo_full(3));
  usr_rdf_empty(1) <= usr_rdf_empty(0);

--Read_cmd_FIFO : read_cmd_store_fifo
--              port map (
--                      rd_clk => CNTL_CLK,
--                      din(0) => cmdF_rd_cmd,
--                      rd_en => usr_cmdF_rden,
--                      rst => SYS_RST,
--                      wr_clk => CNTL_CLK,
--                      wr_en => usr_cmdF_wren,
--                      prog_full => read_cmd_fifo_full,
--                      dout(0) => cmdF_rd_cmd_dly,
--                      empty => open,
--                      full => fifo_full(5));
  Read_cmd_FIFO : sync_fifo_deep
    generic map (
      width => 1)
    port map (
      clk        => CNTL_CLK,
      rst        => sys_rst,
      wadv       => usr_cmdF_wren,
      wdata(0)   => cmdF_rd_cmd,
      hfull      => read_cmd_fifo_full,
      wfull      => fifo_full(5),
      radv       => usr_cmdF_rden,
      rdw_out(0) => cmdF_rd_cmd_dly);

  ff0 : process (CNTL_CLK, SYS_RST)
  begin  -- process ff0
    if SYS_RST = '1' then                         -- asynchronous reset
      overflow(3) <= '0';
      overflow(4) <= '0';
      overflow(5) <= '0';
    elsif CNTL_CLK'event and CNTL_CLK = '1' then  -- rising clock edge
      if fifo_full(3) = '1' then
        overflow(3) <= '1';
      elsif flush = '1' then
        overflow(3) <= '0';
      end if;
      if usr_af_rden = '1' and usr_af_empty = '1' then
        overflow(4) <= '1';
      elsif flush = '1' then
        overflow(4) <= '0';
      end if;
      if fifo_full(5) = '1' then
        overflow(5) <= '1';
      elsif flush = '1' then
        overflow(5) <= '0';
      end if;
      if flush = '1' then
        af_rcount <= (others => '0');
      elsif usr_af_rden = '1' then
        af_rcount <= af_rcount+1;
      end if;
    end if;
  end process ff0;

  ff1 : process (clk, SYS_RST)
  begin  -- process ff0
    if SYS_RST = '1' then               -- asynchronous reset
      overflow(0) <= '0';
      overflow(1) <= '0';
      overflow(2) <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      if fifo_full(0) = '1' then
        overflow(0) <= '1';
      elsif flush = '1' then
        overflow(0) <= '0';
      end if;
      if fifo_full(1) = '1' then
        overflow(1) <= '1';
      elsif flush = '1' then
        overflow(1) <= '0';
      end if;
      if fifo_full(2) = '1' then
        overflow(2) <= '1';
      elsif flush = '1' then
        overflow(2) <= '0';
      end if;
      status(5 downto 0) <= overflow;
      if flush = '1' then
        af_wcount <= (others => '0');
      elsif usr_af_wren = '1' then
        af_wcount <= af_wcount+1;
      end if;
      if flush = '1' then
        rf_rcount <= (others => '0');
      elsif usr_rdf_rden = '1' then
        rf_rcount <= rf_rcount+1;
      end if;
      status(15 downto 8) <= af_wcount;

      status(23 downto 16) <= af_rcount;
      status(31 downto 24) <= rf_rcount;
      
    end if;
  end process ff1;



-- 
-- DDR2 SDRAM Controller instance
--  Mig 1.6, DirectClk type Core
--
  controller : mem_interface_small_top_0
    generic map(use_chipscope => use_chipscope)
    port map (
      DDR2_DQ            => cntrl_DDR2_DQ,
      DDR2_A             => cntrl_DDR2_A,
      DDR2_BA            => cntrl_DDR2_BA,
      DDR2_RAS_N         => cntrl_DDR2_RAS_N,
      DDR2_CAS_N         => cntrl_DDR2_CAS_N,
      DDR2_WE_N          => cntrl_DDR2_WE_N,
      DDR2_CS_N(0)       => cntrl_DDR2_CS_N,
      DDR2_ODT(0)        => cntrl_DDR2_ODT,
      DDR2_CKE(0)        => cntrl_DDR2_CKE,
      DDR2_DM            => cntrl_DDR2_DM,
      clk_0              => CNTL_CLK,
      clk_90             => CNTL_CLK90,
      clk_50             => CNTL_CLK_ID1,
      ref_clk            => CNTL_CLK_ID2,
      SYS_RST            => SYS_RST,
      SYS_RST90          => SYS_RST_90,
      sys_rst_ref_clk_1  => sys_rst_id,
      idelay_ctrl_rdy    => idelay_ctrl_rdy,
      CLK_TB             => open,
      RESET_TB           => open,
      WDF_ALMOST_FULL    => WDF_ALMOST_FULL,
      AF_ALMOST_FULL     => WAF_ALMOST_FULL,
      READ_DATA_VALID    => READ_DATA_VALID,
      APP_WDF_WREN       => APP_WDF_WREN,
      APP_AF_WREN        => APP_WAF_WREN,
      BURST_LENGTH       => open,
      APP_AF_ADDR        => APP_WAF_ADDR,
      READ_DATA_FIFO_OUT => READ_DATA_FIFO_OUT,
      APP_WDF_DATA       => APP_WDF_DATA,
      APP_MASK_DATA      => APP_MASK_DATA,
      DDR2_DQS           => cntrl_DDR2_DQS,
      DDR2_DQS_N         => cntrl_DDR2_DQS_N,
      DDR2_CK            => cntrl_DDR2_CK,
      DDR2_CK_N          => cntrl_DDR2_CK_N,
      chip_scope_control => control2,
      error              => error
      );

----------------------------------------------------------------------------
-- ChipScope Instance --
----------------------------------------------------------------------------
  scope :
  if use_chipscope = true generate
  begin

    i_ila : ila
      port map(
        control => control1,
        clk     => cntl_clk,
        trig0   => trig0);              -- (254 downto 0)

    trig0(0)              <= APP_WAF_WREN;
    trig0(36 downto 1)    <= APP_WAF_ADDR;
    trig0(37)             <= APP_WDF_WREN;
    trig0(101 downto 38)  <= usr_RDF_Data;
    trig0(165 downto 102) <= APP_WDF_DATA;
    trig0(173 downto 166) <= APP_MASK_DATA;
    trig0(182)            <= pipeline_en;
    trig0(183)            <= usr_WDF_RDEN;
    trig0(210 downto 184) <= a(27 downto 1);
    trig0(212 downto 211) <= usr_rdf_empty;
    trig0(213)            <= usr_RDF_Valid;
    trig0(214)            <= usr_RDF_wren;
    trig0(215)            <= SYS_RST;
    trig0(216)            <= flush;
    trig0(217)            <= idelay_ctrl_rdy;
    trig0(225 downto 218) <= dm;
    trig0(226)            <= WAF_ALMOST_FULL_r;
    trig0(227)            <= usr_af_empty_r;
    trig0(228)            <= READ_DATA_VALID_r;
    trig0(229)            <= same_block;
    trig0(230)            <= r;
    trig0(231)            <= w;
    trig0(235 downto 232) <= state_vec;
    trig0(236)            <= usr_RDF_rden;
    trig0(237)            <= rd_burst_data;
    trig0(238)            <= wait_read_data;
    trig0(239)            <= qv_i;
    trig0(248 downto 240) <= clear_counter(8 downto 0);
    trig0(249)            <= usr_af_almost_full_r;
    trig0(250)            <= usr_wdf_almost_full_r;
    trig0(251)            <= read_cmd_fifo_full_r;
--        trig0(254 downto 252) <=    ;
    
  end generate;

end Behavioral;

