SyoSil ApS UVM Scoreboard  1.0.3.0
cl_syoscb_queue_base.svh
1 /// Class which represents the base concept of a queue. All queues must extend this class
2 /// and implement the queue API.
3 class cl_syoscb_queue_base extends uvm_component;
4  //-------------------------------------
5  // Non randomizable variables
6  //-------------------------------------
7  /// Handle to the configuration
8  protected cl_syoscb_cfg cfg;
9 
10  /// List of iterators registered with this queue
12 
13  /// Semaphore guarding exclusive access to the queue when
14  /// multiple iterators are in play
15  protected semaphore iter_sem;
16 
17  /// Associative array counting the number of items by
18  /// a given producer that currently exist in the queue
19  protected int unsigned cnt_producer[string];
20 
21  /// Number of items that have been inserted into this queue
22  protected int unsigned cnt_add_item = 0;
23 
24  /// Maximum number of items that have been in this queue so far
25  protected int unsigned max_items = 0;
26 
27  /// The most recently inserted item in this queue
29 
30  /// Shadow queue tracking all items inserted into the queue, used for scoreboard dumps
32 
33  /// Number of items that have been dumped from this queue when performing a scoreboard dump
34  local int unsigned nbr_items_dumped;
35 
36  /// Associative array counting the total number of items by
37  /// a given producer that have been inserted in the queue
38  local int unsigned total_cnt_producer[string];
39 
40  /// Associative array counter the total number of items by
41  /// a given producer that have been flused form the queue
42  local int unsigned total_cnt_flushed_producer[string];
43 
44  /// AA for storing queue debug checks during the UVM check phase.
45  /// These values are used in cl_syoscb#report_phase and cl_syoscb#check_phase
46  local string failed_checks[string];
47 
48  /// The number of iterators that have been created for this queue so far
49  protected int num_iters_created = 0;
50 
51  //-------------------------------------
52  // UVM Macros
53  //-------------------------------------
54  `uvm_component_utils_begin(cl_syoscb_queue_base)
55  `uvm_field_object(cfg, UVM_DEFAULT | UVM_REFERENCE)
56  `uvm_field_aa_int_string(cnt_producer, UVM_DEFAULT | UVM_DEC)
57  `uvm_field_int(cnt_add_item, UVM_DEFAULT | UVM_DEC)
58  `uvm_field_int(max_items, UVM_DEFAULT | UVM_DEC)
59  `uvm_field_object(last_inserted_item, UVM_DEFAULT)
60  `uvm_field_queue_object(shadow_items, UVM_DEFAULT)
61  `uvm_field_int(nbr_items_dumped, UVM_DEFAULT | UVM_DEC)
62  `uvm_field_aa_int_string(total_cnt_producer, UVM_DEFAULT | UVM_DEC)
63  `uvm_field_aa_int_string(total_cnt_flushed_producer, UVM_DEFAULT | UVM_DEC)
64  `uvm_field_aa_string_string(failed_checks, UVM_DEFAULT)
65  `uvm_field_int(num_iters_created, UVM_DEFAULT | UVM_DEC)
66  `uvm_component_utils_end
67 
68  //-------------------------------------
69  // Constructor
70  //-------------------------------------
71  function new(string name, uvm_component parent);
72  super.new(name, parent);
73 
74  this.iter_sem = new(1);
75  endfunction: new
76 
77  //-------------------------------------
78  // UVM Phase methods
79  //-------------------------------------
80  extern function void build_phase(uvm_phase phase);
81  extern function void check_phase(uvm_phase phase);
82 
83  //-------------------------------------
84  // Queue API
85  //-------------------------------------
86  // Basic queue functions
87  extern virtual function bit add_item(string producer, uvm_sequence_item item);
88  extern virtual function bit delete_item(cl_syoscb_proxy_item_base proxy_item);
89  extern virtual function void dump(uvm_printer printer = null, int fd = UVM_STDOUT);
90  extern virtual function cl_syoscb_item get_item(cl_syoscb_proxy_item_base proxy_item);
91  extern virtual function int unsigned get_size();
92  extern virtual function bit empty();
93  extern virtual function bit insert_item(string producer,
94  uvm_sequence_item item,
95  int unsigned idx);
96  extern virtual function void flush_queue();
97 
98  // Iterator support functions
99  extern virtual function cl_syoscb_queue_iterator_base create_iterator(string name = "");
100  extern virtual function cl_syoscb_queue_iterator_base get_iterator(string name);
101  extern virtual function bit delete_iterator(cl_syoscb_queue_iterator_base iterator);
102 
103  // Locator support function
104  extern virtual function cl_syoscb_queue_locator_base get_locator();
105 
106  // Misc support functions
107  extern virtual function bit exists_cnt_producer(string producer);
108  extern virtual function int unsigned get_cnt_producer(string producer);
109  extern virtual function int unsigned get_cnt_add_item();
110  extern virtual function int unsigned get_max_items();
111  extern virtual function int unsigned get_cnt_flushed_item();
112  extern virtual function int unsigned get_cnt_matched_item();
113  extern virtual function cl_syoscb_item get_last_inserted_item();
114  extern virtual function cl_syoscb_cfg get_cfg();
115  extern virtual function string get_failed_checks();
116  extern virtual function string create_queue_report(int unsigned offset,
117  int unsigned first_column_width);
118 
119  //-------------------------------------
120  // Internal support functions
121  //-------------------------------------
122  extern protected virtual function cl_syoscb_item pre_add_item(string producer, uvm_sequence_item item);
123  extern protected virtual function void post_add_item(cl_syoscb_item item);
124  extern protected virtual function void do_flush_queue();
125  extern protected virtual function void incr_cnt_producer(string producer);
126  extern protected virtual function void decr_cnt_producer(string producer);
127  extern protected virtual function void dump_orphans_to_file();
128  extern protected virtual function void dump_orphans_to_stdout();
129  extern protected virtual function string create_producer_stats(int unsigned offset,
130  int unsigned first_column_width);
131  extern protected virtual function string get_dump_extension(t_dump_type dump_type);
132  extern protected virtual function void print_orphan_xml_header(int fd);
133  extern protected virtual function void print_orphan_xml_footer(int fd);
134 
135  extern virtual function void do_print(uvm_printer printer);
136  extern virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer);
137  extern virtual function void do_copy(uvm_object rhs);
138  extern virtual function void pre_abort();
139 endclass: cl_syoscb_queue_base
140 
141 /// UVM Build Phase. Gets the scoreboard configuration for this SCB
142 function void cl_syoscb_queue_base::build_phase(uvm_phase phase);
143  if (!uvm_config_db #(cl_syoscb_cfg)::get(this, "", "cfg", this.cfg)) begin
144  `uvm_fatal("CFG_ERROR", $sformatf("[%s]: Configuration object not passed.", this.cfg.get_scb_name()))
145  end
146 endfunction: build_phase
147 
148 /// UVM check phase. Checks if the queue is empty and if it had zero insertions.
149 /// If either is true, a UVM_ERROR is generated in cl_syoscb
150 function void cl_syoscb_queue_base::check_phase(uvm_phase phase);
151  // Check that this queue is empty. If not then issue an error
152  if(!this.empty()) begin
153  // *NOTE*: Using this.get_name() is sufficient since the component
154  // instance name is the queue name by definition
155  this.failed_checks["QUEUE_NOT_EMPTY"] = $sformatf("Queue %s not empty, orphans: %0d",
156  this.get_name(), this.get_size());
157 
158  //Print information regarding orphans. Potentially also dump it to file if toggled
159  if(this.cfg.get_max_print_orphans() >= 0) begin
160  this.dump_orphans_to_stdout();
161 
162  if(this.cfg.get_dump_orphans_to_files()) begin
163  this.dump_orphans_to_file();
164  end
165  end
166  end
167 
168  // Check that the queue had at least one element insertion
169  if (this.cfg.get_enable_no_insert_check && this.get_cnt_add_item === 0) begin
170  this.failed_checks["QUEUE_NO_INSERTS"] = $sformatf("Queue %s had no insertions", this.get_name());
171  end
172 endfunction: check_phase
173 
174 /// <b>Queue API:</b> Adds a uvm_sequence_item to this queue.
175 /// The basic job of the add_item method is:
176 /// -# Create the new cl_syoscb_item and give it a unique name
177 /// -# Set the producer and other metadata of the scoreboard item
178 /// -# Wrap the uvm_sequence_item inside the scoreboard item
179 /// -# Insert the item into the queue and shadow queue
180 /// -# Update the producer counter and insert counter
181 /// \param producer The producer of the sequence item
182 /// \param item The item that should be add to the queue
183 /// \return 1 if the item was successfully added, 0 otherwise
184 /// \note Abstract method. Must be implemented in a subclass
185 
186 function bit cl_syoscb_queue_base::add_item(string producer, uvm_sequence_item item);
187  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::add_item() *MUST* be overwritten", this.cfg.get_scb_name()));
188  return 1'b0;
189 endfunction: add_item
190 
191 /// <b>Queue API:</b> Deletes the item indicated by the proxy item from the queue.
192 /// The basic job of the delete_item method is:
193 /// -# Delete the element
194 /// -# Notify any iterators, moving them as necessary
195 /// -# Update the producer counter for the deleted item's producer
196 /// \param proxy_item A proxy item indicating which scoreboard item to delete from the queue
197 /// \return if the item was successfully deleted, 0 otherwise
198 /// \note Abstract method. Must be implemented in a subclass
199 
200 function bit cl_syoscb_queue_base::delete_item(cl_syoscb_proxy_item_base proxy_item);
201  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::delete_item() *MUST* be overwritten", this.cfg.get_scb_name()));
202  return 1'b0;
203 endfunction: delete_item
204 
205 /// Perform some basic bookkeeping that is the same for all sequence items before insertion.
206 /// Generates the scoreboard wrapper item
207 /// \param producer The producer of this item
208 /// \param item The item to be inserted into the scoreboard
209 /// \return A scoreboard item, wrapping the given sequence item
210 function cl_syoscb_item cl_syoscb_queue_base::pre_add_item(string producer, uvm_sequence_item item);
211  cl_syoscb_item new_item;
212 
213  //Create a new scoreboard item with metadata that wraps the seq. item.
214  //Don't need to use type_id::create since we require no customization here
215  //Once created with default name, we can assign unique name using instance id
216  new_item = new;
217  new_item.set_name({producer,"-item-", $psprintf("%0d", new_item.get_inst_id())});
218 
219  //Assign producer to scoreboard item, assign metadata fields
220  new_item.set_item(item);
221  new_item.set_producer(producer);
222  new_item.set_insertion_index(this.cnt_add_item);
223 
224  return new_item;
225 
226 endfunction: pre_add_item
227 
228 /// Perform some basic bookkeping that is the same for all sequence items after insertion
229 /// \param item The scoreboard item that has been inserted into the scoreboard
230 function void cl_syoscb_queue_base::post_add_item(cl_syoscb_item item);
231  if(this.cfg.get_full_scb_dump()) begin
232  this.shadow_items.push_back(item);
233  end
234  this.last_inserted_item = item;
235  this.incr_cnt_producer(item.get_producer());
236  this.cnt_add_item++;
237  if(this.get_size() > this.max_items) begin
238  this.max_items = this.get_size();
239  end
240 endfunction: post_add_item
241 
242 /// <b>Queue API:</b> Gets the item pointed to by the proxy item from the queue.
243 /// If the proxy item does not specify a valid item in the queue, print a UVM_INFO/DEBUG message
244 /// \param proxy_item A proxy item indicating which scoreboard item to delete from the queue
245 /// \return The scoreboard item indicated by the proxy item, null if the proxy item did not point to a valid item
246 /// \note Abstract method. Must be implemented in a subclass
247 
248 function cl_syoscb_item cl_syoscb_queue_base::get_item(cl_syoscb_proxy_item_base proxy_item);
249  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::get_item() *MUST* be overwritten", this.cfg.get_scb_name()));
250  return null;
251 endfunction: get_item
252 
253 /// <b>Queue API:</b> Returns the current size of the queue.
254 /// \return Number of items currently in the queue
255 /// \note Abstract method. Must be implemented in a subclass
256 
257 function int unsigned cl_syoscb_queue_base::get_size();
258  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::get_size() *MUST* be overwritten", this.cfg.get_scb_name()));
259  return 0;
260 endfunction: get_size
261 
262 /// <b>Queue API:</b> Returns whether or not the queue is empty.
263 /// \return 1 if the queue is empty, 0 otherwise
264 /// \note Abstract method. Must be implemented in a subclass
265 
267  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::empty() *MUST* be overwritten", this.cfg.get_scb_name()));
268  return 0;
269 endfunction: empty
270 
271 /// <b>Queue API:</b> Inserts a uvm_sequence_item at index idx.
272 /// The method works in the same manner as #add_item, by doing the following:
273 /// -# Insert the a new item as the add_item() method
274 /// -# Notify any iterators
275 /// \param producer The producer of the sequence item
276 /// \param item The item that should be add to the queue
277 /// \param idx The index at which the item should be inserted
278 /// \return 1 if the item was successfully inserted, 0 otherwise
279 /// \note Abstract method. Must be implemented in a subclass
280 
281 function bit cl_syoscb_queue_base::insert_item(string producer, uvm_sequence_item item, int unsigned idx);
282  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::insert_item() *MUST* be overwritten", this.cfg.get_scb_name()));
283  return 1'b0;
284 endfunction: insert_item
285 
286 /// <b>Queue API:</b> Deletes all elements from the queue.
287 /// Updates the flush counter, sets all producer counts to 0 and resets all iterators.
289  string producers[];
290 
291  this.cfg.get_producers(producers);
292 
293  foreach (producers[i]) begin
294  if(this.cnt_producer.exists(producers[i])) begin
295  this.total_cnt_flushed_producer[producers[i]] += this.cnt_producer[producers[i]];
296  this.cnt_producer[producers[i]] = 0;
297  end
298  end
299 
300  //Reset all iterators
301  while(this.iter_sem.try_get() == 0);
302  foreach(this.iterators[i]) begin
303  void'(this.iterators[i].first());
304  end
305  this.iter_sem.put();
306  this.do_flush_queue();
307 endfunction: flush_queue
308 
309 /// Performs the actual element deletion from the queue when called by #flush_queue
311  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue::do_flush_queue() *MUST* be overwritten", this.cfg.get_scb_name()));
312 endfunction: do_flush_queue
313 
314 /// <b>Queue API:</b> Creates an iterator for this queue.
315 /// Iterators are by default named "[name]_iter[X]", where [name] is the name of the queue, and [X]
316 /// is the number of iterators that have previusly been created for this queue
317 /// \param name A name to be used for the iterator. If an iterator with this name already exists,
318 /// prints a UVM_DEBUG message
319 /// \return An iterator over this queue, or null if a queue with the requested name already exists
321  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::create_iterator() *MUST* be overwritten", this.cfg.get_scb_name()));
322  return null;
323 endfunction: create_iterator
324 
325 /// <b>Queue API:</b> Gets the iterator from this queue with a given name.
326 /// If no queue exists with that name, returns null
327 /// \param name The name of the queue to lookup
328 /// \return That iterator, if it exists, or null if no such queue exists
329 /// \note Will raise a UVM_ERROR if multiple iterators with the same name exist
332  f = this.iterators.find_index() with (item.get_name() == name);
333  if(f.size() > 1) begin
334  `uvm_error("ITERATOR_ERROR", $sformatf("[%0s]: Found %0d iterators with the same name (%0s), don't know what to do", this.cfg.get_scb_name(), f.size(), name))
335  end else if (f.size() == 1) begin
336  return f[0];
337  end else begin
338  return null;
339  end
340 endfunction: get_iterator
341 
342 /// <b>Queue API:</b> Deletes an iterator from this queue.
343 /// \param iterator The iterator to delete
344 /// \return 1 if the iterator was successfully deleted, 0 otherwise
345 function bit cl_syoscb_queue_base::delete_iterator(cl_syoscb_queue_iterator_base iterator);
346  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::delete_item() *MUST* be overwritten", this.cfg.get_scb_name()));
347  return 1'b0;
348 endfunction: delete_iterator
349 
350 /// <b>Queue API:</b> Creates a locator for this queue.
351 /// \return A locator over this queue
353  `uvm_fatal("IMPL_ERROR", $sformatf("[%s]: cl_syoscb_queue_base::get_locator() *MUST* be overwritten", this.cfg.get_scb_name()));
354  return null;
355 endfunction: get_locator
356 
357 function cl_syoscb_cfg cl_syoscb_queue_base::get_cfg();
358  return this.cfg;
359 endfunction: get_cfg
360 
361 /// Increment the producer counter for a given producer.
362 /// \param producer The producer to increment the counter for
363 function void cl_syoscb_queue_base::incr_cnt_producer(string producer);
364  // Reset counter if the producer does not exist
365  if(!this.cnt_producer.exists(producer)) begin
366  this.cnt_producer[producer] = 0;
367  this.total_cnt_producer[producer] = 0;
368  this.total_cnt_flushed_producer[producer] = 0;
369  end
370 
371  // Increment the producer count
372  this.cnt_producer[producer] = this.cnt_producer[producer]+1;
373 
374  // Increment the total producer count
375  this.total_cnt_producer[producer] = this.total_cnt_producer[producer]+1;
376 endfunction: incr_cnt_producer
377 
378 /// Decrement the producer counter for a given producer
379 /// \param producer The producer to decrement the counter for
380 function void cl_syoscb_queue_base::decr_cnt_producer(string producer);
381  if(!this.cnt_producer.exists(producer)) begin
382  `uvm_fatal("QUEUE_ERROR", $sformatf("[%s]: Trying to decrement a non-existing producer: %s ", this.cfg.get_scb_name(), producer));
383  end
384 
385  if(this.cnt_producer[producer] == 0) begin
386  `uvm_fatal("QUEUE_ERROR", $sformatf("[%s]: Trying to decrement the producer: %s which has count 0", this.cfg.get_scb_name(), producer));
387  end
388 
389  this.cnt_producer[producer] = this.cnt_producer[producer]-1;
390 endfunction: decr_cnt_producer
391 
392 /// <b>Queue API</b>: Check if a given producer exists in the producer counter for this queue
393 /// \param producer The producer to check for existence
394 /// 1 if the producer exists, 0 otherwise
395 function bit cl_syoscb_queue_base::exists_cnt_producer(string producer);
396  return this.cnt_producer.exists(producer);
397 endfunction: exists_cnt_producer
398 
399 /// <b>Queue API</b>: Get the producer count for a given producer.
400 /// \param producer The producer to get count for
401 /// \return The number of items in the queue that were from the given producer
402 /// \note May *ONLY* be called if the producer exists (see #exists_cnt_producer)
403 function int unsigned cl_syoscb_queue_base::get_cnt_producer(string producer);
404  return this.cnt_producer[producer];
405 endfunction: get_cnt_producer
406 
407 /// <b>Queue API</b>: Returns the number of items that have been inserted in this queue
409  return this.cnt_add_item;
410 endfunction: get_cnt_add_item
411 
412 /// <b>Queue API</b>: Returns the maximum number of elements that have been in the queue.
413 function int unsigned cl_syoscb_queue_base::get_max_items();
414  return this.max_items;
415 endfunction: get_max_items
416 
417 /// <b>Queue API</b>: Returns the total number of elements flushed from this queue.
419  return this.total_cnt_flushed_producer.sum();
420 endfunction: get_cnt_flushed_item
421 
422 /// <b>Queue API</b>: Returns the total number of elements matched in this queue
424  return this.cnt_add_item - (this.get_cnt_flushed_item()+this.get_size());
425 endfunction: get_cnt_matched_item
426 
427 /// <b>Queue API</b>: Gets the last inserted item in the queue
429  return this.last_inserted_item;
430 endfunction : get_last_inserted_item
431 
432 /// <b>Queue API</b>: Loop over all the items in the shadow queue and dump them.
433 /// If a printer has not been passed in the arguments, used cl_syoscb_cfg#get_printer to lookup a printer for each shadow item
434 /// (which may be quite inefficient).
435 /// If cl_syoscb_cfg#full_scb_type has been set to XML, the XML printer is used, overriding any specific printers that have been set
436 /// \param printer The printer to use when dumping items. Defaults to null, getting a queue/producer specific printer for each item
437 /// \param fd File descriptor for where to dump items. Defaults to STDOUT
438 function void cl_syoscb_queue_base::dump(uvm_printer printer = null, int fd = UVM_STDOUT);
439  //Have to use a separate printer variable to ensure that correct queue/producer
440  //printer is used on every iteration if input printer is null.
441  //otherwise, shadow_items[1] will use the printer set when parsing shadow_items[0].
442  uvm_printer printer_used;
443 
444  if(this.cfg.get_full_scb_dump() == 1'b0) begin
445  `uvm_fatal("CFG_ERROR", "Cannot dump queue contents when get_full_scb_dump is disabled")
446  return;
447  end
448 
449  if(this.cfg.get_full_scb_dump_type() == pk_syoscb::XML) begin
450  uvm_xml_printer xp = new;
451  printer_used = xp;
452  end
453 
454  foreach(this.shadow_items[i])begin
455  this.shadow_items[i].set_queue_index(-1); //Queue index has no meaning when performing scb dump
456 
457  case (this.cfg.get_full_scb_dump_type())
458  pk_syoscb::TXT: begin //Print text header, look up printer based on queue name and producer name
459  $fwrite (fd, $sformatf("\n//--item: %9d -------------------------------//\n",this.nbr_items_dumped++));
460 
461  //If a printer has been passed in the argument, use that. If not, try to get a queue/producer specific printer
462  printer_used = (printer != null) ? printer : this.cfg.get_printer(this.get_name(), this.shadow_items[i].get_producer());
463  if(printer_used == null) begin
464  printer_used = this.cfg.get_default_printer();
465  end
466  end
467  pk_syoscb::XML: begin //Print XML header
468  $fwrite (fd, $sformatf("\n<!-- item: %9d -->\n",this.nbr_items_dumped++));
469  end
470  endcase
471  cl_syoscb_printer_config::set_file_descriptor(printer_used, fd);
472 
473  if(this.cfg.get_full_scb_dump_type() == pk_syoscb::TXT && this.cfg.get_enable_c2s_full_scb_dump()) begin //Only in this case should we use convert2string
474  $fwrite(fd, {this.shadow_items[i].convert2string(), "\n"});
475  end else begin
476  this.shadow_items[i].print(printer_used);
477  end
478  end
479  this.shadow_items.delete();
480 endfunction: dump
481 
482 /// Prints orphans remaining in the queue to stdout.
483 /// The number of orphans that are printed depends on cl_syoscb_cfg#max_print_orphans
484 function void cl_syoscb_queue_base::dump_orphans_to_stdout();
485  cl_syoscb_queue_iterator_base l_iterator;
486  cl_syoscb_item l_scb_item;
487  cl_syoscb_proxy_item_base l_proxy_item;
488  int fd;
489  uvm_printer printer;
490 
491  if(this.cfg.get_max_print_orphans() < 0) begin
492  return;
493  end
494 
495  l_iterator = this.create_iterator();
496  void'(l_iterator.first());
497 
498  //Using (A -> B) operator below. If A=true, evaluates B. If A=false, always returns true
499  while(l_iterator.has_next() &&
500  (this.cfg.get_max_print_orphans() > 0 -> (l_iterator.next_index() < this.cfg.get_max_print_orphans()))) begin
501 
502  l_proxy_item = l_iterator.next();
503  l_scb_item = l_proxy_item.get_item();
504  l_scb_item.set_queue_index(l_iterator.previous_index());
505 
506  //Print to stdout
507  if(this.cfg.get_orphans_as_errors()) begin
508  `uvm_error(this.get_name(), $sformatf("\n%s", l_scb_item.sprint()))
509  end
510  else begin
511  `uvm_info(this.get_name(), $sformatf("\n%s", l_scb_item.sprint()), UVM_NONE)
512  end
513  end
514 
515  void'(this.delete_iterator(l_iterator));
516 
517 endfunction: dump_orphans_to_stdout
518 
519 /// Dumps orphans remaining in the queue into a logfile.
520 /// Assumes that the caller has checked whether cl_syoscb_cfg#dump_orphans_to_files is set
521 function void cl_syoscb_queue_base::dump_orphans_to_file();
522  cl_syoscb_queue_iterator_base l_iterator;
523  cl_syoscb_item l_scb_item;
524  cl_syoscb_proxy_item_base l_proxy_item;
525  int fd;
526  uvm_printer printer;
527  string ext;
528 
529  if(this.cfg.get_max_print_orphans() < 0) begin
530  return;
531  end
532 
533  ext = this.get_dump_extension(this.cfg.get_orphan_dump_type());
534  fd = $fopen($sformatf("%s.%s.%s_orphans.%s", this.cfg.get_scb_name(), this.cfg.get_orphan_dump_file_name(), this.get_name(), ext), "w");
535 
536  //Get XML printer already if toggled
537  if(this.cfg.get_orphan_dump_type() == pk_syoscb::XML) begin
538  uvm_xml_printer xp = new;
539  printer = xp;
540  cl_syoscb_printer_config::set_file_descriptor(printer, fd);
541  this.print_orphan_xml_header(fd);
542  end
543 
544  l_iterator = this.create_iterator();
545  void'(l_iterator.first());
546 
547  while(l_iterator.has_next() &&
548  (this.cfg.get_max_print_orphans() > 0 -> (l_iterator.next_index() < this.cfg.get_max_print_orphans()))) begin
549 
550  l_proxy_item = l_iterator.next();
551  l_scb_item = l_proxy_item.get_item();
552  l_scb_item.set_queue_index(l_iterator.previous_index());
553 
554  //Get queue/producer specific printer if output is TXT.
555  //If XML, we've already obtained the printer and set output file handle above
556  if(this.cfg.get_orphan_dump_type() == pk_syoscb::TXT) begin
557  printer = this.cfg.get_printer(this.get_name(), l_scb_item.get_producer());
558  //If no printer set, get default
559  printer = (printer != null) ? printer : this.cfg.get_default_printer();
560  cl_syoscb_printer_config::set_file_descriptor(printer, fd);
561  end
562 
563  l_scb_item.print(printer);
564  end
565 
566  if(this.cfg.get_orphan_dump_type() == pk_syoscb::XML) begin
567  this.print_orphan_xml_footer(fd);
568  end
569  $fclose(fd);
570 
571  void'(this.delete_iterator(l_iterator));
572 endfunction: dump_orphans_to_file
573 
574 /// <b>Queue API</b>: Gets a string containing all queue checks that this queue have failed.
575 /// Failed checks include having orphans at the end of simulation, and not having any insertions
576 /// \return A string containing all failed checks for this queue
577 function string cl_syoscb_queue_base::get_failed_checks();
578  if(this.failed_checks.size() == 0) begin
579  return "";
580  end else begin
581  string failed_checks_str;
582 
583  foreach(this.failed_checks[str]) begin
584  failed_checks_str = { failed_checks_str, " ", str, ": ", failed_checks[str], "\n"};
585  end
586 
587  return failed_checks_str;
588  end
589 endfunction: get_failed_checks
590 
591 /// Returns a table with statistics for all producers in this queue.
592 /// Outputs the number of insertions, matches, flushed items and orphans per-producer.
593 /// \param offset The x-offset that should be used when printing producer names
594 /// \param first_column_width The width of the first column in the table
595 /// \return A string containing producer stats for all producers in this queue.
596 // Producer name | Inserts | Matches | Flushed | Orphans
597 function string cl_syoscb_queue_base::create_producer_stats(int unsigned offset, int unsigned first_column_width);
598  string producers[];
599  string producer_stats;
600 
601  this.cfg.get_producers(producers);
602 
603  foreach (producers[i]) begin
604  if(this.total_cnt_producer.exists(producers[i])) begin
605  producer_stats = { producer_stats,
606  "\n",
607  $sformatf("%s%s | %8d | %8d | %8d | %8d |",
608  cl_syoscb_string_library::pad_str("", offset),
609  cl_syoscb_string_library::pad_str(producers[i], first_column_width, " ", 1'b1),
610  this.total_cnt_producer[producers[i]],
611  this.total_cnt_producer[producers[i]]-(this.total_cnt_flushed_producer[producers[i]]+this.cnt_producer[producers[i]]),
612  this.total_cnt_flushed_producer[producers[i]],
613  this.cnt_producer[producers[i]])};
614  end else begin
615  producer_stats = { producer_stats,
616  "\n",
617  $sformatf("%s%s | %8d | %8d | %8d | %8d |",
618  cl_syoscb_string_library::pad_str("", offset),
619  cl_syoscb_string_library::pad_str(producers[i], first_column_width, " ", 1'b1),
620  0,
621  0,
622  0,
623  0)};
624  end
625  end
626 
627  return producer_stats;
628 endfunction: create_producer_stats
629 
630 /// <b>Queue API</b>: Returns a string with overall queues statistics.
631 /// Reports the number of insertions, matches, flushed items and orphans.
632 /// If cl_syoscb_cfg#enable_queue_stats is 1, also includes per-producer statistics (see #create_producer_stats)
633 /// \param offset The x-offset that should be used when printing the queue name names
634 /// \param first_column_width The width of the first column in the table
635 /// \return A string containing overall queues statistics.
636 // | Queue name | Inserts | Matches | Flushed | Orphans |
637 // | Producer X | Inserts | Matches | Flushed | Orphans | (only if enable_queue_stats is toggled for this queue)
638 function string cl_syoscb_queue_base::create_queue_report(int unsigned offset, int unsigned first_column_width);
639  string stats_str;
640  stats_str = { stats_str,
641  "\n",
642  $sformatf("%s%s | %8d | %8d | %8d | %8d |",
643  cl_syoscb_string_library::pad_str("", offset),
644  cl_syoscb_string_library::pad_str(this.get_name(), first_column_width, " ", 1'b1),
645  this.get_cnt_add_item(),
646  this.get_cnt_matched_item(),
647  this.get_cnt_flushed_item(),
648  this.get_size())};
649  if(this.cfg.get_enable_queue_stats(this.get_name())) begin
650  stats_str = {stats_str, this.create_producer_stats(offset+pk_syoscb::GLOBAL_REPORT_INDENTION, first_column_width-pk_syoscb::GLOBAL_REPORT_INDENTION)};
651  end
652 
653  return stats_str;
654 endfunction: create_queue_report
655 
656 /// Gets the file extension to be used for a dump file.
657 /// \param dump_type The type of dump that should be performed.
658 /// \return A string with the file extension that should be used for that kind of dump
659 function string cl_syoscb_queue_base::get_dump_extension(t_dump_type dump_type);
660  string r;
661  case (dump_type)
662  pk_syoscb::TXT: r = "txt";
663  pk_syoscb::XML: r = "xml";
664  default: `uvm_fatal("CFG_ERROR", $sformatf("No file extension associated with dump type %0s/%0d", dump_type.name(), dump_type))
665  endcase
666  return r;
667 endfunction: get_dump_extension
668 
669 /// Prints the header for an XML orphan dump.
670 ///
671 /// \param fd File descriptor for the file to write the header into
672 function void cl_syoscb_queue_base::print_orphan_xml_header(int fd);
673  string header;
674  header = {
675  "<?xml version='1.0' encoding='UTF-8'?>\n",
676  "<scb name='", this.cfg.get_scb_name(), " orphans'>\n",
677  "<queues>\n",
678  "<queue name='", this.get_name(), "'>\n",
679  "<items>\n"
680  };
681 
682  $fwrite(fd, header);
683 endfunction: print_orphan_xml_header
684 
685 /// Prints the footer for an XML orphan dump.
686 ///
687 /// \param fd File descriptor for the file to write the header into
688 function void cl_syoscb_queue_base::print_orphan_xml_footer(int fd);
689  string footer;
690  footer = {
691  "</items>\n",
692  "</queue>\n",
693  "</queues>\n",
694  "</scb>\n"
695  };
696  $fwrite(fd, footer);
697 endfunction: print_orphan_xml_footer
698 
699 // Custom do_print implementation for the iterators in the AA,
700 // in order to print the registered iterators' basic information only
701 function void cl_syoscb_queue_base::do_print(uvm_printer printer);
702  cl_syoscb_queue_iterator_base l_iterator;
703 
704  if(this.iterators.first(l_iterator)) begin
705  printer.print_generic(.name("iterators"),
706  .type_name("-"),
707  .size(this.iterators.size()),
708  .value("-"));
709  do begin
710  printer.print_generic(.name($sformatf(" [%s]", l_iterator.get_name())),
711  .type_name("cl_syoscb_iterator"),
712  .size(l_iterator == null ? 0 :1),
713  .value(l_iterator == null? "<null>" : $sformatf("<%0d>",
714  l_iterator.get_inst_id())));
715  end
716  while(this.iterators.next(l_iterator));
717  end
718 
719  super.do_print(printer);
720 endfunction: do_print
721 
722 // Custom do_compare implementation in order to compare if both queues have the same iterators registered
723 function bit cl_syoscb_queue_base::do_compare(uvm_object rhs, uvm_comparer comparer);
724  cl_syoscb_queue_base rhs_cast;
725  bit compare_result = super.do_compare(rhs, comparer);
726 
727  if(!$cast(rhs_cast, rhs))begin
728  `uvm_fatal("do_compare",
729  $sformatf("The given object argument is not %0p type", rhs_cast.get_type()))
730  return 0;
731  end
732 
733  // Check if both itrerators associative arrays have the same size
734  if(rhs_cast.iterators.size() != this.iterators.size()) begin
735  return 0;
736  end
737  else begin
738  // Here size are equal. Now check if both queues are registered with the same iterators.
739  // Since both aa should be equal, they should also have the same items indexed by the same key
740  // in the same position inside them. For this reason, looping using the foreach should be ok.
741  foreach(this.iterators[i]) begin
742  compare_result &= comparer.compare_object($sformatf("%0s", this.iterators[i].get_name()),
743  this.iterators[i],
744  rhs_cast.iterators[i]);
745  end
746  end
747 
748  return compare_result;
749 endfunction: do_compare
750 
751 // Custom do_copy implementation for iterators in the AA in order
752 // to correctly clone each registered iterator from rhs queue
753 function void cl_syoscb_queue_base::do_copy(uvm_object rhs);
754  cl_syoscb_queue_base rhs_cast;
755 
756  if(!$cast(rhs_cast, rhs))begin
757  `uvm_fatal("do_copy",
758  $sformatf("The given object argument is not %0p type", rhs_cast.get_type()))
759  end
760 
761  // Delete the aa content because this queue_base might be used before calling the copy
762  // method. on the other hand, the result of this.copy(rhs), should override each field values
763  // without keeping memory on what was before.
764  this.iterators.delete();
765 
766  foreach(rhs_cast.iterators[i]) begin
767  cl_syoscb_queue_iterator_base l_iterator;
768 
769  // Need to clone each rhs_cast.iterators[i] since they cannot be shared within queues
770  if(!$cast(l_iterator, rhs_cast.iterators[i].clone())) begin
771  `uvm_fatal("do_copy",
772  $sformatf("Clone of iterator: '%0s' failed!", rhs_cast.iterators[i].get_name()))
773  end
774 
775  this.iterators[l_iterator] = l_iterator;
776  end
777 
778  super.do_copy(rhs);
779 endfunction: do_copy
780 
781 // Implements the pre_abort hook, performing orphan dumping and shadow queue dumping if enabled,
782 // before the simulation finishes due to an error
783 function void cl_syoscb_queue_base::pre_abort();
784  if(this.cfg.get_dump_orphans_to_files()) begin
785  this.dump_orphans_to_file();
786  end
787 endfunction: pre_abort
virtual cl_syoscb_item get_last_inserted_item()
Queue API: Gets the last inserted item in the queue
cl_syoscb_item shadow_items[$]
Shadow queue tracking all items inserted into the queue, used for scoreboard dumps.
virtual string create_producer_stats(int unsigned offset, int unsigned first_column_width)
Returns a table with statistics for all producers in this queue.
cl_syoscb_queue_iterator_base iterators[cl_syoscb_queue_iterator_base]
List of iterators registered with this queue.
virtual void incr_cnt_producer(string producer)
Increment the producer counter for a given producer.
virtual void dump(uvm_printer printer=null, int fd=UVM_STDOUT)
Queue API: Loop over all the items in the shadow queue and dump them.
virtual void post_add_item(cl_syoscb_item item)
Perform some basic bookkeping that is the same for all sequence items after insertion.
The UVM scoreboard item which wraps uvm_sequence_item .
virtual cl_syoscb_queue_iterator_base get_iterator(string name)
Queue API: Gets the iterator from this queue with a given name.
virtual void dump_orphans_to_stdout()
Prints orphans remaining in the queue to stdout.
virtual bit delete_item(cl_syoscb_proxy_item_base proxy_item)
Queue API: Deletes the item indicated by the proxy item from the queue.
cl_syoscb_item last_inserted_item
The most recently inserted item in this queue.
virtual bit exists_cnt_producer(string producer)
Queue API: Check if a given producer exists in the producer counter for this queue ...
An XML printer for cl_syoscb_items.
int unsigned cnt_add_item
Number of items that have been inserted into this queue.
virtual void flush_queue()
Queue API: Deletes all elements from the queue.
virtual void do_flush_queue()
Performs the actual element deletion from the queue when called by flush_queue.
virtual int unsigned get_cnt_matched_item()
Queue API: Returns the total number of elements matched in this queue
virtual void dump_orphans_to_file()
Dumps orphans remaining in the queue into a logfile.
virtual void decr_cnt_producer(string producer)
Decrement the producer counter for a given producer.
virtual int unsigned get_cnt_add_item()
Queue API: Returns the number of items that have been inserted in this queue
Locator base class defining the locator API used for searching in queues.
virtual string get_failed_checks()
Queue API: Gets a string containing all queue checks that this queue have failed. ...
virtual string create_queue_report(int unsigned offset, int unsigned first_column_width)
Queue API: Returns a string with overall queues statistics.
semaphore iter_sem
Semaphore guarding exclusive access to the queue when multiple iterators are in play.
virtual bit insert_item(string producer, uvm_sequence_item item, int unsigned idx)
Queue API: Inserts a uvm_sequence_item at index idx.
Queue iterator base class defining the iterator API used for iterating over queues.
virtual cl_syoscb_item pre_add_item(string producer, uvm_sequence_item item)
Perform some basic bookkeeping that is the same for all sequence items before insertion.
int unsigned nbr_items_dumped
Number of items that have been dumped from this queue when performing a scoreboard dump...
virtual void print_orphan_xml_header(int fd)
Prints the header for an XML orphan dump.
Class which represents the base concept of a queue.
virtual int unsigned get_cnt_flushed_item()
Queue API: Returns the total number of elements flushed from this queue.
void build_phase(uvm_phase phase)
UVM Build Phase. Gets the scoreboard configuration for this SCB.
virtual cl_syoscb_queue_iterator_base create_iterator(string name="")
Queue API: Creates an iterator for this queue.
virtual string get_dump_extension(t_dump_type dump_type)
Gets the file extension to be used for a dump file.
virtual int unsigned get_max_items()
Queue API: Returns the maximum number of elements that have been in the queue.
virtual int unsigned get_cnt_producer(string producer)
Queue API: Get the producer count for a given producer.
int num_iters_created
The number of iterators that have been created for this queue so far.
void check_phase(uvm_phase phase)
UVM check phase.
string failed_checks[string]
AA for storing queue debug checks during the UVM check phase.
virtual bit delete_iterator(cl_syoscb_queue_iterator_base iterator)
Queue API: Deletes an iterator from this queue.
virtual bit empty()
Queue API: Returns whether or not the queue is empty.
cl_syoscb_cfg cfg
Handle to the configuration.
virtual cl_syoscb_queue_locator_base get_locator()
Queue API: Creates a locator for this queue.
virtual bit add_item(string producer, uvm_sequence_item item)
Queue API: Adds a uvm_sequence_item to this queue.
Configuration class for the SyoSil UVM scoreboard.
int unsigned max_items
Maximum number of items that have been in this queue so far.
virtual void print_orphan_xml_footer(int fd)
Prints the footer for an XML orphan dump.
virtual cl_syoscb_item get_item(cl_syoscb_proxy_item_base proxy_item)
Queue API: Gets the item pointed to by the proxy item from the queue.
int unsigned cnt_producer[string]
Associative array counting the number of items by a given producer that currently exist in the queue...
int unsigned total_cnt_flushed_producer[string]
Associative array counter the total number of items by a given producer that have been flused form th...
virtual int unsigned get_size()
Queue API: Returns the current size of the queue.
int unsigned total_cnt_producer[string]
Associative array counting the total number of items by a given producer that have been inserted in t...

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:39:37
Find a documentation bug? Report bugs to: scoreboard@syosil.com