--******************************************************************************
--* @short   Readout logic that goes into the Input or Sort FPGA
--*             
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv5.cern.ch>
--* @version $Revision: 1.5 $
--* @date    $Date: 2004/12/17 09:30:38 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_std.all;
use work.ReadOutBufTypes.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VCOMPONENTS.all;
-- pragma translate_on

entity ReadOutLogic is
  
  generic (
    nwords : integer := 4; -- width of readout logic in 32bit words
                           -- not counting on 32bit reg for the bx counter

    lat_delay_reg_addr : integer);      -- address of LATENCY delay register
  port (
    data           : in TReadoutData_vec(0 to nwords-1);
    mondata        : in TReadoutMonData_vec(0 to 2*(nwords+1)-1 );
    iBXCount       : in std_logic_vector(11 downto 0);
    
    iBCReset       : in std_logic;      -- BCReset from input FF (decoded)
    iL1A           : in std_logic;      -- L1A from input FF (decoded)
    iL1Reset       : in std_logic;      -- clears the FIFO

    -- 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;

    -- Readout port
    ro_data    : out std_logic_vector(23 downto 0);
    ro_rdfifo  : in std_logic;
    ro_fetch   : in std_logic;
    
    -- Clock, control
    clk            : in    std_logic;
    reset          : in    std_logic
    );  

end entity ReadOutLogic;


architecture behavioral of ReadOutLogic is

  signal sReadCounter : std_logic_vector(11 downto 0);
  signal read_addr    : std_logic_vector(8 downto 0);
  signal bccnt_word32 : std_logic_vector(31 downto 0);
  signal l1a_pulse    : std_logic;
  signal we_fifo      : std_logic;

  subtype TOutReg is std_logic_vector(15 downto 0);
  type TOutReg_vec is array (integer range <>) of TOutReg;

  signal out_regs     : TOutReg_vec(0 to (2*(nwords+1))-1);
  signal out_counter1 : integer := 0;
begin  -- architecture behavioral

  -----------------------------------------------------------------------------
  -- Read counter and L1A pulse generator
  -----------------------------------------------------------------------------

  read_counter: entity work.BXReadCounter
    generic map (
      lat_delay_reg_addr => lat_delay_reg_addr)
    port map (
      iBCReset       => iBCReset,
      iL1A           => iL1A,
      oDo5BX         => open,
      oBXReadCounter => sReadCounter,
      oL1A_pulse     => l1a_pulse,

      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,
      
      clk            => clk,
      reset          => reset);

  read_addr <= sReadCounter(8 downto 0);  -- ring buffers are 512 steps long

  -- need to delay the l1a pulse. l1a pulse comes synchronous with the
  -- read address, but reading the data takes one cycle.
  generate_fifo_we: process (clk, reset) is
  begin  -- process generate_fifo_we
    if reset = '1' then
      we_fifo <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      we_fifo <= l1a_pulse;
    end if;
  end process generate_fifo_we;

  
  -----------------------------------------------------------------------------
  -- instantiate the Readout Blocks
  -----------------------------------------------------------------------------
  bccnt_word32(31 downto 12) <= (others => '0');
  bccnt_word32(11 downto 0) <= iBXCount;
  
  rop_block_bc: entity work.ROPBlock32
    port map (
      data       => bccnt_word32,
      wr_addr    => iBXCount(8 downto 0),
      rd_addr    => read_addr,
      
      we_fifo    => we_fifo,
      rd_fifo    => ro_rdfifo,
      
      dout_low   => out_regs(0),
      dout_high  => out_regs(1),
      clk        => clk,
      sinit_fifo => iL1Reset);

  per_dataword: for i in 0 to (nwords -1) generate
  begin  -- generate per_dataword
    rop_block_data: entity work.ROPBlock32
      port map (
        data       => data(i),
        wr_addr    => iBXCount(8 downto 0),
        rd_addr    => read_addr,
        we_fifo    => we_fifo,
        rd_fifo    => ro_rdfifo,
        dout_low   => out_regs((i+1)*2),
        dout_high  => out_regs((i+1)*2+1),
        clk        => clk,
        sinit_fifo => iL1Reset);
  end generate per_dataword;


  -----------------------------------------------------------------------------
  -- steering for readout of FIFOs
  -----------------------------------------------------------------------------

  select_output: process (clk, reset) is
    variable out_counter : integer:= 0;                                
  begin  -- process select_output
    if reset = '1' then
      out_counter := 0;      
      out_counter1 <= out_counter;
    elsif clk'event and clk = '1' then  -- rising clock edge
      if ro_rdfifo = '1' then
        out_counter := 0;
      else
        if ro_fetch = '1' and (out_counter < ((nwords+1)*2-1)) then
          out_counter := out_counter+1;
        end if;
      end if;
      out_counter1 <= out_counter;
    end if;
  end process select_output;

  ro_data(15 downto 0)  <= out_regs(out_counter1);
  ro_data(23 downto 16) <= mondata(out_counter1);

  
end architecture behavioral;