--******************************************************************************
--* @short      12 bit BX counter used for the read address in the FIFOs of the
--*             Input Chips and Sort Chip. Also used as reference bunch counter
--*             in the ROP chip.
--*
--*             Includes the delay from BCReset to reset of counter. (this delay
--*             is the same in all GMT chips).
--*             Also generates the L1 accept pulse for either 3 or 5 bx (as
--*             configured by VME). In 3bx mode, an extra flip-flop is added to the
--*             reset delay so that the delay settign does not have to be
--*             changed when switching from 3bx to 5bx mode.
--*
--*             The minimum programmable delay (both SRL16 set to 0000) from BCReset
--*             to L1A for bunch crossing 0 is 4bx
--*             (in 3 bx mode: 2x SRL16 + 1 extra FF + 1 bx read before main bx).
--*             (in 5 bx mode: 2x SRL16 + 2 bx read before main bx).
--*             The maximum delay between BCReset and L1A for BX 0 (bot SRL set
--*             to 1111), is 4+15 = 19 bx.
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv5.cern.ch>
--* @date    $Date: 2004/12/17 09:30:37 $
--* @version $Revision: 1.3 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_std.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VCOMPONENTS.all;
-- pragma translate_on


entity BXReadCounter is
  generic (
    lat_delay_reg_addr : integer);      -- address of LATENCY delay register
  port (
    iBCReset          : in std_logic;   -- bcreset after input FF and decoding
    iL1A              : in std_logic;   -- L1A after input FF and decoding

    oDo5BX            : out std_logic;

    oBXReadCounter    : out std_logic_vector(11 downto 0);
    oL1A_pulse        : out std_logic;

    -- VME port (for latency delay register)
    vme_addr       : in    std_logic_vector;
    vme_data       : in    std_logic_vector;
    vme_en         : in    std_logic;
    vme_wr         : in    std_logic;

    vme_data_out   : out   std_logic_vector(15 downto 0);
    vme_en_out     : out   std_logic;

    -- Clock, control
    clk            : in    std_logic;
    reset          : in    std_logic    -- asynch reset
    );  

end entity BXReadCounter;


architecture behavioral of BXReadCounter is

  component SRL16
-- synthesis translate_off
    generic (
      INIT: bit_vector:= X"0001");
-- synthesis translate_on
    port (Q : out STD_ULOGIC;
          A0 : in STD_ULOGIC;
          A1 : in STD_ULOGIC;
          A2 : in STD_ULOGIC;
          A3 : in STD_ULOGIC;
          CLK : in STD_ULOGIC;
          D : in STD_ULOGIC);
  end component;

  signal sLAT_DelayReg : std_logic_vector(15 downto 0);
  signal bcres_delayed : std_logic;
  signal bcres_srl1    : std_logic;
  signal bcres_srl2    : std_logic;
  signal bcres_srl2_d  : std_logic;

  signal sDo5BX        : std_logic;
  
  signal sL1A_d1 : std_logic;
  signal sL1A_d2 : std_logic;
  signal sL1A_d3 : std_logic;
  signal sL1A_d4 : std_logic;

begin  -- architecture behavioral

  -----------------------------------------------------------------------------
  --  Configuration Register
  -----------------------------------------------------------------------------
  --
  -- 0   0   0   0  |  0   0   0   0   |  0   0   0   0   |  0   0   0   0
  -- |   |   |   |                     | LAT delay2       |  LAT delay1      
  -- |   
  -- |   
  -- +================ do five BX readout (1) / do three BX readout (0)
  -- 
  --
  
  readout_sync_reg: entity work.VMEReg
    generic map (
      -- *** change the default here, to simulate different latencies or to
      -- switch from 3bx mode to 5bx mode ***
      init_val            => "0000000000001000",
      my_vme_base_address => lat_delay_reg_addr )
    port map (
      data         => sLAT_DelayReg,        
      reset        => reset,
      
      vme_addr     => vme_addr,
      vme_data     => vme_data,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out,
      vme_en_out   => vme_en_out,
      vme_clk      => clk);

  sDo5BX <= sLAT_DelayReg(15);
  oDo5BX <= sDo5BX;

  -----------------------------------------------------------------------------
  -- BCReset delay for ROP read counter = LATENCY
  -----------------------------------------------------------------------------

  bcres_lat_delay1_block: SRL16
    port map (
      D   => iBCReset,
      Q   => bcres_srl1,
      A0  => sLAT_DelayReg(0),
      A1  => sLAT_DelayReg(1),
      A2  => sLAT_DelayReg(2),
      A3  => sLAT_DelayReg(3),
      CLK => clk);


  bcres_lat_delay2_block: SRL16
    port map (
      D   => bcres_srl1,
      Q   => bcres_srl2,
      A0  => sLAT_DelayReg(4),
      A1  => sLAT_DelayReg(5),
      A2  => sLAT_DelayReg(6),
      A3  => sLAT_DelayReg(7),
      CLK => clk);

  delay_more: process (clk, reset) is
  begin  -- process delay_more
    if reset = '1' then
      bcres_srl2_d <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      bcres_srl2_d <= bcres_srl2;
    end if;
  end process delay_more;

  -- need to start read counter 1 bx later in 5bx mode.
  -- it then starts reading data one bx lower.
  bcres_delayed <= bcres_srl2_d when sDo5BX = '1' else bcres_srl2;

  -----------------------------------------------------------------------------
  -- BX read (or reference) counter
  -----------------------------------------------------------------------------
  bx_counter: process (clk, reset) is
    variable counter : std_logic_vector(11 downto 0) := "000000000000";
                            
  begin
    if reset = '1' then
      counter := "000000000000";
      oBXReadCounter <= "000000000000";
    elsif clk'event and clk = '1' then
      if bcres_delayed = '1' then
        counter := "000000000000";
      else
        counter := std_logic_vector(TO_UNSIGNED(TO_INTEGER(UNSIGNED(counter))+1,12));
      end if;      
    end if;
    oBXReadCounter <= counter;
  end process bx_counter;


  -----------------------------------------------------------------------------
  -- make l1 pulse for 3 (5) bx
  -----------------------------------------------------------------------------
  
  delay_l1a: process (clk, reset) is
  begin  -- process delay_l1a
    if reset = '1' then
      sL1A_d1 <= '0';
      sL1A_d2 <= '0';
      sL1A_d3 <= '0';
      sL1A_d4 <= '0';    
    elsif clk'event and clk = '1' then  -- rising clock edge
      sL1A_d1 <= iL1A;
      sL1A_d2 <= sL1A_d1;
      sL1A_d3 <= sL1A_d2;
      sL1A_d4 <= sL1A_d3;
    end if;
  end process delay_l1a;

  oL1A_pulse <= iL1A or sL1A_d1 or sL1A_d2 or ( ( sL1A_d3 or sL1A_d4) and  sDo5BX );

  
end architecture behavioral;