SyoSil ApS UVM Scoreboard  1.0.3.0
cl_scb_test_iterator_unit_tests.svh
1 /// Test containing a series of unit tests to ensure that all iterators conform to spec.
2 class cl_scb_test_iterator_unit_tests extends cl_scb_test_single_scb;
3  //-------------------------------------
4  // Non randomizable variables
5  //-------------------------------------
6 
7  //-------------------------------------
8  // UVM Macros
9  //-------------------------------------
10  `uvm_component_utils_begin(cl_scb_test_iterator_unit_tests)
11 
12  `uvm_component_utils_end
13 
14  //-------------------------------------
15  // Constructor
16  //-------------------------------------
17  function new(string name = "cl_scb_test_iterator_unit_tests", uvm_component parent = null);
18  super.new(name, parent);
19  endfunction: new
20 
21  //-------------------------------------
22  // Functions
23  //-------------------------------------
24 
25  extern task main_phase(uvm_phase phase);
26  extern function cl_tb_seq_item get_next(cl_syoscb_queue_iterator_base iter);
27  extern function cl_tb_seq_item get_previous(cl_syoscb_queue_iterator_base iter);
28 
29  extern task check_next();
30  extern task check_prev();
31  extern task check_first();
32  extern task check_last();
33  extern task check_set_queue();
34  extern task check_names();
35  extern task check_flush();
36 
38 
39 //Gets the cl_tb_seq_item that the given iterator is currently pointing to
40 function cl_tb_seq_item cl_scb_test_iterator_unit_tests::get_next(cl_syoscb_queue_iterator_base iter);
41  cl_tb_seq_item ctsi;
42  $cast(ctsi, iter.next().get_item().get_item()); //proxy -> syoscb item -> seq item -> cast to ctsi
43  return ctsi;
44 endfunction: get_next
45 
46 function cl_tb_seq_item cl_scb_test_iterator_unit_tests::get_previous(cl_syoscb_queue_iterator_base iter);
47  cl_tb_seq_item ctsi;
48  $cast(ctsi, iter.previous().get_item().get_item()); //proxy -> syoscb item -> seq item -> cast to ctsi
49  return ctsi;
50 endfunction: get_previous
51 
52 /// Checks whether the cl_syoscb_queue_iterator_base#next method correctly moves through the queue
53 /// When called, the idx should increment and it should return 1'b1. It should then also point to the next item in the queue.
54 /// When called while already pointing to the last element of the queue, it should generate an out-of-bounds message and return 1'b0
56  cl_tb_seq_item ctsi;
57 
58  cl_syoscb_queue_base q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
59  cl_syoscb_queue_iterator_base iter = q.create_iterator();
60 
61  //Check that we can iterate over items in the queue
62  for(int i=0; i<10; i++) begin
63  ctsi = this.get_next(iter);
64  if(ctsi.int_a != i || iter.previous_index() != i) begin
65  `uvm_error("ITER_NEXT", $sformatf("iterator.next() did not correctly advance the iterator. i=%0d, int_a=%0d, prev_idx=%0x", i, ctsi.int_a, iter.previous_index()))
66  end
67  end
68 
69  if(iter.next_index() != q.get_size()) begin
70  `uvm_error("ITER_NEXT", "iterator.next() did not advance to the end of the queue")
71  end
72 
73  //Check that calling has_next() when iter.next_idx() == queue.size returns 1'b0
74  if(iter.has_next()) begin
75  `uvm_error("ITER_NEXT", "iterator.has_next() returned 1'b1 while at the end of the queue")
76  end
77 
78  //Check that calling has_next() on an empty queue returns 1'b0
79  begin
80  cl_syoscb_queue_iterator_base iter2 = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").create_iterator();
81  if(iter2.has_next()) begin
82  `uvm_error("ITER_NEXT", "iterator.has_next() returned 1'b1 on an empty queue")
83  end
84  void'(this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").delete_iterator(iter2));
85  end
86 
87  void'(q.delete_iterator(iter));
88  `uvm_info("ITER_NEXT", "iterator.next() and iterator.has_next() passed tests", UVM_LOW)
89 
90 endtask: check_next
91 
92 /// Checks whether the cl_syoscb_queue_iterator_base#previous method correctly moves through the queue.
93 /// When called, the idx should decrement and it should return 1'b1. It should then also point to the previous item in the queue.
94 /// When called while already pointing to the first element of the queue, it should generate an out-of-bounds message and return 1'b0.
95 /// When called on an empty queue, it should return 1'b0.
96 task cl_scb_test_iterator_unit_tests::check_prev();
97  cl_tb_seq_item ctsi;
98 
99  cl_syoscb_queue_base q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
100  cl_syoscb_queue_iterator_base iter = q.create_iterator();
101 
102  //We now know that next() works. Start by iterating forward to final item
103  while(iter.has_next()) begin
104  void'(iter.next());
105  end
106 
107  //Iterate backwards
108  for(int i=9; i>0; i--) begin
109  ctsi = this.get_previous(iter);
110  if(ctsi.int_a != i || iter.next_index() != i) begin
111  `uvm_error("ITER_PREV", "iterator.previous() did not correctly move iterator back")
112  end
113  end
114 
115  //Check that we have arrived at first element of queue
116  ctsi = this.get_previous(iter);
117  if(ctsi.int_a != 0 || iter.previous_index() != -1) begin
118  `uvm_error("ITER_PREV", "iterator.previous() did not move to index 0")
119  end
120 
121  //Check that calling has_previous() returns 1'b0
122  if(iter.has_previous()) begin
123  `uvm_error("ITER_PREV", "iterator.has_previous() returned 1'b1 while at the start of the queue")
124  end
125 
126  //Check that calling has_previous() on an empty queue returns 1'b0
127  begin
128  cl_syoscb_queue_iterator_base iter2 = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").create_iterator();
129  if(iter2.has_previous()) begin
130  `uvm_error("ITER_PREV", "iterator.has_previous() returned 1'b1 on an empty queue")
131  end
132  void'(this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").delete_iterator(iter2));
133  end
134 
135  void'(q.delete_iterator(iter));
136  `uvm_info("ITER_PREV", "iterator.previous() and iterator.has_previous() passed tests", UVM_LOW)
137 endtask: check_prev
138 
139 /// Checks whether the cl_syoscb_queue_iterator_base#first method correctly moves through the queue.
140 /// When called, the idx should become 0 and it should return 1'b1. It should then also point to the first item in the queue.
141 /// When called while already pointing to the first element of the queue, behavior should be the same.
142 /// When called on an empty queue, should return 1'b0.
144  cl_tb_seq_item ctsi;
145 
146  cl_syoscb_queue_base q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
147  cl_syoscb_queue_iterator_base iter = q.create_iterator();
148 
149  //We now know that next() works. Start by iterating 6 times forwards
150  for(int i=0; i<6; i++) begin
151  void'(iter.next());
152  end
153 
154  //Check twice that calling first works
155  //Initial call resets the iterator, next call should not modify state of iterator
156  for(int i=0; i<2; i++) begin
157  //Go back to first
158  if(!iter.first()) begin
159  `uvm_error("ITER_FIRST", "iterator.first() did not return 1'b1 while moving to first element")
160  end
161 
162  //Check that we are at the start
163  if(iter.previous_index() != -1) begin
164  `uvm_error("ITER_FIRST", "iterator.first() did not set idx to 0")
165  end
166 
167  ctsi = this.get_next(iter);
168  if(ctsi.int_a != 0) begin
169  `uvm_error("ITER_FIRST", "iterator.first() did not move to first element in queue")
170  end
171  end
172 
173  //Check that calling first on an empty queue fails
174  begin
175  cl_syoscb_queue_iterator_base iter2 = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").create_iterator();
176  if(iter2.first()) begin
177  `uvm_error("ITER_FIRST", "iterator.first() did not return 1'b0 when called on an empty queue")
178  end
179  void'(this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").delete_iterator(iter2));
180  end
181 
182  void'(q.delete_iterator(iter));
183  `uvm_info("ITER_FIRST", "iterator.first() passed tests", UVM_LOW)
184 endtask: check_first
185 
186 /// Checks whether the cl_syoscb_queue_iterator_base#last method correctly moves through the queue.
187 /// When called, the idx should become queue.size()-1 and it should return 1'b1. It should then also point to the final item in the queue.
188 /// When called while already pointing to the final element of the queue, behavior should be the same.
189 /// When called on an empty queue, should return 1'b0.
190 task cl_scb_test_iterator_unit_tests::check_last();
191  cl_tb_seq_item ctsi;
192  cl_syoscb_queue_base q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
193  cl_syoscb_queue_iterator_base iter = q.create_iterator();
194 
195  //Calling last on a queue with items should move to final element
196  //Initial call moves iterator to final element, next call should not modify state of iterator
197  for(int i=0; i<2; i++) begin
198  if(!iter.last()) begin
199  `uvm_error("ITER_LAST", "iterator.last() did not return 1'b1 when moving to last element")
200  end
201  ctsi = this.get_previous(iter);
202  if(ctsi.int_a != q.get_size()-1 || iter.next_index() != q.get_size()-1) begin
203  $display("int_a=%0d, next_index=%0d, get_size=%0d", ctsi.int_a, iter.next_index(), q.get_size());
204  `uvm_error("ITER_LAST", "iterator.last() did not move to the last element of the queue")
205  end
206  end
207 
208  //Check that calling last on an empty queue fails
209  begin
210  cl_syoscb_queue_iterator_base iter2 = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").create_iterator();
211  if(iter2.last()) begin
212  `uvm_error("ITER_LAST", "iterator.last() did not return 1'b0 when called on an empty queue")
213  end
214  void'(this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2").delete_iterator(iter2));
215  end
216 
217  void'(q.delete_iterator(iter));
218  `uvm_info("ITER_LAST", "iterator.last() passed tests", UVM_LOW)
219 endtask: check_last
220 
221 /// Checks whether the cl_syoscb_queue_iterator_base#set_queue method correctly sets the queue associated with an iterator.
222 /// When called with null as argument, should return 1'b0.
223 /// When called and the iterator already has an owner associated, should raise a UVM_ERROR
224 /// When called and the new owner is not of the right queue type, should raise a UVM_ERROR
225 /// When called and the iterator does not have an owner associated, should return 1'b1 and set the queue as owner.
226 task cl_scb_test_iterator_unit_tests::check_set_queue();
227  cl_tb_seq_item ctsi;
228  cl_syoscb_queue_iterator_std iter2_std;
229  cl_syoscb_queue_iterator_hash#(pk_syoscb::MD5_HASH_DIGEST_WIDTH) iter2_hash;
230 
231  cl_syoscb_queue_base q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
232  cl_syoscb_queue_base q2 = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2");
233  cl_syoscb_queue_iterator_base iter = q.create_iterator();
234 
235  //Demote ITER_ERROR for the duration of this test
236  uvm_root::get().set_report_severity_id_override(UVM_ERROR, "ITER_ERROR", UVM_INFO);
237 
238  //Check that we cannot reassign the queue that an iterator is assigned to
239  if(iter.set_queue(q2)) begin
240  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() allowed us to reassign the owner of an iterator")
241  end
242 
243  iter2_std = new;
244  iter2_hash = new;
245  //Check that we cannot assign the owner of an iterator to null
246  if(iter2_std.set_queue(null)) begin
247  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() allowed us to set owner of a std queue to null")
248  end
249  if(iter2_hash.set_queue(null)) begin
250  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() allowed us to set owner of a hash queue to null")
251  end
252 
253  //Check that we can assign queue to an iterator, but only if the iterator type matches the queue type
254  if(this.syoscb_cfgs.syoscb_cfg[0].get_queue_type() == SYOSCB_QUEUE_STD) begin
255  //Attempt to set a queue of the wrong type as the owner
256  if(iter2_hash.set_queue(q2)) begin
257  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() allowed us to assign a hash iterator to a standard queue")
258  end
259  //Check that we can assign a queue to an iterator that doesn't have an owner
260  if(!iter2_std.set_queue(q2)) begin
261  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() did not allow us to set owner of an un-owned iterator")
262  end
263  //Check that it was set by trying to reassign the owner
264  if(iter2_std.set_queue(q)) begin
265  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() did not correctly set owner of an un-owned iterator")
266  end
267  end else begin //queue type is HASH_MD5
268  //Attempt to set a queue of the wrong type as the owner
269  if(iter2_std.set_queue(q2)) begin
270  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() allowed us to assign a std iterator to a hash queue");
271  end
272  //Check that we can assign a queue to an iterator that doesn't have an owner
273  if(!iter2_hash.set_queue(q2)) begin
274  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() did not allow us to set owner of an un-owned iterator")
275  end
276  //Check that it was set by trying to reassign the owner
277  if(iter2_hash.set_queue(q)) begin
278  `uvm_error("ITER_SET_QUEUE", "iter.set_queue() did not correctly set owner of an un-owned iterator")
279  end
280  end
281 
282  void'(q.delete_iterator(iter));
283  uvm_root::get().set_report_severity_id_override(UVM_INFO, "ITER_ERROR", UVM_ERROR);
284  `uvm_info("ITER_SET_QUEUE", "iterator.set_queue() passed tests", UVM_LOW)
285 
286 endtask: check_set_queue
287 
288 /// Checks whether cl_syoscb_queue_base::get_iterator and cl_syoscb_queue_base::create_iterator correctly
289 /// create and retrieve named iterators.
290 /// It should not be possible to create two iterators with the same name, and it should not be possible
291 /// to retrieve an iterator if the name does not match any iterators.
292 task cl_scb_test_iterator_unit_tests::check_names();
293  cl_syoscb_queue_base q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q2");
294  cl_syoscb_queue_iterator_base iter = q.create_iterator("custom_name");
295 
296  //Check that we cannot create an iterator with the same name as an existing iterator
297  if(q.create_iterator("custom_name") != null) begin
298  `uvm_error("ITER_NAMES", "queue.create_iterator() allowed us to create two iterators with the same name")
299  end
300 
301  //Check that new iterators get assigned progressively larger indices
302  begin
303  cl_syoscb_queue_iterator_base iter2, iter3, iter4;
304  int iter2_idx, iter4_idx;
305  string iter2_name, iter4_name;
306  iter2 = q.create_iterator();
307  iter3 = q.create_iterator("iter3");
308  iter4 = q.create_iterator();
309 
310  iter2_name = iter2.get_name();
311  iter4_name = iter4.get_name();
312  //Must find the last 'r' to extract number
313  for(int i=iter2_name.len(); i>=0; i--) begin
314  if(iter2_name[i] == "r") begin
315  string sub = iter2_name.substr(i+1, iter2_name.len()-1);
316  iter2_idx = sub.atoi();
317  end
318  end
319  for(int i=iter4_name.len(); i>=0; i--) begin
320  if(iter4_name[i] == "r") begin
321  string sub = iter4_name.substr(i+1, iter4_name.len()-1);
322  iter4_idx = sub.atoi();
323  end
324  end
325  if(iter4_idx != iter2_idx+2) begin
326  `uvm_error("ITER_NAMES", $sformatf({"queue.create_iterator() did not use progessively larger indices for iterators\n",
327  "iterators were named %0s and %0s, indices were %0d and %0d"}, iter2_name, iter4_name, iter2_idx, iter4_idx))
328  end
329 
330  void'(q.delete_iterator(iter2));
331  void'(q.delete_iterator(iter3));
332  void'(q.delete_iterator(iter4));
333  end
334 
335  //Check that attempting to get an iterator with undefined name returns null
336  if(q.get_iterator("not_set") != null) begin
337  `uvm_error("ITER_NAMES", "queue.get_iterator() returned an iterator for a name that was not set")
338  end
339 
340  //Check that getting an iterator with the same name returns the same handle
341  if(q.get_iterator("custom_name") != iter) begin
342  `uvm_error("ITER_NAMES", "queue.get_iterator() did not return the same handle for the same name")
343  end
344 
345  //Check that deleting an iterator and then creating a new one with the same name is OK
346  void'(q.delete_iterator(iter));
347  //First, verify that it really is deleted
348  if(q.get_iterator("custom_name") != null) begin
349  `uvm_error("ITER_NAMES", "queue.get_iterator() returned an iterator after deleting it")
350  end else if(q.create_iterator("custom_name") == null) begin
351  `uvm_error("ITER_NAMES", "queue.create_iterator() was not able to create an iterator after the last iterator with same name was deleted")
352  end
353 
354  `uvm_info("ITER_NAMES", "queue.get_iterator() and queue.create_iterator() name functionality passed tests", UVM_LOW)
355 endtask: check_names
356 
357 /// When a queue is flushed, all associated iterators should be reset such that has_next/has_previous both return 0
358 task cl_scb_test_iterator_unit_tests::check_flush();
359  cl_syoscb_queue_base q;
360  cl_syoscb_queue_iterator_base iter;
361  cl_syoscb_proxy_item_base pib;
362  cl_tb_seq_item first;
363 
364  q = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
365  iter = q.create_iterator();
366 
367  //Move the iterator into the middle of the queue
368  void'(iter.first());
369  first = this.get_next(iter); //Storing a copy of the first item so we can check hash queues with ordered_next=0 behavior
370  void'(iter.next());
371  void'(iter.next());
372 
373  //And now, flush the SCB
374  this.scb_env.syoscb[0].flush_queues_all();
375 
376  //Attempts to move forward/backward should raise an error
377  if(iter.has_next()) begin
378  `uvm_error("ITER_FLUSH", "iter.has_next() returns 1 after flushing queue.");
379  end
380  if(iter.has_previous()) begin
381  `uvm_error("ITER_FLUSH", "iter.has_previous() returns 1 after flushing queue.");
382  end
383  if(iter.first()) begin
384  `uvm_error("ITER_FLUSH", "iter.first() returns 1 after flushing queue.");
385  end
386  if(iter.last()) begin
387  `uvm_error("ITER_FLUSH", "iter.last() returns 1 after flushing queue.");
388  end
389  if(iter.next_index() != 0) begin
390  `uvm_error("ITER_FLUSH", $sformatf("iter.next_index() did not return 0 after flushing queue, returned %0d", iter.next_index()))
391  end
392  if(iter.previous_index() != -1) begin
393  `uvm_error("ITER_FLUSH", $sformatf("iter.previous_index() did not return -1 after flushing queue, returned %0d", iter.next_index()))
394  end
395 
396  //Re-add items to Q1 to make other tests pass
397  for(int i=0; i<10; i++) begin
398  cl_tb_seq_item item = cl_tb_seq_item::type_id::create("item");
399  item.int_a = i;
400  this.scb_env.syoscb[0].add_item("Q1", "P1", item);
401  end
402 
403  //Should now be able to move forward again
404  if(!iter.has_next()) begin
405  `uvm_error("ITER_FLUSH", "iter.has_next() returns 0 after reinserting items.");
406  end else begin
407  cl_tb_seq_item ctsi = this.get_next(iter);
408  //By comparing first to ctsi, we also validate correctness for hash queues
409  if(ctsi.int_a != first.int_a) begin
410  `uvm_error("ITER_FLUSH", $sformatf("iter.next() did not return item with int_a=%0d after reinserting, got int_a=%0d", first.int_a, ctsi.int_a))
411  end
412  end
413 
414  void'(q.delete_iterator(iter));
415  `uvm_info("ITER_FLUSH", "Queue behavior after flushing queues passed tests", UVM_LOW)
416 
417 endtask: check_flush
418 
419 task cl_scb_test_iterator_unit_tests::main_phase(uvm_phase phase);
420  phase.raise_objection(this);
421  super.main_phase(phase);
422 
423  //Add items to Q1 that we can iterate through
424  for(int i=0; i<10; i++) begin
425  cl_tb_seq_item item = cl_tb_seq_item::type_id::create("item");
426  item.int_a = i;
427  this.scb_env.syoscb[0].add_item("Q1", "P1", item);
428  end
429 
430  this.check_flush();
431  this.check_next();
432  this.check_prev();
433  this.check_first();
434  this.check_last();
435  this.check_set_queue();
436  this.check_names();
437  `uvm_info("ITER_TESTS", "ALL TESTS PASSED", UVM_LOW)
438 
439  //Add items to Q2 to match and avoid errors
440  for(int i=0; i<10; i++) begin
441  cl_tb_seq_item item = cl_tb_seq_item::type_id::create("item");
442  item.int_a = i;
443  this.scb_env.syoscb[0].add_item("Q2", "P1", item);
444  end
445 
446  phase.drop_objection(this);
447 endtask: main_phase
task check_first()
Checks whether the cl_syoscb_queue_iterator_base::first method correctly moves through the queue...
Test containing a series of unit tests to ensure that all iterators conform to spec.
task check_names()
Checks whether cl_syoscb_queue_base::get_iterator and cl_syoscb_queue_base::create_iterator correctly...
Queue iterator base class defining the iterator API used for iterating over queues.
task check_next()
Checks whether the cl_syoscb_queue_iterator_base::next method correctly moves through the queue When ...
task check_last()
Checks whether the cl_syoscb_queue_iterator_base::last method correctly moves through the queue...
Class which represents the base concept of a queue.
task check_flush()
When a queue is flushed, all associated iterators should be reset such that has_next/has_previous bot...
task check_prev()
Checks whether the cl_syoscb_queue_iterator_base::previous method correctly moves through the queue...
task check_set_queue()
Checks whether the cl_syoscb_queue_iterator_base::set_queue method correctly sets the queue associate...

Project: SyoSil ApS UVM Scoreboard, Revision: 1.0.3.0

Copyright 2014-2022 SyoSil ApS
All Rights Reserved Worldwide

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

http://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.
doxygen
Doxygen Version: 1.8.14
Generated with IDV SV Filter Version: 2.6.3
Fri Sep 2 2022 14:37:42
Find a documentation bug? Report bugs to: scoreboard@syosil.com