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 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 this.notify.configure(XACTOR_IDLE, vmm_notify::ON_OFF); 00036 this.notify.configure(XACTOR_BUSY, vmm_notify::ON_OFF); 00037 this.notify.configure(XACTOR_STARTED); 00038 this.notify.configure(XACTOR_STOPPING, vmm_notify::ON_OFF); 00039 this.notify.configure(XACTOR_STOPPED); 00040 this.notify.configure(XACTOR_RESET); 00041 00042 this.notify.indicate(XACTOR_IDLE); 00043 this.notify.reset(XACTOR_BUSY); 00044 00045 this.stream_id = stream_id; 00046 00047 this.start_it = 0; 00048 this.stop_it = 1; 00049 this.n_threads_to_stop = 0; 00050 this.n_threads_stopped = 0; 00051 this.reset_it = 0; 00052 this.resetable = 0; 00053 this.main_running = 0; 00054 00055 fork 00056 begin 00057 this.save_main_rng_state = 1; 00058 this.restore_main_rng_state = 0; 00059 this.main_rng_state = get_randstate(); 00060 00061 while (1) begin 00062 this.main_running = 0; 00063 00064 // wait to start 00065 while (!this.start_it) begin 00066 @ (this.start_it_event); 00067 // Reset has no effect since we are not started yet 00068 this.reset_it = 0; 00069 end 00070 this.start_it = 0; 00071 this.stop_it = 0; 00072 this.n_threads_to_stop = 0; 00073 this.n_threads_stopped = 0; 00074 00075 // We may be held back by on-going reset operation 00076 fork 00077 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00078 void'(this.log.text("Start delayed by on-going reset activity")); 00079 this.log.end_msg(); 00080 end 00081 join_none 00082 00083 while (this.reset_pending > 0) begin 00084 `vmm_fatal(this.log, "Pending resets not currently supported"); 00085 // `wait(@(this.reset_pending)); // Not supported yet. 00086 end 00087 disable fork; 00088 00089 // 00090 // Fork the main body 00091 // 00092 00093 if (this.save_main_rng_state) begin 00094 this.main_rng_state = get_randstate(); 00095 end 00096 if (this.restore_main_rng_state) begin 00097 set_randstate(main_rng_state); 00098 end 00099 this.save_main_rng_state = 0; 00100 this.restore_main_rng_state = 0; 00101 00102 fork 00103 begin 00104 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV )) begin 00105 void'(this.log.text("Started")); 00106 this.log.end_msg(); 00107 end 00108 00109 this.notify.reset(XACTOR_IDLE); 00110 this.notify.indicate(XACTOR_BUSY); 00111 this.notify.indicate(XACTOR_STARTED); 00112 main(); 00113 end 00114 00115 begin 00116 // Check that super.main() was called in all 00117 // extensions of this class 00118 #1; 00119 if (!this.main_running) begin 00120 `vmm_warning(this.log, "Virtual vmm_xactor::main() does not call super.main()"); 00121 end 00122 end 00123 join_none 00124 00125 // Wait to reset 00126 this.resetable = 1; 00127 do 00128 @ (this.reset_it_event); 00129 while (!this.reset_it); 00130 this.resetable = 0; 00131 this.reset_it = 0; 00132 this.stop_it = 1; 00133 this.n_threads_to_stop = 0; 00134 this.n_threads_stopped = 0; 00135 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00136 void'(this.log.text("Reset")); 00137 this.log.end_msg(); 00138 end 00139 this.notify.reset(XACTOR_BUSY); 00140 this.notify.indicate(XACTOR_IDLE); 00141 this.notify.reset(XACTOR_STOPPING); 00142 this.notify.indicate(XACTOR_STOPPED); 00143 this.notify.indicate(XACTOR_RESET); 00144 disable fork; 00145 // Pending start? 00146 if (this.start_it) begin 00147 ->this.start_it_event; 00148 end 00149 end 00150 end 00151 join_none 00152 endfunction: new 00153 00154 00155 function string vmm_xactor::get_name(); 00156 get_name = this.log.get_name(); 00157 endfunction:get_name 00158 00159 00160 function string vmm_xactor::get_instance(); 00161 get_instance = this.log.get_instance(); 00162 endfunction: get_instance 00163 00164 00165 function void vmm_xactor::start_xactor(); 00166 this.start_it = 1; 00167 -> this.start_it_event; 00168 this.notify.reset(XACTOR_STOPPING); 00169 endfunction: start_xactor 00170 00171 00172 function void vmm_xactor::stop_xactor(); 00173 this.stop_it = 1; 00174 this.start_it = 0; 00175 this.notify.indicate(XACTOR_STOPPING); 00176 00177 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00178 void'(this.log.text("Stop requested")); 00179 this.log.end_msg(); 00180 end 00181 endfunction: stop_xactor 00182 00183 00184 function void vmm_xactor::reset_xactor(reset_e rst_typ); 00185 this.reset_it = 1; 00186 -> this.reset_it_event; 00187 this.start_it = 0; 00188 00189 // Reset notifier & RNG state on FIRM and above 00190 if (rst_typ == FIRM_RST || 00191 rst_typ == HARD_RST) begin 00192 this.notify.reset(-1, vmm_notify::HARD); 00193 this.restore_rng_state(); 00194 end 00195 else begin 00196 this.notify.reset(-1, vmm_notify::SOFT); 00197 end 00198 00199 // Unregister all callbacks on HARD reset 00200 if (rst_typ == HARD_RST) begin 00201 `ifdef VCS2006_06 00202 // Work-around for NYI feature in VCS2006.06 00203 // *NOT* IEEE compliant :-( 00204 this.callbacks.delete(); 00205 `else 00206 // Works in VCS2008.03 00207 this.callbacks = '{}; 00208 `endif 00209 end 00210 endfunction: reset_xactor 00211 00212 00213 function void vmm_xactor::save_rng_state(); 00214 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00215 void'(this.log.text("Saving RNG state information...")); 00216 this.log.end_msg(); 00217 end 00218 00219 if (!this.stop_it) begin 00220 `vmm_warning(this.log, "save_rng_state() called while transactor is still running"); 00221 end 00222 this.save_main_rng_state = 1; 00223 endfunction: save_rng_state 00224 00225 00226 function void vmm_xactor::restore_rng_state(); 00227 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00228 void'(this.log.text("Restoring RNG state information...")); 00229 this.log.end_msg(); 00230 end 00231 00232 if (!this.stop_it) begin 00233 `vmm_warning(this.log, "restore_rng_state() called while transactor is still running"); 00234 end 00235 this.restore_main_rng_state = 1; 00236 endfunction: restore_rng_state 00237 00238 00239 function void vmm_xactor::xactor_status(string prefix); 00240 if (this.stop_it) begin 00241 if (this.n_threads_to_stop == 0) begin 00242 `vmm_note(this.log, {prefix, "Transactor is STOPPING (no threads stopped yet)"}); 00243 end 00244 else if (this.n_threads_to_stop < this.n_threads_stopped) begin 00245 `vmm_note(this.log, `vmm_sformatf("%sTransactor is STOPPING (%0d out of %0d threads stopped)", 00246 prefix, this.n_threads_stopped, 00247 this.n_threads_to_stop)); 00248 end 00249 else begin 00250 `vmm_note(this.log, {prefix, "Transactor is STOPPED"}); 00251 end 00252 end 00253 else `vmm_note(this.log, {prefix, "Transactor is RUNNING"}); 00254 endfunction: xactor_status 00255 00256 00257 task vmm_xactor::main(); 00258 this.main_running = 1; 00259 endtask: main 00260 00261 00262 task vmm_xactor::wait_if_stopped(int unsigned n_threads); 00263 if (n_threads == 0) begin 00264 if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 00265 void'(this.log.text("Number of threads to stop specified to vmm_xactor::wait_if_stopped() must be greater than 0")); 00266 this.log.end_msg(); 00267 end 00268 n_threads = 1; 00269 end 00270 00271 if (this.stop_it) begin 00272 if (this.n_threads_to_stop == 0) this.n_threads_to_stop = n_threads; 00273 else if (this.n_threads_to_stop != n_threads) begin 00274 if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 00275 void'(this.log.text("All threads must specify the same number of threads to stop to vmm_xactor::wait_if_stopped()")); 00276 this.log.end_msg(); 00277 end 00278 if (this.n_threads_to_stop < n_threads) this.n_threads_to_stop = n_threads; 00279 end 00280 00281 this.n_threads_stopped++; 00282 if (this.n_threads_stopped >= this.n_threads_to_stop) begin 00283 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00284 void'(this.log.text("Stopped")); 00285 this.log.end_msg(); 00286 end 00287 00288 this.notify.reset(XACTOR_BUSY); 00289 this.notify.indicate(XACTOR_IDLE); 00290 this.notify.reset(XACTOR_STOPPING); 00291 this.notify.indicate(XACTOR_STOPPED); 00292 end 00293 00294 @(this.start_it_event); 00295 this.start_it = 0; 00296 this.stop_it = 0; 00297 this.n_threads_stopped = 0; 00298 this.n_threads_to_stop = 0; 00299 00300 if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin 00301 void'(this.log.text("Started")); 00302 this.log.end_msg(); 00303 end 00304 this.notify.reset(XACTOR_IDLE); 00305 this.notify.indicate(XACTOR_BUSY); 00306 this.notify.indicate(XACTOR_STARTED); 00307 end 00308 endtask: wait_if_stopped 00309 00310 00311 task vmm_xactor::wait_if_stopped_or_empty(vmm_channel chan, 00312 int unsigned n_threads); 00313 this.wait_if_stopped(n_threads); 00314 while (chan.level() == 0) begin 00315 vmm_data data; 00316 00317 // Indicate IDLE because we are going to block on the channel 00318 this.notify.reset(XACTOR_BUSY); 00319 this.notify.indicate(XACTOR_IDLE); 00320 00321 chan.peek(data); 00322 this.wait_if_stopped(n_threads); 00323 end 00324 00325 this.notify.reset(XACTOR_IDLE); 00326 this.notify.indicate(XACTOR_BUSY); 00327 endtask: wait_if_stopped_or_empty 00328 00329 00330 function void vmm_xactor::prepend_callback(vmm_xactor_callbacks cb); 00331 if (cb == null) begin 00332 `vmm_error(this.log, "Attempting to prepend a NULL callback extension"); 00333 return; 00334 end 00335 00336 foreach(this.callbacks[i]) begin 00337 if (this.callbacks[i] == cb) begin 00338 `vmm_warning(this.log, "Callback has already been registered"); 00339 return; 00340 end 00341 end 00342 //Prepend new callback 00343 this.callbacks.push_front(cb); 00344 endfunction: prepend_callback 00345 00346 00347 function void vmm_xactor::append_callback(vmm_xactor_callbacks cb); 00348 if (cb == null) begin 00349 `vmm_error(this.log, "Attempting to append a NULL callback extension"); 00350 return; 00351 end 00352 00353 foreach(this.callbacks[i]) begin 00354 if (this.callbacks[i] == cb) begin 00355 `vmm_warning(this.log, "Callback has already been registered"); 00356 return; 00357 end 00358 end 00359 //Append new callback 00360 this.callbacks.push_back(cb); 00361 endfunction: append_callback 00362 00363 00364 function void vmm_xactor::unregister_callback(vmm_xactor_callbacks cb); 00365 foreach(this.callbacks[i]) begin 00366 if (this.callbacks[i] == cb) begin 00367 // Unregister it 00368 this.callbacks.delete(i); 00369 return; 00370 end 00371 end 00372 00373 `vmm_warning(this.log, "Callback was not registered"); 00374 endfunction: unregister_callback 00375 00376 00377 00378 00379 00380 `ifdef VMM_SB_DS_IN_STDLIB 00381 function void vmm_xactor::inp_vmm_sb_ds(vmm_data tr); 00382 foreach (this._vmm_sb_ds[i]) begin 00383 if (this._vmm_sb_ds[i].is_in) begin 00384 this._vmm_sb_ds[i].sb.insert(tr); 00385 end 00386 end 00387 endfunction: inp_vmm_sb_ds 00388 00389 00390 function void vmm_xactor::exp_vmm_sb_ds(vmm_data tr); 00391 foreach (this._vmm_sb_ds[i]) begin 00392 if (this._vmm_sb_ds[i].is_out) begin 00393 case (this._vmm_sb_ds[i].order) 00394 vmm_sb_ds::IN_ORDER: 00395 this._vmm_sb_ds[i].sb.expect_in_order(tr); 00396 00397 vmm_sb_ds::WITH_LOSSES: begin 00398 vmm_data p; 00399 vmm_data losses[]; 00400 this._vmm_sb_ds[i].sb.expect_with_losses(tr, p, losses); 00401 end 00402 00403 vmm_sb_ds::OUT_ORDER: 00404 this._vmm_sb_ds[i].sb.expect_out_of_order(tr); 00405 00406 endcase 00407 end 00408 end 00409 endfunction: exp_vmm_sb_ds 00410 00411 00412 function void vmm_xactor::register_vmm_sb_ds(vmm_sb_ds sb, 00413 vmm_sb_ds::kind_e kind, 00414 vmm_sb_ds::ordering_e order); 00415 vmm_sb_ds_registration ds; 00416 00417 foreach (this._vmm_sb_ds[i]) begin 00418 if (this._vmm_sb_ds[i].sb == sb) begin 00419 `vmm_warning(this.log, "Data stream scoreboard is already registered"); 00420 return; 00421 end 00422 end 00423 00424 ds = new; 00425 ds.sb = sb; 00426 ds.is_in = (kind == vmm_sb_ds::INPUT || 00427 kind == vmm_sb_ds::EITHER); 00428 ds.is_out = (kind == vmm_sb_ds::EXPECT || 00429 kind == vmm_sb_ds::EITHER); 00430 ds.order = order; 00431 this._vmm_sb_ds.push_back(ds); 00432 endfunction: register_vmm_sb_ds 00433 00434 00435 function void vmm_xactor::unregister_vmm_sb_ds(vmm_sb_ds sb); 00436 foreach (this._vmm_sb_ds[i]) begin 00437 if (this._vmm_sb_ds[i].sb == sb) begin 00438 this._vmm_sb_ds.delete(i); 00439 return; 00440 end 00441 end 00442 00443 `vmm_error(this.log, "Data stream scoreboard is not registered"); 00444 endfunction: unregister_vmm_sb_ds 00445 `endif