Browse Source

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)
pull/1/head
T. Meissner 9 years ago
parent
commit
4b97da49fb
2 changed files with 144 additions and 55 deletions
  1. +84
    -42
      sim/DictP.vhd
  2. +60
    -13
      test/DictT.vhd

+ 84
- 42
sim/DictP.vhd View File

@ -6,15 +6,23 @@ library ieee;
package DictP is 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 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 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 hasKey (key : string) return boolean;
impure function size return natural; impure function size return natural;
procedure setFirst;
procedure setLast;
impure function iter (dir : t_dict_dir := UP) return string;
end protected t_dict; end protected t_dict;
@ -32,54 +40,61 @@ package body DictP is
type t_entry; type t_entry;
type t_entry_ptr is access 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_data_ptr is access std_logic_vector;
type t_entry is record type t_entry is record
key : t_key_ptr;
key : t_dict_key_ptr;
data : t_data_ptr; data : t_data_ptr;
last_entry : t_entry_ptr; last_entry : t_entry_ptr;
next_entry : t_entry_ptr; next_entry : t_entry_ptr;
end record t_entry; end record t_entry;
variable v_begin : t_entry_ptr := null;
variable v_head : 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_size : natural := 0;
variable v_logging : boolean := false; variable v_logging : boolean := false;
impure function find (key : string) return t_entry_ptr; 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); variable v_entry : t_entry_ptr := find(key);
begin 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 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; end if;
err := NO_ERROR;
end if; end if;
end procedure set; 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); variable v_entry : t_entry_ptr := find(key);
begin begin
if(v_entry /= null) then if(v_entry /= null) then
@ -87,13 +102,13 @@ package body DictP is
if v_logging then if v_logging then
report t_dict'instance_name & ": Got key " & key & " with data 0x" & to_hstring(v_entry.data.all); report t_dict'instance_name & ": Got key " & key & " with data 0x" & to_hstring(v_entry.data.all);
end if; end if;
err := false;
err := NO_ERROR;
else else
err := true;
err := KEY_NOT_FOUND;
end if; end if;
end procedure get; 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); variable v_entry : t_entry_ptr := find(key);
begin begin
if (v_entry /= null) then if (v_entry /= null) then
@ -104,7 +119,8 @@ package body DictP is
-- remove start entry -- remove start entry
elsif(v_entry.next_entry /= null and v_entry.last_entry = null) then 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 := 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 -- remove from between
elsif(v_entry.next_entry /= null and v_entry.last_entry /= null) then elsif(v_entry.next_entry /= null and v_entry.last_entry /= null) then
v_entry.last_entry.next_entry := v_entry.next_entry; 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.data);
deallocate(v_entry); deallocate(v_entry);
v_size := v_size - 1; v_size := v_size - 1;
err := false;
err := NO_ERROR;
else else
err := true;
err := KEY_NOT_FOUND;
end if; end if;
end procedure del; end procedure del;
@ -132,22 +148,22 @@ package body DictP is
return null; return null;
end function find; 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 : t_entry_ptr := v_head;
variable v_entry_d : t_entry_ptr; variable v_entry_d : t_entry_ptr;
variable v_err : boolean;
variable v_err : t_dict_error;
begin begin
err := false;
while (v_entry /= null) loop while (v_entry /= null) loop
v_entry_d := v_entry; v_entry_d := v_entry;
del(v_entry_d.key.all, v_err); del(v_entry_d.key.all, v_err);
if v_err then
err := true;
if (v_err /= NO_ERROR) then
err := v_err;
return; return;
else else
v_entry := v_entry.last_entry; v_entry := v_entry.last_entry;
end if; end if;
end loop; end loop;
err := NO_ERROR;
end procedure clear; end procedure clear;
impure function hasKey (key : string) return boolean is impure function hasKey (key : string) return boolean is
@ -165,6 +181,32 @@ package body DictP is
v_logging := logging; v_logging := logging;
end procedure init; 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; end protected body t_dict;


+ 60
- 13
test/DictT.vhd View File

