-- altera vhdl_input_version vhdl_2008
-- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html)

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

use work.rtps_package.all;
use work.rtps_config_package.all;

entity TYPENAME_reader_interface is
    port (
        -- SYSTEM
        clk                                 : in std_logic;
        reset                               : in std_logic;
        -- FROM DDS READER
        start_dds                           : out std_logic;
        ack_dds                             : in std_logic;
        opcode_dds                          : out DDS_READER_OPCODE_TYPE;
        instance_state_dds                  : out std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        view_state_dds                      : out std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        sample_state_dds                    : out std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
        instance_handle_dds                 : out INSTANCE_HANDLE_TYPE;
        max_samples_dds                     : out std_logic_vector(MAX_SAMPLES_WIDTH-1 downto 0);
        get_data_dds                        : out std_logic;
        done_dds                            : in std_logic;
        return_code_dds                     : in std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        valid_in_dds                        : in std_logic;
        ready_in_dds                        : out std_logic;
        data_in_dds                         : in std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_in_dds                    : in std_logic;
        sample_info_dds                     : in SAMPLE_INFO_TYPE;
        sample_info_valid_dds               : in std_logic;
        sample_info_ack_dds                 : out std_logic;
        eoc_dds                             : in std_logic;
        -- Communication Status
        status_dds                          : in std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        
        -- TO USER ENTITY
        start_user                          : in std_logic;
        ack_user                            : out std_logic;
        opcode_user                         : in DDS_READER_OPCODE_TYPE;
        instance_state_user                 : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        view_state_user                     : in std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        sample_state_user                   : in std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
        instance_handle_user                : in INSTANCE_HANDLE_TYPE;
        max_samples_user                    : in std_logic_vector(MAX_SAMPLES_WIDTH-1 downto 0);
        get_data_user                       : in std_logic;
        done_user                           : out std_logic;
        return_code_user                    : out std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        -- Sample Info
        sample_info_user                    : out SAMPLE_INFO_TYPE;
        sample_info_valid_user              : out std_logic;
        sample_info_ack_user                : in std_logic;
        eoc_user                            : out std_logic;
        -- Communication Status
        status_user                         : out std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        decode_error                        : out std_logic;
        
        -- ###GENERATED START###
            -- TYPE SPECIFIC PORTS
        -- ###GENERATED END###
        valid                               : out std_logic
    );
end entity;

architecture arch of TYPENAME_reader_interface is
    
    --*****TYPE DECLARATION*****
    -- FSM states. Explained below in detail
    type STAGE_TYPE is (IDLE,GET_PAYLOAD_HEADER,FETCH,ALIGN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD);
    -- ###GENERATED START###
    type DECODE_STAGE_TYPE is (TODO,GET_OPTIONAL_HEADER);
        -- TYPES DECLARATIONS
    -- ###GENERATED END###
    
    -- *MAIN PROCESS*
    signal stage, stage_next : STAGE_TYPE;
    signal cnt, cnt_next : natural range 0 to 5;
    signal endian_flag, endian_flag_next : std_logic;
    signal last_word_in_latch, last_word_in_latch_next : std_logic;
    signal decode_error_latch, decode_error_latch_next : std_logic;
    signal align_offset, align_offset_next  : unsigned(MAX_ALIGN_OFFSET_WIDTH-1 downto 0);
    signal align_op, align_op_next : std_logic;
    signal target_align, target_align_next : ALIGN_TYPE;
    signal data_in_latch, data_in_latch_next : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal optional, optional_next : std_logic;
    signal abort_mem : std_logic;
    signal ready_in_dds_sig : std_logic;
    signal valid_sig, valid_sig_next : std_logic;
    signal decode_stage, decode_stage_next : DECODE_STAGE_TYPE;
    signal return_stage, return_stage_next : DECODE_STAGE_TYPE;
    -- ###GENERATED START###
        -- SIGNAL DECLARATIONS
    -- ###GENERATED END###
    
    --*****ALIAS DECLARATION*****
    alias representation_id         : std_logic_vector(PAYLOAD_REPRESENTATION_ID_WIDTH-1 downto 0) is data_in_dds(WORD_WIDTH-1 downto WORD_WIDTH-PAYLOAD_REPRESENTATION_ID_WIDTH);
    alias representation_options    : std_logic_vector(PAYLOAD_REPRESENTATION_ID_WIDTH-1 downto 0) is data_in_dds(PAYLOAD_REPRESENTATION_OPTIONS_WIDTH-1 downto 0);
    alias parameter_id              : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) is data_in_latch(WORD_WIDTH-1 downto WORD_WIDTH-PARAMETER_ID_WIDTH);
    alias parameter_length          : std_logic_vector(PARAMETER_LENGTH_WIDTH-1 downto 0) is data_in_latch(PARAMETER_LENGTH_WIDTH-1 downto 0);
    
    
