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

entity history_cache is
    generic (
        TIME_BASED_FILTER_QOS       : DURATION_TYPE := DEFAULT_TIME_BASED_FILTER_QOS;
        MAX_INSTANCES               : natural       := DEFAULT_MAX_INSTANCES;
        MAX_SAMPLES_PER_INSTANCE    : natural       := DEFAULT_MAX_SAMPLES_PER_INSTANCE;
        HISTORY_QOS                 : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_HISTORY_QOS;
        RELIABILITY_QOS             : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_RELIABILTY_QOS;
        GENERATION_COUNTERS         : boolean   := TRUE;
    );
    port (
        clk             : in std_logic;
        reset           : in std_logic;
        
        start_a         : in std_logic;
        opcode_a        : in HISTORY_CACHE_OPCODE_TYPE;
        res_a           : out HISTORY_CACHE_RESPOSNE_TYPE;
        data_in_a       : in std_logic_vector(WORD_WIDTH-1 downto 0);
        valid_in_a      : in std_logic;
        ready_in_a      : out std_logic;
        last_word_in_a  : in std_logic;
        
        start_b         : in std_logic;
        opcode_b        : in HISTORY_CACHE_OPCODE_TYPE;
        res_b           : out HISTORY_CACHE_RESPOSNE_TYPE;
        data_out_b      : out std_logic_vector(WORD_WIDTH-1 downto 0);
        last_word_out_b : in std_logic;
    );
end entity;

architecture arch of history_cache is
    
    --*****CONSTANT DECLARATION*****
    -- Sample Info Memory Size in 4-Byte Words
    constant SAMPLE_MEMORY_SIZE         : natural := TODO;
    -- Sample Info Memory Address Width
    constant SAMPLE_MEMORY_ADDR_WIDTH   : natural := log2c(SAMPLE_MEMORY_SIZE);
    -- Highest Sample Info Memory Address
    constant SAMPLE_MEMORY_MAX_ADDRESS  : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(SAMPLE_MEMORY_SIZE-1, SAMPLE_MEMORY_ADDR_WIDTH);
    -- Highest Sample Info Frame Address
    constant MAX_SAMPLE_ADDRESS         : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := SAMPLE_MEMORY_MAX_ADDRESS - SAMPLE_INFO_FRAME_SIZE + 1;
    
    -- Payload Memory Size in 4-Byte Words
    constant PAYLOAD_MEMORY_SIZE        : natural := TODO;
    -- Payload Memory Address Width
    constant PAYLOAD_MEMORY_ADDR_WIDTH  : natural := log2c(PAYLOAD_MEMORY_SIZE);
    -- Highest Payload Memory Address
    constant PAYLOAD_MEMORY_MAX_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(PAYLOAD_MEMORY_SIZE-1, PAYLOAD_MEMORY_ADDR_WIDTH);
    -- Highest Payload Frame Address
    constant MAX_PAYLOAD_ADDRESS        : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := PAYLOAD_MEMORY_MAX_ADDRESS - PAYLOAD_FRAME_SIZE + 1;
    
    -- Instance Memory Size in 4-Byte Words
    constant INSTANCE_MEMORY_SIZE       : natural := TODO;
    -- Instance Memory Address Width
    constant INSTANCE_MEMORY_ADDR_WIDTH : natural := log2c(INSTANCE_MEMORY_SIZE);
    -- Highest Instance Memory Address
    constant INSTANCE_MEMORY_MAX_ADDRESS: unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(INSTANCE_MEMORY_SIZE-1, INSTANCE_MEMORY_ADDR_WIDTH);
    -- Highest Instance Frame Address
    constant MAX_INSTANCE_ADDRESS        : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := INSTANCE_MEMORY_MAX_ADDRESS - INSTANCE_FRAME_SIZE + 1;
    -- Address pointing to the beginning of the first Instance Data Frame
    constant FIRST_INSTANCE_ADDRESS     : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    
    -- *UPDATE INSTANCE FLAG POSITIONS*
    constant UPDATE_INSTANCE_FLAG_WIDTH : natural := 6;
    constant STATUS_FLAG                : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (0 => 1, others => '0');
    constant SAMPLE_CNT_FLAG            : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (1 => 1, others => '0');
    constant DISPOSED_CNT_FLAG          : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (2 => 1, others => '0');
    constant NO_WRITERS_CNT_FLAG        : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (3 => 1, others => '0');
    constant IGNORE_DEADLINE_FLAG       : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (4 => 1, others => '0');
    constant WRITER_BITMAP_FLAG         : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (5 => 1, others => '0');
    
    -- *SAMPLE MEMORY FRAME FORMAT*
    constant SMF_STATUS_INFO_OFFSET         : natural := 0;
    constant SMF_TIMESTAMP_OFFSET           : natural := 1;
    constant SMF_LIFESPAN_DEADLINE_OFFSET   : natural := 3;
    constant SMF_PAYLOAD_ADDR_OFFSET        : natural := 5;
    constant SMF_INSTANCE_ADDR_OFFSET       : natural := 6;
    constant SMF_DISPOSED_GEN_CNT_OFFSET    : natural := 7;
    constant SMF_NO_WRITERS_GEN_CNT_OFFSET  : natural := 8;
    constant SMF_PREV_ADDR_OFFSET           : natural := SMF_NO_WRITERS_GEN_CNT_OFFSET+1 when GENERATION_COUNTERS else SMF_INSTANCE_ADDR_OFFSET+1;
    constant SMF_NEXT_ADDR_OFFSET           : natural := SMF_PREV_ADDR_OFFSET+1;
    -- *PAYLOAD MEMORY FRAME FORMAT*
    constant PMF_NEXT_ADDR_OFFSET   : natural := 0;
    constant PMF_PAYLOAD_OFFSET     : natural := 1;
    -- *INSTANCE MEMORY FRAME OFFSET*
    constant IMF_NEXT_ADDR_OFFSET           : natural := 0;
    constant IMF_KEY_HASH_OFFSET            : natural := 1;
    constant IMF_STATUS_INFO_OFFSET         : natural := 5;
    constant IMF_SAMPLE_CNT_OFFSET          : natural := 6;
    constant IMF_DISPOSED_GEN_CNT_OFFSET    : natural := IMF_SAMPLE_CNT_OFFSET+1 when (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) else IMF_STATUS_INFO_OFFSET+1;
    constant IMF_NO_WRITERS_GEN_CNT_OFFSET  : natural := IMF_DISPOSED_GEN_CNT_OFFSET+1;
    constant IMF_IGNORE_DEADLINE_OFFSET     : natural := IMF_NO_WRITERS_GEN_CNT_OFFSET+1 when (GENERATION_COUNTERS) else
                                                         IMF_SAMPLE_CNT_OFFSET+1 when (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) else IMF_STATUS_INFO_OFFSET+1;
    constant IMF_WRITER_BITMAP_OFFSET       : natural := IMF_IGNORE_DEADLINE_OFFSET+2 when (TIME_BASED_FILTER_QOS /= DURATION_ZERO) else
                                                         IMF_NO_WRITERS_GEN_CNT_OFFSET+1 when (GENERATION_COUNTERS) else
                                                         IMF_SAMPLE_CNT_OFFSET+1 when (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) else IMF_STATUS_INFO_OFFSET+1;
    
    --*****TYPE DECLARATION*****
    -- FSM states. Explained below in detail
    type STAGE_TYPE is (IDLE, TODO);
    type INST_STAGE_TYPE is (IDLE, TODO);
    type INSTANCE_OPCODE_TYPE is (NOP, TODO);
    type INSTANCE_DATA_TYPE is record
        status_info         : std_logic_vector(WORD_WIDTH-1 downto 0);
        sample_cnt          : unsigned(WORD_WIDTH-1 downto 0);
        disposed_gen_cnt    : unsigned(WORD_WIDTH-1 downto 0);
        no_writers_gen_cnt  : unsigned(WORD_WIDTH-1 downto 0);
        ignore_deadline     : TIME_TYPE;
        writer_bitmap       : ENDPOINT_BITMAP_ARRAY_TYPE;
    end record;
    constant ZERO_INSTANCE_DATA : INSTANCE_DATA_TYPE := (
        status_info         => (others => '0'),
        sample_cnt          => (others => '0'),
        disposed_gen_cnt    => (others => '0'),
        no_writers_gen_cnt  => (others => '0'),
        ignore_deadline     => TIME_INVALID,
        writer_bitmap       => (others => (others => '0'))
    );
    type INST_LATCH_DATA_TYPE is record
        key_hash        : KEY_HASH_TYPE;
        instance_state  : INSTANCE_STATE_TYPE;
        gen_cnt         : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        deadline        : TIME_TYPE;
        writer_bitmap   : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1);
        update_flags    : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1);
        release_lock    : std_logic;
    end record;
    constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := (
        key_hash        => (others => (others => '0')),
        instance_state  => ALIVE,
        gen_cnt         => (others => '0'),
        deadline        => TIME_INVALID,
        writer_bitmap   => (others => (others => '0')),
        update_flags    => (others => '0'),
        release_lock    => '0'
    );
    
    --*****SIGNAL DECLARATION
    signal sample_addr_a, sample_addr_a_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal sample_addr_b, sample_addr_b_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal sample_wen_a, sample_wen_b : std_logic := '0';
    signal sample_ren_a, sample_ren_b : std_logic := '0';
    signal sample_read_data_a, sample_read_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    signal sample_write_data_a, sample_write_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    
    signal payload_addr_a, payload_addr_a_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal payload_addr_b, payload_addr_b_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal payload_wen_a, payload_wen_b : std_logic := '0';
    signal payload_ren_a, payload_ren_b : std_logic := '0';
    signal payload_read_data_a, payload_read_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    signal payload_write_data_a, payload_write_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    
    signal inst_addr_a, inst_addr_a_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_addr_b, inst_addr_b_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_wen_a, inst_wen_b : std_logic := '0';
    signal inst_ren_a, inst_ren_b : std_logic := '0';
    signal inst_read_data_a, inst_read_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    signal inst_write_data_a, inst_write_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    
    signal khg_valid_in, khg_ready_in, khg_last_word_in, khg_valid_out, khg_ready_out, khg_last_word_out : std_logic := '0';
    signal khg_data_in, khg_data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    
    signal stage_a, stage_a_next : STAGE_TYPE := IDLE;
    signal cnt_a, cnt_a_next : natural range TODO := 0;
    signal empty_sample_list_head, empty_sample_list_head_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal empty_sample_list_tail, empty_sample_list_tail_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal empty_payload_list_head, empty_payload_list_head_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal empty_payload_list_tail, empty_payload_list_tail_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal oldest_sample, oldest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal newest_sample, newest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal first_unread_sample, first_unread_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal payload_addr_latch_1, payload_addr_latch_1_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal payload_addr_latch_2, payload_addr_latch_2_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal sample_addr_latch_1, sample_addr_latch_1_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal sample_addr_latch_2, sample_addr_latch_2_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal ts_latch, ts_latch_next : TIME_TYPE := TIME_INVALID;
    signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
    signal payload_mem_full, payload_mem_full_next : std_logic := '0';
    signal sample_mem_full, sample_mem_full_next : std_logic := '0';
    signal writer_pos, writer_pos_next : natural range TODO := 0;
    signal writer_bitmap : ENDPOINT_BITMAP_ARRAY_TYPE;
    signal instance_state : INSTANCE_STATE_TYPE := ALIVE;
    signal key_hash, key_hash_next  : KEY_HASH_TYPE := (others => (others => '0'));
    signal od_instance_sample_removal : std_logic := '0';
    signal od_oldest_sample_removal : std_logic := '0';
    signal od_sample_removal_done : std_logic := '0';
    signal sample_status_info, sample_status_info_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
    signal gen_cnt  : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
    signal deadline : TIME_TYPE := TIME_INVALID;
    signal release_inst_lock : std_logic := '0';
    
    
    
    signal inst_op_start_a : std_logic := '0';
    signal inst_op_done_a : std_logic := '0';
    signal inst_opcode_a  : INSTANCE_OPCODE_TYPE := NOP;
    signal inst_stage_a, inst_stage_a_next  : INST_STAGE_TYPE := IDLE;
    signal inst_addr_base_a, inst_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_addr_base_a, inst_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_next_addr_base_a, inst_next_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_prev_addr_base_a, inst_prev_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_empty_head, inst_empty_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_occupied_tail, inst_occupied_tail_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
    signal inst_latch_data, inst_latch_data_next : INST_LATCH_DATA_TYPE := ZERO_INST_LATCH_DATA;
    signal update_inst_flags_a : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0');
    signal inst_cnt_a, inst_cnt_a_next : natural range TODO := 0;
    signal inst_mem_full, inst_mem_full_next : std_logic := '0';
    signal inst_delete_lock_a, inst_delete_lock_a_next : std_logic := '0';
    signal inst_atomic_lock_a : std_logic := '0';
    signal inst_long_latch_a, inst_long_latch_a_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
    
    --*****ALIAS DECLARATION*****
    alias prev_sample       : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1;
    alias prev_sample_next  : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1_next;
    alias next_sample       : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2;
    alias next_sample_next  : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2_next;
    alias cur_payload       : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1;
    alias cur_payload_next  : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1_next;
    alias next_payload      : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1;
    alias next_payload_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1_next;
    alias has_data          : std_logic is sample_status_info(PAYLOAD_FLAG);
    alias has_key_hash      : std_logic is sample_status_info(KEY_HASH_FLAG);
    
