From 0574f9e69daafa2c566e4929c4e58552398bf38e Mon Sep 17 00:00:00 2001 From: Greek Date: Mon, 11 Jan 2021 12:21:36 +0100 Subject: [PATCH] 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. --- src/history_cache.vhd | 619 +++++++++++++++++++++++++++++++++++++ src/key_generator.vhd | 24 ++ src/key_hash_generator.vhd | 167 ++++++++++ 3 files changed, 810 insertions(+) create mode 100644 src/history_cache.vhd create mode 100644 src/key_generator.vhd create mode 100644 src/key_hash_generator.vhd diff --git a/src/history_cache.vhd b/src/history_cache.vhd new file mode 100644 index 0000000..c5fc109 --- /dev/null +++ b/src/history_cache.vhd @@ -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; \ No newline at end of file diff --git a/src/key_generator.vhd b/src/key_generator.vhd new file mode 100644 index 0000000..42582b3 --- /dev/null +++ b/src/key_generator.vhd @@ -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; \ No newline at end of file diff --git a/src/key_hash_generator.vhd b/src/key_hash_generator.vhd new file mode 100644 index 0000000..1c4ddbf --- /dev/null +++ b/src/key_hash_generator.vhd @@ -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; \ No newline at end of file