ovm_sequencer.sv

Go to the documentation of this file.
00001 // $Id: ovm__sequencer_8sv-source.html,v 1.1 2008/10/07 21:54:41 alex.marin Exp $
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 // isolate inner fork block so can later disable it
00283     begin
00284      fork
00285       @m_eval_queue_e;  //this is a block waiting for new action entry or ungrab
00286       begin  // this block is detect changes for a sequence's relevance
00287         event trigger;
00288         for(int i=0; i<m_action_q.size(); ++i)
00289           if(m_grabbers.size() == 0 || 
00290             m_is_current_grabber(this.m_action_q[i]) == 1)
00291             if(!m_action_q[i].is_relevant()) begin
00292               // IUS issue work-around here...
00293               ovm_sequence s;
00294               s = m_action_q[i];
00295               fork 
00296               begin
00297                 s.wait_for_relevant();
00298                 ->trigger;
00299               end
00300               join_none
00301             end
00302         @trigger;
00303       end
00304      join_any
00305      disable fork;
00306     end
00307    join
00308   end
00309 endtask
00310 
00311 
00312 // get_next_item
00313 // -------------
00314   
00315 task ovm_sequencer::get_next_item(output ovm_sequence_item item);
00316   int index;
00317   while (!process_queue(index)) begin // select action
00318     m_wait_for_activate();
00319   end
00320   item_ready.wait_trigger(); // wait for pre_do, rand, mid_do to complete
00321   m_action_q.delete(index);
00322   m_action_e.delete(index);
00323   $cast(item, item_ready.get_trigger_data()); /* returns item passed into 
00324                                                m_item_ready_trigger in 
00325                                                ovm_sequence::m_post_sync */
00326 endtask
00327 
00328 
00329 // wait_for_sequences()
00330 // -------------
00331   
00332 task ovm_sequencer::wait_for_sequences();
00333     for (int i=0; i < 100 ; i++)
00334       #0;
00335 endtask
00336 
00337 
00338 // try_next_item()
00339 // -------------
00340   
00341 task ovm_sequencer::try_next_item(output ovm_sequence_item item);
00342   fork // isolate inner fork block so can later disable it
00343    begin
00344     fork : try_next_fork
00345      get_next_item(item);
00346      //items will be lost if wait_for_sequences does not delay sufficiently
00347      wait_for_sequences();
00348     join_any
00349     disable fork;
00350    end
00351   join
00352 endtask
00353   
00354 
00355 // item_done_trigger
00356 // -----------------
00357 
00358 function void ovm_sequencer::item_done_trigger(ovm_sequence_item 
00359   item=null);
00360   item_done.trigger(item);
00361 endfunction
00362   
00363 
00364 // has_do_available
00365 // -----------------
00366 
00367 function bit ovm_sequencer::has_do_available();
00368   for(int i = 0; i < this.m_action_q.size() ; i ++)
00369     if(this.m_action_q[i].is_relevant())
00370       return 1;
00371   return 0;
00372 endfunction
00373 
00374 
00375 // m_item_ready_trigger
00376 // --------------------
00377 
00378 function void ovm_sequencer::m_item_ready_trigger(
00379                     input ovm_object m_item=null);
00380   item_ready.trigger(m_item);
00381 endfunction
00382 
00383 
00384 // item_done_wait_trigger_data
00385 // ------------------------
00386 
00387 task ovm_sequencer::item_done_wait_trigger_data(output 
00388   ovm_sequence_item item);
00389   ovm_object m_object;
00390   item_done.wait_trigger_data(m_object);
00391   if (m_object != null) begin
00392     if(!$cast(item, m_object)) 
00393       ovm_report_fatal("ILLCST", $psprintf("cast failure on %0s %0s", 
00394         m_object.get_name(), m_object.get_type_name()));
00395   end
00396 endtask
00397 
00398 
00399 // grab()
00400 // ------
00401 
00402 task ovm_sequencer::grab(ovm_sequence seq);
00403   // already holds the grab
00404   if(m_grabbers[0] == seq)
00405     ovm_report_warning("DUPGRB", 
00406       "Duplicate grab for this sequence.  grab() ignored.");
00407     // grabbers queue is empty.  requestor gets.
00408   else if(!m_grabbers.size()) begin
00409       m_grabbers[0] = seq;
00410     end
00411   else begin
00412     // is child of grabber
00413     if(m_is_current_grabber(seq)) begin
00414       m_grabbers.push_front(seq);
00415     end
00416     else begin
00417       // block grab requestor
00418       m_block_grabber(seq);
00419       m_grabbers.push_front(seq);
00420     end
00421   end
00422 endtask: grab
00423 
00424 
00425 // m_block_grabber()
00426 // -----------------
00427 
00428 task ovm_sequencer::m_block_grabber(ovm_sequence seq);
00429   seq.m_set_is_blocked(1);
00430   while(1)  begin
00431     @ m_ungrab_e;
00432     if(m_is_current_grabber(seq) || m_grabbers.size() == 0) begin
00433       seq.m_set_is_blocked(0);
00434       return;
00435     end
00436   end
00437 endtask: m_block_grabber
00438 
00439 
00440 // m_is_current_grabber()
00441 // ------
00442 
00443 function bit ovm_sequencer::m_is_current_grabber(ovm_sequence seq);
00444   if(seq == m_grabbers[0])
00445     m_is_current_grabber = 1;
00446   else begin
00447     while(seq.get_parent_seq()) begin
00448       if(seq.get_parent_seq() == m_grabbers[0])
00449         return 1;
00450       else
00451         seq = seq.get_parent_seq();
00452     end
00453     m_is_current_grabber = 0;
00454   end
00455 endfunction : m_is_current_grabber
00456 
00457 
00458 // ungrab()
00459 // ------
00460 
00461 function void ovm_sequencer::ungrab(ovm_sequence seq);
00462   if(seq == m_grabbers[0]) begin
00463     m_grabbers.delete(0);
00464     -> m_ungrab_e;
00465     -> m_eval_queue_e;
00466   end
00467   else 
00468     ovm_report_error("ILNGRB", $psprintf("Illegal ungrab by %0s", 
00469       seq.get_name()));
00470 endfunction : ungrab
00471 
00472 
00473 // current_grabber()
00474 // ------
00475 
00476 function ovm_sequence ovm_sequencer::current_grabber();
00477   if(m_grabbers.size())
00478     return m_grabbers[0];
00479   else
00480     return null;
00481 endfunction :current_grabber
00482 
00483 
00484 // is_grabbed()
00485 // ------
00486 
00487 function bit ovm_sequencer::is_grabbed();
00488   if(m_grabbers.size())
00489     return 1;
00490   else
00491     return 0;
00492 endfunction :is_grabbed
00493 
00494 
00495 // m_last_push_front
00496 // --------------
00497 
00498 function void ovm_sequencer::m_last_push_front(ovm_sequence_item item);
00499    if(!num_last_items)
00500      return;
00501 
00502    if(m_last_queue.size() == num_last_items)
00503      void'(m_last_queue.pop_back());
00504 
00505    this.m_last_queue.push_front(item);
00506 endfunction
00507 
00508 
00509 // set_num_last_items
00510 // ----------------
00511 
00512 function void ovm_sequencer::set_num_last_items(int unsigned max);
00513   if(max > 1024) begin
00514     ovm_report_warning("HSTOB", 
00515       $psprintf("Invalid last size; 1024 is the maximum and will be used", 
00516       max));
00517     max = 1024;
00518   end
00519 
00520   //shrink the buffer
00521   while((m_last_queue.size() != 0) && (m_last_queue.size() > max)) begin
00522      void'(m_last_queue.pop_back());
00523   end
00524 
00525   num_last_items = max;
00526 endfunction
00527 
00528 
00529 // last
00530 // ----
00531 
00532 function ovm_sequence_item ovm_sequencer::last(int unsigned n);
00533   if(n > num_last_items) begin
00534     ovm_report_warning("HSTOB",
00535       $psprintf("Invalid last access (%0d), the max history is %0d", n,
00536       num_last_items));
00537     return null;
00538   end
00539   if(n == m_last_queue.size())
00540     return null;
00541 
00542   return m_last_queue[n];
00543 endfunction
00544 
00545 

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