----------------------------------------------------------------------------------
-- Company:        CERN, BE-CO-HT
-- Engineer:       Carlos Gil Soriano
-- 
-- Create Date:    09:58:06 10/12/2011 
-- Design Name:    HDL trigger
-- Module Name:    trigger - Behavioral 
-- Project Name:   CTDAH
-- Target Devices: Spartan 6
-- Tool versions: 
-- Description:    This is the wishbone trigger which receives a debounced input
--                 and outputs a trigger signal for the pulse converter
-- Dependencies:   none
--
-- Revision: 
-- Revision 0.1
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
library work;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

use work.ctdah_pkg.ALL;
use work.trigger_pkg.ALL;

entity trigger_core is
  port (
         pulse_i    : in  STD_LOGIC;
         pulse_o    : out STD_LOGIC;

         led_o      : out STD_LOGIC;

         wb_clk_i   : in  STD_LOGIC;
         wb_rst_i   : in  STD_LOGIC;

         write_tt_o : out STD_LOGIC;

         CTR0_i     : in  r_CTR0;
         CTR1_i     : in  r_CTR1;
         CTR2_o     : out r_CTR2
       );
end trigger_core;

architecture Behavioral of trigger_core is

  signal s_pulse               : STD_LOGIC;
  signal s_deglitched_pulse    : STD_LOGIC;
  signal s_deglitched_pulse_d0 : STD_LOGIC;

  signal s_PET_counter_rst     : STD_LOGIC;
  signal s_PET_counter_en      : STD_LOGIC;

  signal s_CTR0                : r_CTR0;
  signal s_CTR0_d0             : r_CTR0;
  signal s_CTR2                : r_CTR2;

  type t_level_mon_fsm is (R0_RESET,
                           S0_IDLE,
                           S1_START_EDGE_DETECTED,
                           S2_ACTIVE_STATE,
                           S2A_LONG_PULSE_NOTIFICATION,
                           S3_END_EDGE_DETECTED,
                           S3A_SHORT_PULSE_NOTIFICATION,
                           Q0_ERROR);

  signal s_MON_fsm : t_level_mon_fsm;
  
