diff --git a/sim/QueueP.vhd b/sim/QueueP.vhd index 3098db0..8e53f12 100644 --- a/sim/QueueP.vhd +++ b/sim/QueueP.vhd @@ -1,26 +1,27 @@ library ieee; 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 + generic ( + type QUEUE_TYPE; + MAX_LEN : natural := 64; + function to_string(d : in QUEUE_TYPE) return string + ); + + -- simple queue interface 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_full return boolean; impure function fillstate return natural; - impure function freeslots return natural; end protected t_simple_queue; @@ -28,10 +29,11 @@ package QueueP is -- linked list queue interface 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_full return boolean; impure function fillstate return natural; 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/ 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_head : 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 - procedure push (data : in std_logic_vector) is + procedure push (data : in QUEUE_TYPE) is begin assert not(is_full) report "push into full queue -> discarded" @@ -67,17 +67,25 @@ package body QueueP is v_queue(v_head) := data; v_head := (v_head + 1) mod t_queue_array'length; 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; -- 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 assert not(is_empty) report "pop from empty queue -> discarded" severity failure; - data := v_queue(v_tail); + v_data := v_queue(v_tail); v_tail := (v_tail + 1) mod t_queue_array'length; 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; -- returns true if queue is empty, false otherwise @@ -104,6 +112,12 @@ package body QueueP is return t_queue_array'length - v_count; end function freeslots; + procedure init (logging : in boolean := false) is + begin + v_logging := logging; + end procedure init; + + end protected body t_simple_queue; @@ -111,12 +125,10 @@ package body QueueP is type t_list_queue is protected body - constant C_QUEUE_WIDTH : natural := 8; - type 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 data : t_data_ptr; @@ -124,59 +136,73 @@ package body QueueP is next_entry : t_entry_ptr; 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; -- write one entry into queue by -- 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; 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 - 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 procedure push; -- read one entry from queue at tail of list and -- 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_data : QUEUE_TYPE; begin assert not(is_empty) report "pop from empty queue -> discarded" severity failure; - data := v_tail.data.all; + v_data := v_tail.data.all; v_tail := v_tail.next_entry; deallocate(v_entry.data); deallocate(v_entry); v_count := v_count - 1; 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; + data := v_data; end procedure pop; - procedure init (depth : in natural; logging : in boolean := false) is + procedure init (logging : in boolean := false) is begin v_logging := logging; 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 impure function is_empty return boolean is begin diff --git a/test/Makefile b/test/Makefile index 3c43726..74743a9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -32,7 +32,7 @@ UtilsP.o: $(CMN_SRC)/UtilsP.vhd 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 -e --std=$(VHD_STD) $@ diff --git a/test/QueueT.vhd b/test/QueueT.vhd index c114406..e3c6c7d 100644 --- a/test/QueueT.vhd +++ b/test/QueueT.vhd @@ -4,7 +4,9 @@ library ieee; library libvhdl; 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; - 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 @@ -27,26 +36,34 @@ begin QueueInitP : process is begin - sv_list_queue.init(C_QUEUE_DEPTH); + sv_simple_queue.init(false); + sv_list_queue.init(false); wait; end process QueueInitP; 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 -- check initial emptiness 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; -- check that it's 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 - 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); - assert_equal(v_data, std_logic_vector(to_unsigned(i, 64))); + assert_equal(v_data, v_random.RandSlv(64)); end loop; -- check emptiness assert_true(sv_simple_queue.is_empty, "Queue should be empty!"); @@ -56,19 +73,26 @@ begin 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 -- check initial emptiness 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 - 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; -- 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"); -- empty the queue + v_random.InitSeed(v_random'instance_name); for i in 0 to C_QUEUE_DEPTH-1 loop 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; -- check emptiness assert_true(sv_list_queue.is_empty, "Queue should be empty!");