00001 // $Id: ovm_sequencer.sv 1 2008-03-05 02:42:30Z seanoboyle $ 00002 //---------------------------------------------------------------------- 00003 // Copyright 2007-2008 Mentor Graphics Corporation 00004 // Copyright 2007-2008 Cadence Design Systems, Inc. 00005 // All Rights Reserved Worldwide 00006 // 00007 // Licensed under the Apache License, Version 2.0 (the 00008 // "License"); you may not use this file except in 00009 // compliance with the License. You may obtain a copy of 00010 // the License at 00011 // 00012 // http://www.apache.org/licenses/LICENSE-2.0 00013 // 00014 // Unless required by applicable law or agreed to in 00015 // writing, software distributed under the License is 00016 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 00017 // CONDITIONS OF ANY KIND, either express or implied. See 00018 // the License for the specific language governing 00019 // permissions and limitations under the License. 00020 //---------------------------------------------------------------------- 00021 00022 00023 `include "methodology/sequences/ovm_sequencer.svh" 00024 `include "methodology/sequences/ovm_sequence.svh" 00025 00026 00027 // new 00028 // --- 00029 00030 function ovm_seq_item_cons_if::new (string name="", 00031 ovm_component parent = null); 00032 super.new(name, parent); 00033 $cast(parent_as_seqr, parent); 00034 endfunction 00035 00036 00037 // do_print 00038 // --- 00039 00040 function void ovm_seq_item_cons_if::do_print (ovm_printer printer); 00041 super.do_print(printer); 00042 if (consumer != null) 00043 printer.print_string("item consumer", consumer.get_name()); 00044 else 00045 printer.print_string("item consumer", "NOT_CONNECTED"); 00046 endfunction 00047 00048 00049 // create 00050 // --- 00051 00052 function ovm_object ovm_seq_item_cons_if::create (string name=""); 00053 ovm_seq_item_cons_if i; i=new(name); 00054 return i; 00055 endfunction 00056 00057 00058 // get_type_name 00059 // --- 00060 00061 function string ovm_seq_item_cons_if::get_type_name(); 00062 return "ovm_seq_item_cons_if"; 00063 endfunction 00064 00065 00066 // connect_if 00067 // --- 00068 00069 function void ovm_seq_item_cons_if::connect_if( 00070 ovm_seq_item_prod_if item_prod_if); 00071 item_prod_if.seqr_ref = parent_as_seqr; 00072 consumer = item_prod_if.get_parent(); 00073 endfunction 00074 00075 00076 00077 // new 00078 // --- 00079 00080 function ovm_sequencer::new (string name, ovm_component parent); 00081 super.new(name, parent); 00082 $cast(seq_item_cons_if, create_component("ovm_seq_item_cons_if", 00083 "seq_item_cons_if")); 00084 item_done = new("item_done"); 00085 item_ready = new("item_ready"); 00086 void'(get_config_int("pull_mode", pull_mode)); 00087 void'(get_config_int("max_random_depth", max_random_depth)); 00088 void'(get_config_int("num_last_items", num_last_items)); 00089 endfunction 00090 00091 00092 // get_type_name 00093 // --- 00094 00095 function string ovm_sequencer::get_type_name(); 00096 return "ovm_sequencer"; 00097 endfunction 00098 00099 00100 // Implement data functions 00101 // ------------------------ 00102 00103 function void ovm_sequencer::do_copy (ovm_object rhs); 00104 ovm_sequencer seqr; 00105 super.do_copy(rhs); 00106 if(rhs == null) return; 00107 if(!$cast(seqr, rhs)) return; 00108 pull_mode = seqr.pull_mode; 00109 item_done = seqr.item_done; 00110 item_ready = seqr.item_ready; 00111 max_random_depth = seqr.max_random_depth; 00112 num_last_items = seqr.num_last_items; 00113 endfunction 00114 00115 function bit ovm_sequencer::do_compare (ovm_object rhs, 00116 ovm_comparer comparer); 00117 ovm_sequencer seqr; 00118 do_compare = 1; 00119 if(rhs == null) return 0; 00120 if(!$cast(seqr, rhs)) return 0; 00121 do_compare &= comparer.compare_field_int("pull_mode", pull_mode, seqr.pull_mode, 00122 $bits(pull_mode)); 00123 do_compare &= comparer.compare_object("item_done", item_done, seqr.item_done); 00124 do_compare &= comparer.compare_object("item_ready", item_ready, seqr.item_ready); 00125 do_compare &= comparer.compare_field_int("max_random_depth", max_random_depth, 00126 seqr.max_random_depth, $bits(max_random_depth), OVM_DEC); 00127 do_compare &= comparer.compare_field_int("num_last_items", num_last_items, 00128 seqr.num_last_items, $bits(num_last_items), OVM_DEC); 00129 endfunction 00130 00131 function void ovm_sequencer::do_print (ovm_printer printer); 00132 super.do_print(printer); 00133 if(sequences.size() != 0) 00134 printer.print_field("max_random_depth", max_random_depth, 00135 $bits(max_random_depth), OVM_DEC); 00136 printer.print_field("pull_mode", pull_mode, $bits(pull_mode)); 00137 printer.print_field("num_last_items", num_last_items, 00138 $bits(num_last_items), OVM_DEC); 00139 endfunction 00140 00141 function void ovm_sequencer::do_record (ovm_recorder recorder); 00142 super.do_record(recorder); 00143 recorder.record_field("pull_mode", pull_mode, $bits(pull_mode)); 00144 recorder.record_field("max_random_depth", max_random_depth, 00145 $bits(max_random_depth), OVM_DEC); 00146 recorder.record_field("num_last_items", num_last_items, 00147 $bits(num_last_items), OVM_DEC); 00148 endfunction 00149 00150 00151 // process_queue 00152 // ------------- 00153 00154 function bit ovm_sequencer::process_queue(output int index); 00155 00156 if(m_action_q.size() == 0) begin 00157 return 0; 00158 end else begin 00159 for(int i = 0; i < this.m_action_q.size() ; i ++) begin : process_queue_for 00160 if(m_grabbers.size() == 0 || 00161 m_is_current_grabber(this.m_action_q[i]) == 1) begin 00162 if(this.m_action_q[i].is_relevant()) begin : relevant_block 00163 //trigger process-specific urm_sequence::m_sync ovm_event 00164 m_action_e[i].trigger(); 00165 index = i; 00166 return 1; //process one action at a time 00167 end : relevant_block 00168 end 00169 process_queue = 0; 00170 end : process_queue_for 00171 end 00172 00173 endfunction 00174 00175 00176 // m_sync 00177 // ------ 00178 00179 task ovm_sequencer::m_sequencer_sync(input string item_name, 00180 ovm_sequence parent_seq, ovm_event ack_process); 00181 00182 this.m_action_q.push_back(parent_seq); 00183 this.m_action_e.push_back(ack_process); 00184 00185 ->m_eval_queue_e; 00186 00187 endtask 00188 00189 00190 // execute_item 00191 // ------------ 00192 00193 task ovm_sequencer::execute_item(input ovm_sequence_item item, 00194 ovm_sequence seq = null); 00195 ovm_sequence temp_seq; 00196 if (seq == null) 00197 temp_seq = new(); 00198 else 00199 temp_seq = seq; 00200 if(item.is_item()) begin 00201 ovm_event ack_process; 00202 ack_process = new({"ack_", item.get_name()}); 00203 m_sequencer_sync(item.get_name(), temp_seq, ack_process); 00204 ack_process.wait_trigger(); 00205 temp_seq.pre_do(1); 00206 #0; 00207 temp_seq.mid_do(item); 00208 m_last_push_front(item); 00209 m_item_ready_trigger(item); 00210 item_done_wait_trigger_data(item); 00211 temp_seq.post_do(item); 00212 end 00213 else begin 00214 ovm_sequence m_seq; 00215 $cast(m_seq, item); 00216 if (this.recording_detail != OVM_NONE) 00217 m_seq.tr_handle = begin_tr(m_seq, m_seq.get_name()); 00218 //temp_seq.pre_do(0); 00219 //temp_seq.mid_do(item); 00220 m_seq.set_sequencer(this); 00221 //allow users to detect started when a subsequence body() 00222 //calls ovm_do immediately 00223 #0 -> m_seq.started; 00224 m_seq.body(); 00225 -> m_seq.ended; 00226 //temp_seq.post_do(item); 00227 this.end_tr(item); 00228 end 00229 endtask 00230 00231 00232 // apply 00233 // ----- 00234 00235 task ovm_sequencer::apply(input ovm_sequence_item item, 00236 ovm_sequence seq = null); 00237 ovm_sequence temp_seq; 00238 if (seq == null) 00239 temp_seq = new(); 00240 else 00241 temp_seq = seq; 00242 if(item.is_item()) begin 00243 ovm_event ack_process; 00244 ack_process = new({"ack_", item.get_name()}); 00245 m_sequencer_sync(item.get_name(), temp_seq, ack_process); 00246 ack_process.wait_trigger(); 00247 temp_seq.pre_apply(); 00248 #0; 00249 temp_seq.mid_apply(); 00250 m_last_push_front(item); 00251 m_item_ready_trigger(item); 00252 item_done_wait_trigger_data(item); 00253 temp_seq.post_apply(); 00254 end 00255 else begin 00256 ovm_sequence m_seq; 00257 $cast(m_seq, item); 00258 if (this.recording_detail != OVM_NONE) 00259 m_seq.tr_handle = begin_tr(m_seq, m_seq.get_name()); 00260 temp_seq.pre_apply(); 00261 temp_seq.mid_apply(); 00262 m_seq.set_sequencer(this); 00263 //allow users to detect started when a subsequence body() 00264 //calls ovm_do immediately 00265 #0 -> m_seq.started; 00266 m_seq.body(); 00267 -> m_seq.ended; 00268 temp_seq.post_apply(); 00269 this.end_tr(item); 00270 end 00271 endtask 00272 00273 00274 // wait_for_activate 00275 // ----------------- 00276 00277 task ovm_sequencer::m_wait_for_activate(); 00278 if(m_action_q.size() == 0) 00279 @m_eval_queue_e; 00280 else begin // action queue is not empty (implication says process_queue 00281 // already returned a 0, which means no relevant, grab qualifier 00282 fork 00283 @m_eval_queue_e; //this is a block waiting for new action entry or ungrab 00284 begin // this block is detect changes for a sequence's relevance 00285 event trigger; 00286 for(int i=0; i<m_action_q.size(); ++i) 00287 if(m_grabbers.size() == 0 || 00288 m_is_current_grabber(this.m_action_q[i]) == 1) 00289 if(!m_action_q[i].is_relevant()) begin 00290 // IUS issue work-around here... 00291 ovm_sequence s; 00292 s = m_action_q[i]; 00293 fork 00294 begin 00295 s.wait_for_relevant(); 00296 ->trigger; 00297 end 00298 join_none 00299 end 00300 @trigger; 00301 end 00302 join_any 00303 disable fork; 00304 end 00305 endtask 00306 00307 00308 // get_next_item 00309 // ------------- 00310 00311 task ovm_sequencer::get_next_item(output ovm_sequence_item item); 00312 int index; 00313 while (!process_queue(index)) begin // select action 00314 m_wait_for_activate(); 00315 end 00316 item_ready.wait_trigger(); // wait for pre_do, rand, mid_do to complete 00317 m_action_q.delete(index); 00318 m_action_e.delete(index); 00319 $cast(item, item_ready.get_trigger_data()); /* returns item passed into 00320 m_item_ready_trigger in 00321 ovm_sequence::m_post_sync */ 00322 endtask 00323 00324 00325 // wait_for_sequences() 00326 // ------------- 00327 00328 task ovm_sequencer::wait_for_sequences(); 00329 for (int i=0; i < 100 ; i++) 00330 #0; 00331 endtask 00332 00333 00334 // try_next_item() 00335 // ------------- 00336 00337 task ovm_sequencer::try_next_item(output ovm_sequence_item item); 00338 fork 00339 get_next_item(item); 00340 //items will be lost if wait_for_sequences does not delay sufficiently 00341 wait_for_sequences(); 00342 join_any 00343 disable fork; 00344 endtask 00345 00346 00347 // item_done_trigger 00348 // ----------------- 00349 00350 function void ovm_sequencer::item_done_trigger(ovm_sequence_item 00351 item=null); 00352 item_done.trigger(item); 00353 endfunction 00354 00355 00356 // has_do_available 00357 // ----------------- 00358 00359 function bit ovm_sequencer::has_do_available(); 00360 for(int i = 0; i < this.m_action_q.size() ; i ++) 00361 if(this.m_action_q[i].is_relevant()) 00362 return 1; 00363 return 0; 00364 endfunction 00365 00366 00367 // m_item_ready_trigger 00368 // -------------------- 00369 00370 function void ovm_sequencer::m_item_ready_trigger( 00371 input ovm_object m_item=null); 00372 item_ready.trigger(m_item); 00373 endfunction 00374 00375 00376 // item_done_wait_trigger_data 00377 // ------------------------ 00378 00379 task ovm_sequencer::item_done_wait_trigger_data(output 00380 ovm_sequence_item item); 00381 ovm_object m_object; 00382 item_done.wait_trigger_data(m_object); 00383 if (m_object != null) begin 00384 if(!$cast(item, m_object)) 00385 ovm_report_fatal("ILLCST", $psprintf("cast failure on %0s %0s", 00386 m_object.get_name(), m_object.get_type_name())); 00387 end 00388 endtask 00389 00390 00391 // grab() 00392 // ------ 00393 00394 task ovm_sequencer::grab(ovm_sequence seq); 00395 // already holds the grab 00396 if(m_grabbers[0] == seq) 00397 ovm_report_warning("DUPGRB", 00398 "Duplicate grab for this sequence. grab() ignored."); 00399 // grabbers queue is empty. requestor gets. 00400 else if(!m_grabbers.size()) begin 00401 m_grabbers[0] = seq; 00402 end 00403 else begin 00404 // is child of grabber 00405 if(m_is_current_grabber(seq)) begin 00406 m_grabbers.push_front(seq); 00407 end 00408 else begin 00409 // block grab requestor 00410 m_block_grabber(seq); 00411 m_grabbers.push_front(seq); 00412 end 00413 end 00414 endtask: grab 00415 00416 00417 // m_block_grabber() 00418 // ----------------- 00419 00420 task ovm_sequencer::m_block_grabber(ovm_sequence seq); 00421 seq.m_set_is_blocked(1); 00422 while(1) begin 00423 @ m_ungrab_e; 00424 if(m_is_current_grabber(seq) || m_grabbers.size() == 0) begin 00425 seq.m_set_is_blocked(0); 00426 return; 00427 end 00428 end 00429 endtask: m_block_grabber 00430 00431 00432 // m_is_current_grabber() 00433 // ------ 00434 00435 function bit ovm_sequencer::m_is_current_grabber(ovm_sequence seq); 00436 if(seq == m_grabbers[0]) 00437 m_is_current_grabber = 1; 00438 else begin 00439 while(seq.get_parent_seq()) begin 00440 if(seq.get_parent_seq() == m_grabbers[0]) 00441 return 1; 00442 else 00443 seq = seq.get_parent_seq(); 00444 end 00445 m_is_current_grabber = 0; 00446 end 00447 endfunction : m_is_current_grabber 00448 00449 00450 // ungrab() 00451 // ------ 00452 00453 function void ovm_sequencer::ungrab(ovm_sequence seq); 00454 if(seq == m_grabbers[0]) begin 00455 m_grabbers.delete(0); 00456 -> m_ungrab_e; 00457 -> m_eval_queue_e; 00458 end 00459 else 00460 ovm_report_error("ILNGRB", $psprintf("Illegal ungrab by %0s", 00461 seq.get_name())); 00462 endfunction : ungrab 00463 00464 00465 // current_grabber() 00466 // ------ 00467 00468 function ovm_sequence ovm_sequencer::current_grabber(); 00469 if(m_grabbers.size()) 00470 return m_grabbers[0]; 00471 else 00472 return null; 00473 endfunction :current_grabber 00474 00475 00476 // is_grabbed() 00477 // ------ 00478 00479 function bit ovm_sequencer::is_grabbed(); 00480 if(m_grabbers.size()) 00481 return 1; 00482 else 00483 return 0; 00484 endfunction :is_grabbed 00485 00486 00487 // m_last_push_front 00488 // -------------- 00489 00490 function void ovm_sequencer::m_last_push_front(ovm_sequence_item item); 00491 if(!num_last_items) 00492 return; 00493 00494 if(m_last_queue.size() == num_last_items) 00495 void'(m_last_queue.pop_back()); 00496 00497 this.m_last_queue.push_front(item); 00498 endfunction 00499 00500 00501 // set_num_last_items 00502 // ---------------- 00503 00504 function void ovm_sequencer::set_num_last_items(int unsigned max); 00505 if(max > 1024) begin 00506 ovm_report_warning("HSTOB", 00507 $psprintf("Invalid last size; 1024 is the maximum and will be used", 00508 max)); 00509 max = 1024; 00510 end 00511 00512 //shrink the buffer 00513 while((m_last_queue.size() != 0) && (m_last_queue.size() > max)) begin 00514 void'(m_last_queue.pop_back()); 00515 end 00516 00517 num_last_items = max; 00518 endfunction 00519 00520 00521 // last 00522 // ---- 00523 00524 function ovm_sequence_item ovm_sequencer::last(int unsigned n); 00525 if(n > num_last_items) begin 00526 ovm_report_warning("HSTOB", 00527 $psprintf("Invalid last access (%0d), the max history is %0d", n, 00528 num_last_items)); 00529 return null; 00530 end 00531 if(n == m_last_queue.size()) 00532 return null; 00533 00534 return m_last_queue[n]; 00535 endfunction 00536 00537
![]() Intelligent Design Verification Project: OVM, Revision: 1.0.1 |
Copyright (c) 2008-2010 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.6.3 IDV SV Filter Version: 2.6.3 Sat Jun 19 11:16:37 2010 |