-- 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;
use work.ros_package.all;

entity AddTwoInts_ros_srv_server is
    generic (
        LITTLE_ENDIAN   : std_logic := '0'
    );
    port (
        -- SYSTEM
        clk                                 : in std_logic;
        reset                               : in std_logic;
        -- FROM DDS READER
        start_r                             : out std_logic;
        ack_r                               : in std_logic;
        opcode_r                            : out DDS_READER_OPCODE_TYPE;
        instance_state_r                    : out std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        view_state_r                        : out std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        sample_state_r                      : out std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
        instance_handle_r                   : out INSTANCE_HANDLE_TYPE;
        max_samples_r                       : out std_logic_vector(MAX_SAMPLES_WIDTH-1 downto 0);
        get_data_r                          : out std_logic;
        done_r                              : in std_logic;
        return_code_r                       : in std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        valid_in_r                          : in std_logic;
        ready_in_r                          : out std_logic;
        data_in_r                           : in std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_in_r                      : in std_logic;
        sample_info_r                       : in SAMPLE_INFO_TYPE;
        sample_info_valid_r                 : in std_logic;
        sample_info_ack_r                   : out std_logic;
        eoc_r                               : in std_logic;
        status_r                            : in std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        -- FROM DDS WRITER
        start_w                             : out std_logic;
        ack_w                               : in std_logic;
        opcode_w                            : out DDS_WRITER_OPCODE_TYPE;
        instance_handle_in_w                : out INSTANCE_HANDLE_TYPE;
        source_ts_w                         : out TIME_TYPE;
        max_wait_w                          : out DURATION_TYPE;
        done_w                              : in std_logic;
        return_code_w                       : in std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        instance_handle_out_w               : in INSTANCE_HANDLE_TYPE;
        valid_out_w                         : out std_logic;
        ready_out_w                         : in std_logic;
        data_out_w                          : out std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_out_w                     : out std_logic;
        valid_in_w                          : in std_logic;
        ready_in_w                          : out std_logic;
        data_in_w                           : in std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_in_w                      : in std_logic;
        status_w                            : in std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        
        -- TO USER
        start_user                          : in std_logic;
        ack_user                            : out std_logic;
        opcode_user                         : in ROS_SERVICE_OPCODE_TYPE;
        service_info_user                   : out SERVICE_INFO_TYPE;
        request_id_user                     : in REQUEST_ID_TYPE;
        data_available_user                 : out std_logic;
        -- REQUEST
        taken_user                          : out std_logic;
        a                                   : out std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
        b                                   : out std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
        -- RESPONSE
        sum                                 : in std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
        done_user                           : out std_logic;
        return_code_user                    : out std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0)
    );
end entity;

