library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
USE work.ipbus.all;
USE work.ipbus_reg_types.all;
USE work.fmcTLU.all;

entity triggerInputs_newTLU_tb is
  generic (
    g_NUM_INPUTS  : natural  := 6;
    g_IPBUS_WIDTH : positive := 32
    );
end;

architecture bench of triggerInputs_newTLU_tb is

  component triggerInputs_newTLU
     GENERIC( 
        g_NUM_INPUTS  : natural  := g_NUM_INPUTS;
        g_IPBUS_WIDTH : positive := g_IPBUS_WIDTH
        );
     PORT(
        clk_4x_logic         : IN     std_logic;
        clk_200_i : IN     std_logic;
        strobe_4x_logic_i    : IN     std_logic;
        threshold_discr_p_i  : IN     std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
        threshold_discr_n_i  : IN     std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
        reset_i              : IN     std_logic;
        trigger_times_o      : OUT    t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
        trigger_o            : OUT    std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
        edge_rising_times_o  : OUT    t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
        edge_falling_times_o : OUT    t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
        edge_rising_o        : OUT    std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
        edge_falling_o       : OUT    std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
        ipbus_clk_i          : IN     std_logic;
        ipbus_reset_i        : IN     std_logic;
        ipbus_i              : IN     ipb_wbus;
        ipbus_o              : OUT    ipb_rbus;
        clk_8x_logic_i      : IN     std_logic;
        strobe_8x_logic_i   : IN     std_logic
     );
  end component;

  signal clk_4x_logic: std_logic := '0';
  signal clk_200_i: std_logic;
  signal strobe_4x_logic_i: std_logic;
  signal threshold_discr_p_i: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
  signal threshold_discr_n_i: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
  signal reset_i: std_logic;
  signal trigger_times_o: t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
  signal trigger_o: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
  signal edge_rising_times_o: t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
  signal edge_falling_times_o: t_triggerTimeArray (g_NUM_INPUTS-1 DOWNTO 0);
  signal edge_rising_o: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
  signal edge_falling_o: std_logic_vector (g_NUM_INPUTS-1 DOWNTO 0);
  signal ipbus_clk_i: std_logic;
  signal ipbus_reset_i: std_logic;
  signal ipbus_i: ipb_wbus;
  signal ipbus_o: ipb_rbus;
  signal clk_8x_logic_i: std_logic;
  signal clk_logic : std_logic;
  signal strobe_8x_logic_i: std_logic ;
  constant C_NUM_STROBE_TAPS : positive := 2;  --! Adjust to shift strobes relative to 40MHz clock edge
  signal s_clk40_delayed_160 : std_logic_vector(C_NUM_STROBE_TAPS downto 0); --! Shift register used to generate clock_4x strobe. Adjust length for correct alignment with incoming clock
  signal s_clk40_delayed_320 : std_logic_vector((2*C_NUM_STROBE_TAPS)+1 downto 0);  --! Shift register used to generate clock_8x strobe. Adjust length for correct alignment with incoming clock

   signal s_dut_clk, s_clocks_locked , s_logic_reset : std_logic;


  constant delta : time := 0.02 ns; -- make sure IPBus clock drifts w.r.t.
                                    -- logic clocks
  constant clockLogic_period : time := 25 ns; -- 40MHz clock
  --constant clock320_period: time := 3.125 ns; -- 320 MHz clock
  constant clock200_period: time := 5 ns + delta; -- 200 MHz clock
  constant clockipbus_period: time := 31.25 ns + delta; -- 320 MHz clock

  signal stop_the_clock: boolean;

begin

  -- Insert values for generic parameters !!
  uut: triggerInputs_newTLU generic map ( g_NUM_INPUTS         => g_NUM_INPUTS,
                                          g_IPBUS_WIDTH        => g_IPBUS_WIDTH )
                               port map ( clk_4x_logic         => clk_4x_logic,
                                          clk_200_i            => clk_200_i,
                                          strobe_4x_logic_i    => strobe_4x_logic_i,
                                          threshold_discr_p_i  => threshold_discr_p_i,
                                          threshold_discr_n_i  => threshold_discr_n_i,
                                          reset_i              => s_logic_reset,
                                          trigger_times_o      => trigger_times_o,
                                          trigger_o            => trigger_o,
                                          edge_rising_times_o  => edge_rising_times_o,
                                          edge_falling_times_o => edge_falling_times_o,
                                          edge_rising_o        => edge_rising_o,
                                          edge_falling_o       => edge_falling_o,
                                          ipbus_clk_i          => ipbus_clk_i,
                                          ipbus_reset_i        => ipbus_reset_i,
                                          ipbus_i              => ipbus_i,
                                          ipbus_o              => ipbus_o,
                                          clk_8x_logic_i       => clk_8x_logic_i,
                                          strobe_8x_logic_i    => strobe_8x_logic_i );

  stimulus: process
  begin
      stop_the_clock <= false;
    -- Put initialisation code here
      reset_i <= '1';
      ipbus_reset_i <= '1';
      wait for clockLogic_period * 16;
      reset_i <= '0';
      ipbus_reset_i <= '0';
      
      wait for clockLogic_period * 500;

    -- Put test bench stimulus code here

      stop_the_clock <= true;
      reset_i <= '1';
      wait;
  end process;

  clockGenerator: ENTITY work.logic_clocks
   port map (
        ipbus_clk_i           => ipbus_clk_i,
        ipbus_i               => ipbus_i,
        ipbus_reset_i         => ipbus_reset_i,
        Reset_i               => reset_i,
        clk_logic_xtal_i      => clk_logic,
        clk_8x_logic_o        => clk_8x_logic_i,
        clk_4x_logic_o        => clk_4x_logic,
        ipbus_o               => ipbus_o,
        strobe_8x_logic_o    =>  strobe_8x_logic_i,
        strobe_4x_logic_o    =>  strobe_4x_logic_i,
        DUT_clk_o            => s_dut_clk,
        logic_clocks_locked_o => s_clocks_locked,
        logic_reset_o         => s_logic_reset
    );


  clockLogic: process
  begin
    while not stop_the_clock loop
      clk_logic <= '0', '1' after clockLogic_period / 2;
      wait for clockLogic_period;
    end loop;
    wait;
  end process;
  
  clockIpbus: process
  begin
    while not stop_the_clock loop
      ipbus_clk_i <= '0', '1' after clockipbus_period / 2;
      wait for clockipbus_period;
    end loop;
    wait;
  end process;

  clock200: process
  begin
    while not stop_the_clock loop
      clk_200_i <= '0', '1' after clock200_period / 2;
      wait for clock200_period;
    end loop;
    wait;
  end process;

end;
  
