-- ==============================================================
-- FILE : USER_AP2.VHD  -  MUST be modified by the USER
-- ==============================================================
--
-- This file is part of Example 2, for the HERON-FPGA14 module.
--
-- This file must be modified by the user.
--
-- ==============================================================
--
--  Date        : 06/04/2006
--  Author      : R. Williams - HUNT ENGINEERING
--  Description : User code section
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     R. Williams    06-04-06    Taken from FPGA12 Example 2.
--
-- ==============================================================



-- ==============================================================
--   Package : CONFIG
-- ==============================================================
--
-- This package allow users to set up the different clock domains
-- of the application (FIFO interfaces) in the top level.
-- Please refer to the HUNT documentation for more details.
--
-- ==============================================================

package CONFIG is

  -- FIFO CLOCK
  -- ==========

--   --------------------------------------------------------------------
--   Normally you will use the same clock source for the input and output
--   HERON FIFOs. In that case you need a single clock domain.
--   Then you drive SRC_FCLK_G with the frequency you want, which for the 
--   HEPC9/HECPCI9/HERON_BASE2 must be >=60Mhz and <= 100Mhz.
--   The clock you use in your design is then FCLK_G which has the corrct 
--   phase relative to the FIFO data.
--   In this case set FCLK_G_DOMAIN = TRUE

--   If however you want to use different clocks for the input and output 
--   HERON FIFOs, you have seperate clock domains.
--   Now you drive the signals SRC_FCLK_RD and SRC_FCLK_WR with the frequencies
--   you want, (still probably >60Mhz and <100Mhz) and your design must use 
--   FCLK_RD to deal with input FIFO data but FCLK_WR to deal with output FIFO data.  
--   In this case set FCLK_G_DOMAIN = FALSE

  -- To use a single common FIFO clock, set FCLK_G_DOMAIN = TRUE
  constant FCLK_G_DOMAIN : boolean := TRUE;

end CONFIG;


-- ==============================================================
--   Module : USER_AP
-- ==============================================================

library IEEE;
  use IEEE.std_logic_1164.all;
  use IEEE.std_logic_unsigned.all;
  use IEEE.numeric_std.all;
  use WORK.CONFIG.all;


--pragma translate_off
library sim_lib;
  use sim_lib.all;
library UNISIM;
  use UNISIM.VCOMPONENTS.all;
--pragma translate_on