@ -42,12 +42,12 @@ begin
DictTestP : process is DictTestP : process is
variable v_key : string(1 to 4);
variable v_key : t_dict_key_ptr;
variable v_random : RandomPType; variable v_random : RandomPType;
variable v_input : std_logic_vector(7 downto 0); variable v_input : std_logic_vector(7 downto 0);
variable v_output : 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_scoreboard : t_scoreboard(0 to 256);
variable v_error : boolean;
variable v_error : t_dict_error;
begin begin
v_random.InitSeed(v_random'instance_name); v_random.InitSeed(v_random'instance_name);
@ -56,11 +56,19 @@ begin
report "ERROR: Dict should be empty" report "ERROR: Dict should be empty"
severity failure; 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 -- fill dictionary and check count
report "INFO: Test 0: Fill dictionary";
report "INFO: Test 1: Fill dictionary";
for i in 0 to 255 loop for i in 0 to 255 loop
v_input := v_random.RandSlv(8); 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; v_scoreboard(i) := v_input;
assert sv_dict.size = i+1 assert sv_dict.size = i+1
report "ERROR: Dict should have " & to_string(i+1) & " entries" report "ERROR: Dict should have " & to_string(i+1) & " entries"
@ -69,7 +77,7 @@ begin
report "INFO: Test successful"; report "INFO: Test successful";
-- read all entries and check for correct data -- 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 for i in 0 to 255 loop
sv_dict.get(integer'image(i), v_output, v_error); sv_dict.get(integer'image(i), v_output, v_error);
assert v_output = v_scoreboard(i) assert v_output = v_scoreboard(i)
@ -79,9 +87,9 @@ begin
report "INFO: Test successful"; report "INFO: Test successful";
-- overwrite a key/value pair -- 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); 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; v_scoreboard(128) := v_input;
sv_dict.get("128", v_output, v_error); sv_dict.get("128", v_output, v_error);
assert v_output = v_scoreboard(128) assert v_output = v_scoreboard(128)
@ -89,8 +97,8 @@ begin
severity failure; severity failure;
report "INFO: Test successful"; 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 for i in 0 to 255 loop
assert sv_dict.hasKey(integer'image(i)) assert sv_dict.hasKey(integer'image(i))
report "ERROR: Key" & integer'image(i) & " should exist in dictionary" report "ERROR: Key" & integer'image(i) & " should exist in dictionary"
@ -101,8 +109,47 @@ begin
severity failure; severity failure;
report "INFO: Test successful"; 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 -- 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); sv_dict.del("255", v_error);
assert not(sv_dict.hasKey("255")) assert not(sv_dict.hasKey("255"))
report "ERROR: Key 255 shouldn't exist in dictionary" report "ERROR: Key 255 shouldn't exist in dictionary"
@ -110,7 +157,7 @@ begin
report "INFO: Test successful"; report "INFO: Test successful";
-- Remove key/value pair from head of dictionary -- 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); sv_dict.del("127", v_error);
assert not(sv_dict.hasKey("127")) assert not(sv_dict.hasKey("127"))
report "ERROR: Key 127 shouldn't exist in dictionary" report "ERROR: Key 127 shouldn't exist in dictionary"
@ -118,7 +165,7 @@ begin
report "INFO: Test successful"; report "INFO: Test successful";
-- Remove key/value pair from head of dictionary -- 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); sv_dict.del("0", v_error);
assert not(sv_dict.hasKey("0")) assert not(sv_dict.hasKey("0"))
report "ERROR: Key 0 shouldn't exist in dictionary" report "ERROR: Key 0 shouldn't exist in dictionary"
@ -126,7 +173,7 @@ begin
report "INFO: Test successful"; report "INFO: Test successful";
-- Remove key/value pair from head of dictionary -- 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); sv_dict.clear(v_error);
assert sv_dict.size = 0 assert sv_dict.size = 0
report "ERROR: Dict should be empty" report "ERROR: Dict should be empty"


Loading…
Cancel
Save