Browse Source

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

T. Meissner 2 years ago
parent
commit
2a938e28b2
3 changed files with 110 additions and 58 deletions
  1. 73
    45
      sim/QueueP.vhd
  2. 1
    1
      test/Makefile
  3. 36
    12
      test/QueueT.vhd

+ 73
- 45
sim/QueueP.vhd View File

@@ -1,26 +1,27 @@
1 1
 library ieee;
2 2
   use ieee.std_logic_1164.all;
3 3
 
4
---+ including vhdl 2008 libraries
5
---+ These lines can be commented out when using
6
---+ a simulator with built-in VHDL 2008 support
7
---library ieee_proposed;
8 4
 
9 5
 
10 6
 package QueueP is
11 7
 
12 8
 
9
+  generic (
10
+    type     QUEUE_TYPE;
11
+    MAX_LEN : natural := 64;
12
+    function to_string(d : in QUEUE_TYPE) return string
13
+  );
14
+
15
+
13 16
   -- simple queue interface
14 17
   type t_simple_queue is protected
15 18
 
16
-    procedure push (data : in  std_logic_vector);
17
-    procedure pop  (data : out std_logic_vector);
19
+    procedure push (data : in  QUEUE_TYPE);
20
+    procedure pop  (data : out QUEUE_TYPE);
21
+    procedure init (logging : in boolean := false);
18 22
     impure function is_empty  return boolean;
19 23
     impure function is_full   return boolean;
20 24
     impure function fillstate return natural;
21
-    impure function freeslots return natural;
22 25
 
23 26
   end protected t_simple_queue;
24 27
 
@@ -28,10 +29,11 @@ package QueueP is
28 29
   -- linked list queue interface
29 30
   type t_list_queue is protected
30 31
 
31
-    procedure push (data : in  std_logic_vector);
32
-    procedure pop  (data : inout std_logic_vector);
33
-    procedure init (depth : in natural; logging : in boolean := false);
32
+    procedure push (data : in  QUEUE_TYPE);
33
+    procedure pop  (data : out QUEUE_TYPE);
34
+    procedure init (logging : in boolean := false);
34 35
     impure function is_empty return boolean;
36
+    impure function is_full   return boolean;
35 37
     impure function fillstate return natural;
36 38
 
37 39
   end protected t_list_queue;
@@ -48,18 +50,16 @@ package body QueueP is
48 50
   -- inspired by noasic article http://noasic.com/blog/a-simple-fifo-using-vhdl-protected-types/
49 51
   type t_simple_queue is protected body
50 52
 
51
-    constant C_QUEUE_DEPTH : natural := 64;
52
-    constant C_QUEUE_WIDTH : natural := 64;
53
+    type t_queue_array is array (0 to MAX_LEN-1) of QUEUE_TYPE;
53 54
 
54
-    type t_queue_array is array (0 to C_QUEUE_DEPTH-1) of std_logic_vector(C_QUEUE_WIDTH-1 downto 0);
55
-
56
-    variable v_queue : t_queue_array := (others => (others => '0'));
55
+    variable v_queue : t_queue_array;
57 56
     variable v_count : natural range 0 to t_queue_array'length := 0;
58 57
     variable v_head  : natural range 0 to t_queue_array'high   := 0;
59 58
     variable v_tail  : natural range 0 to t_queue_array'high   := 0;
59
+    variable v_logging : boolean := false;
60 60
 
61 61
     -- write one entry into queue
62
-    procedure push (data : in  std_logic_vector) is
62
+    procedure push (data : in QUEUE_TYPE) is
63 63
     begin
64 64
       assert not(is_full)
65 65
         report "push into full queue -> discarded"
@@ -67,17 +67,25 @@ package body QueueP is
67 67
       v_queue(v_head) := data;
68 68
       v_head  := (v_head + 1) mod t_queue_array'length;
69 69
       v_count := v_count + 1;
70
+      if v_logging then
71
+        report t_simple_queue'instance_name & " pushed 0x" & to_string(data) & " into queue";
72
+      end if;
70 73
     end procedure push;
71 74
 
72 75
     -- read one entry from queue
73
-    procedure pop (data : out std_logic_vector) is
76
+    procedure pop (data : out QUEUE_TYPE) is
77
+      variable v_data : QUEUE_TYPE;
74 78
     begin
75 79
       assert not(is_empty)
76 80
         report "pop from empty queue -> discarded"
77 81
         severity failure;
78
-      data := v_queue(v_tail);
82
+      v_data := v_queue(v_tail);
79 83
       v_tail  := (v_tail + 1) mod t_queue_array'length;
80 84
       v_count := v_count - 1;
85
+      if v_logging then
86
+        report t_simple_queue'instance_name & " popped 0x" & to_string(v_data) & " from queue";
87
+      end if;
88
+      data := v_data;
81 89
     end procedure pop;
82 90
 
83 91
     -- returns true if queue is empty, false otherwise
@@ -104,6 +112,12 @@ package body QueueP is
104 112
       return t_queue_array'length - v_count;