begin

   s_CTR0 <= CTR0_i; 
   s_CTR1 <= CTR1_i; 
   CTR2_o <= s_CTR2; 


  inst_debo: gc_debouncer
  generic map( g_LENGTH  => 6)
  port map(
            rst         => wb_rst_i,
            clk         => wb_clk_i,
            input       => pulse_i,
            output      => s_deglitched_pulse,
            glitch_mask => s_CTR0.CGM
          );

  inst_mono: gc_monostable
  port map(
            rst                       => wb_rst_i,
            clk                       => wb_clk_i,
            pulse_len(31 downto 16)   => X"0000",
            pulse_len(15 downto  0)   => s_CTR0.CPL,
            write_tt_o                => write_tt_o,
            input                     => s_deglitched_pulse,
            output                    => pulse_o
          );

  led_mono: gc_monostable
  port map(
   rst         => wb_rst_i,
   clk         => wb_clk_i,
   pulse_len   => STD_LOGIC_VECTOR(to_unsigned(c_LED_PERIOD, 32)),  -- 500ms
--   write_tt_o  => 'Z',
   input       => s_deglitched_pulse,
   output      => led_o);

  PET_counter: gc_counter
  generic map(g_DATA_WIDTH => 16)
  port map(
        clk_i  => wb_clk_i, 
        rst_i  => s_PET_counter_rst,
        en_i   => s_PET_counter_en,
        cnt_o  => s_CTR2.PET);


  --! @brief Some delays
  --! @param wb_clk_i System clock
  p_delays : process (wb_clk_i) is
  begin
     if rising_edge(wb_clk_i) then
        s_pulse_d0    <= s_pulse;
        s_CTR0_d0     <= s_CTR0;
     end if;
  end process p_delays;

  --! @brief Stupid repetitor process to keep reliability high in basic
  --!        functionality.
  --!        A pulse is repeated whenever it is able to pass the deglitching
  --!        mask.
  --! @param wb_clk_i System clock
  p_pulse_i_en: process(wb_clk_i) is
  begin
    if rising_edge(wb_clk_i) then
      if s_CTR0.EN = '1' then
         if s_CTR0.AH = '1' then
            s_pulse <= pulse_i;
         else
            s_pulse <= not(pulse_i);
         end if;
      else
         s_pulse <= '0';
      end if;
    end if;
  end process p_pulse_i_en;


  --! @brief Assignment of signals to be feed into an external unit through
  --!        CTR2
  --! @param s_MON_fsm Pulse monitor fsm current status 
  p_comb_MON_CTR2 : process (s_MON_fsm) is
  begin
     s_CTR2.SPF <= c_CTR2_default.SPF; 
     s_CTR2.LPF <= c_CTR2_default.LPF; 
     s_CTR2.EPF <= c_CTR2_default.EPF; 
     s_CTR2.x   <= c_CTR2_default.x; 

     case s_MON_fsm is
        when S2A_LONG_PULSE_NOTIFICATION  =>
           s_CTR2.LPF <= '1'; 
        when S3_END_EDGE_DETECTED         =>
           if long_pulse_notification = '1' then
              s_CTR2.LPF <= '1'; 
           end if;
           s_CTR2.EPF <= '1'; 
        when S3A_SHORT_PULSE_NOTIFICATION =>
           s_CTR2.SPF <= '1'; 
           s_CTR2.EPF <= '1'; 
        when others =>
           null;
     end case;
  end process p_comb_MON_CTR2;


  --! @brief Synchronous process for the monitor fsm
  --! @param wb_clk_i System clock
  --!        wb_rst_i Wishbone reset
  p_level_mon_fsm : process (wb_clk_i, wb_rst_i) is

     function start_detection return STD_LOGIC is
        variable v_return  : STD_LOGIC;
     begin
        v_return := '0';
        if     (s_deglitched_pulse   
           xor  s_deglitched_pulse_d0) = '1' then
              if s_deglitched_pulse = s_CTR0.AH then
                 v_return := '1'; 
              end if;
           end if;
        return v_return;
     end function;

     function end_detection return STD_LOGIC is
        variable v_return  : STD_LOGIC;
     begin
        v_return := '0';
        if     (s_deglitched_pulse   
           xor  s_deglitched_pulse_d0) = '1' then
              if s_deglitched_pulse_d0 = s_CTR0.AH then
                 v_return := '1'; 
              end if;
        end if;
        return v_return;
     end function;

  begin
     if rising_edge(wb_clk_i) then
        if wb_rst_i = '1' then
           s_MON_fsm <= R0_RESET;
        else
           if s_CTR0.AH /= s_CTR0_d0.AH then
              s_MON_fsm <= R0_RESET;
           else
              case s_MON_fsm is
                 --! We specify one clock delay after the reset to detect correct
                 --! deglitched pulses
                 when R0_RESET                     =>
                    s_MON_fsm <= S0_IDLE;
                 when S0_IDLE                      =>
                    if start_detection = '1' then
                       s_MON_fsm <= S1_START_EDGE_DETECTED;
                    end if;
                 when S1_START_EDGE_DETECTED       =>
                    if end_detection = '1' then
                       s_MON_fsm <= S3A_SHORT_PULSE_NOTIFICATION;
                    else
                       s_MON_fsm <= S2_ACTIVE_STATE;
                    end if;
                 when S2_ACTIVE_STATE              =>
                    case end_detection is
                       when '1' =>
                          if short_pulse = '1' then
                             s_MON_fsm <= S3A_SHORT_PULSE_NOTIFICATION;
                          else
                             s_MON_fsm <= S3_END_EDGE_DETECTED;
                          end if;
                       when others =>
                          if long_pulse_notification = '1' then
                             s_MON_fsm <= S2A_LONG_PULSE_NOTIFICATION;
                          end if;
                    end case;
                 when S2A_LONG_PULSE_NOTIFICATION  => 
                    case end_detection is
                       when '1'    =>
                          s_MON_fsm <= S3_END_EDGE_DETECTED;
                       when others =>
                          s_MON_fsm <= S2_ACTIVE_STATE;
                    end case;
                 when S3_END_EDGE_DETECTED         => 
                    --! As we will deglitch more than one cycle, no pulses will
                    --! be missed
                    s_MON_fsm <= S0_IDLE;
                 when S3A_SHORT_PULSE_NOTIFICATION =>
                    --! As we will deglitch more than one cycle, no pulses will
                    --! be missed
                    s_MON_fsm <= S0_IDLE;
                 when others     => 
                    s_MON_fsm <= R0_RESET;
              end case;
           end if;
        end if;
     end if;
  end process p_level_mon_fsm;

end Behavioral;
