1 |
16 |
HanySalah |
//----------------------------------------------------------------------
|
2 |
|
|
// Copyright 2007-2011 Mentor Graphics Corporation
|
3 |
|
|
// Copyright 2007-2010 Cadence Design Systems, Inc.
|
4 |
|
|
// Copyright 2010-2011 Synopsys, Inc.
|
5 |
|
|
// All Rights Reserved Worldwide
|
6 |
|
|
//
|
7 |
|
|
// Licensed under the Apache License, Version 2.0 (the
|
8 |
|
|
// "License"); you may not use this file except in
|
9 |
|
|
// compliance with the License. You may obtain a copy of
|
10 |
|
|
// the License at
|
11 |
|
|
//
|
12 |
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
13 |
|
|
//
|
14 |
|
|
// Unless required by applicable law or agreed to in
|
15 |
|
|
// writing, software distributed under the License is
|
16 |
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
17 |
|
|
// CONDITIONS OF ANY KIND, either express or implied. See
|
18 |
|
|
// the License for the specific language governing
|
19 |
|
|
// permissions and limitations under the License.
|
20 |
|
|
//----------------------------------------------------------------------
|
21 |
|
|
|
22 |
|
|
`include "uvm_macros.svh"
|
23 |
|
|
|
24 |
|
|
`ifndef UVM_CALLBACK_SVH
|
25 |
|
|
`define UVM_CALLBACK_SVH
|
26 |
|
|
|
27 |
|
|
//------------------------------------------------------------------------------
|
28 |
|
|
// Title: Callbacks Classes
|
29 |
|
|
//
|
30 |
|
|
// This section defines the classes used for callback registration, management,
|
31 |
|
|
// and user-defined callbacks.
|
32 |
|
|
//------------------------------------------------------------------------------
|
33 |
|
|
|
34 |
|
|
typedef class uvm_root;
|
35 |
|
|
typedef class uvm_callback;
|
36 |
|
|
typedef class uvm_callbacks_base;
|
37 |
|
|
|
38 |
|
|
|
39 |
|
|
//------------------------------------------------------------------------------
|
40 |
|
|
//
|
41 |
|
|
// Class - uvm_typeid_base
|
42 |
|
|
//
|
43 |
|
|
//------------------------------------------------------------------------------
|
44 |
|
|
//
|
45 |
|
|
// Simple typeid interface. Need this to set up the base-super mapping.
|
46 |
|
|
// This is similar to the factory, but much simpler. The idea of this
|
47 |
|
|
// interface is that each object type T has a typeid that can be
|
48 |
|
|
// used for mapping type relationships. This is not a user visible class.
|
49 |
|
|
|
50 |
|
|
class uvm_typeid_base;
|
51 |
|
|
static string typename;
|
52 |
|
|
static uvm_callbacks_base typeid_map[uvm_typeid_base];
|
53 |
|
|
static uvm_typeid_base type_map[uvm_callbacks_base];
|
54 |
|
|
endclass
|
55 |
|
|
|
56 |
|
|
|
57 |
|
|
|
58 |
|
|
//------------------------------------------------------------------------------
|
59 |
|
|
//
|
60 |
|
|
// Class - uvm_typeid#(T)
|
61 |
|
|
//
|
62 |
|
|
//------------------------------------------------------------------------------
|
63 |
|
|
|
64 |
|
|
class uvm_typeid#(type T=uvm_object) extends uvm_typeid_base;
|
65 |
|
|
static uvm_typeid#(T) m_b_inst;
|
66 |
|
|
static function uvm_typeid#(T) get();
|
67 |
|
|
if(m_b_inst == null)
|
68 |
|
|
m_b_inst = new;
|
69 |
|
|
return m_b_inst;
|
70 |
|
|
endfunction
|
71 |
|
|
endclass
|
72 |
|
|
|
73 |
|
|
//------------------------------------------------------------------------------
|
74 |
|
|
// Class - uvm_callbacks_base
|
75 |
|
|
//
|
76 |
|
|
// Base class singleton that holds generic queues for all instance
|
77 |
|
|
// specific objects. This is an internal class. This class contains a
|
78 |
|
|
// global pool that has all of the instance specific callback queues in it.
|
79 |
|
|
// All of the typewide callback queues live in the derivative class
|
80 |
|
|
// uvm_typed_callbacks#(T). This is not a user visible class.
|
81 |
|
|
//
|
82 |
|
|
// This class holds the class inheritance hierarchy information
|
83 |
|
|
// (super types and derivative types).
|
84 |
|
|
//
|
85 |
|
|
// Note, all derivative uvm_callbacks#() class singletons access this
|
86 |
|
|
// global m_pool object in order to get access to their specific
|
87 |
|
|
// instance queue.
|
88 |
|
|
//------------------------------------------------------------------------------
|
89 |
|
|
|
90 |
|
|
class uvm_callbacks_base extends uvm_object;
|
91 |
|
|
|
92 |
|
|
typedef uvm_callbacks_base this_type;
|
93 |
|
|
|
94 |
|
|
/*protected*/ static bit m_tracing = 1;
|
95 |
|
|
static this_type m_b_inst;
|
96 |
|
|
|
97 |
|
|
static uvm_pool#(uvm_object,uvm_queue#(uvm_callback)) m_pool;
|
98 |
|
|
|
99 |
|
|
static function this_type m_initialize();
|
100 |
|
|
if(m_b_inst == null) begin
|
101 |
|
|
m_b_inst = new;
|
102 |
|
|
m_pool = new;
|
103 |
|
|
end
|
104 |
|
|
return m_b_inst;
|
105 |
|
|
endfunction
|
106 |
|
|
|
107 |
|
|
//Type checking interface
|
108 |
|
|
this_type m_this_type[$]; //one to many T->T/CB
|
109 |
|
|
uvm_typeid_base m_super_type; //one to one relation
|
110 |
|
|
uvm_typeid_base m_derived_types[$]; //one to many relation
|
111 |
|
|
|
112 |
|
|
virtual function bit m_am_i_a(uvm_object obj);
|
113 |
|
|
return 0;
|
114 |
|
|
endfunction
|
115 |
|
|
|
116 |
|
|
virtual function bit m_is_for_me(uvm_callback cb);
|
117 |
|
|
return 0;
|
118 |
|
|
endfunction
|
119 |
|
|
|
120 |
|
|
virtual function bit m_is_registered(uvm_object obj, uvm_callback cb);
|
121 |
|
|
return 0;
|
122 |
|
|
endfunction
|
123 |
|
|
|
124 |
|
|
virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj);
|
125 |
|
|
return null;
|
126 |
|
|
endfunction
|
127 |
|
|
|
128 |
|
|
virtual function void m_add_tw_cbs(uvm_callback cb, uvm_apprepend ordering);
|
129 |
|
|
endfunction
|
130 |
|
|
|
131 |
|
|
virtual function bit m_delete_tw_cbs(uvm_callback cb);
|
132 |
|
|
return 0;
|
133 |
|
|
endfunction
|
134 |
|
|
|
135 |
|
|
//Check registration. To test registration, start at this class and
|
136 |
|
|
//work down the class hierarchy. If any class returns true then
|
137 |
|
|
//the pair is legal.
|
138 |
|
|
function bit check_registration(uvm_object obj, uvm_callback cb);
|
139 |
|
|
this_type st, dt;
|
140 |
|
|
|
141 |
|
|
if (m_is_registered(obj,cb))
|
142 |
|
|
return 1;
|
143 |
|
|
|
144 |
|
|
// Need to look at all possible T/CB pairs of this type
|
145 |
|
|
foreach(m_this_type[i])
|
146 |
|
|
if(m_b_inst != m_this_type[i] && m_this_type[i].m_is_registered(obj,cb))
|
147 |
|
|
return 1;
|
148 |
|
|
|
149 |
|
|
if(obj == null) begin
|
150 |
|
|
foreach(m_derived_types[i]) begin
|
151 |
|
|
dt = uvm_typeid_base::typeid_map[m_derived_types[i] ];
|
152 |
|
|
if(dt != null && dt.check_registration(null,cb))
|
153 |
|
|
return 1;
|
154 |
|
|
end
|
155 |
|
|
end
|
156 |
|
|
|
157 |
|
|
return 0;
|
158 |
|
|
endfunction
|
159 |
|
|
|
160 |
|
|
endclass
|
161 |
|
|
|
162 |
|
|
|
163 |
|
|
|
164 |
|
|
//------------------------------------------------------------------------------
|
165 |
|
|
//
|
166 |
|
|
// Class - uvm_typed_callbacks#(T)
|
167 |
|
|
//
|
168 |
|
|
//------------------------------------------------------------------------------
|
169 |
|
|
//
|
170 |
|
|
// Another internal class. This contains the queue of typewide
|
171 |
|
|
// callbacks. It also contains some of the public interface methods,
|
172 |
|
|
// but those methods are accessed via the uvm_callbacks#() class
|
173 |
|
|
// so they are documented in that class even though the implementation
|
174 |
|
|
// is in this class.
|
175 |
|
|
//
|
176 |
|
|
// The , , and methods are implemented in this class.
|
177 |
|
|
|
178 |
|
|
class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base;
|
179 |
|
|
|
180 |
|
|
static uvm_queue#(uvm_callback) m_tw_cb_q;
|
181 |
|
|
static string m_typename;
|
182 |
|
|
|
183 |
|
|
typedef uvm_typed_callbacks#(T) this_type;
|
184 |
|
|
typedef uvm_callbacks_base super_type;
|
185 |
|
|
|
186 |
|
|
//The actual global object from the derivative class. Note that this is
|
187 |
|
|
//just a reference to the object that is generated in the derived class.
|
188 |
|
|
static this_type m_t_inst;
|
189 |
|
|
|
190 |
|
|
static function this_type m_initialize();
|
191 |
|
|
if(m_t_inst == null) begin
|
192 |
|
|
void'(super_type::m_initialize());
|
193 |
|
|
m_t_inst = new;
|
194 |
|
|
m_t_inst.m_tw_cb_q = new("typewide_queue");
|
195 |
|
|
end
|
196 |
|
|
return m_t_inst;
|
197 |
|
|
endfunction
|
198 |
|
|
|
199 |
|
|
//Type checking interface: is given ~obj~ of type T?
|
200 |
|
|
virtual function bit m_am_i_a(uvm_object obj);
|
201 |
|
|
T this_type;
|
202 |
|
|
if (obj == null)
|
203 |
|
|
return 1;
|
204 |
|
|
return($cast(this_type,obj));
|
205 |
|
|
endfunction
|
206 |
|
|
|
207 |
|
|
//Getting the typewide queue
|
208 |
|
|
virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj);
|
209 |
|
|
if(m_am_i_a(obj)) begin
|
210 |
|
|
foreach(m_derived_types[i]) begin
|
211 |
|
|
super_type dt;
|
212 |
|
|
dt = uvm_typeid_base::typeid_map[m_derived_types[i] ];
|
213 |
|
|
if(dt != null && dt != this) begin
|
214 |
|
|
m_get_tw_cb_q = dt.m_get_tw_cb_q(obj);
|
215 |
|
|
if(m_get_tw_cb_q != null)
|
216 |
|
|
return m_get_tw_cb_q;
|
217 |
|
|
end
|
218 |
|
|
end
|
219 |
|
|
return m_t_inst.m_tw_cb_q;
|
220 |
|
|
end
|
221 |
|
|
else
|
222 |
|
|
return null;
|
223 |
|
|
endfunction
|
224 |
|
|
|
225 |
|
|
static function int m_cb_find(uvm_queue#(uvm_callback) q, uvm_callback cb);
|
226 |
|
|
for(int i=0; i
|
227 |
|
|
if(q.get(i) == cb)
|
228 |
|
|
return i;
|
229 |
|
|
return -1;
|
230 |
|
|
endfunction
|
231 |
|
|
|
232 |
|
|
static function int m_cb_find_name(uvm_queue#(uvm_callback) q, string name, string where);
|
233 |
|
|
uvm_callback cb;
|
234 |
|
|
for(int i=0; i
|
235 |
|
|
cb = q.get(i);
|
236 |
|
|
if(cb.get_name() == name) begin
|
237 |
|
|
`uvm_warning("UVM/CB/NAM/SAM", {"A callback named \"", name,
|
238 |
|
|
"\" is already registered with ", where})
|
239 |
|
|
return 1;
|
240 |
|
|
end
|
241 |
|
|
end
|
242 |
|
|
return 0;
|
243 |
|
|
endfunction
|
244 |
|
|
|
245 |
|
|
//For a typewide callback, need to add to derivative types as well.
|
246 |
|
|
virtual function void m_add_tw_cbs(uvm_callback cb, uvm_apprepend ordering);
|
247 |
|
|
super_type cb_pair;
|
248 |
|
|
uvm_object obj;
|
249 |
|
|
T me;
|
250 |
|
|
bit warned;
|
251 |
|
|
uvm_queue#(uvm_callback) q;
|
252 |
|
|
if(m_cb_find(m_t_inst.m_tw_cb_q,cb) == -1) begin
|
253 |
|
|
warned = m_cb_find_name(m_t_inst.m_tw_cb_q, cb.get_name(), "type");
|
254 |
|
|
if(ordering == UVM_APPEND)
|
255 |
|
|
m_t_inst.m_tw_cb_q.push_back(cb);
|
256 |
|
|
else
|
257 |
|
|
m_t_inst.m_tw_cb_q.push_front(cb);
|
258 |
|
|
end
|
259 |
|
|
if(m_t_inst.m_pool.first(obj)) begin
|
260 |
|
|
do begin
|
261 |
|
|
if($cast(me,obj)) begin
|
262 |
|
|
q = m_t_inst.m_pool.get(obj);
|
263 |
|
|
if(q==null) begin
|
264 |
|
|
q=new;
|
265 |
|
|
m_t_inst.m_pool.add(obj,q);
|
266 |
|
|
end
|
267 |
|
|
if(m_cb_find(q,cb) == -1) begin
|
268 |
|
|
if (!warned) begin
|
269 |
|
|
void'(m_cb_find_name(q, cb.get_name(), {"object instance ", me.get_full_name()}));
|
270 |
|
|
end
|
271 |
|
|
if(ordering == UVM_APPEND)
|
272 |
|
|
q.push_back(cb);
|
273 |
|
|
else
|
274 |
|
|
q.push_front(cb);
|
275 |
|
|
end
|
276 |
|
|
end
|
277 |
|
|
end while(m_t_inst.m_pool.next(obj));
|
278 |
|
|
end
|
279 |
|
|
foreach(m_derived_types[i]) begin
|
280 |
|
|
cb_pair = uvm_typeid_base::typeid_map[m_derived_types[i] ];
|
281 |
|
|
if(cb_pair != this)
|
282 |
|
|
cb_pair.m_add_tw_cbs(cb,ordering);
|
283 |
|
|
end
|
284 |
|
|
endfunction
|
285 |
|
|
|
286 |
|
|
|
287 |
|
|
//For a typewide callback, need to remove from derivative types as well.
|
288 |
|
|
virtual function bit m_delete_tw_cbs(uvm_callback cb);
|
289 |
|
|
super_type cb_pair;
|
290 |
|
|
uvm_object obj;
|
291 |
|
|
uvm_queue#(uvm_callback) q;
|
292 |
|
|
int pos = m_cb_find(m_t_inst.m_tw_cb_q,cb);
|
293 |
|
|
|
294 |
|
|
if(pos != -1) begin
|
295 |
|
|
m_t_inst.m_tw_cb_q.delete(pos);
|
296 |
|
|
m_delete_tw_cbs = 1;
|
297 |
|
|
end
|
298 |
|
|
|
299 |
|
|
if(m_t_inst.m_pool.first(obj)) begin
|
300 |
|
|
do begin
|
301 |
|
|
q = m_t_inst.m_pool.get(obj);
|
302 |
|
|
if(q==null) begin
|
303 |
|
|
q=new;
|
304 |
|
|
m_t_inst.m_pool.add(obj,q);
|
305 |
|
|
end
|
306 |
|
|
pos = m_cb_find(q,cb);
|
307 |
|
|
if(pos != -1) begin
|
308 |
|
|
q.delete(pos);
|
309 |
|
|
m_delete_tw_cbs = 1;
|
310 |
|
|
end
|
311 |
|
|
end while(m_t_inst.m_pool.next(obj));
|
312 |
|
|
end
|
313 |
|
|
foreach(m_derived_types[i]) begin
|
314 |
|
|
cb_pair = uvm_typeid_base::typeid_map[m_derived_types[i] ];
|
315 |
|
|
if(cb_pair != this)
|
316 |
|
|
m_delete_tw_cbs |= cb_pair.m_delete_tw_cbs(cb);
|
317 |
|
|
end
|
318 |
|
|
endfunction
|
319 |
|
|
|
320 |
|
|
|
321 |
|
|
static function void display(T obj=null);
|
322 |
|
|
T me;
|
323 |
|
|
super_type ib = m_t_inst;
|
324 |
|
|
string cbq[$];
|
325 |
|
|
string inst_q[$];
|
326 |
|
|
string mode_q[$];
|
327 |
|
|
uvm_callback cb;
|
328 |
|
|
string blanks = " ";
|
329 |
|
|
uvm_object bobj = obj;
|
330 |
|
|
string qs[$];
|
331 |
|
|
|
332 |
|
|
uvm_queue#(uvm_callback) q;
|
333 |
|
|
string tname, str;
|
334 |
|
|
|
335 |
|
|
int max_cb_name=0, max_inst_name=0;
|
336 |
|
|
|
337 |
|
|
m_tracing = 0; //don't allow tracing during display
|
338 |
|
|
|
339 |
|
|
if(m_typename != "") tname = m_typename;
|
340 |
|
|
else if(obj != null) tname = obj.get_type_name();
|
341 |
|
|
else tname = "*";
|
342 |
|
|
|
343 |
|
|
q = m_t_inst.m_tw_cb_q;
|
344 |
|
|
for(int i=0; i
|
345 |
|
|
cb = q.get(i);
|
346 |
|
|
cbq.push_back(cb.get_name());
|
347 |
|
|
inst_q.push_back("(*)");
|
348 |
|
|
if(cb.is_enabled()) mode_q.push_back("ON");
|
349 |
|
|
else mode_q.push_back("OFF");
|
350 |
|
|
|
351 |
|
|
str = cb.get_name();
|
352 |
|
|
max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len();
|
353 |
|
|
str = "(*)";
|
354 |
|
|
max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len();
|
355 |
|
|
end
|
356 |
|
|
|
357 |
|
|
if(obj ==null) begin
|
358 |
|
|
if(m_t_inst.m_pool.first(bobj)) begin
|
359 |
|
|
do
|
360 |
|
|
if($cast(me,bobj)) break;
|
361 |
|
|
while(m_t_inst.m_pool.next(bobj));
|
362 |
|
|
end
|
363 |
|
|
if(me != null || m_t_inst.m_tw_cb_q.size()) begin
|
364 |
|
|
qs.push_back($sformatf("Registered callbacks for all instances of %s\n", tname));
|
365 |
|
|
qs.push_back("---------------------------------------------------------------\n");
|
366 |
|
|
end
|
367 |
|
|
if(me != null) begin
|
368 |
|
|
do begin
|
369 |
|
|
if($cast(me,bobj)) begin
|
370 |
|
|
q = m_t_inst.m_pool.get(bobj);
|
371 |
|
|
if (q==null) begin
|
372 |
|
|
q=new;
|
373 |
|
|
m_t_inst.m_pool.add(bobj,q);
|
374 |
|
|
end
|
375 |
|
|
for(int i=0; i
|
376 |
|
|
cb = q.get(i);
|
377 |
|
|
cbq.push_back(cb.get_name());
|
378 |
|
|
inst_q.push_back(bobj.get_full_name());
|
379 |
|
|
if(cb.is_enabled()) mode_q.push_back("ON");
|
380 |
|
|
else mode_q.push_back("OFF");
|
381 |
|
|
|
382 |
|
|
str = cb.get_name();
|
383 |
|
|
max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len();
|
384 |
|
|
str = bobj.get_full_name();
|
385 |
|
|
max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len();
|
386 |
|
|
end
|
387 |
|
|
end
|
388 |
|
|
end while (m_t_inst.m_pool.next(bobj));
|
389 |
|
|
end
|
390 |
|
|
else begin
|
391 |
|
|
qs.push_back($sformatf("No callbacks registered for any instances of type %s\n", tname));
|
392 |
|
|
end
|
393 |
|
|
end
|
394 |
|
|
else begin
|
395 |
|
|
if(m_t_inst.m_pool.exists(bobj) || m_t_inst.m_tw_cb_q.size()) begin
|
396 |
|
|
qs.push_back($sformatf("Registered callbacks for instance %s of %s\n", obj.get_full_name(), tname));
|
397 |
|
|
qs.push_back("---------------------------------------------------------------\n");
|
398 |
|
|
end
|
399 |
|
|
if(m_t_inst.m_pool.exists(bobj)) begin
|
400 |
|
|
q = m_t_inst.m_pool.get(bobj);
|
401 |
|
|
if(q==null) begin
|
402 |
|
|
q=new;
|
403 |
|
|
m_t_inst.m_pool.add(bobj,q);
|
404 |
|
|
end
|
405 |
|
|
for(int i=0; i
|
406 |
|
|
cb = q.get(i);
|
407 |
|
|
cbq.push_back(cb.get_name());
|
408 |
|
|
inst_q.push_back(bobj.get_full_name());
|
409 |
|
|
if(cb.is_enabled()) mode_q.push_back("ON");
|
410 |
|
|
else mode_q.push_back("OFF");
|
411 |
|
|
|
412 |
|
|
str = cb.get_name();
|
413 |
|
|
max_cb_name = max_cb_name > str.len() ? max_cb_name : str.len();
|
414 |
|
|
str = bobj.get_full_name();
|
415 |
|
|
max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len();
|
416 |
|
|
end
|
417 |
|
|
end
|
418 |
|
|
end
|
419 |
|
|
if(!cbq.size()) begin
|
420 |
|
|
if(obj == null) str = "*";
|
421 |
|
|
else str = obj.get_full_name();
|
422 |
|
|
qs.push_back($sformatf("No callbacks registered for instance %s of type %s\n", str, tname));
|
423 |
|
|
end
|
424 |
|
|
|
425 |
|
|
foreach (cbq[i]) begin
|
426 |
|
|
qs.push_back($sformatf("%s %s %s on %s %s\n", cbq[i], blanks.substr(0,max_cb_name-cbq[i].len()-1), inst_q[i], blanks.substr(0,max_inst_name - inst_q[i].len()-1), mode_q[i]));
|
427 |
|
|
end
|
428 |
|
|
`uvm_info("UVM/CB/DISPLAY",`UVM_STRING_QUEUE_STREAMING_PACK(qs),UVM_NONE)
|
429 |
|
|
|
430 |
|
|
m_tracing = 1; //allow tracing to be resumed
|
431 |
|
|
endfunction
|
432 |
|
|
|
433 |
|
|
endclass
|
434 |
|
|
|
435 |
|
|
|
436 |
|
|
|
437 |
|
|
//------------------------------------------------------------------------------
|
438 |
|
|
//
|
439 |
|
|
// CLASS: uvm_callbacks #(T,CB)
|
440 |
|
|
//
|
441 |
|
|
// The ~uvm_callbacks~ class provides a base class for implementing callbacks,
|
442 |
|
|
// which are typically used to modify or augment component behavior without
|
443 |
|
|
// changing the component class. To work effectively, the developer of the
|
444 |
|
|
// component class defines a set of "hook" methods that enable users to
|
445 |
|
|
// customize certain behaviors of the component in a manner that is controlled
|
446 |
|
|
// by the component developer. The integrity of the component's overall behavior
|
447 |
|
|
// is intact, while still allowing certain customizable actions by the user.
|
448 |
|
|
//
|
449 |
|
|
// To enable compile-time type-safety, the class is parameterized on both the
|
450 |
|
|
// user-defined callback interface implementation as well as the object type
|
451 |
|
|
// associated with the callback. The object type-callback type pair are
|
452 |
|
|
// associated together using the <`uvm_register_cb> macro to define
|
453 |
|
|
// a valid pairing; valid pairings are checked when a user attempts to add
|
454 |
|
|
// a callback to an object.
|
455 |
|
|
//
|
456 |
|
|
// To provide the most flexibility for end-user customization and reuse, it
|
457 |
|
|
// is recommended that the component developer also define a corresponding set
|
458 |
|
|
// of virtual method hooks in the component itself. This affords users the ability
|
459 |
|
|
// to customize via inheritance/factory overrides as well as callback object
|
460 |
|
|
// registration. The implementation of each virtual method would provide the
|
461 |
|
|
// default traversal algorithm for the particular callback being called. Being
|
462 |
|
|
// virtual, users can define subtypes that override the default algorithm,
|
463 |
|
|
// perform tasks before and/or after calling super. to execute any
|
464 |
|
|
// registered callbacks, or to not call the base implementation, effectively
|
465 |
|
|
// disabling that particular hook. A demonstration of this methodology is
|
466 |
|
|
// provided in an example included in the kit.
|
467 |
|
|
//------------------------------------------------------------------------------
|
468 |
|
|
|
469 |
|
|
class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback)
|
470 |
|
|
extends uvm_typed_callbacks#(T);
|
471 |
|
|
|
472 |
|
|
// Parameter: T
|
473 |
|
|
//
|
474 |
|
|
// This type parameter specifies the base object type with which the
|
475 |
|
|
// callback objects will be registered. This object must be
|
476 |
|
|
// a derivative of ~uvm_object~.
|
477 |
|
|
|
478 |
|
|
// Parameter: CB
|
479 |
|
|
//
|
480 |
|
|
// This type parameter specifies the base callback type that will be
|
481 |
|
|
// managed by this callback class. The callback type is typically a
|
482 |
|
|
// interface class, which defines one or more virtual method prototypes
|
483 |
|
|
// that users can override in subtypes. This type must be a derivative
|
484 |
|
|
// of .
|
485 |
|
|
|
486 |
|
|
typedef uvm_typed_callbacks#(T) super_type;
|
487 |
|
|
typedef uvm_callbacks#(T,CB) this_type;
|
488 |
|
|
|
489 |
|
|
|
490 |
|
|
// Singleton instance is used for type checking
|
491 |
|
|
local static this_type m_inst;
|
492 |
|
|
|
493 |
|
|
// typeinfo
|
494 |
|
|
static uvm_typeid_base m_typeid;
|
495 |
|
|
static uvm_typeid_base m_cb_typeid;
|
496 |
|
|
|
497 |
|
|
static string m_typename;
|
498 |
|
|
static string m_cb_typename;
|
499 |
|
|
static uvm_report_object reporter = new("cb_tracer");
|
500 |
|
|
static uvm_callbacks#(T,uvm_callback) m_base_inst;
|
501 |
|
|
|
502 |
|
|
bit m_registered;
|
503 |
|
|
|
504 |
|
|
// get
|
505 |
|
|
// ---
|
506 |
|
|
|
507 |
|
|
static function this_type get();
|
508 |
|
|
|
509 |
|
|
if (m_inst == null) begin
|
510 |
|
|
uvm_typeid_base cb_base_type;
|
511 |
|
|
|
512 |
|
|
void'(super_type::m_initialize());
|
513 |
|
|
|
514 |
|
|
cb_base_type = uvm_typeid#(uvm_callback)::get();
|
515 |
|
|
m_cb_typeid = uvm_typeid#(CB)::get();
|
516 |
|
|
m_typeid = uvm_typeid#(T)::get();
|
517 |
|
|
|
518 |
|
|
m_inst = new;
|
519 |
|
|
|
520 |
|
|
if (cb_base_type == m_cb_typeid) begin
|
521 |
|
|
$cast(m_base_inst, m_inst);
|
522 |
|
|
// The base inst in the super class gets set to this base inst
|
523 |
|
|
m_t_inst = m_base_inst;
|
524 |
|
|
uvm_typeid_base::typeid_map[m_typeid] = m_inst;
|
525 |
|
|
uvm_typeid_base::type_map[m_b_inst] = m_typeid;
|
526 |
|
|
end
|
527 |
|
|
else begin
|
528 |
|
|
m_base_inst = uvm_callbacks#(T,uvm_callback)::get();
|
529 |
|
|
m_base_inst.m_this_type.push_back(m_inst);
|
530 |
|
|
end
|
531 |
|
|
|
532 |
|
|
if (m_inst == null)
|
533 |
|
|
`uvm_fatal("CB/INTERNAL","get(): m_inst is null")
|
534 |
|
|
end
|
535 |
|
|
|
536 |
|
|
return m_inst;
|
537 |
|
|
endfunction
|
538 |
|
|
|
539 |
|
|
|
540 |
|
|
|
541 |
|
|
// m_register_pair
|
542 |
|
|
// -------------
|
543 |
|
|
// Register valid callback type
|
544 |
|
|
|
545 |
|
|
static function bit m_register_pair(string tname="", cbname="");
|
546 |
|
|
this_type inst = get();
|
547 |
|
|
|
548 |
|
|
m_typename = tname;
|
549 |
|
|
super_type::m_typename = tname;
|
550 |
|
|
m_typeid.typename = tname;
|
551 |
|
|
|
552 |
|
|
m_cb_typename = cbname;
|
553 |
|
|
m_cb_typeid.typename = cbname;
|
554 |
|
|
|
555 |
|
|
inst.m_registered = 1;
|
556 |
|
|
|
557 |
|
|
return 1;
|
558 |
|
|
endfunction
|
559 |
|
|
|
560 |
|
|
virtual function bit m_is_registered(uvm_object obj, uvm_callback cb);
|
561 |
|
|
if(m_is_for_me(cb) && m_am_i_a(obj)) begin
|
562 |
|
|
return m_registered;
|
563 |
|
|
end
|
564 |
|
|
endfunction
|
565 |
|
|
|
566 |
|
|
//Does type check to see if the callback is valid for this type
|
567 |
|
|
virtual function bit m_is_for_me(uvm_callback cb);
|
568 |
|
|
CB this_cb;
|
569 |
|
|
return($cast(this_cb,cb));
|
570 |
|
|
endfunction
|
571 |
|
|
|
572 |
|
|
// Group: Add/delete interface
|
573 |
|
|
|
574 |
|
|
// Function: add
|
575 |
|
|
//
|
576 |
|
|
// Registers the given callback object, ~cb~, with the given
|
577 |
|
|
// ~obj~ handle. The ~obj~ handle can be ~null~, which allows
|
578 |
|
|
// registration of callbacks without an object context. If
|
579 |
|
|
// ~ordering~ is UVM_APPEND (default), the callback will be executed
|
580 |
|
|
// after previously added callbacks, else the callback
|
581 |
|
|
// will be executed ahead of previously added callbacks. The ~cb~
|
582 |
|
|
// is the callback handle; it must be non-~null~, and if the callback
|
583 |
|
|
// has already been added to the object instance then a warning is
|
584 |
|
|
// issued. Note that the CB parameter is optional. For example, the
|
585 |
|
|
// following are equivalent:
|
586 |
|
|
//
|
587 |
|
|
//| uvm_callbacks#(my_comp)::add(comp_a, cb);
|
588 |
|
|
//| uvm_callbacks#(my_comp, my_callback)::add(comp_a,cb);
|
589 |
|
|
|
590 |
|
|
static function void add(T obj, uvm_callback cb, uvm_apprepend ordering=UVM_APPEND);
|
591 |
|
|
uvm_queue#(uvm_callback) q;
|
592 |
|
|
string nm,tnm;
|
593 |
|
|
|
594 |
|
|
void'(get());
|
595 |
|
|
|
596 |
|
|
if (cb==null) begin
|
597 |
|
|
if (obj==null)
|
598 |
|
|
nm = "(*)";
|
599 |
|
|
else
|
600 |
|
|
nm = obj.get_full_name();
|
601 |
|
|
|
602 |
|
|
if (m_base_inst.m_typename!="")
|
603 |
|
|
tnm = m_base_inst.m_typename;
|
604 |
|
|
else if (obj != null)
|
605 |
|
|
tnm = obj.get_type_name();
|
606 |
|
|
else
|
607 |
|
|
tnm = "uvm_object";
|
608 |
|
|
|
609 |
|
|
uvm_report_error("CBUNREG",
|
610 |
|
|
{"Null callback object cannot be registered with object ",
|
611 |
|
|
nm, " (", tnm, ")"}, UVM_NONE);
|
612 |
|
|
return;
|
613 |
|
|
end
|
614 |
|
|
|
615 |
|
|
if (!m_base_inst.check_registration(obj,cb)) begin
|
616 |
|
|
|
617 |
|
|
if (obj==null)
|
618 |
|
|
nm = "(*)";
|
619 |
|
|
else
|
620 |
|
|
nm = obj.get_full_name();
|
621 |
|
|
|
622 |
|
|
if (m_base_inst.m_typename!="")
|
623 |
|
|
tnm = m_base_inst.m_typename;
|
624 |
|
|
else if(obj != null)
|
625 |
|
|
tnm = obj.get_type_name();
|
626 |
|
|
else
|
627 |
|
|
tnm = "uvm_object";
|
628 |
|
|
|
629 |
|
|
uvm_report_warning("CBUNREG",
|
630 |
|
|
{"Callback ", cb.get_name(), " cannot be registered with object ",
|
631 |
|
|
nm, " because callback type ", cb.get_type_name(),
|
632 |
|
|
" is not registered with object type ", tnm }, UVM_NONE);
|
633 |
|
|
end
|
634 |
|
|
|
635 |
|
|
if(obj == null) begin
|
636 |
|
|
|
637 |
|
|
if (m_cb_find(m_t_inst.m_tw_cb_q,cb) != -1) begin
|
638 |
|
|
|
639 |
|
|
if (m_base_inst.m_typename!="")
|
640 |
|
|
tnm = m_base_inst.m_typename;
|
641 |
|
|
else tnm = "uvm_object";
|
642 |
|
|
|
643 |
|
|
uvm_report_warning("CBPREG",
|
644 |
|
|
{"Callback object ", cb.get_name(),
|
645 |
|
|
" is already registered with type ", tnm }, UVM_NONE);
|
646 |
|
|
end
|
647 |
|
|
else begin
|
648 |
|
|
`uvm_cb_trace_noobj(cb,$sformatf("Add (%s) typewide callback %0s for type %s",
|
649 |
|
|
ordering.name(), cb.get_name(), m_base_inst.m_typename))
|
650 |
|
|
m_t_inst.m_add_tw_cbs(cb,ordering);
|
651 |
|
|
end
|
652 |
|
|
end
|
653 |
|
|
|
654 |
|
|
else begin
|
655 |
|
|
|
656 |
|
|
`uvm_cb_trace_noobj(cb,$sformatf("Add (%s) callback %0s to object %0s ",
|
657 |
|
|
ordering.name(), cb.get_name(), obj.get_full_name()))
|
658 |
|
|
|
659 |
|
|
q = m_base_inst.m_pool.get(obj);
|
660 |
|
|
|
661 |
|
|
if (q==null) begin
|
662 |
|
|
q=new;
|
663 |
|
|
m_base_inst.m_pool.add(obj,q);
|
664 |
|
|
end
|
665 |
|
|
|
666 |
|
|
if(q.size() == 0) begin
|
667 |
|
|
// Need to make sure that registered report catchers are added. This
|
668 |
|
|
// way users don't need to set up uvm_report_object as a super type.
|
669 |
|
|
uvm_report_object o;
|
670 |
|
|
|
671 |
|
|
if($cast(o,obj)) begin
|
672 |
|
|
uvm_queue#(uvm_callback) qr;
|
673 |
|
|
void'(uvm_callbacks#(uvm_report_object, uvm_callback)::get());
|
674 |
|
|
qr = uvm_callbacks#(uvm_report_object,uvm_callback)::m_t_inst.m_tw_cb_q;
|
675 |
|
|
for(int i=0; i
|
676 |
|
|
q.push_back(qr.get(i));
|
677 |
|
|
end
|
678 |
|
|
|
679 |
|
|
for(int i=0; i
|
680 |
|
|
q.push_back(m_t_inst.m_tw_cb_q.get(i));
|
681 |
|
|
end
|
682 |
|
|
|
683 |
|
|
//check if already exists in the queue
|
684 |
|
|
if(m_cb_find(q,cb) != -1) begin
|
685 |
|
|
uvm_report_warning("CBPREG", { "Callback object ", cb.get_name(), " is already registered",
|
686 |
|
|
" with object ", obj.get_full_name() }, UVM_NONE);
|
687 |
|
|
end
|
688 |
|
|
else begin
|
689 |
|
|
void'(m_cb_find_name(q, cb.get_name(), {"object instance ", obj.get_full_name()}));
|
690 |
|
|
if(ordering == UVM_APPEND)
|
691 |
|
|
q.push_back(cb);
|
692 |
|
|
else
|
693 |
|
|
q.push_front(cb);
|
694 |
|
|
end
|
695 |
|
|
end
|
696 |
|
|
endfunction
|
697 |
|
|
|
698 |
|
|
// Function: add_by_name
|
699 |
|
|
//
|
700 |
|
|
// Registers the given callback object, ~cb~, with one or more uvm_components.
|
701 |
|
|
// The components must already exist and must be type T or a derivative. As
|
702 |
|
|
// with the CB parameter is optional. ~root~ specifies the location in
|
703 |
|
|
// the component hierarchy to start the search for ~name~. See
|
704 |
|
|
// for more details on searching by name.
|
705 |
|
|
|
706 |
|
|
static function void add_by_name(string name,
|
707 |
|
|
uvm_callback cb,
|
708 |
|
|
uvm_component root,
|
709 |
|
|
uvm_apprepend ordering=UVM_APPEND);
|
710 |
|
|
uvm_component cq[$];
|
711 |
|
|
uvm_root top;
|
712 |
|
|
uvm_coreservice_t cs;
|
713 |
|
|
T t;
|
714 |
|
|
void'(get());
|
715 |
|
|
cs = uvm_coreservice_t::get();
|
716 |
|
|
top = cs.get_root();
|
717 |
|
|
|
718 |
|
|
if(cb==null) begin
|
719 |
|
|
uvm_report_error("CBUNREG", { "Null callback object cannot be registered with object(s) ",
|
720 |
|
|
name }, UVM_NONE);
|
721 |
|
|
return;
|
722 |
|
|
end
|
723 |
|
|
`uvm_cb_trace_noobj(cb,$sformatf("Add (%s) callback %0s by name to object(s) %0s ",
|
724 |
|
|
ordering.name(), cb.get_name(), name))
|
725 |
|
|
top.find_all(name,cq,root);
|
726 |
|
|
if(cq.size() == 0) begin
|
727 |
|
|
uvm_report_warning("CBNOMTC", { "add_by_name failed to find any components matching the name ",
|
728 |
|
|
name, ", callback ", cb.get_name(), " will not be registered." }, UVM_NONE);
|
729 |
|
|
end
|
730 |
|
|
foreach(cq[i]) begin
|
731 |
|
|
if($cast(t,cq[i])) begin
|
732 |
|
|
add(t,cb,ordering);
|
733 |
|
|
end
|
734 |
|
|
end
|
735 |
|
|
endfunction
|
736 |
|
|
|
737 |
|
|
|
738 |
|
|
// Function: delete
|
739 |
|
|
//
|
740 |
|
|
// Deletes the given callback object, ~cb~, from the queue associated with
|
741 |
|
|
// the given ~obj~ handle. The ~obj~ handle can be ~null~, which allows
|
742 |
|
|
// de-registration of callbacks without an object context.
|
743 |
|
|
// The ~cb~ is the callback handle; it must be non-~null~, and if the callback
|
744 |
|
|
// has already been removed from the object instance then a warning is
|
745 |
|
|
// issued. Note that the CB parameter is optional. For example, the
|
746 |
|
|
// following are equivalent:
|
747 |
|
|
//
|
748 |
|
|
//| uvm_callbacks#(my_comp)::delete(comp_a, cb);
|
749 |
|
|
//| uvm_callbacks#(my_comp, my_callback)::delete(comp_a,cb);
|
750 |
|
|
|
751 |
|
|
static function void delete(T obj, uvm_callback cb);
|
752 |
|
|
uvm_object b_obj = obj;
|
753 |
|
|
uvm_queue#(uvm_callback) q;
|
754 |
|
|
bit found;
|
755 |
|
|
int pos;
|
756 |
|
|
void'(get());
|
757 |
|
|
|
758 |
|
|
if(obj == null) begin
|
759 |
|
|
`uvm_cb_trace_noobj(cb,$sformatf("Delete typewide callback %0s for type %s",
|
760 |
|
|
cb.get_name(), m_base_inst.m_typename))
|
761 |
|
|
found = m_t_inst.m_delete_tw_cbs(cb);
|
762 |
|
|
end
|
763 |
|
|
else begin
|
764 |
|
|
`uvm_cb_trace_noobj(cb,$sformatf("Delete callback %0s from object %0s ",
|
765 |
|
|
cb.get_name(), obj.get_full_name()))
|
766 |
|
|
q = m_base_inst.m_pool.get(b_obj);
|
767 |
|
|
pos = m_cb_find(q,cb);
|
768 |
|
|
if(pos != -1) begin
|
769 |
|
|
q.delete(pos);
|
770 |
|
|
found = 1;
|
771 |
|
|
end
|
772 |
|
|
end
|
773 |
|
|
if(!found) begin
|
774 |
|
|
string nm;
|
775 |
|
|
if(obj==null) nm = "(*)"; else nm = obj.get_full_name();
|
776 |
|
|
uvm_report_warning("CBUNREG", { "Callback ", cb.get_name(), " cannot be removed from object ",
|
777 |
|
|
nm, " because it is not currently registered to that object." }, UVM_NONE);
|
778 |
|
|
end
|
779 |
|
|
endfunction
|
780 |
|
|
|
781 |
|
|
|
782 |
|
|
// Function: delete_by_name
|
783 |
|
|
//
|
784 |
|
|
// Removes the given callback object, ~cb~, associated with one or more
|
785 |
|
|
// uvm_component callback queues. As with the CB parameter is
|
786 |
|
|
// optional. ~root~ specifies the location in the component hierarchy to start
|
787 |
|
|
// the search for ~name~. See for more details on searching
|
788 |
|
|
// by name.
|
789 |
|
|
|
790 |
|
|
static function void delete_by_name(string name, uvm_callback cb,
|
791 |
|
|
uvm_component root);
|
792 |
|
|
uvm_component cq[$];
|
793 |
|
|
uvm_root top;
|
794 |
|
|
T t;
|
795 |
|
|
uvm_coreservice_t cs;
|
796 |
|
|
void'(get());
|
797 |
|
|
cs = uvm_coreservice_t::get();
|
798 |
|
|
top = cs.get_root();
|
799 |
|
|
|
800 |
|
|
`uvm_cb_trace_noobj(cb,$sformatf("Delete callback %0s by name from object(s) %0s ",
|
801 |
|
|
cb.get_name(), name))
|
802 |
|
|
top.find_all(name,cq,root);
|
803 |
|
|
if(cq.size() == 0) begin
|
804 |
|
|
uvm_report_warning("CBNOMTC", { "delete_by_name failed to find any components matching the name ",
|
805 |
|
|
name, ", callback ", cb.get_name(), " will not be unregistered." }, UVM_NONE);
|
806 |
|
|
end
|
807 |
|
|
foreach(cq[i]) begin
|
808 |
|
|
if($cast(t,cq[i])) begin
|
809 |
|
|
delete(t,cb);
|
810 |
|
|
end
|
811 |
|
|
end
|
812 |
|
|
endfunction
|
813 |
|
|
|
814 |
|
|
|
815 |
|
|
//--------------------------
|
816 |
|
|
// Group: Iterator Interface
|
817 |
|
|
//--------------------------
|
818 |
|
|
//
|
819 |
|
|
// This set of functions provide an iterator interface for callback queues. A facade
|
820 |
|
|
// class, is also available, and is the generally preferred way to
|
821 |
|
|
// iterate over callback queues.
|
822 |
|
|
|
823 |
|
|
static function void m_get_q (ref uvm_queue #(uvm_callback) q, input T obj);
|
824 |
|
|
if(!m_base_inst.m_pool.exists(obj)) begin //no instance specific
|
825 |
|
|
q = (obj == null) ? m_t_inst.m_tw_cb_q : m_t_inst.m_get_tw_cb_q(obj);
|
826 |
|
|
end
|
827 |
|
|
else begin
|
828 |
|
|
q = m_base_inst.m_pool.get(obj);
|
829 |
|
|
if(q==null) begin
|
830 |
|
|
q=new;
|
831 |
|
|
m_base_inst.m_pool.add(obj,q);
|
832 |
|
|
end
|
833 |
|
|
end
|
834 |
|
|
endfunction
|
835 |
|
|
|
836 |
|
|
|
837 |
|
|
// Function: get_first
|
838 |
|
|
//
|
839 |
|
|
// Returns the first enabled callback of type CB which resides in the queue for ~obj~.
|
840 |
|
|
// If ~obj~ is ~null~ then the typewide queue for T is searched. ~itr~ is the iterator;
|
841 |
|
|
// it will be updated with a value that can be supplied to to get the next
|
842 |
|
|
// callback object.
|
843 |
|
|
//
|
844 |
|
|
// If the queue is empty then ~null~ is returned.
|
845 |
|
|
//
|
846 |
|
|
// The iterator class may be used as an alternative, simplified,
|
847 |
|
|
// iterator interface.
|
848 |
|
|
|
849 |
|
|
static function CB get_first (ref int itr, input T obj);
|
850 |
|
|
uvm_queue#(uvm_callback) q;
|
851 |
|
|
CB cb;
|
852 |
|
|
void'(get());
|
853 |
|
|
m_get_q(q,obj);
|
854 |
|
|
for(itr = 0; itr
|
855 |
|
|
if($cast(cb, q.get(itr)) && cb.callback_mode())
|
856 |
|
|
return cb;
|
857 |
|
|
return null;
|
858 |
|
|
endfunction
|
859 |
|
|
|
860 |
|
|
// Function: get_last
|
861 |
|
|
//
|
862 |
|
|
// Returns the last enabled callback of type CB which resides in the queue for ~obj~.
|
863 |
|
|
// If ~obj~ is ~null~ then the typewide queue for T is searched. ~itr~ is the iterator;
|
864 |
|
|
// it will be updated with a value that can be supplied to to get the previous
|
865 |
|
|
// callback object.
|
866 |
|
|
//
|
867 |
|
|
// If the queue is empty then ~null~ is returned.
|
868 |
|
|
//
|
869 |
|
|
// The iterator class may be used as an alternative, simplified,
|
870 |
|
|
// iterator interface.
|
871 |
|
|
|
872 |
|
|
static function CB get_last (ref int itr, input T obj);
|
873 |
|
|
uvm_queue#(uvm_callback) q;
|
874 |
|
|
CB cb;
|
875 |
|
|
void'(get());
|
876 |
|
|
m_get_q(q,obj);
|
877 |
|
|
for(itr = q.size()-1; itr>=0; --itr)
|
878 |
|
|
if ($cast(cb, q.get(itr)) && cb.callback_mode())
|
879 |
|
|
return cb;
|
880 |
|
|
return null;
|
881 |
|
|
endfunction
|
882 |
|
|
|
883 |
|
|
|
884 |
|
|
// Function: get_next
|
885 |
|
|
//
|
886 |
|
|
// Returns the next enabled callback of type CB which resides in the queue for ~obj~,
|
887 |
|
|
// using ~itr~ as the starting point. If ~obj~ is ~null~ then the typewide queue for T
|
888 |
|
|
// is searched. ~itr~ is the iterator; it will be updated with a value that can be
|
889 |
|
|
// supplied to to get the next callback object.
|
890 |
|
|
//
|
891 |
|
|
// If no more callbacks exist in the queue, then ~null~ is returned. will
|
892 |
|
|
// continue to return ~null~ in this case until or has been used to reset
|
893 |
|
|
// the iterator.
|
894 |
|
|
//
|
895 |
|
|
// The iterator class may be used as an alternative, simplified,
|
896 |
|
|
// iterator interface.
|
897 |
|
|
|
898 |
|
|
static function CB get_next (ref int itr, input T obj);
|
899 |
|
|
uvm_queue#(uvm_callback) q;
|
900 |
|
|
CB cb;
|
901 |
|
|
void'(get());
|
902 |
|
|
m_get_q(q,obj);
|
903 |
|
|
for(itr = itr+1; itr
|
904 |
|
|
if ($cast(cb, q.get(itr)) && cb.callback_mode())
|
905 |
|
|
return cb;
|
906 |
|
|
return null;
|
907 |
|
|
endfunction
|
908 |
|
|
|
909 |
|
|
|
910 |
|
|
// Function: get_prev
|
911 |
|
|
//
|
912 |
|
|
// Returns the previous enabled callback of type CB which resides in the queue for ~obj~,
|
913 |
|
|
// using ~itr~ as the starting point. If ~obj~ is ~null~ then the typewide queue for T
|
914 |
|
|
// is searched. ~itr~ is the iterator; it will be updated with a value that can be
|
915 |
|
|
// supplied to to get the previous callback object.
|
916 |
|
|
//
|
917 |
|
|
// If no more callbacks exist in the queue, then ~null~ is returned. will
|
918 |
|
|
// continue to return ~null~ in this case until or has been used to reset
|
919 |
|
|
// the iterator.
|
920 |
|
|
//
|
921 |
|
|
// The iterator class may be used as an alternative, simplified,
|
922 |
|
|
// iterator interface.
|
923 |
|
|
|
924 |
|
|
static function CB get_prev (ref int itr, input T obj);
|
925 |
|
|
uvm_queue#(uvm_callback) q;
|
926 |
|
|
CB cb;
|
927 |
|
|
void'(get());
|
928 |
|
|
m_get_q(q,obj);
|
929 |
|
|
for(itr = itr-1; itr>= 0; --itr)
|
930 |
|
|
if($cast(cb, q.get(itr)) && cb.callback_mode())
|
931 |
|
|
return cb;
|
932 |
|
|
return null;
|
933 |
|
|
endfunction
|
934 |
|
|
|
935 |
|
|
|
936 |
|
|
//-------------
|
937 |
|
|
// Group: Debug
|
938 |
|
|
//-------------
|
939 |
|
|
|
940 |
|
|
// Function: display
|
941 |
|
|
//
|
942 |
|
|
// This function displays callback information for ~obj~. If ~obj~ is
|
943 |
|
|
// ~null~, then it displays callback information for all objects
|
944 |
|
|
// of type ~T~, including typewide callbacks.
|
945 |
|
|
|
946 |
|
|
static function void display(T obj=null);
|
947 |
|
|
// For documentation purposes, need a function wrapper here.
|
948 |
|
|
void'(get());
|
949 |
|
|
super_type::display(obj);
|
950 |
|
|
endfunction
|
951 |
|
|
|
952 |
|
|
endclass
|
953 |
|
|
|
954 |
|
|
|
955 |
|
|
|
956 |
|
|
//------------------------------------------------------------------------------
|
957 |
|
|
//
|
958 |
|
|
// Class- uvm_derived_callbacks #(T,ST,CB)
|
959 |
|
|
//
|
960 |
|
|
//------------------------------------------------------------------------------
|
961 |
|
|
// This type is not really expected to be used directly by the user, instead they are
|
962 |
|
|
// expected to use the macro `uvm_set_super_type. The sole purpose of this type is to
|
963 |
|
|
// allow for setting up of the derived_type/super_type mapping.
|
964 |
|
|
//------------------------------------------------------------------------------
|
965 |
|
|
|
966 |
|
|
class uvm_derived_callbacks#(type T=uvm_object, type ST=uvm_object, type CB=uvm_callback)
|
967 |
|
|
extends uvm_callbacks#(T,CB);
|
968 |
|
|
|
969 |
|
|
typedef uvm_derived_callbacks#(T,ST,CB) this_type;
|
970 |
|
|
typedef uvm_callbacks#(T) this_user_type;
|
971 |
|
|
typedef uvm_callbacks#(ST) this_super_type;
|
972 |
|
|
|
973 |
|
|
// Singleton instance is used for type checking
|
974 |
|
|
static this_type m_d_inst;
|
975 |
|
|
static this_user_type m_user_inst;
|
976 |
|
|
static this_super_type m_super_inst;
|
977 |
|
|
|
978 |
|
|
// typeinfo
|
979 |
|
|
static uvm_typeid_base m_s_typeid;
|
980 |
|
|
|
981 |
|
|
static function this_type get();
|
982 |
|
|
m_user_inst = this_user_type::get();
|
983 |
|
|
m_super_inst = this_super_type::get();
|
984 |
|
|
m_s_typeid = uvm_typeid#(ST)::get();
|
985 |
|
|
if(m_d_inst == null) begin
|
986 |
|
|
m_d_inst = new;
|
987 |
|
|
end
|
988 |
|
|
return m_d_inst;
|
989 |
|
|
endfunction
|
990 |
|
|
|
991 |
|
|
static function bit register_super_type(string tname="", sname="");
|
992 |
|
|
this_user_type u_inst = this_user_type::get();
|
993 |
|
|
this_type inst = this_type::get();
|
994 |
|
|
uvm_callbacks_base s_obj;
|
995 |
|
|
|
996 |
|
|
this_user_type::m_t_inst.m_typename = tname;
|
997 |
|
|
|
998 |
|
|
if(sname != "") m_s_typeid.typename = sname;
|
999 |
|
|
|
1000 |
|
|
if(u_inst.m_super_type != null) begin
|
1001 |
|
|
if(u_inst.m_super_type == m_s_typeid) return 1;
|
1002 |
|
|
uvm_report_warning("CBTPREG", { "Type ", tname, " is already registered to super type ",
|
1003 |
|
|
this_super_type::m_t_inst.m_typename, ". Ignoring attempt to register to super type ",
|
1004 |
|
|
sname}, UVM_NONE);
|
1005 |
|
|
return 1;
|
1006 |
|
|
end
|
1007 |
|
|
if(this_super_type::m_t_inst.m_typename == "")
|
1008 |
|
|
this_super_type::m_t_inst.m_typename = sname;
|
1009 |
|
|
u_inst.m_super_type = m_s_typeid;
|
1010 |
|
|
u_inst.m_base_inst.m_super_type = m_s_typeid;
|
1011 |
|
|
s_obj = uvm_typeid_base::typeid_map[m_s_typeid];
|
1012 |
|
|
s_obj.m_derived_types.push_back(m_typeid);
|
1013 |
|
|
return 1;
|
1014 |
|
|
endfunction
|
1015 |
|
|
|
1016 |
|
|
endclass
|
1017 |
|
|
|
1018 |
|
|
|
1019 |
|
|
//------------------------------------------------------------------------------
|
1020 |
|
|
//
|
1021 |
|
|
// CLASS: uvm_callback_iter
|
1022 |
|
|
//
|
1023 |
|
|
//------------------------------------------------------------------------------
|
1024 |
|
|
// The ~uvm_callback_iter~ class is an iterator class for iterating over
|
1025 |
|
|
// callback queues of a specific callback type. The typical usage of
|
1026 |
|
|
// the class is:
|
1027 |
|
|
//
|
1028 |
|
|
//| uvm_callback_iter#(mycomp,mycb) iter = new(this);
|
1029 |
|
|
//| for(mycb cb = iter.first(); cb != null; cb = iter.next())
|
1030 |
|
|
//| cb.dosomething();
|
1031 |
|
|
//
|
1032 |
|
|
// The callback iteration macros, <`uvm_do_callbacks> and
|
1033 |
|
|
// <`uvm_do_callbacks_exit_on> provide a simple method for iterating
|
1034 |
|
|
// callbacks and executing the callback methods.
|
1035 |
|
|
//------------------------------------------------------------------------------
|
1036 |
|
|
|
1037 |
|
|
class uvm_callback_iter#(type T = uvm_object, type CB = uvm_callback);
|
1038 |
|
|
|
1039 |
|
|
local int m_i;
|
1040 |
|
|
local T m_obj;
|
1041 |
|
|
local CB m_cb;
|
1042 |
|
|
|
1043 |
|
|
// Function: new
|
1044 |
|
|
//
|
1045 |
|
|
// Creates a new callback iterator object. It is required that the object
|
1046 |
|
|
// context be provided.
|
1047 |
|
|
|
1048 |
|
|
function new(T obj);
|
1049 |
|
|
m_obj = obj;
|
1050 |
|
|
endfunction
|
1051 |
|
|
|
1052 |
|
|
// Function: first
|
1053 |
|
|
//
|
1054 |
|
|
// Returns the first valid (enabled) callback of the callback type (or
|
1055 |
|
|
// a derivative) that is in the queue of the context object. If the
|
1056 |
|
|
// queue is empty then ~null~ is returned.
|
1057 |
|
|
|
1058 |
|
|
function CB first();
|
1059 |
|
|
m_cb = uvm_callbacks#(T,CB)::get_first(m_i, m_obj);
|
1060 |
|
|
return m_cb;
|
1061 |
|
|
endfunction
|
1062 |
|
|
|
1063 |
|
|
// Function: last
|
1064 |
|
|
//
|
1065 |
|
|
// Returns the last valid (enabled) callback of the callback type (or
|
1066 |
|
|
// a derivative) that is in the queue of the context object. If the
|
1067 |
|
|
// queue is empty then ~null~ is returned.
|
1068 |
|
|
|
1069 |
|
|
function CB last();
|
1070 |
|
|
m_cb = uvm_callbacks#(T,CB)::get_last(m_i, m_obj);
|
1071 |
|
|
return m_cb;
|
1072 |
|
|
endfunction
|
1073 |
|
|
|
1074 |
|
|
// Function: next
|
1075 |
|
|
//
|
1076 |
|
|
// Returns the next valid (enabled) callback of the callback type (or
|
1077 |
|
|
// a derivative) that is in the queue of the context object. If there
|
1078 |
|
|
// are no more valid callbacks in the queue, then ~null~ is returned.
|
1079 |
|
|
|
1080 |
|
|
function CB next();
|
1081 |
|
|
m_cb = uvm_callbacks#(T,CB)::get_next(m_i, m_obj);
|
1082 |
|
|
return m_cb;
|
1083 |
|
|
endfunction
|
1084 |
|
|
|
1085 |
|
|
// Function: prev
|
1086 |
|
|
//
|
1087 |
|
|
// Returns the previous valid (enabled) callback of the callback type (or
|
1088 |
|
|
// a derivative) that is in the queue of the context object. If there
|
1089 |
|
|
// are no more valid callbacks in the queue, then ~null~ is returned.
|
1090 |
|
|
|
1091 |
|
|
function CB prev();
|
1092 |
|
|
m_cb = uvm_callbacks#(T,CB)::get_prev(m_i, m_obj);
|
1093 |
|
|
return m_cb;
|
1094 |
|
|
endfunction
|
1095 |
|
|
|
1096 |
|
|
// Function: get_cb
|
1097 |
|
|
//
|
1098 |
|
|
// Returns the last callback accessed via a first() or next()
|
1099 |
|
|
// call.
|
1100 |
|
|
|
1101 |
|
|
function CB get_cb();
|
1102 |
|
|
return m_cb;
|
1103 |
|
|
endfunction
|
1104 |
|
|
|
1105 |
|
|
/****
|
1106 |
|
|
function void trace(uvm_object obj = null);
|
1107 |
|
|
if (m_cb != null && T::cbs::get_debug_flags() & UVM_CALLBACK_TRACE) begin
|
1108 |
|
|
uvm_report_object reporter = null;
|
1109 |
|
|
string who = "Executing ";
|
1110 |
|
|
void'($cast(reporter, obj));
|
1111 |
|
|
if (reporter == null) void'($cast(reporter, m_obj));
|
1112 |
|
|
if (reporter == null) reporter = uvm_top;
|
1113 |
|
|
if (obj != null) who = {obj.get_full_name(), " is executing "};
|
1114 |
|
|
else if (m_obj != null) who = {m_obj.get_full_name(), " is executing "};
|
1115 |
|
|
reporter.uvm_report_info("CLLBK_TRC", {who, "callback ", m_cb.get_name()}, UVM_LOW);
|
1116 |
|
|
end
|
1117 |
|
|
endfunction
|
1118 |
|
|
****/
|
1119 |
|
|
endclass
|
1120 |
|
|
|
1121 |
|
|
|
1122 |
|
|
|
1123 |
|
|
//------------------------------------------------------------------------------
|
1124 |
|
|
// CLASS: uvm_callback
|
1125 |
|
|
//
|
1126 |
|
|
// The ~uvm_callback~ class is the base class for user-defined callback classes.
|
1127 |
|
|
// Typically, the component developer defines an application-specific callback
|
1128 |
|
|
// class that extends from this class. In it, he defines one or more virtual
|
1129 |
|
|
// methods, called a ~callback interface~, that represent the hooks available
|
1130 |
|
|
// for user override.
|
1131 |
|
|
//
|
1132 |
|
|
// Methods intended for optional override should not be declared ~pure.~ Usually,
|
1133 |
|
|
// all the callback methods are defined with empty implementations so users have
|
1134 |
|
|
// the option of overriding any or all of them.
|
1135 |
|
|
//
|
1136 |
|
|
// The prototypes for each hook method are completely application specific with
|
1137 |
|
|
// no restrictions.
|
1138 |
|
|
//------------------------------------------------------------------------------
|
1139 |
|
|
|
1140 |
|
|
class uvm_callback extends uvm_object;
|
1141 |
|
|
|
1142 |
|
|
static uvm_report_object reporter = new("cb_tracer");
|
1143 |
|
|
|
1144 |
|
|
protected bit m_enabled = 1;
|
1145 |
|
|
|
1146 |
|
|
// Function: new
|
1147 |
|
|
//
|
1148 |
|
|
// Creates a new uvm_callback object, giving it an optional ~name~.
|
1149 |
|
|
|
1150 |
|
|
function new(string name="uvm_callback");
|
1151 |
|
|
super.new(name);
|
1152 |
|
|
endfunction
|
1153 |
|
|
|
1154 |
|
|
|
1155 |
|
|
// Function: callback_mode
|
1156 |
|
|
//
|
1157 |
|
|
// Enable/disable callbacks (modeled like rand_mode and constraint_mode).
|
1158 |
|
|
|
1159 |
|
|
function bit callback_mode(int on=-1);
|
1160 |
|
|
if(on == 0 || on == 1) begin
|
1161 |
|
|
`uvm_cb_trace_noobj(this,$sformatf("Setting callback mode for %s to %s",
|
1162 |
|
|
get_name(), ((on==1) ? "ENABLED":"DISABLED")))
|
1163 |
|
|
end
|
1164 |
|
|
else begin
|
1165 |
|
|
`uvm_cb_trace_noobj(this,$sformatf("Callback mode for %s is %s",
|
1166 |
|
|
get_name(), ((m_enabled==1) ? "ENABLED":"DISABLED")))
|
1167 |
|
|
end
|
1168 |
|
|
callback_mode = m_enabled;
|
1169 |
|
|
if(on==0) m_enabled=0;
|
1170 |
|
|
if(on==1) m_enabled=1;
|
1171 |
|
|
endfunction
|
1172 |
|
|
|
1173 |
|
|
|
1174 |
|
|
// Function: is_enabled
|
1175 |
|
|
//
|
1176 |
|
|
// Returns 1 if the callback is enabled, 0 otherwise.
|
1177 |
|
|
|
1178 |
|
|
function bit is_enabled();
|
1179 |
|
|
return callback_mode();
|
1180 |
|
|
endfunction
|
1181 |
|
|
|
1182 |
|
|
static string type_name = "uvm_callback";
|
1183 |
|
|
|
1184 |
|
|
|
1185 |
|
|
// Function: get_type_name
|
1186 |
|
|
//
|
1187 |
|
|
// Returns the type name of this callback object.
|
1188 |
|
|
|
1189 |
|
|
virtual function string get_type_name();
|
1190 |
|
|
return type_name;
|
1191 |
|
|
endfunction
|
1192 |
|
|
|
1193 |
|
|
endclass
|
1194 |
|
|
|
1195 |
|
|
|
1196 |
|
|
`endif // UVM_CALLBACK_SVH
|
1197 |
|
|
|
1198 |
|
|
|