begin
    
    sample_ram_inst : entity work.true_dual_port_ram(arch)
        generic map (
            ADDR_WIDTH      => SAMPLE_MEMORY_ADDR_WIDTH,
            DATA_WIDTH      => WORD_WIDTH,
            MEMORY_DEPTH    => SAMPLE_MEMORY_SIZE
        )
        port map (
            clk         => clk,
            addr_a      => sample_addr_a,
            addr_b      => sample_addr_b,
            wen_a       => sample_wen_a,
            wen_b       => sample_wen_b,
            ren_a       => sample_ren_a,
            ren_b       => sample_ren_b,
            wr_data_a   => sample_write_data_a,
            wr_data_b   => sample_write_data_b,
            rd_data_a   => sample_read_data_a,
            rd_data_b   => sample_read_data_b
        );
    
    payload_ram_inst : entity work.true_dual_port_ram(arch)
        generic map (
            ADDR_WIDTH      => PAYLOAD_MEMORY_ADDR_WIDTH,
            DATA_WIDTH      => WORD_WIDTH,
            MEMORY_DEPTH    => PAYLOAD_MEMORY_SIZE
        )
        port map (
            clk         => clk,
            addr_a      => payload_addr_a,
            addr_b      => payload_addr_b,
            wen_a       => payload_wen_a,
            wen_b       => payload_wen_b,
            ren_a       => payload_ren_a,
            ren_b       => payload_ren_b,
            wr_data_a   => payload_write_data_a,
            wr_data_b   => payload_write_data_b,
            rd_data_a   => payload_read_data_a,
            rd_data_b   => payload_read_data_b
        );
        
    instance_ram_inst : entity work.true_dual_port_ram(arch)
        generic map (
            ADDR_WIDTH      => INSTANCE_MEMORY_ADDR_WIDTH,
            DATA_WIDTH      => WORD_WIDTH,
            MEMORY_DEPTH    => INSTANCE_MEMORY_SIZE
        )
        port map (
            clk         => clk,
            addr_a      => inst_addr_a,
            addr_b      => inst_addr_b,
            wen_a       => inst_wen_a,
            wen_b       => inst_wen_b,
            ren_a       => inst_ren_a,
            ren_b       => inst_ren_b,
            wr_data_a   => inst_write_data_a,
            wr_data_b   => inst_write_data_b,
            rd_data_a   => inst_read_data_a,
            rd_data_b   => inst_read_data_b
        );
        
    key_hash_generator_inst : entity work.key_hash_generator(arch)
        port (
            clk             => clk,
            reset           => reset,
            data_in         => khg_data_in,
            valid_in        => khg_valid_in,
            ready_in        => khg_ready_in,
            last_word_in    => khg_last_word_in,
            data_out        => khg_data_out,
            valid_out       => khg_valid_out,
            ready_out       => khg_ready_out,
            last_word_out   => khg_last_word_out
        );
    
    parse_a_prc : process (all)
        variable tmp_dw     : DOUBLE_WORD_ARRAY := (others => (others => '0'));
        variable tmp_bitmap : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1) := (others => '0');
        variable tmp_update : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0');
    begin
        -- Default
        stage_a_next                    <= stage_a;
        res_a                           <= UNDEFINED;
        sample_addr_a_next              <= sample_addr_a;
        sample_write_data_a             <= (others => '0');
        sample_ren_a                    <= '0';
        sample_wen_a                    <= '0';
        payload_addr_a_next             <= payload_addr_a;
        payload_write_data_a            <= (others => '0');
        payload_ren_a                   <= '0';
        payload_wen_a                   <= '0';
        ready_in_a                      <= '0';
        newest_sample_next              <= newest_sample;
        empty_payload_list_head_next    <= empty_payload_list_head;
        empty_sample_list_head_next     <= empty_sample_list_head;
        payload_addr_latch_1_next       <= payload_addr_latch_1;
        payload_addr_latch_2_next       <= payload_addr_latch_2;
        ts_latch_next                   <= ts_latch;
        long_latch_next                 <= long_latch;
        sample_addr_latch_1_next        <= sample_addr_latch_1;
        sample_addr_latch_2_next        <= sample_addr_latch_2;
        payload_mem_full_next           <= payload_mem_full;
        sample_mem_full_next            <= sample_mem_full;
        writer_pos_next                 <= writer_pos;
        inst_opcode_a                   <= NOP;
        key_hash_next                   <= key_hash;
        sample_status_info_next         <= sample_status_info;
        inst_op_start_a                 <= '0';
        khg_last_word_in                <= '0';
        khg_data_in                     <= (others => '0');
        khg_valid_in                    <= '0';
        khg_ready_out                   <= '0';
        writer_bitmap                   <= (others => '0');
        od_instance_sample_removal      <= '0';
        od_oldest_sample_removal        <= '0';
        release_inst_lock               <= '0';
        
        -- Reset Payload Memory Fullness Indicator
        if (payload_mem_full = '1' and empty_payload_list_head /= empty_payload_list_tail) then
            payload_mem_full_next   <= '0';
        end if;
        
        -- Reset Sample Memory Fullness Indicator
        if (sample_mem_full = '1' and empty_sample_list_head /= empty_sample_list_tail) then
            sample_mem_full_next    <= '0';
        end if;
        
        case (stage_a) is
            when IDLE =>
                -- Release Instance Memory Lock
                if (inst_delete_lock_a = '1' and inst_op_done_a = '1') then
                    inst_op_start_a <= '1';
                    inst_opcode_a   <= RELEASE_LOCK;
                end if;
                
                if (start_a = '1') then
                    ready_in_a  <= '1';
                    
                    case (opcode_a) is
                        when ADD_CHANGE =>
                            -- This Operation does not accept input at this time
                            ready_in_a          <= '0';
                            
                            -- If memory Full 
                            if (sample_mem_full = '1' or payload_mem_full = '1') then
                                stage_a_next    <= WAIT_FOR_REMOVE;
                                res_a           <= ACK;
                            else
                                stage_a_next        <= ADD_SAMPLE_INFO;
                                sample_addr_a_next  <= empty_sample_list_head;
                                cnt_a_next          <= 0;
                                res_a               <= ACK;
                            end if;
                        when REMOVE_WRITER =>
                            -- Input and Memory Gurad
                            if (valid_in_a = '1' and inst_op_done_a = '1') then
                                -- Latch Writer Pos
                                writer_pos_next <= to_integer(unsigned(data_in_a));
                                inst_op_start_a <= '1';
                                inst_opcode_a   <= GET_FIRST_INSTANCE;
                                stage_a_next    <= REMOVE_WRITER;
                                res_a           <= ACK;
                            end if;
                        when others =>
                            null;
                    end case;
                end if;
            
            when ADD_SAMPLE_INFO =>
                -- Precondition: sample_addr_a (empty_sample_list_head)
                
                ready_in_a  <= '1';
                
                -- Input Guard
                if (valid_in_a = '1') then
                    cnt_a_next          <= cnt_a + 1;
                    sample_addr_a_next  <= sample_addr_a + 1;
                    
                    -- Write Through
                    sample_wen_a        <= '1';
                    sample_write_data_a <= data_in_a;
                    
                    case (cnt_a) is
                        -- Status Info
                        when 0 =>
                            -- Initialize local status bits
                            sample_write_data_a(READ_FLAG)      <= '0';
                            -- Latch Status Info
                            sample_status_info_next             <= data_in_a;
                            sample_status_info_next(READ_FLAG)  <= '0';
                        -- Latch Timestamp for ordering
                        -- Timestamp 1/2
                        when 1 =>
                            ts_latch_next(0)    <= data_in_a;
                        -- Timestamp 2/2
                        when 2 =>
                            ts_latch_next(1)    <= data_in_a;
                        -- Lifespna Deadline 2/2
                        when 4 =>
                            -- Skip Key Hash, if not available
                            if (has_key_hash = '0') then
                                cnt_a_next  <= 9;
                            end if;
                        -- Latch Key Hash
                        -- Key Hash 1/4
                        when 5 =>
                            -- Latch Input, but do not pass to Memory
                            sample_wen_a        <= '0';
                            sample_addr_a_next  <= sample_addr_a;
                            key_hash_next(0)    <= data_in_a;
                        -- Key Hash 2/4
                        when 6 =>
                            -- Latch Input, but do not pass to Memory
                            sample_wen_a        <= '0';
                            sample_addr_a_next  <= sample_addr_a;
                            key_hash_next(1)    <= data_in_a;
                        -- Key Hash 3/4
                        when 7 =>
                            -- Latch Input, but do not pass to Memory
                            sample_wen_a        <= '0';
                            sample_addr_a_next  <= sample_addr_a;
                            key_hash_next(2)    <= data_in_a;
                        -- Key Hash 4/4
                        when 8 =>
                            -- Latch Input, but do not pass to Memory
                            sample_wen_a        <= '0';
                            sample_addr_a_next  <= sample_addr_a;
                            key_hash_next(3)    <= data_in_a;
                        when 9 =>
                            -- Latch Input, but do not pass to Memory
                            writer_pos_next     <= to_integer(unsigned(data_in_a));
                            sample_wen_a        <= '0';
                            sample_addr_a_next  <= sample_addr_a;
                            stage_a_next        <= ADD_PAYLOAD_ADDRESS;
                        when others =>
                            null;
                    end case;
                end if;
            when ADD_PAYLOAD_ADDRESS =>
                -- Precondition: sample_addr_a (Payload Address)
                
                sample_addr_a_next  <= sample_addr_a + 1; -- Instance Address
                
                if (has_data = '1') then
                    -- Store Payload Address
                    sample_wen_a        <= '1';
                    sample_write_data_a <= empty_payload_list_head;
                    
                    payload_addr_a_next     <= empty_payload_list_head + PMF_NEXT_ADDR_OFFSET;
                    cur_payload_next        <= empty_payload_list_head;
                else
                    -- Mark Sample with no Payload
                    sample_wen_a        <= '1';
                    sample_write_data_a <= PAYLOAD_MEMORY_MAX_ADDRESS;
                end if;
                
                -- If key Hash is avialable, start the Instacne Search first
                if (has_key_hash = '1') then
                    stage_a_next    <= INITIATE_INSTANCE_SEARCH;
                else
                    stage_a_next    <= ADD_PAYLOAD;
                    cnt_a_next      <= 0;
                end if;
            when ADD_PAYLOAD =>
                -- Precondition (if has_data = '1'): cur_payload set (Current Slot), payload_addr_a (Beginning of Payload Data of cur_payload)
                
                -- NOTE: This state is responsible for reading the payload and writing it through to the local payload memory
                --       and key hash generator (KHG). This state is taken on following cases:
                -- has_data     has_key_hash
                --    1              1          The payload is written to memory
                --    1              0          The payload is written to memory and the KHG at the same time (KHG controls the flow)
                --    0              0          There is no payload to write, but the input contains the key for the KHG
                
                if (has_key_hash = '0') then
                    ready_in_a  <= khg_ready_in;
                else
                    ready_in_a  <= '1';
                end if;
                
                -- Flow Control Guard
                if ((valid_in_a = '1' and has_key_hash = '0') or (valid_in_a = '1' and has_key_hash = '0' and khg_ready_in = '1')) then
                    cnt_a_next          <= cnt_a + 1;
                    payload_addr_a_next <= payload_addr_a + PMF_NEXT_ADDR_OFFSET;
                    
                    -- Payload Write
                    if (has_data = '1') then
                        payload_write_data_a    <= data_in_a;
                        payload_wen_a           <= '1';
                    end if;
                    
                    -- Key Hash Generator Write
                    if (has_key_hash = '0') then
                        khg_data_in     <= data_in_a;
                        khg_valid_in    <= '1';
                    end if;
                    
                    -- End of Payload
                    if (last_word_in_a = '1') then
                        if (has_key_hash = '0') then
                            khg_last_word_in    <= '1';
                            stage_a_next        <= GET_KEY_HASH;
                            cnt_a_next          <= 0;
                        else
                            stage_a_next        <= FILTER_STAGE;
                        end if;
                    -- End of Payload Slot
                    elsif (has_data = '1' and cnt_a = PAYLOAD_FRAME_SIZE-2) then
                        stage_a_next        <= NEXT_PAYLOAD_SLOT;
                        payload_addr_a_next <= cur_payload;
                        cnt_a_next          <= 0;
                    end if;
                end if;
            when NEXT_PAYLOAD_SLOT =>
                -- Precondition: payload_addr_a (Beginning of current Slot)
                
                cnt_a_next  <= cnt_a + 1;
                
                case (cnt_a) is
                    -- Preload
                    when 0 =>
                        payload_ren_a   <= '1';
                    when 1 =>
                        -- No Empty Payload Slots available
                        if (payload_read_data_a = PAYLOAD_MEMORY_MAX_ADDRESS) then
                            -- TODO
                        else
                            -- Latch next Payload Slot and Continue
                            cur_payload_next    <= payload_read_data_a;
                            payload_addr_a_next <= payload_read_data_a + PMF_NEXT_ADDR_OFFSET;
                            stage_a_next        <= ADD_PAYLOAD;
                        end if;
                    when others =>
                        null;
                end case;
            when GET_KEY_HASH =>
                
                khg_ready_out   <= '1';
                
                if (khg_valid_out = '1') then
                    cnt_a_next          <= cnt_a + 1;
                    
                    -- Latch Key Hash
                    key_hash_next(cnt_a)    <= khg_data_out;
                    
                    -- Exit Condition
                    if (khg_last_word_out = '1') then
                        -- DONE
                        stage_a_next    <= INITIATE_INSTANCE_SEARCH;
                    end if;
                end if;
            when INITIATE_INSTANCE_SEARCH =>
                -- Memory Operation Guard
                if (inst_op_done_a = '1') then
                    inst_opcode_a   <= SEARCH_INSTANCE;
                    inst_op_start_a <= '1';
                    
                    -- Payload not yet stored
                    if (has_data = '1') then
                        stage_a_next    <= ADD_PAYLOAD;
                        cnt_a_next      <= 0;
                    else
                        stage_a_next    <= FILTER_STAGE;
                    end if;
                end if;
            when FILTER_STAGE =>
                -- Precondition: sample_addr_a (Instance Address of New Sample)
                
                -- Wait for Instance Search to finish
                if (inst_op_done_a = '1') then
                    sample_addr_a_next  <= sample_addr_a + 1; -- Disposed Gen Counter (Prev Address if GENERATION_COUNTERS=FALSE)
                    
                    -- Instance Found
                    if (inst_addr_base_a /= INSTANCE_MEMORY_MAX_ADDRESS) then
                        -- Store Instance Address
                        sample_write_data_a <= inst_addr_base_a;
                        sample_wen_a        <= '1';
                        
                        -- TIME_BASED_FILTER QOS
                        if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time < inst_data.ignore_deadline) then
                            -- Reject Change
                            res_a           <= REJECTED;
                            stage_a_next    <= IDLE;
                        -- RESOURCE_LIMITS_QOS / HISTORY_QOS
                        elsif (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then
                            if (HISTORY_QOS = KEEP_LAST_HISTORY_QOS) then
                               -- Reject Change
                                res_a           <= REJECTED;
                                stage_a_next    <= IDLE;
                            else
                                od_instance_sample_removal  <= '1';
                                -- Wait until B process completes On-Demand Sample Removal
                                if (od_sample_removal_done = '1') then
                                    -- Accept Change
                                    res_a           <= ACCEPTED;
                                    stage_a_next    <= UPDATE_INSTANCE;
                                end if;
                            end if;
                        else
                            -- Accept Change
                            res_a           <= ACCEPTED;
                            stage_a_next    <= UPDATE_INSTANCE;
                        end if;
                    else
                        -- Store Instance Address
                        sample_write_data_a <= inst_empty_head;
                        sample_wen_a        <= '1';
                        
                        -- MAX_INSTANCES Reached (Instance Memory Full)
                        if (inst_mem_full = '1') then
                            -- Reject Change
                            res_a           <= REJECTED;
                            stage_a_next    <= IDLE;
                        else
                            -- Accept Change
                            res_a   <= ACCEPTED;
                            
                            -- Only Insert Sample/Instance if Instance is ALIVE
                            if (sample_status_info(DISPOSED_FLAG) /= '1' and sample_status_info(UNREGISTERED_FLAG) /= '1' and sample_status_info(FILTERED_FLAG) /= '1') then
                                -- Insert New Instance
                                inst_opcode_a       <= INSERT_INSTANCE;
                                inst_op_start_a     <= '1';
                                release_inst_lock   <= '1';
                                
                                if (has_data = '1') then
                                    payload_addr_a_next <= cur_payload;
                                    stage_a_next        <= FINALIZE_PAYLOAD;
                                    cnt_a_next          <= 0;
                                else
                                    stage_a_next        <= SAMPLE_PRE_FINISH;
                                    cnt_a_next          <= 0 when GENERATION_COUNTERS else 2;
                                end if;
                            else
                                -- Ignore
                                stage_a_next    <= IDLE;
                            end if;
                        end if;
                    end if;
                end if;
            when UPDATE_INSTANCE =>
                -- Memory Operation Guard
                if (inst_op_done_a = '1') then
                    -- DEFAULT
                    tmp_update  := (others => '0');
                    
                    -- Instance DISPOSED
                    if (sample_status_info(DISPOSED_FLAG) = '1') then
                        -- ALIVE -> NOT_ALIVE_DISPOSED Transition
                        if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) /= '1') then
                            -- STATUS INFO
                            tmp_update      <= tmp_update or STATUS_FLAG;
                            instance_state  <= NOT_ALIVE_DISPOSED;
                        end if;
                        -- WRITER BITMAP
                        -- Convert Writer Bitmap to SLV
                        tmp_bitmap              := to_endpoint_bitmap(inst_data.writer_bitmap);
                        -- Remove Writer
                        tmp_bitmap(writer_pos)  := '0';
                        -- Convert Back
                        writer_bitmap           <= from_endpoint_bitmap(tmp_bitmap);
                        tmp_update              := tmp_update or WRITER_BITMAP_FLAG;
                    -- Instance UNREGISTERED
                    elsif (sample_status_info(UNREGISTERED_FLAG) = '1') then
                        -- WRITER BITMAP
                        -- Convert Writer Bitmap to SLV
                        tmp_bitmap              := to_endpoint_bitmap(inst_data.writer_bitmap);
                        -- Remove Writer
                        tmp_bitmap(writer_pos)  := '0';
                        -- Convert Back
                        writer_bitmap           <= from_endpoint_bitmap(tmp_bitmap);
                        tmp_update              := tmp_update or WRITER_BITMAP_FLAG;
                        
                        -- ALIVE -> NOT_ALIVE_NO_WRITERS Transition
                        if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) /= '1' and tmp_bitmap = (tmp_bitmap => '0')) then
                            -- STATUS INFO
                            tmp_update          <= tmp_update or STATUS_FLAG;
                            instance_state      <= NOT_ALIVE_NO_WRITERS;
                        end if;
                    -- Instance ALIVE/FILTERED
                    else
                        -- STATUS INFO
                        tmp_update      <= tmp_update or STATUS_FLAG;
                        instance_state  <= ALIVE;
                        
                        -- GENERATION COUNTERS
                        if (GENERATION_COUNTERS) then
                            -- NOT_ALIVE_DISPOSED -> ALIVE Transition
                            if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1') then
                                tmp_update  := tmp_update or DISPOSED_CNT_FLAG;
                                gen_cnt     <= inst_data.disposed_gen_cnt + 1;
                            -- NOT_ALIVE_NO_WRITERS -> ALIVE Transition
                            elsif (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then
                                tmp_update := tmp_update or NO_WRITERS_CNT_FLAG;
                                gen_cnt     <= inst_data.no_writers_gen_cnt + 1;
                            end if;
                        end if;
                        
                        -- WRITER BITMAP
                        -- Convert Writer Bitmap to SLV
                        tmp_bitmap              := to_endpoint_bitmap(inst_data.writer_bitmap);
                        -- Write if Writer New for Instance
                        if (tmp_bitmap(writer_pos) /= '1') then
                            -- Remove Writer
                            tmp_bitmap(writer_pos)  := '0';
                            -- Convert Back
                            writer_bitmap           <= from_endpoint_bitmap(tmp_bitmap);
                            tmp_update              := tmp_update or WRITER_BITMAP_FLAG;
                        end if;
                    end if;
                    
                    -- INSANCE SAMPLE COUNT
                    if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then
                        tmp_update := tmp_update or SAMPLE_CNT_FLAG;
                    end if;
                    -- IGNORE DEADLINE
                    if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
                        tmp_update := tmp_update or IGNORE_DEADLINE_FLAG;
                        deadline    <= time + TIME_BASED_FILTER_QOS;
                    end if;
                    
                    inst_opcode_a       <= UPDATE_INSTANCE;
                    inst_op_start_a     <= '1';
                    release_inst_lock   <= '1';
                    update_inst_flags_a <= tmp_update;
                    
                    if (has_data = '1') then
                        payload_addr_a_next <= cur_payload;
                        stage_a_next        <= FINALIZE_PAYLOAD;
                        cnt_a_next          <= 0;
                    else
                        stage_a_next        <= SAMPLE_PRE_FINISH;
                        cnt_a_next          <= 0 when GENERATION_COUNTERS else 2;
                    end if;
                end if;
            when FINALIZE_PAYLOAD =>
                -- Precondition: payload_addr_a (Beginning of Last Added Payload Slot)
            
                cnt_a_next  <= cnt_a + 1;
                
                case (cnt_a) is 
                    -- Preload
                    when 0 =>
                        payload_ren_a   <= '1';
                    when 1 =>
                        -- No Empty Payload Slot available
                        if (payload_read_data_a = PAYLOAD_MEMORY_MAX_ADDRESS) then
                            assert (cur_payload = empty_payload_list_tail) report "Payload List empty, but HEAD /= TAIL" severity FAILURE;
                            -- Signal Sample Memory Full
                            payload_mem_full_next           <= '1';
                        else
                            empty_payload_list_head_next    <= payload_read_data_a;    
                        end if;
                        
                        -- Make current Slot the Tail
                        payload_write_data_a            <= PAYLOAD_MEMORY_MAX_ADDRESS;
                        payload_wen_a                   <= '1';
                        
                        stage_a_next        <= SAMPLE_PRE_FINISH;
                        cnt_a_next          <= 0 when GENERATION_COUNTERS else 2;
                    when others =>
                        null;
                end case;
            when SAMPLE_PRE_FINISH =>
                -- Precondition: sample_addr_a (Disposed generation Counter of New Sample)
                
                cnt_a_next  <= cnt_a + 1;
                
                case (cnt_a) is
                    -- Disposed Generation Counter
                    when 0 =>
                        if (GENERATION_COUNTERS) then
                            sample_addr_a_next  <= sample_addr_a + 1;
                            sample_wen_a        <= '1';
                            
                            -- NOT_ALIVE_DISPOSED -> ALIVE Transition
                            if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1' and sample_status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and sample_status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then
                                sample_write_data_a <= gen_cnt + 1;
                            else
                                sample_write_data_a <= gen_cnt;
                            end if;
                        end if;
                    -- No Writer Generation Counter
                    when 1 =>
                        if (GENERATION_COUNTERS) then
                            sample_wen_a        <= '1';
                            
                            -- NOT_ALIVE_NO_WRITERS -> ALIVE Transition
                            if (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1' and sample_status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and sample_status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then
                                sample_write_data_a <= gen_cnt + 1;
                            else
                                sample_write_data_a <= gen_cnt;
                            end if;
                        end if;
                    when 2 =>
                        -- First Sample
                        if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
                            stage_a_next        <= FINALIZE_SAMPLE_INFO;
                            sample_addr_a_next  <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET;
                            next_sample_next    <= SAMPLE_MEMORY_MAX_ADDRESS;
                            prev_sample_next    <= SAMPLE_MEMORY_MAX_ADDRESS;
                            cnt_a_next          <= 0;
                        else
                            stage_a_next        <= FIND_POS;
                            prev_sample_next    <= newest_sample;
                            sample_addr_a_next  <= newest_sample + SMF_TIMESTAMP_OFFSET;
                            cnt_a_next          <= 0;
                        end if;
                    when others =>
                        null;
                end case;
            when FIND_POS =>
                -- Precondition: prev_sample set, sample_addr_a (Timestamp 1/2 Addr of prev_sample)
                
                cnt_a_next  <= cnt_a + 1;
                
                case (cnt_a) is
                    -- Preload
                    when 0 =>
                        sample_addr_a_next  <= sample_addr_a + 1;
                        sample_ren_a        <= '1';
                    -- Timestamp 1/2
                    when 1 =>
                        sample_addr_a_next  <= sample_addr_a + SMF_PREV_ADDR_OFFSET-(SMF_TIMESTAMP_OFFSET+1); -- Prev Addr
                        sample_ren_a        <= '1';
                        long_latch_next     <= sample_read_data_a;
                    -- Timestamp 2/2
                    when 2 =>
                        sample_ren_a        <= '1';
                        
                        tmp_dw  := (0 => unsigned(long_latch), 1 => unsigned(sample_read_data_a));
                        
                        sample_addr_a_next  <= sample_addr_a + SMF_NEXT_ADDR_OFFSET-SMF_PREV_ADDR_OFFSET; -- Next Addr
                        
                        -- Found position (After current slot)
                        if (ts_latch >= tmp_dw) then
                            stage_a_next    <= FIX_POINTERS;
                            cnt_a_next      <= 0;
                        end if;
                    -- Previous Address
                    when 3 =>
                        -- No previous Slot (Oldest Sample)
                        if (sample_read_data_a = PAYLOAD_MEMORY_MAX_ADDRESS) then
                            assert (prev_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but sample is not OLDEST (HEAD)" severity FAILURE;
                            
                            stage_a_next    <= FIX_POINTERS;
                            cnt_a_next      <= 0;
                        else
                            prev_sample_next    <= sample_read_data_a;
                            sample_addr_a_next  <= sample_read_data_a + SMF_TIMESTAMP_OFFSET;
                            cnt_a_next          <= 0;
                        end if;
                end case;
            when FIX_POINTERS =>
                -- Precondition: sample_addr_a (Next Addr of prev_sample)
                
                cnt_a_next  <= cnt_a + 1;
                
                case (cnt_a) is
                    -- Preload
                    when 0 =>
                        sample_ren_a    <= '1';
                    when 1 =>
                        
                        -- Fix Next Pointer
                        sample_write_data_a <= empty_sample_list_head;
                        sample_wen_a        <= '1';
                        
                        -- No next Slot (Newest Sample)
                        if (sample_read_data_a = SAMPLE_MEMORY_MAX_ADDRESS) then
                            assert (prev_sample = newest_sample) report "Next Sample is MAX_ADDRESS, but sample is not NEWEST (TAIL)" severity FAILURE;
                            
                            next_sample_next    <= SAMPLE_MEMORY_MAX_ADDRESS;
                            stage_a_next        <= FINALIZE_SAMPLE_INFO;
                            sample_addr_a_next  <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample
                            cnt_a_next          <= 0;
                        else
                            -- Latch Next Sample
                            next_sample_next    <= sample_read_data_a;
                            
                            sample_addr_a_next  <= sample_read_data_a + SMF_PREV_ADDR_OFFSET; -- Prev Addr of Next Sample
                        end if;
                    when 2 =>
                        -- Fix Previous Pointer
                        sample_write_data_a <= empty_sample_list_head;
                        sample_wen_a        <= '1';
                        
                        stage_a_next        <= FINALIZE_SAMPLE_INFO;
                        sample_addr_a_next  <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample
                        cnt_a_next          <= 0;
                    when others =>
                        null;
                end case;
            when FINALIZE_SAMPLE_INFO =>
                -- Precondition: prev_sample set, next_sample set, sample_addr_a (Prev Addr of new sample)
                
                cnt_a_next  <= cnt_a + 1;
                
                case (cnt_a) is
                    -- Previous Address
                    when 0 =>
                        sample_addr_a_next  <= sample_addr_a + SMF_NEXT_ADDR_OFFSET-SMF_PREV_ADDR_OFFSET;
                        
                        -- Write Prev Addr
                        sample_write_data_a <= prev_sample;
                        sample_ren_a        <= '1';
                    -- Preload
                    when 1 =>
                        sample_ren_a    <= '1';
                    -- Next Address
                    when 2 =>
                        -- No empty Sample Slot Available
                        if (sample_read_data_a = SAMPLE_MEMORY_MAX_ADDRESS) then
                            -- Signal Smaple Memory Full
                            sample_mem_full_next        <= '1';    
                        else
                            empty_sample_list_head_next <= sample_read_data_a;
                        end if;
                        
                        -- Write Next Addr
                        sample_write_data_a <= next_sample;
                        sample_ren_a        <= '1';
                        
                        -- If newest Sample is now previous, select current sample as new newest
                        if (newest_sample = prev_sample) then
                            newest_sample_next  <= empty_sample_list_head;
                        end if;
                        
                        -- DONE
                        stage_a_next    <= IDLE;
                end case;
            when SKIP_ADD =>
                case (cnt_a) is
                    -- SKIP READ
                    when 0 =>
                        ready_in_a  <= '1';
                        -- Wait until last word from input
                        if (last_word_in_a  = '1') then
                            cnt_a_next  <= 1;
                        end if;
                    -- REJECT SAMPLE
                    when 1 =>
                        res_a           <= REJECTED;
                        stage_a_next    <= IDLE;
                    when others =>
                        null;
                end case;
            when REMOVE_WRITER =>
                -- Memory Operation Guard
                if (inst_op_done_a = '1') then
                    -- No More Instances
                    if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then
                        -- DONE
                        stage_a_next    <= IDLE;
                    else
                        -- Convert Writer Bitmap to SLV
                        tmp_bitmap  := to_endpoint_bitmap(inst_data.writer_bitmap);
                        
                        -- Remove Writer
                        tmp_bitmap(writer_pos) := '0';
                        
                        -- NOTE: writer_bitmap is not latched, since the memory process is latching it at the
                        --       same clock cycle.
                        -- Convert Back
                        writer_bitmap   <= from_endpoint_bitmap(tmp_bitmap);
                        
                        -- No More Writers for Instance
                        if (tmp_bitmap = (tmp_bitmap'range => '0')) then
                            inst_op_start_a     <= '1';
                            instance_state      <= NOT_ALIVE_NO_WRITERS;
                            inst_opcode_a       <= UPDATE_INSTANCE;
                            update_inst_flags_a <= STATUS_FLAG or WRITER_BITMAP_FLAG;
                        else
                            inst_op_start_a     <= '1';
                            inst_opcode_a       <= UPDATE_INSTANCE;
                            update_inst_flags_a <= WRITER_BITMAP_FLAG;
                        end if;
                        
                        stage_a_next    <= GET_NEXT_INSTANCE;
                    end if;
                end if;
            when GET_NEXT_INSTANCE =>
                -- Wait for Operation to Complete
                if (inst_op_done_a = '1') then                    
                    inst_op_start_a     <= '1';
                    inst_opcode_a       <= NEXT_INSTANCE;
                    stage_a_next        <= REMOVE_WRITER;
                end if;
            when WAIT_FOR_REMOVE =>
                -- Stall Input
                ready_in_a  <= '0';
                
                if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
                    -- Reject Change
                    stage_a_next    <= SKIP_ADD;
                    cnt_a_next      <= 0;
                else
                    od_oldest_sample_removal    <= '1';
                    
                    -- NOTE: We are ignoring the od_sample_removal_done signal of process B, because in this
                    --       case we can directly observe the status from the available signals. This cannot
                    --       be done in the MAX_SAMPLES_PER_INSTANCE removal case, since there we have to wait
                    --       until process B explicitly states that it has removed a sample of the offending instance.
                    --       In addition to that, the removal of the oldest sample is no guarantee that the payload 
                    --       memory will also get freed (Since the oldest sample may be one without data).
                    --       Here we are keeping the od_oldest_sample_removal signal high (meaning process B will keep 
                    --       removing samples) as long as it takes for both memories to get freed.
                    
                    -- Memory Available
                    if (sample_mem_full = '0' and payload_mem_full = '0') then
                        stage_a_next        <= ADD_SAMPLE_INFO;
                        sample_addr_a_next  <= empty_sample_list_head;
                        cnt_a_next          <= 0;
                    end if;
                end if;
            when others =>
                null;
        end case;
    end process;
    
    
    signal stage_b, stage_b_next : STAGE_TYPE := IDLE;
    
    parse_b_prc : process (all)
    begin
        -- DEFAULT
        stage_b_next    <= stage_b;
        
        case (stage_b) is
            when IDLE =>
                if (start_b = '1') then
                    
                    case (opcode_b) is
                        when others =>
                            null;
                    end case;
                end if;
            when others =>
                null;
        end case;
    end process;
    
    inst_ctrl_prc : process(all)
    begin
        -- DEFAULT Registered
        inst_stage_a_next           <= inst_stage_a;
        inst_addr_base_a_next       <= inst_addr_base_a;
        inst_addr_a_next            <= inst_addr_a;
        inst_empty_head_next        <= inst_empty_head;
        inst_occupied_tail_next     <= inst_occupied_tail;
        inst_latch_data_next        <= inst_latch_data;
        inst_next_addr_base_a_next  <= inst_next_addr_base_a;
        inst_prev_addr_base_a_next  <= inst_prev_addr_base_a;
        inst_cnt_a_next             <= inst_cnt_a;
        inst_mem_full_next          <= inst_mem_full;
        inst_delete_lock_a_next     <= inst_delete_lock_a;
        inst_data_next              <= inst_data;
        -- DEFAULT Unregistered
        inst_write_data_a   <= (others => '0');
        inst_op_done_a      <= '0';
        inst_ren_a          <= '0';
        inst_wen_a          <= '0';
        inst_atomic_lock_a  <= '0';
        
        
        case (mem_stage) is
            when IDLE =>
                inst_op_done_a    <= '1';
                
                -- Lock Release
                if (inst_delete_lock_a = '1' and inst_latch_data.release_lock = '1') then
                    inst_delete_lock_a_next <= '0';
                end if;
                
                if (inst_op_start_a = '1') then
                    -- Latch Signals needed for Mermory Operation (Use _next signals, because some signals are set in same clk)
                    inst_latch_data_next    <= (
                        key_hash        => key_hash_next,
                        instance_state  => instance_state,
                        gen_cnt         => gen_cnt,
                        deadline        => deadline,
                        writer_bitmap   => writer_bitmap,
                        update_flags    => update_inst_flags_a,
                        release_lock    => release_inst_lock
                    );
                    
                    -- Reset Memory Fullness Indicator
                    if (inst_mem_full = '1' and inst_empty_head /= inst_empty_tail) then
                        inst_mem_full_next  <= '0';
                    end if;
                    
                    case(inst_opcode_a) is
                        when SEARCH_INSTANCE =>
                            -- Reset Data
                            inst_data_next  <= ZERO_INSTANCE_DATA;
                            -- NOTE: This process gets the lock implicitly when the SEARCH_INSTANCE, or GET_FIRST_INSTANCE operation is called, and has to be released explicitly
                            --       by the main process. There are two ways to release the lock: 1) The man process explicitly calles the RELEASE_LOCK operation 2) The main 
                            --       process pulls the release_inst_lock signal high during the issuing of the last memory operation (Lock will be release after the opration finishes)
                            -- Process B has lock
                            if (inst_delete_lock_b = '1') then
                                -- Wait until process B releases lock
                                inst_stage_a_next   <= WAIT_FOR_LOCK_1;
                            else
                                -- NOTE: The case that both processes aqcuire the lock at the same time is handled by the B process in the next clock cycle.
                                -- Get Lock
                                inst_delete_lock_a_next    <= '1';
                                -- No Instances avialable
                                if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
                                    inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS;
                                else
                                    inst_prev_addr_base_a   <= INSTANCE_MEMORY_MAX_ADDRESS;
                                    inst_addr_base_a_next   <= inst_occupied_head;
                                    inst_addr_a_next        <= inst_occupied_head;
                                    inst_stage_a_next       <= SEARCH_INSTANCE;
                                    inst_cnt_a_next         <= 0;
                                end if;
                            end if;
                        when INSERT_INSTANCE =>
                            -- NOTE: Since this process has no way to communicate a failed insert to the main process, it has to be made sure
                            --       by the main process that the operation can succeed (Memory is available)
                            assert (inst_mem_full = '0') report "Instance Insertion while memory Full" severity FAILURE;
                            inst_prev_addr_base_a_next  <= inst_occupied_tail;
                            inst_addr_base_a_next       <= inst_occupied_tail;
                            inst_addr_a_next            <= inst_occupied_tail;
                            inst_stage_a_next           <= INSERT_PREPARATION;
                            inst_cnt_a_next             <= 0;
                        when UPDATE_INSTANCE =>
                            inst_addr_base_a_next   <= inst_addr_base_a;
                            if ((update_inst_flags_a and STATUS_FLAG) = STATUS_FLAG) then
                                inst_stage_a_next   <= UPDATE_INSTANCE;
                                inst_addr_a_next    <= inst_addr_base_a + IMF_STATUS_INFO_OFFSET;
                                inst_cnt_a_next     <= 0;
                            elsif (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and (update_inst_flags_a and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then
                                inst_stage_a_next   <= UPDATE_INSTANCE;
                                inst_addr_a_next    <= inst_addr_base_a + IMF_SAMPLE_CNT_OFFSET;
                                inst_cnt_a_next     <= 3;
                            elsif (GENERATION_COUNTERS and (update_inst_flags_a and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then
                                inst_stage_a_next   <= UPDATE_INSTANCE;
                                inst_addr_a_next    <= inst_addr_base_a + IMF_DISPOSED_GEN_CNT_OFFSET;
                                inst_cnt_a_next     <= 6;
                            elsif (GENERATION_COUNTERS and (update_inst_flags_a and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
                                inst_stage_a_next   <= UPDATE_INSTANCE;
                                inst_addr_a_next    <= inst_addr_base_a + IMF_NO_WRITERS_GEN_CNT_OFFSET;
                                inst_cnt_a_next     <= 7;
                            elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (update_inst_flags_a and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
                                inst_stage_a_next   <= UPDATE_INSTANCE;
                                inst_addr_a_next    <= inst_addr_base_a + IMF_IGNORE_DEADLINE_OFFSET;
                                inst_cnt_a_next     <= 8;
                            elsif ((update_inst_flags_a and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_addr_a_next    <= inst_addr_base_a + IMF_WRITER_BITMAP_OFFSET;
                                inst_cnt_a_next     <= 0;
                            end if;
                        when GET_FIRST_INSTANCE =>
                            -- NOTE: This process gets the lock implicitly when the SEARCH_INSTANCE, or GET_FIRST_INSTANCE operation is called, and has to be released explicitly
                            --       by the main process via the RELEASE_LOCK operation.
                            -- Process B has lock
                            if (inst_delete_lock_b = '1') then
                                -- Wait until process B releases lock
                                inst_stage_a_next   <= WAIT_FOR_LOCK_2;
                            else
                                -- NOTE: The case that both processes aqcuire the lock at the same time is handled by the B process in the next clock cycle.
                                -- Get Lock
                                inst_delete_lock_a_next    <= '1';
                                -- No Instances avialable
                                if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
                                    inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS;
                                else
                                    inst_prev_addr_base_a_next  <= INSTANCE_MEMORY_MAX_ADDRESS;
                                    inst_addr_base_a_next       <= inst_occupied_head;
                                    inst_addr_a_next            <= inst_occupied_head + 5;
                                    inst_stage_a_next           <= GET_INSTANCE_DATA;
                                    inst_cnt_a_next             <= 0;
                                end if;
                            end if;
                        when GET_NEXT_INSTANCE =>
                            inst_prev_addr_base_a_next  <= inst_addr_base_a;
                            inst_addr_base_a_next       <= inst_next_addr_base_a;
                            inst_addr_a_next            <= inst_next_addr_base_a;
                            inst_stage_a_next           <= GET_NEXT_INSTANCE;
                            inst_cnt_a_next             <= 0;
                        when RELEASE_LOCK =>
                            inst_delete_lock_a_next    <= '0';
                        when others =>
                            null;
                    end case;
                end if;
            when WAIT_FOR_LOCK_1 =>
                -- Wait until B process releases lock
                if (inst_delete_lock_b = '0') then
                    -- Get Lock
                    inst_delete_lock_a_next    <= '1';
                    if (inst_occupied_head /= INSTANCE_MEMORY_MAX_ADDRESS) then
                        inst_addr_base_a_next <= inst_occupied_head;
                        inst_addr_a_next      <= inst_occupied_head;
                        inst_stage_a_next     <= SEARCH_INSTANCE;
                        inst_cnt_a_next       <= 0;
                    else
                        inst_addr_base_a_next  <= INSTANCE_MEMORY_MAX_ADDRESS;
                    end if;
                end if;
            when WAIT_FOR_LOCK_2 =>
                -- Wait until B process releases lock
                if (inst_delete_lock_b = '0') then
                    -- Get Lock
                    inst_delete_lock_a_next    <= '1';
                    -- No Instances avialable
                    if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
                        inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS;
                    else
                        inst_prev_addr_base_a_next  <= INSTANCE_MEMORY_MAX_ADDRESS;
                        inst_addr_base_a_next       <= inst_occupied_head;
                        inst_addr_a_next            <= inst_occupied_head + 5;
                        inst_stage_a_next           <= GET_INSTANCE_DATA;
                        inst_cnt_a_next             <= 0;
                    end if;
                end if;
            when SEARCH_INSTANCE =>
                inst_ren_a        <= '1';
                inst_cnt_a_next   <= inst_cnt_a + 1;
                inst_addr_a_next  <= inst_addr_a + 1;
                
                case (inst_cnt_a) is
                    -- Preload
                    when 0 =>
                        null;
                    -- Next Instance
                    when 1 =>
                        inst_next_addr_base_a_next    <= inst_read_data_a;
                    -- Key Hash 1/4
                    when 2 =>
                        -- No Match
                        if (inst_read_data_a /= inst_latch_data.key_hash(0)) then
                            -- Reached List Tail, No Match
                            if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then
                                inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
                                -- DONE
                                inst_stage_a_next       <= IDLE;
                            else
                                -- Continue Search
                                inst_prev_addr_base_a_next  <= inst_addr_base_a;
                                inst_addr_base_a_next       <= inst_next_addr_base_a;
                                inst_addr_a_next            <= inst_next_addr_base_a;
                                inst_cnt_a_next             <= 0;
                            end if;
                        end if;
                    -- Key Hash 2/4
                    when 3 =>
                        -- No Match
                        if (inst_read_data_a /= inst_latch_data.key_hash(1)) then
                            -- Reached List Tail, No Match
                            if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then
                                inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
                                -- DONE
                                inst_stage_a_next       <= IDLE;
                            else
                                -- Continue Search
                                inst_prev_addr_base_a_next  <= inst_addr_base_a;
                                inst_addr_base_a_next       <= inst_next_addr_base_a;
                                inst_addr_a_next            <= inst_next_addr_base_a;
                                inst_cnt_a_next             <= 0;
                            end if;
                        end if;
                    -- Key Hash 3/4
                    when 4 =>
                        -- No Match
                        if (inst_read_data_a /= inst_latch_data.key_hash(2)) then
                            -- Reached List Tail, No Match
                            if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then
                                inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
                                -- DONE
                                inst_stage_a_next       <= IDLE;
                            else
                                -- Continue Search
                                inst_prev_addr_base_a_next  <= inst_addr_base_a;
                                inst_addr_base_a_next       <= inst_next_addr_base_a;
                                inst_addr_a_next            <= inst_next_addr_base_a;
                                inst_cnt_a_next             <= 0;
                            end if;
                        end if;
                    -- Key Hash 4/4
                    when 5 =>
                        -- No Match
                        if (inst_read_data_a /= inst_latch_data.key_hash(3)) then
                            -- Reached List Tail, No Match
                            if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then
                                inst_addr_base_a_next   <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
                                -- DONE
                                inst_stage_a_next       <= IDLE;
                            else
                                -- Continue Search
                                inst_prev_addr_base_a_next  <= inst_addr_base_a;
                                inst_addr_base_a_next       <= inst_next_addr_base_a;
                                inst_addr_a_next            <= inst_next_addr_base_a;
                                inst_cnt_a_next             <= 0;
                            end if;
                        -- Match
                        else
                            -- Fetch Instance Data
                            inst_stage_a_next   <= GET_INSTANCE_DATA;
                            inst_cnt_a_next     <= 1; -- No preload needed
                        end if;
                    when others =>
                        null;
                end case;
            when GET_NEXT_INSTANCE =>
                case (inst_cnt_a) is
                    -- Preload
                    when 0 =>
                        inst_wen_a  <= '1';
                    -- Next Instance
                    when 1 =>
                        inst_addr_base_a_next   <= inst_read_data_a;
                        inst_addr_a_next        <= inst_read_data_a + 5;
                        inst_cnt_a_next         <= 0;
                        inst_stage_a_next       <= GET_INSTANCE_DATA;
                end case;
            when GET_INSTANCE_DATA =>
                inst_ren_a        <= '1';
                inst_cnt_a_next   <= inst_cnt_a + 1;
                inst_addr_a_next  <= inst_addr_a + 1;
                
                case (inst_cnt_a) is
                    -- Memory Preload
                    when 0 =>
                        null;
                    -- Status Info
                    when 1 =>
                        inst_data_next.status_info          <= inst_read_data_a;
                    -- Sample Count
                    when 2 =>
                        inst_data_next.sample_cnt           <= inst_read_data_a;
                    -- Disposed Generation Count
                    when 3 =>
                        inst_data_next.disposed_gen_cnt     <= inst_read_data_a;
                    -- No Writers Generation Count
                    when 4 =>
                        inst_data_next.no_writers_gen_cnt   <= inst_read_data_a;
                    -- Ignore Deadline 1/2
                    when 5 =>
                        inst_data_next.ignore_deadline(0)   <= unsigned(inst_read_data_a);
                    -- Ignore Deadline 2/2
                    when 5 =>
                        inst_data_next.ignore_deadline(1)   <= unsigned(inst_read_data_a);
                        -- DONE
                        inst_stage_a_next <= GET_WRITER_BITMAP;
                        inst_cnt_a_next <= 0;
                    when others =>
                        null;
                end case;
            when GET_WRITER_BITMAP =>
                inst_cnt_a_next  <= inst_cnt_a + 1;
                
                inst_latch_data_next.writer_bitmap(inst_cnt_a) <= inst_read_data_a;
                
                if (inst_cnt_a = writer_bitmap'length-1) then
                    -- DONE
                    inst_stage_a_next <= IDLE;
                end if;
            when INSERT_PREPARATION =>
                inst_cnt_a_next   <= inst_cnt_a + 1;
                
                case (inst_cnt_a) is
                    -- Next Payload Slot (Old Occupied Tail)
                    when 0 =>
                        -- Point Old Occupied Tail to New Occupied Tail
                        inst_write_data_a       <= inst_empty_head;
                        inst_wen_a              <= '1';
                        inst_occupied_tail_next <= inst_empty_head;
                        
                        inst_addr_a_next        <= inst_empty_head;
                        inst_addr_base_a_next   <= inst_empty_head;
                    -- Preload
                    when 1 =>
                        inst_ren_a  <= '1';
                    -- Next Payload Slot (New Occupied Tail)
                    when 2 =>
                        -- Instance Memory Full
                        if (inst_read_data_a = INSTANCE_MEMORY_MAX_ADDRESS) then
                            assert (inst_empty_head = inst_empty_tail) report "Instance empty list empty, but HEAD /= TAIL" severity FAILURE;
                            inst_mem_full_next  <= '1';
                            inst_next_addr_base_a_next    <= inst_empty_head; -- Keep same tail
                        else
                            -- Latch new Empty Head
                            inst_next_addr_base_a_next    <= inst_read_data_a;
                        end if;
                        inst_stage_a_next             <= INSERT_INSTANCE;
                        inst_cnt_a_next               <= 0;
                    when others =>
                        null;
                end case;
            when INSERT_INSTANCE =>
                inst_wen_a        <= '1';
                inst_addr_a_next  <= inst_addr_a + 1;
                inst_cnt_a_next   <= inst_cnt_a + 1;
                
                case (inst_cnt_a) is
                    -- Next Instance Address
                    when 0 =>
                        -- Mark as Tail
                        inst_write_data_a       <= INSTANCE_MEMORY_MAX_ADDRESS;
                        -- Set New Empty List Head
                        inst_empty_head_next    <= inst_next_addr_base_a;
                    -- Key Hash 1/4
                    when 1 =>
                        inst_write_data_a   <= inst_latch_data.key_hash(0);
                    -- Key Hash 2/4
                    when 2 =>
                        inst_write_data_a   <= inst_latch_data.key_hash(1);
                    -- Key Hash 3/4
                    when 3 =>
                        inst_write_data_a   <= inst_latch_data.key_hash(2);
                    -- Key Hash 4/4
                    when 4 =>
                        inst_write_data_a   <= inst_latch_data.key_hash(3);
                    -- Status Info
                    when 5 =>
                        inst_write_data_a   <= inst_latch_data.status_info;
                        
                        if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then
                            null;
                        elsif (GENERATION_COUNTERS) then
                            inst_cnt_a  <= 7;
                        elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
                            inst_cnt_a  <= 9;
                        else
                            inst_stage_a_next   <= SET_WRITER_BITMAP;
                            inst_cnt_a_next     <= 0;
                        end if;
                    -- Sample Count
                    when 6 =>
                        if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then
                            inst_write_data_a   <= std_logic_vector(to_unsigned(1, WORD_WIDTH));
                            
                            if (GENERATION_COUNTERS) then
                                inst_cnt_a  <= 7;
                            elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
                                inst_cnt_a  <= 9;
                            else
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_cnt_a_next     <= 0;
                            end if;
                        end if;
                    -- Disposed Generation Count
                    when 7 =>
                        if (GENERATION_COUNTERS) then
                            inst_write_data_a   <= (others => '0');
                        end if;
                    -- No Writers Generation Count
                    when 8 =>
                        if (GENERATION_COUNTERS) then
                            inst_write_data_a   <= (others => '0');
                            
                            if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
                                inst_cnt_a  <= 9;
                            else
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_cnt_a_next     <= 0;
                            end if;
                        end if;
                    -- Ignore Deadline 1/2
                    when 9 =>
                        if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
                            inst_write_data_a   <= inst_latch_data.deadline(0);
                        end if;
                    -- Ignore Deadline 1/2
                    when 10 =>
                        if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
                            inst_write_data_a   <= inst_latch_data.deadline(1);
                            
                            inst_stage_a_next   <= SET_WRITER_BITMAP;
                            inst_cnt_a_next     <= 0;
                        end if;
                    when others => 
                        null;
                end case;
            when SET_WRITER_BITMAP =>
                inst_wen_a          <= '1';
                inst_addr_a_next    <= inst_addr_a + 1;
                inst_cnt_a_next     <= inst_cnt_a + 1;
                
                inst_write_data_a   <= inst_latch_data.writer_bitmap(inst_cnt_a);
                
                -- Exit Condition
                if (inst_cnt_a = inst_latch_data.writer_bitmap'length-1) then
                    -- DONE
                    inst_stage_a_next   <= IDLE;
                end if;
            when UPDATE_INSTANCE =>
                inst_cnt_a_next     <= inst_cnt_a + 1;
                
                case (inst_cnt_a) is
                    -- *Status Info Begin*
                    -- Preload
                    when 0 =>
                        inst_atomic_lock_a  <= '1';
                        inst_ren_a          <= '1';
                    -- Read
                    when 1 =>
                        -- Latch Contents
                        inst_atomic_lock_a      <= '1';
                        inst_long_latch_a_next  <= inst_read_data_a;
                    -- Write
                    when 2 =>
                        inst_atomic_lock_a  <= '1';
                        inst_wen_a          <= '1';
                        inst_write_data_a   <= inst_long_latch_a;
                        case (inst_latch_data.instance_state) is
                            when ALIVE =>
                                inst_write_data_a(NOT_ALIVE_DISPOSED_FLAG)      <= '0';
                                inst_write_data_a(NOT_ALIVE_NO_WRITERS_FLAG)    <= '0';
                                inst_write_data_a(LIVELINESS_FLAG)              <= '1';
                            when NOT_ALIVE_DISPOSED =>
                                inst_write_data_a(NOT_ALIVE_DISPOSED_FLAG)      <= '1';
                                inst_write_data_a(NOT_ALIVE_NO_WRITERS_FLAG)    <= '0';
                                inst_write_data_a(LIVELINESS_FLAG)              <= '1';
                            when NOT_ALIVE_NO_WRITERS =>
                                inst_write_data_a(NOT_ALIVE_DISPOSED_FLAG)      <= '0';
                                inst_write_data_a(NOT_ALIVE_NO_WRITERS_FLAG)    <= '1';
                                inst_write_data_a(LIVELINESS_FLAG)              <= '1';
                        end case;
                        
                        if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and (inst_latch_data.update_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then
                            inst_addr_a_next    <= inst_addr_base_a + IMF_SAMPLE_CNT_OFFSET;
                            inst_cnt_a_next     <= 3;
                        elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then
                            inst_addr_a_next    <= inst_addr_base_a + IMF_DISPOSED_GEN_CNT_OFFSET;
                            inst_cnt_a_next     <= 6;
                        elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
                            inst_addr_a_next    <= inst_addr_base_a + IMF_NO_WRITERS_GEN_CNT_OFFSET;
                            inst_cnt_a_next     <= 7;
                        elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
                            inst_addr_a_next    <=  inst_addr_base_a + IMF_IGNORE_DEADLINE_OFFSET;
                            inst_cnt_a_next     <= 8;
                        elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
                            inst_addr_a_next    <=  inst_addr_base_a + IMF_WRITER_BITMAP_OFFSET;
                            inst_stage_a_next   <= SET_WRITER_BITMAP;
                            inst_cnt_a_next     <= 0;
                        else
                            -- DONE
                            inst_stage_a_next   <= IDLE;
                        end if;
                    -- *Status Info End*
                    -- *Sample Count Begin*
                    -- Preload
                    when 3 =>
                        if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then
                            inst_ren_a          <= '1';
                            inst_atomic_lock_a  <= '1';
                        end if;
                    -- Read
                    when 4 =>
                        if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then
                            -- Latch Contents
                            inst_atomic_lock_a      <= '1';
                            inst_long_latch_a_next  <= inst_read_data_a;
                        end if;
                    when 5 =>
                        if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then
                            -- Increment Sample Count
                            inst_atomic_lock_a  <= '1';
                            inst_wen_a          <= '1';
                            inst_write_data_a   <= std_logic_vector(unsigned(inst_long_latch_a) + 1);
                            
                            if (GENERATION_COUNTERS and (inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then
                                inst_addr_a_next    <= inst_addr_base_a + IMF_DISPOSED_GEN_CNT_OFFSET;
                                inst_cnt_a_next     <= 6;
                            elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
                                inst_addr_a_next    <= inst_addr_base_a + IMF_NO_WRITERS_GEN_CNT_OFFSET;
                                inst_cnt_a_next     <= 7;
                            elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_IGNORE_DEADLINE_OFFSET;
                                inst_cnt_a_next     <= 8;
                            elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_WRITER_BITMAP_OFFSET;
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_cnt_a_next     <= 0;
                            else
                                -- DONE
                                inst_stage_a_next   <= IDLE;
                            end if;
                        end if;
                    -- *Sample Count End*
                    -- Disposed Generation Count
                    when 6 =>
                        if (GENERATION_COUNTERS) then
                            inst_wen_a          <= '1';
                            inst_write_data_a   <= inst_latch_data.gen_cnt;
                        
                            if (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
                                inst_addr_a_next    <= inst_addr_base_a + IMF_NO_WRITERS_GEN_CNT_OFFSET;
                                inst_cnt_a_next     <= 7;
                            elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_IGNORE_DEADLINE_OFFSET;
                                inst_cnt_a_next     <= 8;
                            elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_WRITER_BITMAP_OFFSET;
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_cnt_a_next     <= 0;
                            else
                                -- DONE
                                inst_stage_a_next   <= IDLE;
                            end if;
                        end if;
                    -- No Writers Generation Count
                    when 7 =>
                        if (GENERATION_COUNTERS) then
                            inst_wen_a          <= '1';
                            inst_write_data_a   <= inst_latch_data.gen_cnt;
                        
                            if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_IGNORE_DEADLINE_OFFSET;
                                inst_cnt_a_next     <= 8;
                            elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_WRITER_BITMAP_OFFSET;
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_cnt_a_next     <= 0;
                            else
                                -- DONE
                                inst_stage_a_next   <= IDLE;
                            end if;
                        end if;
                    -- Ignore Deadline 1/2
                    when 8 =>
                        if (TIME_BASED_FILTER_QOS /= DURATION_ZERO)  then
                            inst_wen_a          <= '1';
                            inst_write_data_a   <= std_logic_vector(inst_latch_data.ignore_deadline(0));
                        end if;
                    -- Ignore Deadline 2/2
                    when 9 =>
                        if (TIME_BASED_FILTER_QOS /= DURATION_ZERO)  then
                            inst_wen_a          <= '1';
                            inst_write_data_a   <= std_logic_vector(inst_latch_data.ignore_deadline(1));
                            
                            if ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
                                inst_addr_a_next    <=  inst_addr_base_a + IMF_WRITER_BITMAP_OFFSET;
                                inst_stage_a_next   <= SET_WRITER_BITMAP;
                                inst_cnt_a_next     <= 0;
                            else
                                -- DONE
                                inst_stage_a_next   <= IDLE;
                            end if;
                        end if;
                    when others =>
                        null;
                end case;
                when others =>
                    null;
                end case;
            when others =>
                null;
        end case;
    end process;
    
end architecture;