Browse Source

QueueP is now a package with generics for type & max depth

AHBL_BFM
T. Meissner 7 years ago
parent
commit
2a938e28b2
3 changed files with 110 additions and 60 deletions
  1. +73
    -47
      sim/QueueP.vhd
  2. +1
    -1
      test/Makefile
  3. +36
    -12
      test/QueueT.vhd

+ 73
- 47
sim/QueueP.vhd View File

@ -1,26 +1,27 @@
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
--+ including vhdl 2008 libraries
--+ These lines can be commented out when using
--+ a simulator with built-in VHDL 2008 support
--library ieee_proposed;
-- use ieee_proposed.standard_additions.all;
-- use ieee_proposed.std_logic_1164_additions.all;
package QueueP is package QueueP is
generic (
type QUEUE_TYPE;
MAX_LEN : natural := 64;
function to_string(d : in QUEUE_TYPE) return string
);
-- simple queue interface -- simple queue interface
type t_simple_queue is protected type t_simple_queue is protected
procedure push (data : in std_logic_vector);
procedure pop (data : out std_logic_vector);
procedure push (data : in QUEUE_TYPE);
procedure pop (data : out QUEUE_TYPE);
procedure init (logging : in boolean := false);
impure function is_empty return boolean; impure function is_empty return boolean;
impure function is_full return boolean; impure function is_full return boolean;
impure function fillstate return natural; impure function fillstate return natural;
impure function freeslots return natural;
end protected t_simple_queue; end protected t_simple_queue;
@ -28,10 +29,11 @@ package QueueP is
-- linked list queue interface -- linked list queue interface
type t_list_queue is protected type t_list_queue is protected
procedure push (data : in std_logic_vector);
procedure pop (data : inout std_logic_vector);
procedure init (depth : in natural; logging : in boolean := false);
procedure push (data : in QUEUE_TYPE);
procedure pop (data : out QUEUE_TYPE);
procedure init (logging : in boolean := false);
impure function is_empty return boolean; impure function is_empty return boolean;
impure function is_full return boolean;
impure function fillstate return natural; impure function fillstate return natural;
end protected t_list_queue; end protected t_list_queue;
@ -48,18 +50,16 @@ package body QueueP is
-- inspired by noasic article http://noasic.com/blog/a-simple-fifo-using-vhdl-protected-types/ -- inspired by noasic article http://noasic.com/blog/a-simple-fifo-using-vhdl-protected-types/
type t_simple_queue is protected body type t_simple_queue is protected body
constant C_QUEUE_DEPTH : natural := 64;
constant C_QUEUE_WIDTH : natural := 64;
type t_queue_array is array (0 to MAX_LEN-1) of QUEUE_TYPE;
type t_queue_array is array (0 to C_QUEUE_DEPTH-1) of std_logic_vector(C_QUEUE_WIDTH-1 downto 0);
variable v_queue : t_queue_array := (others => (others => '0'));
variable v_queue : t_queue_array;
variable v_count : natural range 0 to t_queue_array'length := 0; variable v_count : natural range 0 to t_queue_array'length := 0;
variable v_head : natural range 0 to t_queue_array'high := 0; variable v_head : natural range 0 to t_queue_array'high := 0;
variable v_tail : natural range 0 to t_queue_array'high := 0; variable v_tail : natural range 0 to t_queue_array'high := 0;
variable v_logging : boolean := false;
-- write one entry into queue -- write one entry into queue
procedure push (data : in std_logic_vector) is
procedure push (data : in QUEUE_TYPE) is
begin begin
assert not(is_full) assert not(is_full)
report "push into full queue -> discarded" report "push into full queue -> discarded"
@ -67,17 +67,25 @@ package body QueueP is
v_queue(v_head) := data; v_queue(v_head) := data;
v_head := (v_head + 1) mod t_queue_array'length; v_head := (v_head + 1) mod t_queue_array'length;
v_count := v_count + 1; v_count := v_count + 1;
if v_logging then
report t_simple_queue'instance_name & " pushed 0x" & to_string(data) & " into queue";
end if;
end procedure push; end procedure push;
-- read one entry from queue -- read one entry from queue
procedure pop (data : out std_logic_vector) is
procedure pop (data : out QUEUE_TYPE) is
variable v_data : QUEUE_TYPE;
begin begin
assert not(is_empty) assert not(is_empty)
report "pop from empty queue -> discarded" report "pop from empty queue -> discarded"
severity failure; severity failure;
data := v_queue(v_tail);
v_data := v_queue(v_tail);
v_tail := (v_tail + 1) mod t_queue_array'length; v_tail := (v_tail + 1) mod t_queue_array'length;
v_count := v_count - 1; v_count := v_count - 1;
if v_logging then
report t_simple_queue'instance_name & " popped 0x" & to_string(v_data) & " from queue";
end if;
data := v_data;
end procedure pop; end procedure pop;
-- returns true if queue is empty, false otherwise -- returns true if queue is empty, false otherwise
@ -104,6 +112,12 @@ package body QueueP is
return t_queue_array'length - v_count; return t_queue_array'length - v_count;
end function freeslots; end function freeslots;
procedure init (logging : in boolean := false) is
begin
v_logging := logging;
end procedure init;
end protected body t_simple_queue; end protected body t_simple_queue;
@ -111,12 +125,10 @@ package body QueueP is
type t_list_queue is protected body type t_list_queue is protected body
constant C_QUEUE_WIDTH : natural := 8;
type t_entry; type t_entry;
type t_entry_ptr is access t_entry; type t_entry_ptr is access t_entry;
type t_data_ptr is access std_logic_vector;
type t_data_ptr is access QUEUE_TYPE;
type t_entry is record type t_entry is record
data : t_data_ptr; data : t_data_ptr;
@ -124,59 +136,73 @@ package body QueueP is
next_entry : t_entry_ptr; next_entry : t_entry_ptr;
end record t_entry; end record t_entry;
variable v_head : t_entry_ptr;
variable v_tail : t_entry_ptr;
variable v_count : natural := 0;
variable v_head : t_entry_ptr;
variable v_tail : t_entry_ptr;
variable v_count : natural := 0;
variable v_logging : boolean := false; variable v_logging : boolean := false;
-- write one entry into queue by -- write one entry into queue by
-- creating new entry at head of list -- creating new entry at head of list
procedure push (data : in std_logic_vector) is
procedure push (data : in QUEUE_TYPE) is
variable v_entry : t_entry_ptr; variable v_entry : t_entry_ptr;
begin begin
if (v_count /= 0) then
v_entry := new t_entry;
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;
if (not(is_full)) then
if (v_count /= 0) then
v_entry := new t_entry;
v_entry.data := new QUEUE_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.data := new QUEUE_TYPE'(data);
v_head.last_entry := null;
v_head.next_entry := null;
v_tail := v_head;
end if;
v_count := v_count + 1;
if v_logging then
report t_list_queue'instance_name & " pushed 0x" & to_string(data) & " into queue";
end if;
else else
v_head := new t_entry;
v_head.data := new std_logic_vector'(data);
v_head.last_entry := null;
v_head.next_entry := null;
v_tail := v_head;
end if;
v_count := v_count + 1;
if v_logging then
report t_list_queue'instance_name & " pushed 0x" & to_hstring(data) & " into queue";
assert false
report "Push to full queue -> discared"
severity warning;
end if; end if;
end procedure push; end procedure push;
-- read one entry from queue at tail of list and -- read one entry from queue at tail of list and
-- delete that entry from list after read -- delete that entry from list after read
procedure pop (data : inout std_logic_vector) is
procedure pop (data : out QUEUE_TYPE) is
variable v_entry : t_entry_ptr := v_tail; variable v_entry : t_entry_ptr := v_tail;
variable v_data : QUEUE_TYPE;
begin begin
assert not(is_empty) assert not(is_empty)
report "pop from empty queue -> discarded" report "pop from empty queue -> discarded"
severity failure; severity failure;
data := v_tail.data.all;
v_data := v_tail.data.all;
v_tail := v_tail.next_entry; v_tail := v_tail.next_entry;
deallocate(v_entry.data); deallocate(v_entry.data);
deallocate(v_entry); deallocate(v_entry);
v_count := v_count - 1; v_count := v_count - 1;
if v_logging then if v_logging then
report t_list_queue'instance_name & " popped 0x" & to_hstring(data) & " from queue";
report t_list_queue'instance_name & " popped 0x" & to_string(v_data) & " from queue";
end if; end if;
data := v_data;
end procedure pop; end procedure pop;
procedure init (depth : in natural; logging : in boolean := false) is
procedure init (logging : in boolean := false) is
begin begin
v_logging := logging; v_logging := logging;
end procedure init; end procedure init;
-- returns true if queue is full, false otherwise
impure function is_full return boolean is
begin
return v_count = MAX_LEN;
end function is_full;
-- returns true if queue is empty, false otherwise -- returns true if queue is empty, false otherwise
impure function is_empty return boolean is impure function is_empty return boolean is
begin begin