entity USER_AP is
  port (
    RESET             : in  std_logic;                      -- Asynchronous reset active high
    CONFIG            : in  std_logic;                      -- System wide Config signal
-- CLOCK IO
    OSC0              : in  std_logic;                      -- Xtal OSC0
    OSC3              : in  std_logic;                      -- Xtal OSC3 factory default fitted with 100Mhz
-- MISCELLANEOUS IO
    UDPRES            : out std_logic;                      -- reset the carrier (high if NOT used)
    LED               : out std_logic_vector(4 downto 0);   -- LEDs
    MOD_HAS_PROC      : out std_logic;
    CID               : in  std_logic_vector(3 downto 0);   -- Carrier ID
    MID               : in  std_logic_vector(3 downto 0);   -- Module ID
-- UMIs
    UMI_IN            : in  std_logic_vector(3 downto 0);
    UMI_OUT           : out std_logic_vector(3 downto 0);
    UMI_EN            : out std_logic_vector(3 downto 0);
-- READ FIFO CLK
    FCLK_RD           : in  std_logic;                      -- FIFO_IN clock to be used in this module (only when FCLK_G_DOMAIN=FALSE)
    SRC_FCLK_RD       : out std_logic;                      -- FIFO_IN clock source for the top level  (only when FCLK_G_DOMAIN=FALSE)
-- WRITE FIFO CLK
    FCLK_WR           : in  std_logic;                      -- FIFO_OUT clock to be used in this module (only when FCLK_G_DOMAIN=FALSE)
    SRC_FCLK_WR       : out std_logic;                      -- FIFO_OUT clock source for the top level  (only when FCLK_G_DOMAIN=FALSE)
-- COMMON FIFO CLK
    FCLK_G            : in  std_logic;                      -- Common FIFO clock to be used in this module (only when FCLK_G_DOMAIN=TRUE)
    SRC_FCLK_G        : out std_logic;                      -- Common FIFO clock source for the top level  (only when FCLK_G_DOMAIN=TRUE)
-- FIFO IN / HE_RD_6F interface
    INFIFO_READ_REQ   : out std_logic_vector(5 downto 0);   -- FIFO_IN Read Request
    INFIFO_DVALID     : in  std_logic_vector(5 downto 0);   -- FIFO_IN Data Valid
    INFIFO_SINGLE     : in  std_logic_vector(5 downto 0);   -- FIFO_IN Single data item available
    INFIFO_BURST      : in  std_logic_vector(5 downto 0);   -- FIFO_IN Block of data available
    INFIFO0_D         : in  std_logic_vector(31 downto 0);  -- FIFO_IN Data for FIFO 0
    INFIFO1_D         : in  std_logic_vector(31 downto 0);  -- FIFO_IN Data for FIFO 1
    INFIFO2_D         : in  std_logic_vector(31 downto 0);  -- FIFO_IN Data for FIFO 2
    INFIFO3_D         : in  std_logic_vector(31 downto 0);  -- FIFO_IN Data for FIFO 3
    INFIFO4_D         : in  std_logic_vector(31 downto 0);  -- FIFO_IN Data for FIFO 4
    INFIFO5_D         : in  std_logic_vector(31 downto 0);  -- FIFO_IN Data for FIFO 5
-- FIFO OUT / HE_WR_6F interface
    OUTFIFO_READY     : in  std_logic_vector(5 downto 0);   -- FIFO_OUT Ready Flag
    OUTFIFO_WRITE     : out std_logic_vector(5 downto 0);   -- FIFO_OUT Write Command
    OUTFIFO_D         : out std_logic_vector(31 downto 0);  -- FIFO_OUT Data
-- SERIAL BUS / HE_USER Message interface
    MSG_CLK           : out std_logic;                      -- HSB clock source for the top level
    MSG_DIN           : in  std_logic_vector(7 downto 0);   -- data received from HSB
    MSG_ADDR          : in  std_logic_vector(7 downto 0);   -- HSB address
    MSG_AEN           : in  std_logic;                      -- address enable
    MSG_WEN           : in  std_logic;                      -- write access
    MSG_REN           : in  std_logic;                      -- read access
    MSG_DONE          : in  std_logic;                      -- message successfully transmitted
    MSG_COUNT         : in  std_logic;                      -- user's counter enable
    MSG_CLEAR         : in  std_logic;                      -- user's counter clear
    MSG_READY         : out std_logic;                      -- to acknowledge an access
    MSG_SEND_MSG      : out std_logic;                      -- message send command
    MSG_CE            : out std_logic;                      -- to control speed operation
    MSG_DOUT          : out std_logic_vector(7 downto 0);   -- data sent to HSB
    MSG_SEND_ID       : out std_logic;                      -- ID information send command
    MSG_LAST_BYTE     : out std_logic;                      -- to indicate when the last byte is presented
-- CONNECTOR DIGITAL IO
    CONN_A_IN         : in  std_logic_vector(29 downto 0);  -- Data input on Connector A
    CONN_A_OUT        : out std_logic_vector(29 downto 0);  -- Data output on Connector A
    CONN_A_EN         : out std_logic_vector(29 downto 0);  -- Output enables for Connector A
    CONN_B_IN         : in  std_logic_vector(29 downto 0);  -- Data input on Connector B
    CONN_B_OUT        : out std_logic_vector(29 downto 0);  -- Data output on Connector B
    CONN_B_EN         : out std_logic_vector(29 downto 0);  -- Output enables for Connector B
    CONN_C_IN         : in  std_logic_vector(29 downto 0);  -- Data input on Connector C
    CONN_C_OUT        : out std_logic_vector(29 downto 0);  -- Data output on Connector C
    CONN_C_EN         : out std_logic_vector(29 downto 0);  -- Output enables for Connector C
    CONN_D_IN         : in  std_logic_vector(29 downto 0);  -- Data input on Connector D
    CONN_D_OUT        : out std_logic_vector(29 downto 0);  -- Data output on Connector D
    CONN_D_EN         : out std_logic_vector(29 downto 0);  -- Output enables for Connector D
    CONN_E_IN         : in  std_logic_vector(29 downto 0);  -- Data input on Connector E
    CONN_E_OUT        : out std_logic_vector(29 downto 0);  -- Data output on Connector E
    CONN_E_EN         : out std_logic_vector(29 downto 0);  -- Output enables for Connector E
    CONN_F_IN         : in  std_logic_vector(29 downto 0);  -- Data input on Connector F
    CONN_F_OUT        : out std_logic_vector(29 downto 0);  -- Data output on Connector F
    CONN_F_EN         : out std_logic_vector(29 downto 0);  -- Output enables for Connector F
-- DDR User Clock A
    DDR_A_USER_CLK    : out std_logic;                      -- DDR Port A Clock source
-- DDR User Reset A
    DDR_A_USER_RST    : out std_logic;                      -- DDR Port A Data Count Reset
-- DDR Data Count
    DDR_A_DATA_COUNT  : in  std_logic_vector(31 downto 0);  -- DDR Port A Data Count
-- DDR Write Port A
    DDR_A_WR_DATA     : out std_logic_vector(71 downto 0);  -- DDR Port A Write Data
    DDR_A_WR_ADDR     : out std_logic_vector(24 downto 0);  -- DDR Port A Write Address
    DDR_A_WR_ADDR_WEN : out std_logic;                      -- DDR Port A Wr-Address Enable
    DDR_A_WR_ADDR_FF  : in  std_logic;                      -- DDR Port A Wr-Address Full Flag
    DDR_A_WR_ADDR_AF  : in  std_logic;                      -- DDR Port A Wr-Address Almost Full
    DDR_A_WR_RISE_WEN : out std_logic;                      -- DDR Port A Rising Data Enable
    DDR_A_WR_RISE_FF  : in  std_logic;                      -- DDR Port A Rising Data Full Flag
    DDR_A_WR_RISE_AF  : in  std_logic;                      -- DDR Port A Rising Data Almost Full
    DDR_A_WR_FALL_WEN : out std_logic;                      -- DDR Port A Falling Data Enable
    DDR_A_WR_FALL_FF  : in  std_logic;                      -- DDR Port A Falling Data Full Flag
    DDR_A_WR_FALL_AF  : in  std_logic;                      -- DDR Port A Falling Data Almost Full
    DDR_A_WR_DM_WEN   : out std_logic;                      -- DDR Port A Data Mask Enable
    DDR_A_WR_DM_FF    : in  std_logic;                      -- DDR Port A Data Mask Full Flag
    DDR_A_WR_DM_AF    : in  std_logic;                      -- DDR Port A Data Mask Almost Full
-- DDR Read Port A
    DDR_A_RD_DATA     : in  std_logic_vector(63 downto 0);  -- DDR Port A Read Data
    DDR_A_RD_ADDR     : out std_logic_vector(24 downto 0);  -- DDR Port A Read Address
    DDR_A_RD_ADDR_WEN : out std_logic;                      -- DDR Port A Rd-Address Enable
    DDR_A_RD_ADDR_FF  : in  std_logic;                      -- DDR Port A Rd-Address Full Flag
    DDR_A_RD_ADDR_AF  : in  std_logic;                      -- DDR Port A Rd-Address Almost Full
    DDR_A_RD_RISE_REN : out std_logic;                      -- DDR Port A Rising Data Enable
    DDR_A_RD_RISE_EF  : in  std_logic;                      -- DDR Port A Rising Data Empty Flag
    DDR_A_RD_RISE_AE  : in  std_logic;                      -- DDR Port A Rising Data Almost Empty
    DDR_A_RD_FALL_REN : out std_logic;                      -- DDR Port A Falling Data Enable
    DDR_A_RD_FALL_EF  : in  std_logic;                      -- DDR Port A Falling Data Empty Flag
    DDR_A_RD_FALL_AE  : in  std_logic                       -- DDR Port A Falling Data Almost Empty
  );
