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   protected int                 m_seq_item_port_connect_size;
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     m_sequencer_id = g_sequencer_id++;
00102     m_lock_arb_size = -1;
00103     m_seq_item_port_connect_size = -1;
00104     void'(get_config_string("default_sequence", default_sequence));
00105     void'(get_config_int("count", count));
00106     void'(get_config_int("max_random_count", max_random_count));
00107     void'(get_config_int("max_random_depth", max_random_depth));
00108     void'(get_config_int("pound_zero_count", pound_zero_count));
00109   endfunction // new
00110 
00111   virtual function void build();
00112     super.build();
00113     void'(get_config_string("default_sequence", default_sequence));
00114     void'(get_config_int("count", count));
00115     void'(get_config_int("max_random_count", max_random_count));
00116     void'(get_config_int("max_random_depth", max_random_depth));
00117     void'(get_config_int("pound_zero_count", pound_zero_count));
00118   endfunction // build
00119 
00120   function void do_print (ovm_printer printer);
00121     super.do_print(printer);
00122     if(sequences.size() != 0) begin
00123       printer.print_string("default_sequence", default_sequence);
00124       printer.print_field("count", count, $bits(count), OVM_DEC);
00125       printer.print_field("max_random_count", max_random_count, 
00126         $bits(max_random_count), OVM_DEC);
00127       printer.print_array_header("sequences", sequences.size());
00128       for(int i=0; i<sequences.size(); ++i)
00129         printer.print_string($psprintf("[%0d]", i), sequences[i], "[");
00130       printer.print_array_footer();
00131       printer.print_field("max_random_depth", max_random_depth, 
00132         $bits(max_random_depth), OVM_DEC);
00133     end
00134   endfunction
00135  
00137   //
00138   // Local functions
00139   //
00141 
00142   protected function void m_update_lists();
00143     m_lock_arb_size++;
00144   endfunction // void
00145 
00146   function string display_queues();
00147     string s;
00148     
00149     $sformat(s, "  -- arb i/id/type: ");
00150     foreach (arb_sequence_q[i]) begin
00151       $sformat(s, "%s %0d/%0d/%s ", s, i, arb_sequence_q[i].sequence_id, arb_sequence_q[i].request);
00152     end // UNMATCHED !!
00153     $sformat(s, "%s\n -- lock_list i/id: ", s);
00154     foreach (lock_list[i]) begin
00155       $sformat(s, "%s %0d/%0d",s, i, lock_list[i].get_sequence_id());
00156     end // UNMATCHED !!
00157     return(s);
00158   endfunction // string
00159 
00160   local function integer next_sequence_id();
00161     return(g_sequence_id++);
00162   endfunction // int
00163 
00165   //
00166   // Local Sequence Registration Functions
00167   //
00169 
00170   protected virtual function int  m_find_number_driver_connections();
00171     return(0);
00172   endfunction
00173 
00174   protected function integer register_sequence(ovm_sequence_base sequence_ptr);
00175 
00176     if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0) begin
00177       return (sequence_ptr.get_sequence_id());
00178     end
00179     
00180     sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, next_sequence_id());
00181     reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr;
00182     return(sequence_ptr.get_sequence_id());
00183   endfunction
00184 
00185   protected function ovm_sequence_base find_sequence(integer sequence_id);
00186     ovm_sequence_base seq_ptr;
00187     integer           i;
00188     
00189     // When sequence_id is -1, return the first available sequence.  This is used
00190     // when deleting all sequences
00191     if (sequence_id == -1) begin
00192       if (reg_sequences.first(i)) begin
00193         return(reg_sequences[i]);
00194       end
00195       return(null);
00196     end
00197     
00198     if (reg_sequences.exists(sequence_id) == 0) begin
00199 //      ovm_report_warning("find_sequence", 
00200 //                         $psprintf("Sequence %d doesn't exist (find_sequence)", sequence_id));
00201       return (null);
00202     end
00203     return(reg_sequences[sequence_id]);
00204   endfunction  
00205 
00206   protected function void unregister_sequence(integer sequence_id);
00207     if (reg_sequences.exists(sequence_id) == 0) begin
00208 //      ovm_report_warning("unregister_sequence", 
00209 //                         $psprintf("Sequence %d doesn't exist (unregister_sequence)", sequence_id));
00210     end
00211     reg_sequences.delete(sequence_id);
00212   endfunction  
00213 
00214 
00216   //
00217   // virtual function integer user_priority_arbitration(integer avail_sequences[$]);
00218   //
00219   // If a user specifies that the sequencer is to use user_priority_arbitration
00220   // through the call set_arbitration(SEQ_ARB_USER), then the sequencer will
00221   // call this function each time that it needs to arbitrate among sequences.
00222   //
00223   // This function must return an integer that matches one of the available
00224   // sequences that is passed into the call through the avail_sequences parameter
00225   //
00226   // Each integer in avail_sequences points to an entry in the arb_sequence_q, 
00227   // which is a protected queue that may be accessed from this function.
00228   //
00229   // To modify the operation of user_priority_arbitration, the function may
00230   // arbitrarily choose any sequence among the list of avail_sequences.  It is
00231   // important to choose only an available sequence.
00232   //
00233   // The default implementation is FIFO, which simply returns the first integer
00234   // in the avail_sequences array
00236   
00237   virtual function integer user_priority_arbitration(integer avail_sequences[$]);
00238     return (avail_sequences[0]);
00239   endfunction // user_priority_arbitration
00240 
00242   //
00243   // grant_queued_locks
00244   //    Any lock or grab requests that are at the front of the
00245   //    queue will be granted at the earliest possible time.
00246   //
00247   //    This function grants any queues at the front that are
00248   //    not locked out
00250   
00251   protected function void grant_queued_locks();
00252     integer i, temp;
00253 
00254     for (i = 0; i < arb_sequence_q.size(); i++) begin
00255       
00256       // Check for lock requests.  Any lock request at the head
00257       // of the queue that is not blocked will be granted immediately.
00258       temp = 0;
00259       if (i < arb_sequence_q.size()) begin
00260         if (arb_sequence_q[i].request == SEQ_TYPE_LOCK) begin
00261           temp = (is_blocked(arb_sequence_q[i].sequence_ptr) == 0);
00262         end
00263       end
00264 
00265       // Grant the lock request and remove it from the queue.
00266       // This is a loop to handle multiple back-to-back locks.
00267       // Since each entry is deleted, i remains constant
00268       while (temp) begin
00269         lock_list.push_back(arb_sequence_q[i].sequence_ptr);
00270         set_arbitration_completed(arb_sequence_q[i].request_id);
00271         arb_sequence_q.delete(i);
00272         m_update_lists();
00273 
00274         temp = 0;
00275         if (i < arb_sequence_q.size()) begin
00276           if (arb_sequence_q[i].request == SEQ_TYPE_LOCK) begin
00277             temp = is_blocked(arb_sequence_q[i].sequence_ptr) == 0;
00278           end
00279         end
00280       end
00281     end // for (i = 0; i < arb_sequence_q.size(); i++)
00282   endfunction // void
00283 
00284     
00286   //
00287   // choose_next_request
00288   //    When a driver requests an operation, this function
00289   //    must find the next available, unlocked, relevant sequence
00290   //
00291   //    This function returns -1 if no sequences are available
00292   //    or the entry into arb_sequence_q for the chosen sequence
00294   
00295   protected function integer choose_next_request();
00296     integer i, temp;
00297     integer avail_sequence_count;
00298     integer sum_priority_val;
00299     integer avail_sequences[$];
00300     integer highest_sequences[$];
00301     integer highest_pri;
00302     string  s;
00303 
00304     avail_sequence_count = 0;
00305 
00306     grant_queued_locks();
00307 
00308     for (i = 0; i < arb_sequence_q.size(); i++) begin
00309       // Search for available sequences.  If in SEQ_ARB_FIFO arbitration,
00310       // then just return the first available sequence.  Otherwise,
00311       // create a list for arbitration purposes.
00312       if (i < arb_sequence_q.size())
00313         if (arb_sequence_q[i].request == SEQ_TYPE_REQ)
00314           if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0)
00315             if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin
00316               if (arbitration == SEQ_ARB_FIFO) begin
00317                 return (i);
00318               end
00319               else avail_sequences.push_back(i);
00320             end
00321     end // for (i = 0; i < arb_sequence_q.size(); i++)
00322 
00323     // Return immediately if there are 0 or 1 available sequences
00324     if (arbitration == SEQ_ARB_FIFO) begin
00325       return (-1);
00326     end
00327     if (avail_sequences.size() < 1)  begin
00328       return (-1);
00329     end
00330     
00331     if (avail_sequences.size() == 1) begin
00332       return (avail_sequences[0]);
00333     end
00334     
00335     // If any locks are in place, then the available queue must
00336     // be checked to see if a lock prevents any sequence from proceeding
00337     if (lock_list.size() > 0) begin
00338       for (i = 0; i < avail_sequences.size(); i++) begin
00339         if (is_blocked(arb_sequence_q[avail_sequences[i]].sequence_ptr) != 0) begin
00340           avail_sequences.delete(i);
00341           i--;
00342         end
00343       end
00344       if (avail_sequences.size() < 1) return (-1);
00345       if (avail_sequences.size() == 1) return (avail_sequences[0]);
00346     end
00347 
00349     //  Weighted Priority Distribution
00351     if (arbitration == SEQ_ARB_WEIGHTED) begin
00352       sum_priority_val = 0;
00353       for (i = 0; i < avail_sequences.size(); i++) begin
00354         sum_priority_val += get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
00355       end
00356       
00357       // Pick an available sequence based on weighted priorities of available sequences
00358       temp = $urandom_range(sum_priority_val-1, 0);
00359 
00360       sum_priority_val = 0;
00361       for (i = 0; i < avail_sequences.size(); i++) begin
00362         if ((get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) + 
00363              sum_priority_val) > temp) begin
00364           return (avail_sequences[i]);
00365         end
00366         sum_priority_val += get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
00367       end
00368       ovm_report_fatal("Sequencer", "OVM Internal error in weighted arbitration code");
00369     end // if (arbitration == SEQ_ARB_WEIGHTED)
00370     
00372     //  Random Distribution
00374     if (arbitration == SEQ_ARB_RANDOM) begin
00375       i = $urandom_range(avail_sequences.size()-1, 0);
00376       return (avail_sequences[i]);
00377     end
00378 
00380     //  Strict Fifo
00382     if ((arbitration == SEQ_ARB_STRICT_FIFO) || arbitration == SEQ_ARB_STRICT_RANDOM) begin
00383       highest_pri = 0;
00384       // Build a list of sequences at the highest priority
00385       for (i = 0; i < avail_sequences.size(); i++) begin
00386         if (get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) > highest_pri) begin
00387           // New highest priority, so start new list
00388           `ovm_clear_queue(highest_sequences)
00389           highest_sequences.push_back(i);
00390           highest_pri = get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
00391         end
00392         else if (get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) == highest_pri) begin
00393           highest_sequences.push_back(i);
00394         end
00395       end
00396 
00397       // Now choose one based on arbitration type
00398       if (arbitration == SEQ_ARB_STRICT_FIFO) begin
00399         return(highest_sequences[0]);
00400       end
00401       
00402       i = $urandom_range(highest_sequences.size()-1, 0);
00403       return (highest_sequences[i]);
00404     end // if ((arbitration == SEQ_ARB_STRICT_FIFO) || arbitration == SEQ_ARB_STRICT_RANDOM)
00405 
00406     if (arbitration == SEQ_ARB_USER) begin
00407       i = user_priority_arbitration(avail_sequences);
00408 
00409       // Check that the returned sequence is in the list of available sequences.  Failure to
00410       // use an available sequence will cause highly unpredictable results.
00411       highest_sequences = avail_sequences.find with (item == i);
00412       if (highest_sequences.size() == 0) begin
00413         ovm_report_fatal("Sequencer", $psprintf("Error in User arbitration, sequence %0d not available\n%s",
00414                                                 i, display_queues()));
00415       end
00416       return(i);
00417     end
00418       
00419     ovm_report_fatal("Sequencer", "Internal error: Failed to choose sequence");
00420 
00421   endfunction // int
00422 
00423   protected task m_wait_arb_not_equal();
00424     wait (m_arb_size != m_lock_arb_size);
00425   endtask // m_wait_arb_not_equal
00426 
00427   protected task wait_for_available_sequence();
00428     integer i;
00429     integer is_relevant_entries[$];
00430 
00431     // This routine will wait for a change in the request list, or for
00432     // wait_for_relevant to return on any non-relevant, non-blocked sequence
00433     m_arb_size = m_lock_arb_size;
00434 
00435     for (i = 0; i < arb_sequence_q.size(); i++) begin
00436       if (arb_sequence_q[i].request == SEQ_TYPE_REQ) begin
00437         if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) begin
00438           if (arb_sequence_q[i].sequence_ptr.is_relevant() == 0) begin
00439             is_relevant_entries.push_back(i);
00440           end
00441         end
00442       end
00443     end
00444 
00445     // Typical path - don't need fork if all queued entries are relevant
00446     if (is_relevant_entries.size() == 0) begin
00447       m_wait_arb_not_equal();
00448       return;
00449     end
00450 
00451     fork  // isolate inner fork block for disabling
00452       begin
00453         fork
00454           begin
00455             fork
00456 
00457               // One path in fork is for any wait_for_relevant to return
00458               for(i = 0; i < is_relevant_entries.size(); i++) begin
00459                 fork
00460                   begin
00461                     arb_sequence_q[is_relevant_entries[i]].sequence_ptr.wait_for_relevant();
00462                   end
00463                 join_any
00464               end
00465 
00466               // The other path in the fork is for any queue entry to change
00467               begin
00468                 m_wait_arb_not_equal();
00469               end
00470             join_any
00471           end
00472         join_any
00473         disable fork;
00474       end // fork
00475     join
00476   endtask // wait_for_available_sequence
00477 
00478   protected function integer get_seq_item_priority(seq_req_class seq_q_entry);
00479     // If the priority was set on the item, then that is used
00480     if (seq_q_entry.item_priority != -1) begin
00481       if (seq_q_entry.item_priority < 0) begin
00482         ovm_report_fatal("SEQITEMPRI", $psprintf("Sequence item from %s has illegal priority: %0d",
00483                                                  seq_q_entry.sequence_ptr.get_full_name(),
00484                                                  seq_q_entry.item_priority));
00485       end
00486       return (seq_q_entry.item_priority);
00487     end
00488     // Otherwise, use the priority of the calling sequence
00489     if (seq_q_entry.sequence_ptr.get_priority() < 0) begin
00490       ovm_report_fatal("SEQDEFPRI", $psprintf("Sequence %s has illegal priority: %0d",
00491                                                seq_q_entry.sequence_ptr.get_full_name(),
00492                                                seq_q_entry.sequence_ptr.get_priority()));
00493     end
00494     return (seq_q_entry.sequence_ptr.get_priority());
00495   endfunction
00496   
00498   //
00499   // arbitration completed tasks
00500   //    Used to tell the wait_for_grant function when
00501   //    a new arbitration is available
00503   
00504   task wait_for_arbitration_completed(integer request_id);
00505     int lock_arb_size;
00506     
00507     // Search the list of arb_wait_q, see if this item is done
00508     forever 
00509       begin
00510         lock_arb_size  = m_lock_arb_size;
00511         
00512         if (arb_completed.exists(request_id)) begin
00513           arb_completed.delete(request_id);
00514           return;
00515         end
00516         wait (lock_arb_size != m_lock_arb_size);
00517       end
00518   endtask // wait_for_arbitration_completed
00519 
00520   function void set_arbitration_completed(integer request_id);
00521     arb_completed[request_id] = 1;
00522   endfunction // void
00523 
00525 //
00526 // is_child
00527 //    Determine if a scenario is a child of a parent
00529 
00530 function bit is_child (ovm_sequence_base parent, ovm_sequence_base child);
00531     ovm_sequence_base sequence_ptr;
00532 
00533     if (child == null) begin
00534       ovm_report_fatal("ovm_sequencer", "is_child passed null child");
00535     end
00536 
00537     if (parent == null) begin
00538       ovm_report_fatal("ovm_sequencer", "is_child passed null parent");
00539     end
00540 
00541     sequence_ptr = child.get_parent_sequence();
00542     while (sequence_ptr != null) begin
00543       if (sequence_ptr.get_inst_id() == parent.get_inst_id()) begin
00544         return (1);
00545       end
00546       sequence_ptr = sequence_ptr.get_parent_sequence();
00547     end
00548     return (0);
00549 endfunction // bit
00550 
00552   //
00553   // Methods available to Sequences
00554   // 
00556   
00557   virtual task wait_for_grant(ovm_sequence_base sequence_ptr, integer item_priority = -1, bit lock_request = 0);
00558     seq_req_class req_s;
00559     integer my_seq_id;
00560 
00561     if (sequence_ptr == null) begin
00562       ovm_report_fatal("ovm_sequencer", "wait_for_grant passed null sequence_ptr");
00563     end
00564 
00565     // Determine the number of drivers connected to this sequencer
00566     if(m_seq_item_port_connect_size < 0) begin
00567       m_seq_item_port_connect_size = m_find_number_driver_connections();
00568     end
00569 
00570 `ifndef CDNS_NO_SQR_CON_CHK
00571     // If there are no drivers, then it is not possible to wait for grant
00572     if(m_seq_item_port_connect_size == 0) begin
00573       ovm_report_fatal("SQRWFG", "Wait_for_grant called on sequencer with no driver connected");
00574     end
00575 `endif
00576     
00577     my_seq_id = register_sequence(sequence_ptr);
00578     
00579     // If lock_request is asserted, then issue a lock.  Don't wait for the response, since
00580     // there is a request immediately following the lock request
00581     if (lock_request == 1) begin
00582       req_s = new();
00583       req_s.grant = 0;
00584       req_s.sequence_id = my_seq_id;
00585       req_s.request = SEQ_TYPE_LOCK;
00586       req_s.sequence_ptr = sequence_ptr;
00587       req_s.request_id = req_s.g_request_id++;
00588       arb_sequence_q.push_back(req_s);
00589     end // lock_request == 1
00590         
00591     // Push the request onto the queue
00592     req_s = new();
00593     req_s.grant = 0;
00594     req_s.request = SEQ_TYPE_REQ;
00595     req_s.sequence_id = my_seq_id;
00596     req_s.item_priority = item_priority;
00597     req_s.sequence_ptr = sequence_ptr;
00598     req_s.request_id = req_s.g_request_id++;
00599     arb_sequence_q.push_back(req_s);
00600     m_update_lists();
00601 
00602     // Wait until this entry is granted
00603     // Continue to point to the element, since location in queue will change
00604     wait_for_arbitration_completed(req_s.request_id);
00605 
00606     // The wait_for_grant_semaphore is used only to check that send_request
00607     // is only called after wait_for_grant.  This is not a complete check, since
00608     // requests might be done in parallel, but it will catch basic errors
00609     req_s.sequence_ptr.m_wait_for_grant_semaphore++;
00610 
00611   endtask // wait_for_grant
00612 
00613   task wait_for_item_done(ovm_sequence_base sequence_ptr, integer transaction_id);
00614     integer sequence_id;
00615 
00616     sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1);
00617     m_wait_for_item_sequence_id = -1;
00618     m_wait_for_item_transaction_id = -1;
00619 
00620     if (transaction_id == -1) begin
00621       wait (m_wait_for_item_sequence_id == sequence_id);
00622     end else begin
00623       wait ((m_wait_for_item_sequence_id == sequence_id &&
00624              m_wait_for_item_transaction_id == transaction_id));
00625     end
00626   endtask // wait_for_item_done
00627 
00628 
00630 //
00631 //  function bit is_blocked(ovm_sequence_base sequence_ptr);
00632 //
00633 //  is_blocked will return 1 if the sequence refered to in the parameter
00634 //  is currently locked out of the sequencer.  It will return 0 if the
00635 //  sequence is currently allowed to issue operations
00636 //
00637 //  Note that even when a sequence is not blocked, it is possible
00638 //  for another sequence to issue a lock before this sequence is able
00639 //  to issue a request or lock
00640 //
00642   
00643 function bit is_blocked(ovm_sequence_base sequence_ptr);
00644 
00645     if (sequence_ptr == null)
00646       ovm_report_fatal("ovm_sequence_controller", "is_blocked passed null sequence_ptr");
00647 
00648       foreach (lock_list[i]) begin
00649         if ((lock_list[i].get_inst_id() != 
00650              sequence_ptr.get_inst_id()) &&
00651             (is_child(lock_list[i], sequence_ptr) == 0)) begin
00652           return (1);
00653         end
00654       end 
00655       return (0);
00656 endfunction //
00657 
00658 
00660 //
00661 //  function bit is_locked(ovm_sequence_base sequence_ptr);
00662 //
00663 //  is_locked returns 1 if the sequence refered to in the parameter
00664 //  currently has a lock on this sequencer.  It will return 0 if the
00665 //  sequence does not currently have a lock.
00666 // 
00667 //  Note that even if this sequence has a lock, a child sequence may
00668 //  also have a lock, in which case the sequence is still blocked from
00669 //  issueing operations on the sequencer
00670 //
00672   
00673 function bit is_locked(ovm_sequence_base sequence_ptr);
00674     integer my_seq_id;
00675     
00676     if (sequence_ptr == null)
00677       ovm_report_fatal("ovm_sequence_controller", "is_locked passed null sequence_ptr");
00678     my_seq_id = register_sequence(sequence_ptr);
00679       foreach (lock_list[i]) begin
00680         if (lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) begin
00681           return (1);
00682         end
00683       end 
00684     return (0);
00685 endfunction // bit
00686 
00688 //
00689 // lock_req
00690 //    Internal Call by a sequence to request a lock.  Puts
00691 //    the lock request onto the arbitration queue
00693   
00694 local task lock_req(ovm_sequence_base sequence_ptr, bit lock);
00695     integer my_seq_id;
00696     seq_req_class new_req;
00697     
00698     if (sequence_ptr == null)
00699       ovm_report_fatal("ovm_sequence_controller", "lock_req passed null sequence_ptr");
00700 
00701     my_seq_id = register_sequence(sequence_ptr);
00702     new_req = new();
00703     new_req.grant = 0;
00704     new_req.sequence_id = sequence_ptr.get_sequence_id();
00705     new_req.request = SEQ_TYPE_LOCK;
00706     new_req.sequence_ptr = sequence_ptr;
00707     new_req.request_id = new_req.g_request_id++;
00708     
00709     if (lock == 1) begin
00710       // Locks are arbitrated just like all other requests
00711       arb_sequence_q.push_back(new_req);
00712     end else begin
00713       // Grabs are not arbitrated - they go to the front
00714       // TODO:
00715       // Missing: grabs get arbitrated behind other grabs
00716       arb_sequence_q.push_front(new_req);
00717       m_update_lists();
00718     end
00719 
00720     // If this lock can be granted immediately, then do so.
00721     grant_queued_locks();
00722     
00723     wait_for_arbitration_completed(new_req.request_id);
00724 endtask
00725     
00727 //
00728 // unlock_req
00729 //    Called by a sequence to request an unlock.  This
00730 //    will remove a lock for this sequence if it exists
00732   
00733 function void unlock_req(ovm_sequence_base sequence_ptr);
00734     integer my_seq_id;
00735     
00736     if (sequence_ptr == null) begin
00737       ovm_report_fatal("ovm_sequencer", "unlock_req passed null sequence_ptr");
00738     end
00739     my_seq_id = register_sequence(sequence_ptr);
00740     
00741     foreach (lock_list[i]) begin
00742       if (lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) begin
00743         lock_list.delete(i);
00744         m_update_lists();
00745         return;
00746       end
00747     end
00748 endfunction // void
00749 
00750 task lock(ovm_sequence_base sequence_ptr);
00751     lock_req(sequence_ptr, 1);
00752 endtask // lock
00753 
00754 task grab(ovm_sequence_base sequence_ptr);
00755     lock_req(sequence_ptr, 0);
00756 endtask // lock
00757 
00758 function void unlock(ovm_sequence_base sequence_ptr);
00759     unlock_req(sequence_ptr);
00760 endfunction // lock
00761 
00762 function void  ungrab(ovm_sequence_base sequence_ptr);
00763     unlock_req(sequence_ptr);
00764 endfunction // lock
00765 
00766 local function void remove_sequence_from_queues(ovm_sequence_base sequence_ptr);
00767     int i;
00768     int seq_id;
00769     
00770     seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0);
00771     
00772     // Remove all queued items for this sequence and any child sequences
00773     i = 0;
00774     do 
00775       begin
00776         if (arb_sequence_q.size() > i) begin
00777           if ((arb_sequence_q[i].sequence_id == seq_id) ||
00778               (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin
00779             arb_sequence_q.delete(i);
00780             m_update_lists();
00781           end
00782           else begin
00783             i++;
00784           end
00785         end
00786       end
00787     while (i < arb_sequence_q.size());
00788     
00789     // remove locks for this sequence, and any child sequences
00790     i = 0;
00791     do
00792       begin
00793         if (lock_list.size() > i) begin
00794           if ((lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) ||
00795               (is_child(sequence_ptr, lock_list[i]))) begin
00796             lock_list.delete(i);
00797             m_update_lists();
00798           end
00799           else begin
00800             i++;
00801           end
00802         end
00803       end
00804     while (i < lock_list.size());
00805     
00806     // Unregister the sequence_id, so that any returning data is dropped
00807     unregister_sequence(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1));
00808 endfunction // void
00809 
00810 function void stop_sequences();
00811     ovm_sequence_base seq_ptr;
00812     
00813     // remove all sequences
00814     seq_ptr = find_sequence(-1);
00815     while (seq_ptr != null)
00816       begin
00817         kill_sequence(seq_ptr);
00818         seq_ptr = find_sequence(-1);
00819       end
00820 endfunction // void
00821       
00822 function void sequence_exiting(ovm_sequence_base sequence_ptr);
00823     remove_sequence_from_queues(sequence_ptr);
00824 endfunction // void
00825 
00826 function void kill_sequence(ovm_sequence_base sequence_ptr);
00827     integer i;
00828 
00829     remove_sequence_from_queues(sequence_ptr);
00830     // kill the sequence
00831     sequence_ptr.m_kill();
00832 endfunction // void
00833 
00834 virtual function bit is_grabbed();
00835     return(lock_list.size() != 0);
00836 endfunction // bit
00837 
00838 virtual function ovm_sequence_base current_grabber();
00839     if (lock_list.size() == 0) begin
00840       return (null);
00841     end
00842     return (lock_list[lock_list.size()-1]);
00843 endfunction // ovm_sequence_base
00844 
00846   //
00847   // has_do_available function
00848   //   Determines if a sequence is ready to supply
00849   //   a transaction.  A sequence that obtains a
00850   //   transaction in pre-do must determine if the
00851   //   upstream object is ready to provide an item
00852   //
00853   //  returns 1 if a sequence is ready to issue an
00854   //  operation.  returns 0 if no unblocked, relevant
00855   //  sequence is requesting.
00856   //
00858 
00859   function bit has_do_available();
00860     
00861     foreach (arb_sequence_q[i]) begin
00862       if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin
00863         return (1);
00864       end
00865     end // UNMATCHED !!
00866     return (0);
00867   endfunction
00868   
00870   //
00871   //  function void set_arbitration(SEQ_ARB_TYPE val);
00872   //
00873   //  Specify the arbitration mode for the sequencer.
00874   //  the arbitration mode must be one of:
00875   //
00876   //  SEQ_ARB_FIFO:          All requests are granted in FIFO order
00877   //  SEQ_ARB_WEIGHTED:      Requests are granted randomly by weight
00878   //  SEQ_ARB_RANDOM:        Requests are granted randomly
00879   //  SEQ_ARB_STRICT_FIFO:   All requests at the highest priority are granted
00880   //                         in fifo order
00881   //  SEQ_ARB_STRICT_RANDOM: All requests at the highest priority are granted
00882   //                         in random order
00883   //  SEQ_ARB_USER:          The user function user_priority_arbitration is
00884   //                         called.  That function will specify the next
00885   //                         sequence to grant.  The default user function 
00886   //                         specifies FIFO order
00887   //
00889 
00890   function void set_arbitration(SEQ_ARB_TYPE val);
00891     arbitration = val;
00892   endfunction
00893 
00894   function SEQ_ARB_TYPE get_arbitration();
00895     return (arbitration);
00896   endfunction // SEQ_ARB_TYPE
00897 
00898   virtual function void analysis_write(ovm_sequence_item t);
00899     return;
00900   endfunction
00901 
00903   //
00904   // Methods available to Pull Drivers
00905   // 
00907 
00908   virtual task wait_for_sequences();
00909     for (int i = 0; i < pound_zero_count; i++) begin
00910       #0;
00911     end
00912   endtask // wait_for_sequences
00913 
00914    // add_sequence
00915 // ------------
00916 
00917 function void add_sequence(string type_name);
00918 
00919     //assign typename key to an int based on size
00920     //used with get_seq_kind to return an int key to match a type name
00921     sequence_ids[type_name] = sequences.size();
00922     //used w/ get_sequence to return a ovm_sequence factory object that 
00923     //matches an int id
00924     sequences.push_back(type_name);
00925 endfunction
00926 
00927 // remove_sequence
00928 // ---------------
00929 
00930 function void remove_sequence(string type_name);
00931   sequence_ids.delete(type_name);
00932   for (int i = 0; i < sequences.size(); i++) begin
00933     if (sequences[i] == type_name)
00934       sequences.delete(i);
00935   end
00936 endfunction
00937 
00938 // set_sequences_queue
00939 // -------------------
00940 
00941 function void set_sequences_queue(ref string sequencer_sequence_lib[$]);
00942     
00943     for(integer j=0; j < sequencer_sequence_lib.size(); j++) begin
00944       sequence_ids[sequencer_sequence_lib[j]] = sequences.size();
00945       this.sequences.push_back(sequencer_sequence_lib[j]);
00946     end
00947 endfunction // void
00948 
00949 // get_seq_kind
00950 // ------------
00951 
00952 // Return a unique sequence id given the name of a sequence.
00953 // This id is expected to be used in inline constraints.
00954 function integer get_seq_kind(string type_name);
00955 
00956   if (sequence_ids.exists(type_name))
00957     return sequence_ids[type_name];
00958 
00959   ovm_report_fatal("SEQNF", 
00960     $psprintf("Sequence type_name '%0s' not registered with this sequencer.",
00961     type_name));
00962 
00963 endfunction
00964 
00965 
00966 // get_sequence
00967 // ------------
00968 
00969 function ovm_sequence_base get_sequence(integer req_kind);
00970 
00971   ovm_factory factory = ovm_factory::get();
00972   ovm_sequence_base m_seq ;
00973   string m_seq_type;
00974 
00975   if (req_kind < 0 || req_kind >= sequences.size()) begin
00976     ovm_report_error("SEQRNG", 
00977       $psprintf("Kind arg '%0d' out of range. Need 0-%0d", 
00978       req_kind, sequences.size()-1));
00979   end
00980 
00981   m_seq_type = sequences[req_kind];
00982   if (!$cast(m_seq, factory.create_object_by_name(m_seq_type,
00983                                           get_full_name(),
00984                                           m_seq_type))) 
00985   begin
00986       ovm_report_fatal("FCTSEQ", 
00987         $psprintf("Factory can not produce a sequence of type %0s.",
00988         m_seq_type));
00989   end
00990 
00991   m_seq.print_sequence_info = 1;
00992   m_seq.set_sequencer (this);
00993   return m_seq;
00994   
00995 endfunction // ovm_sequence_base
00996 
00997   function integer num_sequences();
00998     return (sequences.size());
00999   endfunction // num_sequences
01000 
01001   virtual function void send_request(ovm_sequence_base sequence_ptr, ovm_sequence_item t, bit rerandomize = 0);
01002     return;
01003   endfunction
01004 
01006 
01008 //
01009 // Deprecated Methods
01010 //
01012 
01013   virtual task start_sequence(ovm_sequence_base seq_base);
01014     static bit issued=0;
01015     if (!issued) begin
01016       issued=1;
01017       ovm_report_warning("deprecated",
01018         {"ovm_sequencer_base::start_sequence() has been deprecated and ",
01019         "replaced by the start() task, which becomes the only means ",
01020         "of starting sequences."});
01021     end
01022 
01023     fork
01024       seq_base.start(this);
01025     join_none
01026   endtask // start_sequence
01027 
01028 endclass

Intelligent Design Verification
Intelligent Design Verification
Project: OVM, Revision: 2.0.1
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.5.5
Wed Jan 7 19:27:18 2009
Find a documentation bug? Report bugs to: bugs.intelligentdv.com Project: DoxygenFilterSV