OpenCores
URL https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk

Subversion Repositories uart2bus_testbench

[/] [uart2bus_testbench/] [trunk/] [tb/] [uvm_src/] [base/] [uvm_phase.svh] - Blame information for rev 16

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 HanySalah
//
2
//----------------------------------------------------------------------
3
//   Copyright 2007-2011 Mentor Graphics Corporation
4
//   Copyright 2007-2010 Cadence Design Systems, Inc.
5
//   Copyright 2010-2013 Synopsys, Inc.
6
//   Copyright 2013      NVIDIA Corporation
7
//   Copyright 2013      Cisco Systems, Inc.
8
//   All Rights Reserved Worldwide
9
//
10
//   Licensed under the Apache License, Version 2.0 (the
11
//   "License"); you may not use this file except in
12
//   compliance with the License.  You may obtain a copy of
13
//   the License at
14
//
15
//       http://www.apache.org/licenses/LICENSE-2.0
16
//
17
//   Unless required by applicable law or agreed to in
18
//   writing, software distributed under the License is
19
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
20
//   CONDITIONS OF ANY KIND, either express or implied.  See
21
//   the License for the specific language governing
22
//   permissions and limitations under the License.
23
//----------------------------------------------------------------------
24
 
25
typedef class uvm_test_done_objection;
26
typedef class uvm_sequencer_base;
27
 
28
typedef class uvm_domain;
29
typedef class uvm_task_phase;
30
 
31
typedef class uvm_phase_cb;
32
 
33
 
34
 
35
//------------------------------------------------------------------------------
36
//
37
// Section: Phasing Definition classes
38
//
39
//------------------------------------------------------------------------------
40
//
41
// The following class are used to specify a phase and its implied functionality.
42
//
43
 
44
//------------------------------------------------------------------------------
45
//
46
// Class: uvm_phase
47
//
48
//------------------------------------------------------------------------------
49
//
50
// This base class defines everything about a phase: behavior, state, and context.
51
//
52
// To define behavior, it is extended by UVM or the user to create singleton
53
// objects which capture the definition of what the phase does and how it does it.
54
// These are then cloned to produce multiple nodes which are hooked up in a graph
55
// structure to provide context: which phases follow which, and to hold the state
56
// of the phase throughout its lifetime.
57
// UVM provides default extensions of this class for the standard runtime phases.
58
// VIP Providers can likewise extend this class to define the phase functor for a
59
// particular component context as required.
60
//
61
// This base class defines everything about a phase: behavior, state, and context.
62
//
63
// To define behavior, it is extended by UVM or the user to create singleton
64
// objects which capture the definition of what the phase does and how it does it.
65
// These are then cloned to produce multiple nodes which are hooked up in a graph
66
// structure to provide context: which phases follow which, and to hold the state
67
// of the phase throughout its lifetime.
68
// UVM provides default extensions of this class for the standard runtime phases.
69
// VIP Providers can likewise extend this class to define the phase functor for a
70
// particular component context as required.
71
//
72
// *Phase Definition*
73
//
74
// Singleton instances of those extensions are provided as package variables.
75
// These instances define the attributes of the phase (not what state it is in)
76
// They are then cloned into schedule nodes which point back to one of these
77
// implementations, and calls its virtual task or function methods on each
78
// participating component.
79
// It is the base class for phase functors, for both predefined and
80
// user-defined phases. Per-component overrides can use a customized imp.
81
//
82
// To create custom phases, do not extend uvm_phase directly: see the
83
// three predefined extended classes below which encapsulate behavior for
84
// different phase types: task, bottom-up function and top-down function.
85
//
86
// Extend the appropriate one of these to create a uvm_YOURNAME_phase class
87
// (or YOURPREFIX_NAME_phase class) for each phase, containing the default
88
// implementation of the new phase, which must be a uvm_component-compatible
89
// delegate, and which may be a ~null~ implementation. Instantiate a singleton
90
// instance of that class for your code to use when a phase handle is required.
91
// If your custom phase depends on methods that are not in uvm_component, but
92
// are within an extended class, then extend the base YOURPREFIX_NAME_phase
93
// class with parameterized component class context as required, to create a
94
// specialized functor which calls your extended component class methods.
95
// This scheme ensures compile-safety for your extended component classes while
96
// providing homogeneous base types for APIs and underlying data structures.
97
//
98
// *Phase Context*
99
//
100
// A schedule is a coherent group of one or mode phase/state nodes linked
101
// together by a graph structure, allowing arbitrary linear/parallel
102
// relationships to be specified, and executed by stepping through them in
103
// the graph order.
104
// Each schedule node points to a phase and holds the execution state of that
105
// phase, and has optional links to other nodes for synchronization.
106
//
107
// The main operations are: construct, add phases, and instantiate
108
// hierarchically within another schedule.
109
//
110
// Structure is a DAG (Directed Acyclic Graph). Each instance is a node
111
// connected to others to form the graph. Hierarchy is overlaid with m_parent.
112
// Each node in the graph has zero or more successors, and zero or more
113
// predecessors. No nodes are completely isolated from others. Exactly
114
// one node has zero predecessors. This is the root node. Also the graph
115
// is acyclic, meaning for all nodes in the graph, by following the forward
116
// arrows you will never end up back where you started but you will eventually
117
// reach a node that has no successors.
118
//
119
// *Phase State*
120
//
121
// A given phase may appear multiple times in the complete phase graph, due
122
// to the multiple independent domain feature, and the ability for different
123
// VIP to customize their own phase schedules perhaps reusing existing phases.
124
// Each node instance in the graph maintains its own state of execution.
125
//
126
// *Phase Handle*
127
//
128
// Handles of this type uvm_phase are used frequently in the API, both by
129
// the user, to access phasing-specific API, and also as a parameter to some
130
// APIs. In many cases, the singleton phase handles can be
131
// used (eg. ) in APIs. For those APIs that need to look
132
// up that phase in the graph, this is done automatically.
133
 
134
class uvm_phase extends uvm_object;
135
 
136
  //`uvm_object_utils(uvm_phase)
137
 
