library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.std_logic_signed.all;

library fact_fad_lib;
use fact_fad_lib.fad_definitions.all;


ENTITY drs_pulser is
     port (
         -- input CLK; RSRLOAD and SRCLK are derived from this signal
         CLK : in std_logic;
         -- async reset;
         reset : in std_logic;
         
         start_endless_mode : in std_logic;
         start_read_stop_pos_mode : in std_logic;

         SROUT_in_0 : in std_logic;
         SROUT_in_1 : in std_logic;
         SROUT_in_2 : in std_logic;
         SROUT_in_3 : in std_logic;

--         stop_pos_0 : out std_logic_vector(9 downto 0);
--         stop_pos_1 : out std_logic_vector(9 downto 0);
--         stop_pos_2 : out std_logic_vector(9 downto 0);
--         stop_pos_3 : out std_logic_vector(9 downto 0);
          stop_pos : out drs_s_cell_array_type;
         stop_pos_valid : out std_logic;

         RSRLOAD : out std_logic;
         SRCLK : out std_logic;
         busy :out std_logic
     );
end drs_pulser;


ARCHITECTURE behavior of drs_pulser IS

type states is (idle, started_endless, started_read_stop_pos , waiting_e, waiting_r, running_e, running_r);
signal current_state : states := idle;
signal next_state : states := idle;
signal CEN,LEN : std_logic;


signal local_roi : std_logic_vector (9 downto 0):= (others => '0');

signal flag_read_stop_pos : std_logic := '0';

signal cell_cntr : std_logic_vector (9 downto 0);
signal cc_en : std_logic;
signal cc_reset : std_logic;

signal wait_cntr : std_logic_vector (2 downto 0);
signal wc_en : std_logic;
signal wc_reset : std_logic;

signal int_stop_pos_0 : std_logic_vector(9 downto 0) := (others => '0');
signal int_stop_pos_1 : std_logic_vector(9 downto 0) := (others => '0');
signal int_stop_pos_2 : std_logic_vector(9 downto 0) := (others => '0');
signal int_stop_pos_3 : std_logic_vector(9 downto 0) := (others => '0');

