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"