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 := 0;
    
    constant CRC_INIT  : std_logic_vector(31 downto 0) := X"FFFFFFFF";
    constant CRC_POLY  : std_logic_vector(31 downto 0) := X"EDB88320";
    signal crc         : std_logic_vector(31 downto 0) := CRC_INIT;
    signal data_reg    : std_logic_vector(31 downto 0);
    signal data_valid  : std_logic := '0';

begin
    task_state <= current_task_state;
    
    -- TASK STATE MACHINE (VORLAGE - nicht ändern!)
    task_state_transitions: process(current_task_state, task_start, index)
    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 =>
                -- WICHTIG: Schreiben nach 1024 Werten (index 0-1023)
                if index = 1023 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;

    -- Data Channel Control
    signal_read <= '1' when current_task_state = work.task.TASK_RUNNING 
                             and data_valid = '0' 
                             and index < 1024 
                  else '0';
    
    signal_write <= '1' when current_task_state = work.task.TASK_DONE else '0';
    signal_writedata <= crc xor X"FFFFFFFF";  -- Final XOR

    -- Haupt-Sync Process (identisch zur SW-Version)
    sync: process(clk, reset)
        variable temp_crc : std_logic_vector(31 downto 0);
    begin
        if reset = '1' then
            current_task_state <= work.task.TASK_IDLE;
            index <= 0;
            crc <= CRC_INIT;
            data_reg <= (others => '0');
            data_valid <= '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 <= CRC_INIT;
                    data_valid <= '0';
                    
                when work.task.TASK_RUNNING =>
                    -- 1. DATA LESEN (Timing: signal_read='1' -> NEXT CLK data_valid)
                    if signal_read = '1' then
                        data_reg <= signal_readdata;
                        data_valid <= '1';
                    end if;
                    
                    -- 2. CRC UPDATE (zlib: XOR dann 32x bitweise LSB-first)
                    if data_valid = '1' then
                        temp_crc := crc xor data_reg;
                        crc <= temp_crc;
                        
                        -- 32 Bit LSB-first Verarbeitung in EINEM Takt (wie SW)
                        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 <= temp_crc;
                        
                        data_valid <= '0';
                        index <= index + 1;
                    end if;
                    
                when work.task.TASK_DONE =>
                    index <= 0;
                    data_valid <= '0';
            end case;
        end if;
    end process;

end architecture rtl;

