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:
Greek 2021-01-11 12:21:36 +01:00
parent d0709db3a2
commit 0574f9e69d
3 changed files with 810 additions and 0 deletions

619
src/history_cache.vhd Normal file
View 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
View 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
View 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;