----------------------------------------------------------------------------------
-- $File: READERWindowDetect.vhd$
--
-- Contents:
-- Funktion: Nach READ_ENABLE = 1 wird das BUSY-FLAG gesetzt und solange gewartet,
--           bis der StepCounter den Anfang des WINDOW erreicht hat. Darauf wird
--           das TRIGGER-Flag gesetzt. Bei Erreichen des WINDOW-Ende wird das
--           BUSY-Flag und das TRIGGER-Flag wieder zurueckgesetzt.
--           Zwischen Window Start und -Ende kann das Mask-Fenster definiert sein.
--           Waehrend des MASK-Fensters wird das TRIGGER-Flag zurueckgesetzt.
--           Die State-Maschine wird auf Idle zurueckgesetzt wenn READ_ENABLE auf 0
--           zurueckgesetzt wird oder nach RESET.
--
--           Die Window- und Mask-Grenzen sind scharf definiert, (kein >= usw)
--           Bedingung fuer das Funktionieren der Fenstererkennung ist die korrekte
--           Initialisierung von WINDOW- und MASK-Werten
--           Die Reihenfolge der Fenstererkennung ist fix. Wenn also z.B. MASK_START
--           kleiner ist als WINDOW_START aber nicht null, so wird MASK_START erst nach
--           einem STEP_COUNT Ueberlauf erreicht.
--
--           MASK_START = 0: kein Mask Fenster, nach WAIT_WINDOW_START wird direkt
--                           nach WAIT_WINDOW_END gewechselt
--           WINDOW_END = 0: kein Lesefenster, WindowDetect wird auch bei REEAD_ENABLE
--                           nicht BUSY
--
-- Inputs:
--     READ_ENABLE     1: State-Maschine laeuft ab (falls WINDOW_END <> 0)
--                     0: State-Maschine wird auf Idle gesetzt
--
--     WINDOW_START    \ 
--     WINDOW_END       \ 14Bit Fenster-Grenzen. Die Window- und Mask-Definition
--     MASK_START       | ist Basis fuer die Ausgangssignale
--     MASK_END        | 
-- 
--     STEP_COUNT      14Bit Wert des StepCounters. Die Windows sind bezogen
--                     auf den StepCounter definiert
--
-- Outputs:
--     BUSY_FLAG       State-Maschine laeuft ab aufgrund von READ_ENABLE = 1
--
--     WINDOW_FLAG     Der StepCounter befindet sich zwischen WINDOW_START und _END
--     MASK_FLAG        "     "          "        "    "      MASK_START und _END
--                     falls MASK definiert
----------------------------------------------------------------------------------

-- WindowDetect -----------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;

entity READERWindowDetect is
    port (
        -- system
        INT_CLK                             : in    STD_LOGIC;
        INT_RESET                           : in    STD_LOGIC;
        -- window detect
        READ_ENABLE                         : in    STD_LOGIC;
        WINDOW_START                        : in    STD_LOGIC_VECTOR(13 downto 0);
        WINDOW_END                          : in    STD_LOGIC_VECTOR(13 downto 0);
        MASK_START                          : in    STD_LOGIC_VECTOR(13 downto 0);
        MASK_END                            : in    STD_LOGIC_VECTOR(13 downto 0);
        STEP_COUNT                          : in    STD_LOGIC_VECTOR(13 downto 0);
        -- control outputs
        BUSY_FLAG                           : out   STD_LOGIC;
        TRIGGER_FLAG                        : out   STD_LOGIC
    );
end READERWindowDetect;

architecture READERWindowDetect_arch of READERWindowDetect is
    
    type state_type is (WAIT_ENABLE, WAIT_WINDOW_START, WAIT_MASK_START, WAIT_MASK_END, WAIT_WINDOW_END, WAIT_ENABLE_END );
    signal current_state                    : state_type := WAIT_ENABLE;
    signal next_state                       : state_type;

    -- Fenster-Grenzen erkennen
    signal WS_flag                          : STD_LOGIC; -- Window Start detect
    signal WE_flag                          : STD_LOGIC; -- Window End detect
    signal MS_flag                          : STD_LOGIC; -- Mask Start detect
    signal ME_flag                          : STD_LOGIC; -- Mask End detect
    signal WE_VALID_flag                    : STD_LOGIC; -- Erkennen ob Window Ende gueltig definiert ist, ungleich 0
    signal MS_VALID_flag                    : STD_LOGIC; -- Erkennen ob Mask Start gueltig ist, d.h. ein Mask-Fenster definiert ist
 
