SyoSil ApS UVM Scoreboard  1.0.3.0
cl_syoscb_queue_hash.svh
1 /// Class which represents the base concept of a hash queue.
2 /// All hash queues must extend this class and implement the queue API.
3 class cl_syoscb_queue_hash #(int unsigned HASH_DIGEST_WIDTH = 1) extends cl_syoscb_queue_base;
4 
5  ///Typedef for hash algorithm digests
6  typedef cl_syoscb_hash_base#(HASH_DIGEST_WIDTH)::tp_hash_digest tp_digest;
7 
8  /// Typedef for struct used to track items and their digests in the key queue.
9  /// Only used when cl_syoscb_cfg.ordered_next=1
10  typedef struct {
11  cl_syoscb_item item;
12  tp_digest digest;
14 
15  /// Typedef for queue of digests and items
16  typedef tp_item_digest tp_queue_of_keys[$];
17 
18  /// Typedef for parameterized AA wrapper
19  typedef cl_syoscb_hash_aa_wrapper#(HASH_DIGEST_WIDTH) tp_aa_hash;
20 
21  /// Typedef for struct representing whether an option with an iterator was valid
22  typedef struct packed{
23  bit valid;
24  tp_digest digest;
26 
27 
28  //-------------------------------------
29  // Non randomizable variables
30  //-------------------------------------
31  /// Handle to the implemented hash algorithm
32  protected cl_syoscb_hash_base#(HASH_DIGEST_WIDTH) hash_algo;
33 
34  /// Queue implementation with an assosiative array. Wrapped in a class for performance reasons
35  protected cl_syoscb_hash_aa_wrapper#(HASH_DIGEST_WIDTH) hash;
36 
37  /// List of hash values of the items in the queue.
38  /// Only used if cl_syoscb_cfg#ordered_next is 1.
39  protected tp_item_digest key_queue[$];
40 
41  /// Size of queue, stored here to optimize for speed
42  protected int unsigned size;
43 
44  //-------------------------------------
45  // UVM Macros
46  //-------------------------------------
47  `uvm_component_param_utils_begin(cl_syoscb_queue_hash#(HASH_DIGEST_WIDTH))
48  `uvm_field_object(hash, UVM_DEFAULT)
49  `uvm_field_object(hash_algo,UVM_DEFAULT)
50  `uvm_field_int(size, UVM_DEFAULT)
51  `uvm_component_utils_end
52 
53  //-------------------------------------
54  // Constructor
55  //-------------------------------------
56  extern function new(string name, uvm_component parent);
57 
58  //-------------------------------------
59  // Queue API
60  //-------------------------------------
61  // Basic queue functions
62  extern virtual function bit add_item(string producer, uvm_sequence_item item);
63  extern virtual function bit delete_item(cl_syoscb_proxy_item_base proxy_item);
64  extern virtual function cl_syoscb_item get_item(cl_syoscb_proxy_item_base proxy_item);
65  extern virtual function int unsigned get_size();
66  extern virtual function bit empty();
67  extern virtual function bit insert_item(string producer,
68  uvm_sequence_item item,
69  int unsigned idx);
70 
71  // Iterator support functions
72  extern virtual function bit delete_iterator(cl_syoscb_queue_iterator_base iterator);
73 
74  // Hash queue functions
75  extern virtual function tp_queue_of_keys get_key_queue();
76  extern virtual function tp_aa_hash get_hash();
77 
78  // Misc support functions
79  extern protected virtual function void do_flush_queue();
80  // The UVM function do_copy() *MUST* be implemented inside every derived class, since this one
81  // is only implementing the API for a generic hash queue and it cannot be directlty instantiated.
82 endclass: cl_syoscb_queue_hash
83 
84 function cl_syoscb_queue_hash::new(string name, uvm_component parent);
85  super.new(name, parent);
86  this.hash = new;
87 endfunction: new
88 
89 /// <b>Queue API:</b> See cl_syoscb_queue_base#add_item for more details
90 function bit cl_syoscb_queue_hash::add_item(string producer, uvm_sequence_item item);
91  cl_syoscb_item new_item;
92  tp_digest digest;
93 
94  new_item = this.pre_add_item(producer, item);
95 
96  // Insert the item in the queue
97  // Generate hash, check for collision. If collision, add to queue on that hash item
98  // otherwise, generate new hash itme with only this element
99  digest=this.hash_algo.hash(new_item);
100  this.hash.insert(digest, new_item);
101 
102  if(this.cfg.get_ordered_next() == 1) begin
103  this.key_queue.push_back('{new_item, digest});
104  end
105 
106  this.post_add_item(new_item);
107  this.size++;
108 
109  // Signal that it worked
110  return 1'b1;
111 endfunction: add_item
112 
113 /// <b>Queue API:</b> See cl_syoscb_queue_base#insert_item for more details
114 function bit cl_syoscb_queue_hash::insert_item(string producer, uvm_sequence_item item, int unsigned idx);
115  cl_syoscb_item new_item;
116  tp_digest digest;
117 
118  if(!this.cfg.get_ordered_next()) begin
119  `uvm_fatal("CFG_ERROR", "Cannot use insert_item() on hash queues when cfg.ordered_next is disabled")
120  return 1'b0;
121  end else if(idx > this.get_size()) begin //Check immediatedly if index is too large
122  `uvm_info("OUT_OF_BOUNDS", $sformatf("[%s] Idx %0d too large for insertion into queue %0s", this.cfg.get_scb_name(), idx, this.get_name()), UVM_DEBUG)
123  return 1'b0;
124  end
125 
126  new_item = this.pre_add_item(producer, item);
127  digest = this.hash_algo.hash(new_item);
128 
129  //Update order of key queue
130  if(idx < this.get_size()) begin
132 
133  //Get exclusive acces to all iterators
134  while(!this.iter_sem.try_get());
135  this.hash.insert(digest, new_item);
136 
137  //Insert into key queue and update iterators
138  this.key_queue.insert(idx, '{new_item, digest});
139  iters = this.iterators.find(x) with (x.next_index() > idx);
140  for(int i=0; i<iters.size(); i++) begin
141  //We can blindly call iter.next
142  //See cl_syoscb_queue_std::insert_item for more description as to why
143  void'(iters[i].next());
144  end
145  this.iter_sem.put();
146 
147  end else begin //We already checked if idx > this.size, so here idx must == this.size
148  this.hash.insert(digest, new_item);
149  this.key_queue.push_back('{new_item, digest});
150  end
151 
152  this.post_add_item(new_item);
153  this.size++;
154  return 1'b1;
155 endfunction: insert_item
156 
157 /// <b>Queue API:</b> See cl_syoscb_queue_base#delete_item for more details
159  tp_digest digest;
160  cl_syoscb_proxy_item_hash#(HASH_DIGEST_WIDTH) proxy_item_hash;
161  int unsigned item_position_idx = 0;
163  string producer;
164 
165  if(!$cast(proxy_item_hash,proxy_item))begin
166  `uvm_fatal("Incorrect item type", $sformatf("[%s]:Proxy_item ", this.cfg.get_scb_name()));
167  return 0;
168  end
169 
170  digest = proxy_item_hash.digest;
171 
172  // Check if the aa contains the current digest value
173  if(!this.hash.exists(digest)) begin
174  return 0;
175  end
176 
177  // Wait to get exclusive access to the queue
178  // if there are multiple iterators
179  while(!this.iter_sem.try_get());
180 
181  // Get the item producer name. The name needs to be cached before the item is being deleted.
182  // This value is used after the item deletion for decreasing the item producer count.
183  begin
184  cl_syoscb_item tmp_item = this.hash.get_item(digest, proxy_item_hash.idx);
185  producer = tmp_item.get_producer();
186  end
187 
188  // Update all iterators on this queue
189  // Before deleting the item, we need the iterator position of the current item to correctly perform
190  // iter.previous() on all iterators that are pointing to or past the current item
191  if(this.cfg.get_ordered_next() == 1) begin
192  int q_idx[$];
193 
194  q_idx = this.key_queue.find_index with (item.digest==digest);
195 
196  //If AA[digest].size == 1, we can simply delete the matching item from our key queue
197  if(this.hash.get_size(digest) <= 1) begin
198  if(q_idx.size() == 0) begin
199  return 0; //Did not find a match
200  end
201  this.key_queue.delete(q_idx[0]);
202  item_position_idx = q_idx[0];
203  end else begin
204  //This branch is only executed if a hash collision occured
205  //Must take special care to ensure correct item is removed from key queue
206  cl_syoscb_item item1, item2;
207 
208  item1 = proxy_item_hash.get_item();
209  //For each index, check if that item matches our expected item. If yes, remove
210  foreach(q_idx[i]) begin
211  item2 = this.key_queue[q_idx[i]].item;
212  if(item1.compare(item2)) begin
213  item_position_idx = q_idx[i];
214  break;
215  end
216  end
217  end
218  end
219  // If ordered_next is 0, key_queue can't be used to determine which is the current item position
220  // inside the queue.
221  // Instead, we go over all iterators associated with the queue, as one of them should
222  // be pointing to our current item, allowing us to get idx from the iterator.
223  // If no iterators are pointing to the item, we manually search over the AA to find the item
224  else begin
225  //Go over all iterators, find the one pointing to this proxy item and retrieve idx from that one
226  foreach(this.iterators[i]) begin
227  cl_syoscb_proxy_item_base other_proxy;
228 
229  //iterator.next() was called to get the proxy item, so we first rewind the iterator, then re-get the item
230  void'(this.iterators[i].previous());
231  other_proxy = this.iterators[i].next();
232  //Can compare references directly, since they should both be pointing to the same object.
233  //No need to compare hash digest or contents
234  if(other_proxy.get_item() == proxy_item_hash.get_item()) begin
235  item_position_idx = this.iterators[i].previous_index();
236  break;
237  end
238  end
239 
240  // Only need to search if we didn't previously find the item by checking iterators
241  // AND if there are actually any iterators to test out
242  if(this.iterators.size() > 0 && item_position_idx == 0) begin
243  int unsigned v_idx = 0;
244  tp_digest loop_digest;
245 
246  if(this.hash.first(loop_digest)) begin
247  while(loop_digest != digest) begin
248  void'(this.hash.next(loop_digest));
249  //If multiple items have this digest, we must also account for those in our final position idx
250  v_idx += this.hash.get_size(loop_digest);
251  end
252  v_idx += proxy_item_hash.idx;
253  end
254  item_position_idx = v_idx;
255  end
256  end
257 
258  // Iterators update process can be shared independently by the value of ordered_next
259  // Find all the iter which need to be updated (all of those which have a next idx > item_position_idx)
260  iter = this.iterators.find(x) with (x.next_index() > item_position_idx);
261 
262  // Update them
263  foreach(iter[i]) begin
264  void'(iter[i].previous());
265  end
266 
267  //Delete item, decrease producer count and size, return semaphore
268  this.hash.delete(digest, proxy_item_hash.idx);
269  this.decr_cnt_producer(producer);
270  this.size--;
271  this.iter_sem.put();
272 
273  return 1;
274 endfunction: delete_item
275 
276 /// <b>Queue API:</b> See cl_syoscb_queue_base#get_item for more details
278  cl_syoscb_proxy_item_hash#(HASH_DIGEST_WIDTH) proxy_item_hash;
279 
280  if(!$cast(proxy_item_hash, proxy_item)) begin
281  `uvm_fatal("Incorrect item type", $sformatf("[%s]:Proxy_item was of type %0s", this.cfg.get_scb_name(), proxy_item.get_type_name()));
282  return null;
283  end
284 
285  return this.hash.get_item(proxy_item_hash.digest, proxy_item_hash.idx);
286 endfunction: get_item
287 
288 /// <b>Queue API:</b> See cl_syoscb_queue_base#get_size for more details.
289 function int unsigned cl_syoscb_queue_hash::get_size();
290  return this.size;
291 endfunction: get_size
292 
293 /// <b>Queue API:</b> See cl_syoscb_queue_base#empty for more details
295  return this.get_size()==0;
296 endfunction
297 
298 /// <b>Queue API:</b> See cl_syoscb_queue_base#delete_iterator for more details
300  if(iterator == null) begin
301  `uvm_info("NULL", $sformatf("[%s]: Asked to delete null iterator from list of iterators in %s",
302  this.cfg.get_scb_name(), this.get_name()), UVM_DEBUG);
303  return 0;
304  end else begin
305  // Wait to get exclusive access to the queue
306  // if there are multiple iterators
307  while(!this.iter_sem.try_get());
308 
309  this.iterators.delete(iterator);
310  this.iter_sem.put();
311  return 1;
312  end
313 endfunction: delete_iterator
314 
315 /// See cl_syoscb_queue_base#do_flush_queue for more details
317  this.hash.delete_all();
318  this.key_queue = {};
319  this.size = 0;
320 endfunction: do_flush_queue
321 
322 /// Get the list of hash values of items in the queue.
323 /// \note If cl_syoscb_cfg#ordered_next is 0, the key queue has no inherent meaning.
324 /// An empty queue is returned in this case
326  return this.key_queue;
327 endfunction: get_key_queue
328 
329 /// Gets the hash AA wrapper used for this queue
331  return this.hash;
332 endfunction: get_hash
virtual void do_flush_queue()
See cl_syoscb_queue_base::do_flush_queue for more details.
int unsigned size
Size of queue, stored here to optimize for speed.
virtual bit delete_item(cl_syoscb_proxy_item_base proxy_item)
Queue API: See cl_syoscb_queue_base::delete_item for more details
virtual cl_syoscb_proxy_item_base previous()
Iterator API: Moves the iterator one step backward, returning the previous item in the queue...
virtual tp_aa_hash get_hash()
Gets the hash AA wrapper used for this queue.
The UVM scoreboard item which wraps uvm_sequence_item .
virtual bit empty()
Queue API: See cl_syoscb_queue_base::empty for more details
tp_item_digest tp_queue_of_keys[$]
Typedef for queue of digests and items.
Base class for all proxy items.
virtual int unsigned get_size()
Queue API: See cl_syoscb_queue_base::get_size for more details.
Typedef for struct used to track items and their digests in the key queue.
virtual bit add_item(string producer, uvm_sequence_item item)
Queue API: See cl_syoscb_queue_base::add_item for more details
cl_syoscb_hash_base< HASH_DIGEST_WIDTH >::tp_hash_digest tp_digest
Typedef for hash algorithm digests.
virtual tp_queue_of_keys get_key_queue()
Get the list of hash values of items in the queue.
virtual cl_syoscb_item get_item()
Item API: Get the scoreboard item that this proxy item represents
virtual bit insert_item(string producer, uvm_sequence_item item, int unsigned idx)
Queue API: See cl_syoscb_queue_base::insert_item for more details
virtual uvm_sequence_item get_item()
Item API: Returns the wrapped uvm_sequence_item
Typedef for struct representing whether an option with an iterator was valid.
Queue iterator base class defining the iterator API used for iterating over queues.
virtual bit delete_iterator(cl_syoscb_queue_iterator_base iterator)
Queue API: See cl_syoscb_queue_base::delete_iterator for more details
Class which represents the base concept of a queue.
virtual cl_syoscb_item get_item(cl_syoscb_proxy_item_base proxy_item)
Queue API: See cl_syoscb_queue_base::get_item for more details
Class which defines the base concept of a hash algorithm.
A wrapper around an associative array, used for storing hash queues.
Proxy item implementation for hash queues.
Class which represents the base concept of a hash queue.

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