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, 00027 xvc_action_channel action_chan, 00028 xvc_action_channel interrupt_chan 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); 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 // *NOT* IEEE compliant :-( 00118 this.known_actions.delete(); 00119 `else 00120 // Works in VCS2008.03 00121 this.known_actions = '{}; 00122 `endif 00123 end 00124 endfunction: reset_xactor 00125 00126 00127 function void xvc_xactor::xactor_status(string prefix); 00128 super.xactor_status(prefix); 00129 00130 if (this.interrupt) begin 00131 // Pending interrupt 00132 if (this.interrupted) begin 00133 // Interrupted... 00134 if (this.executing == null) begin 00135 `vmm_error(this.log, 00136 "Internal Error: interrupted but not executing"); 00137 end else begin 00138 $display(" Executing interrupt action \"%s\".", 00139 this.executing.get_name()); 00140 end 00141 end else begin 00142 $display(" Waiting for action \"%s\" to be interrupted.", 00143 this.executing.get_name()); 00144 end 00145 end else begin 00146 if (this.executing == null) begin 00147 $display(" Waiting to execute an action..."); 00148 end else begin 00149 $display(" Executing action \"%s\".", 00150 this.executing.get_name()); 00151 end 00152 end 00153 endfunction: xactor_status 00154 00155 00156 task xvc_xactor::main(); 00157 fork 00158 super.main(); 00159 this.execute_actions(); 00160 this.execute_interruptions(); 00161 join_none 00162 endtask: main 00163 00164 00165 task xvc_xactor::execute_actions(); 00166 xvc_action action; 00167 00168 while (1) begin 00169 // OK to be interrupted while not executing actions 00170 this.interrupted = 1; 00171 this.wait_if_stopped_or_empty(this.action_chan); 00172 this.action_chan.activate(action); 00173 this.interrupted = 0; 00174 00175 this.executing = action; 00176 this.wait_if_interrupted(); 00177 00178 this.execute_action(this.action_chan, "action"); 00179 end 00180 endtask: execute_actions 00181 00182 00183 task xvc_xactor::execute_interruptions(); 00184 xvc_action action; 00185 00186 while (1) begin 00187 this.wait_if_stopped_or_empty(this.interrupt_chan); 00188 this.interrupt_chan.activate(action); 00189 00190 this.interrupt = 1; 00191 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) begin 00192 void'(this.log.text("Requesting action interrupt...")); 00193 this.log.end_msg(); 00194 end 00195 wait (this.interrupted); 00196 00197 if (this.suspended == null) this.suspended = idle; 00198 this.execute_action(this.interrupt_chan, "interrupt action"); 00199 if (this.suspended == idle) this.suspended = null; 00200 00201 if (this.interrupt_chan.level() == 0) begin 00202 this.interrupt = 0; 00203 -> this.rte; 00204 end 00205 end 00206 endtask: execute_interruptions 00207 00208 00209 task xvc_xactor::wait_if_interrupted(); 00210 if (this.suspended != null) begin 00211 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::WARNING_SEV)) begin 00212 void'(this.log.text("Interrupt actions cannot be interrupted. Ignoring call to xvc_xactor::wait_if_interrupted()")); 00213 this.log.end_msg(); 00214 end 00215 return; 00216 end 00217 00218 // Wait, not only for an interrupt action that is 00219 // requesting execution - but also if there is 00220 // one ready in the interrupt channel to resolve 00221 // race condition between the regular executor and 00222 // the interrupt executor. 00223 if (this.interrupt || this.interrupt_chan.level() > 0) begin 00224 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00225 void'(this.log.text(`vmm_sformatf("Interrupting action \"%s\"...", 00226 this.executing.get_name()))); 00227 this.log.end_msg(); 00228 end 00229 this.suspended = this.executing; 00230 this.executing = null; 00231 this.interrupted = 1; 00232 00233 @this.rte; 00234 this.executing = this.suspended; 00235 this.suspended = null; 00236 this.interrupted = 0; 00237 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00238 void'(this.log.text(`vmm_sformatf("Resuming action \"%s\"...", 00239 this.executing.get_name()))); 00240 this.log.end_msg(); 00241 end 00242 end 00243 endtask: wait_if_interrupted 00244 00245 00246 task xvc_xactor::execute_action(xvc_action_channel chan, 00247 string descr); 00248 xvc_action action; 00249 int i; 00250 00251 action = chan.active_slot(); 00252 00253 if (this.trace.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00254 void'(this.trace.text(`vmm_sformatf("Executing %s \"%s\"...", 00255 descr, action.get_name()))); 00256 this.trace.end_msg(); 00257 end 00258 00259 this.executing = action; 00260 this.executing.display({descr,": "}); 00261 // Prepend any callback required by the action 00262 foreach (action.callbacks[i]) begin 00263 if (action.callbacks[i] != null) begin 00264 if (i >= this.xactors.size() || this.xactors[i] == null) begin 00265 `vmm_fatal(this.log, 00266 `vmm_sformatf("No xvc_xactor::xactors[%0d] to register callback from action \"%s\".", 00267 i, action.get_name())); 00268 continue; 00269 end 00270 this.xactors[i].prepend_callback(action.callbacks[i]); 00271 end 00272 end 00273 00274 chan.start(); 00275 action.execute(this.exec_chan, this); 00276 chan.complete(); 00277 00278 // De-register callbacks 00279 foreach (action.callbacks[i]) begin 00280 if (action.callbacks[i] != null) begin 00281 if (i >= this.xactors.size() || this.xactors[i] == null) continue; 00282 this.xactors[i].unregister_callback(action.callbacks[i]); 00283 end 00284 end 00285 00286 this.executing = null; 00287 00288 if (this.trace.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00289 void'(this.trace.text(`vmm_sformatf("Completed %s \"%s\"...", 00290 descr, action.get_name()))); 00291 this.trace.end_msg(); 00292 end 00293 00294 chan.remove(); 00295 endtask: execute_action 00296 00297 00298 function void xvc_xactor::save_rng_state(); 00299 endfunction: save_rng_state 00300 00301 00302 function void xvc_xactor::restore_rng_state(); 00303 endfunction: restore_rng_state