begin
    
    -- IDLE state after RESET and when no READ_ENABLE, else next state
    -- and synchronize input signal READ_ENABLE
    process(INT_CLK,INT_RESET)
    begin
        if INT_RESET = '1' then
            current_state   <= WAIT_ENABLE;
        elsif rising_edge(INT_CLK) then
            if READ_ENABLE = '1' then
                current_state <= next_state;
             else
                current_state <= WAIT_ENABLE;
            end if;
        end if;
    end process;

    -- state machine
    process (current_state, READ_ENABLE, WE_VALID_flag, WS_flag, MS_VALID_flag, MS_flag, ME_flag, WE_flag )
    begin
        -- Default-Werte, werden uebernommen wenn sonst nichts zutrifft, z.B. in IDLE
        BUSY_FLAG       <= '0';
        TRIGGER_FLAG    <= '0';
        next_state      <= WAIT_ENABLE;
        
        case current_state is
            when WAIT_ENABLE =>
                -- Start des Lesezyklus wenn READ_ENABLE = 1 wird, sonst bleibt
                -- current_state immer auf IDLE
                -- Nur starten wenn ein gueltiges Lesung Ende definiert ist
                if READ_ENABLE = '1' then
                    if WE_VALID_flag = '1' then
	                   BUSY_FLAG       <= '1';
	                   TRIGGER_FLAG    <= '0';
	                   next_state      <= WAIT_WINDOW_START;   -- Ablauf starten bei gueltigem Window
                    else
	                   BUSY_FLAG       <= '0';
	                   TRIGGER_FLAG    <= '0';
	                   next_state      <= WAIT_ENABLE_END;     -- Ablauf nicht starten, ungueltiges Window
				end if;
                else
                    next_state          <= WAIT_ENABLE;         -- kein gueltiges Window -> Abbruch
                end if;
                
            when WAIT_WINDOW_START =>
                -- warten auf den Anfang des WINDOW
                if WS_flag = '1' then
                    -- STEP_COUNT hat WINDOW_START erreicht
                    if MS_VALID_flag = '0' then
                        -- keine MASK definiert
                        BUSY_FLAG       <= '1';
                        TRIGGER_FLAG    <= '1';
                        next_state      <= WAIT_WINDOW_END;     -- warten auf Ende von WINDOW
                    else
                        -- MASK ist definiert
                        BUSY_FLAG       <= '1';
                        TRIGGER_FLAG    <= '1';
                        next_state      <= WAIT_MASK_START;     -- warten auf Anfang von MASK
                    end if;
                else
                    BUSY_FLAG           <= '1';
                    TRIGGER_FLAG        <= '0';
                    next_state          <= WAIT_WINDOW_START;   -- WINDOW Start noch nicht erreicht
                end if;
            
            when WAIT_MASK_START =>
                -- warten auf MASK
                if MS_flag = '1' then
                    -- STEP_COUNT hat MASK_START erreicht
                    BUSY_FLAG           <= '1';
                    TRIGGER_FLAG        <= '0';
                    next_state          <= WAIT_MASK_END;       -- warten auf Ende von MASK
                else
                    BUSY_FLAG           <= '1';
                    TRIGGER_FLAG        <= '1';
                    next_state          <= WAIT_MASK_START;     -- MASK Start noch nicht erreicht
                end if;
            
            when WAIT_MASK_END =>
                -- warten auf Ende von MASK
                if ME_flag = '1' then
                    BUSY_FLAG           <= '1';
                    TRIGGER_FLAG        <= '1';
                    next_state          <= WAIT_WINDOW_END;     -- warten auf Ende von WINDOW
                else
                    BUSY_FLAG           <= '1';
                    TRIGGER_FLAG        <= '0';
                    next_state          <= WAIT_MASK_END;       -- MASK Ende noch nicht erreicht
                end if;
        
            when WAIT_WINDOW_END =>
                -- warten auf Ende von WINDOW
                if WE_flag = '1' then
                    BUSY_FLAG           <= '0';
                    TRIGGER_FLAG        <= '0';
                    next_state          <= WAIT_ENABLE_END;     -- auf Ende von Enable warten
                else
                    BUSY_FLAG           <= '1';
                    TRIGGER_FLAG        <= '1';
                    next_state          <= WAIT_WINDOW_END;     -- WINDOW Ende noch nicht erreicht
                end if;

            when WAIT_ENABLE_END =>
                -- warten auf Ende von READ_ENABLE
                if READ_ENABLE = '1' then
                    next_state          <= WAIT_WINDOW_END;     -- warten auf neues Enable
                else
        	        -- State-Wechsel erfolgt dann automatisch im state change process
                    next_state <= WAIT_ENABLE_END;
                end if;

            when others =>   
                next_state <= WAIT_ENABLE;
        end case;
    end process;

    -- Fenstergrenzen erkennen
    WS_flag         <= '1' when STEP_COUNT = WINDOW_START       else '0';
    WE_flag         <= '1' when STEP_COUNT = WINDOW_END         else '0';
    MS_flag         <= '1' when STEP_COUNT = MASK_START         else '0';
    ME_flag         <= '1' when STEP_COUNT = MASK_END           else '0';
    WE_VALID_flag   <= '0' when WINDOW_END = "00000000000000"   else '1';
    MS_VALID_flag   <= '0' when MASK_START = "00000000000000"   else '1';

end READERWindowDetect_arch;
