VMM - std_lib/vmm_xactor.sv

std_lib/vmm_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 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