VMM OpenSource - sv/std_lib/xvc_xactor.sv

sv/std_lib/xvc_xactor.sv expanded source

00001 // 
00002 // -------------------------------------------------------------
00003 //    Copyright 2004-2008 Synopsys, 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 
00022 
00023 
00024 function xvc_xactor::new(string             name,
00025                          string             inst,
00026                          int                stream_id = -1,
00027                          xvc_action_channel action_chan = null,
00028                          xvc_action_channel interrupt_chan = null
00029                          `VMM_XACTOR_NEW_EXTERN_ARGS);
00030    super.new(name, inst, stream_id `VMM_XACTOR_NEW_CALL);
00031 
00032    this.trace = new({name, " Trace"}, inst);
00033 
00034    if (action_chan == null) begin
00035       action_chan = new({name, "Action Channel"}, inst);
00036    end else action_chan.reconfigure(1, 0);
00037    this.action_chan = action_chan;
00038    this.log.is_above(this.action_chan.log);
00039 
00040    if (interrupt_chan == null) begin
00041       interrupt_chan = new({name, "Interrupt Channel"}, inst, 65535);
00042    end else interrupt_chan.reconfigure(65535, 0);
00043    this.interrupt_chan = interrupt_chan;
00044    this.log.is_above(this.interrupt_chan.log);
00045 
00046    this.interrupt = 0;
00047    this.interrupted = 0;
00048 
00049    this.idle = new("Dummy idle action", this.log);
00050 endfunction: new
00051 
00052 
00053 function void xvc_xactor::add_action(xvc_action action);
00054    int i;
00055 
00056    if (action == null) begin
00057       `vmm_error(this.log, "Attempting to add a NULL action");
00058       return;
00059    end
00060 
00061    // Do we already know about this action?
00062    foreach(this.known_actions[i]) begin
00063       if (this.known_actions[i] == action) begin
00064          `vmm_warning(this.log, "Attempting to add already-known action");
00065          return;
00066       end
00067    end
00068 
00069    this.known_actions.push_back(action);
00070 endfunction: add_action
00071 
00072 
00073 function xvc_action xvc_xactor::parse(string argv[]);
00074    int i;
00075 
00076    parse = null;
00077 
00078    foreach(this.known_actions[i]) begin
00079       parse = this.known_actions[i].parse(argv);
00080       if (parse != null) return parse;
00081    end
00082 
00083    if (this.log.start_msg(vmm_log::FAILURE_TYP,
00084                           vmm_log::ERROR_SEV)) begin
00085        string msg = "Unknown action command:";
00086        foreach (argv[i]) begin
00087           msg = {msg, " ", argv[i]};
00088        end
00089        void'(this.log.text(msg));
00090        this.log.end_msg();
00091    end
00092 endfunction: parse
00093 
00094 
00095 function void xvc_xactor::start_xactor();
00096    super.start_xactor();
00097 endfunction: start_xactor
00098 
00099 
00100 function void xvc_xactor::stop_xactor();
00101    super.stop_xactor();
00102 endfunction: stop_xactor
00103 
00104 
00105 function void xvc_xactor::reset_xactor(vmm_xactor::reset_e rst_typ = SOFT_RST);
00106    super.reset_xactor(rst_typ);
00107 
00108    this.action_chan.flush();
00109    this.interrupt_chan.flush();
00110    this.executing = null;
00111    this.interrupt = 0;
00112    this.interrupted = 0;
00113        
00114    if (rst_typ > vmm_xactor::HARD_RST) begin
00115 `ifdef VCS2006_06
00116       // Work-around for NYI feature in VCS2006.06
00117       // but IEEE 1800-2009 compliant
00118       this.known_actions.delete();
00119 `else
00120       // Works in VCS2008.03 or later
00121       // IEEE 1800-2005 compliant
00122       this.known_actions = '{};
00123 `endif
00124    end
00125 endfunction: reset_xactor
00126 
00127 
00128 function void xvc_xactor::xactor_status(string prefix = "");
00129    super.xactor_status(prefix);
00130 
00131    if (this.interrupt) begin
00132       // Pending interrupt
00133       if (this.interrupted) begin
00134          // Interrupted...
00135          if (this.executing == null) begin
00136             `vmm_error(this.log,
00137                        "Internal Error: interrupted but not executing");
00138          end else begin
00139             $display("   Executing interrupt action \"%s\".",
00140                      this.executing.get_name());
00141          end
00142       end else begin
00143          $display("   Waiting for action \"%s\" to be interrupted.",
00144                   this.executing.get_name());
00145       end
00146    end else begin
00147       if (this.executing == null) begin
00148          $display("   Waiting to execute an action...");
00149       end else begin
00150          $display("   Executing action \"%s\".",
00151                 this.executing.get_name());
00152       end
00153    end
00154 endfunction: xactor_status
00155 
00156 
00157 task xvc_xactor::main();
00158    fork
00159        super.main();
00160        this.execute_actions();
00161        this.execute_interruptions();
00162    join_none
00163 endtask: main
00164 
00165 
00166 task xvc_xactor::execute_actions();
00167    xvc_action action;
00168 
00169    while (1) begin
00170       // OK to be interrupted while not executing actions
00171       this.interrupted = 1;
00172       this.wait_if_stopped_or_empty(this.action_chan);
00173       this.action_chan.activate(action);
00174       this.interrupted = 0;
00175 
00176       this.executing = action;
00177       this.wait_if_interrupted();
00178 
00179       this.execute_action(this.action_chan, "action");
00180    end
00181 endtask: execute_actions
00182 
00183 
00184 task xvc_xactor::execute_interruptions();
00185    xvc_action action;
00186 
00187    while (1) begin
00188       this.wait_if_stopped_or_empty(this.interrupt_chan);
00189       this.interrupt_chan.activate(action);
00190 
00191       this.interrupt = 1;
00192       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) begin
00193          void'(this.log.text("Requesting action interrupt..."));
00194          this.log.end_msg();
00195       end
00196       wait (this.interrupted);
00197 
00198       if (this.suspended == null) this.suspended = idle;
00199       this.execute_action(this.interrupt_chan, "interrupt action");
00200       if (this.suspended == idle) this.suspended = null;
00201    
00202      if (this.interrupt_chan.level() == 0) begin
00203          this.interrupt = 0;
00204          -> this.rte;
00205       end
00206    end
00207 endtask: execute_interruptions          
00208 
00209 
00210 task xvc_xactor::wait_if_interrupted();
00211    if (this.suspended != null) begin
00212       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::WARNING_SEV)) begin
00213          void'(this.log.text("Interrupt actions cannot be interrupted. Ignoring call to xvc_xactor::wait_if_interrupted()"));
00214          this.log.end_msg();
00215       end
00216       return;
00217    end
00218 
00219    // Wait, not only for an interrupt action that is
00220    // requesting execution - but also if there is
00221    // one ready in the interrupt channel to resolve
00222    // race condition between the regular executor and
00223    // the interrupt executor.
00224    if (this.interrupt || this.interrupt_chan.level() > 0) begin
00225       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00226          void'(this.log.text(`vmm_sformatf("Interrupting action \"%s\"...",
00227                                            this.executing.get_name())));
00228          this.log.end_msg();
00229       end
00230       this.suspended = this.executing;
00231       this.executing = null;
00232       this.interrupted = 1;
00233 
00234       @this.rte;
00235       this.executing = this.suspended;
00236       this.suspended = null;
00237       this.interrupted = 0;
00238       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00239          void'(this.log.text(`vmm_sformatf("Resuming action \"%s\"...",
00240                                            this.executing.get_name())));
00241          this.log.end_msg();
00242       end
00243    end
00244 endtask: wait_if_interrupted
00245 
00246 
00247 task xvc_xactor::execute_action(xvc_action_channel chan,
00248                                 string             descr);
00249    xvc_action action;
00250    int i;
00251 
00252    action = chan.active_slot();
00253 
00254    if (this.trace.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00255       void'(this.trace.text(`vmm_sformatf("Executing %s \"%s\"...",
00256                                           descr, action.get_name())));
00257       this.trace.end_msg();
00258    end
00259 
00260    this.executing = action;
00261    this.executing.display({descr,": "});
00262    // Prepend any callback required by the action
00263    foreach (action.callbacks[i]) begin
00264       if (action.callbacks[i] != null) begin
00265          if (i >= this.xactors.size() || this.xactors[i] == null) begin
00266             `vmm_fatal(this.log,
00267                        `vmm_sformatf("No xvc_xactor::xactors[%0d] to register callback from action \"%s\".",
00268                                      i, action.get_name()));
00269             continue;
00270          end
00271          this.xactors[i].prepend_callback(action.callbacks[i]);
00272       end
00273    end
00274    
00275    void'(chan.start());
00276    action.execute(this.exec_chan, this);
00277    void'(chan.complete());
00278 
00279    // De-register callbacks
00280    foreach (action.callbacks[i]) begin
00281       if (action.callbacks[i] != null) begin
00282          if (i >= this.xactors.size() || this.xactors[i] == null) continue;
00283          this.xactors[i].unregister_callback(action.callbacks[i]);
00284       end
00285    end
00286    
00287    this.executing = null;
00288 
00289    if (this.trace.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00290       void'(this.trace.text(`vmm_sformatf("Completed %s \"%s\"...",
00291                                           descr, action.get_name())));
00292       this.trace.end_msg();
00293    end
00294    
00295    void'(chan.remove());
00296 endtask: execute_action
00297 
00298 
00299 function void xvc_xactor::save_rng_state();
00300 endfunction: save_rng_state
00301 
00302 
00303 function void xvc_xactor::restore_rng_state();
00304 endfunction: restore_rng_state