end USER_AP;


architecture EXAMPLE2 of USER_AP is

  component BUFG
    port ( I : in  std_logic;
           O : out std_logic);
  end component;

  component HSB2
    port (
      RST          : in  std_logic;
      CLK          : in  std_logic;
      DIN          : in  std_logic_vector(7 downto 0);
      ADDR         : in  std_logic_vector(7 downto 0);
      AEN          : in  std_logic;
      WEN          : in  std_logic;
      REN          : in  std_logic;
      DONE         : in  std_logic;
      COUNT        : in  std_logic;
      CLEAR        : in  std_logic;
      READY        : out std_logic;
      SEND_MSG     : out std_logic;
      CE           : out std_logic;
      DOUT         : out std_logic_vector(7 downto 0);
      SEND_ID      : out std_logic;
      LAST_BYTE    : out std_logic
    );
  end component;

  -- Asynchronous FIFO
  component fifo15x32
    port (
      din          : in  std_logic_vector(31 downto 0);
      wr_en        : in  std_logic;
      wr_clk       : in  std_logic;
      rd_en        : in  std_logic;
      rd_clk       : in  std_logic;
      ainit        : in  std_logic;
      dout         : out std_logic_vector(31 downto 0);
      full         : out std_logic;
      empty        : out std_logic;
      almost_full  : out std_logic;
      almost_empty : out std_logic
    );
  end component;

  -- Synchronous FIFO
  component FIFO16x32
    port (
      RESET    : in  std_logic;
      CLOCK    : in  std_logic;
      DIN      : in  std_logic_vector(31 downto 0);
      WR_EN    : in  std_logic;
      RD_EN    : in  std_logic;
      DOUT     : out std_logic_vector(31 downto 0);
      FULL     : out std_logic;
      EMPTY    : out std_logic;
      WR_COUNT : out std_logic_vector(4 downto 0);
      RD_COUNT : out std_logic_vector(4 downto 0)
    );
  end component;

  type state_type is (idle, write_mem, write_wait, read_mem, read_wait);

  signal state           : state_type;

  signal MCLK            : std_logic;
  signal LEDcount        : unsigned(24 downto 0);

  signal HSB_CLK         : std_logic;
  signal HSB_CLOCK       : std_logic;

  signal SDCLK           : std_logic;

  signal IN_FIFO_DATA    : std_logic_vector(31 downto 0);
  signal IN_FIFO_RD      : std_logic;
  signal IN_FIFO_EF      : std_logic;
  signal IN_FIFO_AF      : std_logic;

  signal OUT_FIFO_WR     : std_logic;
  signal OUT_FIFO_RD     : std_logic;
  signal OUT_FIFO_EF     : std_logic;
  signal OUT_FIFO_AF     : std_logic;

  signal NEW_COMMAND     : std_logic;
  signal DO_MEM_WRITE    : std_logic;
  signal DO_MEM_READ     : std_logic;

  signal IDLE_STATE      : std_logic;
  signal ADDR_EN         : std_logic;
  signal WRITE_EN        : std_logic;
  signal READ_EN         : std_logic;
  signal WRITE_DONE      : std_logic;
  signal READ_DONE       : std_logic;
  signal WR_DELAY        : std_logic;
  signal RD_DELAY        : std_logic;

  signal DATA_SEL        : std_logic_vector(3 downto 0);
  signal TEST_PATTERN    : std_logic_vector(31 downto 0);

  signal WR_FIFO_DOUT_A  : std_logic_vector(31 downto 0);
  signal WR_FIFO_WR_CT_A : std_logic_vector(4 downto 0);
  signal WR_FIFO_RD_CT_A : std_logic_vector(4 downto 0);
  signal WR_FIFO_WR_A    : std_logic;
  signal WR_FIFO_RD_A    : std_logic;
  signal WR_FIFO_RD_A_DL : std_logic;
  signal WR_FIFO_EF_A    : std_logic;
  signal WR_FIFO_AF_A    : std_logic;
  signal WR_ADDRESS_A    : std_logic_vector(22 downto 0);
  signal WR_COUNT_A      : std_logic_vector(1 downto 0);

  signal RD_FIFO_DIN_A   : std_logic_vector(31 downto 0);
  signal RD_FIFO_OUT_A   : std_logic_vector(31 downto 0);
  signal RD_FIFO_OUT     : std_logic_vector(31 downto 0);
  signal RD_FIFO_WR_CT_A : std_logic_vector(4 downto 0);
  signal RD_FIFO_WR_A    : std_logic;
  signal RD_FIFO_RD_A    : std_logic;
  signal RD_FIFO_EF_A    : std_logic;
  signal RD_FIFO_AF_A    : std_logic;
  signal RD_ADDRESS_A    : std_logic_vector(22 downto 0);
  signal RD_COUNT_A      : std_logic_vector(1 downto 0);

  signal RISE_FALL_A     : std_logic;
  signal RIP_DONE_A      : std_logic;
  signal RIP_A           : std_logic;

  signal WRITE_DATA      : std_logic_vector(31 downto 0);
  signal WRITE_SHIFT     : std_logic;
  signal WRITE_COUNT_A   : std_logic_vector(25 downto 0);

  signal READ_DATA_A     : std_logic_vector(31 downto 0);
  signal READ_SHIFT_A    : std_logic;
  signal READ_COUNT_A    : std_logic_vector(25 downto 0);
  signal WRITE_ZERO_A    : std_logic;
  signal READ_ZERO_A     : std_logic;

  signal DATA_REG_A      : std_logic_vector(31 downto 0);
  signal DATA_COMPARE_A  : std_logic;
  signal DATA_CHECK_A    : std_logic;
  signal DATA_ERROR_A    : std_logic;

  signal OSC3_CLK        : std_logic;