138
  `uvm_register_cb(uvm_phase, uvm_phase_cb)
139
 
140
 
141
  //--------------------
142
  // Group: Construction
143
  //--------------------
144
 
145
  // Function: new
146
  //
147
  // Create a new phase node, with a name and a note of its type
148
  //   name   - name of this phase
149
  //   type   - a value in 
150
  //
151
  extern function new(string name="uvm_phase",
152
                      uvm_phase_type phase_type=UVM_PHASE_SCHEDULE,
153
                      uvm_phase parent=null);
154
 
155
  // Function: get_phase_type
156
  //
157
  // Returns the phase type as defined by 
158
  //
159
  extern function uvm_phase_type get_phase_type();
160
 
161
 
162
  //-------------
163
  // Group: State
164
  //-------------
165
 
166
  // Function: get_state
167
  //
168
  // Accessor to return current state of this phase
169
  //
170
  extern function uvm_phase_state get_state();
171
 
172
 
173
  // Function: get_run_count
174
  //
175
  // Accessor to return the integer number of times this phase has executed
176
  //
177
  extern function int get_run_count();
178
 
179
 
180
  // Function: find_by_name
181
  //
182
  // Locate a phase node with the specified ~name~ and return its handle.
183
  // With ~stay_in_scope~ set, searches only within this phase's schedule or
184
  // domain.
185
  //
186
  extern function uvm_phase find_by_name(string name, bit stay_in_scope=1);
187
 
188
 
189
  // Function: find
190
  //
191
  // Locate the phase node with the specified ~phase~ IMP and return its handle.
192
  // With ~stay_in_scope~ set, searches only within this phase's schedule or
193
  // domain.
194
  //
195
  extern function uvm_phase find(uvm_phase phase, bit stay_in_scope=1);
196
 
197
 
198
  // Function: is
199
  //
200
  // returns 1 if the containing uvm_phase refers to the same phase
201
  // as the phase argument, 0 otherwise
202
  //
203
  extern function bit is(uvm_phase phase);
204
 
205
 
206
  // Function: is_before
207
  //
208
  // Returns 1 if the containing uvm_phase refers to a phase that is earlier
209
  // than the phase argument, 0 otherwise
210
  //
211
  extern function bit is_before(uvm_phase phase);
212
 
213
 
214
  // Function: is_after
215
  //
216
  // returns 1 if the containing uvm_phase refers to a phase that is later
217
  // than the phase argument, 0 otherwise
218
  //
219
  extern function bit is_after(uvm_phase phase);
220
 
221
 
222
  //-----------------
223
  // Group: Callbacks
224
  //-----------------
225
 
226
  // Function: exec_func
227
  //
228
  // Implements the functor/delegate functionality for a function phase type
229
  //   comp  - the component to execute the functionality upon
230
  //   phase - the phase schedule that originated this phase call
231
  //
232
  virtual function void exec_func(uvm_component comp, uvm_phase phase); endfunction
233
 
234
 
235
  // Function: exec_task
236
  //
237
  // Implements the functor/delegate functionality for a task phase type
238
  //   comp  - the component to execute the functionality upon
239
  //   phase - the phase schedule that originated this phase call
240
  //
241
  virtual task exec_task(uvm_component comp, uvm_phase phase); endtask
242
 
243
 
244
 
245
  //----------------
246
  // Group: Schedule
247
  //----------------
248
 
249
  // Function: add
250
  //
251
  // Build up a schedule structure inserting phase by phase, specifying linkage
252
  //
253
  // Phases can be added anywhere, in series or parallel with existing nodes
254
  //
255
  //   phase        - handle of singleton derived imp containing actual functor.
256
  //                  by default the new phase is appended to the schedule
257
  //   with_phase   - specify to add the new phase in parallel with this one
258
  //   after_phase  - specify to add the new phase as successor to this one
259
  //   before_phase - specify to add the new phase as predecessor to this one
260
  //
261
  extern function void add(uvm_phase phase,
262
                           uvm_phase with_phase=null,
263
                           uvm_phase after_phase=null,
264
                           uvm_phase before_phase=null);
265
 
266
 
267
  // Function: get_parent
268
  //
269
  // Returns the parent schedule node, if any, for hierarchical graph traversal
270
  //
271
  extern function uvm_phase get_parent();
272
 
273
 
274
  // Function: get_full_name
275
  //
276
  // Returns the full path from the enclosing domain down to this node.
277
  // The singleton IMP phases have no hierarchy.
278
  //
279
  extern virtual function string get_full_name();
280
 
281
 
282
  // Function: get_schedule
283
  //
284
  // Returns the topmost parent schedule node, if any, for hierarchical graph traversal
285
  //
286
  extern function uvm_phase get_schedule(bit hier = 0);
287
 
288
 
289
  // Function: get_schedule_name
290
  //
291
  // Returns the schedule name associated with this phase node
292
  //
293
  extern function string get_schedule_name(bit hier = 0);
294
 
295
 
296
  // Function: get_domain
297
  //
298
  // Returns the enclosing domain
299
  //
300
  extern function uvm_domain get_domain();
301
 
302
 
303
  // Function: get_imp
304
  //
305
  // Returns the phase implementation for this this node.
306
  // Returns ~null~ if this phase type is not a UVM_PHASE_LEAF_NODE.
307
  //
308
  extern function uvm_phase get_imp();
309
 
310
 
311
  // Function: get_domain_name
312
  //
313
  // Returns the domain name associated with this phase node
314
  //
315
  extern function string get_domain_name();
316
 
317
  // Function: get_adjacent_predecessor_nodes
318
  //
319
  // Provides an array of nodes which are predecessors to
320
  // ~this~ phase node.  A 'predecessor node' is defined
321
  // as any phase node which lies prior to ~this~ node in
322
  // the phase graph, with no nodes between ~this~ node and
323
  // the predecessor node.
324
  //
325
  extern function void get_adjacent_predecessor_nodes(ref uvm_phase pred[]);
326
 
327
  // Function: get_adjacent_successor_nodes
328
  //
329
  // Provides an array of nodes which are successors to
330
  // ~this~ phase node.  A 'successor's node' is defined
331
  // as any phase node which comes after ~this~ node in
332
  // the phase graph, with no nodes between ~this~ node
333
  // and the successor node.
334
  //
335
  extern function void get_adjacent_successor_nodes(ref uvm_phase succ[]);
336
 
337
  //-----------------------
338
  // Group: Phase Done Objection
339
  //-----------------------
340
  //
341
  // Task-based phase nodes within the phasing graph provide a 
342
  // based interface for prolonging the execution of the phase.  All other
343
  // phase types do not contain an objection, and will report a fatal error
344
  // if the user attempts to ~raise~, ~drop~, or ~get_objection_count~.
345
 
346
  // Function- m_report_null_objection
347
  // Simplifies the reporting of ~null~ objection errors
348
  extern function void m_report_null_objection(uvm_object obj,
349
                                               string description,
350
                                               int count,
351
                                               string action);
352
 
353
  // Function: get_objection
354
  //
355
  // Return the  that gates the termination of the phase.
356
  //
357
  function uvm_objection get_objection(); return this.phase_done; endfunction
358
 
359
  // Function: raise_objection
360
  //
361
  // Raise an objection to ending this phase
362
  // Provides components with greater control over the phase flow for
363
  // processes which are not implicit objectors to the phase.
364
  //
365
  //|   while(1) begin
366
  //|     some_phase.raise_objection(this);
367
  //|     ...
368
  //|     some_phase.drop_objection(this);
369
  //|   end
370
  //|   ...
371
  //
372
  extern virtual function void raise_objection (uvm_object obj,
373
                                                string description="",
374
                                                int count=1);
375
 
376
  // Function: drop_objection
377
  //
378
  // Drop an objection to ending this phase
379
  //
380
  // The drop is expected to be matched with an earlier raise.
381
  //
382
  extern virtual function void drop_objection (uvm_object obj,
383
                                               string description="",
384
                                               int count=1);
385
 
386
 
387
  // Function: get_objection_count
388
  //
389
  // Returns the current number of objections to ending this phase raised by the given ~object~.
390
  //
391
  extern virtual function int get_objection_count( uvm_object obj=null );
392
 
393
  //-----------------------
394
  // Group: Synchronization
395
  //-----------------------
396
  // The functions 'sync' and 'unsync' add soft sync relationships between nodes
397
  //
398
  // Summary of usage:
399
  //| my_phase.sync(.target(domain)
400
  //|              [,.phase(phase)[,.with_phase(phase)]]);
401
  //| my_phase.unsync(.target(domain)
402
  //|                [,.phase(phase)[,.with_phase(phase)]]);
403
  //
404
  // Components in different schedule domains can be phased independently or in sync
405
  // with each other. An API is provided to specify synchronization rules between any
406
  // two domains. Synchronization can be done at any of three levels:
407
  //
408
  // - the domain's whole phase schedule can be synchronized
409
  // - a phase can be specified, to sync that phase with a matching counterpart
410
  // - or a more detailed arbitrary synchronization between any two phases
411
  //
412
  // Each kind of synchronization causes the same underlying data structures to
413
  // be managed. Like other APIs, we use the parameter dot-notation to set
414
  // optional parameters.
415
  //
416
  // When a domain is synced with another domain, all of the matching phases in
417
  // the two domains get a 'with' relationship between them. Likewise, if a domain
418
  // is unsynched, all of the matching phases that have a 'with' relationship have
419
  // the dependency removed. It is possible to sync two domains and then just
420
  // remove a single phase from the dependency relationship by unsyncing just
421
  // the one phase.
422
 
423
 
424
  // Function: sync
425
  //
426
  // Synchronize two domains, fully or partially
427
  //
428
  //   target       - handle of target domain to synchronize this one to
429
  //   phase        - optional single phase in this domain to synchronize,
430
  //                  otherwise sync all
431
  //   with_phase   - optional different target-domain phase to synchronize with,
432
  //                  otherwise use ~phase~ in the target domain
433
  //
434
  extern function void sync(uvm_domain target,
435
                            uvm_phase phase=null,
436
                            uvm_phase with_phase=null);
437
 
438
  // Function: unsync
439
  //
440
  // Remove synchronization between two domains, fully or partially
441
  //
442
  //   target       - handle of target domain to remove synchronization from
443
  //   phase        - optional single phase in this domain to un-synchronize,
444
  //                  otherwise unsync all
445
  //   with_phase   - optional different target-domain phase to un-synchronize with,
446
  //                  otherwise use ~phase~ in the target domain
447
  //
448
  extern function void unsync(uvm_domain target,
449
                              uvm_phase phase=null,
450
                              uvm_phase with_phase=null);
451
 
452
 
453
  // Function: wait_for_state
454
  //
455
  // Wait until this phase compares with the given ~state~ and ~op~ operand.
456
  // For  and  operands, several  can be
457
  // supplied by ORing their enum constants, in which case the caller will
458
  // wait until the phase state is any of (UVM_EQ) or none of (UVM_NE) the
459
  // provided states.
460
  //
461
  // To wait for the phase to be at the started state or after
462
  //
463
  //| wait_for_state(UVM_PHASE_STARTED, UVM_GTE);
464
  //
465
  // To wait for the phase to be either started or executing
466
  //
467
  //| wait_for_state(UVM_PHASE_STARTED | UVM_PHASE_EXECUTING, UVM_EQ);
468
  //
469
  extern task wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ);
470
 
471
 
472
  //---------------
473
  // Group: Jumping
474
  //---------------
475
 
476
  // Force phases to jump forward or backward in a schedule
477
  //
478
  // A phasing domain can execute a jump from its current phase to any other.
479
  // A jump passes phasing control in the current domain from the current phase
480
  // to a target phase. There are two kinds of jump scope:
481
  //
482
  // - local jump to another phase within the current schedule, back- or forwards
483
  // - global jump of all domains together, either to a point in the master
484
  //   schedule outwith the current schedule, or by calling jump_all()
485
  //
486
  // A jump preserves the existing soft synchronization, so the domain that is
487
  // ahead of schedule relative to another synchronized domain, as a result of
488
  // a jump in either domain, will await the domain that is behind schedule.
489
  //
490
  // *Note*: A jump out of the local schedule causes other schedules that have
491
  // the jump node in their schedule to jump as well. In some cases, it is
492
  // desirable to jump to a local phase in the schedule but to have all
493
  // schedules that share that phase to jump as well. In that situation, the
494
  // jump_all static function should be used. This function causes all schedules
495
  // that share a phase to jump to that phase.
496
 
497
  // Function: jump
498
  //
499
  // Jump to a specified ~phase~. If the destination ~phase~ is within the current
500
  // phase schedule, a simple local jump takes place. If the jump-to ~phase~ is
501
  // outside of the current schedule then the jump affects other schedules which
502
  // share the phase.
503
  //
504
  extern function void jump(uvm_phase phase);
505
 
506
  // Function: set_jump_phase
507
  //
508
  // Specify a phase to transition to when phase is complete.
509
  // Note that this function is part of what jump() does; unlike jump()
510
  // it does not set the flag to terminate the phase prematurely.
511
  extern function void set_jump_phase(uvm_phase phase) ;
512
 
513
  // Function: end_prematurely
514
  //
515
  // Set a flag to cause the phase to end prematurely.
516
  // Note that this function is part of what jump() does; unlike jump()
517
  // it does not set a jump_phase to go to after the phase ends.
518
  extern function void end_prematurely() ;
519
 
520
  // Function- jump_all
521
  //
522
  // Make all schedules jump to a specified ~phase~, even if the jump target is local.
523
  // The jump happens to all phase schedules that contain the jump-to ~phase~,
524
  // i.e. a global jump.
525
  //
526
  extern static function void jump_all(uvm_phase phase);
527
 
528
 
529
  // Function: get_jump_target
530
  //
531
  // Return handle to the target phase of the current jump, or ~null~ if no jump
532
  // is in progress. Valid for use during the phase_ended() callback
533
  //
534
  extern function uvm_phase get_jump_target();
535
 
536
 
537
  int unsigned max_ready_to_end_iter = 20;
538
 
539
  //--------------------------
540
  // Internal - Implementation
541
  //--------------------------
542
 
543
  // Implementation - Construction
544
  //------------------------------
545
  protected uvm_phase_type m_phase_type;
546
  protected uvm_phase      m_parent;     // our 'schedule' node [or points 'up' one level]
547
  uvm_phase                m_imp;        // phase imp to call when we execute this node
548
 
549
  // Implementation - State
550
  //-----------------------
551
  local uvm_phase_state    m_state;
552
  local int                m_run_count; // num times this phase has executed
553
  local process            m_phase_proc;
554
  int                      m_num_procs_not_yet_returned;
555
  extern function uvm_phase m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null);
556
  extern function uvm_phase m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null);
557
  extern function uvm_phase m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null);
558
  extern function uvm_phase m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null);
559
  extern function void m_print_successors();
560
 
561
  // Implementation - Callbacks
562
  //---------------------------
563
  // Provide the required component traversal behavior. Called by execute()
564
  virtual function void traverse(uvm_component comp,
565
                                 uvm_phase phase,
566
                                 uvm_phase_state state);
567
  endfunction
568
  // Provide the required per-component execution flow. Called by traverse()
569
  virtual function void execute(uvm_component comp,
570
                                 uvm_phase phase);
571
  endfunction
572
 
573
  // Implementation - Schedule
574
  //--------------------------
575
  protected bit  m_predecessors[uvm_phase];
576
  protected bit  m_successors[uvm_phase];
577
  protected uvm_phase m_end_node;
578
  // Track the currently executing real task phases (used for debug)
579
  static protected bit m_executing_phases[uvm_phase];
580
  function uvm_phase get_begin_node(); if (m_imp != null) return this; return null; endfunction
581
  function uvm_phase get_end_node();   return m_end_node; endfunction
582
 
583
  // Implementation - Synchronization
584
  //---------------------------------
585
  local uvm_phase m_sync[$];  // schedule instance to which we are synced
586
  uvm_objection phase_done; // phase done objection
587
  local int unsigned m_ready_to_end_count;
588
 
589
  function int unsigned get_ready_to_end_count();
590
     return m_ready_to_end_count;
591
  endfunction
592
 
593
  extern local function void get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]);
594
  extern local task m_wait_for_pred();
595
 
596
  // Implementation - Jumping
597
  //-------------------------
598
  local bit                m_jump_bkwd;
599
  local bit                m_jump_fwd;
600
  local uvm_phase          m_jump_phase;
601
  local bit                m_premature_end;
602
  extern function void clear(uvm_phase_state state = UVM_PHASE_DORMANT);
603
  extern function void clear_successors(
604
                             uvm_phase_state state = UVM_PHASE_DORMANT,
605
                             uvm_phase end_state=null);
606
 
607
  // Implementation - Overall Control
608
  //---------------------------------
609
  local static mailbox #(uvm_phase) m_phase_hopper = new();
610
 
611
  extern static task m_run_phases();
612
  extern local task  execute_phase();
613
  extern local function void m_terminate_phase();
614
  extern local function void m_print_termination_state();
615
  extern local task wait_for_self_and_siblings_to_drop();
616
  extern function void kill();
617
  extern function void kill_successors();
618
 
619
  // TBD add more useful debug
620
  //---------------------------------
621
  protected static bit m_phase_trace;
622
  local static bit m_use_ovm_run_semantic;
623
 
624
 
625
  function string convert2string();
626
  //return $sformatf("PHASE %s = %p",get_name(),this);
627
  string s;
628
    s = $sformatf("phase: %s parent=%s  pred=%s  succ=%s",get_name(),
629
                     (m_parent==null) ? "null" : get_schedule_name(),
630
                     m_aa2string(m_predecessors),
631
                     m_aa2string(m_successors));
632
    return s;
633
  endfunction
634
 
635
  local function string m_aa2string(bit aa[uvm_phase]); // TBD tidy
636
    string s;
637
    int i;
638
    s = "'{ ";
639
    foreach (aa[ph]) begin
640
      uvm_phase n = ph;
641
      s = {s, (n == null) ? "null" : n.get_name(),
642
        (i == aa.num()-1) ? "" : ", "};
643
      i++;
644
    end
645
    s = {s, " }"};
646
    return s;
647
  endfunction
648
 
649
  function bit is_domain();
650
    return (m_phase_type == UVM_PHASE_DOMAIN);
651
  endfunction
652
 
653
  virtual function void m_get_transitive_children(ref uvm_phase phases[$]);
654
    foreach (m_successors[succ])
655
    begin
656
        phases.push_back(succ);
657
        succ.m_get_transitive_children(phases);
658
    end
659
  endfunction
660
endclass
661
 
662
 
663
//------------------------------------------------------------------------------
664
//
665
// Class: uvm_phase_state_change
666
//
667
//------------------------------------------------------------------------------
668
//
669
// Phase state transition descriptor.
670
// Used to describe the phase transition that caused a
671
//  callback to be invoked.
672
//
673
 
674
class uvm_phase_state_change extends uvm_object;
675
 
676
  `uvm_object_utils(uvm_phase_state_change)
