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 function vmm_xactor::new(string name,
00024 string inst,
00025 int stream_id = -1
00026 `VMM_XACTOR_BASE_NEW_EXTERN_ARGS);
00027
00028
00029 `ifdef VMM_XACTOR_BASE_NEW_CALL
00030 super.new(`VMM_XACTOR_BASE_NEW_CALL);
00031 `endif
00032
00033 this.log = new(name, inst);
00034 this.notify = new(this.log);
00035 `VMM_OBJECT_SET_PARENT(this.notify, this)
00036
00037 void'(this.notify.configure(XACTOR_IDLE, vmm_notify::ON_OFF));
00038 void'(this.notify.configure(XACTOR_BUSY, vmm_notify::ON_OFF));
00039 void'(this.notify.configure(XACTOR_STARTED));
00040 void'(this.notify.configure(XACTOR_STOPPING, vmm_notify::ON_OFF));
00041 void'(this.notify.configure(XACTOR_IS_STOPPED, vmm_notify::ON_OFF));
00042 void'(this.notify.configure(XACTOR_STOPPED));
00043 void'(this.notify.configure(XACTOR_RESET));
00044
00045 this.is_stopped = 1;
00046 this.notify.indicate(XACTOR_IS_STOPPED);
00047 this.notify.indicate(XACTOR_IDLE);
00048 this.notify.reset(XACTOR_BUSY);
00049
00050 this.stream_id = stream_id;
00051
00052 this.start_it = 0;
00053 this.stop_it = 1;
00054 this.reset_it = 0;
00055 this.n_threads_to_stop = -1;
00056 this.n_threads_stopped = 0;
00057 this.main_running = 0;
00058
00059 this._vmm_available_xactor.push_back(this);
00060
00061 fork
00062 begin
00063 this.save_main_rng_state = 1;
00064 this.restore_main_rng_state = 0;
00065 this.main_rng_state = get_randstate();
00066
00067 while (1) begin
00068 this.main_running = 0;
00069
00070 // wait to start
00071 while (!this.start_it) @(this.control_event);
00072 this.start_it = 0;
00073 this.stop_it = 0;
00074 this.reset_it = 0;
00075 this.n_threads_to_stop = -1;
00076 this.n_threads_stopped = 0;
00077 this.is_stopped = 0;
00078
00079 // We may be held back by on-going reset operation
00080 fork
00081 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00082 void'(this.log.text("Start delayed by on-going reset activity"));
00083 this.log.end_msg();
00084 end
00085 join_none
00086
00087 while (this.reset_pending > 0) begin
00088 `vmm_fatal(this.log, "Pending resets not currently supported");
00089 // `wait(@(this.reset_pending)); // Not supported yet.
00090 end
00091 disable fork;
00092
00093 //
00094 // Fork the main body
00095 //
00096
00097 if (this.save_main_rng_state) begin
00098 this.main_rng_state = get_randstate();
00099 end
00100 if (this.restore_main_rng_state) begin
00101 set_randstate(main_rng_state);
00102 end
00103 this.save_main_rng_state = 0;
00104 this.restore_main_rng_state = 0;
00105
00106 fork
00107 begin
00108 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV )) begin
00109 void'(this.log.text("Started"));
00110 this.log.end_msg();
00111 end
00112
00113 this.is_stopped = 0;
00114 this.notify.reset(XACTOR_IDLE);
00115 this.notify.reset(XACTOR_IS_STOPPED);
00116 this.notify.indicate(XACTOR_BUSY);
00117 this.notify.indicate(XACTOR_STARTED);
00118 main();
00119 end
00120
00121 begin
00122 // Check that super.main() was called in all
00123 // extensions of this class
00124 #1;
00125 if (!this.main_running) begin
00126 `vmm_warning(this.log, "Virtual vmm_xactor::main() does not call super.main()");
00127 end
00128 end
00129 join_none
00130
00131 // Wait to reset
00132 while (!this.reset_it) @(this.control_event);
00133 this.reset_it = 0;
00134 this.n_threads_to_stop = -1;
00135 this.n_threads_stopped = 0;
00136 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00137 void'(this.log.text("Reset"));
00138 this.log.end_msg();
00139 end
00140 this.is_stopped = 1;
00141 this.notify.reset(XACTOR_BUSY);
00142 this.notify.indicate(XACTOR_IDLE);
00143 this.notify.reset(XACTOR_STOPPING);
00144 this.notify.indicate(XACTOR_IS_STOPPED);
00145 this.notify.indicate(XACTOR_STOPPED);
00146 this.notify.indicate(XACTOR_RESET);
00147 disable fork;
00148 end
00149 end
00150 join_none
00151 endfunction: new
00152
00153
00154 function string vmm_xactor::get_name();
00155 get_name = this.log.get_name();
00156 endfunction:get_name
00157
00158
00159 function string vmm_xactor::get_instance();
00160 get_instance = this.log.get_instance();
00161 endfunction: get_instance
00162
00163
00164 function void vmm_xactor::start_xactor();
00165 this.start_it = 1;
00166 this.stop_it = 0;
00167 -> this.control_event;
00168 this.notify.reset(XACTOR_STOPPING);
00169 endfunction: start_xactor
00170
00171
00172 function void vmm_xactor::stop_xactor();
00173 this.start_it = 0;
00174 this.stop_it = 1;
00175 -> this.control_event;
00176 this.notify.indicate(XACTOR_STOPPING);
00177
00178 // Is it already stopped?
00179 if (this.is_stopped) begin
00180 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00181 void'(this.log.text("Already stopped"));
00182 this.log.end_msg();
00183 end
00184 this.notify.indicate(XACTOR_STOPPED);
00185 return;
00186 end
00187
00188 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00189 void'(this.log.text("Stop requested"));
00190 this.log.end_msg();
00191 end
00192 this.check_all_threads_stopped();
00193 endfunction: stop_xactor
00194
00195
00196 function void vmm_xactor::reset_xactor(vmm_xactor::reset_e rst_typ = SOFT_RST);
00197 this.start_it = 0;
00198 this.reset_it = 1;
00199 -> this.control_event;
00200 this.is_stopped = 1;
00201
00202 // Reset notifier & RNG state on FIRM and above
00203 if (rst_typ == FIRM_RST ||
00204 rst_typ == HARD_RST) begin
00205 this.notify.reset(-1, vmm_notify::HARD);
00206 this.restore_rng_state();
00207 end
00208 else begin
00209 this.notify.reset(-1, vmm_notify::SOFT);
00210 end
00211
00212 // Unregister all callbacks on HARD reset
00213 if (rst_typ == HARD_RST) begin
00214 `ifdef VCS2006_06
00215 // Work-around for NYI feature in VCS2006.06
00216 // but IEEE 1800-2009 compliant
00217 this.callbacks.delete();
00218 `else
00219 // Works in VCS2008.03 or later
00220 // IEEE 1800-2005 compliant
00221 this.callbacks = '{};
00222 `endif
00223 end
00224 endfunction: reset_xactor
00225
00226
00227 function void vmm_xactor::save_rng_state();
00228 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00229 void'(this.log.text("Saving RNG state information..."));
00230 this.log.end_msg();
00231 end
00232
00233 if (!this.is_stopped) begin
00234 `vmm_warning(this.log, "save_rng_state() called while transactor is still running");
00235 end
00236 this.save_main_rng_state = 1;
00237 endfunction: save_rng_state
00238
00239
00240 function void vmm_xactor::restore_rng_state();
00241 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00242 void'(this.log.text("Restoring RNG state information..."));
00243 this.log.end_msg();
00244 end
00245
00246 if (!this.is_stopped) begin
00247 `vmm_warning(this.log, "restore_rng_state() called while transactor is still running");
00248 end
00249 this.restore_main_rng_state = 1;
00250 endfunction: restore_rng_state
00251
00252
00253 function string vmm_xactor::psdisplay(string prefix = "");
00254 $sformat(psdisplay, "%sTransactor %s (%s):", prefix,
00255 this.log.get_name(), this.log.get_instance());
00256
00257 if (this.is_stopped) begin
00258 return {psdisplay, "\n", prefix, "Transactor is STOPPED"};
00259 end
00260
00261 if (this.n_threads_stopped < this.n_threads_to_stop) begin
00262 return `vmm_sformatf("%s\n%sTransactor is STOPPING (%0d out of %0d threads stopped)",
00263 psdisplay, prefix, this.n_threads_stopped,
00264 this.n_threads_to_stop);
00265 end
00266
00267 return {psdisplay, "\n", prefix, "Transactor is RUNNING"};
00268 endfunction: psdisplay
00269
00270
00271 function void vmm_xactor::xactor_status(string prefix = "");
00272 `vmm_note(this.log, this.psdisplay(prefix));
00273 endfunction: xactor_status
00274
00275
00276 task vmm_xactor::main();
00277 this.main_running = 1;
00278 endtask: main
00279
00280
00281 function void vmm_xactor::check_all_threads_stopped();
00282 if (this.n_threads_to_stop > 0) begin
00283 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00284 void'(this.log.text($psprintf("%0d out of %0d threads have now stopped",n_threads_stopped,this.n_threads_to_stop)));
00285 this.log.end_msg();
00286 end
00287
00288 if (this.n_threads_stopped >= this.n_threads_to_stop) begin
00289 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00290 void'(this.log.text("Stopped"));
00291 this.log.end_msg();
00292 end
00293
00294 this.is_stopped = 1;
00295 this.notify.reset(XACTOR_BUSY);
00296 this.notify.indicate(XACTOR_IDLE);
00297 this.notify.reset(XACTOR_STOPPING);
00298 this.notify.indicate(XACTOR_IS_STOPPED);
00299 this.notify.indicate(XACTOR_STOPPED);
00300 end
00301 end
00302 endfunction
00303
00304
00305 task vmm_xactor::wait_if_stopped(int unsigned n_threads = 1);
00306 if (n_threads == 0) begin
00307 if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin
00308 void'(this.log.text("Number of threads to stop specified to vmm_xactor::wait_if_stopped() must be greater than 0"));
00309 this.log.end_msg();
00310 end
00311 n_threads = 1;
00312 end
00313
00314 if (this.n_threads_to_stop <= 0) this.n_threads_to_stop = n_threads;
00315 else if (this.n_threads_to_stop != n_threads) begin
00316 if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin
00317 void'(this.log.text("All threads must specify the same number of threads to stop to vmm_xactor::wait_if_stopped() and vmm_xactor::wait_if_stopped_or_empty()"));
00318 this.log.end_msg();
00319 end
00320 if (this.n_threads_to_stop < n_threads) this.n_threads_to_stop = n_threads;
00321 end
00322
00323 if (this.stop_it) begin
00324 this.n_threads_stopped++;
00325 this.check_all_threads_stopped();
00326
00327 while (this.stop_it) @(this.control_event);
00328 // Make sure these are done only once if
00329 // there are multiple stopped threads
00330 if (this.is_stopped) begin
00331 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00332 void'(this.log.text("Restarted"));
00333 this.log.end_msg();
00334 end
00335 this.is_stopped = 0;
00336 this.notify.indicate(XACTOR_STARTED);
00337 this.notify.reset(XACTOR_IS_STOPPED);
00338 this.notify.reset(XACTOR_IDLE);
00339 this.notify.indicate(XACTOR_BUSY);
00340 end
00341 this.n_threads_stopped--;
00342 end
00343 endtask: wait_if_stopped
00344
00345
00346 task vmm_xactor::wait_if_stopped_or_empty(vmm_channel chan,
00347 int unsigned n_threads = 1);
00348 this.wait_if_stopped(n_threads);
00349 while (chan.level() == 0) begin
00350 vmm_data data;
00351
00352 this.n_threads_stopped++;
00353 // If all other threads are blocked, indicate IDLE
00354 // because we are going to block on the channel
00355 if (this.n_threads_stopped >= this.n_threads_to_stop) begin
00356 this.notify.reset(XACTOR_BUSY);
00357 this.notify.indicate(XACTOR_IDLE);
00358 end
00359
00360 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00361 void'(this.log.text($psprintf("%0d threads have now stopped or blocked",n_threads_stopped)));
00362 this.log.end_msg();
00363 end
00364
00365 chan.peek(data);
00366 this.n_threads_stopped--;
00367 this.wait_if_stopped(n_threads);
00368 end
00369
00370 this.notify.reset(XACTOR_IDLE);
00371 this.notify.indicate(XACTOR_BUSY);
00372 endtask: wait_if_stopped_or_empty
00373
00374
00375 function void vmm_xactor::prepend_callback(vmm_xactor_callbacks cb);
00376 if (cb == null) begin
00377 `vmm_error(this.log, "Attempting to prepend a NULL callback extension");
00378 return;
00379 end
00380
00381 foreach(this.callbacks[i]) begin
00382 if (this.callbacks[i] == cb) begin
00383 `vmm_warning(this.log, "Callback has already been registered");
00384 return;
00385 end
00386 end
00387 //Prepend new callback
00388 this.callbacks.push_front(cb);
00389 endfunction: prepend_callback
00390
00391
00392 function void vmm_xactor::append_callback(vmm_xactor_callbacks cb);
00393 if (cb == null) begin
00394 `vmm_error(this.log, "Attempting to append a NULL callback extension");
00395 return;
00396 end
00397
00398 foreach(this.callbacks[i]) begin
00399 if (this.callbacks[i] == cb) begin
00400 `vmm_warning(this.log, "Callback has already been registered");
00401 return;
00402 end
00403 end
00404 //Append new callback
00405 this.callbacks.push_back(cb);
00406 endfunction: append_callback
00407
00408
00409 function void vmm_xactor::unregister_callback(vmm_xactor_callbacks cb);
00410 foreach(this.callbacks[i]) begin
00411 if (this.callbacks[i] == cb) begin
00412 // Unregister it
00413 this.callbacks.delete(i);
00414 return;
00415 end
00416 end
00417
00418 `vmm_warning(this.log, "Callback was not registered");
00419 endfunction: unregister_callback
00420
00421
00422 function void vmm_xactor::get_input_channels(ref vmm_channel chans[$]);
00423 chans = this.Xinput_chansX;
00424 endfunction: get_input_channels
00425
00426
00427 function void vmm_xactor::get_output_channels(ref vmm_channel chans[$]);
00428 chans = this.Xoutput_chansX;
00429 endfunction: get_output_channels
00430
00431
00432 function void vmm_xactor::kill();
00433 vmm_channel ins[$] = this.Xinput_chansX;
00434 vmm_channel outs[$] = this.Xoutput_chansX;
00435
00436 `ifdef VCS2006_06
00437 // Work-around for NYI feature in VCS2006.06
00438 // but IEEE 1800-2009 compliant
00439 this.Xinput_chansX.delete();
00440 this.Xoutput_chansX.delete();
00441 `else
00442 // Works in VCS2008.03 or later
00443 // IEEE 1800-2005 compliant
00444 this.Xinput_chansX = '{};
00445 this.Xoutput_chansX = '{};
00446 `endif
00447
00448 foreach(ins[i]) begin
00449 if (ins[i].get_consumer() == this) begin
00450 ins[i].set_consumer(null);
00451 if (ins[i].get_producer() == null) ins[i].kill();
00452 end
00453 end
00454
00455 foreach(outs[i]) begin
00456 if (outs[i].get_producer() == this) begin
00457 outs[i].set_producer(null);
00458 if (outs[i].get_consumer() == null) outs[i].kill();
00459 end
00460 end
00461
00462 foreach(this._vmm_available_xactor[i]) begin
00463 if (this._vmm_available_xactor[i] == this) begin
00464 this._vmm_available_xactor.delete(i);
00465 break;
00466 end
00467 end
00468
00469 this.log.kill();
00470 endfunction: kill
00471
00472
00473
00474
00475
00476 `ifdef VMM_SB_DS_IN_STDLIB
00477 function void vmm_xactor::inp_vmm_sb_ds(vmm_data tr);
00478 foreach (this._vmm_sb_ds[i]) begin
00479 if (this._vmm_sb_ds[i].is_in) begin
00480 this._vmm_sb_ds[i].sb.insert(tr);
00481 end
00482 end
00483 endfunction: inp_vmm_sb_ds
00484
00485
00486 function void vmm_xactor::exp_vmm_sb_ds(vmm_data tr);
00487 foreach (this._vmm_sb_ds[i]) begin
00488 if (this._vmm_sb_ds[i].is_out) begin
00489 case (this._vmm_sb_ds[i].order)
00490 vmm_sb_ds::IN_ORDER:
00491 this._vmm_sb_ds[i].sb.expect_in_order(tr);
00492
00493 vmm_sb_ds::WITH_LOSSES: begin
00494 vmm_data p;
00495 vmm_data losses[];
00496 this._vmm_sb_ds[i].sb.expect_with_losses(tr, p, losses);
00497 end
00498
00499 vmm_sb_ds::OUT_ORDER:
00500 this._vmm_sb_ds[i].sb.expect_out_of_order(tr);
00501
00502 endcase
00503 end
00504 end
00505 endfunction: exp_vmm_sb_ds
00506
00507
00508 function void vmm_xactor::register_vmm_sb_ds(vmm_sb_ds sb,
00509 vmm_sb_ds::kind_e kind,
00510 vmm_sb_ds::ordering_e order = vmm_sb_ds::IN_ORDER);
00511 vmm_sb_ds_registration ds;
00512
00513 foreach (this._vmm_sb_ds[i]) begin
00514 if (this._vmm_sb_ds[i].sb == sb) begin
00515 `vmm_warning(this.log, "Data stream scoreboard is already registered");
00516 return;
00517 end
00518 end
00519
00520 ds = new;
00521 ds.sb = sb;
00522 ds.is_in = (kind == vmm_sb_ds::INPUT ||
00523 kind == vmm_sb_ds::EITHER);
00524 ds.is_out = (kind == vmm_sb_ds::EXPECT ||
00525 kind == vmm_sb_ds::EITHER);
00526 ds.order = order;
00527 this._vmm_sb_ds.push_back(ds);
00528 endfunction: register_vmm_sb_ds
00529
00530
00531 function void vmm_xactor::unregister_vmm_sb_ds(vmm_sb_ds sb);
00532 foreach (this._vmm_sb_ds[i]) begin
00533 if (this._vmm_sb_ds[i].sb == sb) begin
00534 this._vmm_sb_ds.delete(i);
00535 return;
00536 end
00537 end
00538
00539 `vmm_error(this.log, "Data stream scoreboard is not registered");
00540 endfunction: unregister_vmm_sb_ds
00541 `endif
00542
00543
00544 function string vmm_xactor::do_psdisplay(string prefix = "");
00545 this.__vmm_done_user = 0;
00546 endfunction
00547
00548
00549 function void vmm_xactor::do_start_xactor();
00550 this.__vmm_done_user = 0;
00551 endfunction
00552
00553
00554 function void vmm_xactor::do_stop_xactor();
00555 this.__vmm_done_user = 0;
00556 endfunction
00557
00558
00559 function void vmm_xactor::do_reset_xactor(vmm_xactor::reset_e rst_typ);
00560 this.__vmm_done_user = 0;
00561 endfunction
00562
00563
00564 function void vmm_xactor::do_kill_xactor();
00565 this.__vmm_done_user = 0;
00566 endfunction
00567
00568
00569 function vmm_xactor_iter::new(string name = "",
00570 string inst = "");
00571 if (name == "") this.name = ".";
00572 else begin
00573 // Remove "/" surrounding the pattern, if any
00574 if (`vmm_str_match(name, "^/(.*)/$")) name = `vmm_str_backref(name, 0);
00575 this.name = name;
00576 end
00577
00578 if (inst == "") this.inst = ".";
00579 else begin
00580 // Remove "/" surrounding the pattern, if any
00581 if (`vmm_str_match(inst, "^/(.*)/$")) inst = `vmm_str_backref(inst, 0);
00582 this.inst = inst;
00583 end
00584
00585 void'(this.first());
00586 endfunction: new
00587
00588
00589 function void vmm_xactor_iter::move_iterator();
00590 string xa_name;
00591 string xa_inst;
00592 int n = _vmm_xactor._vmm_available_xactor.size();
00593
00594 if (this.idx >= n || n <= 1) return;
00595
00596 for (int x = this.idx+1; x < n; x++) begin
00597 xa_name = _vmm_xactor._vmm_available_xactor[x].log.get_name();
00598 xa_inst = _vmm_xactor._vmm_available_xactor[x].log.get_instance();
00599
00600 if (`vmm_str_match(xa_name, this.name) &&
00601 `vmm_str_match(xa_inst, this.inst)) begin
00602 this.idx = x;
00603 return;
00604 end
00605 end
00606 this.idx = 0;
00607 endfunction
00608
00609
00610 function vmm_xactor vmm_xactor_iter::xactor();
00611 if (this.idx <= 0 ||
00612 this.idx >= _vmm_xactor._vmm_available_xactor.size())
00613 return null;
00614
00615 return _vmm_xactor._vmm_available_xactor[this.idx];
00616 endfunction
00617
00618
00619 function vmm_xactor vmm_xactor_iter::first();
00620 this.idx = 0;
00621 this.move_iterator();
00622 return this.xactor();
00623 endfunction
00624
00625
00626 function vmm_xactor vmm_xactor_iter::next();
00627 this.move_iterator();
00628 return this.xactor();
00629 endfunction