library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

library work;
    use work.reg32.all;
    use work.task.all;

entity crc is
    port (
        clk : in std_logic;
        reset : in std_logic;
        
        task_start : in std_logic;
        task_state : out work.task.State;
        
        signal_read : out std_logic;
        signal_readdata : in std_logic_vector( 31 downto 0 );
        
        signal_write : out std_logic;
        signal_writedata : out std_logic_vector( 31 downto 0 )
    );
end entity crc;

architecture rtl of crc is
    signal current_task_state : work.task.State;
    signal next_task_state : work.task.State;
    signal index : integer range 0 to work.task.STREAM_LEN;
    
    constant CRC_INIT : std_logic_vector(31 downto 0) := X"FFFFFFFF";
    constant CRC_POLY : std_logic_vector(31 downto 0) := X"EDB88320";
    
    signal crc_reg : std_logic_vector(31 downto 0) := CRC_INIT;
    signal data_reg : std_logic_vector(31 downto 0);
    signal data_ready : std_logic := '0';

begin
    task_state <= current_task_state;

    task_state_transitions : process ( current_task_state, task_start, index ) is
    begin
        next_task_state <= current_task_state;
        case current_task_state is
            when work.task.TASK_IDLE =>
                if task_start = '1' then
                    next_task_state <= work.task.TASK_RUNNING;
                end if;
            when work.task.TASK_RUNNING =>
                if index = work.task.STREAM_LEN then
                    next_task_state <= work.task.TASK_DONE;
                end if;
            when work.task.TASK_DONE =>
                if task_start = '1' then
                    next_task_state <= work.task.TASK_RUNNING;
                end if;
        end case;
    end process;

    signal_read <= '1' when current_task_state = work.task.TASK_RUNNING 
                             and data_ready = '0' 
                             and index < work.task.STREAM_LEN 
                  else '0';
    
    signal_write <= '1' when current_task_state = work.task.TASK_DONE else '0';
    
    signal_writedata <= crc_reg xor X"FFFFFFFF";

sync : process ( clk, reset ) is
    variable temp_crc : std_logic_vector(31 downto 0);
begin
    if reset = '1' then
        current_task_state <= work.task.TASK_IDLE;
        index <= 0;
        crc_reg <= CRC_INIT;
        data_reg <= X"00000000";
        data_ready <= '0';
        
    elsif rising_edge(clk) then
        current_task_state <= next_task_state;
        
        case next_task_state is
            when work.task.TASK_IDLE =>
                index <= 0;
                crc_reg <= CRC_INIT;
                data_ready <= '0';
                data_reg <= X"00000000";
                
            when work.task.TASK_RUNNING =>
                -- DATA LESEN (Timing korrekt)
                if signal_read = '1' then
                    data_reg <= signal_readdata;
                    data_ready <= '1';
                end if;
                
                -- CRC UPDATE (INDEX PRÜFEN VOR Update!)
                if data_ready = '1' then
                    -- WICHTIG: Index bleibt gleich bis TASK_DONE triggert!
                    --temp_crc := crc_reg xor data_reg;  -- Berechne aber schreibe nicht sofort
                    
                    temp_crc := crc_reg xor data_reg;
                    for i in 0 to 31 loop
                        if temp_crc(0) = '1' then
                            temp_crc := std_logic_vector(shift_right(unsigned(temp_crc), 1)) xor CRC_POLY;
                        else
                            temp_crc := std_logic_vector(shift_right(unsigned(temp_crc), 1));
                        end if;
                    end loop;
                    
                    crc_reg <= temp_crc;
                    data_ready <= '0';
                    
                    -- INDEX NUR erhöhen wenn NICHT letzter!
                    if index < work.task.STREAM_LEN then
                        index <= index + 1;
                    end if;  -- Bei index=1023: bleibt 1023 → TASK_DONE triggert!
                end if;
                
            when work.task.TASK_DONE =>
                index <= 0;
                data_ready <= '0';
        end case;
    end if;
end process sync;


end architecture rtl;