architecture arch of AddTwoInts_ros_srv_server is
    
    --*****TYPE DECLARATION*****
    -- FSM states. Explained below in detail
    type STAGE_TYPE is (IDLE,RETURN_ROS,INITIATE_READ,WAIT_FOR_READER,WAIT_FOR_WRITER,WAIT_FOR_DATA,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD,INITIATE_WRITE,WRITE_PAYLOAD_HEADER,PUSH,ALIGN_OUT_STREAM,ENCODE_PAYLOAD);
    -- ###GENERATED START###
    type ENCODE_STAGE_TYPE is (WRITE_RID_WGUID,WRITE_RID_SN,WRITE_RR_SUM);
    type DECODE_STAGE_TYPE is (GET_RID_WGUID,GET_RID_SN,GET_OPTIONAL_HEADER,GET_RQ_A,GET_RQ_B);
    -- ###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 dw_latch, dw_latch_next : std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
    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 data_out_latch, data_out_latch_next : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal abort_mem : std_logic;
    signal ready_in_r_sig : std_logic;
    signal taken_sig, taken_sig_next : std_logic;
    signal service_info_sig, service_info_sig_next : SERVICE_INFO_TYPE;
    signal finalize_payload, finalize_payload_next : std_logic;
    signal encode_stage, encode_stage_next : ENCODE_STAGE_TYPE;
    signal decode_stage, decode_stage_next : DECODE_STAGE_TYPE;
    signal return_stage, return_stage_next : DECODE_STAGE_TYPE;
    signal return_code_latch, return_code_latch_next : std_logic_vector(ROS_RETCODE_WIDTH-1 downto 0);
    signal data_available_sig, data_available_sig_next : std_logic;
    -- ###GENERATED START###
    signal a_latch, a_latch_next : std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
    signal b_latch, b_latch_next : std_logic_vector(CDR_LONG_LONG_WIDTH-1 downto 0);
    -- ###GENERATED END###
    
    --*****ALIAS DECLARATION*****
    alias representation_id         : std_logic_vector(PAYLOAD_REPRESENTATION_ID_WIDTH-1 downto 0) is data_in_r(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_r(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###
    
    instance_state_r        <= ANY_INSTANCE_STATE;
    view_state_r            <= ANY_VIEW_STATE;
    sample_state_r          <= ANY_SAMPLE_STATE;
    instance_handle_r       <= HANDLE_NIL;
    max_samples_r           <= (others => '0');
    instance_handle_in_w    <= HANDLE_NIL;
    source_ts_w             <= TIME_INVALID;
    max_wait_w              <= DURATION_ZERO;
    ready_in_w              <= '0'; -- DDS Writer Input is unused
    taken_user              <= taken_sig;
    ready_in_r              <= ready_in_r_sig;
    service_info_user       <= service_info_sig;
    data_available_user     <= data_available_sig;
    
    -- ###GENERATED START###
    a   <= a_latch;
    b   <= b_latch;
    -- ###GENERATED END###
    
    main_prc : process (all)
        variable tmp_length : unsigned(WORD_WIDTH-1 downto 0);
    begin
        -- DEFAULT
        stage_next                  <= stage;
        encode_stage_next           <= encode_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;
        data_out_latch_next         <= data_out_latch;
        finalize_payload_next       <= finalize_payload;
        optional_next               <= optional;
        taken_sig_next              <= taken_sig;
        data_in_latch_next          <= data_in_latch;
        align_op_next               <= align_op;
        return_code_latch_next      <= return_code_latch;
        service_info_sig_next       <= service_info_sig;
        dw_latch_next               <= dw_latch;
        data_available_sig_next     <= data_available_sig;
        ready_in_r_sig              <= '0';
        abort_mem                   <= '0';
        ack_user                    <= '0';
        sample_info_ack_r           <= '0';
        get_data_r                  <= '0';
        start_r                     <= '0';
        opcode_r                    <= NOP;
        start_w                     <= '0';
        opcode_w                    <= NOP;
        valid_out_w                 <= '0';
        last_word_out_w             <= '0';
        done_user                   <= '0';
        return_code_user            <= ROS_RET_OK;
        data_out_w                  <= (others => '0');
        -- ###GENERATED START###
        a_latch_next    <= a_latch;
        b_latch_next    <= b_latch;
        -- ###GENERATED END###
        
        -- Last Word Latch Setter
        if (last_word_in_r = '1') then
            last_word_in_latch_next <= '1';
        end if;
        -- Data Available Setter
        if (check_mask(status_r, DATA_AVAILABLE_STATUS)) then
            data_available_sig_next <= '1';
        end if;
        
        
        case (stage) is
            when IDLE =>
                if (start_user = '1') then
                    ack_user    <= '1';
                    case (opcode_user) is
                        when TAKE_REQUEST =>
                            stage_next  <= INITIATE_READ;
                        when SEND_RESPONSE =>
                            stage_next  <= INITIATE_WRITE;
                        when others =>
                            return_code_latch_next  <= ROS_RET_UNSUPPORTED;
                            stage_next              <= RETURN_ROS;
                    end case;
                    -- RESET
                    taken_sig_next          <= '0';
                    abort_mem               <= '1';
                else
                    -- ###GENERATED START###
                        -- MEMORY SIGNAL CONNECTIONS
                    -- ###GENERATED END###
                end if;
            when RETURN_ROS =>
                done_user           <= '1';
                return_code_user    <= return_code_latch;
                
                -- DONE
                stage_next  <= IDLE;
            when INITIATE_READ =>
                start_r     <= '1';
                opcode_r    <= TAKE_NEXT_SAMPLE;
                
                if (ack_r = '1') then
                    stage_next  <= WAIT_FOR_READER;
                end if;
            when WAIT_FOR_READER =>
                if (done_r = '1') then
                    case (return_code_r) is
                        when RETCODE_OK =>
                            stage_next  <= WAIT_FOR_DATA;
                        when RETCODE_NO_DATA =>
                            assert (taken_sig = '0') severity FAILURE;
                            
                            -- Data Available Resetter
                            data_available_sig_next <= '0';
                            
                            return_code_latch_next  <= ROS_RET_OK;
                            stage_next              <= RETURN_ROS;
                        when others =>
                            return_code_latch_next  <= ROS_RET_ERROR;
                            stage_next              <= RETURN_ROS;
                    end case;
                end if;
            when WAIT_FOR_DATA =>
                if (sample_info_valid_r = '1') then
                    sample_info_ack_r   <= '1';
                    -- Meta Sample
                    if (sample_info_r.valid_data = '0') then
                        -- Ignore and read Next Sample
                        stage_next  <= INITIATE_READ;
                    else
                        get_data_r  <= '1';
                        stage_next  <= GET_PAYLOAD_HEADER;
                        
                        service_info_sig_next.received_timestamp    <= TIME_INVALID;
                        service_info_sig_next.source_timestamp      <= sample_info_r.source_timestamp;
                    end if;
                end if;
            when GET_PAYLOAD_HEADER =>
                -- TODO: Latch Offset from Options Field?
                
                ready_in_r_sig  <= '1';
                -- Input Guard
                if (valid_in_r = '1') then
                    case (representation_id) is
                        when CDR_BE =>
                            endian_flag_next    <= '0';
                            stage_next          <= FETCH;
                            -- Alignment Reset 
                            align_offset_next   <= (others => '0');
                            decode_stage_next   <= GET_RID_WGUID;
                            cnt_next            <= 0;
                            -- Initial Fetch
                        when CDR_LE =>
                            endian_flag_next    <= '1';
                            stage_next          <= FETCH;
                            -- Alignment Reset 
                            align_offset_next   <= (others => '0');
                            decode_stage_next   <= GET_RID_WGUID;
                            cnt_next            <= 0;
                        when others =>
                            -- Unknown Payload Encoding
                            stage_next              <= SKIP_PAYLOAD;
                            decode_error_latch_next <= '1';
                    end case;
                end if;
            when FETCH =>
                ready_in_r_sig    <= '1';
                -- Input Guard
                if (valid_in_r = '1') then
                    data_in_latch_next  <= data_in_r;
                    -- Alignment Operation in progress
                    if (align_op = '1') then
                        stage_next      <= ALIGN_IN_STREAM;
                        -- Reset
                        align_op_next   <= '0';
                    else
                        stage_next  <= DECODE_PAYLOAD;
                    end if;
                end if;
            when ALIGN_IN_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 DECODE_PAYLOAD =>
                case (decode_stage) is
                    -- NOTE:    The Cyclone DDS implementation uses a custom request header that is pre-pended to the actual service request/response.
                    --          It is defined as follows:
                    --              struct cdds_request_header_t{
                    --                  uint64_t guid;
                    --                  int64_t seq;
                    --              };
                    --          'seq' is set by a counter that is incremented on each "send_request".
                    --          'guid' is set to the publication handle of the request writer of the service client.
                    --          Note that the publication handle is useless for the server, since it is only meanigful localy (i.e. only the client can do something with it)
                    --          Nevertheless the same 'guid' has to be returned to the client.
                    when GET_RID_WGUID =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_IN_STREAM;
                        else
                            case (cnt) is
                                -- Double Word 1/2
                                when 0 =>
                                    dw_latch_next(CDR_LONG_LONG_WIDTH-1 downto CDR_LONG_LONG_WIDTH/2)   <= data_in_latch;
                                    stage_next  <= FETCH;
                                    cnt_next    <= cnt + 1;
                                -- Double Word 2/2
                                when 1 =>
                                    dw_latch_next((CDR_LONG_LONG_WIDTH/2)-1 downto 0)   <= data_in_latch;
                                    cnt_next    <= cnt + 1;
                                -- Push Double Word
                                when 2 =>
                                    service_info_sig_next.request_id.writer_guid(0) <= get_sub_vector(endian_swap(endian_flag, dw_latch),0,WORD_WIDTH,TRUE);
                                    service_info_sig_next.request_id.writer_guid(1) <= get_sub_vector(endian_swap(endian_flag, dw_latch),1,WORD_WIDTH,TRUE);
                                    stage_next          <= FETCH;
                                    align_offset_next   <= align_offset + 8;
                                    decode_stage_next   <= GET_RID_SN;
                                    cnt_next            <= 0;
                                when others =>
                                    null;
                            end case;
                        end if;
                    when GET_RID_SN =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_IN_STREAM;
                        else
                            case (cnt) is
                                -- Double Word 1/2
                                when 0 =>
                                    dw_latch_next(CDR_LONG_LONG_WIDTH-1 downto CDR_LONG_LONG_WIDTH/2)   <= data_in_latch;
                                    stage_next  <= FETCH;
                                    cnt_next    <= cnt + 1;
                                -- Double Word 2/2
                                when 1 =>
                                    dw_latch_next((CDR_LONG_LONG_WIDTH/2)-1 downto 0)   <= data_in_latch;
                                    cnt_next    <= cnt + 1;
                                -- Push Double Word
                                when 2 =>
                                    service_info_sig_next.request_id.sequence_number    <= to_double_word(unsigned(endian_swap(endian_flag, dw_latch)));
                                    stage_next          <= FETCH;
                                    align_offset_next   <= align_offset + 8;
                                    -- ###GENERATED START###
                                    decode_stage_next   <= GET_RQ_A;
                                    cnt_next            <= 0;
                                    -- ###GENERATED END###
                                when others =>
                                    null;
                            end case;
                        end if;
                    -- ###GENERATED START###
                    when GET_RQ_A =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_IN_STREAM;
                        else
                            case (cnt) is
                                -- Double Word 1/2
                                when 0 =>
                                    dw_latch_next(CDR_LONG_LONG_WIDTH-1 downto CDR_LONG_LONG_WIDTH/2)   <= data_in_latch;
                                    stage_next  <= FETCH;
                                    cnt_next    <= cnt + 1;
                                -- Double Word 2/2
                                when 1 =>
                                    dw_latch_next((CDR_LONG_LONG_WIDTH/2)-1 downto 0)   <= data_in_latch;
                                    cnt_next    <= cnt + 1;
                                -- Push Double Word
                                when 2 =>
                                    a_latch_next        <= endian_swap(endian_flag, dw_latch);
                                    stage_next          <= FETCH;
                                    align_offset_next   <= align_offset + 8;
                                    decode_stage_next   <= GET_RQ_B;
                                    cnt_next            <= 0;
                                when others =>
                                    null;
                            end case;
                        end if;
                    when GET_RQ_B =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_IN_STREAM;
                        else
                            case (cnt) is
                                -- Double Word 1/2
                                when 0 =>
                                    dw_latch_next(CDR_LONG_LONG_WIDTH-1 downto CDR_LONG_LONG_WIDTH/2)   <= data_in_latch;
                                    stage_next  <= FETCH;
                                    cnt_next    <= cnt + 1;
                                -- Double Word 2/2
                                when 1 =>
                                    dw_latch_next((CDR_LONG_LONG_WIDTH/2)-1 downto 0)   <= data_in_latch;
                                    cnt_next    <= cnt + 1;
                                -- Push Double Word
                                when 2 =>
                                    b_latch_next        <= endian_swap(endian_flag, dw_latch);
                                    stage_next          <= FETCH;
                                    align_offset_next   <= align_offset + 8;
                                    
                                    -- DONE
                                    stage_next  <= SKIP_PAYLOAD;
                                when others =>
                                    null;
                            end case;
                        end if;
                    -- ###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_IN_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_r) = (data_in_r'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 SKIP_PAYLOAD =>
                if (last_word_in_latch = '0') then
                    -- Skip Read
                    ready_in_r_sig    <= '1';
                else
                    -- Reset
                    last_word_in_latch_next <= '0';
                    
                    -- If no Decode Error, mark output as valid
                    if (decode_error_latch = '0') then
                        taken_sig_next          <= '1';
                        return_code_latch_next  <= ROS_RET_OK;
                    else
                        taken_sig_next          <= '0';
                        return_code_latch_next  <= ROS_RET_ERROR;
                    end if;
                    
                    stage_next  <= RETURN_ROS;
                end if;
            when INITIATE_WRITE =>
                start_w     <= '1';
                opcode_w    <= WRITE;
                
                if (ack_w = '1') then
                    stage_next  <= WRITE_PAYLOAD_HEADER;
                end if;
            when WRITE_PAYLOAD_HEADER =>
                valid_out_w     <= '1';
                if (LITTLE_ENDIAN = '0') then
                    data_out_w  <= CDR_BE & x"0000";
                else
                    data_out_w  <= CDR_LE & x"0000";
                end if;
                -- Output Guard
                if (ready_out_w = '1') then
                    stage_next  <= ENCODE_PAYLOAD;
                    -- Reset 
                    align_offset_next   <= (others => '0');
                    data_out_latch_next <= (others => '0');
                    encode_stage_next   <= WRITE_RID_WGUID;
                    cnt_next            <= 0;
                end if;
            when PUSH =>
                -- Mark Last Word
                if (finalize_payload = '1') then
                    last_word_out_w <= '1';
                end if;
                
                valid_out_w <= '1';
                data_out_w  <= data_out_latch;
                -- Output Guard
                if (ready_out_w = '1') then
                    -- NOTE: Ensures all padding is zero.
                    data_out_latch_next <= (others => '0');
                    -- Alignment Operation in process
                    if (align_op = '1') then
                        stage_next      <= ALIGN_OUT_STREAM;
                        -- Reset
                        align_op_next   <= '0';
                    -- DONE
                    elsif (finalize_payload = '1') then
                        finalize_payload_next   <= '0';
                        stage_next              <= WAIT_FOR_WRITER;
                    else
                        stage_next  <= ENCODE_PAYLOAD;
                    end if;
                end if;
            when ALIGN_OUT_STREAM =>
                -- Target Stream Alignment reached
                if (check_align(align_offset, target_align)) then
                    -- DONE
                    stage_next  <= ENCODE_PAYLOAD;
                else
                    align_offset_next   <= align_offset + 1;
                    -- Need to push Word
                    if (align_offset(1 downto 0) = "11") then
                        align_op_next   <= '1';
                        stage_next      <= PUSH;
                    end if;
                end if;
            when ENCODE_PAYLOAD =>
                case (encode_stage) is
                    when WRITE_RID_WGUID =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_OUT_STREAM;
                        else
                            case (cnt) is
                                when 0 =>
                                    data_out_latch_next <= get_sub_vector(endian_swap(LITTLE_ENDIAN, get_sub_vector(std_logic_vector(to_unsigned(request_id_user.writer_guid)), 0, 64, TRUE)), 0, WORD_WIDTH, TRUE);
                                    stage_next          <= PUSH;
                                    cnt_next            <= cnt + 1;
                                when 1 =>
                                    data_out_latch_next <= get_sub_vector(endian_swap(LITTLE_ENDIAN, get_sub_vector(std_logic_vector(to_unsigned(request_id_user.writer_guid)), 0, 64, TRUE)), 1, WORD_WIDTH, TRUE);
                                    stage_next          <= PUSH;
                                    align_offset_next   <= align_offset + 8;
                                    encode_stage_next   <= WRITE_RID_SN;
                                    cnt_next            <= 0;
                                when others => 
                            end case;
                        end if;
                    when WRITE_RID_SN =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_OUT_STREAM;
                        else
                            case (cnt) is
                                when 0 =>
                                    data_out_latch_next <= get_sub_vector(endian_swap(LITTLE_ENDIAN, std_logic_vector(to_unsigned(request_id_user.sequence_number))), 0, WORD_WIDTH, TRUE);
                                    stage_next          <= PUSH;
                                    cnt_next            <= cnt + 1;
                                when 1 =>
                                    data_out_latch_next <= get_sub_vector(endian_swap(LITTLE_ENDIAN, std_logic_vector(to_unsigned(request_id_user.sequence_number))), 1, WORD_WIDTH, TRUE);
                                    stage_next          <= PUSH;
                                    align_offset_next   <= align_offset + 8;
                                    -- ###GENERATED START###
                                    encode_stage_next   <= WRITE_RR_SUM;
                                    cnt_next            <= 0;
                                    -- ###GENERATED END###
                                when others => 
                            end case;
                        end if;
                    -- ###GENERATED START###
                    when WRITE_RR_SUM =>
                        -- ALIGN GUARD
                        if (not check_align(align_offset, ALIGN_8)) then
                            target_align_next   <= ALIGN_8;
                            stage_next          <= ALIGN_OUT_STREAM;
                        else
                            case (cnt) is
                                when 0 =>
                                    data_out_latch_next <= get_sub_vector(endian_swap(LITTLE_ENDIAN, sum), 0, WORD_WIDTH, TRUE);
                                    stage_next          <= PUSH;
                                    cnt_next            <= cnt + 1;
                                when 1 =>
                                    data_out_latch_next <= get_sub_vector(endian_swap(LITTLE_ENDIAN, sum), 1, WORD_WIDTH, TRUE);
                                    stage_next          <= PUSH;
                                    align_offset_next   <= align_offset + 8;
                                    
                                    -- DONE
                                    finalize_payload_next   <= '1';
                                when others => 
                            end case;
                        end if;
                    -- ###GENERATED END###
                    when others =>
                        null;
                end case;
            when WAIT_FOR_WRITER =>
                if (done_w = '1') then
                    case (return_code_w) is
                        when RETCODE_OK =>
                            return_code_latch_next  <= ROS_RET_OK;
                            stage_next              <= RETURN_ROS;
                        when others =>
                            return_code_latch_next  <= ROS_RET_ERROR;
                            stage_next              <= RETURN_ROS;
                    end case;
                end if;
            when others =>
                null;
        end case;
        
        -- OVERREAD GUARD
        -- Attempted read on empty input
        if (last_word_in_latch = '1' and last_word_in_r = '0' and ready_in_r_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;
                encode_stage        <= WRITE_RID_WGUID;
                decode_stage        <= GET_RID_WGUID;
                return_stage        <= GET_RID_WGUID;
                target_align        <= ALIGN_1;
                cnt                 <= 0;
                endian_flag         <= '0';
                last_word_in_latch  <= '0';
                decode_error_latch  <= '0';
                optional            <= '0';
                taken_sig           <= '0';
                align_op            <= '0';
                finalize_payload    <= '0';
                data_available_sig  <= '0';
                align_offset        <= (others => '0');
                data_in_latch       <= (others => '0');
                data_out_latch      <= (others => '0');
                dw_latch            <= (others => '0');
                return_code_latch   <= ROS_RET_OK;
                service_info_sig    <= EMPTY_SERVICE_INFO;
                -- ###GENERATED START###
                a_latch             <= (others => '0');
                b_latch             <= (others => '0');
                -- ###GENERATED END###
            else
                stage               <= stage_next;
                encode_stage        <= encode_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;
                taken_sig           <= taken_sig_next;
                align_op            <= align_op_next;
                finalize_payload    <= finalize_payload_next;
                data_available_sig  <= data_available_sig_next;
                align_offset        <= align_offset_next;
                data_in_latch       <= data_in_latch_next;
                data_out_latch      <= data_out_latch_next;
                dw_latch            <= dw_latch_next;
                return_code_latch   <= return_code_latch_next;
                service_info_sig    <= service_info_sig_next;
                -- ###GENERATED START###
                a_latch             <= a_latch_next;
                b_latch             <= b_latch_next;
                -- ###GENERATED END###
            end if;
        end if;
    end process;
    
end architecture;