Library of reusable VHDL components
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

259 lines
8.1 KiB

-- Copyright (c) 2014 - 2022 by Torsten Meissner
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- https://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
library ieee;
use ieee.std_logic_1164.all;
package DictP is
generic (
type KEY_TYPE;
type VALUE_TYPE;
function key_to_string(d : in KEY_TYPE) return string;
function value_to_string(d : in VALUE_TYPE) return string
);
type t_dict_key_ptr is access KEY_TYPE;
type t_dict_data_ptr is access VALUE_TYPE;
type t_dict_dir is (UP, DOWN);
type t_dict_iter is (TAIL, HEAD);
type t_dict is protected
procedure set (constant key : in KEY_TYPE; constant data : in VALUE_TYPE);
procedure get (constant key : in KEY_TYPE; data : out VALUE_TYPE);
procedure del (constant key : in KEY_TYPE);
procedure init (constant logging : in boolean := false);
procedure clear;
impure function hasKey (constant key : KEY_TYPE) return boolean;
impure function size return natural;
procedure setIter(constant start : in t_dict_iter := TAIL);
impure function iter (constant dir : t_dict_dir := UP) return KEY_TYPE;
impure function get (constant key : KEY_TYPE) return VALUE_TYPE;
end protected t_dict;
procedure merge(d0 : inout t_dict; d1 : inout t_dict; d : inout t_dict);
end package DictP;
package body DictP is
type t_dict is protected body
type t_entry;
type t_entry_ptr is access t_entry;
type t_entry is record
key : t_dict_key_ptr;
data : t_dict_data_ptr;
last_entry : t_entry_ptr;
next_entry : t_entry_ptr;
end record t_entry;
variable v_tail : t_entry_ptr := null;
variable v_head : t_entry_ptr := null;
variable v_iterator : t_entry_ptr := null;
variable v_size : natural := 0;
variable v_logging : boolean := false;
impure function find (constant key : KEY_TYPE) return t_entry_ptr;
procedure set (constant key : in KEY_TYPE; constant data : in VALUE_TYPE) 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 KEY_TYPE'(key);
v_entry.data := new VALUE_TYPE'(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 KEY_TYPE'(key);
v_head.data := new VALUE_TYPE'(data);
v_head.last_entry := null;
v_head.next_entry := null;
v_tail := v_head;
end if;
if (v_logging) then
report t_dict'instance_name & ": Add key " & key_to_string(key) & " with value " & value_to_string(data) & " to dictionary";
end if;
v_size := v_size + 1;
else
v_entry.data.all := data;
if (v_logging) then
report t_dict'instance_name & ": Set value of key " & key_to_string(key) & " to 0x" & value_to_string(data);
end if;
end if;
end procedure set;
procedure get (constant key : in KEY_TYPE; data : out VALUE_TYPE) is
variable v_entry : t_entry_ptr := find(key);
begin
assert v_entry /= null
report t_dict'instance_name & ": key " & key_to_string(key) & " not found"
severity failure;
if(v_entry /= null) then
data := v_entry.data.all;
if v_logging then
report t_dict'instance_name & ": Got key " & key_to_string(key) & " with value " & value_to_string(v_entry.data.all);
end if;
end if;
end procedure get;
procedure del (constant key : in KEY_TYPE) is
variable v_entry : t_entry_ptr := find(key);
begin
assert v_entry /= null
report t_dict'instance_name & ": key " & key_to_string(key) & " not found"
severity failure;
if (v_entry /= null) then
-- remove head entry
if(v_entry.next_entry = null and v_entry.last_entry /= null) then
v_entry.last_entry.next_entry := null;
v_head := v_entry.last_entry;
-- 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_tail := 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;
v_entry.next_entry.last_entry := v_entry.last_entry;
end if;
deallocate(v_entry.key);
deallocate(v_entry.data);
deallocate(v_entry);
v_size := v_size - 1;
end if;
end procedure del;
impure function find (constant key : KEY_TYPE) return t_entry_ptr is
variable v_entry : t_entry_ptr := v_head;
begin
while (v_entry /= null) loop
if(v_entry.key.all = key) then
return v_entry;
end if;
v_entry := v_entry.last_entry;
end loop;
return null;
end function find;
procedure clear is
variable v_entry : t_entry_ptr := v_head;
variable v_entry_d : t_entry_ptr;
begin
while (v_entry /= null) loop
v_entry_d := v_entry;
del(v_entry_d.key.all);
v_entry := v_entry.last_entry;
end loop;
end procedure clear;
impure function hasKey (constant key : KEY_TYPE) return boolean is
begin
return find(key) /= null;
end function hasKey;
impure function size return natural is
begin
return v_size;
end function size;
procedure init (constant logging : in boolean := false) is
begin
v_logging := logging;
end procedure init;
procedure setIter (constant start : in t_dict_iter := TAIL) is
begin
if (start = TAIL) then
v_iterator := v_tail;
else
v_iterator := v_head;
end if;
end procedure setIter;
impure function iter (constant dir : t_dict_dir := UP) return KEY_TYPE is
variable v_key : t_dict_key_ptr := null;
begin
v_key := new KEY_TYPE'(v_iterator.key.all);
if (dir = UP) then
if (v_iterator.next_entry /= null) then
v_iterator := v_iterator.next_entry;
end if;
else
if (v_iterator.last_entry /= null) then
v_iterator := v_iterator.last_entry;
end if;
end if;
return v_key.all;
end function iter;
impure function get(constant key : KEY_TYPE) return VALUE_TYPE is
variable v_entry : t_entry_ptr := find(key);
begin
assert v_entry /= null
report t_dict'instance_name & ": key " & key_to_string(key) & " not found"
severity failure;
return v_entry.data.all;
end function get;
end protected body t_dict;
procedure merge(d0 : inout t_dict; d1 : inout t_dict; d : inout t_dict) is
variable v_key : t_dict_key_ptr;
variable v_data : t_dict_data_ptr;
begin
if (d0.size > 0) then
d0.setIter(TAIL);
for i in 0 to d0.size-1 loop
v_key := new KEY_TYPE'(d0.iter(UP));
v_data := new VALUE_TYPE'(d0.get(v_key.all));
d.set(v_key.all, v_data.all);
end loop;
end if;
if (d1.size > 0) then
d1.setIter(TAIL);
for i in 0 to d1.size-1 loop
v_key := new KEY_TYPE'(d1.iter(UP));
v_data := new VALUE_TYPE'(d1.get(v_key.all));
d.set(v_key.all, v_data.all);
end loop;
end if;
end procedure merge;
end package body DictP;