ovm_sequencer_base.svh

Go to the documentation of this file.
00001 //----------------------------------------------------------------------
00002 //   Copyright 2007-2008 Mentor Graphics Corporation
00003 //   Copyright 2007-2008 Cadence Design Systems, Inc.
00004 //   All Rights Reserved Worldwide
00005 //
00006 //   Licensed under the Apache License, Version 2.0 (the
00007 //   "License"); you may not use this file except in
00008 //   compliance with the License.  You may obtain a copy of
00009 //   the License at
00010 //
00011 //       http://www.apache.org/licenses/LICENSE-2.0
00012 //
00013 //   Unless required by applicable law or agreed to in
00014 //   writing, software distributed under the License is
00015 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00016 //   CONDITIONS OF ANY KIND, either express or implied.  See
00017 //   the License for the specific language governing
00018 //   permissions and limitations under the License.
00019 //----------------------------------------------------------------------
00020 
00021 typedef class ovm_sequencer_base;
00022 
00023 typedef enum {SEQ_TYPE_REQ, SEQ_TYPE_LOCK, SEQ_TYPE_GRAB} SEQ_REQ_TYPE;
00024 typedef enum {SEQ_ARB_FIFO, SEQ_ARB_WEIGHTED, SEQ_ARB_RANDOM, SEQ_ARB_STRICT_FIFO, SEQ_ARB_STRICT_RANDOM, SEQ_ARB_USER} 
00025         SEQ_ARB_TYPE;
00026 
00027 class seq_req_class;
00028   static integer    g_request_id = 0;
00029   bit               grant;
00030   integer           sequence_id;
00031   integer           request_id;
00032   integer           item_priority;
00033   SEQ_REQ_TYPE      request;
00034   ovm_sequence_base sequence_ptr;
00035 
00036   function new(string name= "");
00037   endfunction
00038 endclass  
00039 
00040 class ovm_sequencer_base extends ovm_component;
00041 
00042   protected seq_req_class       arb_sequence_q[$];
00043 
00044   // The arb_completed associative array is used to indicate when a particular request_id
00045   // has been completed.  The array in indexed by request_id, and sequences will wait based
00046   // on the request_id assigned in the arb_sequence_q
00047   protected bit                 arb_completed[integer];
00048 
00049   protected ovm_sequence_base   lock_list[$];
00050   local     SEQ_ARB_TYPE        arbitration = SEQ_ARB_FIFO;
00051   local     ovm_sequence_base   reg_sequences[integer];
00052   local     static integer      g_sequence_id = 1;
00053   local     static integer      g_sequencer_id = 1;
00054   protected integer             m_sequencer_id;
00055   protected integer             m_lock_arb_size;  // used for waiting processes
00056   protected integer             m_arb_size;       // used for waiting processes
00057   protected integer             m_wait_for_item_sequence_id, m_wait_for_item_transaction_id;
00058             integer unsigned    pound_zero_count = 4;
00059              
00060 
00062   //set main and random sequence count variable if != -1
00063   //also accessed by ovm_main/random_sequence 
00064   integer count = -1;
00065 
00066   // testing fields
00067   integer m_random_count = 0;
00068   integer m_exhaustive_count = 0;
00069   integer m_simple_count = 0;
00070 
00071   //user settable property to limit main/random subsequences 
00072   //also accessed by ovm_main/random_sequence 
00073   integer unsigned max_random_count = 10;
00074 
00075   //Used for setting the maximum depth inside random sequences. 
00076   //(Beyond that depth, random creates only simple sequences.)
00077   int unsigned max_random_depth = 4;
00078 
00079   // This property defines which sequence will be auto-started (default=main).
00080   protected string default_sequence = "ovm_random_sequence";               
00081 
00082   // The sequeunce aray holds the type names of the sequence types registered
00083   // to this sequencer; the factory will actually create the instances on demand.
00084   string sequences[$];
00085 
00086   // The ids array associates each sequence entry (above) with an integer
00087   // number. This allows sequences to be randomly selected by randomizing
00088   // a number between 0 and the sequences array size.
00089   protected integer sequence_ids[string];
00090 
00091   // variable used to randomly select a sequence from the sequences array
00092   protected rand integer seq_kind;
00093 
00095 
00096   
00098   
00099   function new (string name, ovm_component parent);
00100     super.new(name, parent);
00101     void'(get_config_string("default_sequence", default_sequence));
00102     void'(get_config_int("count", count));
00103     void'(get_config_int("max_random_count", max_random_count));
00104     void'(get_config_int("max_random_depth", max_random_depth));
00105     void'(get_config_int("pound_zero_count", pound_zero_count));
00106     m_sequencer_id = g_sequencer_id++;
00107     m_lock_arb_size = -1;
00108   endfunction // new
00109 
00110   function void do_print (ovm_printer printer);
00111     super.do_print(printer);
00112     if(sequences.size() != 0) begin
00113       printer.print_string("default_sequence", default_sequence);
00114       printer.print_field("count", count, $bits(count), OVM_DEC);
00115       printer.print_field("max_random_count", max_random_count, 
00116         $bits(max_random_count), OVM_DEC);
00117       printer.print_array_header("sequences", sequences.size());
00118       for(int i=0; i<sequences.size(); ++i)
00119         printer.print_string($psprintf("[%0d]", i), sequences[i], "[");
00120       printer.print_array_footer();
00121       printer.print_field("max_random_depth", max_random_depth, 
00122         $bits(max_random_depth), OVM_DEC);
00123     end
00124   endfunction
00125  
00127   //
00128   // Local functions
00129   //
00131 
00132   protected function void m_update_lists();
00133     m_lock_arb_size++;
00134   endfunction // void
00135 
00136   function string display_queues();
00137     string s;
00138     
00139     $sformat(s, "  -- arb i/id/type: ");
00140     foreach (arb_sequence_q[i]) begin
00141       $sformat(s, "%s %0d/%0d/%s ", s, i, arb_sequence_q[i].sequence_id, arb_sequence_q[i].request);
00142     end // UNMATCHED !!
00143     $sformat(s, "%s\n -- lock_list i/id: ", s);
00144     foreach (lock_list[i]) begin
00145       $sformat(s, "%s %0d/%0d",s, i, lock_list[i].get_sequence_id());
00146     end // UNMATCHED !!
00147     return(s);
00148   endfunction // string
00149 
00150   local function integer next_sequence_id();
00151     return(g_sequence_id++);
00152   endfunction // int
00153 
00155   //
00156   // Local Sequence Registration Functions
00157   //
00159 
00160   protected function integer register_sequence(ovm_sequence_base sequence_ptr);
00161 
00162     if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0) begin
00163       return (sequence_ptr.get_sequence_id());
00164     end
00165     
00166     sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, next_sequence_id());
00167     reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr;
00168     return(sequence_ptr.get_sequence_id());
00169   endfunction
00170 
00171   protected function ovm_sequence_base find_sequence(integer sequence_id);
00172     ovm_sequence_base seq_ptr;
00173     integer           i;
00174     
00175     // When sequence_id is -1, return the first available sequence.  This is used
00176     // when deleting all sequences
00177     if (sequence_id == -1) begin
00178       if (reg_sequences.first(i)) begin
00179         return(reg_sequences[i]);
00180       end
00181       return(null);
00182     end
00183     
00184     if (reg_sequences.exists(sequence_id) == 0) begin
00185 //      ovm_report_warning("find_sequence", 
00186 //                         $psprintf("Sequence %d doesn't exist (find_sequence)", sequence_id));
00187       return (null);
00188     end
00189     return(reg_sequences[sequence_id]);
00190   endfunction  
00191 
00192   protected function void unregister_sequence(integer sequence_id);
00193     if (reg_sequences.exists(sequence_id) == 0) begin
00194 //      ovm_report_warning("unregister_sequence", 
00195 //                         $psprintf("Sequence %d doesn't exist (unregister_sequence)", sequence_id));
00196     end
00197     reg_sequences.delete(sequence_id);
00198   endfunction  
00199 
00200 
00202   //
00203   // virtual function integer user_priority_arbitration(integer avail_sequences[$]);
00204   //
00205   // If a user specifies that the sequencer is to use user_priority_arbitration
00206   // through the call set_arbitration(SEQ_ARB_USER), then the sequencer will
00207   // call this function each time that it needs to arbitrate among sequences.
00208   //
00209   // This function must return an integer that matches one of the available
00210   // sequences that is passed into the call through the avail_sequences parameter
00211   //
00212   // Each integer in avail_sequences points to an entry in the arb_sequence_q, 
00213   // which is a protected queue that may be accessed from this function.
00214   //
00215   // To modify the operation of user_priority_arbitration, the function may
00216   // arbitrarily choose any sequence among the list of avail_sequences.  It is
00217   // important to choose only an available sequence.
00218   //
00219   // The default implementation is FIFO, which simply returns the first integer
00220   // in the avail_sequences array
00222   
00223   virtual function integer user_priority_arbitration(integer avail_sequences[$]);
00224     return (avail_sequences[0]);
00225   endfunction // user_priority_arbitration
00226 
00228   //
00229   // grant_queued_locks
00230   //    Any lock or grab requests that are at the front of the
00231   //    queue will be granted at the earliest possible time.
00232   //
00233   //    This function grants any queues at the front that are
00234   //    not locked out
00236   
00237   protected function void grant_queued_locks();
00238     integer i, temp;
00239 
00240     for (i = 0; i < arb_sequence_q.size(); i++) begin
00241       
00242       // Check for lock requests.  Any lock request at the head
00243       // of the queue that is not blocked will be granted immediately.
00244       temp = 0;
00245       if (i < arb_sequence_q.size()) begin
00246         if (arb_sequence_q[i].request == SEQ_TYPE_LOCK) begin
00247           temp = (is_blocked(arb_sequence_q[i].sequence_ptr) == 0);
00248         end
00249       end
00250 
00251       // Grant the lock request and remove it from the queue.
00252       // This is a loop to handle multiple back-to-back locks.
00253       // Since each entry is deleted, i remains constant
00254       while (temp) begin
00255         lock_list.push_back(arb_sequence_q[i].sequence_ptr);
00256         set_arbitration_completed(arb_sequence_q[i].request_id);
00257         arb_sequence_q.delete(i);
00258         m_update_lists();
00259 
00260         temp = 0;
00261         if (i < arb_sequence_q.size()) begin
00262           if (arb_sequence_q[i].request == SEQ_TYPE_LOCK) begin
00263             temp = is_blocked(arb_sequence_q[i].sequence_ptr) == 0;
00264           end
00265         end
00266       end
00267     end // for (i = 0; i < arb_sequence_q.size(); i++)
00268   endfunction // void
00269 
00270     
00272   //
00273   // choose_next_request
00274   //    When a driver requests an operation, this function
00275   //    must find the next available, unlocked, relevant sequence
00276   //
00277   //    This function returns -1 if no sequences are available
00278   //    or the entry into arb_sequence_q for the chosen sequence
00280   
00281   protected function integer choose_next_request();
00282     integer i, temp;
00283     integer avail_sequence_count;
00284     integer sum_priority_val;
00285     integer avail_sequences[$];
00286     integer highest_sequences[$];
00287     integer highest_pri;
00288     string  s;
00289 
00290     avail_sequence_count = 0;
00291 
00292     grant_queued_locks();
00293 
00294     for (i = 0; i < arb_sequence_q.size(); i++) begin
00295       // Search for available sequences.  If in SEQ_ARB_FIFO arbitration,
00296       // then just return the first available sequence.  Otherwise,
00297       // create a list for arbitration purposes.
00298       if (i < arb_sequence_q.size())
00299         if (arb_sequence_q[i].request == SEQ_TYPE_REQ)
00300           if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0)
00301             if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin
00302               if (arbitration == SEQ_ARB_FIFO) begin
00303                 return (i);
00304               end
00305               else avail_sequences.push_back(i);
00306             end
00307     end // for (i = 0; i < arb_sequence_q.size(); i++)
00308 
00309     // Return immediately if there are 0 or 1 available sequences
00310     if (arbitration == SEQ_ARB_FIFO) begin
00311       return (-1);
00312     end
00313     if (avail_sequences.size() < 1)  begin
00314       return (-1);
00315     end
00316     
00317     if (avail_sequences.size() == 1) begin
00318       return (avail_sequences[0]);
00319     end
00320     
00321     // If any locks are in place, then the available queue must
00322     // be checked to see if a lock prevents any sequence from proceeding
00323     if (lock_list.size() > 0) begin
00324       for (i = 0; i < avail_sequences.size(); i++) begin
00325         if (is_blocked(arb_sequence_q[avail_sequences[i]].sequence_ptr) != 0) begin
00326           avail_sequences.delete(i);
00327           i--;
00328         end
00329       end
00330       if (avail_sequences.size() < 1) return (-1);
00331       if (avail_sequences.size() == 1) return (avail_sequences[0]);
00332     end
00333 
00335     //  Weighted Priority Distribution
00337     if (arbitration == SEQ_ARB_WEIGHTED) begin
00338       sum_priority_val = 0;
00339       for (i = 0; i < avail_sequences.size(); i++) begin
00340         sum_priority_val += get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
00341       end
00342       
00343       // Pick an available sequence based on weighted priorities of available sequences
00344       temp = $urandom_range(sum_priority_val-1, 0);
00345       sum_priority_val = 0;
00346       for (i = 0; i < avail_sequences.size(); i++) begin
00347         if ((get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) + 
00348              sum_priority_val) > temp) begin
00349           return (avail_sequences[i]);
00350         end
00351         sum_priority_val += get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
00352       end
00353       ovm_report_fatal("Sequencer", "OVM Internal error in weighted arbitration code");
00354     end // if (arbitration == SEQ_ARB_WEIGHTED)
00355     
00357     //  Random Distribution
00359     if (arbitration == SEQ_ARB_RANDOM) begin
00360       i = $urandom_range(avail_sequences.size()-1, 0);
00361       return (avail_sequences[i]);
00362     end
00363 
00365     //  Strict Fifo
00367     if ((arbitration == SEQ_ARB_STRICT_FIFO) || arbitration == SEQ_ARB_STRICT_RANDOM) begin
00368       highest_pri = 0;
00369       // Build a list of sequences at the highest priority
00370       for (i = 0; i < avail_sequences.size(); i++) begin
00371         if (get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) > highest_pri) begin
00372           // New highest priority, so start new list
00373           `ovm_clear_queue(highest_sequences)
00374           highest_sequences.push_back(i);
00375           highest_pri = get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
00376         end
00377         else if (get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) == highest_pri) begin
00378           highest_sequences.push_back(i);
00379         end
00380       end
00381 
00382       // Now choose one based on arbitration type
00383       if (arbitration == SEQ_ARB_STRICT_FIFO) begin
00384         return(highest_sequences[0]);
00385       end
00386       
00387       i = $urandom_range(highest_sequences.size()-1, 0);
00388       return (highest_sequences[i]);
00389     end // if ((arbitration == SEQ_ARB_STRICT_FIFO) || arbitration == SEQ_ARB_STRICT_RANDOM)
00390 
00391     if (arbitration == SEQ_ARB_USER) begin
00392       i = user_priority_arbitration(avail_sequences);
00393 
00394       // Check that the returned sequence is in the list of available sequences.  Failure to
00395       // use an available sequence will cause highly unpredictable results.
00396       highest_sequences = avail_sequences.find with (item == i);
00397       if (highest_sequences.size() == 0) begin
00398         ovm_report_fatal("Sequencer", $psprintf("Error in User arbitration, sequence %0d not available\n%s",
00399                                                 i, display_queues()));
00400       end
00401       return(i);
00402     end
00403       
00404     ovm_report_fatal("Sequencer", "Internal error: Failed to choose sequence");
00405 
00406   endfunction // int
00407 
00408   protected task m_wait_arb_not_equal();
00409     wait (m_arb_size != m_lock_arb_size);
00410   endtask // m_wait_arb_not_equal
00411 
00412   protected task wait_for_available_sequence();
00413     integer i;
00414     integer is_relevant_entries[$];
00415 
00416     // This routine will wait for a change in the request list, or for
00417     // wait_for_relevant to return on any non-relevant, non-blocked sequence
00418     m_arb_size = m_lock_arb_size;
00419 
00420     for (i = 0; i < arb_sequence_q.size(); i++) begin
00421       if (arb_sequence_q[i].request == SEQ_TYPE_REQ) begin
00422         if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) begin
00423           if (arb_sequence_q[i].sequence_ptr.is_relevant() == 0) begin
00424             is_relevant_entries.push_back(i);
00425           end
00426         end
00427       end
00428     end
00429 
00430     // Typical path - don't need fork if all queued entries are relevant
00431     if (is_relevant_entries.size() == 0) begin
00432       m_wait_arb_not_equal();
00433       return;
00434     end
00435 
00436     fork  // isolate inner fork block for disabling
00437       begin
00438         fork
00439           begin
00440             fork
00441 
00442               // One path in fork is for any wait_for_relevant to return
00443               for(i = 0; i < is_relevant_entries.size(); i++) begin
00444                 fork
00445                   begin
00446                     arb_sequence_q[is_relevant_entries[i]].sequence_ptr.wait_for_relevant();
00447                   end
00448                 join_any
00449               end
00450 
00451               // The other path in the fork is for any queue entry to change
00452               begin
00453                 m_wait_arb_not_equal();
00454               end
00455             join_any
00456           end
00457         join_any
00458         disable fork;
00459       end // fork
00460     join
00461   endtask // wait_for_available_sequence
00462 
00463   protected function integer get_seq_item_priority(seq_req_class seq_q_entry);
00464     // If the priority was set on the item, then that is used
00465     if (seq_q_entry.item_priority != -1) begin
00466       return (seq_q_entry.item_priority);
00467     end
00468     // Otherwise, use the priority of the calling sequence
00469     return (seq_q_entry.sequence_ptr.get_priority());
00470   endfunction
00471   
00473   //
00474   // arbitration completed tasks
00475   //    Used to tell the wait_for_grant function when
00476   //    a new arbitration is available
00478   
00479   task wait_for_arbitration_completed(integer request_id);
00480     int lock_arb_size;
00481     
00482     // Search the list of arb_wait_q, see if this item is done
00483     forever 
00484       begin
00485         lock_arb_size  = m_lock_arb_size;
00486         
00487         if (arb_completed.exists(request_id)) begin
00488           arb_completed.delete(request_id);
00489           return;
00490         end
00491         wait (lock_arb_size != m_lock_arb_size);
00492       end
00493   endtask // wait_for_arbitration_completed
00494 
00495   function void set_arbitration_completed(integer request_id);
00496     arb_completed[request_id] = 1;
00497   endfunction // void
00498 
00500 //
00501 // is_child
00502 //    Determine if a scenario is a child of a parent
00504 
00505 function bit is_child (ovm_sequence_base parent, ovm_sequence_base child);
00506     ovm_sequence_base sequence_ptr;
00507 
00508     if (child == null) begin
00509       ovm_report_fatal("ovm_sequencer", "is_child passed null child");
00510     end
00511 
00512     if (parent == null) begin
00513       ovm_report_fatal("ovm_sequencer", "is_child passed null parent");
00514     end
00515 
00516     sequence_ptr = child.get_parent_sequence();
00517     while (sequence_ptr != null) begin
00518       if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0) == 
00519           (parent.m_get_sqr_sequence_id(m_sequencer_id, 0))) begin
00520         return (1);
00521       end
00522       sequence_ptr = sequence_ptr.get_parent_sequence();
00523     end
00524     return (0);
00525 endfunction // bit
00526 
00528   //
00529   // Methods available to Sequences
00530   // 
00532   
00533   task wait_for_grant(ovm_sequence_base sequence_ptr, integer item_priority = -1, bit lock_request = 0);
00534     seq_req_class req_s;
00535     integer my_seq_id;
00536 
00537     if (sequence_ptr == null) begin
00538       ovm_report_fatal("ovm_sequencer", "wait_for_grant passed null sequence_ptr");
00539     end
00540 
00541     my_seq_id = register_sequence(sequence_ptr);
00542     
00543     // If lock_request is asserted, then issue a lock.  Don't wait for the response, since
00544     // there is a request immediately following the lock request
00545     if (lock_request == 1) begin
00546       req_s = new();
00547       req_s.grant = 0;
00548       req_s.sequence_id = sequence_ptr.get_sequence_id();
00549       req_s.request = SEQ_TYPE_LOCK;
00550       req_s.sequence_ptr = sequence_ptr;
00551       req_s.request_id = req_s.g_request_id++;
00552       arb_sequence_q.push_back(req_s);
00553     end // lock_request == 1
00554         
00555     // Push the request onto the queue
00556     req_s = new();
00557     req_s.grant = 0;
00558     req_s.request = SEQ_TYPE_REQ;
00559     req_s.sequence_id = my_seq_id;
00560     req_s.item_priority = item_priority;
00561     req_s.sequence_ptr = sequence_ptr;
00562     req_s.request_id = req_s.g_request_id++;
00563     arb_sequence_q.push_back(req_s);
00564     m_update_lists();
00565 
00566     // Wait until this entry is granted
00567     // Continue to point to the element, since location in queue will change
00568     wait_for_arbitration_completed(req_s.request_id);
00569   endtask // wait_for_grant
00570 
00571   task wait_for_item_done(ovm_sequence_base sequence_ptr, integer transaction_id);
00572     integer sequence_id;
00573 
00574     sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1);
00575     m_wait_for_item_sequence_id = -1;
00576     m_wait_for_item_transaction_id = -1;
00577 
00578     if (transaction_id == -1) begin
00579       wait (m_wait_for_item_sequence_id == sequence_id);
00580     end else begin
00581       wait ((m_wait_for_item_sequence_id == sequence_id &&
00582              m_wait_for_item_transaction_id == transaction_id));
00583     end
00584   endtask // wait_for_item_done
00585 
00586 
00588 //
00589 //  function bit is_blocked(ovm_sequence_base sequence_ptr);
00590 //
00591 //  is_blocked will return 1 if the sequence refered to in the parameter
00592 //  is currently locked out of the sequencer.  It will return 0 if the
00593 //  sequence is currently allowed to issue operations
00594 //
00595 //  Note that even when a sequence is not blocked, it is possible
00596 //  for another sequence to issue a lock before this sequence is able
00597 //  to issue a request or lock
00598 //
00600   
00601 function bit is_blocked(ovm_sequence_base sequence_ptr);
00602 
00603     if (sequence_ptr == null)
00604       ovm_report_fatal("ovm_sequence_controller", "is_blocked passed null sequence_ptr");
00605 
00606       foreach (lock_list[i]) begin
00607         if ((lock_list[i].m_get_sqr_sequence_id(m_sequencer_id, 0) != 
00608              sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0)) &&
00609             (is_child(lock_list[i], sequence_ptr) == 0)) begin
00610           return (1);
00611         end
00612       end 
00613       return (0);
00614 endfunction //
00615 
00616 
00618 //
00619 //  function bit is_locked(ovm_sequence_base sequence_ptr);
00620 //
00621 //  is_locked returns 1 if the sequence refered to in the parameter
00622 //  currently has a lock on this sequencer.  It will return 0 if the
00623 //  sequence does not currently have a lock.
00624 // 
00625 //  Note that even if this sequence has a lock, a child sequence may
00626 //  also have a lock, in which case the sequence is still blocked from
00627 //  issueing operations on the sequencer
00628 //
00630   
00631 function bit is_locked(ovm_sequence_base sequence_ptr);
00632     integer my_seq_id;
00633     
00634     if (sequence_ptr == null)
00635       ovm_report_fatal("ovm_sequence_controller", "is_locked passed null sequence_ptr");
00636     my_seq_id = register_sequence(sequence_ptr);
00637       foreach (lock_list[i]) begin
00638         if (lock_list[i].m_get_sqr_sequence_id(m_sequencer_id, 0) == 
00639             sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0)) begin
00640           return (1);
00641         end
00642       end 
00643     return (0);
00644 endfunction // bit
00645 
00647 //
00648 // lock_req
00649 //    Internal Call by a sequence to request a lock.  Puts
00650 //    the lock request onto the arbitration queue
00652   
00653 local task lock_req(ovm_sequence_base sequence_ptr, bit lock);
00654     integer my_seq_id;
00655     seq_req_class new_req;
00656     
00657     if (sequence_ptr == null)
00658       ovm_report_fatal("ovm_sequence_controller", "lock_req passed null sequence_ptr");
00659 
00660     my_seq_id = register_sequence(sequence_ptr);
00661     new_req = new();
00662     new_req.grant = 0;
00663     new_req.sequence_id = sequence_ptr.get_sequence_id();
00664     new_req.request = SEQ_TYPE_LOCK;
00665     new_req.sequence_ptr = sequence_ptr;
00666     new_req.request_id = new_req.g_request_id++;
00667     
00668     if (lock == 1) begin
00669       // Locks are arbitrated just like all other requests
00670       arb_sequence_q.push_back(new_req);
00671     end else begin
00672       // Grabs are not arbitrated - they go to the front
00673       // TODO:
00674       // Missing: grabs get arbitrated behind other grabs
00675       arb_sequence_q.push_front(new_req);
00676       m_update_lists();
00677     end
00678 
00679     // If this lock can be granted immediately, then do so.
00680     grant_queued_locks();
00681     
00682     wait_for_arbitration_completed(new_req.request_id);
00683 endtask
00684     
00686 //
00687 // unlock_req
00688 //    Called by a sequence to request an unlock.  This
00689 //    will remove a lock for this sequence if it exists
00691   
00692 function void unlock_req(ovm_sequence_base sequence_ptr);
00693     integer my_seq_id;
00694     
00695     if (sequence_ptr == null) begin
00696       ovm_report_fatal("ovm_sequencer", "unlock_req passed null sequence_ptr");
00697     end
00698     my_seq_id = register_sequence(sequence_ptr);
00699     
00700     foreach (lock_list[i]) begin
00701       if (lock_list[i].m_get_sqr_sequence_id(m_sequencer_id, 0) == 
00702           sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0)) begin
00703         lock_list.delete(i);
00704         m_update_lists();
00705         return;
00706       end
00707     end
00708 endfunction // void
00709 
00710 task lock(ovm_sequence_base sequence_ptr);
00711     lock_req(sequence_ptr, 1);
00712 endtask // lock
00713 
00714 task grab(ovm_sequence_base sequence_ptr);
00715     lock_req(sequence_ptr, 0);
00716 endtask // lock
00717 
00718 function void unlock(ovm_sequence_base sequence_ptr);
00719     unlock_req(sequence_ptr);
00720 endfunction // lock
00721 
00722 function void  ungrab(ovm_sequence_base sequence_ptr);
00723     unlock_req(sequence_ptr);
00724 endfunction // lock
00725 
00726 local function void remove_sequence_from_queues(ovm_sequence_base sequence_ptr);
00727     integer i;
00728 
00729     // Remove all queued items for this sequence and any child sequences
00730     i = 0;
00731     do 
00732       begin
00733         if (arb_sequence_q.size() > i) begin
00734           if ((arb_sequence_q[i].sequence_id == sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0)) ||
00735               (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin
00736             arb_sequence_q.delete(i);
00737             m_update_lists();
00738           end
00739           else begin
00740             i++;
00741           end
00742         end
00743       end
00744     while (i < arb_sequence_q.size());
00745     
00746     // remove locks for this sequence, and any child sequences
00747     i = 0;
00748     do
00749       begin
00750         if (lock_list.size() > i) begin
00751           if ((lock_list[i].m_get_sqr_sequence_id(m_sequencer_id, 0) == 
00752                sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0)) ||
00753               (is_child(sequence_ptr, lock_list[i]))) begin
00754             lock_list.delete(i);
00755             m_update_lists();
00756           end
00757           else begin
00758             i++;
00759           end
00760         end
00761       end
00762     while (i < lock_list.size());
00763     
00764     // Unregister the sequence_id, so that any returning data is dropped
00765     unregister_sequence(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1));
00766 endfunction // void
00767 
00768 function void stop_sequences();
00769     ovm_sequence_base seq_ptr;
00770     
00771     // remove all sequences
00772     seq_ptr = find_sequence(-1);
00773     while (seq_ptr != null)
00774       begin
00775         kill_sequence(seq_ptr);
00776         seq_ptr = find_sequence(-1);
00777       end
00778 endfunction // void
00779       
00780 function void sequence_exiting(ovm_sequence_base sequence_ptr);
00781     remove_sequence_from_queues(sequence_ptr);
00782 endfunction // void
00783 
00784 function void kill_sequence(ovm_sequence_base sequence_ptr);
00785     integer i;
00786 
00787     remove_sequence_from_queues(sequence_ptr);
00788     // kill the sequence
00789     sequence_ptr.m_kill();
00790 endfunction // void
00791 
00792 virtual function bit is_grabbed();
00793     return(lock_list.size() != 0);
00794 endfunction // bit
00795 
00796 virtual function ovm_sequence_base current_grabber();
00797     if (lock_list.size() == 0) begin
00798       return (null);
00799     end
00800     return (lock_list[lock_list.size()-1]);
00801 endfunction // ovm_sequence_base
00802 
00804   //
00805   // has_do_available function
00806   //   Determines if a sequence is ready to supply
00807   //   a transaction.  A sequence that obtains a
00808   //   transaction in pre-do must determine if the
00809   //   upstream object is ready to provide an item
00810   //
00811   //  returns 1 if a sequence is ready to issue an
00812   //  operation.  returns 0 if no unblocked, relevant
00813   //  sequence is requesting.
00814   //
00816 
00817   function bit has_do_available();
00818     
00819     foreach (arb_sequence_q[i]) begin
00820       if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin
00821         return (1);
00822       end
00823     end // UNMATCHED !!
00824     return (0);
00825   endfunction
00826   
00828   //
00829   //  function void set_arbitration(SEQ_ARB_TYPE val);
00830   //
00831   //  Specify the arbitration mode for the sequencer.
00832   //  the arbitration mode must be one of:
00833   //
00834   //  SEQ_ARB_FIFO:          All requests are granted in FIFO order
00835   //  SEQ_ARB_WEIGHTED:      Requests are granted randomly by weight
00836   //  SEQ_ARB_RANDOM:        Requests are granted randomly
00837   //  SEQ_ARB_STRICT_FIFO:   All requests at the highest priority are granted
00838   //                         in fifo order
00839   //  SEQ_ARB_STRICT_RANDOM: All requests at the highest priority are granted
00840   //                         in random order
00841   //  SEQ_ARB_USER:          The user function user_priority_arbitration is
00842   //                         called.  That function will specify the next
00843   //                         sequence to grant.  The default user function 
00844   //                         specifies FIFO order
00845   //
00847 
00848   function void set_arbitration(SEQ_ARB_TYPE val);
00849     arbitration = val;
00850   endfunction
00851 
00852   virtual function void analysis_write(ovm_sequence_item t);
00853     return;
00854   endfunction
00855 
00857   //
00858   // Methods available to Pull Drivers
00859   // 
00861 
00862   virtual task wait_for_sequences();
00863     for (int i = 0; i < pound_zero_count; i++) begin
00864       #0;
00865     end
00866   endtask // wait_for_sequences
00867 
00868    // add_sequence
00869 // ------------
00870 
00871 function void add_sequence(string type_name);
00872 
00873     //assign typename key to an int based on size
00874     //used with get_seq_kind to return an int key to match a type name
00875     sequence_ids[type_name] = sequences.size();
00876     //used w/ get_sequence to return a ovm_sequence factory object that 
00877     //matches an int id
00878     sequences.push_back(type_name);
00879 endfunction
00880 
00881 // remove_sequence
00882 // ---------------
00883 
00884 function void remove_sequence(string type_name);
00885   sequence_ids.delete(type_name);
00886   for (int i = 0; i < sequences.size(); i++) begin
00887     if (sequences[i] == type_name)
00888       sequences.delete(i);
00889   end
00890 endfunction
00891 
00892 // set_sequences_queue
00893 // -------------------
00894 
00895 function void set_sequences_queue(ref string sequencer_sequence_lib[$]);
00896     
00897     for(integer j=0; j < sequencer_sequence_lib.size(); j++) begin
00898       sequence_ids[sequencer_sequence_lib[j]] = sequences.size();
00899       this.sequences.push_back(sequencer_sequence_lib[j]);
00900     end
00901 endfunction // void
00902 
00903 // get_seq_kind
00904 // ------------
00905 
00906 // Return a unique sequence id given the name of a sequence.
00907 // This id is expected to be used in inline constraints.
00908 function integer get_seq_kind(string type_name);
00909 
00910   if (sequence_ids.exists(type_name))
00911     return sequence_ids[type_name];
00912 
00913   ovm_report_fatal("SEQNF", 
00914     $psprintf("Sequence type_name '%0s' not registered with this sequencer.",
00915     type_name));
00916 
00917 endfunction
00918 
00919 
00920 // get_sequence
00921 // ------------
00922 
00923 function ovm_sequence_base get_sequence(integer req_kind);
00924 
00925   ovm_factory factory = ovm_factory::get();
00926   ovm_sequence_base m_seq ;
00927   string m_seq_type;
00928 
00929   if (req_kind < 0 || req_kind >= sequences.size()) begin
00930     ovm_report_error("SEQRNG", 
00931       $psprintf("Kind arg '%0d' out of range. Need 0-%0d", 
00932       req_kind, sequences.size()-1));
00933   end
00934 
00935   m_seq_type = sequences[req_kind];
00936   if (!$cast(m_seq, factory.create_object_by_name(m_seq_type,
00937                                           get_full_name(),
00938                                           m_seq_type))) 
00939   begin
00940       ovm_report_fatal("FCTSEQ", 
00941         $psprintf("Factory can not produce a sequence of type %0s.",
00942         m_seq_type));
00943   end
00944 
00945   m_seq.print_sequence_info = 1;
00946   m_seq.set_sequencer (this);
00947   return m_seq;
00948   
00949 endfunction // ovm_sequence_base
00950 
00951   function integer num_sequences();
00952     return (sequences.size());
00953   endfunction // num_sequences
00954 
00955   virtual function void send_request(ovm_sequence_base sequence_ptr, ovm_sequence_item t, bit rerandomize = 0);
00956     return;
00957   endfunction
00958 
00960 
00962 //
00963 // Deprecated Methods
00964 //
00966 
00967   virtual task start_sequence(ovm_sequence_base seq_base);
00968     fork
00969       seq_base.start(this);
00970     join_none
00971   endtask // start_sequence
00972 
00973 endclass

Intelligent Design Verification
Intelligent Design Verification
Project: OVM, Revision: 1.1.0
Copyright (c) 2008 Intelligent Design Verification.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included here:
http://www.intelligentdv.com/licenses/fdl.txt
doxygen
Doxygen Version: 1.4.6
Mon Sep 29 14:23:30 2008
Find a documentation bug? Report bugs to: bugs.intelligentdv.com Project: DoxygenFilterSV