677
 
678
  // Implementation -- do not use directly
679
  /* local */ uvm_phase       m_phase;
680
  /* local */ uvm_phase_state m_prev_state;
681
  /* local */ uvm_phase       m_jump_to;
682
 
683
  function new(string name = "uvm_phase_state_change");
684
    super.new(name);
685
  endfunction
686
 
687
 
688
  // Function: get_state()
689
  //
690
  // Returns the state the phase just transitioned to.
691
  // Functionally equivalent to .
692
  //
693
  virtual function uvm_phase_state get_state();
694
    return m_phase.get_state();
695
  endfunction
696
 
697
  // Function: get_prev_state()
698
  //
699
  // Returns the state the phase just transitioned from.
700
  //
701
  virtual function uvm_phase_state get_prev_state();
702
    return m_prev_state;
703
  endfunction
704
 
705
  // Function: jump_to()
706
  //
707
  // If the current state is ~UVM_PHASE_ENDED~ or ~UVM_PHASE_JUMPING~ because of
708
  // a phase jump, returns the phase that is the target of jump.
709
  // Returns ~null~ otherwise.
710
  //
711
  function uvm_phase jump_to();
712
    return m_jump_to;
713
  endfunction
714
 
715
endclass
716
 
717
 
718
//------------------------------------------------------------------------------
719
//
720
// Class: uvm_phase_cb
721
//
722
//------------------------------------------------------------------------------
723
//
724
// This class defines a callback method that is invoked by the phaser
725
// during the execution of a specific node in the phase graph or all phase nodes.
726
// User-defined callback extensions can be used to integrate data types that
727
// are not natively phase-aware with the UVM phasing.
728
//
729
 
730
class uvm_phase_cb extends uvm_callback;
731
 
732
  // Function: new
733
  // Constructor
734
  function new(string name="unnamed-uvm_phase_cb");
735
     super.new(name);
736
  endfunction : new
737
 
738
  // Function: phase_state_change
739
  //
740
  // Called whenever a ~phase~ changes state.
741
  // The ~change~ descriptor describes the transition that was just completed.
742
  // The callback method is invoked immediately after the phase state has changed,
743
  // but before the phase implementation is executed.
744
  //
745
  // An extension may interact with the phase,
746
  // such as raising the phase objection to prolong the phase,
747
  // in a manner that is consistent with the current phase state.
748
  //
749
  // By default, the callback method does nothing.
750
  // Unless otherwise specified, modifying the  phase transition descriptor has
751
  // no effect on the phasing schedule or execution.
752
  //
753
  virtual function void phase_state_change(uvm_phase phase,
754
                                           uvm_phase_state_change change);
755
  endfunction
756
endclass
757
 
758
//------------------------------------------------------------------------------
759
//
760
// Class: uvm_phase_cb_pool
761
//
762
//------------------------------------------------------------------------------
763
//
764
// Convenience type for the uvm_callbacks#(uvm_phase, uvm_phase_cb) class.
765
//
766
typedef uvm_callbacks#(uvm_phase, uvm_phase_cb) uvm_phase_cb_pool;
767
 
768
 
769
//------------------------------------------------------------------------------
770
//                               IMPLEMENTATION
771
//------------------------------------------------------------------------------
772
 
773
typedef class uvm_cmdline_processor;
774
 
775
`define UVM_PH_TRACE(ID,MSG,PH,VERB) \
776
   `uvm_info(ID, {$sformatf("Phase '%0s' (id=%0d) ", \
777
       PH.get_full_name(), PH.get_inst_id()),MSG}, VERB);
778
 
779
//-----------------------------
780
// Implementation - Construction
781
//-----------------------------
782
 
783
// new
784
 
785
function uvm_phase::new(string name="uvm_phase",
786
                        uvm_phase_type phase_type=UVM_PHASE_SCHEDULE,
787
                        uvm_phase parent=null);
788
  super.new(name);
789
  m_phase_type = phase_type;
790
 
791
  // The common domain is the only thing that initializes m_state.  All
792
  // other states are initialized by being 'added' to a schedule.
793
  if ((name == "common") &&
794
      (phase_type == UVM_PHASE_DOMAIN))
795
    m_state = UVM_PHASE_DORMANT;
796
 
797
  m_run_count = 0;
798
  m_parent = parent;
799
 
800
  begin
801
    uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst();
802
    string val;
803
    if (clp.get_arg_value("+UVM_PHASE_TRACE", val))
804
      m_phase_trace = 1;
805
    else
806
      m_phase_trace = 0;
807
    if (clp.get_arg_value("+UVM_USE_OVM_RUN_SEMANTIC", val))
808
      m_use_ovm_run_semantic = 1;
809
    else
810
      m_use_ovm_run_semantic = 0;
811
  end
812
 
813
 
814
  if (parent == null && (phase_type == UVM_PHASE_SCHEDULE ||
815
                         phase_type == UVM_PHASE_DOMAIN )) begin
816
    //m_parent = this;
817
    m_end_node = new({name,"_end"}, UVM_PHASE_TERMINAL, this);
818
    this.m_successors[m_end_node] = 1;
819
    m_end_node.m_predecessors[this] = 1;
820
  end
821
 
822
endfunction
823
 
824
 
825
// add
826
// ---
827
// TBD error checks if param nodes are actually in this schedule or not
828
 
829
function void uvm_phase::add(uvm_phase phase,
830
                             uvm_phase with_phase=null,
831
                             uvm_phase after_phase=null,
832
                             uvm_phase before_phase=null);
833
  uvm_phase new_node, begin_node, end_node, tmp_node;
834
  uvm_phase_state_change state_chg;
835
 
836
  if (phase == null)
837
      `uvm_fatal("PH/NULL", "add: phase argument is null")
838
 
839
  if (with_phase != null && with_phase.get_phase_type() == UVM_PHASE_IMP) begin
840
    string nm = with_phase.get_name();
841
    with_phase = find(with_phase);
842
    if (with_phase == null)
843
      `uvm_fatal("PH_BAD_ADD",
844
         {"cannot find with_phase '",nm,"' within node '",get_name(),"'"})
845
  end
846
 
847
  if (before_phase != null && before_phase.get_phase_type() == UVM_PHASE_IMP) begin
848
    string nm = before_phase.get_name();
849
    before_phase = find(before_phase);
850
    if (before_phase == null)
851
      `uvm_fatal("PH_BAD_ADD",
852
         {"cannot find before_phase '",nm,"' within node '",get_name(),"'"})
853
  end
854
 
855
  if (after_phase != null && after_phase.get_phase_type() == UVM_PHASE_IMP) begin
856
    string nm = after_phase.get_name();
857
    after_phase = find(after_phase);
858
    if (after_phase == null)
859
      `uvm_fatal("PH_BAD_ADD",
860
         {"cannot find after_phase '",nm,"' within node '",get_name(),"'"})
861
  end
862
 
863
  if (with_phase != null && (after_phase != null || before_phase != null))
864
    `uvm_fatal("PH_BAD_ADD",
865
       "cannot specify both 'with' and 'before/after' phase relationships")
866
 
867
  if (before_phase == this || after_phase == m_end_node || with_phase == m_end_node)
868
    `uvm_fatal("PH_BAD_ADD",
869
       "cannot add before begin node, after end node, or with end nodes")
