From 4b97da49fb2b7588c197a38d6ab21f64c8b43773 Mon Sep 17 00:00:00 2001 From: tmeissner Date: Tue, 1 Sep 2015 00:00:07 +0200 Subject: [PATCH] Add new methods to iterate over keys stored in dictionary Three new methods to support iteration over the keys stored in the dictionary: * setFirst: set start of iterator to begin og dictionary * setLast: set start of iterator to end of dictionary * iter(dir): iterate over keys in dictionary in dir direction The key pointer type t_dict_key_ptr is now moved to the public part of the DictP package to support using in testbench code when saving the keys with different lengths from iter() function. Error return values are now of type t_dict_error with 3 possible values: (NO_ERROR, KEY_INVALID, KEY_NOT_FOUND) --- sim/DictP.vhd | 126 ++++++++++++++++++++++++++++++++----------------- test/DictT.vhd | 73 +++++++++++++++++++++++----- 2 files changed, 144 insertions(+), 55 deletions(-) diff --git a/sim/DictP.vhd b/sim/DictP.vhd index 026bf93..82a47c2 100644 --- a/sim/DictP.vhd +++ b/sim/DictP.vhd @@ -6,15 +6,23 @@ library ieee; package DictP is + type t_dict_dir is (UP, DOWN); + type t_dict_error is (NO_ERROR, KEY_INVALID, KEY_NOT_FOUND); + type t_dict_key_ptr is access string; + type t_dict is protected - procedure set (key : in string; data : in std_logic_vector); - procedure get (key : in string; data : out std_logic_vector; err : out boolean); - procedure del (key : in string; err : out boolean); + procedure set (key : in string; data : in std_logic_vector; err : out t_dict_error); + procedure get (key : in string; data : out std_logic_vector; err : out t_dict_error); + procedure del (key : in string; err : out t_dict_error); procedure init (logging : in boolean := false); - procedure clear (err : out boolean); + procedure clear (err : out t_dict_error); impure function hasKey (key : string) return boolean; impure function size return natural; + procedure setFirst; + procedure setLast; + impure function iter (dir : t_dict_dir := UP) return string; + end protected t_dict; @@ -32,54 +40,61 @@ package body DictP is type t_entry; type t_entry_ptr is access t_entry; - type t_key_ptr is access string; type t_data_ptr is access std_logic_vector; type t_entry is record - key : t_key_ptr; + key : t_dict_key_ptr; data : t_data_ptr; last_entry : t_entry_ptr; next_entry : t_entry_ptr; end record t_entry; + variable v_begin : t_entry_ptr := null; variable v_head : t_entry_ptr := null; + variable v_current : t_entry_ptr := null; variable v_size : natural := 0; variable v_logging : boolean := false; impure function find (key : string) return t_entry_ptr; - procedure set (key : in string; data : in std_logic_vector) is + procedure set (key : in string; data : in std_logic_vector; err : out t_dict_error) is variable v_entry : t_entry_ptr := find(key); begin - if (v_entry = null) then - if (v_head /= null) then - v_entry := new t_entry; - v_entry.key := new string'(key); - v_entry.data := new std_logic_vector'(data); - v_entry.last_entry := v_head; - v_entry.next_entry := null; - v_head := v_entry; - v_head.last_entry.next_entry := v_head; - else - v_head := new t_entry; - v_head.key := new string'(key); - v_head.data := new std_logic_vector'(data); - v_head.last_entry := null; - v_head.next_entry := null; - end if; - if (v_logging) then - report t_dict'instance_name & ": Add key " & key & " with data 0x" & to_hstring(data); - end if; - v_size := v_size + 1; + if (key = "") then + err := KEY_INVALID; else - v_entry.data.all := data; - if (v_logging) then - report t_dict'instance_name & ": Set key " & key & " to 0x" & to_hstring(data); + if (v_entry = null) then + if (v_head /= null) then + v_entry := new t_entry; + v_entry.key := new string'(key); + v_entry.data := new std_logic_vector'(data); + v_entry.last_entry := v_head; + v_entry.next_entry := null; + v_head := v_entry; + v_head.last_entry.next_entry := v_head; + else + v_head := new t_entry; + v_head.key := new string'(key); + v_head.data := new std_logic_vector'(data); + v_head.last_entry := null; + v_head.next_entry := null; + v_begin := v_head; + end if; + if (v_logging) then + report t_dict'instance_name & ": Add key " & key & " with data 0x" & to_hstring(data); + end if; + v_size := v_size + 1; + else + v_entry.data.all := data; + if (v_logging) then + report t_dict'instance_name & ": Set key " & key & " to 0x" & to_hstring(data); + end if; end if; + err := NO_ERROR; end if; end procedure set; - procedure get (key : in string; data : out std_logic_vector; err : out boolean) is + procedure get (key : in string; data : out std_logic_vector; err : out t_dict_error) is variable v_entry : t_entry_ptr := find(key); begin if(v_entry /= null) then @@ -87,13 +102,13 @@ package body DictP is if v_logging then report t_dict'instance_name & ": Got key " & key & " with data 0x" & to_hstring(v_entry.data.all); end if; - err := false; + err := NO_ERROR; else - err := true; + err := KEY_NOT_FOUND; end if; end procedure get; - procedure del (key : in string; err : out boolean) is + procedure del (key : in string; err : out t_dict_error) is variable v_entry : t_entry_ptr := find(key); begin if (v_entry /= null) then @@ -104,7 +119,8 @@ package body DictP is -- remove start entry elsif(v_entry.next_entry /= null and v_entry.last_entry = null) then v_entry.next_entry.last_entry := null; - v_entry.next_entry.last_entry := v_entry.last_entry; + --v_entry.next_entry.last_entry := v_entry.last_entry; + v_begin := v_entry.next_entry; -- remove from between elsif(v_entry.next_entry /= null and v_entry.last_entry /= null) then v_entry.last_entry.next_entry := v_entry.next_entry; @@ -114,9 +130,9 @@ package body DictP is deallocate(v_entry.data); deallocate(v_entry); v_size := v_size - 1; - err := false; + err := NO_ERROR; else - err := true; + err := KEY_NOT_FOUND; end if; end procedure del; @@ -132,22 +148,22 @@ package body DictP is return null; end function find; - procedure clear (err : out boolean) is + procedure clear (err : out t_dict_error) is variable v_entry : t_entry_ptr := v_head; variable v_entry_d : t_entry_ptr; - variable v_err : boolean; + variable v_err : t_dict_error; begin - err := false; while (v_entry /= null) loop v_entry_d := v_entry; del(v_entry_d.key.all, v_err); - if v_err then - err := true; + if (v_err /= NO_ERROR) then + err := v_err; return; else v_entry := v_entry.last_entry; end if; end loop; + err := NO_ERROR; end procedure clear; impure function hasKey (key : string) return boolean is @@ -165,6 +181,32 @@ package body DictP is v_logging := logging; end procedure init; + procedure setFirst is + begin + v_current := v_begin; + end procedure setFirst; + + procedure setLast is + begin + v_current := v_head; + end procedure setLast; + + impure function iter (dir : t_dict_dir := UP) return string is + variable v_key : t_dict_key_ptr := null; + begin + if (v_current /= null) then + v_key := new string'(v_current.key.all); + if (dir = UP) then + v_current := v_current.next_entry; + else + v_current := v_current.last_entry; + end if; + return v_key.all; + else + return ""; + end if; + end function iter; + end protected body t_dict; diff --git a/test/DictT.vhd b/test/DictT.vhd index 0195083..c9b4cd4 100644 --- a/test/DictT.vhd +++ b/test/DictT.vhd @@ -42,12 +42,12 @@ begin DictTestP : process is - variable v_key : string(1 to 4); + variable v_key : t_dict_key_ptr; variable v_random : RandomPType; variable v_input : std_logic_vector(7 downto 0); variable v_output : std_logic_vector(7 downto 0); variable v_scoreboard : t_scoreboard(0 to 256); - variable v_error : boolean; + variable v_error : t_dict_error; begin v_random.InitSeed(v_random'instance_name); @@ -56,11 +56,19 @@ begin report "ERROR: Dict should be empty" severity failure; + -- The dict shouldn_t accept an empty key string + report "INFO: Test 0: Try to set an entry with empty key string"; + sv_dict.set("", x"0123456789", v_error); + assert v_error = KEY_INVALID + report "ERROR: Key '' should raise a KEY_INVALID error" + severity failure; + report "INFO: Test successful"; + -- fill dictionary and check count - report "INFO: Test 0: Fill dictionary"; + report "INFO: Test 1: Fill dictionary"; for i in 0 to 255 loop v_input := v_random.RandSlv(8); - sv_dict.set(integer'image(i), v_input); + sv_dict.set(integer'image(i), v_input, v_error); v_scoreboard(i) := v_input; assert sv_dict.size = i+1 report "ERROR: Dict should have " & to_string(i+1) & " entries" @@ -69,7 +77,7 @@ begin report "INFO: Test successful"; -- read all entries and check for correct data - report "INFO: Test 1: Read dictionary"; + report "INFO: Test 2: Read dictionary"; for i in 0 to 255 loop sv_dict.get(integer'image(i), v_output, v_error); assert v_output = v_scoreboard(i) @@ -79,9 +87,9 @@ begin report "INFO: Test successful"; -- overwrite a key/value pair - report "INFO: Test 2: Overwrite a entry"; + report "INFO: Test 3: Overwrite a entry"; v_input := v_random.RandSlv(8); - sv_dict.set("128", v_input); + sv_dict.set("128", v_input, v_error); v_scoreboard(128) := v_input; sv_dict.get("128", v_output, v_error); assert v_output = v_scoreboard(128) @@ -89,8 +97,8 @@ begin severity failure; report "INFO: Test successful"; - -- overwrite a key/value pair - report "INFO: Test 3: Check hasKey() method"; + -- check for existing keys + report "INFO: Test 4: Check hasKey() method"; for i in 0 to 255 loop assert sv_dict.hasKey(integer'image(i)) report "ERROR: Key" & integer'image(i) & " should exist in dictionary" @@ -101,8 +109,47 @@ begin severity failure; report "INFO: Test successful"; + -- iterate up over all entries + report "INFO: Test 5: Iterate up over all entries"; + sv_dict.setFirst; + for i in 0 to 255 loop + v_key := new string'(sv_dict.iter(UP)); + assert v_key.all = integer'image(i) + report "ERROR: Got key " & v_key.all & ", expected " & integer'image(i) + severity failure; + sv_dict.get(v_key.all, v_output, v_error); + assert v_key.all = integer'image(i) and v_output = v_scoreboard(i) + report "ERROR: Got 0x" & to_hstring(v_output) & ", expected 0x" & to_hstring(v_scoreboard(i)) + severity failure; + end loop; + v_key := new string'(sv_dict.iter(UP)); + assert v_key.all = "" + report "ERROR: Got key " & v_key.all & ", expected empty key" + severity failure; + report "INFO: Test successful"; + + -- iterate down over all entries + report "INFO: Test 6: Iterate down over all entries"; + sv_dict.setLast; + for i in 255 downto 0 loop + v_key := new string'(sv_dict.iter(DOWN)); + assert v_key.all = integer'image(i) + report "ERROR: Got key " & v_key.all & ", expected " & integer'image(i) + severity failure; + sv_dict.get(v_key.all, v_output, v_error); + assert v_key.all = integer'image(i) and v_output = v_scoreboard(i) + report "ERROR: Got 0x" & to_hstring(v_output) & ", expected 0x" & to_hstring(v_scoreboard(i)) + severity failure; + end loop; + v_key := new string'(sv_dict.iter(DOWN)); + assert v_key.all = "" + report "ERROR: Got key " & v_key.all & ", expected empty key" + severity failure; + deallocate(v_key); + report "INFO: Test successful"; + -- Remove key/value pair from head of dictionary - report "INFO: Test 4: Removing entry from head of dictionary"; + report "INFO: Test 7: Removing entry from head of dictionary"; sv_dict.del("255", v_error); assert not(sv_dict.hasKey("255")) report "ERROR: Key 255 shouldn't exist in dictionary" @@ -110,7 +157,7 @@ begin report "INFO: Test successful"; -- Remove key/value pair from head of dictionary - report "INFO: Test 5: Removing entry from middle of dictionary"; + report "INFO: Test 8: Removing entry from middle of dictionary"; sv_dict.del("127", v_error); assert not(sv_dict.hasKey("127")) report "ERROR: Key 127 shouldn't exist in dictionary" @@ -118,7 +165,7 @@ begin report "INFO: Test successful"; -- Remove key/value pair from head of dictionary - report "INFO: Test 6: Removing entry from beginning of dictionary"; + report "INFO: Test 9: Removing entry from beginning of dictionary"; sv_dict.del("0", v_error); assert not(sv_dict.hasKey("0")) report "ERROR: Key 0 shouldn't exist in dictionary" @@ -126,7 +173,7 @@ begin report "INFO: Test successful"; -- Remove key/value pair from head of dictionary - report "INFO: Test 7: Clear all entries from dictionary"; + report "INFO: Test 10: Clear all entries from dictionary"; sv_dict.clear(v_error); assert sv_dict.size = 0 report "ERROR: Dict should be empty"