begin
     RSRLOAD <= (LEN and CLK);
     SRCLK <= (CEN and CLK);
     stop_pos(0) <= int_stop_pos_0;
     stop_pos(1) <= int_stop_pos_1;
     stop_pos(2) <= int_stop_pos_2;
     stop_pos(3) <= int_stop_pos_3;
     

               
     state_register: process(clk, reset)
     begin
         IF reset = '1' THEN
           current_state <= idle ;
         ELSIF clk = '0' and clk'event THEN  -- ! falling edge !
            current_state <= next_state ;
         END IF;
     end process state_register;

    --Folgezustandsberechnung asynchron
     transition: process(current_state,
                         start_endless_mode,
                         start_read_stop_pos_mode,
                         wait_cntr,
                         cell_cntr,
                         local_roi)
         begin
             CASE current_state IS
                 WHEN idle =>            
                     if start_endless_mode = '1' then
                         next_state <= started_endless ;                                             
                     elsif start_read_stop_pos_mode = '1' then
                         next_state <= started_read_stop_pos ;
                     end if;
                     
                   WHEN started_endless =>
                     if cell_cntr = conv_std_logic_vector(1,10) then 
                       next_state <= waiting_e;
                     end if;
                     
                                                                        
                                     
                 WHEN started_read_stop_pos =>        
                     if cell_cntr = conv_std_logic_vector(1,10) then 
                       next_state <= waiting_r;
                     end if;
                     
                 WHEN waiting_e =>        
                     if wait_cntr = conv_std_logic_vector(0,3) then
                       next_state <= running_e;
                     else 
                       next_state <= waiting_e;
                     end if;

                 WHEN waiting_r =>        
                     if wait_cntr = conv_std_logic_vector(0,3) then
                       next_state <= running_r;
                     end if;

                     
                   WHEN running_e =>
                      IF (start_endless_mode = '0') THEN
                        next_state <= idle;
                      END IF;
                  
                  WHEN running_r =>
                    if cell_cntr >= local_roi THEN
                     next_state <= idle;
                  end if;                           
     END CASE;
     end process transition;

     output_proc: process(current_state) --Ausgangsberechnung synchron, da current_state sich nur synchron aendert
         begin
             case current_state is

                 when idle =>
                    local_roi <= (others => '0');
                    flag_read_stop_pos <= '0';
                    stop_pos_valid <= '1'; 
                    LEN <= '0'; CEN <= '0';
                    busy <= '0';
                    cc_en <= '0'; cc_reset <= '1';
                    wc_en <= '0'; wc_reset <= '0';

                 when started_endless =>
                     local_roi <= "0111111111";
                     flag_read_stop_pos <= '0';
                     stop_pos_valid <= '0';
                     LEN <= '1'; CEN <= '0';
                     busy <= '1';
                     cc_en <= '1'; cc_reset <= '0';
                     wc_en <= '0'; wc_reset <= '1';

                 when started_read_stop_pos =>
                     local_roi <= conv_std_logic_vector(11,10);
                     flag_read_stop_pos <= '1';
                     stop_pos_valid <= '0';
                     LEN <= '1'; CEN <= '0';
                     busy <= '1';
                     cc_en <= '1'; cc_reset <= '0';
                     wc_en <= '0'; wc_reset <= '1';
 
                 when waiting_e | waiting_r =>
                     local_roi <= local_roi;
                     stop_pos_valid <= '0'; 
                     busy <= '1';
                     LEN <= '0'; CEN <= '0';
                     cc_en <= '0'; cc_reset <= '0';
                     wc_en <= '1'; wc_reset <= '0';
 
                 when running_e =>
                     flag_read_stop_pos <= '0';
                     stop_pos_valid <= '0'; 
                     LEN <= '0'; CEN <= '1';
                     cc_en <= '1'; cc_reset <= '0';
                     wc_en <= '0'; wc_reset <= '0';
                     busy <= '1';

              when running_r =>
                    flag_read_stop_pos <= '1';
                     stop_pos_valid <= '0'; 
                     LEN <= '0'; CEN <= '1';
                     cc_en <= '1'; cc_reset <= '0';
                     wc_en <= '0'; wc_reset <= '0';
                     busy <= '1';
             end case;
     end process output_proc;


     cellcounter: process (clk, cc_reset) begin

         if (cc_reset = '1') then
           cell_cntr <= (others=>'0');
         elsif (rising_edge(clk)) then
           if (cc_en = '1') then
             cell_cntr <= cell_cntr + 1;
           end if;
         end if;

     end process cellcounter;


     waitcounter: process (clk, wc_reset) begin
         if (wc_reset = '1') then
           wait_cntr <= "011"; -- RSRLOAD -> warte 3 -> SRCLK
         elsif (rising_edge(clk)) then
           if (wc_en = '1') then
             wait_cntr <= wait_cntr - 1;
           end if;
         end if;
     end process waitcounter;

  -- laut DRS4_rev09.pdf Seite 13 Figure 15
  -- funktioniert das auslesen der Stop bzw. Startadresse so:
  -- Sende 1x RSRLOAD- und mind. 9 SRCLK- pulse und sample SROUT zur 
  -- steigenden Flanke von SRCLK. 
  -- MSB first LSB last, kommen dann die 10 bits, 
  -- die die Stopposition darstellen.
  -- 
  -- diese Architecture liefert immer dann eine steigende Flanke
  -- auf RSRCLK, wenn CLK eine steigende Flanke hat und CEN='1' ist.
  -- Die an SROUT zur steigenden Flanke anliegenden Werte werden wie in einem Schieberegister
  -- Schritt fuer Schritt in die stop_pos_x vectoren geschoben.
  -- 
  -- wenn sie 10 schritte weit reingschoben wurden, ist der process fertig.
  -- es gibt keinen eigenen counter fuer die 10 schritte, der cell counter kann hier
  -- missbraucht werden.
  -- 
  -- da der process eine steigende flanke auf SRCLK braucht um SROUT zu sampeln 
  -- wird im Prinzip ein Puls aud SRCLK *zuviel* erzeugt, das ist aber egal...
  --
  stop_pos_reader: process (CEN, clk, flag_read_stop_pos)
  begin
    IF (flag_read_stop_pos = '1') THEN -- nur wenn ich im read_stop_mode bin, laeuft dieser process
      IF (CEN = '1') THEN -- nur wenn CEN='1' ist kommen SRCLK pulse raus. 
        IF (rising_edge(CLK)) THEN -- wenn steigende Flanke, dann SROUT samplen.
          int_stop_pos_0 <= int_stop_pos_0(8 downto 0) & SROUT_in_0;	
          int_stop_pos_1 <= int_stop_pos_1(8 downto 0) & SROUT_in_1;	
          int_stop_pos_2 <= int_stop_pos_2(8 downto 0) & SROUT_in_2;	
          int_stop_pos_3 <= int_stop_pos_3(8 downto 0) & SROUT_in_3;	
          
        END IF; -- rising edge CLK
      END IF; -- CEN ='1'
    END IF; -- flag_read_stop_pos = '1'
  end process stop_pos_reader;  
  
end behavior;