The Sample Memory was changed to contain only the Instance Memory Address instead of the whole Key Hash. This simplifies the B process and reduces memory footprint. The instance memory process was also updated to handle the conditional fields defined in the previous commit.
1680 lines
90 KiB
VHDL
1680 lines
90 KiB
VHDL
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; |