vmm_channel.sv

Go to the documentation of this file.
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    this.data.delete();
00196    this.tee_data.delete();
00197    full_chan = 0;
00198    this.active = null;
00199    this.active_status = INACTIVE ;
00200    -> this.item_taken;
00201    this.notify.reset(FULL);
00202    this.notify.indicate(EMPTY);
00203 endfunction: flush
00204 
00205 
00206 function void vmm_channel::sink();
00207    this.flush();
00208    this.is_sunk = 1;
00209 endfunction: sink
00210 
00211 
00212 function void vmm_channel::flow();
00213    this.is_sunk = 0;
00214 endfunction: flow
00215 
00216 
00217 function void vmm_channel::reset();
00218    this.flush();
00219 endfunction: reset
00220 
00221 
00222 function void vmm_channel::lock(bit [1:0] who);
00223    this.locks |= who;
00224    this.notify.indicate(LOCKED);
00225 endfunction: lock
00226 
00227 
00228 function void vmm_channel::unlock(bit [1:0] who);
00229    this.locks &= ~who;
00230    this.notify.indicate(UNLOCKED);
00231    // May cause a consumer or producer to unblock
00232    -> this.item_taken;
00233    -> this.item_added;
00234 endfunction: unlock
00235 
00236 
00237 function bit vmm_channel::is_locked(bit [1:0] who);
00238    is_locked = (this.locks & who) ? 1 : 0;
00239 endfunction: is_locked
00240 
00241 
00242 function void vmm_channel::display(string prefix);
00243    $display(this.psdisplay(prefix));
00244 endfunction: display
00245 
00246 
00247 function string vmm_channel::psdisplay(string prefix);
00248    $sformat(psdisplay, "%sChannel %s(%s): Level = %0d of %0d (empty=%0d)",
00249             prefix, this.log.get_name(), this.log.get_instance(),
00250             this.level(), this.full, this.empty);
00251    case (this.locks) 
00252       SOURCE+SINK : psdisplay = {psdisplay, " [src+snk locked]"};
00253       SOURCE:       psdisplay = {psdisplay, " [src locked]"};
00254       SINK:         psdisplay = {psdisplay, " [snk locked]"};
00255    endcase
00256    if (this.is_sunk) psdisplay = {psdisplay, " (sunk)"};
00257 
00258    foreach(this.data[i]) begin
00259       $sformat(psdisplay, "%s\n%s", psdisplay, this.data[i].psdisplay(`vmm_sformatf("%s   [%0d] ",
00260                                                                                     prefix, i)));
00261    end
00262 endfunction: psdisplay
00263 
00264 
00265 `ifndef VMM_OV_INTEROP
00266 task vmm_channel::put(vmm_data obj,
00267                       int offset);
00268    if (obj == null)
00269    begin
00270       `vmm_error(this.log, "Attempted to put null instance into channel");
00271       return;
00272    end // if obj == null
00273 
00274    this.block_producer();
00275    this.sneak(obj, offset);
00276    this.block_producer();
00277 endtask: put
00278 `endif
00279 
00280 function void vmm_channel::sneak(vmm_data obj,
00281                                  int offset);
00282    string txt;
00283 
00284    if (obj == null)
00285    begin
00286       `vmm_error(this.log, "Attempted to sneak null instance into channel");
00287       return;
00288    end // obj == null
00289 
00290    if (this.is_sunk) return;
00291 
00292    if (offset == -1 || (offset == 0 && this.data.size() == 0))
00293    begin
00294       this.data.push_back(obj);
00295    end
00296    else
00297    begin
00298       int idx = this.index(offset);
00299       if (idx < 0) return;
00300 
00301       this.data.insert(offset, obj);
00302    end // if offset
00303 
00304    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00305    begin
00306      $sformat(txt, "New instance added to channel @%0d (level %0d of %0d/%0d)\n%s",
00307               offset, this.level(), this.full, this.empty,
00308               obj.psdisplay("    "));
00309       this.log.text(txt);
00310       this.log.end_msg();
00311    end // if dbg
00312 
00313    this.notify.indicate(PUT, obj);
00314 
00315    if (this.level() >= this.full)
00316    begin
00317       this.full_chan = 1;
00318       this.notify.indicate(FULL);
00319    end
00320 
00321    if (this.level() > this.empty)
00322    begin
00323       this.notify.reset(EMPTY);
00324    end
00325 
00326    -> this.item_added;
00327 endfunction: sneak
00328 
00329 
00330 function vmm_data vmm_channel::unput(int offset);
00331    if (this.size() == 0)
00332    begin
00333       `vmm_error(this.log, "Cannot unput from an empty channel");
00334       return null;
00335    end // if size == 0
00336 
00337    if (offset == -1)
00338    begin
00339      unput = this.data.pop_back();
00340    end
00341    else
00342    begin
00343      int idx = this.index(offset);
00344      if (idx < 0)
00345      begin
00346         unput = null;
00347      end
00348      else
00349      begin
00350         unput = this.data[idx];
00351         this.data.delete(idx);
00352      end
00353    end // if offset != -1
00354 
00355    if (unput != null) begin
00356       this.notify.indicate(GOT, unput);
00357       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00358       begin
00359          string txt;
00360          $sformat(txt, "Instance unput from channel @%0d (level %0d of %0d/%0d)\n%s", 
00361                   offset, this.level(), this.full, this.empty,
00362                   unput.psdisplay("    "));
00363          this.log.text(txt);
00364          this.log.end_msg();
00365       end // if dbg_lvl
00366    end
00367 
00368    this.unblock_producer();
00369 endfunction: unput
00370 
00371 
00372 task vmm_channel::get1(output vmm_data obj,
00373                        input  int      offset);
00374    if (offset == 0)
00375    begin
00376       obj = this.data.pop_front();
00377    end
00378    else
00379    begin
00380       int idx = this.index(offset);
00381       if (idx < 0)
00382       begin
00383          obj = null;
00384       end
00385       else 
00386       begin
00387          obj = this.data[idx];
00388          this.data.delete(idx);
00389       end // else if idx < 0
00390     end // else if offset
00391 
00392    if (obj != null)
00393    begin
00394       this.notify.indicate(GOT, obj);
00395       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00396       begin
00397          string txt;
00398          $sformat(txt, "New instance removed from channel @%0d (level %0d of %0d/%0d)\n%s", 
00399                   offset, this.level(), this.full, this.empty,
00400                   obj.psdisplay("    "));
00401          this.log.text(txt);
00402          this.log.end_msg();
00403       end // if dbg_lvl
00404 
00405       if (this.tee_on)
00406       begin
00407          this.tee_data.push_back(obj);
00408          -> this.teed;
00409       end // tee_on
00410 
00411 `ifdef VCS
00412 `ifdef VMM_SB_DS_IN_STDLIB
00413       foreach (this._vmm_sb_ds[i]) begin
00414          if (this._vmm_sb_ds[i].is_in) begin
00415             this._vmm_sb_ds[i].sb.insert(obj);
00416          end
00417 
00418          if (this._vmm_sb_ds[i].is_out) begin
00419             case (this._vmm_sb_ds[i].order)
00420               vmm_sb_ds::IN_ORDER:
00421                 this._vmm_sb_ds[i].sb.expect_in_order(obj);
00422 
00423               vmm_sb_ds::WITH_LOSSES: begin
00424                  vmm_data p;
00425                  vmm_data losses[];
00426                  this._vmm_sb_ds[i].sb.expect_with_losses(obj, p, losses);
00427               end
00428 
00429               vmm_sb_ds::OUT_ORDER:
00430                 this._vmm_sb_ds[i].sb.expect_out_of_order(obj);
00431 
00432             endcase
00433          end
00434       end
00435 `endif
00436 `endif
00437    end // if obj != null
00438 endtask: get1
00439 
00440 
00441 task vmm_channel::get(output vmm_data obj,
00442                       input  int      offset);
00443    this.block_consumer();
00444    this.get1(obj, offset);
00445    this.unblock_producer();
00446 endtask: get
00447 
00448 task vmm_channel::peek(output vmm_data obj,
00449                        input  int      offset);
00450    string txt;
00451    int    idx;
00452 
00453    this.block_consumer();
00454 
00455    idx = this.index(offset);
00456    if (idx < 0)
00457    begin
00458       obj = null;
00459    end
00460    else
00461    begin
00462       obj = this.data[idx];
00463    end
00464 
00465    if (obj != null)
00466    begin
00467       this.notify.indicate(PEEKED, obj);
00468       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00469       begin
00470          $sformat(txt, "New instance peeked from channel @%0d (level %0d of %0d/%0d)\n%s",
00471                   offset, this.level(), this.full, this.empty,
00472                   obj.psdisplay("    "));
00473          this.log.text(txt);
00474          this.log.end_msg();
00475       end // if dbg_lvl
00476    end // obj != null
00477 
00478    this.unblock_producer();
00479 endtask: peek
00480 
00481 
00482 task vmm_channel::activate(output vmm_data obj,
00483                            input  int      offset);
00484    string txt;
00485 
00486    // Empty the active slot
00487    if (active != null) 
00488        this.remove();
00489  
00490    while (this.size() == 0) 
00491       @this.item_added;
00492 
00493    if (offset == 0)
00494    begin
00495       obj = this.data.pop_front();
00496    end
00497    else
00498    begin
00499       int idx = this.index(offset);
00500       if (idx < 0)
00501       begin
00502         obj = null;
00503       end
00504       else
00505       begin
00506         obj = this.data[idx];
00507         this.data.delete(idx);
00508       end
00509    end // else if offset == 0
00510 
00511 
00512    if (obj != null)
00513    begin
00514       this.active = obj;
00515       this.active_status = PENDING ;
00516       this.notify.indicate(ACTIVATED, obj);
00517       this.notify.indicate(PEEKED, obj);
00518 
00519       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00520       begin
00521          $sformat(txt, "New instance activated from channel @%0d (level %0d of %0d/%0d)\n%s",
00522                   offset, this.level(), this.full, this.empty,
00523                   obj.psdisplay("    "));
00524          this.log.text(txt);
00525          this.log.end_msg();
00526       end // if dbg_lvl
00527 
00528       if (this.tee_on)
00529       begin
00530          this.tee_data.push_back(obj);
00531          -> this.teed;
00532       end
00533    end // if obj != null
00534 endtask: activate
00535 
00536 
00537 function vmm_data vmm_channel::active_slot();
00538    active_slot = this.active;
00539 endfunction: active_slot
00540 
00541 
00542 function vmm_data vmm_channel::start();
00543    if (this.active == null)
00544    begin
00545       `vmm_fatal(this.log, "Cannot start() without prior activate()");
00546       return null;
00547    end // if active == null
00548 
00549    if (this.active_status == STARTED)
00550    begin
00551       `vmm_warning(this.log, "Active slot already start()'ed");
00552    end // if STARTED
00553 
00554    this.active_status = STARTED;
00555    this.notify.indicate(ACT_STARTED, this.active);
00556    this.active.notify.indicate(vmm_data::STARTED);
00557    start = this.active;
00558 endfunction: start
00559 
00560 
00561 function vmm_data vmm_channel::complete(vmm_data status);
00562    if (this.active == null)
00563    begin
00564       `vmm_fatal(this.log, "Cannot complete() without prior activate()");
00565       return null;
00566    end
00567    if (this.active_status != STARTED)
00568    begin
00569       `vmm_warning(this.log, "complete() called without start()");
00570    end
00571 
00572    this.active_status = COMPLETED;
00573    this.notify.indicate(ACT_COMPLETED, this.active);
00574    this.active.notify.indicate(vmm_data::ENDED, status);
00575    complete = this.active;
00576 endfunction: complete
00577 
00578 
00579 function vmm_data vmm_channel::remove();
00580    if (this.active == null)
00581    begin
00582       `vmm_fatal(this.log, "Cannot remove() without prior activate()");
00583       return null;
00584    end
00585 
00586    // OK to remove if not started or completed   
00587    if (this.active_status == STARTED)
00588    begin
00589       `vmm_warning(this.log, "remove() called without complete()");
00590    end
00591 
00592    this.notify.indicate(ACT_REMOVED, this.active);
00593    this.notify.indicate(GOT, this.active);
00594    if (this.active_status != COMPLETED)
00595    begin
00596       this.active.notify.indicate(vmm_data::ENDED);
00597    end
00598    this.active_status = INACTIVE;
00599    remove = this.active;
00600    this.active = null;
00601 
00602    this.unblock_producer();
00603 endfunction: remove
00604 
00605 
00606 function vmm_channel::active_status_e vmm_channel::status();
00607    status = this.active_status;
00608 endfunction: status
00609 
00610 
00611 function bit vmm_channel::tee_mode(bit is_on);
00612    string txt;
00613    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV))
00614    begin
00615       $sformat(txt, "tee branch turned %0s", (is_on) ? "ON" : "OFF");
00616       this.log.text(txt);
00617       this.log.end_msg();
00618    end
00619 
00620    tee_mode = this.tee_on;
00621    this.tee_on = is_on;
00622 endfunction: tee_mode
00623 
00624 
00625 task vmm_channel::tee(output vmm_data obj);
00626    string txt;
00627    while (this.tee_data.size() == 0) 
00628       @this.teed;
00629 
00630    obj = this.tee_data.pop_front();
00631 
00632    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00633    begin
00634       $sformat(txt, "New instance teed from channel (level %0d of %0d/%0d)\n%s",
00635                   this.level(), this.full, this.empty,
00636                   obj.psdisplay("    "));
00637       this.log.text(txt);
00638       this.log.end_msg();
00639    end
00640 endtask: tee
00641 
00642 
00643 function void vmm_channel::connect(vmm_channel downstream);
00644    // Do not disrupt an already-established connection
00645    if (this.downstream == downstream) return;
00646 
00647    // Indicate a new connection
00648    this.downstream = downstream;
00649    -> this.new_connection;
00650 endfunction: connect
00651 
00652 
00653 function vmm_data vmm_channel::for_each(bit reset);
00654    if (reset) this.iterator = 0;
00655    else this.iterator++;
00656 
00657    if (this.iterator >= this.data.size()) for_each = null;
00658    else for_each = this.data[this.iterator];
00659 endfunction: for_each
00660 
00661 
00662 function int unsigned vmm_channel::for_each_offset();
00663    for_each_offset = this.iterator;
00664 endfunction: for_each_offset
00665 
00666 
00667 function bit vmm_channel::record(string filename);
00668    if (filename == "")
00669    begin
00670       return 1;
00671    end
00672 
00673    `vmm_warning(this.log, "vmm_channel::record() not implemented yet");
00674    record = 0;
00675 endfunction: record
00676 
00677 
00678 task vmm_channel::playback(output bit      success,
00679                            input  string   filename,
00680                            input  vmm_data loader,
00681                            input  bit      metered);
00682    `vmm_fatal(this.log, "vmm_channel::playback() not implemented yet");
00683    success = 0;
00684 endtask: playback
00685 
00686 
00687 function int vmm_channel::index(int offset);
00688    string txt;
00689    index = offset;
00690    if (offset < 0) index += this.data.size() + offset + 1;
00691    if (index < 0 || index >= this.data.size())
00692    begin
00693       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV))
00694       begin
00695          $sformat(txt, "Invalid offset %0d specified. Not in {0:%0d}.\n",
00696                   offset, this.data.size()-1);
00697          this.log.text(txt);
00698          this.log.end_msg();
00699       end
00700       index = -1;
00701    end
00702 endfunction: index
00703 
00704 
00705 `ifndef VMM_OV_INTEROP
00706 task vmm_channel::block_producer();
00707    while (this.full_chan || this.is_locked(SOURCE)) 
00708       @this.item_taken;
00709 endtask : block_producer
00710 
00711 
00712 task vmm_channel::block_consumer();
00713    while (this.size() == 0 || this.is_locked(SINK)) 
00714       @this.item_added;
00715 endtask: block_consumer
00716 `endif
00717 
00718 
00719 task vmm_channel::unblock_producer();
00720    if (this.level() <= this.empty)
00721    begin
00722       this.full_chan = 0;
00723       this.notify.indicate(EMPTY);
00724    end
00725 
00726    if (this.level() < this.full)
00727    begin
00728       this.notify.reset(FULL);
00729    end
00730 
00731    -> this.item_taken;
00732 endtask: unblock_producer
00733 
00734 
00735 
00736 
00737 
00738 `ifdef VCS
00739 `ifdef VMM_SB_DS_IN_STDLIB
00740 function void vmm_channel::register_vmm_sb_ds(vmm_sb_ds             sb,
00741                                               vmm_sb_ds::kind_e     kind,
00742                                               vmm_sb_ds::ordering_e order);
00743    vmm_sb_ds_registration ds;
00744 
00745    foreach (this._vmm_sb_ds[i]) begin
00746       if (this._vmm_sb_ds[i].sb == sb) begin
00747          `vmm_warning(this.log, "Data stream scoreboard is already registered");
00748          return;
00749       end
00750    end
00751 
00752    ds = new;
00753    ds.sb = sb;
00754    ds.is_in = (kind == vmm_sb_ds::INPUT ||
00755                kind == vmm_sb_ds::EITHER);
00756    ds.is_out = (kind == vmm_sb_ds::EXPECT ||
00757                 kind == vmm_sb_ds::EITHER);
00758    ds.order = order;
00759    this._vmm_sb_ds.push_back(ds);
00760 endfunction: register_vmm_sb_ds
00761 
00762 
00763 function void vmm_channel::unregister_vmm_sb_ds(vmm_sb_ds sb);
00764    foreach (this._vmm_sb_ds[i]) begin
00765       if (this._vmm_sb_ds[i].sb == sb) begin
00766          this._vmm_sb_ds.delete(i);
00767          return;
00768       end
00769    end
00770 
00771    `vmm_error(this.log, "Data stream scoreboard is not registered");
00772 endfunction: unregister_vmm_sb_ds
00773 `endif
00774 
00775 `endif
00776 

Intelligent Design Verification
Intelligent Design Verification
Project: VMM, Revision: 1.0.0
Copyright (c) 2008 Intelligent Design Verification.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included here:
http://www.intelligentdv.com/licenses/fdl.txt
doxygen
Doxygen Version: 1.5.6
Sat Oct 18 11:38:21 2008
Find a documentation bug? Report bugs to: bugs.intelligentdv.com Project: DoxygenFilterSV