VMM - std_lib/vmm_channel.sv

std_lib/vmm_channel.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 // ToDo: Fill level based on bytes
00024    
00025 function vmm_channel::new(string       name,
00026                           string       inst,
00027                           int unsigned full,
00028                           int unsigned empty,
00029                           bit          fill_as_bytes);
00030 `ifdef VMM_CHANNEL_BASE_NEW_CALL
00031    super.new(`VMM_CHANNEL_BASE_NEW_CALL);
00032 `endif
00033 
00034    if (this.one_log) begin
00035       if (this.shared_log == null) begin
00036          this.shared_log = new("VMM Channel", "[shared]");
00037       end
00038       this.log = shared_log;
00039    end else this.log = new(name, inst);
00040 
00041    this.notify = new(this.log);
00042    this.notify.configure(FULL,  vmm_notify::ON_OFF);
00043    this.notify.configure(EMPTY, vmm_notify::ON_OFF);
00044    this.notify.configure(PUT);
00045    this.notify.configure(GOT);
00046    this.notify.configure(PEEKED);
00047    this.notify.configure(ACTIVATED);
00048    this.notify.configure(ACT_STARTED);
00049    this.notify.configure(ACT_COMPLETED);
00050    this.notify.configure(ACT_REMOVED);
00051    this.notify.configure(LOCKED);
00052    this.notify.configure(UNLOCKED);
00053 
00054    if (full <= 0) full = 1;
00055    if (empty < 0 || empty > full) empty = full;
00056 
00057    this.full = full;
00058    this.empty = empty;
00059    this.is_sunk  = 0;
00060 
00061    this.active = null;
00062    this.active_status = INACTIVE;
00063    this.tee_on = 0;
00064    this.downstream = null;
00065    this.locks  = 2'b00;
00066 
00067    this.full_chan = 0;
00068    this.notify.indicate(EMPTY);
00069 
00070    this.iterator = 0;
00071 
00072    //
00073    // Thread to manage connection requests
00074    //
00075    fork: connection_requests
00076       while (1)
00077       begin : new_while_loop
00078          vmm_data data = null;
00079 
00080          // Broken connection?
00081          if (this.downstream != null)
00082          begin
00083             if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV))
00084             begin
00085                string txt;
00086                txt = {"Channel connection established: ",
00087                       this.log.get_name(),
00088                       "(", this.log.get_instance(), ") -> ",
00089                       this.downstream.log.get_name(),
00090                       "(", this.downstream.log.get_instance(), ")"};
00091        
00092                this.log.text(txt);
00093                this.log.end_msg();
00094             end // if debug level
00095      
00096             // Fork the data mover thread
00097             fork
00098                while (1)
00099                begin : inner_while_loop
00100                   // Simple blocking interface
00101                   data = null;
00102                   this.peek(data);
00103                   this.downstream.put(data);
00104                   this.get(data);
00105                end // inner_while_loop
00106             join_none
00107          end // if downstream != null
00108      
00109          // Wait for new connection requests
00110          @this.new_connection;
00111          
00112          // Stop the data mover thread
00113          disable fork;
00114         
00115          // Remove any datum that was forwarded
00116          // to the downstream channel but not removed
00117          // from this channel because of the blocking
00118          // model. Otherwise, the same datum will be
00119          // obtained from this channel twice.
00120          if (data != null) this.get(data);
00121      end // while (1)
00122    join_none // connection_requests
00123 endfunction : new
00124 
00125 
00126 function void vmm_channel::reconfigure(int   full,
00127                                        int   empty,
00128                                        logic fill_as_bytes);
00129    if (full < 0) full = this.full;
00130    if (full == 0) full = 1;
00131    if (empty < 0) empty = this.empty;
00132 
00133    if (full < empty)
00134    begin
00135       `vmm_error(this.log, "Cannot reconfigure channel with FULL < EMPTY");
00136       return;
00137    end
00138 
00139    this.full = full;
00140    this.empty = empty;
00141 
00142    if (this.level() >= this.full)
00143    begin 
00144       this.full_chan = 1;
00145       this.notify.indicate(FULL);
00146       this.notify.reset(EMPTY);
00147    end
00148    else if (this.level() <= this.empty)
00149    begin
00150       this.full_chan = 0;
00151       -> this.item_taken;
00152       this.notify.indicate(EMPTY);
00153       this.notify.reset(FULL);
00154    end
00155    else
00156    begin
00157       this.full_chan = 0;
00158       -> this.item_taken;
00159       this.notify.reset(EMPTY);
00160       this.notify.reset(FULL);
00161    end
00162 endfunction: reconfigure
00163 
00164 
00165 function int unsigned vmm_channel::full_level();
00166    full_level = this.full;
00167 endfunction: full_level
00168 
00169 
00170 function int unsigned vmm_channel::empty_level();
00171    empty_level = this.empty;
00172 endfunction: empty_level
00173 
00174 
00175 function int unsigned vmm_channel::level();
00176    level = this.data.size() + ((this.active == null) ? 0 : 1);
00177 endfunction: level
00178 
00179 
00180 function int unsigned vmm_channel::size();
00181    size = this.data.size() + ((this.active == null) ? 0 : 1);
00182 endfunction : size
00183 
00184 
00185 function bit vmm_channel::is_full();
00186    is_full = full_chan;
00187 endfunction : is_full
00188 
00189 
00190 function void vmm_channel::flush();
00191    vmm_data obj;
00192    if (this.downstream != null)
00193       this.downstream.flush();
00194 
00195 `ifdef VCS2006_06
00196    // Work-around required by VCS 2006.06
00197    // *NOT* IEEE compliant :-(
00198    this.data.delete();
00199    this.tee_data.delete();
00200 `else
00201    // This works in VCS 2008.03
00202    this.data = '{};
00203    this.tee_data = '{};
00204 `endif
00205    full_chan = 0;
00206    this.active = null;
00207    this.active_status = INACTIVE ;
00208    -> this.item_taken;
00209    this.notify.reset(FULL);
00210    this.notify.indicate(EMPTY);
00211 endfunction: flush
00212 
00213 
00214 function void vmm_channel::sink();
00215    this.flush();
00216    this.is_sunk = 1;
00217 endfunction: sink
00218 
00219 
00220 function void vmm_channel::flow();
00221    this.is_sunk = 0;
00222 endfunction: flow
00223 
00224 
00225 function void vmm_channel::reset();
00226    this.flush();
00227 endfunction: reset
00228 
00229 
00230 function void vmm_channel::lock(bit [1:0] who);
00231    this.locks |= who;
00232    this.notify.indicate(LOCKED);
00233 endfunction: lock
00234 
00235 
00236 function void vmm_channel::unlock(bit [1:0] who);
00237    this.locks &= ~who;
00238    this.notify.indicate(UNLOCKED);
00239    // May cause a consumer or producer to unblock
00240    -> this.item_taken;
00241    -> this.item_added;
00242 endfunction: unlock
00243 
00244 
00245 function bit vmm_channel::is_locked(bit [1:0] who);
00246    is_locked = (this.locks & who) ? 1 : 0;
00247 endfunction: is_locked
00248 
00249 
00250 function void vmm_channel::display(string prefix);
00251    $display(this.psdisplay(prefix));
00252 endfunction: display
00253 
00254 
00255 function string vmm_channel::psdisplay(string prefix);
00256    $sformat(psdisplay, "%sChannel %s(%s): Level = %0d of %0d (empty=%0d)",
00257             prefix, this.log.get_name(), this.log.get_instance(),
00258             this.level(), this.full, this.empty);
00259    case (this.locks) 
00260       SOURCE+SINK : psdisplay = {psdisplay, " [src+snk locked]"};
00261       SOURCE:       psdisplay = {psdisplay, " [src locked]"};
00262       SINK:         psdisplay = {psdisplay, " [snk locked]"};
00263    endcase
00264    if (this.is_sunk) psdisplay = {psdisplay, " (sunk)"};
00265 
00266    foreach(this.data[i]) begin
00267       $sformat(psdisplay, "%s\n%s", psdisplay, this.data[i].psdisplay(`vmm_sformatf("%s   [%0d] ",
00268                                                                                     prefix, i)));
00269    end
00270 endfunction: psdisplay
00271 
00272 
00273 `ifndef VMM_OV_INTEROP
00274 task vmm_channel::put(vmm_data obj,
00275                       int offset);
00276    if (obj == null)
00277    begin
00278       `vmm_error(this.log, "Attempted to put null instance into channel");
00279       return;
00280    end // if obj == null
00281 
00282    this.block_producer();
00283    this.sneak(obj, offset);
00284    this.block_producer();
00285 endtask: put
00286 `endif
00287 
00288 function void vmm_channel::sneak(vmm_data obj,
00289                                  int offset);
00290    string txt;
00291 
00292    if (obj == null)
00293    begin
00294       `vmm_error(this.log, "Attempted to sneak null instance into channel");
00295       return;
00296    end // obj == null
00297 
00298    if (this.is_sunk) return;
00299 
00300    if (offset == -1 || (offset == 0 && this.data.size() == 0))
00301    begin
00302       this.data.push_back(obj);
00303    end
00304    else
00305    begin
00306       int idx = this.index(offset);
00307       if (idx < 0) return;
00308 
00309       this.data.insert(offset, obj);
00310    end // if offset
00311 
00312    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00313    begin
00314      $sformat(txt, "New instance added to channel @%0d (level %0d of %0d/%0d)\n%s",
00315               offset, this.level(), this.full, this.empty,
00316               obj.psdisplay("    "));
00317       this.log.text(txt);
00318       this.log.end_msg();
00319    end // if dbg
00320 
00321    this.notify.indicate(PUT, obj);
00322 
00323    if (this.level() >= this.full)
00324    begin
00325       this.full_chan = 1;
00326       this.notify.indicate(FULL);
00327    end
00328 
00329    if (this.level() > this.empty)
00330    begin
00331       this.notify.reset(EMPTY);
00332    end
00333 
00334    -> this.item_added;
00335 endfunction: sneak
00336 
00337 
00338 function vmm_data vmm_channel::unput(int offset);
00339    if (this.size() == 0)
00340    begin
00341       `vmm_error(this.log, "Cannot unput from an empty channel");
00342       return null;
00343    end // if size == 0
00344 
00345    if (offset == -1)
00346    begin
00347      unput = this.data.pop_back();
00348    end
00349    else
00350    begin
00351      int idx = this.index(offset);
00352      if (idx < 0)
00353      begin
00354         unput = null;
00355      end
00356      else
00357      begin
00358         unput = this.data[idx];
00359         this.data.delete(idx);
00360      end
00361    end // if offset != -1
00362 
00363    if (unput != null) begin
00364       this.notify.indicate(GOT, unput);
00365       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00366       begin
00367          string txt;
00368          $sformat(txt, "Instance unput from channel @%0d (level %0d of %0d/%0d)\n%s", 
00369                   offset, this.level(), this.full, this.empty,
00370                   unput.psdisplay("    "));
00371          this.log.text(txt);
00372          this.log.end_msg();
00373       end // if dbg_lvl
00374    end
00375 
00376    this.unblock_producer();
00377 endfunction: unput
00378 
00379 
00380 task vmm_channel::get1(output vmm_data obj,
00381                        input  int      offset);
00382    if (offset == 0)
00383    begin
00384       obj = this.data.pop_front();
00385    end
00386    else
00387    begin
00388       int idx = this.index(offset);
00389       if (idx < 0)
00390       begin
00391          obj = null;
00392       end
00393       else 
00394       begin
00395          obj = this.data[idx];
00396          this.data.delete(idx);
00397       end // else if idx < 0
00398     end // else if offset
00399 
00400    if (obj != null)
00401    begin
00402       this.notify.indicate(GOT, obj);
00403       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00404       begin
00405          string txt;
00406          $sformat(txt, "New instance removed from channel @%0d (level %0d of %0d/%0d)\n%s", 
00407                   offset, this.level(), this.full, this.empty,
00408                   obj.psdisplay("    "));
00409          this.log.text(txt);
00410          this.log.end_msg();
00411       end // if dbg_lvl
00412 
00413       if (this.tee_on)
00414       begin
00415          this.tee_data.push_back(obj);
00416          -> this.teed;
00417       end // tee_on
00418 
00419 `ifdef VMM_SB_DS_IN_STDLIB
00420       foreach (this._vmm_sb_ds[i]) begin
00421          if (this._vmm_sb_ds[i].is_in) begin
00422             this._vmm_sb_ds[i].sb.insert(obj);
00423          end
00424 
00425          if (this._vmm_sb_ds[i].is_out) begin
00426             case (this._vmm_sb_ds[i].order)
00427               vmm_sb_ds::IN_ORDER:
00428                 this._vmm_sb_ds[i].sb.expect_in_order(obj);
00429 
00430               vmm_sb_ds::WITH_LOSSES: begin
00431                  vmm_data p;
00432                  vmm_data losses[];
00433                  this._vmm_sb_ds[i].sb.expect_with_losses(obj, p, losses);
00434               end
00435 
00436               vmm_sb_ds::OUT_ORDER:
00437                 this._vmm_sb_ds[i].sb.expect_out_of_order(obj);
00438 
00439             endcase
00440          end
00441       end
00442 `endif
00443    end // if obj != null
00444 endtask: get1
00445 
00446 
00447 task vmm_channel::get(output vmm_data obj,
00448                       input  int      offset);
00449    this.block_consumer();
00450    this.get1(obj, offset);
00451    this.unblock_producer();
00452 endtask: get
00453 
00454 task vmm_channel::peek(output vmm_data obj,
00455                        input  int      offset);
00456    string txt;
00457    int    idx;
00458 
00459    this.block_consumer();
00460 
00461    idx = this.index(offset);
00462    if (idx < 0)
00463    begin
00464       obj = null;
00465    end
00466    else
00467    begin
00468       obj = this.data[idx];
00469    end
00470 
00471    if (obj != null)
00472    begin
00473       this.notify.indicate(PEEKED, obj);
00474       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00475       begin
00476          $sformat(txt, "New instance peeked from channel @%0d (level %0d of %0d/%0d)\n%s",
00477                   offset, this.level(), this.full, this.empty,
00478                   obj.psdisplay("    "));
00479          this.log.text(txt);
00480          this.log.end_msg();
00481       end // if dbg_lvl
00482    end // obj != null
00483 
00484    this.unblock_producer();
00485 endtask: peek
00486 
00487 
00488 task vmm_channel::activate(output vmm_data obj,
00489                            input  int      offset);
00490    string txt;
00491 
00492    // Empty the active slot
00493    if (active != null) 
00494        this.remove();
00495  
00496    while (this.size() == 0) 
00497       @this.item_added;
00498 
00499    if (offset == 0)
00500    begin
00501       obj = this.data.pop_front();
00502    end
00503    else
00504    begin
00505       int idx = this.index(offset);
00506       if (idx < 0)
00507       begin
00508         obj = null;
00509       end
00510       else
00511       begin
00512         obj = this.data[idx];
00513         this.data.delete(idx);
00514       end
00515    end // else if offset == 0
00516 
00517 
00518    if (obj != null)
00519    begin
00520       this.active = obj;
00521       this.active_status = PENDING ;
00522       this.notify.indicate(ACTIVATED, obj);
00523       this.notify.indicate(PEEKED, obj);
00524 
00525       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00526       begin
00527          $sformat(txt, "New instance activated from channel @%0d (level %0d of %0d/%0d)\n%s",
00528                   offset, this.level(), this.full, this.empty,
00529                   obj.psdisplay("    "));
00530          this.log.text(txt);
00531          this.log.end_msg();
00532       end // if dbg_lvl
00533 
00534       if (this.tee_on)
00535       begin
00536          this.tee_data.push_back(obj);
00537          -> this.teed;
00538       end
00539    end // if obj != null
00540 endtask: activate
00541 
00542 
00543 function vmm_data vmm_channel::active_slot();
00544    active_slot = this.active;
00545 endfunction: active_slot
00546 
00547 
00548 function vmm_data vmm_channel::start();
00549    if (this.active == null)
00550    begin
00551       `vmm_fatal(this.log, "Cannot start() without prior activate()");
00552       return null;
00553    end // if active == null
00554 
00555    if (this.active_status == STARTED)
00556    begin
00557       `vmm_warning(this.log, "Active slot already start()'ed");
00558    end // if STARTED
00559 
00560    this.active_status = STARTED;
00561    this.notify.indicate(ACT_STARTED, this.active);
00562    this.active.notify.indicate(vmm_data::STARTED);
00563    start = this.active;
00564 endfunction: start
00565 
00566 
00567 function vmm_data vmm_channel::complete(vmm_data status);
00568    if (this.active == null)
00569    begin
00570       `vmm_fatal(this.log, "Cannot complete() without prior activate()");
00571       return null;
00572    end
00573    if (this.active_status != STARTED)
00574    begin
00575       `vmm_warning(this.log, "complete() called without start()");
00576    end
00577 
00578    this.active_status = COMPLETED;
00579    this.notify.indicate(ACT_COMPLETED, this.active);
00580    this.active.notify.indicate(vmm_data::ENDED, status);
00581    complete = this.active;
00582 endfunction: complete
00583 
00584 
00585 function vmm_data vmm_channel::remove();
00586    if (this.active == null)
00587    begin
00588       `vmm_fatal(this.log, "Cannot remove() without prior activate()");
00589       return null;
00590    end
00591 
00592    // OK to remove if not started or completed   
00593    if (this.active_status == STARTED)
00594    begin
00595       `vmm_warning(this.log, "remove() called without complete()");
00596    end
00597 
00598    this.notify.indicate(ACT_REMOVED, this.active);
00599    this.notify.indicate(GOT, this.active);
00600    if (this.active_status != COMPLETED)
00601    begin
00602       this.active.notify.indicate(vmm_data::ENDED);
00603    end
00604    this.active_status = INACTIVE;
00605    remove = this.active;
00606    this.active = null;
00607 
00608    this.unblock_producer();
00609 endfunction: remove
00610 
00611 
00612 function vmm_channel::active_status_e vmm_channel::status();
00613    status = this.active_status;
00614 endfunction: status
00615 
00616 
00617 function bit vmm_channel::tee_mode(bit is_on);
00618    string txt;
00619    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV))
00620    begin
00621       $sformat(txt, "tee branch turned %0s", (is_on) ? "ON" : "OFF");
00622       this.log.text(txt);
00623       this.log.end_msg();
00624    end
00625 
00626    tee_mode = this.tee_on;
00627    this.tee_on = is_on;
00628 endfunction: tee_mode
00629 
00630 
00631 task vmm_channel::tee(output vmm_data obj);
00632    string txt;
00633    while (this.tee_data.size() == 0) 
00634       @this.teed;
00635 
00636    obj = this.tee_data.pop_front();
00637 
00638    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00639    begin
00640       $sformat(txt, "New instance teed from channel (level %0d of %0d/%0d)\n%s",
00641                   this.level(), this.full, this.empty,
00642                   obj.psdisplay("    "));
00643       this.log.text(txt);
00644       this.log.end_msg();
00645    end
00646 endtask: tee
00647 
00648 
00649 function void vmm_channel::connect(vmm_channel downstream);
00650    // Do not disrupt an already-established connection
00651    if (this.downstream == downstream) return;
00652 
00653    // Indicate a new connection
00654    this.downstream = downstream;
00655    -> this.new_connection;
00656 endfunction: connect
00657 
00658 
00659 function vmm_data vmm_channel::for_each(bit reset);
00660    if (reset) this.iterator = 0;
00661    else this.iterator++;
00662 
00663    if (this.iterator >= this.data.size()) for_each = null;
00664    else for_each = this.data[this.iterator];
00665 endfunction: for_each
00666 
00667 
00668 function int unsigned vmm_channel::for_each_offset();
00669    for_each_offset = this.iterator;
00670 endfunction: for_each_offset
00671 
00672 
00673 function bit vmm_channel::record(string filename);
00674    if (filename == "")
00675    begin
00676       return 1;
00677    end
00678 
00679    `vmm_warning(this.log, "vmm_channel::record() not implemented yet");
00680    record = 0;
00681 endfunction: record
00682 
00683 
00684 task vmm_channel::playback(output bit      success,
00685                            input  string   filename,
00686                            input  vmm_data loader,
00687                            input  bit      metered);
00688    `vmm_fatal(this.log, "vmm_channel::playback() not implemented yet");
00689    success = 0;
00690 endtask: playback
00691 
00692 
00693 function int vmm_channel::index(int offset);
00694    string txt;
00695    index = offset;
00696    if (offset < 0) index += this.data.size() + offset + 1;
00697    if (index < 0 || index >= this.data.size())
00698    begin
00699       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV))
00700       begin
00701          $sformat(txt, "Invalid offset %0d specified. Not in {0:%0d}.\n",
00702                   offset, this.data.size()-1);
00703          this.log.text(txt);
00704          this.log.end_msg();
00705       end
00706       index = -1;
00707    end
00708 endfunction: index
00709 
00710 
00711 `ifndef VMM_OV_INTEROP
00712 task vmm_channel::block_producer();
00713    while (this.full_chan || this.is_locked(SOURCE)) 
00714       @this.item_taken;
00715 endtask : block_producer
00716 
00717 
00718 task vmm_channel::block_consumer();
00719    while (this.size() == 0 || this.is_locked(SINK)) 
00720       @this.item_added;
00721 endtask: block_consumer
00722 `endif
00723 
00724 
00725 function void vmm_channel::unblock_producer();
00726    if (this.level() <= this.empty)
00727    begin
00728       this.full_chan = 0;
00729       this.notify.indicate(EMPTY);
00730    end
00731 
00732    if (this.level() < this.full)
00733    begin
00734       this.notify.reset(FULL);
00735    end
00736 
00737    -> this.item_taken;
00738 endfunction: unblock_producer
00739 
00740 
00741 
00742 
00743 
00744 
00745 `ifdef VMM_SB_DS_IN_STDLIB
00746 function void vmm_channel::register_vmm_sb_ds(vmm_sb_ds             sb,
00747                                               vmm_sb_ds::kind_e     kind,
00748                                               vmm_sb_ds::ordering_e order);
00749    vmm_sb_ds_registration ds;
00750 
00751    foreach (this._vmm_sb_ds[i]) begin
00752       if (this._vmm_sb_ds[i].sb == sb) begin
00753          `vmm_warning(this.log, "Data stream scoreboard is already registered");
00754          return;
00755       end
00756    end
00757 
00758    ds = new;
00759    ds.sb = sb;
00760    ds.is_in = (kind == vmm_sb_ds::INPUT ||
00761                kind == vmm_sb_ds::EITHER);
00762    ds.is_out = (kind == vmm_sb_ds::EXPECT ||
00763                 kind == vmm_sb_ds::EITHER);
00764    ds.order = order;
00765    this._vmm_sb_ds.push_back(ds);
00766 endfunction: register_vmm_sb_ds
00767 
00768 
00769 function void vmm_channel::unregister_vmm_sb_ds(vmm_sb_ds sb);
00770    foreach (this._vmm_sb_ds[i]) begin
00771       if (this._vmm_sb_ds[i].sb == sb) begin
00772          this._vmm_sb_ds.delete(i);
00773          return;
00774       end
00775    end
00776 
00777    `vmm_error(this.log, "Data stream scoreboard is not registered");
00778 endfunction: unregister_vmm_sb_ds
00779 `endif
00780