+ 1
- 1
test/Makefile View File

@ -32,7 +32,7 @@ UtilsP.o: $(CMN_SRC)/UtilsP.vhd
ghdl -a --std=$(VHD_STD) --work=libvhdl $< ghdl -a --std=$(VHD_STD) --work=libvhdl $<
queuet: AssertP.o QueueP.o QueueT.vhd
queuet: RandomPkg.o AssertP.o QueueP.o QueueT.vhd
ghdl -a --std=$(VHD_STD) QueueT.vhd ghdl -a --std=$(VHD_STD) QueueT.vhd
ghdl -e --std=$(VHD_STD) $@ ghdl -e --std=$(VHD_STD) $@


+ 36
- 12
test/QueueT.vhd View File

@ -4,7 +4,9 @@ library ieee;
library libvhdl; library libvhdl;
use libvhdl.AssertP.all; use libvhdl.AssertP.all;
use libvhdl.QueueP.all;
library osvvm;
use osvvm.RandomPkg.all;
@ -18,8 +20,15 @@ architecture sim of QueueT is
constant C_QUEUE_DEPTH : natural := 64; constant C_QUEUE_DEPTH : natural := 64;
shared variable sv_simple_queue : t_simple_queue;
shared variable sv_list_queue : t_list_queue;
package SlvQueue is new libvhdl.QueueP
generic map (
QUEUE_TYPE => std_logic_vector(63 downto 0),
MAX_LEN => C_QUEUE_DEPTH,
to_string => to_hstring
);
shared variable sv_simple_queue : SlvQueue.t_simple_queue;
shared variable sv_list_queue : SlvQueue.t_list_queue;
begin begin
@ -27,26 +36,34 @@ begin
QueueInitP : process is QueueInitP : process is
begin begin
sv_list_queue.init(C_QUEUE_DEPTH);
sv_simple_queue.init(false);
sv_list_queue.init(false);
wait; wait;
end process QueueInitP; end process QueueInitP;
SimpleQueueTestP : process is SimpleQueueTestP : process is
variable v_data : std_logic_vector(63 downto 0);
variable v_data : std_logic_vector(63 downto 0);
variable v_random : RandomPType;
begin begin
-- check initial emptiness -- check initial emptiness
assert_true(sv_simple_queue.is_empty, "Queue should be empty!"); assert_true(sv_simple_queue.is_empty, "Queue should be empty!");
for i in 0 to 63 loop
sv_simple_queue.push(std_logic_vector(to_unsigned(i, 64)));
-- Fill queue
v_random.InitSeed(v_random'instance_name);
for i in 0 to C_QUEUE_DEPTH-1 loop
v_data := v_random.RandSlv(64);
sv_simple_queue.push(v_data);
end loop; end loop;
-- check that it's full -- check that it's full
assert_true(sv_simple_queue.is_full, "Queue should be full!"); assert_true(sv_simple_queue.is_full, "Queue should be full!");
-- Check number of entries
assert_equal(sv_simple_queue.fillstate, C_QUEUE_DEPTH, "Queue should have" & integer'image(C_QUEUE_DEPTH) & "entries");
-- empty the queue -- empty the queue
for i in 0 to 63 loop
v_random.InitSeed(v_random'instance_name);
for i in 0 to C_QUEUE_DEPTH-1 loop
sv_simple_queue.pop(v_data); sv_simple_queue.pop(v_data);
assert_equal(v_data, std_logic_vector(to_unsigned(i, 64)));
assert_equal(v_data, v_random.RandSlv(64));
end loop; end loop;
-- check emptiness -- check emptiness
assert_true(sv_simple_queue.is_empty, "Queue should be empty!"); assert_true(sv_simple_queue.is_empty, "Queue should be empty!");
@ -56,19 +73,26 @@ begin
ListQueueTestP : process is ListQueueTestP : process is
variable v_data : std_logic_vector(7 downto 0);
variable v_data : std_logic_vector(63 downto 0);
variable v_random : RandomPType;
begin begin
-- check initial emptiness -- check initial emptiness
assert_true(sv_list_queue.is_empty, "Queue should be empty!"); assert_true(sv_list_queue.is_empty, "Queue should be empty!");
-- Fill queue
v_random.InitSeed(v_random'instance_name);
for i in 0 to C_QUEUE_DEPTH-1 loop for i in 0 to C_QUEUE_DEPTH-1 loop
sv_list_queue.push(std_logic_vector(to_unsigned(i, 8)));
v_data := v_random.RandSlv(64);
sv_list_queue.push(v_data);
end loop; end loop;
-- check that it's full -- check that it's full
assert_true(sv_list_queue.is_full, "Queue should be full!");
-- Check number of entries
assert_equal(sv_list_queue.fillstate, C_QUEUE_DEPTH, "Queue should have" & integer'image(C_QUEUE_DEPTH) & "entries"); assert_equal(sv_list_queue.fillstate, C_QUEUE_DEPTH, "Queue should have" & integer'image(C_QUEUE_DEPTH) & "entries");
-- empty the queue -- empty the queue
v_random.InitSeed(v_random'instance_name);
for i in 0 to C_QUEUE_DEPTH-1 loop for i in 0 to C_QUEUE_DEPTH-1 loop
sv_list_queue.pop(v_data); sv_list_queue.pop(v_data);
assert_equal(v_data, std_logic_vector(to_unsigned(i, 8)));
assert_equal(v_data, v_random.RandSlv(64));
end loop; end loop;
-- check emptiness -- check emptiness
assert_true(sv_list_queue.is_empty, "Queue should be empty!"); assert_true(sv_list_queue.is_empty, "Queue should be empty!");


Loading…
Cancel
Save