--------------------------------------------------------------------------------
-- Title   : Top - clock padding function
-- Project : TimEX3
--------------------------------------------------------------------------------
-- Description : generate a 1 kHz clock on the output whenever the input 1 kHz
--               clock is missing on the input.
--               It is used by Cristal laser synchro system to avoid gaps in the
--               1 kHz clock when changing delays
--               The laser frequency is :
--                   Fl = Frf / 2 / 0x2AF60 = 1000.7397555 Hz (999.261 µs)
--------------------------------------------------------------------------------
-- File     : clkpadding_top.vhdl
-- Revision : x.x.x
-- Created  : July 19, 2014
-- Updated  : December 08, 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 Lesser GNU 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;

--------------------------------------------------------------------------------
--------------------------------- ENTITY ---------------------------------------
--------------------------------------------------------------------------------
entity clkPADDING_top is
  port (
    p_clkPADDING_clk500mHz : in  std_logic;
    p_clkPADDING_clk_mon   : in  std_logic; -- monitored clock
    p_clkPADDING_clk_sr    : in  std_logic; -- storage ring clock
    p_clkPADDING_reset     : in  std_logic; -- global reset
    p_clkPADDING_outTTL    : out std_logic_vector (4 downto 0); -- TTL outputs  -- output clock
    p_clkPADDING_outPECL   : out std_logic_vector (4 downto 0); -- LVPECL outputs
    p_clkPADDING_LED       : out std_logic_vector (1 downto 0)
  );
end entity clkPADDING_top;

--------------------------------------------------------------------------------
------------------------------- ARCHITECTURE -----------------------------------
--------------------------------------------------------------------------------
architecture rtl_clkPADDING_top of clkPADDING_top is

  ------------------------------------------------------------------------------
  -- constant
  ------------------------------------------------------------------------------
  constant c_gapDetect     : unsigned (11 downto 0) := X"34F";
  constant c_paddingPeriod : unsigned (11 downto 0) := X"34D";  -- 1000.73839 Hz
  constant c_pulseHigh     : unsigned (07 downto 0) := X"A9";   -- 200 µs

  ------------------------------------------------------------------------------
  -- signal
  ------------------------------------------------------------------------------
  signal s_cnt1 : unsigned (11 downto 0); -- counter
  signal s_cnt2 : unsigned (11 downto 0); -- counter

  signal s_start         : std_logic;
  signal s_underProgress : std_logic;
  signal s_clkPadding    : std_logic;
  signal s_reset         : std_logic;
  signal s_extCLKup      : std_logic;
  signal s_led           : std_logic;
  signal s_ledHold       : std_logic;

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

  -- Detection of a gap in the input clock
  process (p_clkPADDING_reset, s_reset, p_clkPADDING_clk_sr)
  begin
   if ((p_clkPADDING_reset = '1') or (s_reset = '1')) then
      s_cnt1  <= (OTHERS => '0');
      s_start <= '0';
    elsif (rising_edge(p_clkPADDING_clk_sr)) then
      if (s_cnt1 = c_gapDetect) then
        s_start <= '1';
        s_cnt1  <= s_cnt1;
      else
        s_cnt1  <= s_cnt1 + 1;
      end if;
    end if;
  end process;

  -- Generation of a padding clock if a gap is detected
  -- in the input clock
  process (p_clkPADDING_reset, p_clkPADDING_clk_sr)
  begin
    if (p_clkPADDING_reset = '1') then
      s_cnt2          <= (OTHERS => '0');
      s_clkPadding    <= p_clkPADDING_clk_mon;
    elsif (rising_edge(p_clkPADDING_clk_sr)) then
      if (s_start = '1') then
        s_cnt2  <= s_cnt2 + 1;
        if (s_cnt2 < c_pulseHigh) then
          s_clkPadding <= '1';
        elsif (s_cnt2 < c_paddingPeriod) then
          s_clkPadding <= '0';
        else
          s_cnt2       <= (OTHERS => '0');
          s_clkPadding <= '0';
        end if;
      else
        s_cnt2          <= (OTHERS => '0');
        s_clkPadding    <= p_clkPADDING_clk_mon;
      end if;
    end if;
  end process;

  -- Reset the padding if the external clock is on
  process (p_clkPADDING_reset, s_reset, p_clkPADDING_clk_mon)
  begin
    if ((p_clkPADDING_reset = '1') or (s_reset = '1')) then
      s_extCLKup <= '0';
    elsif (rising_edge(p_clkPADDING_clk_mon)) then
      s_extCLKup <= '1';
    end if;
  end process;

  process (p_clkPADDING_reset, p_clkPADDING_clk_sr)
  begin
    if (p_clkPADDING_reset = '1') then
      s_reset <= '0';
    elsif (rising_edge(p_clkPADDING_clk_sr)) then
      if (s_extCLKup = '1') then
        s_reset <= '1';
      else
        s_reset <= '0';
      end if;
    end if;
  end process;

  -- Trigger red LED
  process (p_clkPADDING_reset, s_start, p_clkPADDING_clk500mHz)
  begin
    if ((p_clkPADDING_reset = '1') or (s_start = '1')) then
      s_led     <= '1';
      s_ledHold <= '1';
    elsif (rising_edge(p_clkPADDING_clk500mHz)) then
      s_led     <= s_ledHold;
      s_ledHold <= '0';
    end if;
  end process;

  ------------------------------------------------------------------------------
  ------------------------------------------------------------------------------

  p_clkPADDING_outTTL(0) <= '0'; -- not used ; is configured as input
  p_clkPADDING_outTTL(1) <= '0'; -- not used ; is configured as input
  p_clkPADDING_outTTL(2) <= s_clkPadding;
  p_clkPADDING_outTTL(3) <= s_clkPadding;
  p_clkPADDING_outTTL(4) <= p_clkPADDING_clk_mon;

  p_clkPADDING_outPECL(4 downto 0) <= "00000";

  p_clkPADDING_led(0) <= s_led; -- red LED
  p_clkPADDING_led(1) <= '1'; -- green LED ON

end architecture rtl_clkPADDING_top;
