-------------------------------------------------------------------------------
-- Title   : SPM and LPM simultaneous trigg monitor
-- Project : TimEX3
-------------------------------------------------------------------------------
-- Description : Monitor and count any simultaneous SPM and LPM trigg
-------------------------------------------------------------------------------
-- File     : linacMON_simTrigg.vhdl
-- Revision : x.x.x
-- Created  : July 09, 2013
-- Updated  : July 30, 2013
-------------------------------------------------------------------------------
-- Author       : Jean-Paul Ricaud
-- Organization : Synchrotron Soleil
-- Web          : http://www.synchrotron-soleil.fr
-- Email        : jean-paul.ricaud@synchrotron-soleil.fr
-------------------------------------------------------------------------------
-- Copyright (C) 2012 - 2013 Synchrotron Soleil
--
-- This program 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 3 of the License, or
-- (at your option) any later version.
--
-- This program 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 program.  If not, see <http://www.gnu.org/licenses/>
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
-- Modifications :
--
-------------------------------------------------------------------------------

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

library work;
use work.registers_init.all;

-------------------------------------------------------------------------------
--------------------------------- ENTITY --------------------------------------
-------------------------------------------------------------------------------
entity linacMON_simTrigg is
  port (
    p_clk1kHz     : in  std_logic;
    p_clk60MHz    : in  std_logic;
    p_inTTL       : in  std_logic_vector (1  downto 0); -- p_inTTL(0) = SPM
                                                        -- p_inTTL(1) = LPM
    p_simTriggReg : out std_logic_vector (31 downto 0); -- register with the number
                                                        -- of simultaneous SPM and
                                                        -- LPM trigg
    p_csw         : in  std_logic;
    p_reset       : in  std_logic;
    p_error       : out std_logic
  );
end entity linacMON_simTrigg ;

-------------------------------------------------------------------------------
------------------------------- ARCHITECTURE ----------------------------------
-------------------------------------------------------------------------------
architecture rtl_linacMON_simTrigg of linacMON_simTrigg is
  -----------------------------------------------------------------------------
  -- constant
  -----------------------------------------------------------------------------
  constant c_cntHoldSPMmax : unsigned (8 downto 0)  := "101010100"; -- 340 ms
  constant c_cntHoldLPMmax : unsigned (8 downto 0)  := "101010100"; -- 340 ms
  constant c_cntmax        : unsigned (31 downto 0) := X"FFFFFFFF";

  -----------------------------------------------------------------------------
  -- signal
  -----------------------------------------------------------------------------
  signal s_holdSPM           : std_logic; -- SPM hold
  signal s_resetSPM          : std_logic; -- reset SPM hold
  signal s_cntHoldSPM        : unsigned (8 downto 0); -- SPM hold counter
  signal s_holdLPM           : std_logic; -- LPM hold
  signal s_resetLPM          : std_logic; -- reset LPM hold
  signal s_cntHoldLPM        : unsigned (8 downto 0); -- LPM hold counter
  signal s_simultaneousTrigg : std_logic; -- simultaeous SPM and LPM trigg detection
  signal s_cnt               : unsigned (31 downto 0); -- counter
  signal s_rstCNT            : std_logic; -- reset the counter
  signal s_error             : std_logic; -- simultaneaous SPM / LPM error

  -----------------------------------------------------------------------------
  -- Components
  -----------------------------------------------------------------------------

  -----------------------------------------------------------------------------
  --------------------------------- Main --------------------------------------
  -----------------------------------------------------------------------------
  begin

  -- Detection of a SPM edge
  process (p_reset, s_resetSPM, p_inTTL(0))
  begin
    if ((p_reset = '1') or (s_resetSPM = '1')) then
      s_holdSPM <= '0';
    elsif (rising_edge(p_inTTL(0))) then
      s_holdSPM <= '1';
    end if;
  end process;

  -- Hold the SPM pulse for c_cntHoldSPMmax
  process (p_reset, s_holdSPM, p_clk1kHz)
  begin
    if (p_reset = '1') then
      s_cntHoldSPM <= (OTHERS => '0');
      s_resetSPM   <= '0';
    elsif (falling_edge(p_clk1kHz)) then
      if (s_holdSPM = '1') then
        if (s_cntHoldSPM < c_cntHoldSPMmax) then
          s_cntHoldSPM <= s_cntHoldSPM + 1;
          s_resetSPM   <= '0';
        else
          s_cntHoldSPM <= (OTHERS => '0');
          s_resetSPM   <= '1';
        end if;
      else
        s_resetSPM <= '0';
      end if;
    end if;
  end process;

  -- Detection of a LPM edge
  process (p_reset, s_resetLPM, p_inTTL(1))
  begin
    if ((p_reset = '1') or (s_resetLPM = '1')) then
      s_holdLPM <= '0';
    elsif (rising_edge(p_inTTL(1))) then
      s_holdLPM <= '1';
    end if;
  end process;

  -- Hold the LPM pulse for c_cntHoldLPMmax
  process (p_reset, s_holdLPM, p_clk1kHz)
  begin
    if (p_reset = '1') then
      s_cntHoldLPM <= (OTHERS => '0');
      s_resetLPM   <= '0';
    elsif (falling_edge(p_clk1kHz)) then
      if (s_holdLPM = '1') then
        if (s_cntHoldLPM < c_cntHoldLPMmax) then
          s_cntHoldLPM <= s_cntHoldLPM + 1;
          s_resetLPM   <= '0';
        else
          s_cntHoldLPM <= (OTHERS => '0');
          s_resetLPM   <= '1';
        end if;
      else
        s_resetLPM <= '0';
      end if;
    end if;
  end process;

  -- Count the numbr of simultanous SPM and LPM trigg
  process (p_reset, s_rstCNT, s_simultaneousTrigg)
  begin
    if ((s_rstCNT = '1') or (p_reset = '1')) then
      s_cnt <= (OTHERS => '0');
      s_error <= '0';
    elsif (rising_edge(s_simultaneousTrigg)) then
      if (s_cnt < c_cntmax) then
        s_cnt <= s_cnt + 1;
        s_error <= '1';
      else
        s_cnt <= s_cnt; -- keep the max value in case of overflow
        s_error <= '1';
      end if;
    end if;
  end process;

  -- Reset the SPM and LPM simultaneous counter
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_rstCNT <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (p_csw = '1') then
        s_rstCNT <= '1';
      else
        s_rstCNT <= '0';
      end if;
    end if;
  end process;

  -----------------------------------------------------------------------------
  -----------------------------------------------------------------------------
  s_simultaneousTrigg <= s_holdLPM and s_holdSPM;
  p_simTriggReg <= std_logic_vector(s_cnt);
  p_error       <= s_error;

end architecture rtl_linacMON_simTrigg;
