--******************************************************************************
--* @short      The InChip VME Logic
--*
--*             contains input and output FF's for VME signals
--*             and the logic to generate a DTACK signal
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv3.cern.ch>
--* @date    $Date: 2004/12/17 09:30:37 $
--* @version $Revision: 1.2 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;

entity InChipVMELogic is
  port (
    -- VME port ( these are the unregistered chip ports)
    vme_addr   : in    std_logic_vector(19 downto 1);
    vme_data   : inout std_logic_vector(15 downto 0);
    vme_en     : in    std_logic;
    vme_wr     : in    std_logic;
    vme_ndtack : out   std_logic;       -- low active 
    vme_nirq   : out   std_logic;       -- low active
                                        
    -- VME signal to chip logic
    vme_addr_i : out   std_logic_vector(19 downto 1);
    vme_data_i : out   std_logic_vector(15 downto 0);
    vme_en_i   : out   std_logic;
    vme_wr_i   : out   std_logic;


    -- VME signals coming back form chip logic
    vme_data_out   : in std_logic_vector(15 downto 0);
    vme_en_out     : in std_logic;      -- 1 if VME address was valid and
                                        -- addresse any register/RAM in the chip

    clk        : in std_logic;
    reset      : in std_logic);
end;


architecture behavioral of InChipVMELogic is
  attribute syn_useioff               : boolean;
  attribute syn_useioff of behavioral : architecture is true;

  signal vme_en_reg       : std_logic;
  signal vme_wr_reg       : std_logic;
  
  signal vme_wr_d         : std_logic;
  signal vme_en_out_d     : std_logic;
  signal vme_en_out_pulse : std_logic;

begin
  -----------------------------------------------------------------------------
  -- Input flip-flops
  -----------------------------------------------------------------------------  
  register_vmeinputs : process (clk, reset) is
  begin
    if reset = '1' then
      vme_data_i <= (others => '0');
      vme_addr_i <= (others => '0');
      vme_en_reg   <= '0';
      vme_wr_reg   <= '0';
    elsif (clk'event and clk = '1') then
      vme_data_i <= vme_data;
      vme_addr_i <= vme_addr;
      vme_en_reg   <= vme_en;
      vme_wr_reg   <= vme_wr;
    end if;
  end process register_vmeinputs;

  vme_en_i <= vme_en_reg;
  vme_wr_i <= vme_wr_reg;

  -- delay vme write signal
  delay_vme_wr : process (clk, reset) is
  begin
    if reset = '1' then
      vme_wr_d   <= '0';
    elsif (clk'event and clk = '1') then
      vme_wr_d <= vme_wr_reg;
    end if;
  end process delay_vme_wr;

  -- delay vme enable out signal
  delay_enable_out: process (clk, reset) is
  begin  -- process generate_dtack
    if reset = '1' then            
      vme_en_out_d <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      vme_en_out_d <= vme_en_out;
    end if;
  end process delay_enable_out;

  vme_en_out_pulse <= vme_en_out and not vme_en_out_d;
  
  -----------------------------------------------------------------------------
  -- generate DTACK
  -----------------------------------------------------------------------------
  generate_dtack: process (clk, reset) is
  begin  -- process generate_dtack
    if reset = '1' then            
      vme_ndtack <= '1';
    elsif clk'event and clk = '1' then  -- rising clock edge
      -- set dtack when any register in the chip is selected
      if vme_en_out_pulse = '1'  then
        vme_ndtack <= '0';

      -- clear dtack when vme_enable is clear
      -- cannot use falling edge of vme enable since there is only a pulse when
      -- writing
      elsif vme_en_reg = '0' then
        vme_ndtack <= '1';
      end if;
    end if;
  end process generate_dtack;

  -----------------------------------------------------------------------------
  -- VME data output/enable FF's
  -----------------------------------------------------------------------------
  register_vmeoutputs : process (clk, reset) is
  begin
    if reset = '1' then
      vme_data <= (others => 'Z');
    elsif (clk'event and clk = '1') then
      -- data is ready to be written when vme_en_out is '1'
      -- also require vme_en_reg to be active in order to shorten the VME cycle
      if (vme_en_reg = '1' and vme_en_out = '1' and vme_wr_d = '0') then
        vme_data <= vme_data_out;
      else
        vme_data <= (others => 'Z');
      end if;
    end if;
  end process register_vmeoutputs;

  vme_nirq <= '1';

end architecture behavioral;