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 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 Version: 1.5.5 Wed Jan 7 19:27:18 2009 |