105 113
     end function freeslots;
106 114
 
115
+    procedure init (logging : in boolean := false) is
116
+    begin
117
+      v_logging := logging;
118
+    end procedure init;
119
+
120
+
107 121
   end protected body t_simple_queue;
108 122
 
109 123
 
@@ -111,12 +125,10 @@ package body QueueP is
111 125
   type t_list_queue is protected body
112 126
 
113 127
 
114
-    constant C_QUEUE_WIDTH : natural := 8;
115
-
116 128
     type t_entry;
117 129
     type t_entry_ptr is access t_entry;
118 130
 
119
-    type t_data_ptr is access std_logic_vector;
131
+    type t_data_ptr is access QUEUE_TYPE;
120 132
 
121 133
     type t_entry is record
122 134
       data       : t_data_ptr;
@@ -124,59 +136,73 @@ package body QueueP is
124 136
       next_entry : t_entry_ptr;
125 137
     end record t_entry;
126 138
 
127
-    variable v_head : t_entry_ptr;
128
-    variable v_tail : t_entry_ptr;
129
-    variable v_count : natural := 0;
139
+    variable v_head    : t_entry_ptr;
140
+    variable v_tail    : t_entry_ptr;
141
+    variable v_count   : natural := 0;
130 142
     variable v_logging : boolean := false;
131 143
 
132 144
     -- write one entry into queue by
133 145
     -- creating new entry at head of list
134
-    procedure push (data : in  std_logic_vector) is
146
+    procedure push (data : in  QUEUE_TYPE) is
135 147
       variable v_entry : t_entry_ptr;
136 148
     begin
137
-      if (v_count /= 0) then
138
-        v_entry            := new t_entry;
139
-        v_entry.data       := new std_logic_vector'(data);
140
-        v_entry.last_entry := v_head;
141
-        v_entry.next_entry := null;
142
-        v_head             := v_entry;
143
-        v_head.last_entry.next_entry := v_head;
149
+      if (not(is_full)) then 
150
+        if (v_count /= 0) then
151
+          v_entry            := new t_entry;
152
+          v_entry.data       := new QUEUE_TYPE'(data);
153
+          v_entry.last_entry := v_head;
154
+          v_entry.next_entry := null;
155
+          v_head             := v_entry;
156
+          v_head.last_entry.next_entry := v_head;
157
+        else
158
+          v_head            := new t_entry;
159
+          v_head.data       := new QUEUE_TYPE'(data);
160
+          v_head.last_entry := null;
161
+          v_head.next_entry := null;
162
+          v_tail := v_head;
163
+        end if;
164
+        v_count := v_count + 1;
165
+        if v_logging then
166
+          report t_list_queue'instance_name & " pushed 0x" & to_string(data) & " into queue";
167
+        end if;
144 168
       else
145
-        v_head            := new t_entry;
146
-        v_head.data       := new std_logic_vector'(data);
147
-        v_head.last_entry := null;
148
-        v_head.next_entry := null;
149
-        v_tail := v_head;
150
-      end if;
151
-      v_count := v_count + 1;
152
-      if v_logging then
153
-        report t_list_queue'instance_name & " pushed 0x" & to_hstring(data) & " into queue";
169
+        assert false
170
+        report "Push to full queue -> discared"
171
+        severity warning;
154 172
       end if;
155 173
     end procedure push;
156 174
 
157 175
     -- read one entry from queue at tail of list and
158 176
     -- delete that entry from list after read
159
-    procedure pop  (data : inout std_logic_vector) is
177
+    procedure pop  (data : out QUEUE_TYPE) is
160 178
       variable v_entry : t_entry_ptr := v_tail;
179
+      variable v_data  : QUEUE_TYPE;
161 180
     begin
162 181
       assert not(is_empty)
163 182
         report "pop from empty queue -> discarded"
164 183
         severity failure;
165
-      data   := v_tail.data.all;
184
+      v_data   := v_tail.data.all;
166 185
       v_tail := v_tail.next_entry;
167 186
       deallocate(v_entry.data);
168 187
       deallocate(v_entry);
169 188
       v_count := v_count - 1;
170 189
       if v_logging then
171
-        report t_list_queue'instance_name & " popped 0x" & to_hstring(data) & " from queue";
190
+        report t_list_queue'instance_name & " popped 0x" & to_string(v_data) & " from queue";
172 191
       end if;
192
+      data := v_data;
173 193
     end procedure pop;
174 194
 
175
-    procedure init (depth : in natural; logging : in boolean := false) is
195
+    procedure init (logging : in boolean := false) is
176 196
     begin
177 197
       v_logging := logging;
178 198
     end procedure init;
179 199
 
200
+    -- returns true if queue is full, false otherwise
201
+    impure function is_full return boolean is
202
+    begin
203
+      return v_count = MAX_LEN;
204
+    end function is_full;
205
+
180 206
     -- returns true if queue is empty, false otherwise
181 207
     impure function is_empty return boolean is
182 208
     begin