870
 
871
  // If we are inserting a new "leaf node"
872
  if (phase.get_phase_type() == UVM_PHASE_IMP) begin
873
    uvm_task_phase tp;
874
    new_node = new(phase.get_name(),UVM_PHASE_NODE,this);
875
    new_node.m_imp = phase;
876
    begin_node = new_node;
877
    end_node = new_node;
878
 
879
    // The phase_done objection is only required
880
    // for task-based nodes
881
    if ($cast(tp, phase)) begin
882
       if (new_node.get_name() == "run") begin
883
         new_node.phase_done = uvm_test_done_objection::get();
884
       end
885
       else begin
886
         new_node.phase_done = uvm_objection::type_id::create({phase.get_name(), "_objection"});
887
       end
888
    end
889
 
890
  end
891
  // We are inserting an existing schedule
892
  else begin
893
    begin_node = phase;
894
    end_node   = phase.m_end_node;
895
    phase.m_parent = this;
896
  end
897
 
898
  // If 'with_phase' is us, then insert node in parallel
899
  /*
900
  if (with_phase == this) begin
901
    after_phase = this;
902
    before_phase = m_end_node;
903
  end
904
  */
905
 
906
  // If no before/after/with specified, insert at end of this schedule
907
  if (with_phase == null && after_phase == null && before_phase == null) begin
908
    before_phase = m_end_node;
909
  end
910
 
911
 
912
  if (m_phase_trace) begin
913
    uvm_phase_type typ = phase.get_phase_type();
914
    `uvm_info("PH/TRC/ADD_PH",
915
      {get_name()," (",m_phase_type.name(),") ADD_PHASE: phase=",phase.get_full_name()," (",
916
      typ.name(),", inst_id=",$sformatf("%0d",phase.get_inst_id()),")",
917
      " with_phase=",   (with_phase == null)   ? "null" : with_phase.get_name(),
918
      " after_phase=",  (after_phase == null)  ? "null" : after_phase.get_name(),
919
      " before_phase=", (before_phase == null) ? "null" : before_phase.get_name(),
920
      " new_node=",     (new_node == null)     ? "null" : {new_node.get_name(),
921
                                                           " inst_id=",
922
                                                           $sformatf("%0d",new_node.get_inst_id())},
923
      " begin_node=",   (begin_node == null)   ? "null" : begin_node.get_name(),
924
      " end_node=",     (end_node == null)     ? "null" : end_node.get_name()},UVM_DEBUG)
925
  end
926
 
927
 
928
  // INSERT IN PARALLEL WITH 'WITH' PHASE
929
  if (with_phase != null) begin
930
    begin_node.m_predecessors = with_phase.m_predecessors;
931
    end_node.m_successors = with_phase.m_successors;
932
    foreach (with_phase.m_predecessors[pred])
933
      pred.m_successors[begin_node] = 1;
934
    foreach (with_phase.m_successors[succ])
935
      succ.m_predecessors[end_node] = 1;
936
  end
937
 
938
 
939
  // INSERT BEFORE PHASE
940
  else if (before_phase != null && after_phase == null) begin
941
    begin_node.m_predecessors = before_phase.m_predecessors;
942
    end_node.m_successors[before_phase] = 1;
943
    foreach (before_phase.m_predecessors[pred]) begin
944
      pred.m_successors.delete(before_phase);
945
      pred.m_successors[begin_node] = 1;
946
    end
947
    before_phase.m_predecessors.delete();
948
    before_phase.m_predecessors[end_node] = 1;
949
  end
950
 
951
 
952
  // INSERT AFTER PHASE
953
  else if (before_phase == null && after_phase != null) begin
954
    end_node.m_successors = after_phase.m_successors;
955
    begin_node.m_predecessors[after_phase] = 1;
956
    foreach (after_phase.m_successors[succ]) begin
957
      succ.m_predecessors.delete(after_phase);
958
      succ.m_predecessors[end_node] = 1;
959
    end
960
    after_phase.m_successors.delete();
961
    after_phase.m_successors[begin_node] = 1;
962
  end
963
 
964
 
965
  // IN BETWEEN 'BEFORE' and 'AFTER' PHASES
966
  else if (before_phase != null && after_phase != null) begin
967
    if (!after_phase.is_before(before_phase)) begin
968
      `uvm_fatal("PH_ADD_PHASE",{"Phase '",before_phase.get_name(),
969
                 "' is not before phase '",after_phase.get_name(),"'"})
970
    end
971
    // before and after? add 1 pred and 1 succ
972
    begin_node.m_predecessors[after_phase] = 1;
973
    end_node.m_successors[before_phase] = 1;
974
    after_phase.m_successors[begin_node] = 1;
975
    before_phase.m_predecessors[end_node] = 1;
976
    if (after_phase.m_successors.exists(before_phase)) begin
977
      after_phase.m_successors.delete(before_phase);
978
      before_phase.m_successors.delete(after_phase);
979
    end
980
  end // if (before_phase != null && after_phase != null)
981
 
982
  // Transition nodes to DORMANT state
983
  if (new_node == null)
984
    tmp_node = phase;
985
  else
986
    tmp_node = new_node;
987
 
988
  state_chg = uvm_phase_state_change::type_id::create(tmp_node.get_name());
989
  state_chg.m_phase = tmp_node;
990
  state_chg.m_jump_to = null;
991
  state_chg.m_prev_state = tmp_node.m_state;
992
  tmp_node.m_state = UVM_PHASE_DORMANT;
993
  `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(tmp_node, state_chg))
994
endfunction
995
 
996
 
997
// get_parent
998
// ----------
999
 
1000
function uvm_phase uvm_phase::get_parent();
1001
  return m_parent;
1002
endfunction
1003
 
1004
 
1005
// get_imp
1006
// -------
1007
 
1008
function uvm_phase uvm_phase::get_imp();
1009
  return m_imp;
1010
endfunction
1011
 
1012
 
1013
// get_schedule
1014
// ------------
1015
 
1016
function uvm_phase uvm_phase::get_schedule(bit hier=0);
1017
  uvm_phase sched;
1018
  sched = this;
1019
  if (hier)
1020
    while (sched.m_parent != null && (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE))
1021
      sched = sched.m_parent;
1022
  if (sched.m_phase_type == UVM_PHASE_SCHEDULE)
1023
    return sched;
1024
  if (sched.m_phase_type == UVM_PHASE_NODE)
1025
    if (m_parent != null && m_parent.m_phase_type != UVM_PHASE_DOMAIN)
1026
      return m_parent;
1027
  return null;
1028
endfunction
1029
 
1030
 
1031
// get_domain
1032
// ----------
1033
 
1034
function uvm_domain uvm_phase::get_domain();
1035
  uvm_phase phase;
1036
  phase = this;
1037
  while (phase != null && phase.m_phase_type != UVM_PHASE_DOMAIN)
1038
    phase = phase.m_parent;
1039
  if (phase == null) // no parent domain
1040
    return null;
1041
  if(!$cast(get_domain,phase))
1042
      `uvm_fatal("PH/INTERNAL", "get_domain: m_phase_type is DOMAIN but $cast to uvm_domain fails")
1043
endfunction
1044
 
1045
 
1046
// get_domain_name
1047
// ---------------
1048
 
1049
function string uvm_phase::get_domain_name();
1050
  uvm_domain domain;
1051
  domain = get_domain();
1052
  if (domain == null)
1053
    return "unknown";
1054
  return domain.get_name();
1055
endfunction
1056
 
1057
 
1058
// get_schedule_name
1059
// -----------------
1060
 
1061
function string uvm_phase::get_schedule_name(bit hier=0);
1062
  uvm_phase sched;
1063
  string s;
1064
  sched = get_schedule(hier);
1065
  if (sched == null)
1066
    return "";
1067
  s = sched.get_name();
