Bug Fix and Redesign of TEMPLATE_key_holder

Until now it was assumed that a serialized key is the PLAIN_CDR2
Big Endian encoding of a <TYPENAME>KeyHolder Object [DDS_XTYPES v1.3, 7.6.8]
(I.e. the same blob that computes the MD5 key hash).
Taking other DDS implementations as reference (e.g. Cyclone DDS), it
seems they are using a normal Payload containing a KeyHolder(<TYPENAME>)
Object [DDS_XTYPES v1.3, 7.2.2.4.7] as the serialized key.
The Key Holder Template (together with the Type1 and Type2
implementations) were updated to reflect this change.
A bug fix were the Key Hash was not reset on a 'PUSH_SERIALIZED_KEY'
opcode was also fixed (together with the testbench).
This commit is contained in:
Greek 2021-12-03 12:01:20 +01:00
parent 5d9acb6f41
commit 830d6c1409
16 changed files with 413 additions and 170 deletions

View File

@ -0,0 +1,47 @@
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -divider SYSTEM
add wave -noupdate /l1_type1_key_holder_test1/uut/clk
add wave -noupdate /l1_type1_key_holder_test1/uut/reset
add wave -noupdate /l1_type1_key_holder_test1/uut/start
add wave -noupdate /l1_type1_key_holder_test1/uut/opcode
add wave -noupdate /l1_type1_key_holder_test1/uut/ack
add wave -noupdate /l1_type1_key_holder_test1/uut/decode_error
add wave -noupdate -divider INPUT
add wave -noupdate -radix hexadecimal /l1_type1_key_holder_test1/uut/data_in
add wave -noupdate /l1_type1_key_holder_test1/uut/valid_in
add wave -noupdate /l1_type1_key_holder_test1/uut/ready_in
add wave -noupdate /l1_type1_key_holder_test1/uut/last_word_in
add wave -noupdate -divider OUTPUT
add wave -noupdate -radix hexadecimal /l1_type1_key_holder_test1/uut/data_out
add wave -noupdate /l1_type1_key_holder_test1/uut/valid_out
add wave -noupdate /l1_type1_key_holder_test1/uut/ready_out
add wave -noupdate /l1_type1_key_holder_test1/uut/last_word_out
add wave -noupdate -divider INTERNAL
add wave -noupdate /l1_type1_key_holder_test1/uut/stage
add wave -noupdate /l1_type1_key_holder_test1/uut/stage_next
add wave -noupdate /l1_type1_key_holder_test1/uut/decode_stage
add wave -noupdate /l1_type1_key_holder_test1/uut/decode_stage_next
add wave -noupdate /l1_type1_key_holder_test1/uut/encode_stage
add wave -noupdate /l1_type1_key_holder_test1/uut/encode_stage_next
add wave -noupdate /l1_type1_key_holder_test1/uut/cnt
add wave -noupdate -divider MISC
add wave -noupdate /l1_type1_key_holder_test1/uut/align_offset
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {13838438 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {13547400 ps} {14571400 ps}

View File

@ -0,0 +1,47 @@
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -divider SYSTEM
add wave -noupdate /l1_type2_key_holder_test2/uut/clk
add wave -noupdate /l1_type2_key_holder_test2/uut/reset
add wave -noupdate /l1_type2_key_holder_test2/uut/start
add wave -noupdate /l1_type2_key_holder_test2/uut/opcode
add wave -noupdate /l1_type2_key_holder_test2/uut/ack
add wave -noupdate /l1_type2_key_holder_test2/uut/decode_error
add wave -noupdate -divider INPUT
add wave -noupdate -radix hexadecimal /l1_type2_key_holder_test2/uut/data_in
add wave -noupdate /l1_type2_key_holder_test2/uut/valid_in
add wave -noupdate /l1_type2_key_holder_test2/uut/ready_in
add wave -noupdate /l1_type2_key_holder_test2/uut/last_word_in
add wave -noupdate -divider OUTPUT
add wave -noupdate -radix hexadecimal /l1_type2_key_holder_test2/uut/data_out
add wave -noupdate /l1_type2_key_holder_test2/uut/valid_out
add wave -noupdate /l1_type2_key_holder_test2/uut/ready_out
add wave -noupdate /l1_type2_key_holder_test2/uut/last_word_out
add wave -noupdate -divider INTERNAL
add wave -noupdate /l1_type2_key_holder_test2/uut/stage
add wave -noupdate /l1_type2_key_holder_test2/uut/stage_next
add wave -noupdate /l1_type2_key_holder_test2/uut/decode_stage
add wave -noupdate /l1_type2_key_holder_test2/uut/decode_stage_next
add wave -noupdate /l1_type2_key_holder_test2/uut/encode_stage
add wave -noupdate /l1_type2_key_holder_test2/uut/encode_stage_next
add wave -noupdate /l1_type2_key_holder_test2/uut/cnt
add wave -noupdate -divider MISC
add wave -noupdate /l1_type2_key_holder_test2/uut/align_offset
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {13838438 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {13547400 ps} {14571400 ps}

View File

@ -259,28 +259,39 @@ Both encode_stage and decode_stage signals exist.
The 'ALIGN_STREAM' stage is split into 'ALIGN_IN_STREAM' (for decode_stage) and 'ALIGN_OUT_STREAM'
(for encode_stage).
The encoding/decoding follows the definition of the <TOPIC>KeyHolder sub-type definition.[6]
The decode procedure (decode_stage stages) follow the reader_wrapper procedure of the <TOPIC> type until
the last declared member that is also member of the <TOPIC>KeyHolder type, after which the 'SKIP_PAYLOAD'
stage is taken. (Since the serialized key only uses the KeyHolder members, the rest is ignored)
The encode procedure (encode_stage stages) follow the writer_wrapper procedure of the <TOPIC>KeyHolder type.
The decode procedure (decode_stage stages) follows 2 different decoding procedures.
The first - taken on a 'PUSH_DATA' opcode - follows the reader_wrapper procedure of the <TOPIC> type until
the last declared member that is also member of the KeyHolder(<TYPENAME>)[6] Type (i.e. the last decalred
key of the type), after which the 'SKIP_PAYLOAD' stage is taken.
(Since the serialized key only uses the KeyHolder(<TYPENAME>) members, the rest is ignored)
The second - taken on a 'PUSH_SERIALIZED_KEY' opcode - follows the reader_wrapper procedure of the
KeyHolder(<TYPENAME>) directly.
Since the decode_stages for the second decoding procedure are a subset of the first decoding procedure,
the same decode stages are used, and only the 'decode_stage_next' signal is set depending on the
'opcode_latch' signal. The 'GET_PAYLAOD_HEADER' stage selects the correct first decode stage.
Similarly the encode procedure also follows 2 different encoding procedures.
The first - taken on a 'READ_SERIALIZED_KEY' opcode - follows the write_wrapper procedure of the
KeyHolder(<TYPENAME>) Type.
The second - taken on a 'READ_KEY_HASH' opcode (if the key is not already calculated) - follows the
write_wrapper procedure of the <TYPENAME>KeyHolder[7] Type. Note that this encoding is in PLAIN_CDR2
Big Endian, meaning that types wich have an ALIGN_8 in PLAIN_CDR have a ALIGN_4 in PLAIN_CDR2.
Both encoding procedures share the same encode_stages, and the 'encode_stage_next' signal is
set depending on the 'opcode_latch' signal. On a 'READ_SERIALIZED_KEY' opcode the
'WRITE_PAYLOAD_HEADER' stage selects the first encode_stage, while on a 'READ_KEY_HASH' opcode the
'START_KEY_HASH_GENERATION' stage selects the first encode_stage.
Since the decode_stages are used to parse both <TOPIC> type data (normal Payloads) and <TOPIC>KeyHolder
type data (Serialized Key), some additional modification have to be done to the decode_stages.
The 'GET_PAYLAOD_HEADER' stage select decode_stage of the first declared member of the <TOPIC> type, while
the 'IDLE' stage (with opcode 'PUSH_SERIALIZED_KEY') selects the decode_stage of the first declared member
of the <TOPIC>KeyHolder type.
All decode_stages use the 'opcode_latch' signal to determine the next decode_stage. When 'opcode_latch'
is 'PUSH_SERIALIZED_KEY', the <TOPIC>KeyHolder type declaration order is followed, else the <TOPIC> type
declaration order.
PITFALLS
########
* Make sure to initialize the 'cnt' signal to zero before calling a decode_stage/encode_stage with sub-stages
* Keep in mind the ALIGN difference between PLAIN_CDR and PLAIN_CDR2
* Note that the order of the <TYPENAME>KeyHolder[7] members is in ascending member ID and may not be the same as KeyHolder(<TYPENAME>)[6]
[1] DDS_XTYPES v1.3, 7.4.3.1
[2] DDS_XTYPES v1.3, 7.4.1.1.1
[3] DDS_XTYPES v1.3, 7.4.1.1.3
[4] DDS_XTYPES v1.3, 7.4.1.1.4
[5] DDS_XTYPES v1.3, 7.4.1.1.5.2
[6] DDS_XTYPES v1.3, 7.6.8
[6] DDS_XTYPES v1.3, 7.2.2.4.7
[7] DDS_XTYPES v1.3, 7.6.8

View File

@ -7,7 +7,6 @@ use ieee.numeric_std.all;
use work.rtps_package.all;
use work.rtps_config_package.all;
use work.Type2_package.all;
architecture TYPENAME of key_holder is
@ -32,7 +31,7 @@ architecture TYPENAME of key_holder is
--*****TYPE DECLARATION*****
-- FSM states. Explained below in detail
type STAGE_TYPE is (IDLE,START_KEY_HASH_GENERATION,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD,PUSH,ALIGN_OUT_STREAM,SERIALIZE_KEY,GET_KEY_HASH,PUSH_KEY_HASH);
type STAGE_TYPE is (IDLE,START_KEY_HASH_GENERATION,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD, WRITE_PAYLOAD_HEADER, PUSH,ALIGN_OUT_STREAM,ENCODE_PAYLOAD,GET_KEY_HASH,PUSH_KEY_HASH);
-- ###GENERATED START###
type DECODE_STAGE_TYPE is (GET_OPTIONAL_HEADER, TODO);
type ENCODE_STAGE_TYPE is (TODO);
@ -54,7 +53,7 @@ architecture TYPENAME of key_holder is
signal opcode_latch, opcode_latch_next : KEY_HOLDER_OPCODE_TYPE;
signal cnt_2, cnt_2_next : natural range 0 to (WORD_WIDTH/BYTE_WIDTH)-1;
signal align_op, align_op_next : std_logic;
signal finalize_payload, finalize_payload_next : std_logic
signal finalize_payload, finalize_payload_next : std_logic;
signal ready_in_sig : std_logic;
signal start_kh, ack_kh, done_kh : std_logic;
signal data_in_kh : std_logic_vector(BYTE_WIDTH-1 downto 0);
@ -153,15 +152,9 @@ begin
key_hash_next <= KEY_HASH_NIL;
when PUSH_SERIALIZED_KEY =>
ack <= '1';
-- Serialized Key is in PLAIN_CDR2 Big Endian encoding
endian_flag_next <= '0';
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
-- ###GENERATED START###
decode_stage_next <= TODO;
-- ###GENERATED END###
stage_next <= GET_PAYLOAD_HEADER;
-- Reset
key_hash_next <= KEY_HASH_NIL;
when READ_KEY_HASH =>
ack <= '1';
-- Key Hash not calculated
@ -173,13 +166,8 @@ begin
end if;
when READ_SERIALIZED_KEY =>
ack <= '1';
stage_next <= SERIALIZE_KEY;
-- Alignment Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= TODO;
-- ###GENERATED END###
endian_flag_next <= LITTLE_ENDIAN;
stage_next <= WRITE_PAYLOAD_HEADER;
when others =>
null;
end case;
@ -187,11 +175,17 @@ begin
when START_KEY_HASH_GENERATION =>
start_kh <= '1';
-- <TYPENAME>KeyHolder is in PLAIN_CDR2 Big Endian encoding (see 7.6.8 DDS_XTYPES v1.3)
endian_flag_next <= '0';
-- Alignment Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
if (ack_kh = '1') then
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
-- ###GENERATED START###
encode_stage_next <= TODO;
-- ###GENERATED END###
-- ###GENERATED START###
end if;
when GET_PAYLOAD_HEADER =>
-- TODO: Latch Offset from Options Field?
@ -205,17 +199,31 @@ begin
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
if (opcode_latch = PUSH_DATA) then
-- ###GENERATED START###
decode_stage_next <= TODO;
-- ###GENERATED END###
else --(opcode_latch = PUSH_SERIALIZED_KEY)
assert(opcode_latch = PUSH_SERIALIZED_KEY) severity FAILURE;
-- ###GENERATED START###
decode_stage_next <= TODO;
-- ###GENERATED END###
end if;
when CDR_LE =>
endian_flag_next <= '1';
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
if (opcode_latch = PUSH_DATA) then
-- ###GENERATED START###
decode_stage_next <= TODO;
-- ###GENERATED END###
else --(opcode_latch = PUSH_SERIALIZED_KEY)
assert(opcode_latch = PUSH_SERIALIZED_KEY) severity FAILURE;
-- ###GENERATED START###
decode_stage_next <= TODO;
-- ###GENERATED END###
end if;
when others =>
-- Unknown Payload Encoding
stage_next <= SKIP_PAYLOAD;
@ -316,6 +324,23 @@ begin
when others =>
null;
end case;
when WRITE_PAYLOAD_HEADER =>
valid_out <= '1';
if (LITTLE_ENDIAN = '0') then
data_out <= CDR_BE & x"0000";
else
data_out <= CDR_LE & x"0000";
end if;
-- Output Guard
if (ready_out = '1') then
stage_next <= ENCODE_PAYLOAD;
-- Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= TODO;
-- ###GENERATED END###
end if;
when PUSH =>
-- Push to Key Hash Generator
if (opcode_latch = READ_KEY_HASH) then
@ -343,13 +368,14 @@ begin
-- Reset
finalize_payload_next <= '0';
else
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
end if;
else
cnt_2_next <= cnt_2 + 1;
end if;
end if;
else
else -- (opcode_latch = READ_SERIALIZED_KEY)
assert(opcode_latch = READ_SERIALIZED_KEY) severity FAILURE;
-- Mark Last Word
if (finalize_payload = '1') then
last_word_out <= '1';
@ -371,7 +397,7 @@ begin
finalize_payload_next <= '0';
stage_next <= IDLE;
else
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
end if;
end if;
end if;
@ -379,7 +405,7 @@ begin
-- Target Stream Alignment reached
if (check_align(align_offset, target_align)) then
-- DONE
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
else
align_offset_next <= align_offset + 1;
-- Need to push Word
@ -388,12 +414,11 @@ begin
stage_next <= PUSH;
end if;
end if;
when SERIALIZE_KEY =>
when ENCODE_PAYLOAD =>
case (encode_stage) is
-- ###GENERATED START###
when TODO =>
-- ###GENERATED END###
when others =>
end case;
when GET_KEY_HASH =>
if (done_kh = '1') then

View File

@ -165,15 +165,22 @@ begin
-- ###GENERATED END###
end if;
when WRITE_PAYLOAD_HEADER =>
valid_out_dds <= '1';
if (LITTLE_ENDIAN = '0') then
data_out_latch_next <= CDR_BE & x"0000";
data_out_dds <= CDR_BE & x"0000";
else
data_out_latch_next <= CDR_LE & x"0000";
data_out_dds <= CDR_LE & x"0000";
end if;
stage_next <= PUSH;
-- Output Guard
if (ready_out_dds = '1') then
stage_next <= ENCODE_PAYLOAD;
-- Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= TODO;
-- ###GENERATED END###
end if;
when PUSH =>
-- Mark Last Word
if (finalize_payload = '1') then

View File

@ -65,8 +65,9 @@
* What happens if we get a sample with a source timestamp earlier than the last sample that was accessed by the DataReader when using DESTINATION ORDER BY_SOURCE_TIMESTAMP? Is the sample dropped?
* The spec does not define the serialized Key (KEY=1 DATA MESSAGE)
- fast-rtps assumes it is the Key Hash
- opendds sends Payload Encapsulation with a Key Holder Object (As defined in XType 7.6.8)
- opensplice seems to do the same as opendds
- opendds sends a full Payload (including Payload Header) containing a KeyHolder(Type) (Option a in https://issues.omg.org/issues/DDSXTY14-38)
- opensplice does same as opendds
- CycloneDDS does same as opendds
* Assert Heartbeat period > Heartbeat Suppression Period
* Can I request (NACK) SNs that were NOT announced by the writer (> last_sn in Heartbeat)?
* Does AUTOMATIC Liveliness QoS also update the lease on write/assert_liveliness operations?

View File

@ -12,9 +12,9 @@ use work.rtps_test_package.all;
use work.Type2_package.all;
-- This testbench tests the KEY_HOLDER commands of TYPE1.
-- It uses the writer_wrapper to send a valid TYPE2 payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- It uses the writer_wrapper to send a valid payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- Then the reference serialized key is pushed (resetting the internaly generated key hash), and the serialized key and key hash are re-read and compared (The key hash is compared to the previosuly compared).
-- The TYPE2 payload is sent in Big Endian.
-- The payload is sent in Big Endian.
entity L1_Type1_key_holder_test1 is
end entity;
@ -97,6 +97,7 @@ begin
variable RV : RandomPType;
variable align_offset : unsigned(MAX_ALIGN_OFFSET_WIDTH-1 downto 0) := (others => '0');
variable SK, KH : AlertLogIDType;
constant SERIALIZED_KEY_HEADER : std_logic_vector(WORD_WIDTH-1 downto 0) := CDR_BE & x"0000";
procedure wait_on_sig(signal sig : std_logic) is
begin
@ -132,6 +133,11 @@ begin
wait until rising_edge(clk);
reset <= '0';
-- Serialized Key Payload Header
gen_CDR(SERIALIZED_KEY_HEADER, ALIGN_4, align_offset, serialized_key);
-- Reset Alignement
align_offset := (others => '0');
Log("Setting Data in Writer Side", INFO);
-- Static
id_in <= RV.RandSlv(id_in'length);
@ -258,13 +264,13 @@ begin
sk_prc : process(all)
variable cnt : natural := 0;
begin
if rising_edge(clk) then
valid_sk <= '1';
data_sk <= serialized_key.data(cnt);
if (cnt = serialized_key.length-1) then
last_word_sk <= '1';
end if;
if rising_edge(clk) then
if (ready_sk = '1') then
if (cnt = serialized_key.length-1) then
cnt := 0;

View File

@ -12,9 +12,9 @@ use work.rtps_test_package.all;
use work.Type2_package.all;
-- This testbench tests the KEY_HOLDER commands of TYPE1.
-- It uses the writer_wrapper to send a valid TYPE2 payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- It uses the writer_wrapper to send a valid payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- Then the reference serialized key is pushed (resetting the internaly generated key hash), and the serialized key and key hash are re-read and compared (The key hash is compared to the previosuly compared).
-- The TYPE2 payload is sent in Little Endian.
-- The payload is sent in Little Endian.
entity L1_Type1_key_holder_test2 is
end entity;
@ -77,6 +77,9 @@ begin
);
uut : entity work.key_holder(TYPE1)
generic map (
LITTLE_ENDIAN => '1'
)
port map (
clk => clk,
reset => reset,
@ -100,6 +103,7 @@ begin
variable RV : RandomPType;
variable align_offset : unsigned(MAX_ALIGN_OFFSET_WIDTH-1 downto 0) := (others => '0');
variable SK, KH : AlertLogIDType;
constant SERIALIZED_KEY_HEADER : std_logic_vector(WORD_WIDTH-1 downto 0) := CDR_LE & x"0000";
procedure wait_on_sig(signal sig : std_logic) is
begin
@ -135,12 +139,17 @@ begin
wait until rising_edge(clk);
reset <= '0';
-- Serialized Key Payload Header
gen_CDR(SERIALIZED_KEY_HEADER, ALIGN_4, align_offset, serialized_key);
-- Reset Alignement
align_offset := (others => '0');
Log("Setting Data in Writer Side", INFO);
-- Static
id_in <= RV.RandSlv(id_in'length);
a_in <= RV.RandSlv(a_in'length);
wait for 0 ns;
gen_CDR(id_in, ALIGN_4, align_offset, serialized_key);
gen_CDR(endian_swap('1',id_in), ALIGN_4, align_offset, serialized_key);
-- Finalize Serialized Key
if (align_offset(1 downto 0) /= "00") then
@ -261,13 +270,13 @@ begin
sk_prc : process(all)
variable cnt : natural := 0;
begin
if rising_edge(clk) then
valid_sk <= '1';
data_sk <= serialized_key.data(cnt);
if (cnt = serialized_key.length-1) then
last_word_sk <= '1';
end if;
if rising_edge(clk) then
if (ready_sk = '1') then
if (cnt = serialized_key.length-1) then
cnt := 0;

View File

@ -12,9 +12,9 @@ use work.rtps_test_package.all;
use work.Type2_package.all;
-- This testbench tests the KEY_HOLDER commands of TYPE2.
-- It uses the writer_wrapper to send a valid TYPE2 payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- It uses the writer_wrapper to send a valid payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- Then the reference serialized key is pushed (resetting the internaly generated key hash), and the serialized key and key hash are re-read and compared (The key hash is compared to the previosuly compared).
-- The TYPE2 payload is sent in Big Endian.
-- The payload is sent in Big Endian.
entity L1_Type2_key_holder_test1 is
end entity;
@ -169,6 +169,7 @@ begin
variable RV : RandomPType;
variable align_offset : unsigned(MAX_ALIGN_OFFSET_WIDTH-1 downto 0) := (others => '0');
variable SK, KH : AlertLogIDType;
constant SERIALIZED_KEY_HEADER : std_logic_vector(WORD_WIDTH-1 downto 0) := CDR_BE & x"0000";
procedure wait_on_sig(signal sig : std_logic) is
begin
@ -204,6 +205,11 @@ begin
wait until rising_edge(clk);
reset <= '0';
-- Serialized Key Payload Header
gen_CDR(SERIALIZED_KEY_HEADER, ALIGN_4, align_offset, serialized_key);
-- Reset Alignement
align_offset := (others => '0');
Log("Setting Data in Writer Side", INFO);
-- Static
id_in <= RV.RandSlv(id_in'length);
@ -381,13 +387,13 @@ begin
sk_prc : process(all)
variable cnt : natural := 0;
begin
if rising_edge(clk) then
valid_sk <= '1';
data_sk <= serialized_key.data(cnt);
if (cnt = serialized_key.length-1) then
last_word_sk <= '1';
end if;
if rising_edge(clk) then
if (ready_sk = '1') then
if (cnt = serialized_key.length-1) then
cnt := 0;

View File

@ -12,9 +12,9 @@ use work.rtps_test_package.all;
use work.Type2_package.all;
-- This testbench tests the KEY_HOLDER commands of TYPE2.
-- It uses the writer_wrapper to send a valid TYPE2 payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- It uses the writer_wrapper to send a valid payload, then reads the serialized key and the key hash. The returned serialized key is compared to a "handcrafted" reference, and the key hash is latched for later comparison.
-- Then the reference serialized key is pushed (resetting the internaly generated key hash), and the serialized key and key hash are re-read and compared (The key hash is compared to the previosuly compared).
-- The TYPE2 payload is sent in Little Endian.
-- The payload is sent in Little Endian.
entity L1_Type2_key_holder_test2 is
end entity;
@ -149,6 +149,9 @@ begin
);
uut : entity work.key_holder(TYPE2)
generic map (
LITTLE_ENDIAN => '1'
)
port map (
clk => clk,
reset => reset,
@ -172,6 +175,7 @@ begin
variable RV : RandomPType;
variable align_offset : unsigned(MAX_ALIGN_OFFSET_WIDTH-1 downto 0) := (others => '0');
variable SK, KH : AlertLogIDType;
constant SERIALIZED_KEY_HEADER : std_logic_vector(WORD_WIDTH-1 downto 0) := CDR_LE & x"0000";
procedure wait_on_sig(signal sig : std_logic) is
begin
@ -207,6 +211,11 @@ begin
wait until rising_edge(clk);
reset <= '0';
-- Serialized Key Payload Header
gen_CDR(SERIALIZED_KEY_HEADER, ALIGN_4, align_offset, serialized_key);
-- Reset Alignement
align_offset := (others => '0');
Log("Setting Data in Writer Side", INFO);
-- Static
id_in <= RV.RandSlv(id_in'length);
@ -217,10 +226,10 @@ begin
TestUnion_OctetU_in <= RV.RandSlv(TestUnion_OctetU_in'length);
TestBitmask_in <= RV.RandSlv(TestBitmask_in'length);
wait for 0 ns;
gen_CDR(id_in, ALIGN_4, align_offset, serialized_key);
gen_CDR(endian_swap('1',id_in), ALIGN_4, align_offset, serialized_key);
TestSequence_len_in <= int(2,TestSequence_len_in'length);
gen_CDR(int(2,CDR_LONG_WIDTH), ALIGN_4, align_offset, serialized_key);
gen_CDR(endian_swap('1',int(2,CDR_LONG_WIDTH)), ALIGN_4, align_offset, serialized_key);
-- Memory
for i in 0 to 1 loop
TestSequence_addr_in <= int(i,TestSequence_addr_in'length);
@ -236,7 +245,7 @@ begin
TestSequence_TestArray_wen_in <= '1';
wait until rising_edge(clk);
TestSequence_TestArray_wen_in <= '0';
gen_CDR(TestSequence_TestArray_w_in, ALIGN_1, align_offset, serialized_key);
gen_CDR(endian_swap('1',TestSequence_TestArray_w_in), ALIGN_1, align_offset, serialized_key);
end loop;
wait_on_sig(TestSequence_ready_in);
TestSequence_wen_in <= '1';
@ -384,13 +393,13 @@ begin
sk_prc : process(all)
variable cnt : natural := 0;
begin
if rising_edge(clk) then
valid_sk <= '1';
data_sk <= serialized_key.data(cnt);
if (cnt = serialized_key.length-1) then
last_word_sk <= '1';
end if;
if rising_edge(clk) then
if (ready_sk = '1') then
if (cnt = serialized_key.length-1) then
cnt := 0;

View File

@ -29,7 +29,7 @@ architecture TYPE1 of key_holder is
--*****TYPE DECLARATION*****
-- FSM states. Explained below in detail
type STAGE_TYPE is (IDLE,START_KEY_HASH_GENERATION,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD,PUSH,ALIGN_OUT_STREAM,SERIALIZE_KEY,GET_KEY_HASH,PUSH_KEY_HASH);
type STAGE_TYPE is (IDLE,START_KEY_HASH_GENERATION,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD, WRITE_PAYLOAD_HEADER, PUSH,ALIGN_OUT_STREAM,ENCODE_PAYLOAD,GET_KEY_HASH,PUSH_KEY_HASH);
-- ###GENERATED START###
type DECODE_STAGE_TYPE is (GET_OPTIONAL_HEADER, GET_ID);
type ENCODE_STAGE_TYPE is (WRITE_ID);
@ -145,15 +145,9 @@ begin
key_hash_next <= KEY_HASH_NIL;
when PUSH_SERIALIZED_KEY =>
ack <= '1';
-- Serialized Key is in PLAIN_CDR2 Big Endian encoding
endian_flag_next <= '0';
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
stage_next <= GET_PAYLOAD_HEADER;
-- Reset
key_hash_next <= KEY_HASH_NIL;
when READ_KEY_HASH =>
ack <= '1';
-- Key Hash not calculated
@ -165,13 +159,8 @@ begin
end if;
when READ_SERIALIZED_KEY =>
ack <= '1';
stage_next <= SERIALIZE_KEY;
-- Alignment Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED END###
endian_flag_next <= LITTLE_ENDIAN;
stage_next <= WRITE_PAYLOAD_HEADER;
when others =>
null;
end case;
@ -179,9 +168,17 @@ begin
when START_KEY_HASH_GENERATION =>
start_kh <= '1';
-- <TYPENAME>KeyHolder is in PLAIN_CDR2 Big Endian encoding (see 7.6.8 DDS_XTYPES v1.3)
endian_flag_next <= '0';
-- Alignment Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
if (ack_kh = '1') then
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED START###
end if;
when GET_PAYLOAD_HEADER =>
-- TODO: Latch Offset from Options Field?
@ -195,17 +192,31 @@ begin
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
if (opcode_latch = PUSH_DATA) then
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
else --(opcode_latch = PUSH_SERIALIZED_KEY)
assert(opcode_latch = PUSH_SERIALIZED_KEY) severity FAILURE;
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
end if;
when CDR_LE =>
endian_flag_next <= '1';
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
if (opcode_latch = PUSH_DATA) then
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
else --(opcode_latch = PUSH_SERIALIZED_KEY)
assert(opcode_latch = PUSH_SERIALIZED_KEY) severity FAILURE;
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
end if;
when others =>
-- Unknown Payload Encoding
stage_next <= SKIP_PAYLOAD;
@ -317,6 +328,23 @@ begin
when others =>
null;
end case;
when WRITE_PAYLOAD_HEADER =>
valid_out <= '1';
if (LITTLE_ENDIAN = '0') then
data_out <= CDR_BE & x"0000";
else
data_out <= CDR_LE & x"0000";
end if;
-- Output Guard
if (ready_out = '1') then
stage_next <= ENCODE_PAYLOAD;
-- Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED END###
end if;
when PUSH =>
-- Push to Key Hash Generator
if (opcode_latch = READ_KEY_HASH) then
@ -344,13 +372,14 @@ begin
-- Reset
finalize_payload_next <= '0';
else
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
end if;
else
cnt_2_next <= cnt_2 + 1;
end if;
end if;
else
else -- (opcode_latch = READ_SERIALIZED_KEY)
assert(opcode_latch = READ_SERIALIZED_KEY) severity FAILURE;
-- Mark Last Word
if (finalize_payload = '1') then
last_word_out <= '1';
@ -372,7 +401,7 @@ begin
finalize_payload_next <= '0';
stage_next <= IDLE;
else
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
end if;
end if;
end if;
@ -380,7 +409,7 @@ begin
-- Target Stream Alignment reached
if (check_align(align_offset, target_align)) then
-- DONE
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
else
align_offset_next <= align_offset + 1;
-- Need to push Word
@ -389,7 +418,7 @@ begin
stage_next <= PUSH;
end if;
end if;
when SERIALIZE_KEY =>
when ENCODE_PAYLOAD =>
case (encode_stage) is
-- ###GENERATED START###
when WRITE_ID =>
@ -398,7 +427,7 @@ begin
target_align_next <= ALIGN_4;
stage_next <= ALIGN_OUT_STREAM;
else
data_out_latch_next <= id_latch;
data_out_latch_next <= endian_swap(endian_flag, id_latch);
align_offset_next <= align_offset + 4;
-- DONE
stage_next <= PUSH;

View File

@ -147,15 +147,22 @@ begin
null;
end if;
when WRITE_PAYLOAD_HEADER =>
valid_out_dds <= '1';
if (LITTLE_ENDIAN = '0') then
data_out_latch_next <= CDR_BE & x"0000";
data_out_dds <= CDR_BE & x"0000";
else
data_out_latch_next <= CDR_LE & x"0000";
data_out_dds <= CDR_LE & x"0000";
end if;
stage_next <= PUSH;
-- Output Guard
if (ready_out_dds = '1') then
stage_next <= ENCODE_PAYLOAD;
-- Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED END###
end if;
when PUSH =>
-- Mark Last Word
if (finalize_payload = '1') then

View File

@ -29,7 +29,7 @@ architecture TYPE2 of key_holder is
--*****TYPE DECLARATION*****
-- FSM states. Explained below in detail
type STAGE_TYPE is (IDLE,START_KEY_HASH_GENERATION,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD,PUSH,ALIGN_OUT_STREAM,SERIALIZE_KEY,GET_KEY_HASH,PUSH_KEY_HASH);
type STAGE_TYPE is (IDLE,START_KEY_HASH_GENERATION,GET_PAYLOAD_HEADER,FETCH,ALIGN_IN_STREAM,SKIP_PAYLOAD,DECODE_PAYLOAD, WRITE_PAYLOAD_HEADER, PUSH,ALIGN_OUT_STREAM,ENCODE_PAYLOAD,GET_KEY_HASH,PUSH_KEY_HASH);
-- ###GENERATED START###
type DECODE_STAGE_TYPE is (GET_ID,GET_TESTSEQUENCE_LENGTH,GET_TESTSEQUENCE_TESTARRAY,GET_TESTSEQUENCE_TESTCHAR,GET_TESTSEQUENCE_TESTWCHAR,GET_TESTSEQUENCE_TESTLONGLONG,GET_TESTSEQUENCE_TESTLONGDOUBLE,TESTSEQUENCE_MEMBER_END,GET_OPTIONAL_HEADER);
type ENCODE_STAGE_TYPE is (WRITE_ID,WRITE_TESTSEQUENCE_LENGTH,WRITE_TESTSEQUENCE_TESTARRAY,TESTSEQUENCE_MEMBER_END);
@ -189,15 +189,9 @@ begin
key_hash_next <= KEY_HASH_NIL;
when PUSH_SERIALIZED_KEY =>
ack <= '1';
-- Serialized Key is in PLAIN_CDR2 Big Endian encoding
endian_flag_next <= '0';
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
stage_next <= GET_PAYLOAD_HEADER;
-- Reset
key_hash_next <= KEY_HASH_NIL;
when READ_KEY_HASH =>
ack <= '1';
-- Key Hash not calculated
@ -209,13 +203,8 @@ begin
end if;
when READ_SERIALIZED_KEY =>
ack <= '1';
stage_next <= SERIALIZE_KEY;
-- Alignment Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED END###
endian_flag_next <= LITTLE_ENDIAN;
stage_next <= WRITE_PAYLOAD_HEADER;
when others =>
null;
end case;
@ -223,9 +212,17 @@ begin
when START_KEY_HASH_GENERATION =>
start_kh <= '1';
-- <TYPENAME>KeyHolder is in PLAIN_CDR2 Big Endian encoding (see 7.6.8 DDS_XTYPES v1.3)
endian_flag_next <= '0';
-- Alignment Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
if (ack_kh = '1') then
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED START###
end if;
when GET_PAYLOAD_HEADER =>
-- TODO: Latch Offset from Options Field?
@ -239,17 +236,31 @@ begin
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
if (opcode_latch = PUSH_DATA) then
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
else --(opcode_latch = PUSH_SERIALIZED_KEY)
assert(opcode_latch = PUSH_SERIALIZED_KEY) severity FAILURE;
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
end if;
when CDR_LE =>
endian_flag_next <= '1';
stage_next <= FETCH;
-- Alignment Reset
align_offset_next <= (others => '0');
if (opcode_latch = PUSH_DATA) then
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
else --(opcode_latch = PUSH_SERIALIZED_KEY)
assert(opcode_latch = PUSH_SERIALIZED_KEY) severity FAILURE;
-- ###GENERATED START###
decode_stage_next <= GET_ID;
-- ###GENERATED END###
end if;
when others =>
-- Unknown Payload Encoding
stage_next <= SKIP_PAYLOAD;
@ -293,8 +304,8 @@ begin
last_word_in_latch_next <= '0';
end if;
when DECODE_PAYLOAD =>
-- ###GENERATED START###
case (decode_stage) is
-- ###GENERATED START###
when GET_ID =>
-- ALIGN GUARD
-- DES: If ALIGN_8 is used, we have to to check the latched opcode and use ALIGN_4 if PUSH_SERIALIZED_KEY (since it uses PLAIN_CDR2 encoding)
@ -463,6 +474,7 @@ begin
decode_stage_next <= GET_TESTSEQUENCE_TESTARRAY;
TestSequence_TestArray_cnt_next <= 0;
end if;
-- ###GENERATED END###
when GET_OPTIONAL_HEADER =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_4)) then
@ -516,7 +528,23 @@ begin
when others =>
null;
end case;
when WRITE_PAYLOAD_HEADER =>
valid_out <= '1';
if (LITTLE_ENDIAN = '0') then
data_out <= CDR_BE & x"0000";
else
data_out <= CDR_LE & x"0000";
end if;
-- Output Guard
if (ready_out = '1') then
stage_next <= ENCODE_PAYLOAD;
-- Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED END###
end if;
when PUSH =>
-- Push to Key Hash Generator
if (opcode_latch = READ_KEY_HASH) then
@ -544,13 +572,14 @@ begin
-- Reset
finalize_payload_next <= '0';
else
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
end if;
else
cnt_2_next <= cnt_2 + 1;
end if;
end if;
else
else -- (opcode_latch = READ_SERIALIZED_KEY)
assert(opcode_latch = READ_SERIALIZED_KEY) severity FAILURE;
-- Mark Last Word
if (finalize_payload = '1') then
last_word_out <= '1';
@ -572,7 +601,7 @@ begin
finalize_payload_next <= '0';
stage_next <= IDLE;
else
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
end if;
end if;
end if;
@ -580,7 +609,7 @@ begin
-- Target Stream Alignment reached
if (check_align(align_offset, target_align)) then
-- DONE
stage_next <= SERIALIZE_KEY;
stage_next <= ENCODE_PAYLOAD;
else
align_offset_next <= align_offset + 1;
-- Need to push Word
@ -589,16 +618,16 @@ begin
stage_next <= PUSH;
end if;
end if;
when SERIALIZE_KEY =>
-- ###GENERATED START###
when ENCODE_PAYLOAD =>
case (encode_stage) is
-- ###GENERATED START###
when WRITE_ID =>
-- ALIGN GUARD
if (not check_align(align_offset, ALIGN_4)) then
target_align_next <= ALIGN_4;
stage_next <= ALIGN_OUT_STREAM;
else
data_out_latch_next <= id_latch;
data_out_latch_next <= endian_swap(endian_flag, id_latch);
align_offset_next <= align_offset + 4;
stage_next <= PUSH;
-- Next Member
@ -610,7 +639,7 @@ begin
target_align_next <= ALIGN_4;
stage_next <= ALIGN_OUT_STREAM;
else
data_out_latch_next <= std_logic_vector(resize(TestSequence_len_latch,WORD_WIDTH));
data_out_latch_next <= endian_swap(endian_flag, std_logic_vector(resize(TestSequence_len_latch,WORD_WIDTH)));
align_offset_next <= align_offset + 4;
stage_next <= PUSH;
@ -648,7 +677,7 @@ begin
TestSequence_TestArray_mem_ready_out(TestSequence_cnt) <= '1';
-- Memory Operation Guard
if (TestSequence_TestArray_mem_valid_out(TestSequence_cnt) = '1') then
data_out_latch_next <= write_sub_vector(data_out_latch, TestSequence_TestArray_mem_data_out(TestSequence_cnt), to_integer(align_offset(1 downto 0)), TRUE);
data_out_latch_next <= write_sub_vector(data_out_latch, endian_swap(endian_flag,TestSequence_TestArray_mem_data_out(TestSequence_cnt)), to_integer(align_offset(1 downto 0)), TRUE);
align_offset_next <= align_offset + 1;
cnt_next <= 0;
@ -681,8 +710,8 @@ begin
TestSequence_TestArray_cnt_next <= 0;
cnt_next <= 0;
end if;
end case;
-- ###GENERATED END###
end case;
when GET_KEY_HASH =>
if (done_kh = '1') then
key_hash_next <= to_key_hash(key_hash_kh);

View File

@ -510,15 +510,22 @@ begin
-- ###GENERATED END###
end if;
when WRITE_PAYLOAD_HEADER =>
valid_out_dds <= '1';
if (LITTLE_ENDIAN = '0') then
data_out_latch_next <= CDR_BE & x"0000";
data_out_dds <= CDR_BE & x"0000";
else
data_out_latch_next <= CDR_LE & x"0000";
data_out_dds <= CDR_LE & x"0000";
end if;
stage_next <= PUSH;
-- Output Guard
if (ready_out_dds = '1') then
stage_next <= ENCODE_PAYLOAD;
-- Reset
align_offset_next <= (others => '0');
data_out_latch_next <= (others => '0');
-- ###GENERATED START###
encode_stage_next <= WRITE_ID;
-- ###GENERATED END###
end if;
when PUSH =>
-- Mark Last Word
if (finalize_payload = '1') then

View File

@ -9,6 +9,9 @@ use work.rtps_package.all;
use work.rtps_config_package.all;
entity key_holder is
generic (
LITTLE_ENDIAN : std_logic := '0'
);
port (
-- SYSTEM
clk : in std_logic;