--==============================================================================
-- CERN (BE-CO-HT)
-- Testbench for the manual trigger module
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- date of creation: 2014-01-30
--
-- version: 1.0
--
-- description:
--
-- dependencies:
--
-- references:
--
--==============================================================================
-- 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
--==============================================================================
-- last changes:
--    2014-01-30   Theodor Stana     File created
--==============================================================================
-- TODO: -
--==============================================================================

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.genram_pkg.all;

entity testbench is
end entity testbench;


architecture behav of testbench is

  --============================================================================
  -- Constant declarations
  --============================================================================
  constant c_clk_per : time := 50 ns;
  constant c_reset_width : time := 31 ns;
  constant c_gf_len  : positive := 1;

  --============================================================================
  -- Functions and procedures
  --============================================================================
  procedure f_mantrig
  (
    constant chan   : in  integer;
    signal   mpt    : out std_logic_vector(7 downto 0);
    signal   mpt_wr : out std_logic
  ) is
  begin
    wait for 1 us;
    mpt    <= x"de";
    mpt_wr <= '1';
    wait for c_clk_per;
    mpt_wr <= '0';
    wait for 1 us;
    mpt    <= x"ad";
    mpt_wr <= '1';
    wait for c_clk_per;
    mpt_wr <= '0';
    wait for 1 us;
    mpt    <= x"be";
    mpt_wr <= '1';
    wait for c_clk_per;
    mpt_wr <= '0';
    wait for 1 us;
    mpt    <= x"ef";
    mpt_wr <= '1';
    wait for c_clk_per;
    mpt_wr <= '0';
    wait for 1 us;
    mpt    <= std_logic_vector(to_unsigned(chan, 8));
    mpt_wr <= '1';
    wait for c_clk_per;
    mpt_wr <= '0';
    wait for 1 us;
    mpt_wr <= '1';
    wait for c_clk_per;
    mpt_wr <= '0';
  end procedure;

  --============================================================================
  -- Component declarations
  --============================================================================
  -- DUT
  component conv_man_trig is
    generic
    (
      -- Number of conversion channels
      g_nr_chan : positive := 6;

      -- Glitch filter length, to generate a long enough pulse
      g_gf_len  : positive := 1
    );
    port
    (
      -- Clock, active-low inputs
      clk_i     : in  std_logic;
      rst_n_i   : in  std_logic;

      -- Control inputs from conv_regs
      reg_ld_i : in  std_logic;
      reg_i    : in  std_logic_vector(7 downto 0);

      -- One-clock pulse output
      trig_o   : out std_logic_vector(g_nr_chan downto 1)
    );
  end component conv_man_trig;


  -- Pulse generator driven by DUT
  component conv_pulse_gen is
    generic
    (
      -- Pulse width, in number of clk_i cycles
      -- Default pulse width (20 MHz clock): 1.2 us
      -- Minimum allowable pulse width (20 MHz clock): 1 us
      -- Maximum allowable pulse width (20 MHz clock): 2 us
      g_pwidth : natural range 20 to 40 := 24;

      -- Glitch filter length:
      -- g_gf_len=1 => trigger width should be > 1 clk_i cycle
      -- g_gf_len=2 => trigger width should be > 2 clk_i cycles
      -- etc.
      g_gf_len : natural := 1
    );
    port
    (
      -- Clock and active-low reset inputs
      clk_i     : in  std_logic;
      rst_n_i   : in  std_logic;

      -- Glitch filter enable input
      -- '1' - Glitch filter disabled (glitch-sensitive, no output jitter)
      -- '0' - Glitch filter enabled (glitch-insensitive, with output jitter)
      gf_en_n_i : in  std_logic;

      -- Enable input, pulse generation is enabled when '1'
      en_i      : in  std_logic;

      -- Trigger input, has to be '1' to assure pulse output with delay no greater
      -- than internal gate delays.
      trig_a_i  : in  std_logic;

      -- Pulse output, active-high
      -- latency:
      --    glitch filter disabled : none
      --    glitch filter enabled  : g_gf_len+6 clk_i cycles
      pulse_o   : out std_logic
    );
  end component conv_pulse_gen;

  --============================================================================
  -- Signal declarations
  --============================================================================
  signal clk20     : std_logic := '0';
  signal rst_n     : std_logic;
  signal mpt_wr    : std_logic;
  signal mpt_wr_d0 : std_logic;
  signal mpt_ld    : std_logic;
  signal mpt       : std_logic_vector(7 downto 0);
  signal trig_man  : std_logic_vector(6 downto 1);
  signal pulse     : std_logic_vector(6 downto 1);
  signal gf_n        : std_logic;

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

  --============================================================================
  -- Generate clock and reset signals
  --============================================================================
  p_clk: process
  begin
    clk20 <= not clk20;
    wait for c_clk_per/2;
  end process p_clk;

  p_rst_n: process
  begin
    rst_n <= '0';
    wait for c_reset_width;
    rst_n <= '1';
    wait;
  end process p_rst_n;

  --============================================================================
  -- Instantiate DUT and conv_pulse_gen blocks it drives
  --============================================================================
  -- First, the DUT
  cmp_dut : conv_man_trig
    generic map
    (
      g_nr_chan => 6,
      g_gf_len  => c_gf_len
    )
    port map
    (
      clk_i    => clk20,
      rst_n_i  => rst_n,

      reg_ld_i => mpt_ld,
      reg_i    => mpt,

      trig_o   => trig_man
    );

  -- Then, the pulse generators with a generate statement
  gen_pulse_gens : for i in 1 to 6 generate
    cmp_pulse_gen : conv_pulse_gen
      generic map
      (
        g_pwidth => 24,
        g_gf_len => c_gf_len
      )
      port map
      (
        clk_i     => clk20,
        rst_n_i   => rst_n,
        gf_en_n_i => gf_n,
        en_i      => '1',
        trig_a_i  => trig_man(i),
        pulse_o   => pulse(i)
      );
  end generate gen_pulse_gens;

  --============================================================================
  -- Some stimuli for the DUT
  --============================================================================
  p_mpt_ld : process (clk20)
  begin
    if rising_edge(clk20) then
      if rst_n = '0' then
        mpt_ld    <= '0';
        mpt_wr_d0 <= '0';
      else
        mpt_wr_d0 <= mpt_wr;
        mpt_ld    <= mpt_wr and not mpt_wr_d0;
      end if;
    end if;
  end process;

  p_stim : process
  begin
    mpt_wr <= '0';
    mpt    <= (others => '0');
    --------------------------
    -- No glitch filt
    --------------------------
    gf_n <= '1';
    f_mantrig(6, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(6, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(5, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(5, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(4, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(4, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(3, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(3, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(2, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(2, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(1, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(1, mpt, mpt_wr);
    wait for 1 us;
    --------------------------
    -- With glitch filt
    --------------------------
    gf_n <= '0';
    f_mantrig(6, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(6, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(5, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(5, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(4, mpt, mpt_wr);
    wait for 1 us;
    gf_n <= '1';
    f_mantrig(4, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(3, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(3, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(2, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(2, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(1, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(1, mpt, mpt_wr);
    wait for 1 us;
    --------------------------
    -- No glitch filt
    --------------------------
    gf_n <= '1';
    f_mantrig(6, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(6, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(5, mpt, mpt_wr);
    wait for 1 us;
    gf_n <= '0';
    f_mantrig(5, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(4, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(4, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(3, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(3, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(2, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(2, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(1, mpt, mpt_wr);
    wait for 1 us;
    f_mantrig(1, mpt, mpt_wr);
    wait for 1 us;
    wait;
  end process p_stim;

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