---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004
--
-- Filename: TriggerDelay.vhd
-- Language: VHDL '93
-- Project:  Digitiser Card Peripheral FPGA
--
-- Design Description:
-- Module to delay trigger
--
---------------------------------------------------------------------------

library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;

entity TriggerDelay is
  port(pnReset            : in  std_ulogic;
       pSampleClk         : in  std_ulogic;
       pTriggerDelay      : in  std_logic_vector(20 downto 0);
       pTriggerIn         : in  std_ulogic;
       pTriggerOut        : out std_ulogic);
end entity TriggerDelay;


architecture Rtl of TriggerDelay is

  attribute register_balancing: string;
  attribute register_duplication: string;

  signal ActiveCount: integer range 0 to 3;
  signal TriggerIn:   std_logic_vector(3 downto 0);
  signal TriggerRegs: std_logic_vector(2 downto 0);
  type tDelayCount is array (0 to 3) of std_logic_vector(20 downto 0);
  signal DelayCount:  tDelayCount;
  signal DelayActive: std_logic_vector(3 downto 0);
  signal TriggerOut:  std_logic_vector(3 downto 0);
  signal OutShifter:  std_logic_vector(2 downto 0);


begin


  -- Detect the rising edge of the trigger and assign it to
  -- one of the delay channels
  GenActiveCount: process(pnReset, pSampleClk)
  begin
    if pnReset = '0' then
      ActiveCount  <= 0;
      TriggerRegs  <= "000";

    elsif rising_edge(pSampleClk) then
      if TriggerRegs(2 downto 1) = "01" then
        -- Update which TriggerIn bit is active
        ActiveCount <= (ActiveCount + 1) mod 4;
      end if;

      TriggerRegs <= TriggerRegs(1 downto 0) & pTriggerIn;
    end if;
  end process GenActiveCount;


  GenTriggerIn: process(TriggerRegs, ActiveCount)
  begin
    TriggerIn <= "0000";
    if TriggerRegs(2 downto 1) = "01" then
      TriggerIn(ActiveCount) <= '1';
    end if;
  end process GenTriggerIn;



  -- Create 4 delay channels
  GenTriggerDelays: process(pnReset, pSampleClk)
    constant cDelayMask:  std_logic_vector(20 downto 0) := (others => '1');
    constant cDelayZeros: std_logic_vector(20 downto 0) := (others => '0');
    variable vCountIsZero: std_logic_vector(3 downto 0);
  begin
    if pnReset = '0' then
      DelayActive    <= "0000";
      DelayCount(0)  <= cDelayZeros;
      DelayCount(1)  <= cDelayZeros;
      DelayCount(2)  <= cDelayZeros;
      DelayCount(3)  <= cDelayZeros;
      TriggerOut     <= "0000";
      vCountIsZero   := "1111";

    elsif rising_edge(pSampleClk) then

      for Count in 0 to 3 loop
        TriggerOut(Count)  <= '0';

        -- Decrement the count by default
        DelayCount(Count) <= (unsigned(DelayCount(Count)) - 1) and cDelayMask;

        if TriggerIn(Count) = '1' and DelayActive(Count) = '0' then
          -- This delay channel has a new trigger and is not already active
          DelayCount(Count)  <= pTriggerDelay;
          DelayActive(Count) <= '1';

        elsif DelayActive(Count) = '1' then
          --if DelayCount(Count) = cDelayZeros then
          if vCountIsZero(Count) = '1' then
            -- Count has completed
            DelayActive(Count) <= '0';
            TriggerOut(Count)  <= '1';
          end if;
        end if;
        
        if DelayCount(Count) = cDelayZeros then
          vCountIsZero(Count) := '1';
        else
          vCountIsZero(Count) := '0';
        end if;
      end loop;
    end if;
  end process GenTriggerDelays;


  -- Generate the final, combined trigger output signal
  GenpTriggerOut: process(pnReset, pSampleClk)
  begin
    if pnReset = '0' then
      OutShifter  <= "000";

    elsif rising_edge(pSampleClk) then
      if TriggerOut /= "0000" then
        -- There is a trigger to output, set the output trigger
        OutShifter <= "111";
      else
        OutShifter <= OutShifter(1 downto 0) & '0';
      end if;
    end if;
  end process GenpTriggerOut;

  pTriggerOut <= OutShifter(2);



end architecture rtl;
