-------------------------------------------------------------------------------
-- Title   : Top-up beam lost monitoring
-- Project : TimEX3
-------------------------------------------------------------------------------
-- Description : Monitoring of the beam. Set p_beamGate if the beam is lost
--                                     ___
--     Machine beam lost signal    ___|   |___________________________________
--                                    :
--                                 ____________________________     __________
--     Top-up gating signal           :                        |___|
--                                    :                            :
--                                    :              _______________________
--     p_beamGate signal           _________________|              :        |_
--                                    :             :              :        :
--                                    <------------->              <-------->
--                                      t hold off                 t hold on
-------------------------------------------------------------------------------
-- File     : topup_beamlost.vhdl
-- Revision : x.x.x
-- Created  : April 12, 2013
-- Updated  : October 29, 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 :
--   Version 1.2.1 ; June 13 2013 ; Jean-Paul Ricaud
--     * added a reset impulse on rising edge of pre top-up signal to reset the
--       beam lost cycle
--
-------------------------------------------------------------------------------

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

library work;
use work.registers_init.all;

-------------------------------------------------------------------------------
--------------------------------- ENTITY --------------------------------------
-------------------------------------------------------------------------------
entity topup_beamlost is
  port (
    p_clk1kHz              : in  std_logic;
    p_clk60MHz             : in  std_logic;
    p_inTTL                : in  std_logic_vector (1  downto 0);
    p_beamLostHoldOffDelay : in  std_logic_vector (31 downto 0);
    p_beamLostHoldOnDelay  : in  std_logic_vector (31 downto 0);
    p_csw                  : in  std_logic_vector (1  downto 0);
    p_reset                : in  std_logic;
    p_beamGate             : out std_logic
  );
end entity topup_beamlost ;

-------------------------------------------------------------------------------
------------------------------- ARCHITECTURE ----------------------------------
-------------------------------------------------------------------------------
architecture rtl_topup_beamlost of topup_beamlost is
  -----------------------------------------------------------------------------
  -- constant
  -----------------------------------------------------------------------------

  -----------------------------------------------------------------------------
  -- signal
  -----------------------------------------------------------------------------
  signal s_beamLost   : std_logic;
  signal s_cntHoldOff : unsigned (31 downto 0);
  signal s_holdOffMax : unsigned (31 downto 0);
  signal s_cntHoldOn  : unsigned (31 downto 0);
  signal s_holdOnMax  : unsigned (31 downto 0);
  signal s_gateStart  : std_logic;
  signal s_gateStop   : std_logic;
  signal s_rstCNT0    : std_logic;
  signal s_rstCNT1    : std_logic;
  signal s_rstCNT     : std_logic;
  signal s_rst        : std_logic;
  signal s_rstCycle   : std_logic;

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

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

  -- Create a reset pulse at each pre top-up signal received
  -- p_inTTL(0) = pre top-up
  process (p_reset, s_rst, p_inTTL(0))
  begin
    if ((p_reset = '1') or (s_rst = '1')) then
      s_rstCycle <= '0';
    elsif (rising_edge(p_inTTL(0))) then
      s_rstCycle <= '1'; -- injection occurred, reset cycle
    else
      s_rstCycle <= s_rstCycle;
    end if;
  end process;

  process (p_reset, p_clk1kHz)
  begin
    if (p_reset = '1') then
      s_rst <= '0';
    elsif (rising_edge(p_clk1kHz)) then
      if (s_rstCycle = '1') then
        s_rst <= '1';
      else
        s_rst <= '0';
      end if;
    end if;
  end process;

  -- Detect a beam lost message and memorises it until a new injection
  -- occurres
  -- p_inTTL(0) = pre top-up ; p_inTTL(1) = beam lost
  process (p_reset, s_rstCycle, p_inTTL(1))
  begin
    if ((p_reset = '1') or (s_rstCycle = '1')) then
      s_beamLost <= '0'; -- injection occurred
    elsif (rising_edge(p_inTTL(1))) then
      s_beamLost <= '1'; -- beam lost
    else
      s_beamLost <= s_beamLost;
    end if;
  end process;

  -- Hold off time
  process (p_reset, s_beamLost, p_clk1kHz, s_rstCNT)
  begin
    if ((p_reset = '1') or (s_beamLost = '0') or (s_rstCNT = '1')) then
      s_cntHoldOff <= X"00000001";
      s_gateStart  <= '0';
    elsif (rising_edge(p_clk1kHz)) then
      if (s_cntHoldOff >= s_holdOffMax) then
        -- Start the gating windows
        s_cntHoldOff <= s_cntHoldOff;
        s_gateStart  <= '1';
      else
        --  Counting the hold off time
        s_cntHoldOff <= s_cntHoldOff + 1;
        s_gateStart  <= '0';
      end if;
    end if;
  end process;

  -- Hold on time
  process (p_reset, p_clk1kHz, s_rstCNT)
  begin
    if ((p_reset = '1') or (s_rstCNT = '1')) then
      s_cntHoldOn <= unsigned (c_wRegister_init(3));
      s_gateStop  <= '0'; -- Beam lost gate (hold on time)
    elsif (rising_edge(p_clk1kHz)) then
      if (s_gateStart = '1') then
        s_cntHoldOn <= X"00000001";
        s_gateStop  <= '1';
      elsif (s_cntHoldOn < s_holdOnMax) then
        s_cntHoldOn <= s_cntHoldOn + 1;
        s_gateStop  <= '1';
      else
        s_cntHoldOn <= s_cntHoldOn;
        s_gateStop  <= '0';
      end if;
    end if;
  end process;

  -- Latch from the register the delay before a missing beam is
  -- took into account ; beam lost hold off
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_holdOffMax <= unsigned (c_wRegister_init(2));
      s_rstCNT0    <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (p_csw(0) = '1') then
        s_holdOffMax <= unsigned (p_beamLostHoldOffDelay);
        s_rstCNT0    <= '1';
      else
        s_holdOffMax <= s_holdOffMax;
        s_rstCNT0    <= '0';
      end if;
    end if;
  end process;

  -- Latch from the register the hold on delay after an injection
  -- Beam lost hold on
  process (p_reset, p_clk60MHz)
  begin
    if (p_reset = '1') then
      s_holdOnMax <=  unsigned (c_wRegister_init(3));
      s_rstCNT1   <= '0';
    elsif (rising_edge(p_clk60MHz)) then
      if (p_csw(1) = '1') then
        s_holdOnMax <= unsigned (p_beamLostHoldOnDelay);
        s_rstCNT1   <= '1';
      else
        s_holdOnMax <= s_holdOnMax;
        s_rstCNT1   <= '0';
      end if;
    end if;
  end process;

  -----------------------------------------------------------------------------
  -----------------------------------------------------------------------------
  s_rstCNT   <= s_rstCNT0 or s_rstCNT1;
  p_beamGate <= s_gateStop; -- Beam lost gate (hold on time)

end architecture rtl_topup_beamlost;
