--=============================================================================
--! @file pmtPulseGenerator_rtl.vhd
--=============================================================================
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
-------------------------------------------------------------------------------
-- VHDL Architecture pmtPulseGenerator.rtl
--
--! @brief Produce a series of random pulses. Timing can be optionally
--! referered to system clock.
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--!
--
--! @date 4/3/14
--
--! @version v0.1
--
--! @details
--!
--!
--! <b>Dependencies:</b>\n
--!
--! <b>References:</b>\n
--!
--! <b>Modified by: </b>\n
--! Author: 
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo Implement a periodic calibration sequence \n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

use IEEE.Math_real.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
USE ieee.numeric_std.ALL;

entity pmtPulseGenerator is
  
  generic (
    g_NUM_CHANNELS : positive := 4);    -- --! Number of signal lines

  port (
    pulses_o : out std_logic_vector(g_NUM_CHANNELS-1 downto 0); --! Output pulses
    -- pulseRecord_o : out t_pulseRecord ; --! Record describing the output pulses
    numPulses_i : in positive; --! Number of pulses/events to generate
    averagePulseInterval_i : in time; --! Mean interval between pulses
    averagePulseWidth_i : in time; --! Mean pulse width (must be smaller than interval)
    pulseJitter_i : in time; --! Time spread between outputs.
    sysclock_i : in std_logic;            -- --! Pulses can be optionally referred to rising edge
    simulationDone_o : out boolean --! Goes high when pulse generation is finished
    );
end pmtPulseGenerator;
 
ARCHITECTURE behavior OF pmtPulseGenerator IS 

  signal s_masterPulse : std_logic := '0';
	
BEGIN

   -- Generate "master" pulse
   stim_proc: process
	variable v_seed1 : POSITIVE := 28;
        variable v_seed2 : POSITIVE := 17;
	variable v_pulseWidth , v_pulseLow : time ;
	variable Rand : real;
	
   begin

     assert ( averagePulseInterval_i > averagePulseWidth_i ) report "Pulse width can't be larger than pulse interval!!" severity failure;
     
     simulationDone_o <= False;
     s_masterPulse <= '0';

     for I in 1 to numPulses_i loop

       -- wait for random gap between pulses
       uniform(v_seed1, v_seed2, Rand);
       v_pulseLow := Rand * (averagePulseInterval_i - averagepulseWidth_i);
       wait for v_pulseLow;

       s_masterPulse <= '1'; --! Take pulse high.
       
       -- wait for random pulse width
       uniform(v_seed1, v_seed2, Rand);
       v_pulseWidth := Rand * averagePulseWidth_i;
       wait for v_pulseWidth;
       
       s_masterPulse <= '0'; --! Return pulse low.
       
     end loop;

     simulationDone_o <= True;
     wait;
   end process;

   --! Generate separate outputs that follow the main pulse with timing jitter.
   gen_PulseOutputs: for v_output in 0 to g_NUM_CHANNELS-1 generate
     -- purpose: Sets the individual output pulses based on master pulse
     -- output: pulses_o(v_output)
     p_setOutputs: process
       variable v_timeOffset : time := 0 ns;  -- --! offset between master pulse changing and output changing.
       variable Rand : real;
       variable v_seed1 : POSITIVE := 19*(v_output+1);
       variable v_seed2 : POSITIVE := 47*(v_output+1);
       
     begin  -- process p_setOutputs

       -- set the output low
       -- pulses_o(v_output) <= '0';
         
       wait on s_masterPulse;

       if rising_edge(s_masterPulse) then

         --report "Pulse output proc: found rising edge" severity note;
         
         -- Generate some jitter
         uniform(v_seed1, v_seed2, Rand);
         v_timeOffset := Rand * pulseJitter_i;

         --report "Pulse output proc: waiting to set output pulse" severity note;

         -- wait for that jitter
         wait for v_timeOffset;

         -- set the output high
         pulses_o(v_output) <= '1';

       else
         -- falling edge....
         -- wait for jitter time
         wait for v_timeOffset;

         -- return the output low.
         pulses_o(v_output) <= '0';
         
       end if;
         
     end process p_setOutputs;

   end generate gen_PulseOutputs;
END;
