--------------------------------------------------------------------------------
-- CERN (BE-CO-HT)
-- Converter Common Gateware  
-- https://www.ohwr.org/projects/conv-common-gw
--------------------------------------------------------------------------------
--
-- unit name:     Top-level simulation of conv_common_gw
--
-- description:
--
--   
--
--------------------------------------------------------------------------------
-- Copyright (c) 2010-2012 CERN / BE-CO-HT
--------------------------------------------------------------------------------
-- GNU LESSER GENERAL PUBLIC LICENSE
--------------------------------------------------------------------------------
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.genram_pkg.all;
use work.conv_common_gw_pkg.all;
use work.testbench_pkg.all;
use work.print_pkg.all;

entity testbench is
end entity testbench;


architecture behav of testbench is

  --============================================================================
  -- Functions and procedures
  --============================================================================

  --============================================================================
  -- Signal declarations
  --============================================================================

  signal i2c_m_in                      : t_i2c_master_in;
  signal i2c_m_out                     : t_i2c_master_out;

  signal clk_20, clk_125               : std_logic;
  signal clk_125_p, clk_125_n          : std_logic;
  signal vme_sysreset_n                : std_logic := '0';

  signal ttl_n_in, ttl_out             : std_logic_vector(C_NR_CHANS-1 downto 0) := (others => '1');
  signal rs485_n_in, rs485_fs_n_in     : std_logic_vector(C_NR_CHANS-1 downto 0) := (others => '1');
  signal rs485_out                     : std_logic_vector(C_NR_CHANS-1 downto 0) := (others => '1');
  signal inv_n_in, inv_out             : std_logic_vector(C_NR_INV_CHANS-1 downto 0) := (others => '0');
  
  signal sscl_out                      : std_logic;
  signal sscl_en_out                   : std_logic;
  signal ssda_out                      : std_logic;
  signal ssda_en_out                   : std_logic;
  
  signal mscl_out                      : std_logic;
  signal mscl_en_out                   : std_logic;
  signal msda_out                      : std_logic;
  signal msda_en_out                   : std_logic;
  
  signal sw_gp_n_in                    : std_logic_vector(7  downto 0);
  signal sw_other_in                   : std_logic_vector(31 downto 0);
  signal pcbrev                        : std_logic_vector(5  downto 0);
  signal rtm_in                        : std_logic_vector(5  downto 0);
  signal i2c_master_rcvd_val           : std_logic_vector(31 downto 0);
  signal i2c_master_rcvd_val1          : std_logic_vector(31 downto 0);
 
  signal mscl, msda                    : std_logic_vector(C_NR_MASTERS-1 downto 0);
  signal sscl, ssda                    : std_logic_vector(C_NR_SLAVES-1 downto 0);
  signal scl, sda                      : std_logic;

  signal rst_copm                      : std_logic;
  type cnt_ch_array                     is array (C_NR_CHANS-1 downto 0) of integer;
  signal fp_rp_same, fp_rp_oppos        : cnt_ch_array;
  signal in_out_oppos, in_out_same      : cnt_ch_array;
  signal pulse_cnt_ttl, pulse_cnt_rs485 : cnt_ch_array;
  signal inv_err                        : cnt_ch_array;

  type cnt_inv_ch_array                 is array (C_NR_INV_CHANS-1 downto 0) of integer;


  --==============================================================================
  --  architecture begin
  --==============================================================================
