It was decided to connect the DDS Endpoint directly to the RTPS Endpoint. The history_cache Entity will be converted to a generic History Cache acording to the RTPS Specification. Because of consistency requirements the implementation was changed to a single process/single port RAM design. This should fully (blindly) implement the RTPS Reader side of the DDS Entity.
1837 lines
98 KiB
VHDL
1837 lines
98 KiB
VHDL
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
-- TODO: Cancel KHG operation on incomplete payload parsing
|
|
|
|
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;
|
|
sample_cnt : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
|
|
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);
|
|
addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
end record;
|
|
constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := (
|
|
key_hash => (others => (others => '0')),
|
|
instance_state => ALIVE,
|
|
sample_cnt => (others => '0'),
|
|
gen_cnt => (others => '0'),
|
|
deadline => TIME_INVALID,
|
|
writer_bitmap => (others => (others => '0')),
|
|
update_flags => (others => '0'),
|
|
addr => (others => '0')
|
|
);
|
|
|
|
--*****SIGNAL DECLARATION
|
|
signal sample_addr, sample_addr_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal sample_wen, sample_ren : std_logic := '0';
|
|
signal sample_read_data, sample_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
|
|
|
|
signal payload_addr, payload_addr_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal payload_wen, payload_ren : std_logic := '0';
|
|
signal payload_read_data, payload_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
|
|
|
|
signal inst_addr, inst_addr_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal inst_wen, inst_ren : std_logic := '0';
|
|
signal inst_read_data, inst_write_data : 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, stage_next : STAGE_TYPE := IDLE;
|
|
signal cnt, cnt_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 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 sample_addr_latch_3, sample_addr_latch_3_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 remove_oldest_sample, remove_oldest_sample_next : std_logic := '0';
|
|
signal remove_oldest_inst_sample, remove_oldest_inst_sample_next : std_logic := '0';
|
|
signal added_new_instance, added_new_instance_next : 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 inst_addr_update : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal sample_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
|
|
|
|
signal inst_op_start : std_logic := '0';
|
|
signal inst_op_done : std_logic := '0';
|
|
signal inst_opcode : INSTANCE_OPCODE_TYPE := NOP;
|
|
signal inst_stage, inst_stage_next : INST_STAGE_TYPE := IDLE;
|
|
signal inst_addr_base, inst_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal inst_next_addr_base, inst_next_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal inst_prev_addr_base, inst_prev_addr_base_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 : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0');
|
|
signal inst_cnt, inst_cnt_next : natural range TODO := 0;
|
|
signal inst_mem_full, inst_mem_full_next : std_logic := '0';
|
|
signal inst_delete_lock, inst_delete_lock_next : std_logic := '0';
|
|
signal inst_atomic_lock : std_logic := '0';
|
|
signal inst_long_latch, inst_long_latch_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_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3;
|
|
alias cur_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3_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.single_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 => sample_addr,
|
|
wen => sample_wen,
|
|
ren => sample_ren,
|
|
wr_data => sample_write_data,
|
|
rd_data => sample_read_data
|
|
);
|
|
|
|
payload_ram_inst : entity work.single_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 => payload_addr,
|
|
wen => payload_wen,
|
|
ren => payload_ren,
|
|
wr_data => payload_write_data,
|
|
rd_data => payload_read_data
|
|
);
|
|
|
|
instance_ram_inst : entity work.single_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 => inst_addr,
|
|
wen => inst_wen,
|
|
ren => inst_ren,
|
|
wr_data => inst_write_data,
|
|
rd_data => inst_read_data
|
|
);
|
|
|
|
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_next <= stage;
|
|
res_a <= UNDEFINED;
|
|
sample_addr_next <= sample_addr;
|
|
sample_write_data <= (others => '0');
|
|
sample_ren <= '0';
|
|
sample_wen <= '0';
|
|
payload_addr_next <= payload_addr;
|
|
payload_write_data <= (others => '0');
|
|
payload_ren <= '0';
|
|
payload_wen <= '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;
|
|
empty_sample_list_tail_next <= empty_sample_list_tail;
|
|
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 <= NOP;
|
|
key_hash_next <= key_hash;
|
|
sample_status_info_next <= sample_status_info;
|
|
inst_op_start <= '0';
|
|
khg_last_word_in <= '0';
|
|
khg_data_in <= (others => '0');
|
|
khg_valid_in <= '0';
|
|
khg_ready_out <= '0';
|
|
writer_bitmap <= (others => '0');
|
|
inst_addr_update <= (others => '0');
|
|
remove_oldest_sample_next <= remove_oldest_sample;
|
|
remove_oldest_inst_sample_next <= remove_oldest_inst_sample;
|
|
added_new_instance_next <= added_new_instance;
|
|
|
|
case (stage) is
|
|
when IDLE =>
|
|
-- DEFAULT
|
|
ready_in_a <= '1';
|
|
remove_oldest_inst_sample_next <= '0';
|
|
remove_oldest_sample_next <= '0';
|
|
added_new_instance_next <= '0';
|
|
|
|
if (start_a = '1') then
|
|
case (opcode_a) is
|
|
when ADD_CHANGE =>
|
|
-- This Operation does not accept input at this time
|
|
ready_in_a <= '0';
|
|
|
|
res_a <= ACK;
|
|
stage_next <= ADD_SAMPLE_INFO;
|
|
cur_sample_next <= empty_sample_list_head;
|
|
sample_addr_next <= empty_sample_list_head;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when REMOVE_WRITER =>
|
|
-- Input and Memory Gurad
|
|
if (valid_in_a = '1' and inst_op_done = '1') then
|
|
-- Latch Writer Pos
|
|
writer_pos_next <= to_integer(unsigned(data_in_a));
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
stage_next <= REMOVE_WRITER;
|
|
res_a <= ACK;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
elsif (start_b = '1') then
|
|
-- TODO
|
|
end if;
|
|
|
|
when ADD_SAMPLE_INFO =>
|
|
-- Precondition: sample_addr (empty_sample_list_head)
|
|
|
|
ready_in_a <= '1';
|
|
|
|
-- Input Guard
|
|
if (valid_in_a = '1') then
|
|
cnt_next <= cnt + 1;
|
|
sample_addr_next <= sample_addr + 1;
|
|
|
|
-- Write Through
|
|
sample_wen <= '1';
|
|
sample_write_data <= data_in_a;
|
|
|
|
case (cnt) is
|
|
-- Status Info
|
|
when 0 =>
|
|
-- Initialize local status bits
|
|
sample_write_data(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;
|
|
-- Lifespan Deadline 2/2
|
|
when 4 =>
|
|
-- Skip Key Hash, if not available
|
|
if (has_key_hash = '0') then
|
|
cnt_next <= 9;
|
|
end if;
|
|
-- Latch Key Hash
|
|
-- Key Hash 1/4
|
|
when 5 =>
|
|
-- Latch Input, but do not pass to Memory
|
|
sample_wen <= '0';
|
|
sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr)
|
|
key_hash_next(0) <= data_in_a;
|
|
-- Key Hash 2/4
|
|
when 6 =>
|
|
-- Latch Input, but do not pass to Memory
|
|
sample_wen <= '0';
|
|
sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr)
|
|
key_hash_next(1) <= data_in_a;
|
|
-- Key Hash 3/4
|
|
when 7 =>
|
|
-- Latch Input, but do not pass to Memory
|
|
sample_wen <= '0';
|
|
sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr)
|
|
key_hash_next(2) <= data_in_a;
|
|
-- Key Hash 4/4
|
|
when 8 =>
|
|
-- Latch Input, but do not pass to Memory
|
|
sample_wen <= '0';
|
|
sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr)
|
|
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 <= '0';
|
|
sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr)
|
|
stage_next <= ADD_PAYLOAD_ADDRESS;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when ADD_PAYLOAD_ADDRESS =>
|
|
-- Precondition: sample_addr (Payload Address)
|
|
|
|
sample_addr_next <= sample_addr + 1; -- Instance Address
|
|
|
|
if (has_data = '1') then
|
|
-- Store Payload Address
|
|
sample_wen <= '1';
|
|
sample_write_data <= empty_payload_list_head;
|
|
|
|
payload_addr_next <= empty_payload_list_head + PMF_NEXT_ADDR_OFFSET;
|
|
cur_payload_next <= empty_payload_list_head;
|
|
else
|
|
-- Mark Sample with no Payload
|
|
sample_wen <= '1';
|
|
sample_write_data <= PAYLOAD_MEMORY_MAX_ADDRESS;
|
|
end if;
|
|
|
|
-- If Key Hash is available, start the Instance Search first
|
|
if (has_key_hash = '1') then
|
|
stage_next <= INITIATE_INSTANCE_SEARCH;
|
|
else
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when ADD_PAYLOAD =>
|
|
-- Precondition (if has_data = '1'): cur_payload set (Current Slot), payload_addr (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_next <= cnt + 1;
|
|
payload_addr_next <= payload_addr + PMF_NEXT_ADDR_OFFSET;
|
|
|
|
-- Payload Write
|
|
if (has_data = '1') then
|
|
payload_write_data <= data_in_a;
|
|
payload_wen <= '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_next <= GET_KEY_HASH;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= FILTER_STAGE;
|
|
end if;
|
|
-- End of Payload Slot
|
|
elsif (has_data = '1' and cnt = PAYLOAD_FRAME_SIZE-2) then
|
|
stage_next <= NEXT_PAYLOAD_SLOT;
|
|
payload_addr_next <= cur_payload;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when NEXT_PAYLOAD_SLOT =>
|
|
-- Precondition: payload_addr (Beginning of current Slot)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
payload_ren <= '1';
|
|
when 1 =>
|
|
-- No Empty Payload Slots available
|
|
if (payload_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then
|
|
-- Reject Change
|
|
stage_next <= SKIP_ADD;
|
|
else
|
|
-- Latch next Payload Slot and Continue
|
|
cur_payload_next <= payload_read_data;
|
|
payload_addr_next <= payload_read_data + PMF_NEXT_ADDR_OFFSET;
|
|
stage_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_next <= cnt + 1;
|
|
|
|
-- Latch Key Hash
|
|
key_hash_next(cnt) <= khg_data_out;
|
|
|
|
-- Exit Condition
|
|
if (khg_last_word_out = '1') then
|
|
-- DONE
|
|
stage_next <= INITIATE_INSTANCE_SEARCH;
|
|
end if;
|
|
end if;
|
|
when INITIATE_INSTANCE_SEARCH =>
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
inst_opcode <= SEARCH_INSTANCE_HASH;
|
|
inst_op_start <= '1';
|
|
|
|
-- Payload not yet stored
|
|
if (has_data = '1') then
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= FILTER_STAGE;
|
|
end if;
|
|
end if;
|
|
when FILTER_STAGE =>
|
|
-- Precondition: sample_addr (Instance Address of New Sample)
|
|
|
|
-- Wait for Instance Search to finish
|
|
if (inst_op_done = '1') then
|
|
sample_addr_next <= sample_addr + 1; -- Disposed Gen Counter (Prev Address if GENERATION_COUNTERS=FALSE)
|
|
|
|
-- Instance Found
|
|
if (inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- Store Instance Address
|
|
sample_write_data <= inst_addr_base;
|
|
sample_wen <= '1';
|
|
|
|
-- TIME_BASED_FILTER QOS
|
|
if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time <= inst_data.ignore_deadline) then
|
|
-- Drop Change
|
|
res_a <= ACCEPTED;
|
|
stage_next <= IDLE;
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE)
|
|
elsif (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then
|
|
if (HISTORY_QOS = KEEP_LAST_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
|
|
-- Reject Change
|
|
res_a <= REJECTED;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest Instance Sample)
|
|
remove_oldest_inst_sample_next <= '1';
|
|
res_a <= ACCEPTED;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES)
|
|
elsif (empty_sample_list_head = empty_sample_list_tail) then
|
|
if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
|
|
-- Reject Change
|
|
res_a <= REJECTED;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
res_a <= ACCEPTED;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
else
|
|
-- Accept Change
|
|
res_a <= ACCEPTED;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
else
|
|
-- Store Instance Address
|
|
sample_write_data <= inst_empty_head;
|
|
sample_wen <= '1';
|
|
|
|
-- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full)
|
|
if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- Reject Change
|
|
res_a <= REJECTED;
|
|
stage_next <= IDLE;
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES)
|
|
elsif (empty_sample_list_head = empty_sample_list_tail) then
|
|
if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
|
|
-- Reject Change
|
|
res_a <= REJECTED;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
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 <= INSERT_INSTANCE;
|
|
inst_op_start <= '1';
|
|
|
|
added_new_instance_next <= '1';
|
|
|
|
if (has_data = '1') then
|
|
payload_addr_next <= cur_payload;
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= PRE_SAMPLE_FINALIZE;
|
|
cnt_next <= 0 when GENERATION_COUNTERS else 2;
|
|
end if;
|
|
else
|
|
-- Drop Change
|
|
stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
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 <= INSERT_INSTANCE;
|
|
inst_op_start <= '1';
|
|
|
|
if (has_data = '1') then
|
|
payload_addr_next <= cur_payload;
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= PRE_SAMPLE_FINALIZE;
|
|
cnt_next <= 0 when GENERATION_COUNTERS else 2;
|
|
end if;
|
|
else
|
|
-- Drop Change
|
|
stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when UPDATE_INSTANCE =>
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '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;
|
|
|
|
-- INSTANCE SAMPLE COUNT
|
|
-- NOTE: Ignored when remove_oldest_inst_sample, since it will be decremented again. (Stays same)
|
|
if (remove_oldest_inst_sample = '0') 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 <= UPDATE_INSTANCE;
|
|
inst_op_start <= '1';
|
|
update_inst_flags <= tmp_update;
|
|
|
|
if (has_data = '1') then
|
|
payload_addr_next <= cur_payload;
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= PRE_SAMPLE_FINALIZE;
|
|
cnt_next <= 0 when GENERATION_COUNTERS else 2;
|
|
end if;
|
|
end if;
|
|
when FINALIZE_PAYLOAD =>
|
|
-- Precondition: payload_addr (Beginning of Last Added Payload Slot)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
payload_ren <= '1';
|
|
when 1 =>
|
|
-- Fix New Empty List Head
|
|
empty_payload_list_head_next <= payload_read_data;
|
|
|
|
-- Make current Slot the Tail
|
|
payload_write_data <= PAYLOAD_MEMORY_MAX_ADDRESS;
|
|
payload_wen <= '1';
|
|
|
|
stage_next <= PRE_SAMPLE_FINALIZE;
|
|
cnt_next <= 0 when GENERATION_COUNTERS else 2;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when PRE_SAMPLE_FINALIZE =>
|
|
-- Precondition: sample_addr (Disposed generation Counter of New Sample)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Disposed Generation Counter
|
|
when 0 =>
|
|
if (GENERATION_COUNTERS) then
|
|
sample_addr_next <= sample_addr + 1;
|
|
sample_wen <= '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 <= gen_cnt + 1;
|
|
else
|
|
sample_write_data <= gen_cnt;
|
|
end if;
|
|
end if;
|
|
-- No Writer Generation Counter
|
|
when 1 =>
|
|
if (GENERATION_COUNTERS) then
|
|
sample_wen <= '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 <= gen_cnt + 1;
|
|
else
|
|
sample_write_data <= gen_cnt;
|
|
end if;
|
|
end if;
|
|
when 2 =>
|
|
-- First Sample
|
|
if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
stage_next <= FINALIZE_SAMPLE_INFO;
|
|
sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET;
|
|
next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= FIND_POS;
|
|
prev_sample_next <= newest_sample;
|
|
sample_addr_next <= newest_sample + SMF_TIMESTAMP_OFFSET;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when FIND_POS =>
|
|
-- Precondition: prev_sample set, sample_addr (Timestamp 1/2 Addr of prev_sample)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
sample_addr_next <= sample_addr + 1;
|
|
sample_ren <= '1';
|
|
-- Timestamp 1/2
|
|
when 1 =>
|
|
sample_addr_next <= sample_addr + SMF_PREV_ADDR_OFFSET-(SMF_TIMESTAMP_OFFSET+1); -- Prev Addr
|
|
sample_ren <= '1';
|
|
long_latch_next <= sample_read_data;
|
|
-- Timestamp 2/2
|
|
when 2 =>
|
|
sample_ren <= '1';
|
|
|
|
tmp_dw := (0 => unsigned(long_latch), 1 => unsigned(sample_read_data));
|
|
|
|
sample_addr_next <= sample_addr + SMF_NEXT_ADDR_OFFSET-SMF_PREV_ADDR_OFFSET; -- Next Addr
|
|
|
|
-- Found position (After current slot)
|
|
if (ts_latch >= tmp_dw) then
|
|
stage_next <= FIX_POINTERS;
|
|
cnt_next <= 0;
|
|
end if;
|
|
-- Previous Address
|
|
when 3 =>
|
|
-- No previous Slot (Oldest Sample)
|
|
if (sample_read_data = 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_next <= FIX_POINTERS;
|
|
cnt_next <= 0;
|
|
else
|
|
prev_sample_next <= sample_read_data;
|
|
sample_addr_next <= sample_read_data + SMF_TIMESTAMP_OFFSET;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end case;
|
|
when FIX_POINTERS =>
|
|
-- Precondition: sample_addr (Next Addr of prev_sample)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
sample_ren <= '1';
|
|
when 1 =>
|
|
|
|
-- Fix Next Pointer
|
|
sample_write_data <= empty_sample_list_head;
|
|
sample_wen <= '1';
|
|
|
|
-- No next Slot (Newest Sample)
|
|
if (sample_read_data = 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_next <= FINALIZE_SAMPLE_INFO;
|
|
sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample
|
|
cnt_next <= 0;
|
|
else
|
|
-- Latch Next Sample
|
|
next_sample_next <= sample_read_data;
|
|
|
|
sample_addr_next <= sample_read_data + SMF_PREV_ADDR_OFFSET; -- Prev Addr of Next Sample
|
|
end if;
|
|
when 2 =>
|
|
-- Fix Previous Pointer
|
|
sample_write_data <= empty_sample_list_head;
|
|
sample_wen <= '1';
|
|
|
|
stage_next <= FINALIZE_SAMPLE_INFO;
|
|
sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample
|
|
cnt_next <= 0;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when FINALIZE_SAMPLE_INFO =>
|
|
-- Precondition: prev_sample set, next_sample set, sample_addr (Prev Addr of new sample)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Previous Sample Address
|
|
when 0 =>
|
|
sample_addr_next <= sample_addr + 1; -- Next Sample
|
|
|
|
-- Write Prev Addr
|
|
sample_write_data <= prev_sample;
|
|
sample_wen <= '1';
|
|
-- Preload
|
|
when 1 =>
|
|
sample_ren <= '1';
|
|
-- Next Sample Address
|
|
when 2 =>
|
|
empty_sample_list_head_next <= sample_read_data;
|
|
|
|
-- Write Next Addr
|
|
sample_write_data <= next_sample;
|
|
sample_wen <= '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;
|
|
|
|
-- New Instance was added, and Instance Memory is Full
|
|
if (added_new_instance = '1' and inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
|
|
stage_next <= REMOVE_STALE_INSTANCE;
|
|
else
|
|
cnt_next <= cnt; -- Keep State
|
|
end if;
|
|
elsif (remove_oldest_inst_sample = '1') then
|
|
sample_addr_next <= cur_sample + SMF_INSTANCE_ADDR_OFFSET;
|
|
stage_next <= FIND_OLDEST_INST_SAMPLE;
|
|
elsif (remove_oldest_sample = '1') then
|
|
stage_next <= GET_OLDEST_SAMPLE_INSTANCE;
|
|
else
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
end case;
|
|
when GET_OLDEST_SAMPLE_INSTANCE =>
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
sample_ren <= '1';
|
|
when 1 =>
|
|
inst_op_start <= '1';
|
|
inst_opcode <= SEARCH_INSTANCE_ADDR;
|
|
inst_addr_update <= sample_read_data;
|
|
|
|
cur_sample_next <= oldest_sample;
|
|
sample_addr_next <= oldest_sample + SMF_PREV_ADDR_OFFSET;
|
|
stage_next <= REMOVE_SAMPLE;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when FIND_OLDEST_INST_SAMPLE =>
|
|
-- Precondition: cur_sample set, sample_addr (Instance Address of cur_sample)
|
|
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
sample_ren <= '1';
|
|
sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; -- Next Addr
|
|
-- Instance Address
|
|
when 1 =>
|
|
sample_ren <= '1';
|
|
-- Oldest Instance Sample Found
|
|
if (sample_read_data = inst_addr_base) then
|
|
stage_next <= REMOVE_SAMPLE;
|
|
sample_addr_next <= cur_sample + SMF_PREV_ADDR_OFFSET;
|
|
end if;
|
|
-- Next Address
|
|
when 2 =>
|
|
cur_sample_next <= sample_read_data;
|
|
sample_addr_next <= sample_read_data + SMF_INSTANCE_ADDR_OFFSET; -- Instance Addr
|
|
cnt_next <= 0;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE_SAMPLE =>
|
|
-- Precondition: cur_sample set, sample_addr (Previous Address of cur_sample)
|
|
|
|
-- Wait for Instance Search to finish
|
|
if (inst_op_done = '1') then
|
|
cnt_next <= cnt + 1;
|
|
|
|
case (cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
sample_ren <= '1';
|
|
sample_addr_next <= cur_sample + 1; -- Next Addr
|
|
-- Previous Addr (Current Sample)
|
|
when 1 =>
|
|
sample_ren <= '1';
|
|
prev_sample_next <= sample_read_data;
|
|
-- Next Addr (Current Sample)
|
|
when 2 =>
|
|
next_sample_next <= sample_read_data;
|
|
|
|
-- Make Current Sample Empty List Tail
|
|
sample_write_data <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
sample_wen <= '1';
|
|
|
|
-- Current Sample is Newest (Occupied List Tail)
|
|
if (sample_read_data = MAX_SAMPLE_ADDRESS) then
|
|
assert (cur_sample = newest_sample) report "Next Sample is MAX_ADDR, but cur_sample /= newest_sample" severity FAILURE;
|
|
|
|
-- Fix Newest Pointer
|
|
newest_sample_next <= prev_sample;
|
|
|
|
-- Current Sample is Oldest (List Head)
|
|
if (prev_sample = MAX_SAMPLE_ADDRESS) then
|
|
assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE;
|
|
assert (newest_sample = oldest_sample) report "Previous and Next Sample is MAX_ADDR, but cur_sample /= newest_sample /= oldest_sample" severity FAILURE;
|
|
|
|
-- Fix Oldest Pointer
|
|
oldest_sample_next <= MAX_SAMPLE_ADDRESS;
|
|
-- NOTE: Sample Memory Empty (newest_sample also set to MAX_ADDR)
|
|
|
|
-- Sample Memory Full
|
|
if (empty_sample_list_head = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
empty_sample_list_head_next <= cur_sample;
|
|
empty_sample_list_tail_next <= cur_sample;
|
|
|
|
-- Skip to Payload Handling
|
|
cnt_next <= 6;
|
|
sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET;
|
|
else
|
|
-- Skip to Empty List Handling
|
|
cnt_next <= 5;
|
|
sample_addr_next <= empty_sample_list_tail + SMF_NEXT_ADDR_OFFSET;
|
|
end if;
|
|
else
|
|
-- Skip to Previous Handling
|
|
sample_addr_next <= prev_sample + SMF_NEXT_ADDR_OFFSET;
|
|
cnt_next <= 4;
|
|
end if;
|
|
else
|
|
sample_addr_next <= sample_read_data + SMF_PREV_ADDR_OFFSET;
|
|
end if;
|
|
-- Previous Address (Next Sample)
|
|
when 3 =>
|
|
-- Remove link to cur_sample
|
|
sample_write_data <= prev_sample;
|
|
sample_wen <= '1';
|
|
|
|
-- Current Sample is oldest sample (List Head)
|
|
if (prev_sample = MAX_SAMPLE_ADDRESS) then
|
|
assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE;
|
|
|
|
-- Fix Oldest Pointer
|
|
oldest_sample_next <= MAX_SAMPLE_ADDRESS;
|
|
|
|
-- Sample Memory Full
|
|
if (empty_sample_list_head = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
empty_sample_list_head_next <= cur_sample;
|
|
empty_sample_list_tail_next <= cur_sample;
|
|
|
|
-- Skip to Payload Handling
|
|
cnt_next <= 6;
|
|
sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET;
|
|
else
|
|
-- Skip to Empty List Handling
|
|
cnt_next <= 5;
|
|
sample_addr_next <= empty_sample_list_tail + SMF_NEXT_ADDR_OFFSET;
|
|
end if;
|
|
end if;
|
|
-- Next Address (Previous Sample)
|
|
when 4 =>
|
|
-- Remove link to cur_sample
|
|
sample_write_data <= next_sample;
|
|
sample_wen <= '1';
|
|
|
|
sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET;
|
|
-- Next Address (Empty Tail)
|
|
when 5 =>
|
|
sample_write_data <= cur_sample;
|
|
sample_wen <= '1';
|
|
|
|
-- Fix Empty List Pointers
|
|
empty_sample_list_tail_next <= cur_sample;
|
|
|
|
sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET;
|
|
-- Preload
|
|
when 6 =>
|
|
sample_ren <= '1';
|
|
-- Payload Address
|
|
when 7 =>
|
|
cur_payload_next <= sample_read_data;
|
|
-- Sample has no Data
|
|
if (sample_read_data = MAX_PAYLOAD_ADDRESS) then
|
|
stage_next <= POST_SAMPLE_REMOVE;
|
|
-- Payload Memory Full
|
|
elsif (empty_payload_list_head = MAX_PAYLOAD_ADDRESS) then
|
|
-- NOTE: Make the head of the Payload, the head of the Empty List
|
|
empty_payload_list_head_next <= sample_read_data;
|
|
|
|
stage_next <= POST_SAMPLE_REMOVE;
|
|
else
|
|
payload_addr_next <= cur_payload + PMF_NEXT_ADDR_OFFSET;
|
|
end if;
|
|
-- Preload
|
|
when 8 =>
|
|
payload_ren <= '1';
|
|
-- Next Payload Addr
|
|
when 9 =>
|
|
-- Found Empty List Tail
|
|
if (payload_read_data = MAX_PAYLOAD_ADDRESS) then
|
|
empty_payload_list_head_next <= cur_payload;
|
|
payload_write_data <= empty_payload_list_head;
|
|
payload_wen <= '1';
|
|
|
|
stage_next <= POST_SAMPLE_REMOVE;
|
|
else
|
|
payload_addr_next <= payload_read_data + PMF_NEXT_ADDR_OFFSET;
|
|
cnt_next <= 8;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when POST_SAMPLE_REMOVE =>
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
-- No Instance Change on remove_oldest_inst_sample
|
|
if (remove_oldest_inst_sample = '0') then
|
|
tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap);
|
|
-- Instance obsolete and Instance Memory Full
|
|
if (inst_data.sample_cnt = 1 and tmp_bitmap = (tmp_bitmap'range => '0') and inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= REMOVE_INSTANCE;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
inst_op_start <= '1';
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
update_inst_flags <= SAMPLE_CNT_FLAG;
|
|
sample_cnt <= inst_data.sample_cnt - 1;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when SKIP_ADD =>
|
|
case (cnt) is
|
|
-- SKIP READ
|
|
when 0 =>
|
|
ready_in_a <= '1';
|
|
-- Wait until last word from input
|
|
if (last_word_in_a = '1') then
|
|
cnt_next <= 1;
|
|
end if;
|
|
-- REJECT SAMPLE
|
|
when 1 =>
|
|
res_a <= REJECTED;
|
|
stage_next <= IDLE;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE_WRITER =>
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
-- No More Instances
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_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 <= '1';
|
|
instance_state <= NOT_ALIVE_NO_WRITERS;
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
update_inst_flags <= STATUS_FLAG or WRITER_BITMAP_FLAG;
|
|
else
|
|
inst_op_start <= '1';
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
update_inst_flags <= WRITER_BITMAP_FLAG;
|
|
end if;
|
|
|
|
stage_next <= GET_NEXT_INSTANCE;
|
|
end if;
|
|
end if;
|
|
when GET_NEXT_INSTANCE =>
|
|
-- Wait for Operation to Complete
|
|
if (inst_op_done = '1') then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= NEXT_INSTANCE;
|
|
stage_next <= REMOVE_WRITER;
|
|
end if;
|
|
when REMOVE_STALE_INSTANCE =>
|
|
-- Wait for Instance Data
|
|
if (inst_op_done = '1') then
|
|
-- Iterated through all Instances
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Convert Writer Bitmap to SLV
|
|
tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap);
|
|
|
|
-- Found Stale Instance (No Samples and No Active Writers)
|
|
if (inst_data.sample_cnt = 0 and tmp_bitmap = (tmp_bitmap'range => '0')) then
|
|
-- Remove Stale Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= REMOVE_INSTANCE;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_NEXT_INSTANCE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end process;
|
|
|
|
|
|
inst_ctrl_prc : process(all)
|
|
begin
|
|
-- DEFAULT Registered
|
|
inst_stage_next <= inst_stage;
|
|
inst_addr_base_next <= inst_addr_base;
|
|
inst_addr_next <= inst_addr;
|
|
inst_empty_head_next <= inst_empty_head;
|
|
inst_occupied_head_next <= inst_occupied_head;
|
|
inst_latch_data_next <= inst_latch_data;
|
|
inst_next_addr_base_next <= inst_next_addr_base;
|
|
inst_prev_addr_base_next <= inst_prev_addr_base;
|
|
inst_cnt_next <= inst_cnt;
|
|
inst_mem_full_next <= inst_mem_full;
|
|
inst_data_next <= inst_data;
|
|
-- DEFAULT Unregistered
|
|
inst_write_data <= (others => '0');
|
|
inst_op_done <= '0';
|
|
inst_ren <= '0';
|
|
inst_wen <= '0';
|
|
|
|
|
|
case (mem_stage) is
|
|
when IDLE =>
|
|
inst_op_done <= '1';
|
|
|
|
if (inst_op_start = '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,
|
|
sample_cnt => sample_cnt,
|
|
gen_cnt => gen_cnt,
|
|
deadline => deadline,
|
|
writer_bitmap => writer_bitmap,
|
|
update_flags => update_inst_flags,
|
|
addr => inst_addr_update
|
|
);
|
|
|
|
case(inst_opcode) is
|
|
when SEARCH_INSTANCE_HASH =>
|
|
-- Reset Data
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
-- No Instances avialable
|
|
if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_addr_next <= inst_occupied_head;
|
|
inst_stage_next <= SEARCH_INSTANCE_HASH;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when SEARCH_INSTANCE_ADDR =>
|
|
-- Reset Data
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
-- No Instances avialable
|
|
if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_addr_next <= inst_occupied_head;
|
|
inst_stage_next <= SEARCH_INSTANCE_ADDR;
|
|
inst_cnt_next <= 0;
|
|
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_empty_head /= INSTANCE_MEMORY_MAX_ADDRESS) report "Instance Insertion while memory Full" severity FAILURE;
|
|
|
|
inst_addr_next <= inst_empty_head;
|
|
inst_addr_base_next <= inst_empty_head;
|
|
inst_stage_next <= INSERT_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
when UPDATE_INSTANCE =>
|
|
inst_addr_base_next <= inst_addr_update;
|
|
if ((update_inst_flags and STATUS_FLAG) = STATUS_FLAG) then
|
|
inst_stage_next <= UPDATE_INSTANCE;
|
|
inst_addr_next <= inst_addr_update + IMF_STATUS_INFO_OFFSET;
|
|
inst_cnt_next <= 0;
|
|
elsif ((update_inst_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then
|
|
inst_stage_next <= UPDATE_INSTANCE;
|
|
inst_addr_next <= inst_addr_update + IMF_SAMPLE_CNT_OFFSET;
|
|
inst_cnt_next <= 3;
|
|
elsif (GENERATION_COUNTERS and (update_inst_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then
|
|
inst_stage_next <= UPDATE_INSTANCE;
|
|
inst_addr_next <= inst_addr_update + IMF_DISPOSED_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 6;
|
|
elsif (GENERATION_COUNTERS and (update_inst_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
|
|
inst_stage_next <= UPDATE_INSTANCE;
|
|
inst_addr_next <= inst_addr_update + IMF_NO_WRITERS_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 7;
|
|
elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (update_inst_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
|
|
inst_stage_next <= UPDATE_INSTANCE;
|
|
inst_addr_next <= inst_addr_update + IMF_IGNORE_DEADLINE_OFFSET;
|
|
inst_cnt_next <= 8;
|
|
elsif ((update_inst_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_addr_next <= inst_addr_update + IMF_WRITER_BITMAP_OFFSET;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when GET_FIRST_INSTANCE =>
|
|
-- No Instances avialable
|
|
if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_addr_next <= inst_occupied_head + IMF_STATUS_INFO_OFFSET;
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when GET_NEXT_INSTANCE =>
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_addr_next <= inst_next_addr_base;
|
|
inst_stage_next <= GET_NEXT_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
when REMOVE_INSTANCE =>
|
|
assert (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) report "Request Removal on empty memory" severity FAILURE;
|
|
|
|
inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_addr_next <= inst_occupied_head;
|
|
inst_stage_next <= REMOVE_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when SEARCH_INSTANCE_HASH =>
|
|
inst_ren <= '1';
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
inst_addr_next <= inst_addr + 1;
|
|
|
|
case (inst_cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
null;
|
|
-- Next Instance
|
|
when 1 =>
|
|
inst_next_addr_base_next <= inst_read_data;
|
|
-- Key Hash 1/4
|
|
when 2 =>
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(0)) then
|
|
-- Reached List Tail, No Match
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_addr_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
-- Key Hash 2/4
|
|
when 3 =>
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(1)) then
|
|
-- Reached List Tail, No Match
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_addr_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
-- Key Hash 3/4
|
|
when 4 =>
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(2)) then
|
|
-- Reached List Tail, No Match
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_addr_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
-- Key Hash 4/4
|
|
when 5 =>
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(3)) then
|
|
-- Reached List Tail, No Match
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_addr_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
-- Match
|
|
else
|
|
-- Fetch Instance Data
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
inst_cnt_next <= 1; -- No preload needed
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when SEARCH_INSTANCE_ADDR =>
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
inst_addr_next <= inst_addr + 1;
|
|
|
|
case (inst_cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
inst_ren <= '1';
|
|
-- Next Instance
|
|
when 1 =>
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_read_data;
|
|
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.addr) then
|
|
-- Fetch Instance Data
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
inst_addr_next <= inst_read_data + IMF_STATUS_INFO_OFFSET;
|
|
inst_cnt_next <= 0;
|
|
-- Match
|
|
else
|
|
-- Reached List Tail, No Match
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_addr_next <= inst_read_data;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_NEXT_INSTANCE =>
|
|
case (inst_cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
inst_wen <= '1';
|
|
-- Next Instance
|
|
when 1 =>
|
|
-- Latch Next Instance
|
|
inst_next_addr_base_next <= inst_read_data;
|
|
|
|
inst_addr_next <= inst_addr_base + IMF_STATUS_INFO_OFFSET;
|
|
inst_cnt_next <= 0;
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
end case;
|
|
when GET_INSTANCE_DATA =>
|
|
-- Precondition: inst_addr (Status Info)
|
|
|
|
inst_ren <= '1';
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
inst_addr_next <= inst_addr + 1;
|
|
|
|
case (inst_cnt) is
|
|
-- Memory Preload
|
|
when 0 =>
|
|
null;
|
|
-- Status Info
|
|
when 1 =>
|
|
inst_data_next.status_info <= inst_read_data;
|
|
-- Sample Count
|
|
when 2 =>
|
|
inst_data_next.sample_cnt <= inst_read_data;
|
|
-- Disposed Generation Count
|
|
when 3 =>
|
|
inst_data_next.disposed_gen_cnt <= inst_read_data;
|
|
-- No Writers Generation Count
|
|
when 4 =>
|
|
inst_data_next.no_writers_gen_cnt <= inst_read_data;
|
|
-- Ignore Deadline 1/2
|
|
when 5 =>
|
|
inst_data_next.ignore_deadline(0) <= unsigned(inst_read_data);
|
|
-- Ignore Deadline 2/2
|
|
when 5 =>
|
|
inst_data_next.ignore_deadline(1) <= unsigned(inst_read_data);
|
|
-- DONE
|
|
inst_stage_next <= GET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_WRITER_BITMAP =>
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
|
|
inst_latch_data_next.writer_bitmap(inst_cnt) <= inst_read_data;
|
|
|
|
if (inst_cnt = writer_bitmap'length-1) then
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when INSERT_INSTANCE =>
|
|
|
|
inst_wen <= '1';
|
|
inst_addr_next <= inst_addr + 1;
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
|
|
case (inst_cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
inst_ren <= '1';
|
|
-- Next Instance Address
|
|
when 1 =>
|
|
inst_empty_head_next <= inst_read_data;
|
|
-- Make New Occupied Head
|
|
inst_write_data <= inst_occupied_head;
|
|
inst_occupied_head_next <= inst_empty_head;
|
|
-- Key Hash 1/4
|
|
when 2 =>
|
|
inst_write_data <= inst_latch_data.key_hash(0);
|
|
-- Key Hash 2/4
|
|
when 3 =>
|
|
inst_write_data <= inst_latch_data.key_hash(1);
|
|
-- Key Hash 3/4
|
|
when 4 =>
|
|
inst_write_data <= inst_latch_data.key_hash(2);
|
|
-- Key Hash 4/4
|
|
when 5 =>
|
|
inst_write_data <= inst_latch_data.key_hash(3);
|
|
-- Status Info
|
|
when 6 =>
|
|
inst_write_data <= inst_latch_data.status_info;
|
|
-- Sample Count
|
|
when 7 =>
|
|
inst_write_data <= std_logic_vector(to_unsigned(1, WORD_WIDTH));
|
|
|
|
if (GENERATION_COUNTERS) then
|
|
inst_cnt <= 8;
|
|
elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
|
|
inst_cnt <= 10;
|
|
else
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
-- Disposed Generation Count
|
|
when 8 =>
|
|
if (GENERATION_COUNTERS) then
|
|
inst_write_data <= (others => '0');
|
|
end if;
|
|
-- No Writers Generation Count
|
|
when 9 =>
|
|
if (GENERATION_COUNTERS) then
|
|
inst_write_data <= (others => '0');
|
|
|
|
if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
|
|
inst_cnt <= 10;
|
|
else
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
-- Ignore Deadline 1/2
|
|
when 10 =>
|
|
if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
|
|
inst_write_data <= inst_latch_data.deadline(0);
|
|
end if;
|
|
-- Ignore Deadline 1/2
|
|
when 11 =>
|
|
if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
|
|
inst_write_data <= inst_latch_data.deadline(1);
|
|
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when SET_WRITER_BITMAP =>
|
|
inst_wen <= '1';
|
|
inst_addr_next <= inst_addr + 1;
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
|
|
inst_write_data <= inst_latch_data.writer_bitmap(inst_cnt);
|
|
|
|
-- Exit Condition
|
|
if (inst_cnt = inst_latch_data.writer_bitmap'length-1) then
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when UPDATE_INSTANCE =>
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
|
|
case (inst_cnt) is
|
|
-- Status Info
|
|
when 0 =>
|
|
inst_wen <= '1';
|
|
inst_write_data <= inst_long_latch;
|
|
case (inst_latch_data.instance_state) is
|
|
when ALIVE =>
|
|
inst_write_data(NOT_ALIVE_DISPOSED_FLAG) <= '0';
|
|
inst_write_data(NOT_ALIVE_NO_WRITERS_FLAG) <= '0';
|
|
inst_write_data(LIVELINESS_FLAG) <= '1';
|
|
when NOT_ALIVE_DISPOSED =>
|
|
inst_write_data(NOT_ALIVE_DISPOSED_FLAG) <= '1';
|
|
inst_write_data(NOT_ALIVE_NO_WRITERS_FLAG) <= '0';
|
|
inst_write_data(LIVELINESS_FLAG) <= '1';
|
|
when NOT_ALIVE_NO_WRITERS =>
|
|
inst_write_data(NOT_ALIVE_DISPOSED_FLAG) <= '0';
|
|
inst_write_data(NOT_ALIVE_NO_WRITERS_FLAG) <= '1';
|
|
inst_write_data(LIVELINESS_FLAG) <= '1';
|
|
end case;
|
|
|
|
if ((inst_latch_data.update_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET;
|
|
inst_cnt_next <= 1;
|
|
elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_DISPOSED_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 2;
|
|
elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 3;
|
|
elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET;
|
|
inst_cnt_next <= 4;
|
|
elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET;
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
-- Sample Count
|
|
when 1 =>
|
|
inst_wen <= '1';
|
|
inst_write_data <= inst_latch_data.sample_cnt;
|
|
|
|
if (GENERATION_COUNTERS and (inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_DISPOSED_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 2;
|
|
elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 3;
|
|
elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET;
|
|
inst_cnt_next <= 4;
|
|
elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET;
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
-- Disposed Generation Count
|
|
when 2 =>
|
|
if (GENERATION_COUNTERS) then
|
|
inst_wen <= '1';
|
|
inst_write_data <= 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_next <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET;
|
|
inst_cnt_next <= 3;
|
|
elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET;
|
|
inst_cnt_next <= 4;
|
|
elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET;
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- No Writers Generation Count
|
|
when 3 =>
|
|
if (GENERATION_COUNTERS) then
|
|
inst_wen <= '1';
|
|
inst_write_data <= 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_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET;
|
|
inst_cnt_next <= 4;
|
|
elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then
|
|
inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET;
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
-- Ignore Deadline 1/2
|
|
when 4 =>
|
|
if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
|
|
inst_wen <= '1';
|
|
inst_write_data <= std_logic_vector(inst_latch_data.ignore_deadline(0));
|
|
end if;
|
|
-- Ignore Deadline 2/2
|
|
when 5 =>
|
|
if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then
|
|
inst_wen <= '1';
|
|
inst_write_data <= 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_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET;
|
|
inst_stage_next <= SET_WRITER_BITMAP;
|
|
inst_cnt_next <= 0;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE_INSTANCE =>
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
|
|
case (inst_cnt) is
|
|
-- Preload
|
|
when 0 =>
|
|
inst_ren <= '1';
|
|
inst_addr_next <= inst_prev_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
-- Next Instance (Previous Occupied Instance)
|
|
when 1 =>
|
|
-- Fix Pointer
|
|
inst_write_data <= inst_read_data;
|
|
inst_wen <= '1';
|
|
|
|
inst_addr_next <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
-- Next Instance (Current Instance)
|
|
when 2 =>
|
|
-- Fix Pointer
|
|
inst_write_data <= inst_empty_head;
|
|
inst_wen <= '1';
|
|
-- Fix Empty List Head
|
|
inst_empty_head_next <= inst_addr_base;
|
|
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end process;
|
|
|
|
end architecture; |