--------------------------------------------------------------------------------
-- Title   : Freeze the interlock signal - LINAC synchronized interlock function
-- Project : TimEX3
--------------------------------------------------------------------------------
-- Description : after a precharge event, a count down is done and the interlock
--               signal is freezed in its current state during a defined delay
--               to avoid troncating the injection signal.
--
--      pre-charge              injection               extraction
--         ___                     ___                     ___
--    ____|   |___________________|   |___________________|   |_________________
--        :
--    ==========================XXXXXXXXXXXX====================================
--        :<------------------->:<-------->:<-----------------------------------
--        : t start             : t freeze : wait next pre-charge
--        : interlock monitored : freezed  : interlock monitored
--
--
--                                LPM
--                                ___
--    ___________________________|   |__________________________________________
--    -------------------------->:
--         0.131841163386 s      :
--                               :                    SPM
--                               :                    ___
--    _______________________________________________|   |______________________
--                               :<----------------->:
--                               :     82.295 µs     :
--                               :                   :
--    =========================XXXXXXXXXXXXXXXXXXXXXXXXXXXX=====================
--    ------------------------>:<------------------------>:
--              t start        :         t freeze         :
--         0.131821633861 s    :         120 µs           :
--       = X"78AFB2" / 60MHz   :    = "1C20" / 60MHz      :
--
--
--     Local LPM delay = 5459333 steps = 0.0310016 s ; event = 2
--     Local SPM delay = 5473825 steps = 0.0310839 s ; event = 2
--     Local PRE delay = 0 steps ; event = 1
--     CENTRAL inj delay = 193019 steps = 0.10084 s
--     CENTRAL pre delay = 0 steps
--
--------------------------------------------------------------------------------
-- File     : linacSYNCLOCK_synchroInterlock.vhdl
-- Revision : x.x.x
-- Created  : November 28, 2014
-- Updated  : December 12, 2014
--------------------------------------------------------------------------------
-- Author       : Jean-Paul Ricaud
-- Organization : Synchrotron Soleil
-- Web          : http://www.synchrotron-soleil.fr
-- Email        : jean-paul.ricaud@synchrotron-soleil.fr
--------------------------------------------------------------------------------
-- Copyright (C) 2012 - 2014 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 linacSYNCLOCK_synchroInterlock is
  port (
    p_reset            : in  std_logic;
    p_clk60MHz         : in  std_logic;
    p_precharge        : in  std_logic;
    p_interlock        : in  std_logic;
    p_synchroInterlock : out std_logic  -- O = inhibit outputs
  );
end entity linacSYNCLOCK_synchroInterlock;

--------------------------------------------------------------------------------
------------------------------- ARCHITECTURE -----------------------------------
--------------------------------------------------------------------------------
architecture rtl_linacSYNCLOCK_synchroInterlock of linacSYNCLOCK_synchroInterlock is

  ------------------------------------------------------------------------------
  -- constant
  ------------------------------------------------------------------------------
  constant c_cntmax_precharge : unsigned (23 downto 0) := X"78AFB1";
  constant c_cntmax_freeze    : unsigned (15 downto 0) := X"1C1E"; -- 120 µs window

  ------------------------------------------------------------------------------
  -- signal
  ------------------------------------------------------------------------------
  signal s_cnt_precharge  : unsigned (23 downto 0); -- countdown from precharge
  signal s_cnt_freez      : unsigned (15 downto 0); -- freez interlock counter
  signal s_start_contdown : std_logic;
  signal s_start_freez    : std_logic;
  signal s_end_freez      : std_logic;
  signal s_reset_stats    : std_logic;
  signal s_reset          : std_logic;
  signal s_inhibition     : std_logic; -- 0 : inhibited

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

  -- Monitor the pre-charge event to start the countdown
  process (s_reset, p_precharge)
  begin
    if (s_reset = '1') then
      s_start_contdown <= '0';
    elsif (rising_edge(p_precharge)) then
      s_start_contdown <= '1';
    end if;
  end process;

  -- Start the freez conter when the pre-charge counter has reached the maximum
  process (s_reset, p_clk60MHz)
  begin
    if (s_reset = '1') then
      s_cnt_precharge <= (OTHERS => '0');
      s_start_freez <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (s_start_contdown = '1') then
        s_cnt_precharge <= s_cnt_precharge + 1;
        if (s_cnt_precharge > c_cntmax_precharge) then
          s_start_freez <= '1';
        end if;
      end if;
    end if;
  end process;

  -- Stop freezing after the freez timeout
  process (s_reset, p_clk60MHz)
  begin
    if (s_reset = '1') then
      s_cnt_freez <= (OTHERS => '0');
      s_end_freez <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (s_start_freez = '1') then
        s_cnt_freez <= s_cnt_freez + 1;
        if (s_cnt_freez > c_cntmax_freeze) then
          s_end_freez <= '1';
        end if;
      end if;
    end if;
  end process;

  -- Synchronous reset of stats after the freez timeout
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_reset_stats <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (s_end_freez = '1') then
        s_reset_stats <= '1';
      else
        s_reset_stats <= '0';
      end if;
    end if;
  end process;

  -- Inhibition of the interlock
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_inhibition <= '0'; -- inhibited
    elsif (rising_edge(p_clk60MHz)) then
      if (s_start_freez = '1') then
        s_inhibition <= s_inhibition;  -- freezed
      else
        s_inhibition <= p_interlock;   -- follows the interlock
      end if;
    end if;
  end process;

  ------------------------------------------------------------------------------
  ------------------------------------------------------------------------------
  s_reset <= p_reset or s_reset_stats;
  p_synchroInterlock <= s_inhibition;

end architecture rtl_linacSYNCLOCK_synchroInterlock;
