Blind implementation of RTPS READER history Cache
Initial imeplementation of the RTPS Reader side of the history cache. A key_hash_generator entity that will house the future MD5 hash calculation was also added, along with the entity definition of key_generator, which has to be implemented per-topic-type.
This commit is contained in:
parent
d0709db3a2
commit
0574f9e69d
619
src/history_cache.vhd
Normal file
619
src/history_cache.vhd
Normal file
@ -0,0 +1,619 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity history_cache is
|
||||
generic (
|
||||
ORDER : boolean := TRUE
|
||||
);
|
||||
port (
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
start_a : in std_logic;
|
||||
opcode_a : in HISTORY_CACHE_OPCODE_TYPE;
|
||||
ack_a : out std_logic;
|
||||
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;
|
||||
ack_b : out std_logic;
|
||||
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(PAYLAOD_MEMORY_ADDR_WIDTH-1 downto 0) := PAYLOAD_MEMORY_MAX_ADDRESS - PAYLOAD_FRAME_SIZE + 1;
|
||||
|
||||
|
||||
--*****TYPE DECLARATION*****
|
||||
-- FSM states. Explained below in detail
|
||||
type STAGE_TYPE is (IDLE, TODO);
|
||||
|
||||
--*****SIGNAL DECLARATION
|
||||
signal stage_a, stage_a_next : STAGE_TYPE := IDLE;
|
||||
signal cnt_a, cnt_a_next : natural range TODO := 0;
|
||||
signal empty_sample_slot, empty_sample_slot_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
||||
signal empty_payload_slot, empty_payload_slot_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
||||
signal next_sample, next_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
||||
|
||||
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 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 has_data, has_data_next : std_logic := '0';
|
||||
signal has_key_hash, has_key_hash_next : std_logic := '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 has_latched, has_latched_next : std_logic := '0';
|
||||
|
||||
signal payload_mem_full, payload_mem_full_next : std_logic := '0';
|
||||
signal sample_mem_full, sample_mem_full_next : std_logic := '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 first_payload : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2;
|
||||
alias first_payload_next: unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2_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;
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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_opcode : HISTORY_CACHE_OPCODE_TYPE := NOP;
|
||||
variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0'));
|
||||
begin
|
||||
-- Default
|
||||
stage_a_next <= stage_a;
|
||||
ack_a <= '0';
|
||||
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;
|
||||
has_data_next <= has_data;
|
||||
has_key_hash_next <= has_key_hash;
|
||||
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;
|
||||
has_latched_next <= has_latched;
|
||||
payload_mem_full_next <= payload_mem_full;
|
||||
sample_mem_full_next <= sample_mem_full;
|
||||
khg_last_word_in <= '0';
|
||||
khg_data_in <= (others => '0');
|
||||
khg_valid_in <= '0';
|
||||
khg_ready_out <= '0';
|
||||
|
||||
|
||||
case (stage_a) is
|
||||
when IDLE =>
|
||||
-- No Memory left for ADD
|
||||
if (payload_mem_full = '1' or sample_mem_full = '1') then
|
||||
stage_a_next <= WAIT_FOR_REMOVE;
|
||||
elsif (start_a = '1') then
|
||||
case (opcode_a) is
|
||||
when ADD_CHANGE =>
|
||||
stage_a_next <= ADD_SAMPLE_INFO;
|
||||
sample_addr_a_next <= empty_sample_list_head;
|
||||
cnt_a_next <= 0;
|
||||
ack_a <= '1';
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
when ADD_SAMPLE_INFO =>
|
||||
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
|
||||
has_data_next <= data_in_a(PAYLOAD_FLAG);
|
||||
has_key_hash_next <= data_in_a(KEY_HASH_FLAG);
|
||||
-- Latch Timestamp for ordering
|
||||
-- Timestamp 1/2
|
||||
when 11 =>
|
||||
ts_latch_next(0) <= data_in_a;
|
||||
-- Timestamp 2/2
|
||||
when 12 =>
|
||||
ts_latch_next(1) <= data_in_a;
|
||||
-- Last Sample Info word
|
||||
when 14 =>
|
||||
-- NOTE: Until now correct operation of the requester is assumed (No check on last_word_in)
|
||||
-- No further data
|
||||
if (has_data = '0' and has_key_hash = '1') then
|
||||
-- Signal Sucessfull Operation
|
||||
ack_a <= '1';
|
||||
end if;
|
||||
stage_a_next <= ADD_PAYLOAD_ADDRESS;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
when ADD_PAYLOAD_ADDRESS =>
|
||||
-- Precondition: sample_addr_a (Payload Address)
|
||||
if (has_data = '1') then
|
||||
-- Store Payload Address
|
||||
sample_wen_a <= '1';
|
||||
sample_write_data_a <= empty_payload_list_tail;
|
||||
|
||||
payload_addr_a_next <= empty_payload_list_tail + 1;
|
||||
cur_payload_next <= empty_payload_list_tail;
|
||||
first_payload_next <= empty_payload_list_tail;
|
||||
stage_a_next <= ADD_PAYLOAD;
|
||||
cnt_a_next <= 0;
|
||||
else
|
||||
sample_wen_a <= '1';
|
||||
sample_write_data_a <= MAX_PAYLOAD_ADDRESS;
|
||||
|
||||
-- First Sample
|
||||
if (newest_sample = MAX_SAMPLE_ADDRESS) then
|
||||
stage_a_next <= FINALIZE_SAMPLE_INFO;
|
||||
sample_addr_a_next <= empty_sample_list_head + 16;
|
||||
next_sample_next <= MAX_SAMPLE_ADDRESS;
|
||||
prev_sample_next <= MAX_SAMPLE_ADDRESS;
|
||||
cnt_a_next <= 0;
|
||||
else
|
||||
stage_a_next <= FIND_POS;
|
||||
prev_sample_next <= newest_sample;
|
||||
sample_addr_a_next <= newest_sample + 11;
|
||||
cnt_a_next <= 0;
|
||||
end if;
|
||||
end if;
|
||||
when ADD_PAYLOAD =>
|
||||
-- Precondition: cur_payload set (Current Slot), payload_addr_a (cur_payload+1)
|
||||
ready_in_a <= '1';
|
||||
-- Input Guard
|
||||
if (valid_in_a = '1') then
|
||||
cnt_a_next <= cnt_a + 1;
|
||||
payload_addr_a_next <= payload_addr_a + 1;
|
||||
|
||||
-- Write through
|
||||
payload_write_data_a <= data_in_a;
|
||||
payload_wen_a <= '1';
|
||||
|
||||
-- End of Payload
|
||||
if (last_word_in_a = '1') then
|
||||
-- Mark Operation as sucessfull
|
||||
ack_a <= '1';
|
||||
stage_a_next <= FINALIZE_PAYLOAD;
|
||||
payload_addr_a_next <= cur_payload;
|
||||
cnt_a_next <= 0;
|
||||
-- End of Payload Slot
|
||||
elsif (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 = MAX_PAYLOAD_ADDRESS) then
|
||||
-- Skip Operation
|
||||
stage_a_next <= SKIP_ADD;
|
||||
else
|
||||
-- Latch next Payload Slot
|
||||
cur_payload_next <= payload_read_data_a;
|
||||
|
||||
-- Continue
|
||||
payload_addr_a_next <= payload_read_data_a + 1;
|
||||
stage_a_next <= ADD_PAYLOAD;
|
||||
end if;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
when FINALIZE_PAYLOAD =>
|
||||
-- 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 Slot available
|
||||
if (payload_read_data_a = MAX_PAYLOAD_ADDRESS) then
|
||||
assert (cur_payload = empty_payload_list_tail) report "Payload List empty, but HEAD /= TAIL" severity FAILURE;
|
||||
-- Signal No available slots by setting HEAD to MAX ADDRESS
|
||||
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 <= MAX_PAYLOAD_ADDRESS;
|
||||
payload_wen_a <= '1';
|
||||
|
||||
-- First Sample
|
||||
if (newest_sample = MAX_SAMPLE_ADDRESS) then
|
||||
stage_a_next <= FINALIZE_SAMPLE_INFO;
|
||||
sample_addr_a_next <= empty_sample_list_head + 16;
|
||||
next_sample_next <= MAX_SAMPLE_ADDRESS;
|
||||
prev_sample_next <= MAX_SAMPLE_ADDRESS;
|
||||
cnt_a_next <= 0;
|
||||
else
|
||||
stage_a_next <= FIND_POS;
|
||||
prev_sample_next <= newest_sample;
|
||||
sample_addr_a_next <= newest_sample + 11;
|
||||
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 + 4; -- 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 + 1; -- 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 = MAX_PAYLOAD_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 + 11;
|
||||
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 = MAX_SAMPLE_ADDRESS) then
|
||||
assert (prev_sample = newest_sample) report "Next Sample is MAX_ADDRESS, but sample is not NEWEST (TAIL)" severity FAILURE;
|
||||
|
||||
next_sample_next <= MAX_SAMPLE_ADDRESS;
|
||||
stage_a_next <= FINALIZE_SAMPLE_INFO;
|
||||
sample_addr_a_next <= empty_sample_list_head + 16;
|
||||
cnt_a_next <= 0;
|
||||
else
|
||||
-- Latch Next Sample
|
||||
next_sample_next <= sample_read_data_a;
|
||||
|
||||
sample_addr_a_next <= sample_read_data_a + 16; -- 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 + 16;
|
||||
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
|
||||
when 0 =>
|
||||
sample_addr_a_next <= sample_addr_a + 1;
|
||||
|
||||
-- Write Prev Addr
|
||||
sample_write_data_a <= prev_sample;
|
||||
sample_ren_a <= '1';
|
||||
when 1 =>
|
||||
-- Preload
|
||||
sample_ren_a <= '1';
|
||||
when 2 =>
|
||||
-- No empty Sample Slot Available
|
||||
if (sample_read_data_a = MAX_SAMPLE_ADDRESS) then
|
||||
-- Signal No available slots by setting HEAD to MAX ADDRESS
|
||||
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;
|
||||
|
||||
if (has_key_hash = '0') then
|
||||
-- Key Hash needs Calculating
|
||||
if (has_data = '1') then
|
||||
stage_a_next <= GET_NEXT_PAYLOAD_SLOT;
|
||||
sample_addr_a_next <= empty_sample_list_head + 1; -- Points to beginning of Key Hash
|
||||
payload_addr_a_next <= first_payload; -- Points to first payload slot
|
||||
cnt_a_next <= 0;
|
||||
else
|
||||
stage_a_next <= INITIATE_KEY_HASH_CALCULATION_IN;
|
||||
sample_addr_a_next <= empty_sample_list_head + 1; -- Points to beginning of Key Hash
|
||||
end if;
|
||||
else
|
||||
-- DONE
|
||||
stage_a_next <= IDLE;
|
||||
end if;
|
||||
end case;
|
||||
when GET_NEXT_PAYLOAD_SLOT =>
|
||||
-- Precondition: payload_addr_a (Beginning of payload slot)
|
||||
cnt_a_next <= cnt_a + 1;
|
||||
payload_addr_a_next <= payload_addr_a + 1;
|
||||
payload_ren_a <= '1';
|
||||
|
||||
case (cnt_a) is
|
||||
-- Preload
|
||||
when 0 =>
|
||||
null;
|
||||
when 1 =>
|
||||
-- Latch Next Slot
|
||||
next_payload_next <= payload_read_data_a;
|
||||
stage_a_next <= INITIATE_KEY_HASH_CALCULATION;
|
||||
cnt_a_next <= 0;
|
||||
has_latched_next <= '0';
|
||||
end case;
|
||||
when INITIATE_KEY_HASH_CALCULATION_MEM =>
|
||||
-- Precondition: payload_addr_a (Current Beginning+2), payload_read_data_a (Current Beginning+1), next_payload set to next Slot (if available) or MAX_ADDRESS (if not availble)
|
||||
-- Output Guard
|
||||
if (khg_ready_in = '1') then
|
||||
cnt_a_next <= cnt_a + 1;
|
||||
payload_addr_a_next <= payload_addr_a + 1;
|
||||
payload_ren_a <= '1';
|
||||
khg_valid_in <= '1';
|
||||
|
||||
if (has_latched = '0') then
|
||||
-- Passthrough
|
||||
khg_data_in <= payload_read_data_a;
|
||||
else
|
||||
-- Previously Latched
|
||||
khg_data_in <= long_latch;
|
||||
end if;
|
||||
|
||||
-- Reset
|
||||
has_latched_next <= '0';
|
||||
|
||||
if (cnt_a = PAYLOAD_FRAME_SIZE-2) then
|
||||
-- Last Payload Slot
|
||||
if (next_payload = MAX_PAYLOAD_ADDRESS) then
|
||||
khg_last_word_in <= '1';
|
||||
stage_a_next <= GET_KEY_HASH;
|
||||
else
|
||||
stage_a_next <= GET_NEXT_PAYLOAD_SLOT;
|
||||
payload_addr_a_next <= next_payload;
|
||||
cnt_a_next <= 0;
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
khg_valid_in <= '0';
|
||||
-- Latch Read Data
|
||||
if (has_latched = '0') then
|
||||
long_latch_next <= payload_read_data_a;
|
||||
has_latched_next <= '1';
|
||||
end if;
|
||||
end if;
|
||||
when INITIATE_KEY_HASH_CALCULATION_IN =>
|
||||
-- Input Passthrough
|
||||
ready_in_a <= khg_ready_in;
|
||||
khg_valid_in <= valid_in_a;
|
||||
khg_data_in <= data_in_a;
|
||||
khg_last_word_in<= last_word_in_a;
|
||||
if (last_word_in_a = '1') then
|
||||
stage_a_next <= GET_KEY_HASH;
|
||||
end if;
|
||||
when GET_KEY_HASH =>
|
||||
-- Precondition: sample_addr_a (KeyHash 1/4 of current sample)
|
||||
khg_ready_out <= '1';
|
||||
if (khg_valid_out = '1') then
|
||||
sample_addr_a_next <= sample_addr_a + 1;
|
||||
sample_wen_a <= '1';
|
||||
|
||||
sample_write_data_a <= khg_data_out;
|
||||
|
||||
-- XXX: Assumes the Key Hash Generator writes only KeyHash size
|
||||
-- Exit Condition
|
||||
if (khg_last_word_out = '1') then
|
||||
-- DONE
|
||||
stage_a_next <= IDLE;
|
||||
end if;
|
||||
end if;
|
||||
when SKIP_ADD =>
|
||||
ready_in_a <= '1';
|
||||
-- Wait until last word from input
|
||||
-- NOTE: By not pulling ack_a high we are signaling that the operation failed
|
||||
if (last_word_in_a = '1') then
|
||||
-- NOTE: Because we did not yet change any pointer from the linked lists, we do not have to do any cleanup.
|
||||
stage_a_next <= IDLE;
|
||||
end if;
|
||||
when WAIT_FOR_REMOVE =>
|
||||
-- Exit Condition
|
||||
if (payload_mem_full = '0' and sample_mem_full = '0') then
|
||||
stage_a_next <= IDLE;
|
||||
end if;
|
||||
|
||||
-- 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;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
24
src/key_generator.vhd
Normal file
24
src/key_generator.vhd
Normal file
@ -0,0 +1,24 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity key_generator is
|
||||
port (
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
start : in std_logic;
|
||||
opcode : in KEY_GENERATOR_OPCODE_TYPE;
|
||||
busy : out std_logic;
|
||||
|
||||
data_in : in std_logic_vector(WORD_WIDTH-1 downto 0);
|
||||
valid_in : in std_logic;
|
||||
ready_in : out std_logic;
|
||||
last_word_in : in std_logic;
|
||||
|
||||
data_out : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
||||
valid_out : out std_logic;
|
||||
ready_out : in std_logic;
|
||||
last_word_out : out std_logic
|
||||
);
|
||||
end entity;
|
||||
167
src/key_hash_generator.vhd
Normal file
167
src/key_hash_generator.vhd
Normal file
@ -0,0 +1,167 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity key_hash_generator is
|
||||
port (
|
||||
clk : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
data_in : in std_logic_vector(WORD_WIDTH-1 downto 0);
|
||||
valid_in : in std_logic;
|
||||
ready_in : out std_logic;
|
||||
last_word_in : in std_logic;
|
||||
|
||||
data_out : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
||||
valid_out : out std_logic;
|
||||
ready_out : in std_logic;
|
||||
last_word_out : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of key_hash_generator is
|
||||
|
||||
--*****CONSTANT DECLARATION*****
|
||||
constant KEY_SIZE : natural := TODO;
|
||||
|
||||
--*****TYPE DECLARATION*****
|
||||
type STAGE_TYPE is (IDLE, TODO);
|
||||
|
||||
--*****SIGNAL DECLARATION*****
|
||||
signal key_gen_start, key_gen_busy, key_gen_valid_in, key_gen_ready_in, key_gen_last_word_in, key_gen_valid_out, key_gen_ready_out, key_gen_last_word_out : std_logic := '0';
|
||||
signal key_gen_opcode : KEY_GENERATOR_OPCODE_TYPE := NOP;
|
||||
signal key_gen_data_in, key_gen_data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
|
||||
|
||||
signal stage, stage_next : STAGE_TYPE := IDLE;
|
||||
signal key_hash, key_hash_next : KEY_HASH_TYPE := (others => (others => '0'));
|
||||
signal cnt, cnt_next : natural range 0 to KEY_HASH_TYPE'length-1 := 0;
|
||||
|
||||
begin
|
||||
|
||||
key_generator_inst : entity work.key_generator(arch)
|
||||
port map(
|
||||
clk => clk,
|
||||
reset => reset,
|
||||
start => key_gen_start,
|
||||
opcode => key_gen_opcode,
|
||||
busy => key_gen_busy,
|
||||
data_in => key_gen_data_in,
|
||||
valid_in => key_gen_valid_in,
|
||||
ready_in => key_gen_ready_in,
|
||||
last_word_in => key_gen_last_word_in,
|
||||
data_out => key_gen_data_out,
|
||||
valid_out => key_gen_valid_out,
|
||||
ready_out => key_gen_ready_out,
|
||||
last_word_out => key_gen_last_word_out
|
||||
);
|
||||
|
||||
|
||||
main_prc : process (all)
|
||||
begin
|
||||
-- DEFAULT
|
||||
stage_next <= stage;
|
||||
key_hash_next <= key_hash;
|
||||
cnt_next <= cnt;
|
||||
ready_in <= '0';
|
||||
key_gen_start <= '0';
|
||||
key_gen_valid_in <= '0';
|
||||
key_gen_last_word_in <= '0';
|
||||
key_gen_data_in <= (others => '0');
|
||||
key_gen_ready_out <= '0';
|
||||
valid_out <= '0';
|
||||
last_word_out <= '0';
|
||||
data_out <= (others => '0');
|
||||
|
||||
case (stage) is
|
||||
when IDLE =>
|
||||
if (valid_in = '1' and key_gen_busy = '0') then
|
||||
key_gen_start <= '1';
|
||||
key_gen_opcode <= WRITE_PAYLOAD;
|
||||
stage_next <= PASSTHROUGH_PAYLOAD;
|
||||
end if;
|
||||
when PASSTHROUGH_PAYLOAD =>
|
||||
-- TODO: Connect directly to key_generator?
|
||||
ready_in <= key_gen_ready_in;
|
||||
key_gen_valid_in <= valid_in;
|
||||
key_gen_data_in <= data_in;
|
||||
key_gen_last_word_in <= last_word_in;
|
||||
|
||||
-- Exit Condition
|
||||
if (last_word_in = '1') then
|
||||
stage_next <= GET_SIZE;
|
||||
end if;
|
||||
when GET_SIZE =>
|
||||
if (key_gen_busy = '0') then
|
||||
key_gen_start <= '1';
|
||||
key_gen_opcode <= READ_SIZE;
|
||||
stage_next <= READ_SIZE;
|
||||
end if;
|
||||
when READ_SIZE =>
|
||||
key_gen_ready_out <= '1';
|
||||
if (key_gen_valid_out = '1') then
|
||||
if (unsigned(key_gen_data_out)) > (KEY_HASH_WIDTH/BYTE_WIDTH)) then
|
||||
-- TODO: MD5 Calculation
|
||||
assert FALSE report "MD5 Key hash generation not yet implemented." severity FAILURE;
|
||||
else
|
||||
stage_next <= GET_KEY_HASH;
|
||||
end if;
|
||||
end if;
|
||||
when GET_KEY_HASH =>
|
||||
if (key_gen_busy = '0') then
|
||||
key_gen_start <= '1';
|
||||
key_gen_opcode <= READ_KEY;
|
||||
|
||||
stage_next <= WRITE_KEY_HASH;
|
||||
cnt_next <= 0;
|
||||
key_hash_next <= (others => (others => '0'));
|
||||
end if;
|
||||
when WRITE_KEY_HASH =>
|
||||
key_gen_ready_out <= '1';
|
||||
if (key_gen_valid_out) then
|
||||
cnt_next <= cnt + 1;
|
||||
|
||||
case (cnt) is
|
||||
when 0 =>
|
||||
key_hash_next(0) <= key_gen_data_out;
|
||||
when 1 =>
|
||||
key_hash_next(1) <= key_gen_data_out;
|
||||
when 2 =>
|
||||
key_hash_next(2) <= key_gen_data_out;
|
||||
when 3 =>
|
||||
key_hash_next(3) <= key_gen_data_out;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
|
||||
if (key_gen_last_word_out = '1') then
|
||||
stage_next <= FINISHED_KEY_HASH;
|
||||
cnt_next <= 0;
|
||||
end if;
|
||||
end if;
|
||||
when FINISHED_KEY_HASH =>
|
||||
valid_out <= '1';
|
||||
if (ready_out = '1') then
|
||||
cnt_next <= cnt + 1;
|
||||
|
||||
case (cnt) is
|
||||
when 0 =>
|
||||
data_out <= key_hash(0);
|
||||
when 1 =>
|
||||
data_out <= key_hash(1);
|
||||
when 2 =>
|
||||
data_out <= key_hash(2);
|
||||
when 3 =>
|
||||
data_out <= key_hash(3);
|
||||
last_word_out <= '1';
|
||||
|
||||
stage_next <= IDLE;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end if;
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
end architecture;
|
||||
Loading…
Reference in New Issue
Block a user