begin
    
    -- ###GENERATED START###
        -- MEMORY INSTANTIATIONS
    -- ###GENERATED END###
    
    -- PASSTHROUGH
    start_dds                           <= start_user;
    ack_user                            <= ack_dds;
    opcode_dds                          <= opcode_user;
    instance_state_dds                  <= instance_state_user;
    view_state_dds                      <= view_state_user;
    sample_state_dds                    <= sample_state_user;
    instance_handle_dds                 <= instance_handle_user;
    max_samples_dds                     <= max_samples_user;
    get_data_dds                        <= get_data_user;
    done_user                           <= done_dds;
    return_code_user                    <= return_code_dds;
    sample_info_user                    <= sample_info_dds;
    sample_info_valid_user              <= sample_info_valid_dds;
    sample_info_ack_dds                 <= sample_info_ack_user;
    eoc_user                            <= eoc_dds;
    status_user                         <= status_dds;
    
    valid           <= valid_sig;
    decode_error    <= decode_error_latch;
    ready_in_dds    <= ready_in_dds_sig;
    
    -- ###GENERATED START###
        -- PORT SIGNAL CONNECTIONS
    -- ###GENERATED END###
    
    main_prc : process (all)
        variable tmp_length : unsigned(WORD_WIDTH-1 downto 0);
    begin
        -- DEFAULT
        stage_next                  <= stage;
        decode_stage_next           <= decode_stage;
        return_stage_next           <= return_stage;
        cnt_next                    <= cnt;
        endian_flag_next            <= endian_flag;
        last_word_in_latch_next     <= last_word_in_latch;
        decode_error_latch_next     <= decode_error_latch;
        align_offset_next           <= align_offset;
        target_align_next           <= target_align;
        optional_next               <= optional;
        valid_sig_next              <= valid_sig;
        data_in_latch_next          <= data_in_latch;
        align_op_next               <= align_op;
        abort_mem                   <= '0';
        ready_in_dds_sig            <= '0';
        -- ###GENERATED START###
            -- DEFAULT SIGNAL ASSIGNMENTS
        -- ###GENERATED END###
        
        -- Last Word Latch Setter
        if (last_word_in_dds = '1') then
            last_word_in_latch_next <= '1';
        end if;
        
        case (stage) is
            when IDLE =>
                -- User Requests Payload
                if (sample_info_valid_dds = '1' and sample_info_dds.valid_data = '1' and sample_info_ack_user = '1' and get_data_user = '1') then
                    stage_next  <= GET_PAYLOAD_HEADER;
                    -- RESET
                    decode_error_latch_next <= '0';
                    valid_sig_next          <= '0';
                    abort_mem               <= '1';
                else
                    -- ###GENERATED START###
                        -- MEMORY SIGNAL CONNECTIONS
                    -- ###GENERATED END###
                end if;
            when GET_PAYLOAD_HEADER =>
                -- TODO: Latch Offset from Options Field?
                
                ready_in_dds_sig    <= '1';
                -- Input Guard
                if (valid_in_dds = '1') then
                    case (representation_id) is
                        when CDR_BE =>
                            endian_flag_next    <= '0';
                            stage_next          <= FETCH;
                            -- Alignment Reset 
                            align_offset_next   <= (others => '0');
                            -- ###GENERATED START###
                            decode_stage_next   <= TODO;
                            -- ###GENERATED END###
                            -- Initial Fetch
                        when CDR_LE =>
                            endian_flag_next    <= '1';
                            stage_next          <= FETCH;
                            -- Alignment Reset 
                            align_offset_next   <= (others => '0');
                            -- ###GENERATED START###
                            decode_stage_next   <= TODO;
                            -- ###GENERATED END###
                        when others =>
                            -- Unknown Payload Encoding
                            stage_next              <= SKIP_PAYLOAD;
                            decode_error_latch_next <= '1';
                    end case;
                end if;
            when FETCH =>
                ready_in_dds_sig    <= '1';
                -- Input Guard
                if (valid_in_dds = '1') then
                    data_in_latch_next  <= data_in_dds;
                    -- Alignment Operation in progress
                    if (align_op = '1') then
                        stage_next      <= ALIGN_STREAM;
                        -- Reset
                        align_op_next   <= '0';
                    else
                        stage_next  <= DECODE_PAYLOAD;
                    end if;
                end if;
            when ALIGN_STREAM =>
                -- Target Stream Alignment reached
                if (check_align(align_offset, target_align)) then
                    -- DONE
                    stage_next  <= DECODE_PAYLOAD;
                else
                    align_offset_next   <= align_offset + 1;
                    -- Need to fetch new Input Word
                    if (align_offset(1 downto 0) = "11") then
                        align_op_next   <= '1';
                        stage_next      <= FETCH;
                    end if;
                end if;
            when SKIP_PAYLOAD =>
                if (last_word_in_latch = '0') then
                    -- Skip Read
                    ready_in_dds_sig    <= '1';
                else
                    stage_next  <= IDLE;
                    
                    -- If no Decode Error, mark output as valid
                    if (decode_error_latch = '0') then
                        valid_sig_next  <= '1';
                    end if;
                    
                    -- Reset
                    last_word_in_latch_next <= '0';
                end if;
            when DECODE_PAYLOAD =>
                case (decode_stage) is
                    -- ###GENERATED START###
                    when TODO =>
                    -- ###GENERATED END###
                    when GET_OPTIONAL_HEADER =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_4)) then
                            target_align_next   <= ALIGN_4;
                            stage_next          <= ALIGN_STREAM;
                        else
                            case (cnt) is
                                -- Optional Member Header
                                when 0 =>
                                    -- Extended Parameter Header
                                    if (endian_swap(endian_flag,parameter_id) = PID_EXTENDED) then
                                        cnt_next    <= cnt + 1;
                                        stage_next  <= FETCH;
                                    else
                                        stage_next          <= FETCH;
                                        decode_stage_next   <= return_stage;
                                        cnt_next            <= 0;
                                        -- Alignment Reset 
                                        align_offset_next   <= (others => '0');
                                        
                                        -- Optional omitted
                                        if(endian_swap(endian_flag,parameter_length) = (parameter_length'reverse_range => '0')) then
                                            optional_next   <= '0';
                                        else
                                            optional_next   <= '1';
                                        end if;
                                    end if;
                                -- eMemberHeader 
                                when 1 =>
                                    -- Ignore Parameter ID
                                    cnt_next    <= cnt + 1;
                                    stage_next  <= FETCH;
                                -- Llength
                                when 2 =>
                                    stage_next          <= FETCH;
                                    decode_stage_next   <= return_stage;
                                    cnt_next            <= 0;
                                    -- Alignment Reset 
                                    align_offset_next   <= (others => '0');
                                    
                                    -- Optional omitted
                                    if(endian_swap(endian_flag, data_in_dds) = (data_in_dds'reverse_range => '0')) then
                                        optional_next   <= '0';
                                    else
                                        optional_next   <= '1';
                                    end if;
                                when others =>
                                    null;
                            end case;
                        end if;
                    when others =>
                        null;
                end case;
            when others =>
                null;
        end case;
        
        -- OVERREAD GUARD
        -- Attempted read on empty input
        if (last_word_in_latch = '1' and last_word_in_dds = '0' and ready_in_dds_sig = '1') then
            stage_next              <= SKIP_PAYLOAD;
            decode_error_latch_next <= '1';
        end if;
        
    end process;
    
    sync_prc : process(clk)
    begin
        if rising_edge(clk) then
            if (reset = '1') then
                stage               <= IDLE;
                decode_stage        <= TODO;
                return_stage        <= TODO;
                target_align        <= ALIGN_1;
                cnt                 <= 0;
                endian_flag         <= '0';
                last_word_in_latch  <= '0';
                decode_error_latch  <= '0';
                optional            <= '0';
                valid_sig           <= '0';
                align_op            <= '0';
                align_offset        <= (others => '0');
                data_in_latch       <= (others => '0');
                -- ###GENERATED START###
                    -- RESET SYNC SIGNAL VALUE
                -- ###GENERATED END###
            else
                stage               <= stage_next;
                decode_stage        <= decode_stage_next;
                return_stage        <= return_stage_next;
                target_align        <= target_align_next;
                cnt                 <= cnt_next;
                endian_flag         <= endian_flag_next;
                last_word_in_latch  <= last_word_in_latch_next;
                decode_error_latch  <= decode_error_latch_next;
                optional            <= optional_next;
                valid_sig           <= valid_sig_next;
                align_op            <= align_op_next;
                align_offset        <= align_offset_next;
                data_in_latch       <= data_in_latch_next;
                -- ###GENERATED START###
                    -- SYNC SIGNALS
                -- ###GENERATED END###
            end if;
        end if;
    end process;
    
end architecture;