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 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 Version: 1.4.6 Mon Sep 29 14:23:30 2008 |