begin

  --============================================================================
  -- Instantiate DUT
  --============================================================================
  cmp_DUT: conv_ttl_rs485
  generic map (g_simul     => false)
  port map
  (
    -- Clocks
    clk_20_i                => clk_20,
    clk_125_p_i             => clk_125_p,
    clk_125_n_i             => clk_125_n,
    -- I2C interface
    scl_i                   => scl,
    scl_o                   => sscl_out,
    scl_en_o                => sscl_en_out,
    sda_i                   => sda,
    sda_o                   => ssda_out,
    sda_en_o                => ssda_en_out,
    -- VME interface
    vme_sysreset_n_i        => vme_sysreset_n,
    vme_ga_i                => "11110", --
    vme_gap_i               => '0',
    -- PCB version recognition
    pcbrev_i				=> pcbrev,
    -- Channel enable
    global_oen_o            => open,
    ttl_oen_o               => open,
    inv_oen_o               => open,
    rs485_oen_o             => open,
    -- Front panel channels
    ttl_n_i                 => ttl_n_in,
    ttl_o                   => ttl_out,
    inv_n_i                 => inv_n_in,
    inv_o                   => inv_out,
    -- Rear panel channels
    rs485_n_i               => rs485_n_in,
    rs485_fs_n_i            => rs485_fs_n_in,
    rs485_o                 => rs485_out,
    -- Rear input and output termination lines
    iterm_en_o              => open,
    oterm_en_o              => open,
    -- Channel leds
    led_front_n_o           => open,
    led_front_inv_n_o       => open,
    led_rear_n_o            => open,
    -- SPI interface to on-board flash chip
    flash_cs_n_o            => open,
    flash_sclk_o            => open,
    flash_mosi_o            => open,
    flash_miso_i            => 'Z',
    -- PLL DACs
    dac20_din_o             => open,
    dac20_sclk_o            => open,
    dac20_sync_n_o          => open,
    dac125_din_o            => open,
    dac125_sclk_o           => open,
    dac125_sync_n_o         => open,
    -- SFP lines
    sfp_los_i               => '1',
    sfp_present_i           => '0',
    sfp_rate_select_o       => open,
    sfp_sda_b               => open,
    sfp_scl_b               => open,
    sfp_tx_disable_o        => open,
    sfp_tx_fault_i          => '1',
    -- Thermometer data port
    thermometer_b           => open,
    -- Switches
    sw_gp_n_i               => sw_gp_n_in,
    sw_multicast_n_i        => (others => '0'), -- not used
    -- RTM lines
    rtmm_i                  => rtm_in(5 downto 3),
    rtmp_i                  => rtm_in(2 downto 0),
    -- Front panel bicolor LEDs
    led_ctrl0_o             => open,
    led_ctrl0_oen_o         => open,
    led_ctrl1_o             => open,
    led_ctrl1_oen_o         => open,
    led_gp_2_4_o            => open,
    led_gp_1_3_o            => open,
    led_oterm_wr_o          => open,
    led_iterm_syserror_o    => open,
    led_gf_syspw_o          => open,
    led_ttl_i2c_o           => open);


 
  sscl(0) <= sscl_out when (sscl_en_out = '1') else '1';
  ssda(0) <= ssda_out when (ssda_en_out = '1') else '1';


  --============================================================================
  -- Generate clock and reset signals
  --============================================================================
  p_clk_20 : process
  begin
    clk_20 <= '0';
    wait for C_CLK_20_PER/2;
    clk_20 <= '1';
    wait for C_CLK_20_PER/2;
  end process;

  p_clk_125 : process
  begin
    clk_125 <= '0';
    wait for C_CLK_125_PER/2;
    clk_125 <= '1';
    wait for C_CLK_125_PER/2;
  end process;

  clk_125_p <= clk_125;
  clk_125_n <= not clk_125;
  
  p_vme_sysreset_n: process
  begin
    vme_sysreset_n <= '0';
    wait for c_reset_width;
    vme_sysreset_n <= '1';
    wait for c_reset_width;
    vme_sysreset_n <= '0';
    wait for c_reset_width;
    vme_sysreset_n <= '1';
    wait;
  end process p_vme_sysreset_n;


  --============================================================================
  -- Instantiate I2C master to access DUT
  --============================================================================

  cmp_i2c_master_and_driver: entity work.i2c_master_and_driver
    port map (
      clk_i                            => clk_20,    
      rst_n_i                          => vme_sysreset_n,
      ready_o                          => i2c_m_out.i2c_master_ready,
      start_i                          => i2c_m_in.i2c_master_start,
      finish_o                         => i2c_m_out.i2c_master_finish,
      rdwr_i                           => i2c_m_in.i2c_master_rdwr,
      slv_addr_i                       => i2c_m_in.i2c_master_slv_addr,
      reg_addr_i                       => i2c_m_in.i2c_master_reg_addr,
      send_val_i                       => i2c_m_in.i2c_master_send_val,
      rcvd_val_o                       => i2c_m_out.i2c_master_rcvd_val,
      
      scl_i                            => scl,
      scl_o                            => mscl_out,
      scl_oen                          => mscl_en_out,
      sda_i                            => sda,
      sda_o                            => msda_out,
      sda_oen                          => msda_en_out
  );
   
  -- Tri-state buffers on the I2C lines
  mscl(0) <= mscl_out when (mscl_en_out = '0') else '1';
  msda(0) <= msda_out when (msda_en_out = '0') else '1';
  
  --============================================================================
  -- Bus model connection to master and slaves
  --============================================================================
  cmp_i2c_bus : entity work.i2c_bus_model
    generic map(
      g_nr_masters => C_NR_MASTERS,
      g_nr_slaves  => C_NR_SLAVES
    )
    port map (
      mscl_i => mscl,
      msda_i => msda,
      sscl_i => sscl,
      ssda_i => ssda,
      scl_o  => scl,
      sda_o  => sda
    );


  --============================================================================
  -- Check if ttl_out matches rs485_out
  --============================================================================
  compare_front_rear_pulses: process (clk_125)
  begin
    if rising_edge (clk_125) then
      if vme_sysreset_n = '0' or rst_copm = '1' then
        fp_rp_same   <= (others=> (0));
        fp_rp_oppos  <= (others=> (0));
        in_out_same  <= (others=> (0));
        in_out_oppos <= (others=> (0));
      else
        for i in 0 to C_NR_CHANS-1 loop
          if ttl_out(i) /= rs485_out(i) then
            fp_rp_same(i) <= fp_rp_same(i)+1;
          end if;

          if ttl_out(i) /= not rs485_out(i) then
            fp_rp_oppos(i) <= fp_rp_oppos(i)+1;
          end if;

          if ttl_out(i) /= not ttl_n_in(i) then
            in_out_oppos(i) <= in_out_oppos(i)+1;
          end if;

          if ttl_out(i) /= ttl_n_in(i) then
            in_out_same(i) <= in_out_same(i)+1;
          end if;

        end loop;
      end if;
    end if;
  end process;

  --============================================================================
  -- Check INV channels
  --============================================================================
  compare_inv_i_inv_o: process (clk_125)
  begin
    if rising_edge (clk_125) then
      if vme_sysreset_n = '0' then
        inv_err  <= (others=> (0));
      else
        for i in 0 to C_NR_INV_CHANS-1 loop
          if inv_n_in(i) /= inv_out(i) then
            inv_err(i) <= inv_err(i)+1;
          end if;
        end loop;
      end if;
    end if;
  end process;


  --============================================================================
  -- pulse counter
  --============================================================================
  pulse_counter_ttl: process (ttl_out)
  begin
      if vme_sysreset_n = '0' then
        pulse_cnt_ttl  <= (others=> (0));
      end if;
    --for i in 0 to C_NR_CHANS-1 loop
      if rising_edge(ttl_out(0)) then
        pulse_cnt_ttl(0) <= pulse_cnt_ttl(0) +1;
      end if;
      if rising_edge(ttl_out(1)) then
        pulse_cnt_ttl(1) <= pulse_cnt_ttl(1) +1;
      end if;
      if rising_edge(ttl_out(2)) then
        pulse_cnt_ttl(2) <= pulse_cnt_ttl(2) +1;
      end if;
      if rising_edge(ttl_out(3)) then
        pulse_cnt_ttl(3) <= pulse_cnt_ttl(3) +1;
      end if;
      if rising_edge(ttl_out(4)) then
        pulse_cnt_ttl(4) <= pulse_cnt_ttl(4) +1;
      end if;
      if rising_edge(ttl_out(5)) then
        pulse_cnt_ttl(5) <= pulse_cnt_ttl(5) +1;
      end if;
    --end loop;
  end process pulse_counter_ttl;

  pulse_counter_rs485: process (rs485_out)
  begin
      if vme_sysreset_n = '0' then
        pulse_cnt_rs485  <= (others=> (0));
      end if;
    --for i in 0 to C_NR_CHANS-1 loop
      if rising_edge(rs485_out(0)) then
        pulse_cnt_rs485(0) <= pulse_cnt_rs485(0) +1;
      end if;
      if rising_edge(rs485_out(1)) then
        pulse_cnt_rs485(1) <= pulse_cnt_rs485(1) +1;
      end if;
      if rising_edge(rs485_out(2)) then
        pulse_cnt_rs485(2) <= pulse_cnt_rs485(2) +1;
      end if;
      if rising_edge(rs485_out(3)) then
        pulse_cnt_rs485(3) <= pulse_cnt_rs485(3) +1;
      end if;
      if rising_edge(rs485_out(4)) then
        pulse_cnt_rs485(4) <= pulse_cnt_rs485(4) +1;
      end if;
      if rising_edge(rs485_out(5)) then
        pulse_cnt_rs485(5) <= pulse_cnt_rs485(5) +1;
      end if;
    --end loop;
  end process pulse_counter_rs485;

  --============================================================================
  -- processes to provide stimulus and checks
  --============================================================================

  --i2c access
  p_stim : process
  variable i                        : integer := 0;
  variable nb_pulses_to_send_fp     : integer := 17;
  variable nb_pulses_to_send_fp_slv : std_logic_vector(31 downto 0);
  variable nb_pulses_to_send_rp     : integer := 5;
  variable nb_pulses_to_send_rp_slv : std_logic_vector(31 downto 0);
  variable nb_pulses_to_send_inv    : integer := 5;
  variable nb_pulses_to_send_bar    : integer := 6;
  variable glitch_filter_en         : std_logic := '0'; -- glitch filter disabled
  variable ttl_out_bar_en           : std_logic := '0'; -- TTLbar disabled
  variable err_cnt, err             : integer := 0;
  variable time_intrvl, rst_timetag : integer := 0;
  variable pulse_timetag            : integer := 0;
  constant K                        : time := 1 nS; 

  begin
    print("*****************************************************************************");
    print("                                 Start of Tests");
    print("*****************************************************************************");

    ---------------------------------------------------------------------------
    -- Board settings
    print_now("----------------------------------------------------------------");
    print_now("---> Configure board settings");
    settings_config (glitch_filter_en, ttl_out_bar_en, sw_gp_n_in, sw_other_in, pcbrev, rtm_in);

    ---------------------------------------------------------------------------
    -- VME reset
    print_now("----------------------------------------------------------------");
    print_now("---> VME reset");
    print_now("Sending VME reset");
    wait until vme_sysreset_n = '1';
    print_now("VME reset completed");
    wait for 6500 ns; -- for resets and inhibit_pulse to have finished
    rst_timetag := now/K;
    ---------------------------------------------------------------------------

    ---------------------------------------------------------------------------
    -- I2C readings
    print_now("----------------------------------------------------------------");
    print_now("---> Test 01: I2C reg reading");
    print_now("----------------------------------------------------------------");

    -- I2C reading of the board ID register
    print_now_s("I2C reading of the register ", c_REG_MAP(0).reg_name);
    read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(0).reg_addr, c_REG_MAP(0).reg_name, i2c_master_rcvd_val, C_BOARD_ID, TRUE, err);
    err_cnt := err_cnt +err;
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- I2C writing
    print_now("----------------------------------------------------------------");
    print_now("---> Test 02: I2C reg writing"); 
    print_now("----------------------------------------------------------------");

   -- I2C writing of a big value to Front Panel Counter 1
    print_now_s("I2C writing to the register ", c_REG_MAP(4).reg_name);
    write_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(4).reg_addr, c_REG_MAP(4).reg_name, C_INITIAL_TST_VALUE, err);
    err_cnt := err_cnt +err;
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- Pulses to the front TTL input
    print_now("----------------------------------------------------------------");
    print_now("---> Test 03: Sending TTL pulses and checking the outputs");
    print_now("----------------------------------------------------------------"); 

    -- Sending pulses to Front Panel Channel 1
    nb_pulses_to_send_fp_slv := std_logic_vector(to_unsigned(nb_pulses_to_send_fp, nb_pulses_to_send_fp_slv'length));
    print_now_s_i("Sending TTL pulses to TTL_N_I(0)", nb_pulses_to_send_fp); 
    generate_pulse (ttl_n_in(0), nb_pulses_to_send_fp, "fp", rs485_fs_n_in(0), 200ns, 200ns); -- 200ns so that the counters can count correctly

    -- Checking if the number of TTL output pulses matches the sent ones
    print_now("Check that the pulses arrived to the TTL_O(0)");
    if pulse_cnt_ttl(0) = nb_pulses_to_send_fp then
      print_now_s_i("[OK] Number of pulses measured at TTL_O(0): ",pulse_cnt_ttl(0));
    else
      print_now_s_i("[ERR] Number of pulses measured at TTL_O(0): ",pulse_cnt_ttl(0));
      err_cnt := err_cnt + 1;
    end if;

    -- Check if TTL_N_IN out and TTL_O out are opposite
    print_now("Check that TTL_O(0) is the inverted TTL_N_IN(0)");
    if in_out_oppos(0) = 0 then
      print_now("[OK] TTL_O(0) is exactly the inverted TTL_N_IN(0)");
    else
      print_now("[ERR] TTL_O(0) is not exactly the inverted TTL_N_IN(0)");
      err_cnt := err_cnt + 1;
    end if; 

    -- Check if TTL out and RS485 out are the same
    print_now("Check that the pulses arrived to the RS485_O(0)");
    if fp_rp_same(0) = 0 then
      print_now("[OK] RS485_O(0) matches TTL_O(0)");
    else
      print_now("[ERR] RS485_O(0) does not match TTL_O(0)");
      err_cnt := err_cnt + 1;
    end if; 
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- Counters reading
    print_now("----------------------------------------------------------------");
    print_now("---> Test 04: Reading of the pulse counters through I2C");
    print_now("----------------------------------------------------------------");

    -- Reading from the I2C Front Panel regs; read only two counters to speed up testbench
    while not(i = 3) loop
      if i = 0 then
        -- Front Panel Channel 1 register should roll over and read 
        print_now_s("I2C reading of the register ", c_REG_MAP(i+4).reg_name);
        read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(i+4).reg_addr, c_REG_MAP(i+4).reg_name , i2c_master_rcvd_val, std_logic_vector(unsigned(C_INITIAL_TST_VALUE)+unsigned(nb_pulses_to_send_fp_slv)), TRUE, err);
        err_cnt := err_cnt + err;
      elsif i = 1 then
        -- Front Panel Channel 2 register should have not counted any pulses 
        print_now_s("I2C reading of the register ", c_REG_MAP(i+4).reg_name);
        read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(i+4).reg_addr, c_REG_MAP(i+4).reg_name, i2c_master_rcvd_val, (others =>'0'), TRUE, err);
        err_cnt := err_cnt + err;
      end if;
      i := i + 1;
    end loop;

    print_now("Checking that the rear pulse counters have not registered any pulses");

    -- Reading from the I2C Rear Panel regs; read only two counters to speed up testbench
    i := 0;
    while not(i = 2) loop
      if i = 0 then
        -- Check Rear Panel Channel 1 counter has not counted any pulses
        print_now_s("I2C reading of the register ", c_REG_MAP(i+10).reg_name); 
        read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(i+10).reg_addr, c_REG_MAP(i+10).reg_name , i2c_master_rcvd_val, (others =>'0'), TRUE, err);
        err_cnt := err_cnt + err;
      elsif i = 1 then
        -- Check Rear Panel Channel 1 counter has not counted any pulses 
        print_now_s("I2C reading of the register ", c_REG_MAP(i+10).reg_name); 
        read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(i+10).reg_addr, c_REG_MAP(i+10).reg_name, i2c_master_rcvd_val, (others =>'0'), TRUE, err);
        err_cnt := err_cnt + err;
      end if;
      i := i + 1;
    end loop;
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- Pulses to the rear RS485 input
    print_now("----------------------------------------------------------------");
    print_now("---> Test 05: Sending pulses to the RS485 and checking the outputs");
    print_now("----------------------------------------------------------------");

    -- Sending pulses to Rear Panel Channel 1
    nb_pulses_to_send_rp := 5;
    nb_pulses_to_send_rp_slv := std_logic_vector(to_unsigned(nb_pulses_to_send_rp, nb_pulses_to_send_rp_slv'length));
    print_now_s_i("Sending pulses to RS485_N_I(0): ", nb_pulses_to_send_rp);
    generate_pulse (rs485_n_in(0), nb_pulses_to_send_rp, "rp", rs485_fs_n_in(0), 200ns, 200ns);
    pulse_timetag := (now/K);

    -- Checking if the number of RS485 output pulses matches the sent ones
    print_now("Check that the pulses arrived to the RS485_O(0)");
    if pulse_cnt_rs485(0) = nb_pulses_to_send_rp+nb_pulses_to_send_fp then
      print_now_s_i("[OK] Number of pulses measured at RS485_O(0) :",pulse_cnt_rs485(0));
    else
      print_now_s_i("[ERR] Number of pulses measured in the RS485_O(0) : ",pulse_cnt_rs485(0));
      err_cnt := err_cnt + 1;
    end if; 

    -- Check if TTL out and RS485 out are the same
    print_now("Check that the pulses arrived to the TTL_O(0)");
    if fp_rp_same(0) = 0 then
      print_now("[OK] RS485_O(0) matches TTL_O(0)");
    else
      print_now("[ERR] RS485_O(0) does not match TTL_O(0)");
      err_cnt := err_cnt + 1;
    end if; 
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- Counters reading
    print_now("----------------------------------------------------------------");
    print_now("---> Test 06: Reading of the pulse counters through I2C");
    print_now("----------------------------------------------------------------");
    ---------------------------------------------------------------------------
    -- Reading from the I2C Rear Panel regs; read two reg to speed up testbench
    i := 0;
    while not(i = 2) loop
      if i = 0 then
        -- Check Rear Panel Channel 1 counter has correctly counted the pulses 
        read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(i+10).reg_addr, c_REG_MAP(i+10).reg_name , i2c_master_rcvd_val, nb_pulses_to_send_rp_slv, TRUE, err);
        err_cnt := err_cnt + err;
      elsif i = 1 then
        -- Check Rear Panel Channel 2 has not counted any pulses 
        read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, c_REG_MAP(i+10).reg_addr, c_REG_MAP(i+10).reg_name, i2c_master_rcvd_val, (others =>'0'), TRUE, err);
        err_cnt := err_cnt + err;
      end if;
      i := i + 1;
    end loop;
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- Timetag reading
    print_now("----------------------------------------------------------------");
    print_now("---> Test 07: Reading of the timetag register through I2C");
    print_now("----------------------------------------------------------------");
    read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, CH1LTSCYR, "CH1LTSCY", i2c_master_rcvd_val1, (others =>'0'), FALSE, err);
    time_intrvl := (pulse_timetag - rst_timetag)/8;
    print_now_s_i("Estimated timetag cycles: ",time_intrvl);
     if to_integer(unsigned(i2c_master_rcvd_val1(27 downto 0))) > time_intrvl+1000 or to_integer(unsigned(i2c_master_rcvd_val1(27 downto 0))) < time_intrvl-1000 then
      print_now_s_std_s_std("[ERR] Registered cycles: ", i2c_master_rcvd_val1, " is far from the estimated: ", std_logic_vector(to_unsigned(time_intrvl,28)));
      err_cnt := err_cnt + 1;
    else
      print_now_s_std_s_std("[OK] Registered cycles: ", i2c_master_rcvd_val1(27 downto 0), " is close to the estimated: ", std_logic_vector(to_unsigned(time_intrvl,28)));
    end if;    
    read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, CH1LTSTLR, "CH1LTSTL", i2c_master_rcvd_val, (others =>'0'), TRUE, err);
    err_cnt := err_cnt + err;
    read_i2c (i2c_m_in, i2c_m_out, C_I2C_MASTER_SLV_ADDR, CH1LTSCYR, "CH1LTSCY", i2c_master_rcvd_val, i2c_master_rcvd_val1, TRUE, err);
    err_cnt := err_cnt + err;
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- INV channels
    print_now("----------------------------------------------------------------");
    print_now("---> Test 08: INV channel check");
    print_now("----------------------------------------------------------------");
    -- Note INV channels just take INV_N_I and output the same signal to INV_O;
    -- inversion happens through inv buffers; there is no associated counter, timetag, rear channel
    print_now_s_i("Sending pulses to INV_N_I(3): ", nb_pulses_to_send_inv);
    generate_pulse (inv_n_in(3), nb_pulses_to_send_inv, "fp", rs485_fs_n_in(3), 40ns, 20ns);

    print_now("Check INV_O(3) output");
    if inv_err(3) = 0 then
      print_now("[OK] INV_O(3) matches INV_N_I(3)");
    else
      print_now("[ERR] INV_O(3) does not match INV_N_I(3)");
      err_cnt := err_cnt + 1;
    end if; 
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- Glitch filter test
    print_now("----------------------------------------------------------------");
    print_now("---> Test 09: Test Glitch filter");
    print_now("----------------------------------------------------------------");
    ---------------------------------------------------------------------------
    -- Change board settings
    print_now("---> Configure board settings");
    glitch_filter_en := '1';
    ttl_out_bar_en   := '0';
    settings_config (glitch_filter_en, ttl_out_bar_en, sw_gp_n_in, sw_other_in, pcbrev, rtm_in);
    wait for 2 us; -- ML: does not work without this wait, no idea way?
    print_now_s_i("Sending pulses 50ns-long each to TTL_N_I(3): ", nb_pulses_to_send_fp);
    generate_pulse (ttl_n_in(3), nb_pulses_to_send_fp, "fp", rs485_fs_n_in(3), 50ns, 20ns);

    -- Checking if any pulse was passed to the output
    print_now("Check that the glitches were filtered and there is no pulse in the TTL_O(3) output");
    if pulse_cnt_ttl(3) = 0 then
      print_now("[OK] Glitch filter filtered the glitches");
    else
      print_now_s_i("[ERR] Number of pulses measured at TTL_O(3): ",pulse_cnt_ttl(3));
      err_cnt := err_cnt + 1;
    end if; 
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------
    -- TTL bar test
    print_now("----------------------------------------------------------------");
    print_now("---> Test 10: Test TTL BAR");
    print_now("----------------------------------------------------------------");
    ---------------------------------------------------------------------------
    -- Change board settings
    print_now("---> Configure board settings");
    glitch_filter_en := '0';
    ttl_out_bar_en   := '1';
    settings_config (glitch_filter_en, ttl_out_bar_en, sw_gp_n_in, sw_other_in, pcbrev, rtm_in);
    rst_copm <= '1';
    wait for 2 us; -- ML: does not work without this wait, no idea way?
    rst_copm <= '0';

    generate_pulse (ttl_n_in(5), nb_pulses_to_send_bar, "fp", rs485_fs_n_in(5), 200ns, 200ns);

    -- Check if TTL_N_IN out and TTL_O out are the same
    print_now("Check that TTL_O(5) matches TTL_N_IN(5)");
    if in_out_same(5) = 0 then
      print_now("[OK] TTL_O(5) matches TTL_N_IN(5)");
    else
      print_now("[ERR] TTL_O(5) does not match TTL_N_IN(5)");
      err_cnt := err_cnt + 1;
    end if; 
    ---------------------------------------------------------------------------

    print_now_s_i("Errors so far:             ", err_cnt);

    ---------------------------------------------------------------------------

    print("*****************************************************************************");
    print("                                     Tests Summary");
    print("*****************************************************************************");
    print_now_s_i("Total number of errors:    ", err_cnt);
    print("*****************************************************************************");
    wait for 500 us;

  end process p_stim;


end architecture behav;
--==============================================================================
--  architecture end
--==============================================================================


