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