+ 1
- 1
test/Makefile View File

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

+ 36
- 12
test/QueueT.vhd View File

@@ -4,7 +4,9 @@ library ieee;
4 4
 
5 5
 library libvhdl;
6 6
   use libvhdl.AssertP.all;
7
-  use libvhdl.QueueP.all;
7
+
8
+library osvvm;
9
+  use osvvm.RandomPkg.all;
8 10
 
9 11
 
10 12
 
@@ -18,8 +20,15 @@ architecture sim of QueueT is
18 20
 
19 21
   constant C_QUEUE_DEPTH : natural := 64;
20 22
 
21
-  shared variable sv_simple_queue : t_simple_queue;
22
-  shared variable sv_list_queue   : t_list_queue;
23
+  package SlvQueue is new libvhdl.QueueP
24
+    generic map (
25
+      QUEUE_TYPE => std_logic_vector(63 downto 0),
26
+      MAX_LEN    => C_QUEUE_DEPTH,
27
+      to_string  => to_hstring
28
+    );
29
+
30
+  shared variable sv_simple_queue : SlvQueue.t_simple_queue;
31
+  shared variable sv_list_queue   : SlvQueue.t_list_queue;
23 32
 
24 33
 
25 34
 begin
@@ -27,26 +36,34 @@ begin
27 36
 
28 37
   QueueInitP : process is
29 38
   begin
30
-    sv_list_queue.init(C_QUEUE_DEPTH);
39
+    sv_simple_queue.init(false);
40
+    sv_list_queue.init(false);
31 41
     wait;
32 42
   end process QueueInitP;
33 43
 
34 44
 
35 45
 
36 46
   SimpleQueueTestP : process is
37
-    variable v_data  : std_logic_vector(63 downto 0);
47
+    variable v_data   : std_logic_vector(63 downto 0);
48
+    variable v_random : RandomPType;
38 49
   begin
39 50
     -- check initial emptiness
40 51
     assert_true(sv_simple_queue.is_empty, "Queue should be empty!");
41
-    for i in 0 to 63 loop
42
-      sv_simple_queue.push(std_logic_vector(to_unsigned(i, 64)));
52
+    -- Fill queue
53
+    v_random.InitSeed(v_random'instance_name);
54
+    for i in 0 to C_QUEUE_DEPTH-1 loop
55
+      v_data := v_random.RandSlv(64);
56
+      sv_simple_queue.push(v_data);
43 57
     end loop;
44 58
     -- check that it's full
45 59
     assert_true(sv_simple_queue.is_full, "Queue should be full!");
60
+    -- Check number of entries
61
+    assert_equal(sv_simple_queue.fillstate, C_QUEUE_DEPTH, "Queue should have" & integer'image(C_QUEUE_DEPTH) & "entries");
46 62
     -- empty the queue
47
-    for i in 0 to 63 loop
63
+    v_random.InitSeed(v_random'instance_name);
64
+    for i in 0 to C_QUEUE_DEPTH-1 loop
48 65
       sv_simple_queue.pop(v_data);
49
-      assert_equal(v_data, std_logic_vector(to_unsigned(i, 64)));
66
+      assert_equal(v_data, v_random.RandSlv(64));
50 67
     end loop;
51 68
     -- check emptiness
52 69
     assert_true(sv_simple_queue.is_empty, "Queue should be empty!");
@@ -56,19 +73,26 @@ begin
56 73
 
57 74
 
58 75
   ListQueueTestP : process is
59
-    variable v_data : std_logic_vector(7 downto 0);
76
+    variable v_data   : std_logic_vector(63 downto 0);
77
+    variable v_random : RandomPType;
60 78
   begin
61 79
     -- check initial emptiness
62 80
     assert_true(sv_list_queue.is_empty, "Queue should be empty!");
81
+    -- Fill queue
82
+    v_random.InitSeed(v_random'instance_name);
63 83
     for i in 0 to C_QUEUE_DEPTH-1 loop
64
-      sv_list_queue.push(std_logic_vector(to_unsigned(i, 8)));
84
+      v_data := v_random.RandSlv(64);
85
+      sv_list_queue.push(v_data);
65 86
     end loop;
66 87
     -- check that it's full
88
+    assert_true(sv_list_queue.is_full, "Queue should be full!");
89
+    -- Check number of entries
67 90
     assert_equal(sv_list_queue.fillstate, C_QUEUE_DEPTH, "Queue should have" & integer'image(C_QUEUE_DEPTH) & "entries");
68 91
     -- empty the queue
92
+    v_random.InitSeed(v_random'instance_name);
69 93
     for i in 0 to C_QUEUE_DEPTH-1 loop
70 94
       sv_list_queue.pop(v_data);
71
-      assert_equal(v_data, std_logic_vector(to_unsigned(i, 8)));
95
+      assert_equal(v_data, v_random.RandSlv(64));
72 96
     end loop;
73 97
     -- check emptiness
74 98
     assert_true(sv_list_queue.is_empty, "Queue should be empty!");