1068
  while (sched.m_parent != null && sched.m_parent != sched &&
1069
          (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) begin
1070
    sched = sched.m_parent;
1071
    s = {sched.get_name(),(s.len()>0?".":""),s};
1072
  end
1073
  return s;
1074
endfunction
1075
 
1076
 
1077
// get_full_name
1078
// -------------
1079
 
1080
function string uvm_phase::get_full_name();
1081
  string dom, sch;
1082
  if (m_phase_type == UVM_PHASE_IMP)
1083
    return get_name();
1084
  get_full_name = get_domain_name();
1085
  sch = get_schedule_name();
1086
  if (sch != "")
1087
    get_full_name = {get_full_name, ".", sch};
1088
  if (m_phase_type != UVM_PHASE_DOMAIN && m_phase_type != UVM_PHASE_SCHEDULE)
1089
    get_full_name = {get_full_name, ".", get_name()};
1090
endfunction
1091
 
1092
 
1093
// get_phase_type
1094
// --------------
1095
 
1096
function uvm_phase_type uvm_phase::get_phase_type();
1097
  return m_phase_type;
1098
endfunction
1099
 
1100
 
1101
//-----------------------
1102
// Implementation - State
1103
//-----------------------
1104
 
1105
// get_state
1106
// ---------
1107
 
1108
function uvm_phase_state uvm_phase::get_state();
1109
  return m_state;
1110
endfunction
1111
 
1112
// get_run_count
1113
// -------------
1114
 
1115
function int uvm_phase::get_run_count();
1116
  return m_run_count;
1117
endfunction
1118
 
1119
 
1120
// m_print_successors
1121
// ------------------
1122
 
1123
function void uvm_phase::m_print_successors();
1124
  uvm_phase found;
1125
  static string spaces = "                                                 ";
1126
  static int level;
1127
  if (m_phase_type == UVM_PHASE_DOMAIN)
1128
    level = 0;
1129
  `uvm_info("UVM/PHASE/SUCC",$sformatf("%s%s (%s) id=%0d",spaces.substr(0,level*2),get_name(), m_phase_type.name(),get_inst_id()),UVM_NONE)
1130
  level++;
1131
  foreach (m_successors[succ]) begin
1132
    succ.m_print_successors();
1133
  end
1134
  level--;
1135
endfunction
1136
 
1137
 
1138
// m_find_predecessor
1139
// ------------------
1140
 
1141
function uvm_phase uvm_phase::m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null);
1142
  uvm_phase found;
1143
  //$display("  FIND PRED node '",phase.get_name(),"' (id=",$sformatf("%0d",phase.get_inst_id()),") - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")");
1144
  if (phase == null) begin
1145
    return null ;
1146
  end
1147
  if (phase == m_imp || phase == this)
1148
    return this;
1149
  foreach (m_predecessors[pred]) begin
1150
    uvm_phase orig;
1151
    orig = (orig_phase==null) ? this : orig_phase;
1152
    if (!stay_in_scope ||
1153
        (pred.get_schedule() == orig.get_schedule()) ||
1154
        (pred.get_domain() == orig.get_domain())) begin
1155
      found = pred.m_find_predecessor(phase,stay_in_scope,orig);
1156
      if (found != null)
1157
        return found;
1158
    end
1159
  end
1160
  return null;
1161
endfunction
1162
 
1163
 
1164
// m_find_predecessor_by_name
1165
// --------------------------
1166
 
1167
function uvm_phase uvm_phase::m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null);
1168
  uvm_phase found;
1169
  //$display("  FIND PRED node '",name,"' - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")");
1170
  if (get_name() == name)
1171
    return this;
1172
  foreach (m_predecessors[pred]) begin
1173
    uvm_phase orig;
1174
    orig = (orig_phase==null) ? this : orig_phase;
1175
    if (!stay_in_scope ||
1176
        (pred.get_schedule() == orig.get_schedule()) ||
1177
        (pred.get_domain() == orig.get_domain())) begin
1178
      found = pred.m_find_predecessor_by_name(name,stay_in_scope,orig);
1179
      if (found != null)
1180
        return found;
1181
    end
1182
  end
1183
  return null;
1184
endfunction
1185
 
1186
 
1187
// m_find_successor
1188
// ----------------
1189
 
1190
function uvm_phase uvm_phase::m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null);
1191
  uvm_phase found;
1192
  //$display("  FIND SUCC node '",phase.get_name(),"' (id=",$sformatf("%0d",phase.get_inst_id()),") - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")");
1193
  if (phase == null) begin
1194
    return null ;
1195
  end
1196
  if (phase == m_imp || phase == this) begin
1197
    return this;
1198
    end
1199
  foreach (m_successors[succ]) begin
1200
    uvm_phase orig;
1201
    orig = (orig_phase==null) ? this : orig_phase;
1202
    if (!stay_in_scope ||
1203
        (succ.get_schedule() == orig.get_schedule()) ||
1204
        (succ.get_domain() == orig.get_domain())) begin
1205
      found = succ.m_find_successor(phase,stay_in_scope,orig);
1206
      if (found != null) begin
1207
        return found;
1208
        end
1209
    end
1210
  end
1211
  return null;
1212
endfunction
1213
 
1214
 
1215
// m_find_successor_by_name
1216
// ------------------------
1217
 
1218
function uvm_phase uvm_phase::m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null);
1219
  uvm_phase found;
1220
  //$display("  FIND SUCC node '",name,"' - checking against ",get_name()," (",m_phase_type.name()," id=",$sformatf("%0d",get_inst_id()),(m_imp==null)?"":{"/",$sformatf("%0d",m_imp.get_inst_id())},")");
1221
  if (get_name() == name)
1222
    return this;
1223
  foreach (m_successors[succ]) begin
1224
    uvm_phase orig;
1225
    orig = (orig_phase==null) ? this : orig_phase;
1226
    if (!stay_in_scope ||
1227
        (succ.get_schedule() == orig.get_schedule()) ||
1228
        (succ.get_domain() == orig.get_domain())) begin
1229
      found = succ.m_find_successor_by_name(name,stay_in_scope,orig);
1230
      if (found != null)
1231
        return found;
1232
    end
1233
  end
1234
  return null;
1235
endfunction
1236
 
1237
 
1238
// find
1239
// ----
1240
 
1241
function uvm_phase uvm_phase::find(uvm_phase phase, bit stay_in_scope=1);
1242
  // TBD full search
1243
  //$display({"\nFIND node '",phase.get_name(),"' within ",get_name()," (scope ",m_phase_type.name(),")", (stay_in_scope) ? " staying within scope" : ""});
1244
  if (phase == m_imp || phase == this)
1245
    return phase;
1246
  find = m_find_predecessor(phase,stay_in_scope,this);
1247
  if (find == null)
1248
    find = m_find_successor(phase,stay_in_scope,this);
1249
endfunction
1250
 
1251
 
1252
// find_by_name
1253
// ------------
1254
 
1255
function uvm_phase uvm_phase::find_by_name(string name, bit stay_in_scope=1);
1256
  // TBD full search
1257
  //$display({"\nFIND node named '",name,"' within ",get_name()," (scope ",m_phase_type.name(),")", (stay_in_scope) ? " staying within scope" : ""});
1258
  if (get_name() == name)
1259
    return this;
1260
  find_by_name = m_find_predecessor_by_name(name,stay_in_scope,this);
1261
  if (find_by_name == null)
1262
    find_by_name = m_find_successor_by_name(name,stay_in_scope,this);
1263
endfunction
1264
 
1265
 
1266
// is
1267
// --
1268
 
1269
function bit uvm_phase::is(uvm_phase phase);
1270
  return (m_imp == phase || this == phase);
1271
endfunction
1272
 
1273
 
1274
// is_before
1275
// ---------
1276
 
1277
function bit uvm_phase::is_before(uvm_phase phase);
1278
  //$display("this=%s is before phase=%s?",get_name(),phase.get_name());
1279
  // TODO: add support for 'stay_in_scope=1' functionality
1280
  return (!is(phase) && m_find_successor(phase,0,this) != null);
1281
endfunction
1282
 
1283
 
1284
// is_after
1285
// --------
1286
 
1287
function bit uvm_phase::is_after(uvm_phase phase);
1288
  //$display("this=%s is after phase=%s?",get_name(),phase.get_name());
1289
  // TODO: add support for 'stay_in_scope=1' functionality
1290
  return (!is(phase) && m_find_predecessor(phase,0,this) != null);
1291
endfunction
1292
 
1293
 
1294
// execute_phase
1295
// -------------
1296
 
1297
task uvm_phase::execute_phase();
1298
 
1299
  uvm_task_phase task_phase;
1300
  uvm_root top;
1301
  uvm_phase_state_change state_chg;
1302
  uvm_coreservice_t cs;
1303
 
1304
  cs = uvm_coreservice_t::get();
1305
  top = cs.get_root();
1306
 
1307
  // If we got here by jumping forward, we must wait for
1308
  // all its predecessor nodes to be marked DONE.
1309
  // (the next conditional speeds this up)
1310
  // Also, this helps us fast-forward through terminal (end) nodes
1311
  foreach (m_predecessors[pred])
1312
    wait (pred.m_state == UVM_PHASE_DONE);
1313
 
1314
 
1315
  // If DONE (by, say, a forward jump), return immed
1316
  if (m_state == UVM_PHASE_DONE)
1317
    return;
1318
 
1319
  state_chg = uvm_phase_state_change::type_id::create(get_name());
1320
  state_chg.m_phase      = this;
1321
  state_chg.m_jump_to    = null;
1322
 
1323
  //---------
1324
  // SYNCING:
1325
  //---------
1326
  // Wait for phases with which we have a sync()
1327
  // relationship to be ready. Sync can be 2-way -
1328
  // this additional state avoids deadlock.
1329
  state_chg.m_prev_state = m_state;
1330
  m_state = UVM_PHASE_SYNCING;
1331
  `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1332
  #0;
1333
 
1334
  if (m_sync.size()) begin
1335
 
1336
    foreach (m_sync[i]) begin
1337
      wait (m_sync[i].m_state >= UVM_PHASE_SYNCING);
1338
    end
1339
  end
1340
 
1341
  m_run_count++;
1342
 
1343
 
1344
  if (m_phase_trace) begin
1345
    `UVM_PH_TRACE("PH/TRC/STRT","Starting phase",this,UVM_LOW)
1346
  end
1347
 
1348
 
1349
  // If we're a schedule or domain, then "fake" execution
1350
  if (m_phase_type != UVM_PHASE_NODE) begin
1351
    state_chg.m_prev_state = m_state;
1352
    m_state = UVM_PHASE_STARTED;
1353
    `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1354
 
1355
    #0;
1356
 
1357
    state_chg.m_prev_state = m_state;
1358
    m_state = UVM_PHASE_EXECUTING;
1359
    `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1360
 
1361
    #0;
1362
  end
1363
 
1364
 
1365
  else begin // PHASE NODE
1366
 
1367
    //---------
1368
    // STARTED:
1369
    //---------
1370
    state_chg.m_prev_state = m_state;
1371
    m_state = UVM_PHASE_STARTED;
1372
    `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1373
 
1374
    m_imp.traverse(top,this,UVM_PHASE_STARTED);
1375
    m_ready_to_end_count = 0 ; // reset the ready_to_end count when phase starts
1376
    #0; // LET ANY WAITERS WAKE UP
1377
 
1378
 
1379
    //if (m_imp.get_phase_type() != UVM_PHASE_TASK) begin
1380
    if (!$cast(task_phase,m_imp)) begin
1381
 
1382
      //-----------
1383
      // EXECUTING: (function phases)
1384
      //-----------
1385
      state_chg.m_prev_state = m_state;
1386
      m_state = UVM_PHASE_EXECUTING;
1387
      `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1388
 
1389
      #0; // LET ANY WAITERS WAKE UP
1390
      m_imp.traverse(top,this,UVM_PHASE_EXECUTING);
1391
 
1392
    end
1393
    else begin
1394
        m_executing_phases[this] = 1;
1395
 
1396
        state_chg.m_prev_state = m_state;
1397
        m_state = UVM_PHASE_EXECUTING;
1398
        `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1399
 
1400
        fork : master_phase_process
1401
          begin
1402
 
1403
            m_phase_proc = process::self();
1404
 
1405
            //-----------
1406
            // EXECUTING: (task phases)
1407
            //-----------
1408
            task_phase.traverse(top,this,UVM_PHASE_EXECUTING);
1409
 
1410
            wait(0); // stay alive for later kill
1411
 
1412
          end
1413
        join_none
1414
 
1415
        uvm_wait_for_nba_region(); //Give sequences, etc. a chance to object
1416
 
1417
        // Now wait for one of three criterion for end-of-phase.
1418
        fork
1419
          begin // guard
1420
 
1421
           fork
1422
             // JUMP
1423
             begin
1424
                wait (m_premature_end);
1425
                `UVM_PH_TRACE("PH/TRC/EXE/JUMP","PHASE EXIT ON JUMP REQUEST",this,UVM_DEBUG)
1426
             end
1427
 
1428
             // WAIT_FOR_ALL_DROPPED
1429
             begin
1430
               bit do_ready_to_end  ; // bit used for ready_to_end iterations
1431
               // OVM semantic: don't end until objection raised or stop request
1432
               if (phase_done.get_objection_total(top) ||
1433
                   m_use_ovm_run_semantic && m_imp.get_name() == "run") begin
1434
                 if (!phase_done.m_top_all_dropped)
1435
                   phase_done.wait_for(UVM_ALL_DROPPED, top);
1436
                 `UVM_PH_TRACE("PH/TRC/EXE/ALLDROP","PHASE EXIT ALL_DROPPED",this,UVM_DEBUG)
1437
               end
1438
               else begin
1439
                  if (m_phase_trace) `UVM_PH_TRACE("PH/TRC/SKIP","No objections raised, skipping phase",this,UVM_LOW)
1440
               end
1441
 
1442
               wait_for_self_and_siblings_to_drop() ;
1443
               do_ready_to_end = 1;
1444
 
1445
               //--------------
1446
               // READY_TO_END:
1447
               //--------------
1448
 
1449
               while (do_ready_to_end) begin
1450
                 uvm_wait_for_nba_region(); // Let all siblings see no objections before traverse might raise another
1451
                 `UVM_PH_TRACE("PH_READY_TO_END","PHASE READY TO END",this,UVM_DEBUG)
1452
                 m_ready_to_end_count++;
1453
                 if (m_phase_trace)
1454
                   `UVM_PH_TRACE("PH_READY_TO_END_CB","CALLING READY_TO_END CB",this,UVM_HIGH)
1455
                 state_chg.m_prev_state = m_state;
1456
                 m_state = UVM_PHASE_READY_TO_END;
1457
                 `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1458
                 if (m_imp != null)
1459
                   m_imp.traverse(top,this,UVM_PHASE_READY_TO_END);
1460
 
1461
                 uvm_wait_for_nba_region(); // Give traverse targets a chance to object
1462
 
1463
                 wait_for_self_and_siblings_to_drop();
1464
                 do_ready_to_end = (m_state == UVM_PHASE_EXECUTING) && (m_ready_to_end_count < max_ready_to_end_iter) ; //when we don't wait in task above, we drop out of while loop
1465
               end
1466
             end
1467
 
1468
             // TIMEOUT
1469
             begin
1470
               if (this.get_name() == "run") begin
1471
                  if (top.phase_timeout == 0)
1472
                    wait(top.phase_timeout != 0);
1473
                  if (m_phase_trace)
1474
                    `UVM_PH_TRACE("PH/TRC/TO_WAIT", $sformatf("STARTING PHASE TIMEOUT WATCHDOG (timeout == %t)", top.phase_timeout), this, UVM_HIGH)
1475
                  `uvm_delay(top.phase_timeout)
1476
                  if ($time == `UVM_DEFAULT_TIMEOUT) begin
1477
                     if (m_phase_trace)
1478
                       `UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED", this, UVM_LOW)
1479
                     foreach (m_executing_phases[p]) begin
1480
                        if ((p.phase_done != null) && (p.phase_done.get_objection_total() > 0)) begin
1481
                           if (m_phase_trace)
1482
                             `UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN",
1483
                                           $sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p.phase_done.convert2string()),
1484
                                           this,
1485
                                           UVM_LOW)
1486
                        end
1487
                     end
1488
 
1489
                     `uvm_fatal("PH_TIMEOUT",
1490
                                $sformatf("Default timeout of %0t hit, indicating a probable testbench issue",
1491
                                          `UVM_DEFAULT_TIMEOUT))
1492
                  end
1493
                  else begin
1494
                     if (m_phase_trace)
1495
                       `UVM_PH_TRACE("PH/TRC/TIMEOUT", "PHASE TIMEOUT WATCHDOG EXPIRED", this, UVM_LOW)
1496
                     foreach (m_executing_phases[p]) begin
1497
                        if ((p.phase_done != null) && (p.phase_done.get_objection_total() > 0)) begin
1498
                           if (m_phase_trace)
1499
                             `UVM_PH_TRACE("PH/TRC/TIMEOUT/OBJCTN",
1500
                                           $sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p.phase_done.convert2string()),
1501
                                           this,
1502
                                           UVM_LOW)
1503
                        end
1504
                     end
1505
 
1506
                     `uvm_fatal("PH_TIMEOUT",
1507
                                $sformatf("Explicit timeout of %0t hit, indicating a probable testbench issue",
1508
                                          top.phase_timeout))
1509
                  end
1510
                  if (m_phase_trace)
1511
                    `UVM_PH_TRACE("PH/TRC/EXE/3","PHASE EXIT TIMEOUT",this,UVM_DEBUG)
1512
               end // if (this.get_name() == "run")
1513
               else begin
1514
                  wait (0); // never unblock for non-run phase
1515
               end
1516
             end // if (m_phase_trace)
1517
 
1518
 
1519
           join_any
1520
           disable fork;
1521
 
1522
          end
1523
 
1524
        join // guard
1525
 
1526
    end
1527
 
1528
  end
1529
 
1530
  m_executing_phases.delete(this);
1531
 
1532
  //---------
1533
  // JUMPING:
1534
  //---------
1535
 
1536
  // If jump_to() was called then we need to kill all the successor
1537
  // phases which may still be running and then initiate the new
1538
  // phase.  The return is necessary so we don't start new successor
1539
  // phases.  If we are doing a forward jump then we want to set the
1540
  // state of this phase's successors to UVM_PHASE_DONE.  This
1541
  // will let us pretend that all the phases between here and there
1542
  // were executed and completed.  Thus any dependencies will be
1543
  // satisfied preventing deadlocks.
1544
  // GSA TBD insert new jump support
1545
 
1546
  if (m_phase_type == UVM_PHASE_NODE) begin
1547
 
1548
    if(m_premature_end) begin
1549
      if(m_jump_phase != null) begin
1550
        state_chg.m_jump_to = m_jump_phase;
1551
 
1552
        `uvm_info("PH_JUMP",
1553
              $sformatf("phase %s (schedule %s, domain %s) is jumping to phase %s",
1554
               get_name(), get_schedule_name(), get_domain_name(), m_jump_phase.get_name()),
1555
              UVM_MEDIUM);
1556
      end
1557
      else begin
1558
        `uvm_info("PH_JUMP",
1559
              $sformatf("phase %s (schedule %s, domain %s) is ending prematurely",
1560
               get_name(), get_schedule_name(), get_domain_name()),
1561
              UVM_MEDIUM);
1562
      end
1563
 
1564
 
1565
      #0; // LET ANY WAITERS ON READY_TO_END TO WAKE UP
1566
      if (m_phase_trace)
1567
        `UVM_PH_TRACE("PH_END","ENDING PHASE PREMATURELY",this,UVM_HIGH)
1568
    end
1569
    else begin
1570
      // WAIT FOR PREDECESSORS:  // WAIT FOR PREDECESSORS:
1571
      // function phases only
1572
      if (task_phase == null)
1573
        m_wait_for_pred();
1574
    end
1575
 
1576
    //-------
1577
    // ENDED:
1578
    //-------
1579
    // execute 'phase_ended' callbacks
1580
    if (m_phase_trace)
1581
      `UVM_PH_TRACE("PH_END","ENDING PHASE",this,UVM_HIGH)
1582
    state_chg.m_prev_state = m_state;
1583
    m_state = UVM_PHASE_ENDED;
1584
    `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1585
    if (m_imp != null)
1586
      m_imp.traverse(top,this,UVM_PHASE_ENDED);
1587
    #0; // LET ANY WAITERS WAKE UP
1588
 
1589
 
1590
    //---------
1591
    // CLEANUP:
1592
    //---------
1593
    // kill this phase's threads
1594
    state_chg.m_prev_state = m_state;
1595
    if(m_premature_end) m_state = UVM_PHASE_JUMPING;
1596
    else m_state = UVM_PHASE_CLEANUP ;
1597
    `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1598
    if (m_phase_proc != null) begin
1599
      m_phase_proc.kill();
1600
      m_phase_proc = null;
1601
    end
1602
    #0; // LET ANY WAITERS WAKE UP
1603
    if (phase_done != null)
1604
      phase_done.clear();
1605
  end
1606
 
1607
  //------
1608
  // DONE:
1609
  //------
1610
  m_premature_end = 0 ;
1611
  if(m_jump_fwd || m_jump_bkwd) begin
1612
    if(m_jump_fwd) begin
1613
      clear_successors(UVM_PHASE_DONE,m_jump_phase);
1614
    end
1615
    m_jump_phase.clear_successors();
1616
  end
1617
  else begin
1618
 
1619
    if (m_phase_trace)
1620
      `UVM_PH_TRACE("PH/TRC/DONE","Completed phase",this,UVM_LOW)
1621
    state_chg.m_prev_state = m_state;
1622
    m_state = UVM_PHASE_DONE;
1623
    `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(this, state_chg))
1624
    m_phase_proc = null;
1625
    #0; // LET ANY WAITERS WAKE UP
1626
  end
1627
  #0; // LET ANY WAITERS WAKE UP
1628
  if (phase_done != null)
1629
    phase_done.clear();
1630
 
1631
//-----------
1632
// SCHEDULED:
1633
//-----------
1634
  if(m_jump_fwd || m_jump_bkwd) begin
1635
    void'(m_phase_hopper.try_put(m_jump_phase));
1636
    m_jump_phase = null;
1637
    m_jump_fwd = 0;
1638
    m_jump_bkwd = 0;
1639
  end
1640
  // If more successors, schedule them to run now
1641
  else if (m_successors.size() == 0) begin
1642
    top.m_phase_all_done=1;
1643
  end
1644
  else begin
1645
    // execute all the successors
1646
    foreach (m_successors[succ]) begin
1647
      if(succ.m_state < UVM_PHASE_SCHEDULED) begin
1648
        state_chg.m_prev_state = succ.m_state;
1649
        state_chg.m_phase = succ;
1650
        succ.m_state = UVM_PHASE_SCHEDULED;
1651
        `uvm_do_callbacks(uvm_phase, uvm_phase_cb, phase_state_change(succ, state_chg))
1652
        #0; // LET ANY WAITERS WAKE UP
1653
        void'(m_phase_hopper.try_put(succ));
1654
        if (m_phase_trace)
1655
          `UVM_PH_TRACE("PH/TRC/SCHEDULED",{"Scheduled from phase ",get_full_name()},succ,UVM_LOW)
1656
      end
1657
    end
1658
  end
1659
 
1660
endtask
1661
 
1662
function void uvm_phase::get_adjacent_predecessor_nodes(ref uvm_phase pred[]);
1663
   bit done;
1664
   bit predecessors[uvm_phase];
1665
   int idx;
1666
 
1667
   // Get all predecessors (including TERMINALS, SCHEDULES, etc.)
1668
   foreach (m_predecessors[p])
1669
     predecessors[p] = 1;
1670
 
1671
   // Replace any terminal / schedule nodes with their predecessors,
1672
   // recursively.
1673
   do begin
1674
      done = 1;
1675
      foreach (predecessors[p]) begin
1676
         if (p.get_phase_type() != UVM_PHASE_NODE) begin
1677
            predecessors.delete(p);
1678
            foreach (p.m_predecessors[next_p])
1679
              predecessors[next_p] = 1;
1680
            done = 0;
1681
         end
1682
      end
1683
   end while (!done);
1684
 
1685
   pred = new [predecessors.size()];
1686
   foreach (predecessors[p]) begin
1687
      pred[idx++] = p;
1688
   end
1689
endfunction : get_adjacent_predecessor_nodes
1690
 
1691
function void uvm_phase::get_adjacent_successor_nodes(ref uvm_phase succ[]);
1692
   bit done;
1693
   bit successors[uvm_phase];
1694
   int idx;
1695
 
1696
   // Get all successors (including TERMINALS, SCHEDULES, etc.)
1697
   foreach (m_successors[s])
1698
     successors[s] = 1;
1699
 
1700
   // Replace any terminal / schedule nodes with their successors,
1701
   // recursively.
1702
   do begin
1703
      done = 1;
1704
      foreach (successors[s]) begin
1705
         if (s.get_phase_type() != UVM_PHASE_NODE) begin
1706
            successors.delete(s);
1707
            foreach (s.m_successors[next_s])
1708
              successors[next_s] = 1;
1709
            done = 0;
1710
         end
1711
      end
1712
   end while (!done);
1713
 
1714
   succ = new [successors.size()];
1715
   foreach (successors[s]) begin
1716
      succ[idx++] = s;
1717
   end
1718
endfunction : get_adjacent_successor_nodes
1719
 
1720
// Internal implementation, more efficient than calling get_predessor_nodes on all
1721
// of the successors returned by get_adjacent_successor_nodes
1722
function void uvm_phase::get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]);
1723
    bit done;
1724
    uvm_phase successors[];
1725
 
1726
    get_adjacent_successor_nodes(successors);
1727
 
1728
    // get all predecessors to these successors
1729
    foreach (successors[s])
1730
      foreach (successors[s].m_predecessors[pred])
1731
        pred_of_succ[pred] = 1;
1732
 
1733
    // replace any terminal nodes with their predecessors, recursively.
1734
    // we are only interested in "real" phase nodes
1735
    do begin
1736
      done=1;
1737
      foreach (pred_of_succ[pred]) begin
1738
        if (pred.get_phase_type() != UVM_PHASE_NODE) begin
1739
          pred_of_succ.delete(pred);
1740
          foreach (pred.m_predecessors[next_pred])
1741
            pred_of_succ[next_pred] = 1;
1742
          done =0;
1743
        end
1744
      end
1745
    end while (!done);
1746
 
1747
 
1748
    // remove ourselves from the list
1749
    pred_of_succ.delete(this);
1750
endfunction
1751
 
1752
 
1753
// m_wait_for_pred
1754
// ---------------
1755
 
1756
task uvm_phase::m_wait_for_pred();
1757
 
1758
    bit pred_of_succ[uvm_phase];
1759
    get_predecessors_for_successors(pred_of_succ);
1760
 
1761
    // wait for predecessors to successors (real phase nodes, not terminals)
1762
    // mostly debug msgs
1763
    foreach (pred_of_succ[sibling]) begin
1764
 
1765
      if (m_phase_trace) begin
1766
        string s;
1767
        s = $sformatf("Waiting for phase '%s' (%0d) to be READY_TO_END. Current state is %s",
1768
            sibling.get_name(),sibling.get_inst_id(),sibling.m_state.name());
1769
        `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC",s,this,UVM_HIGH)
1770
      end
1771
 
1772
      sibling.wait_for_state(UVM_PHASE_READY_TO_END, UVM_GTE);
1773
 
1774
      if (m_phase_trace) begin
1775
        string s;
1776
        s = $sformatf("Phase '%s' (%0d) is now READY_TO_END. Releasing phase",
1777
            sibling.get_name(),sibling.get_inst_id());
1778
        `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC",s,this,UVM_HIGH)
1779
      end
1780
 
1781
    end
1782
 
1783
    if (m_phase_trace) begin
1784
      if (pred_of_succ.num()) begin
1785
        string s = "( ";
1786
        foreach (pred_of_succ[pred])
1787
          s = {s, pred.get_full_name()," "};
1788
        s = {s, ")"};
1789
        `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC",
1790
              {"*** All pred to succ ",s," in READY_TO_END state, so ending phase ***"},this,UVM_HIGH)
1791
      end
1792
      else begin
1793
        `UVM_PH_TRACE("PH/TRC/WAIT_PRED_OF_SUCC",
1794
                    "*** No pred to succ other than myself, so ending phase ***",this,UVM_HIGH)
1795
      end
1796
    end
1797
 
1798
  #0; // LET ANY WAITERS WAKE UP
1799
 
1800
endtask
1801
 
1802
 
1803
//---------------------------------
1804
// Implementation - Synchronization
1805
//---------------------------------
1806
 
1807
function void uvm_phase::m_report_null_objection(uvm_object obj,
1808
                                               string description,
1809
                                               int count,
1810
                                               string action);
1811
   string m_action;
1812
   string m_addon;
1813
   string m_obj_name = (obj == null) ? "uvm_top" : obj.get_full_name();
1814
 
1815
   if ((action == "raise") || (action == "drop")) begin
1816
      if (count != 1)
1817
        m_action = $sformatf("%s %0d objections", action, count);
1818
      else
1819
        m_action = $sformatf("%s an objection", action);
1820
   end
1821
   else if (action == "get_objection_count") begin
1822
      m_action = "call get_objection_count";
1823
   end
1824
 
1825
   if (this.get_phase_type() == UVM_PHASE_IMP) begin
1826
      m_addon = " (This is a UVM_PHASE_IMP, you have to query the schedule to find the UVM_PHASE_NODE)";
1827
   end
1828
 
1829
   `uvm_error("UVM/PH/NULL_OBJECTION",
1830
              $sformatf("'%s' attempted to %s on '%s', however '%s' is not a task-based phase node! %s",
1831
                        m_obj_name,
1832
                        m_action,
1833
                        get_name(),
1834
                        get_name(),
1835
                        m_addon))
1836
endfunction : m_report_null_objection
1837
 
1838
 
1839
// raise_objection
1840
// ---------------
1841
 
1842
function void uvm_phase::raise_objection (uvm_object obj,
1843
                                                   string description="",
1844
                                                   int count=1);
1845
  if (phase_done != null)
1846
    phase_done.raise_objection(obj,description,count);
1847
  else
1848
    m_report_null_objection(obj, description, count, "raise");
1849
endfunction
1850
 
1851
 
1852
// drop_objection
1853
// --------------
1854
 
1855
function void uvm_phase::drop_objection (uvm_object obj,
1856
                                                  string description="",
1857
                                                  int count=1);
1858
  if (phase_done != null)
1859
    phase_done.drop_objection(obj,description,count);
1860
  else
1861
    m_report_null_objection(obj, description, count, "drop");
1862
endfunction
1863
 
1864
// get_objection_count
1865
// -------------------
1866
 
1867
function int uvm_phase::get_objection_count (uvm_object obj=null);
1868
   if (phase_done != null)
1869
     return phase_done.get_objection_count(obj);
1870
   else begin
1871
      m_report_null_objection(obj, "" , 0, "get_objection_count");
1872
      return 0;
1873
   end
1874
endfunction : get_objection_count
1875
 
1876
// sync
1877
// ----
1878
 
1879
function void uvm_phase::sync(uvm_domain target,
1880
                              uvm_phase phase=null,
1881
                              uvm_phase with_phase=null);
1882
  if (!this.is_domain()) begin
1883
    `uvm_fatal("PH_BADSYNC","sync() called from a non-domain phase schedule node");
1884
  end
1885
  else if (target == null) begin
1886
    `uvm_fatal("PH_BADSYNC","sync() called with a null target domain");
1887
  end
1888
  else if (!target.is_domain()) begin
1889
    `uvm_fatal("PH_BADSYNC","sync() called with a non-domain phase schedule node as target");
1890
  end
1891
  else if (phase == null && with_phase != null) begin
1892
    `uvm_fatal("PH_BADSYNC","sync() called with null phase and non-null with phase");
1893
  end
1894
  else if (phase == null) begin
1895
    // whole domain sync - traverse this domain schedule from begin to end node and sync each node
1896
    int visited[uvm_phase];
1897
    uvm_phase queue[$];
1898
    queue.push_back(this);
1899
    visited[this] = 1;
1900
    while (queue.size()) begin
1901
      uvm_phase node;
1902
      node = queue.pop_front();
1903
      if (node.m_imp != null) begin
1904
        sync(target, node.m_imp);
1905
      end
1906
      foreach (node.m_successors[succ]) begin
1907
        if (!visited.exists(succ)) begin
1908
          queue.push_back(succ);
1909
          visited[succ] = 1;
1910
        end
1911
      end
1912
    end
1913
  end else begin
1914
    // single phase sync
1915
    // this is a 2-way ('with') sync and we check first in case it is already there
1916
    uvm_phase from_node, to_node;
1917
    int found_to[$], found_from[$];
1918
    if(with_phase == null) with_phase = phase;
1919
    from_node = find(phase);
1920
    to_node = target.find(with_phase);
1921
    if(from_node == null || to_node == null) return;
1922
    found_to = from_node.m_sync.find_index(node) with (node == to_node);
1923
    found_from = to_node.m_sync.find_index(node) with (node == from_node);
1924
    if (found_to.size() == 0) from_node.m_sync.push_back(to_node);
1925
    if (found_from.size() == 0) to_node.m_sync.push_back(from_node);
1926
  end
1927
endfunction
1928
 
1929
 
1930
// unsync
1931
// ------
1932
 
1933
function void uvm_phase::unsync(uvm_domain target,
1934
                                uvm_phase phase=null,
1935
                                uvm_phase with_phase=null);
1936
  if (!this.is_domain()) begin
1937
    `uvm_fatal("PH_BADSYNC","unsync() called from a non-domain phase schedule node");
1938
  end else if (target == null) begin
1939
    `uvm_fatal("PH_BADSYNC","unsync() called with a null target domain");
1940
  end else if (!target.is_domain()) begin
1941
    `uvm_fatal("PH_BADSYNC","unsync() called with a non-domain phase schedule node as target");
1942
  end else if (phase == null && with_phase != null) begin
1943
    `uvm_fatal("PH_BADSYNC","unsync() called with null phase and non-null with phase");
1944
  end else if (phase == null) begin
1945
    // whole domain unsync - traverse this domain schedule from begin to end node and unsync each node
1946
    int visited[uvm_phase];
1947
    uvm_phase queue[$];
1948
    queue.push_back(this);
1949
    visited[this] = 1;
1950
    while (queue.size()) begin
1951
      uvm_phase node;
1952
      node = queue.pop_front();
1953
      if (node.m_imp != null) unsync(target,node.m_imp);
1954
      foreach (node.m_successors[succ]) begin
1955
        if (!visited.exists(succ)) begin
1956
          queue.push_back(succ);
1957
          visited[succ] = 1;
1958
        end
1959
      end
1960
    end
1961
  end else begin
1962
    // single phase unsync
1963
    // this is a 2-way ('with') sync and we check first in case it is already there
1964
    uvm_phase from_node, to_node;
1965
    int found_to[$], found_from[$];
1966
    if(with_phase == null) with_phase = phase;
1967
    from_node = find(phase);
1968
    to_node = target.find(with_phase);
1969
    if(from_node == null || to_node == null) return;
1970
    found_to = from_node.m_sync.find_index(node) with (node == to_node);
1971
    found_from = to_node.m_sync.find_index(node) with (node == from_node);
1972
    if (found_to.size()) from_node.m_sync.delete(found_to[0]);
1973
    if (found_from.size()) to_node.m_sync.delete(found_from[0]);
1974
  end
1975
endfunction
1976
 
1977
 
1978
// wait_for_state
1979
//---------------
1980
 
1981
task uvm_phase::wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ);
1982
  case (op)
1983
    UVM_EQ:  wait((state&m_state) != 0);
1984
    UVM_NE:  wait((state&m_state) == 0);
1985
    UVM_LT:  wait(m_state <  state);
1986
    UVM_LTE: wait(m_state <= state);
1987
    UVM_GT:  wait(m_state >  state);
1988
    UVM_GTE: wait(m_state >= state);
1989
  endcase
1990
endtask
1991
 
1992
 
1993
//-------------------------
1994
// Implementation - Jumping
1995
//-------------------------
1996
 
1997
// set_jump_phase
1998
// ----
1999
//
2000
// Specify a phase to transition to when phase is complete.
2001
 
2002
function void uvm_phase::set_jump_phase(uvm_phase phase) ;
2003
  uvm_phase d;
2004
 
2005
  if ((m_state <  UVM_PHASE_STARTED) ||
2006
      (m_state >  UVM_PHASE_ENDED) )
2007
  begin
2008
   `uvm_error("JMPPHIDL", { "Attempting to jump from phase \"",
2009
      get_name(), "\" which is not currently active (current state is ",
2010
      m_state.name(), "). The jump will not happen until the phase becomes ",
2011
      "active."})
2012
  end
2013
 
2014
 
2015
 
2016
  // A jump can be either forward or backwards in the phase graph.
2017
  // If the specified phase (name) is found in the set of predecessors
2018
  // then we are jumping backwards.  If, on the other hand, the phase is in the set
2019
  // of successors then we are jumping forwards.  If neither, then we
2020
  // have an error.
2021
  //
2022
  // If the phase is non-existant and thus we don't know where to jump
2023
  // we have a situation where the only thing to do is to uvm_report_fatal
2024
  // and terminate_phase.  By calling this function the intent was to
2025
  // jump to some other phase. So, continuing in the current phase doesn't
2026
  // make any sense.  And we don't have a valid phase to jump to.  So we're done.
2027
 
2028
  d = m_find_predecessor(phase,0);
2029
  if (d == null) begin
2030
    d = m_find_successor(phase,0);
2031
    if (d == null) begin
2032
      string msg;
2033
      $sformat(msg,{"phase %s is neither a predecessor or successor of ",
2034
                    "phase %s or is non-existant, so we cannot jump to it.  ",
2035
                    "Phase control flow is now undefined so the simulation ",
2036
                    "must terminate"}, phase.get_name(), get_name());
2037
      `uvm_fatal("PH_BADJUMP", msg);
2038
    end
2039
    else begin
2040
      m_jump_fwd = 1;
2041
      `uvm_info("PH_JUMPF",$sformatf("jumping forward to phase %s", phase.get_name()),
2042
                UVM_DEBUG);
2043
    end
2044
  end
2045
  else begin
2046
    m_jump_bkwd = 1;
2047
    `uvm_info("PH_JUMPB",$sformatf("jumping backward to phase %s", phase.get_name()),
2048
              UVM_DEBUG);
2049
  end
2050
 
2051
  m_jump_phase = d;
2052
endfunction
2053
 
2054
// end_prematurely
2055
// ----
2056
//
2057
// Set a flag to cause the phase to end prematurely.
2058
 
2059
function void uvm_phase::end_prematurely() ;
2060
   m_premature_end = 1 ;
2061
endfunction
2062
 
2063
// jump
2064
// ----
2065
//
2066
// Note that this function does not directly alter flow of control.
2067
// That is, the new phase is not initiated in this function.
2068
// Rather, flags are set which execute_phase() uses to determine
2069
// that a jump has been requested and performs the jump.
2070
 
2071
function void uvm_phase::jump(uvm_phase phase);
2072
   set_jump_phase(phase) ;
2073
   end_prematurely() ;
2074
endfunction
2075
 
2076
 
2077
// jump_all
2078
// --------
2079
function void uvm_phase::jump_all(uvm_phase phase);
2080
    `uvm_warning("NOTIMPL","uvm_phase::jump_all is not implemented and has been replaced by uvm_domain::jump_all")
2081
endfunction
2082
 
2083
 
2084
// get_jump_target
2085
// ---------------
2086
 
2087
function uvm_phase uvm_phase::get_jump_target();
2088
  return m_jump_phase;
2089
endfunction
2090
 
2091
 
2092
// clear
2093
// -----
2094
// for internal graph maintenance after a forward jump
2095
function void uvm_phase::clear(uvm_phase_state state = UVM_PHASE_DORMANT);
2096
  m_state = state;
2097
  m_phase_proc = null;
2098
  if (phase_done != null)
2099
    phase_done.clear(this);
2100
endfunction
2101
 
2102
 
2103
// clear_successors
2104
// ----------------
2105
// for internal graph maintenance after a forward jump
2106
// - called only by execute_phase()
2107
// - depth-first traversal of the DAG, calliing clear() on each node
2108
// - do not clear the end phase or beyond
2109
function void uvm_phase::clear_successors(uvm_phase_state state = UVM_PHASE_DORMANT,
2110
    uvm_phase end_state=null);
2111
  if(this == end_state)
2112
    return;
2113
  clear(state);
2114
  foreach(m_successors[succ]) begin
2115
    succ.clear_successors(state, end_state);
2116
  end
2117
endfunction
2118
 
2119
 
2120
//---------------------------------
2121
// Implementation - Overall Control
2122
//---------------------------------
2123
// wait_for_self_and_siblings_to_drop
2124
// -----------------------------
2125
// This task loops until this phase instance and all its siblings, either
2126
// sync'd or sharing a common successor, have all objections dropped.
2127
task uvm_phase::wait_for_self_and_siblings_to_drop() ;
2128
  bit need_to_check_all = 1 ;
2129
  uvm_root top;
2130
  uvm_coreservice_t cs;
2131
  bit siblings[uvm_phase];
2132
 
2133
  cs = uvm_coreservice_t::get();
2134
  top = cs.get_root();
2135
 
2136
  get_predecessors_for_successors(siblings);
2137
  foreach (m_sync[i]) begin
2138
    siblings[m_sync[i]] = 1;
2139
  end
2140
 
2141
  while (need_to_check_all) begin
2142
    need_to_check_all = 0 ; //if all are dropped, we won't need to do this again
2143
 
2144
    // wait for own objections to drop
2145
    if ((phase_done != null) && (phase_done.get_objection_total(top) != 0)) begin
2146
      m_state = UVM_PHASE_EXECUTING ;
2147
      phase_done.wait_for(UVM_ALL_DROPPED, top);
2148
      need_to_check_all = 1 ;
2149
    end
2150
 
2151
    // now wait for siblings to drop
2152
    foreach(siblings[sib]) begin
2153
      sib.wait_for_state(UVM_PHASE_EXECUTING, UVM_GTE); // sibling must be at least executing
2154
      if ((sib.phase_done != null) && (sib.phase_done.get_objection_total(top) != 0)) begin
2155
        m_state = UVM_PHASE_EXECUTING ;
2156
        sib.phase_done.wait_for(UVM_ALL_DROPPED, top); // sibling must drop any objection
2157
        need_to_check_all = 1 ;
2158
      end
2159
    end
2160
  end
2161
endtask
2162
 
2163
// kill
2164
// ----
2165
 
2166
function void uvm_phase::kill();
2167
 
2168
  `uvm_info("PH_KILL", {"killing phase '", get_name(),"'"}, UVM_DEBUG);
2169
 
2170
  if (m_phase_proc != null) begin
2171
    m_phase_proc.kill();
2172
    m_phase_proc = null;
2173
  end
2174
 
2175
endfunction
2176
 
2177
 
2178
// kill_successors
2179
// ---------------
2180
 
2181
// Using a depth-first traversal, kill all the successor phases of the
2182
// current phase.
2183
function void uvm_phase::kill_successors();
2184
  foreach (m_successors[succ])
2185
    succ.kill_successors();
2186
  kill();
2187
endfunction
2188
 
2189
 
2190
// m_run_phases
2191
// ------------
2192
 
2193
// This task contains the top-level process that owns all the phase
2194
// processes.  By hosting the phase processes here we avoid problems
2195
// associated with phase processes related as parents/children
2196
task uvm_phase::m_run_phases();
2197
  uvm_root top;
2198
  uvm_coreservice_t cs;
2199
  cs = uvm_coreservice_t::get();
2200
  top = cs.get_root();
2201
 
2202
  // initiate by starting first phase in common domain
2203
  begin
2204
    uvm_phase ph = uvm_domain::get_common_domain();
2205
    void'(m_phase_hopper.try_put(ph));
2206
  end
2207
 
2208
  forever begin
2209
    uvm_phase phase;
2210
    m_phase_hopper.get(phase);
2211
    fork
2212
      begin
2213
        phase.execute_phase();
2214
      end
2215
    join_none
2216
    #0;  // let the process start running
2217
  end
2218
endtask
2219
 
2220
 
2221
// terminate_phase
2222
// ---------------
2223
 
2224
function void uvm_phase::m_terminate_phase();
2225
  if (phase_done != null)
2226
    phase_done.clear(this);
2227
endfunction
2228
 
2229
 
2230
// print_termination_state
2231
// -----------------------
2232
 
2233
function void uvm_phase::m_print_termination_state();
2234
  uvm_root top;
2235
  uvm_coreservice_t cs;
2236
  cs = uvm_coreservice_t::get();
2237
  top = cs.get_root();
2238
  if (phase_done != null) begin
2239
    `uvm_info("PH_TERMSTATE",
2240
              $sformatf("phase %s outstanding objections = %0d",
2241
                        get_name(), phase_done.get_objection_total(top)),
2242
              UVM_DEBUG)
2243
  end
2244
  else begin
2245
    `uvm_info("PH_TERMSTATE",
2246
              $sformatf("phase %s has no outstanding objections",
2247
                        get_name()),
2248
              UVM_DEBUG)
2249
  end
2250
endfunction
2251
 
2252
 
2253
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.