begin

  -- ==========================================================
  -- ==========================================================
  --       <<<<<<<   INSERT YOUR CODE HERE    >>>>>>>>>
  -- ==========================================================
  -- ==========================================================


  -------------------------------------------------------------
  -- Main clock to be used in this example

  iOSC3_BUFG : BUFG port map (I=>OSC3, O=>OSC3_CLK);

  MCLK <= OSC3_CLK;

  -------------------------------------------------------------
  -- Drive the UDP-RESET high (inactive)

  UDPRES <= '1';

  -------------------------------------------------------------
  -- Drive the MODULE HAS PROCESSOR signal high (inactive)

  MOD_HAS_PROC <= '1';

  -------------------------------------------------------------
  -- Drive unused signals

  UMI_OUT <= (others=>'0');
  UMI_EN  <= (others=>'1');

  -------------------------------------------------------------
  -- FIFO Clocks

  SRC_FCLK_RD <= '0';   -- clock source for READ FIFO
  SRC_FCLK_WR <= '0';   -- clock source for WRITE FIFO
  SRC_FCLK_G  <= MCLK;  -- global clock source for both FIFOs

  SDCLK <= FCLK_G;

  DDR_A_USER_CLK <= FCLK_G;

  -------------------------------------------------------------
  -- Test Control Data from HERON Input FIFO

  INFIFO_READ_REQ(0) <= (NOT IN_FIFO_AF);
  INFIFO_READ_REQ(1) <= '0';
  INFIFO_READ_REQ(2) <= '0';
  INFIFO_READ_REQ(3) <= '0';
  INFIFO_READ_REQ(4) <= '0';
  INFIFO_READ_REQ(5) <= '0';

  iIN_FIFO : fifo15x32
    port map (
      din          => INFIFO0_D,
      wr_en        => INFIFO_DVALID(0),
      wr_clk       => FCLK_G,
      rd_en        => IN_FIFO_RD,
      rd_clk       => SDCLK,
      ainit        => RESET,
      dout         => IN_FIFO_DATA,
      full         => open,
      empty        => IN_FIFO_EF,
      almost_full  => IN_FIFO_AF,
      almost_empty => open );

  IN_FIFO_RD <= IDLE_STATE AND (NOT IN_FIFO_EF) AND (NOT NEW_COMMAND) AND (NOT ADDR_EN);

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      NEW_COMMAND <= '0';
      ADDR_EN     <= '0';
    elsif rising_edge(SDCLK) then
      NEW_COMMAND <= IN_FIFO_RD;
      ADDR_EN     <= NEW_COMMAND;
    end if;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      DATA_SEL <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if NEW_COMMAND='1' then
        DATA_SEL <= IN_FIFO_DATA(3 downto 0);
      end if;
    end if;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      DO_MEM_WRITE <= '0';
      DO_MEM_READ  <= '0';
    elsif rising_edge(SDCLK) then
      DO_MEM_WRITE <= '0';
      DO_MEM_READ  <= '0';
      if (NEW_COMMAND='1' and IN_FIFO_DATA(4)='1') or (DO_MEM_WRITE='1' and WRITE_DONE='0') then
        DO_MEM_WRITE <= '1';
      end if;
      if (NEW_COMMAND='1' and IN_FIFO_DATA(5)='1') or (DO_MEM_READ='1' and READ_DONE='0') then
        DO_MEM_READ  <= '1';
      end if;
    end if;
  end process;

  -------------------------------------------------------------
  -- DDR SDRAM Memory Read and Write Control State Machine

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      state <= idle;
    elsif rising_edge(SDCLK) then
      case state is
        when idle       => if    DO_MEM_WRITE='1'                   then state <= write_mem;
                           elsif DO_MEM_READ='1'                    then state <= read_mem;
                           else                                          state <= idle;
                           end if;
        when write_mem  =>                                               state <= write_wait;
        when write_wait => if    WRITE_DONE='1' and DO_MEM_READ='1' then state <= read_mem;
                           elsif WRITE_DONE='1'                     then state <= idle;
                           else                                          state <= write_wait;
                           end if;
        when read_mem   =>                                               state <= read_wait;
        when read_wait  => if    READ_DONE='1'                      then state <= idle;
                           else                                          state <= read_wait;
                           end if;
      end case;
    end if;
  end process;

  process(state)
  begin
    case state is
      when idle       => IDLE_STATE <= '1'; WRITE_EN <= '0'; READ_EN <= '0';
      when write_mem  => IDLE_STATE <= '0'; WRITE_EN <= '1'; READ_EN <= '0';
      when write_wait => IDLE_STATE <= '0'; WRITE_EN <= '0'; READ_EN <= '0';
      when read_mem   => IDLE_STATE <= '0'; WRITE_EN <= '0'; READ_EN <= '1';
      when read_wait  => IDLE_STATE <= '0'; WRITE_EN <= '0'; READ_EN <= '0';
    end case;
  end process;

  process(SDCLK)
  begin
    if rising_edge(SDCLK) then
      WR_DELAY <= WRITE_ZERO_A;
      RD_DELAY <= READ_ZERO_A;
    end if;
  end process;

  WRITE_DONE <= (NOT WR_DELAY) AND WRITE_ZERO_A;
  READ_DONE  <= (NOT RD_DELAY) AND READ_ZERO_A;

  -------------------------------------------------------------
  -- DDR SDRAM Test Data Generation

  process (DATA_SEL(1 downto 0))
  begin
    case DATA_SEL(1 downto 0) is
      when "00"   => TEST_PATTERN <= "00000000000000000000000000000000";
      when "01"   => TEST_PATTERN <= "11111111111111111111111111111111";
      when "10"   => TEST_PATTERN <= "01010101010101010101010101010101";
      when "11"   => TEST_PATTERN <= "10101010101010101010101010101010";
      when others => TEST_PATTERN <= (others=>'0');
    end case;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      WRITE_DATA  <= (others=>'0');
      WRITE_SHIFT <= '0';
    elsif rising_edge(SDCLK) then
      if ADDR_EN='1' then
        WRITE_DATA  <= TEST_PATTERN;
        WRITE_SHIFT <= '1';
      elsif (WR_FIFO_WR_A='1') then
        if DATA_SEL(2)='1' then
          WRITE_DATA <= WRITE_DATA + 1;
        elsif DATA_SEL(3)='1' then
          WRITE_DATA  <= WRITE_DATA(30 downto 0) & WRITE_SHIFT;
          WRITE_SHIFT <= WRITE_DATA(31);
        else
          WRITE_DATA <= WRITE_DATA;
        end if;
      end if;
    end if;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      READ_DATA_A  <= (others=>'0');
      READ_SHIFT_A <= '0';
    elsif rising_edge(SDCLK) then
      if ADDR_EN='1' then
        READ_DATA_A  <= TEST_PATTERN;
        READ_SHIFT_A <= '1';
      elsif DATA_CHECK_A='1' then
        if DATA_SEL(2)='1' then
          READ_DATA_A <= READ_DATA_A + 1;
        elsif DATA_SEL(3)='1' then
          READ_DATA_A  <= READ_DATA_A(30 downto 0) & READ_SHIFT_A;
          READ_SHIFT_A <= READ_DATA_A(31);
        else
          READ_DATA_A <= READ_DATA_A;
        end if;
      end if;
    end if;
  end process;

  -------------------------------------------------------------
  -- DDR SDRAM Write Data Count (to write all 256 Mbytes of memory)

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      WRITE_COUNT_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if WRITE_EN='1' then
        WRITE_COUNT_A <= "10000000000000000000000000";
      elsif WR_FIFO_WR_A='1' and WRITE_ZERO_A='0' then
        WRITE_COUNT_A <= WRITE_COUNT_A - 1;
      end if;
    end if;
  end process;

  WRITE_ZERO_A <= '1' when WRITE_COUNT_A="00000000000000000000000000" else '0';

  -------------------------------------------------------------
  -- DDR SDRAM Read Data Count (to read all 256 Mbytes of memory)

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      READ_COUNT_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if READ_EN='1' then
        READ_COUNT_A <= "10000000000000000000000000";
      elsif RD_FIFO_WR_A='1' and READ_ZERO_A='0' then
        READ_COUNT_A <= READ_COUNT_A - 1;
      end if;
    end if;
  end process;

  READ_ZERO_A <= '1' when READ_COUNT_A="00000000000000000000000000" else '0';

  -------------------------------------------------------------
  -- DDR SDRAM Write Interface Data FIFO

  WR_FIFO_WR_A <= WR_FIFO_AF_A AND (NOT WRITE_ZERO_A);

  WR_FIFO_AF_A <= '0' when WR_FIFO_WR_CT_A(4 downto 1)="0000" else '1';

  iWR_FIFO_A : FIFO16x32
    port map (
      RESET    => RESET,
      CLOCK    => SDCLK,
      DIN      => WRITE_DATA,
      WR_EN    => WR_FIFO_WR_A,
      RD_EN    => WR_FIFO_RD_A,
      DOUT     => WR_FIFO_DOUT_A,
      FULL     => open,
      EMPTY    => WR_FIFO_EF_A,
      WR_COUNT => WR_FIFO_WR_CT_A,
      RD_COUNT => WR_FIFO_RD_CT_A );

  DDR_A_WR_RISE_WEN <= WR_FIFO_RD_A AND (NOT WR_COUNT_A(0));
  DDR_A_WR_FALL_WEN <= WR_FIFO_RD_A AND (    WR_COUNT_A(0));
  DDR_A_WR_DM_WEN   <= WR_FIFO_RD_A AND (    WR_COUNT_A(0));

  WR_FIFO_RD_A <= WR_FIFO_EF_A AND (NOT DDR_A_WR_RISE_AF) AND (NOT DDR_A_WR_FALL_AF) AND
                                   (NOT DDR_A_WR_DM_AF) AND (NOT WR_FIFO_RD_A_DL);

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      WR_FIFO_RD_A_DL <= '0';
    elsif rising_edge(SDCLK) then
      WR_FIFO_RD_A_DL <= WR_FIFO_RD_A;
    end if;
  end process;

  DDR_A_WR_DATA( 7 downto  0) <= (others=>'0');
  DDR_A_WR_DATA(39 downto  8) <= WR_FIFO_DOUT_A;
  DDR_A_WR_DATA(71 downto 40) <= WR_FIFO_DOUT_A;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      WR_COUNT_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if WR_FIFO_RD_A='1' then
        WR_COUNT_A <= WR_COUNT_A + 1;
      end if;
    end if;
  end process;

  DDR_A_WR_ADDR_WEN <= WR_FIFO_RD_A AND WR_COUNT_A(1) AND WR_COUNT_A(0);

  DDR_A_WR_ADDR <= WR_ADDRESS_A & "00";

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      WR_ADDRESS_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if ADDR_EN='1' then
        WR_ADDRESS_A <= (others=>'0');
      elsif (WR_FIFO_RD_A='1' and WR_COUNT_A="11") then
        WR_ADDRESS_A <= WR_ADDRESS_A + 1;
      end if;
    end if;
  end process;

  -------------------------------------------------------------
  -- DDR SDRAM Read Interface Data FIFO

  DDR_A_RD_RISE_REN <= (NOT DDR_A_RD_RISE_EF) AND (NOT RISE_FALL_A);
  DDR_A_RD_FALL_REN <= (NOT DDR_A_RD_FALL_EF) AND (    RISE_FALL_A);

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      RISE_FALL_A <= '0';
    elsif rising_edge(SDCLK) then
      RISE_FALL_A <= '0';
      if (RISE_FALL_A='0' and DDR_A_RD_RISE_EF='0') or
         (RISE_FALL_A='1' and DDR_A_RD_FALL_EF='1') then
        RISE_FALL_A <= '1';
      end if;
    end if;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      RD_FIFO_WR_A <= '0';
    elsif rising_edge(SDCLK) then
      RD_FIFO_WR_A <= '0';
      if (RISE_FALL_A='0' and DDR_A_RD_RISE_EF='0') or
         (RISE_FALL_A='1' and DDR_A_RD_FALL_EF='0') then
        RD_FIFO_WR_A <= '1';
      end if;
    end if;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      RD_COUNT_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if RD_FIFO_WR_A='1' then
        RD_COUNT_A <= RD_COUNT_A + 1;
      end if;
    end if;
  end process;

  RD_FIFO_DIN_A <= DDR_A_RD_DATA(31 downto 0) when RISE_FALL_A='1' else DDR_A_RD_DATA(63 downto 32);

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      RIP_A <= '0';
    elsif rising_edge(SDCLK) then
      RIP_A <= '0';
      if (RIP_A='0' and READ_ZERO_A='0' and RD_FIFO_AF_A='1') or
         (RIP_A='1' and RIP_DONE_A='0') then
        RIP_A <= '1';
      end if;
    end if;
  end process;

  RIP_DONE_A <= RD_FIFO_WR_A AND RD_COUNT_A(1) AND RD_COUNT_A(0);

  DDR_A_RD_ADDR_WEN <= (NOT RIP_A) AND (NOT READ_ZERO_A) AND RD_FIFO_AF_A;

  DDR_A_RD_ADDR <= RD_ADDRESS_A & "00";

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      RD_ADDRESS_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if ADDR_EN='1' then
        RD_ADDRESS_A <= (others=>'0');
      elsif (RD_FIFO_WR_A='1' and RD_COUNT_A="11") then
        RD_ADDRESS_A <= RD_ADDRESS_A + 1;
      end if;
    end if;
  end process;

  iRD_FIFO_A : FIFO16x32
    port map (
      RESET    => RESET,
      CLOCK    => SDCLK,
      DIN      => RD_FIFO_DIN_A,
      WR_EN    => RD_FIFO_WR_A,
      RD_EN    => RD_FIFO_RD_A,
      DOUT     => RD_FIFO_OUT_A,
      FULL     => open,
      EMPTY    => RD_FIFO_EF_A,
      WR_COUNT => RD_FIFO_WR_CT_A,
      RD_COUNT => open );

  -- Indicate almost full when 3 words to write or less
  RD_FIFO_AF_A <= '0' when RD_FIFO_WR_CT_A(4 downto 2)="000" else '1';

  -------------------------------------------------------------
  -- DDR SDRAM Data Check

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      DATA_REG_A <= (others=>'0');
    elsif rising_edge(SDCLK) then
      if RD_FIFO_WR_A='1' then
        DATA_REG_A <= RD_FIFO_DIN_A;
      end if;
    end if;
  end process;

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      DATA_CHECK_A <= '0';
    elsif rising_edge(SDCLK) then
      DATA_CHECK_A <= RD_FIFO_WR_A;
    end if;
  end process;

  DATA_COMPARE_A <= '1' when READ_DATA_A=DATA_REG_A else '0';

  process(RESET, SDCLK)
  begin
    if RESET='1' then
      DATA_ERROR_A <= '0';
    elsif rising_edge(SDCLK) then
      if DATA_COMPARE_A='0' and DATA_CHECK_A='1' then
        DATA_ERROR_A <= '1';
      end if;
    end if;
  end process;

  -------------------------------------------------------------
  -- Transfer DDR SDRAM Data to HERON Output FIFO

  RD_FIFO_RD_A <= (NOT OUT_FIFO_AF) AND RD_FIFO_EF_A;

  OUT_FIFO_WR  <= (NOT OUT_FIFO_AF) AND RD_FIFO_EF_A;

  RD_FIFO_OUT <= RD_FIFO_OUT_A;

  iOUT_FIFO : fifo15x32
    port map (
      din          => RD_FIFO_OUT,
      wr_en        => OUT_FIFO_WR,
      wr_clk       => SDCLK,
      rd_en        => OUT_FIFO_RD,
      rd_clk       => FCLK_G,
      ainit        => RESET,
      dout         => OUTFIFO_D,
      full         => open,
      empty        => OUT_FIFO_EF,
      almost_full  => OUT_FIFO_AF,
      almost_empty => open );

  OUT_FIFO_RD <= OUTFIFO_READY(0) AND (NOT OUT_FIFO_EF);

  process(RESET, FCLK_G)
  begin
    if RESET='1' then
      OUTFIFO_WRITE(0) <= '0';
    elsif rising_edge(FCLK_G) then
      OUTFIFO_WRITE(0) <= OUT_FIFO_RD;
    end if;
  end process;

  OUTFIFO_WRITE(1) <= '0';
  OUTFIFO_WRITE(2) <= '0';
  OUTFIFO_WRITE(3) <= '0';
  OUTFIFO_WRITE(4) <= '0';
  OUTFIFO_WRITE(5) <= '0';

  -------------------------------------------------------------
  -- Serial Bus

  iHSB_BUFG : BUFG port map (I=>HSB_CLK, O=>HSB_CLOCK);

  process (OSC3)
  begin
    if rising_edge(OSC3) then
      HSB_CLK <= NOT HSB_CLK;
    end if;
  end process;

  MSG_CLK <= HSB_CLOCK;  -- clock for Message Interface

  iHSB2 : HSB2
    port map (
      RST          => RESET,
      CLK          => HSB_CLOCK,
      DIN          => MSG_DIN,
      ADDR         => MSG_ADDR,
      AEN          => MSG_AEN,
      WEN          => MSG_WEN,
      REN          => MSG_REN,
      DONE         => MSG_DONE,
      COUNT        => MSG_COUNT,
      CLEAR        => MSG_CLEAR,
      READY        => MSG_READY,
      SEND_MSG     => MSG_SEND_MSG,
      CE           => MSG_CE,
      DOUT         => MSG_DOUT,
      SEND_ID      => MSG_SEND_ID,
      LAST_BYTE    => MSG_LAST_BYTE );

  -------------------------------------------------------------
  -- Connector Digital IO (not used in this example)

  CONN_A_OUT <= (others=>'0');
  CONN_A_EN  <= (others=>'1');

  CONN_B_OUT <= (others=>'0');
  CONN_B_EN  <= (others=>'1');

  CONN_C_OUT <= (others=>'0');
  CONN_C_EN  <= (others=>'1');

  CONN_D_OUT <= (others=>'0');
  CONN_D_EN  <= (others=>'1');

  CONN_E_OUT <= (others=>'0');
  CONN_E_EN  <= (others=>'1');

  CONN_F_OUT <= (others=>'0');
  CONN_F_EN  <= (others=>'1');

  -------------------------------------------------------------
  -- Led Flasher : dividing F_CLKG clock by 2**24

  process(RESET, FCLK_G)
  begin
    if RESET='1' then
      LEDcount <= (others=>'0');
    elsif rising_edge(FCLK_G) then
      LEDcount <= LEDcount + 1;
    end if;
  end process;

  LED(4) <= LEDcount(24);

  LED(0) <= NOT (DATA_SEL(0) OR DATA_ERROR_A);
  LED(1) <= NOT (DATA_SEL(1) OR DATA_ERROR_A);
  LED(2) <= NOT (DATA_SEL(2) OR DATA_ERROR_A);
  LED(3) <= NOT (DATA_SEL(3) OR DATA_ERROR_A);

end EXAMPLE2;
