VMM - std_lib/vmm_log.sv

std_lib/vmm_log.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 `ifdef VCS
00024 (* vmm_private_class, _vcs_vmm_class = 1 *)
00025 `endif
00026 class vmm_log_modifier;
00027    int       typ;
00028    int       severity;
00029    string    pattern;
00030    int       new_typ;
00031    int       new_severity;
00032    int       handling;
00033 
00034    static local vmm_log log;
00035 
00036    function new();
00037       // Initialize all static properties
00038       if (log == null) this.log = new("vmm_log_modifier", "class");
00039    endfunction: new
00040    
00041    extern function string psdisplay(string prefix = "");
00042 endclass: vmm_log_modifier
00043      
00044 
00045 typedef class vmm_log_msg;
00046 
00047 `ifdef VCS
00048 (* vmm_private_class, _vcs_vmm_class = 1 *)
00049 `endif
00050 class vmm_log_watchpoint;
00051    int       typ;
00052    int       severity;
00053    string    pattern;
00054    logic     issued;
00055 
00056    event       seen;
00057    vmm_log_msg msg;
00058 
00059    static local vmm_log log;
00060    
00061    function new();
00062       // Initialize all static properties
00063       if (log == null) this.log = new("vmm_log_watchpoint", "class");
00064    endfunction: new
00065 
00066    extern function void   display(string prefix = "");
00067    extern function string psdisplay(string prefix = "");
00068 endclass:vmm_log_watchpoint
00069 
00070 
00071 `ifdef VCS
00072 (* vmm_private_class, _vcs_vmm_class = 1 *)
00073 `endif
00074 class vmm_log_msg;
00075    vmm_log    log;
00076 
00077    bit        invalid;   
00078    time       timestamp;
00079    int        original_typ;
00080    int        original_severity;
00081    int        effective_typ;
00082    int        effective_severity;
00083    string     text[$];
00084    logic      issued;
00085    int        handling;
00086 
00087    /*local*/ int flushed;
00088 
00089    function new(vmm_log log);
00090       this.log     = log;
00091       this.invalid = 1;
00092    endfunction: new
00093 
00094    extern function void   display(string prefix = "");
00095    extern function string psdisplay(string prefix = "");
00096    extern function vmm_log_msg copy();
00097 endclass: vmm_log_msg
00098 
00099 
00100    //
00101    // vmm_log_modifier
00102    //
00103 
00104 function string vmm_log_modifier::psdisplay(string prefix);
00105    $sformat(psdisplay, "%s%s [%s] with \"%s\" -> %s [%s] then %s",
00106           prefix, this.log.typ_image(this.typ),
00107           this.log.sev_image(this.severity),
00108           (this.pattern == "") ? "/./" : this.pattern,
00109           this.log.typ_image(this.new_typ),
00110           this.log.sev_image(this.new_severity),
00111           this.log.handling_image(this.handling));
00112 endfunction: psdisplay
00113 
00114 
00115   //
00116   // vmm_log_watchpoint
00117   //
00118 
00119 function void vmm_log_watchpoint::display(string prefix);
00120    $write("%s\n", this.psdisplay(prefix));
00121 endfunction: display
00122    
00123 function string vmm_log_watchpoint::psdisplay(string prefix);
00124    $sformat(psdisplay, "%s%s [%s] with \"%s\"%s",
00125             prefix, this.log.typ_image(this.typ),
00126             this.log.sev_image(this.severity),
00127             (this.pattern == "") ? "/./" : this.pattern,
00128             (this.issued === 1'bx) ? "" : (this.issued) ? "if issued" : "if not issued");
00129 endfunction: psdisplay
00130 
00131 
00132   //
00133   // vmm_log_msg
00134   //
00135   
00136 function void   vmm_log_msg::display(string prefix);
00137    $write("%s\n", this.psdisplay(prefix));
00138 endfunction: display
00139 
00140 function string vmm_log_msg::psdisplay(string prefix);
00141    $sformat(psdisplay, "%s%s [%s] at %0t", prefix,
00142             this.log.typ_image(this.effective_typ),
00143             this.log.sev_image(this.effective_severity),
00144             this.timestamp);
00145    foreach(this.text[i]) begin
00146       $sformat(psdisplay, "%s\n%s    %s", psdisplay, prefix,
00147                this.text[i]);
00148    end
00149 endfunction: psdisplay
00150 
00151 function vmm_log_msg vmm_log_msg::copy();
00152    copy = new(this.log);
00153 
00154    copy.timestamp          = this.timestamp;
00155    copy.original_typ       = this.original_typ;
00156    copy.original_severity  = this.original_severity;
00157    copy.effective_typ      = this.effective_typ;
00158    copy.effective_severity = this.effective_severity;
00159    copy.text               = this.text;
00160    copy.issued             = this.issued;
00161    copy.handling           = this.handling;
00162 
00163    copy.flushed = this.flushed;
00164 endfunction: copy
00165 
00166 
00167   //
00168   // vmm_log;
00169   //
00170 
00171 function void vmm_log::reset(string name,
00172                              string inst,
00173                              bit    recurse);
00174    this.is_self = 0;
00175    this.is_all  = 0;
00176 
00177    this.known_idx = 0;
00178    this.recurse = recurse;
00179    this.recurse_id++;
00180 `ifdef VCS2006_06
00181    // Work-around for NYI feature in 2006.06
00182    // *NOT* IEEE compliant :-(
00183    this.recurse_stack.delete();
00184 `else
00185    // Works in VCS 2008.03
00186    this.recurse_stack = '{};
00187 `endif
00188 
00189    // Trivial iterators?
00190    if (name == "" && inst == "") begin
00191       this.is_self = 1;
00192       return;
00193    end
00194    if (name == "/./" && inst == "/./") begin
00195       this.is_all = 1;
00196       this.recurse = 0; // No point in recursion
00197       return;
00198    end
00199    
00200    if (name == "") name = this.name;
00201    if (inst == "") inst = this.inst;
00202  
00203    this.pattern[0] = name;
00204    this.is_pattern[0] = `vmm_str_match(this.pattern[0], "^/(.*)/$");
00205    if (is_pattern[0]) begin
00206       this.pattern[0] = `vmm_str_backref(this.pattern[0], 0);
00207    end
00208 
00209    this.pattern[1] = inst;
00210    this.is_pattern[1] = `vmm_str_match(this.pattern[1], "^/(.*)/$");
00211    if (is_pattern[1]) begin
00212       this.pattern[1] = `vmm_str_backref(this.pattern[1], 0);
00213    end
00214 endfunction: reset
00215    
00216 
00217 `ifdef VCS
00218 (* vmm_private_class, _vcs_vmm_class = 1 *)
00219 `endif
00220 class vmm_log_below_iter;
00221    local vmm_log log;
00222    local int idx;
00223 
00224    function new(vmm_log log);
00225       this.log = log;
00226       this.idx = 0;
00227    endfunction
00228 
00229    function vmm_log data();
00230       if (this.idx >= this.log.below.size()) data = null;
00231       else data = this.log.below[idx];
00232    endfunction
00233 
00234    function vmm_log start();
00235       this.idx = 0;
00236       start = this.data();
00237    endfunction
00238 
00239    function vmm_log next();
00240       if (idx < this.log.below.size()) idx++;
00241       next = this.data();
00242    endfunction
00243 endclass
00244 
00245 
00246 function vmm_log vmm_log::for_each();
00247    if (this.is_self) begin
00248       if (this.is_self == 1) begin
00249          this.is_self = 2;
00250          if (this.recurse) begin
00251             vmm_log_below_iter j = new(this);
00252             this.visited = this.recurse_id;
00253             this.recurse_stack.push_back(j);
00254          end
00255          return this;
00256       end else if (!this.recurse) begin
00257          return null;
00258       end
00259    end
00260 
00261    while (this.recurse && this.recurse_stack.size() > 0) begin
00262       vmm_log_below_iter i = recurse_stack[$];
00263 
00264       while (i.data() != null) begin
00265          vmm_log that = i.data();
00266          i.next();
00267          if (that.visited != this.recurse_id) begin
00268             vmm_log_below_iter j = new(that);
00269             that.visited = this.recurse_id;
00270             this.recurse_stack.push_back(j);
00271             return that;
00272          end
00273       end
00274       this.recurse_stack.pop_back();
00275    end
00276 
00277    if (this.is_self) begin
00278       return null;
00279    end
00280 
00281    while (this.known_idx < this.known.size()) begin
00282       vmm_log that = this.known[this.known_idx++];
00283       bit name_ok;
00284       bit inst_ok;
00285 
00286       if (this.is_all) begin
00287          return that;
00288       end
00289 
00290       if (is_pattern[0]) name_ok = `vmm_str_match(that.name, this.pattern[0]);
00291       else               name_ok = (that.name == this.pattern[0]);
00292 
00293       if (is_pattern[1]) inst_ok = `vmm_str_match(that.inst, this.pattern[1]);
00294       else               inst_ok = (that.inst == this.pattern[1]);
00295 
00296       if (name_ok && inst_ok) begin
00297          if (that.visited != this.recurse_id) begin
00298             that.visited = this.recurse_id;
00299             if (this.recurse) begin
00300                vmm_log_below_iter j = new(that);
00301                this.recurse_stack.push_back(j);
00302             end
00303             return that;
00304          end
00305       end
00306    end
00307    for_each = null;
00308 endfunction: for_each
00309 
00310    
00311 function vmm_log::new(string  name,
00312                       string  inst,
00313                       vmm_log under);
00314 `ifdef VMM_LOG_BASE_NEW_CALL
00315    super.new(`VMM_LOG_BASE_NEW_CALL);
00316 `endif
00317 
00318    this.name = name;
00319    this.inst = inst;
00320    if (under != null) under.is_above(this);
00321 
00322    this.msg   = new(this);
00323 
00324    this.n_msg[FATAL_SEV]   = 0;
00325    this.n_msg[ERROR_SEV]   = 0;
00326    this.n_msg[WARNING_SEV] = 0;
00327    this.n_msg[NORMAL_SEV] = 0;
00328    this.n_msg[TRACE_SEV] = 0;
00329    this.n_msg[DEBUG_SEV] = 0;
00330    this.n_msg[VERBOSE_SEV] = 0;
00331    this.n_msg[HIDDEN_SEV] = 0;
00332    this.n_msg[IGNORE_SEV] = 0;
00333 
00334    this.has_text_modifiers = 0;
00335    this.n_demoted[ERROR_SEV] = 0;
00336    this.n_demoted[WARNING_SEV] = 0;
00337 
00338    this.known.push_back(this);
00339 
00340    this.enabled_typs = ALL_TYPS;
00341 
00342    if (this.known.size() == 1) begin
00343       this.type_list.push_back(FAILURE_TYP);
00344       this.type_list.push_back(NOTE_TYP);
00345       this.type_list.push_back(DEBUG_TYP);
00346       this.type_list.push_back(REPORT_TYP);
00347       this.type_list.push_back(NOTIFY_TYP);
00348       this.type_list.push_back(TIMING_TYP);
00349       this.type_list.push_back(XHANDLING_TYP);
00350       this.type_list.push_back(PROTOCOL_TYP);
00351       this.type_list.push_back(TRANSACTION_TYP);
00352       this.type_list.push_back(COMMAND_TYP);
00353       this.type_list.push_back(CYCLE_TYP);
00354       this.type_list.push_back(USER_TYP_0);
00355       this.type_list.push_back(USER_TYP_1);
00356       this.type_list.push_back(USER_TYP_2);
00357       this.type_list.push_back(INTERNAL_TYP);
00358 
00359       this.sev_list.push_back(FATAL_SEV);
00360       this.sev_list.push_back(ERROR_SEV);
00361       this.sev_list.push_back(WARNING_SEV);
00362       this.sev_list.push_back(NORMAL_SEV);
00363       this.sev_list.push_back(TRACE_SEV);
00364       this.sev_list.push_back(DEBUG_SEV);
00365       this.sev_list.push_back(VERBOSE_SEV);
00366 
00367       // Define default images
00368       this.type_images[FAILURE_TYP    ] = "FAILURE";
00369       this.type_images[NOTE_TYP       ] = "NOTE";
00370       this.type_images[DEBUG_TYP      ] = "DEBUG";
00371       this.type_images[REPORT_TYP     ] = "REPORT";
00372       this.type_images[NOTIFY_TYP     ] = "NOTIFY";
00373       this.type_images[TIMING_TYP     ] = "TIMING";
00374       this.type_images[XHANDLING_TYP  ] = "XHANDLING";
00375       this.type_images[PROTOCOL_TYP   ] = "PROTOCOL";
00376       this.type_images[TRANSACTION_TYP] = "XACTION";
00377       this.type_images[COMMAND_TYP    ] = "COMMAND";
00378       this.type_images[CYCLE_TYP      ] = "CYCLE";
00379       this.type_images[USER_TYP_0     ] = "USER_0";
00380       this.type_images[USER_TYP_1     ] = "USER_1";
00381       this.type_images[USER_TYP_2     ] = "USER_2";
00382       this.type_images[INTERNAL_TYP   ] = "INTERNAL";
00383 
00384 `ifdef VMM_LOG_ANSI_COLOR
00385       this.sev_images[FATAL_SEV  ] = "\033[41m*FATAL*\033[0m";
00386       this.sev_images[ERROR_SEV  ] = "\033[31m!ERROR!\033[0m";
00387       this.sev_images[WARNING_SEV] = "\033[33mWARNING\033[0m";
00388 `else
00389       this.sev_images[FATAL_SEV  ] = "*FATAL*";
00390       this.sev_images[ERROR_SEV  ] = "!ERROR!";
00391       this.sev_images[WARNING_SEV] = "WARNING";
00392 `endif
00393       this.sev_images[NORMAL_SEV ] = "Normal";
00394       this.sev_images[TRACE_SEV  ] = "Trace";
00395       this.sev_images[DEBUG_SEV  ] = "Debug";
00396       this.sev_images[VERBOSE_SEV] = "Verbose";
00397 
00398 
00399       // Process command-line options
00400       if ($test$plusargs("rvm_log_debug")) begin
00401          this.plus_debug = 1;
00402       end
00403 
00404       begin
00405          bit    plusarg;
00406          string arg;
00407          string level;
00408 
00409          plusarg = $value$plusargs("rvm_log_default=%s", arg);
00410          if (!plusarg) begin
00411             plusarg = $value$plusargs("vmm_log_default=%s", arg);
00412          end
00413          if (plusarg) begin
00414             level = arg.substr(0, 1); // Only look at the 1st 2 chars
00415 
00416             level = level.tolower();
00417             if (level == "er")
00418                this.dflt_lvl = ERROR_SEV;
00419             else if (level == "wa")
00420                this.dflt_lvl = WARNING_SEV;
00421             else if (level == "no")
00422                this.dflt_lvl = NORMAL_SEV;
00423             else if (level == "tr")
00424                this.dflt_lvl = TRACE_SEV;
00425             else if (level == "de")
00426                this.dflt_lvl = DEBUG_SEV;
00427             else if (level == "ve")
00428                this.dflt_lvl = VERBOSE_SEV;
00429             else if (level == "hi")
00430                this.dflt_lvl = HIDDEN_SEV;
00431             else
00432                $write("Warning: Invalid +rvm_log_default specification: \"%s\"\n",
00433                       arg);
00434          end
00435          // Sometimes, VCS screws up static initialization order
00436          else this.dflt_lvl = NORMAL_SEV;
00437 
00438          plusarg = $value$plusargs("rvm_force_verbosity=%s", arg);
00439          if (!plusarg) begin
00440             plusarg = $value$plusargs("vmm_force_verbosity=%s", arg);
00441          end
00442          if (plusarg) begin
00443             level = arg.substr(0, 1); // Only look at the 1st 2 chars
00444 
00445             level = level.tolower();
00446             if (level == "er")
00447               this.force_lvl = ERROR_SEV;
00448             else if (level == "wa")
00449               this.force_lvl = WARNING_SEV;
00450             else if (level == "no")
00451               this.force_lvl = NORMAL_SEV;
00452             else if (level == "tr")
00453               this.force_lvl = TRACE_SEV;
00454             else if (level == "de")
00455               this.force_lvl = DEBUG_SEV;
00456             else if (level == "ve")
00457               this.force_lvl = VERBOSE_SEV;
00458             else if (level == "hi")
00459               this.force_lvl = HIDDEN_SEV;
00460             else
00461               $write("Warning: Invalid +rvm_force_verbosity level: \"%s\"\n",
00462                      arg);
00463          end
00464       end
00465 
00466 
00467 
00468    end
00469 
00470    this.log_lvl = this.dflt_lvl;
00471    this.log_start(STDOUT);
00472 
00473    //
00474    // Catch a common usage error
00475    ///
00476    if (this.known.size() == 200) begin
00477       if (!$test$plusargs("vmm_log_nowarn_at_200") &&
00478           !$test$plusargs("rvm_log_nowarn_at_200")) begin
00479          if (this.start_msg(FAILURE_TYP, WARNING_SEV)) begin
00480             this.text("Over 200 vmm_log instances have been created.");
00481             this.text("Check that all vmm_data extensions use a static instance");
00482             this.text("or use +vmm_log_nowarn_at_200 to disable this warning.");
00483             this.end_msg();
00484          end
00485       end
00486    end
00487       
00488    if (this.known.size() == 1000) begin
00489       if (!$test$plusargs("vmm_log_nofatal_at_1000") &&
00490           !$test$plusargs("rvm_log_nofatal_at_1000")) begin
00491          if (this.start_msg(FAILURE_TYP, FATAL_SEV)) begin
00492             this.text("Over 1000 vmm_log instances have been created.");
00493             this.text("Check that all vmm_data extensions use a static instance");
00494             this.text("or use +vmm_log_nofatal_at_1000 to disable this failure.");
00495             this.end_msg();
00496          end
00497       end
00498    end
00499 
00500 
00501 
00502 endfunction: new
00503 
00504 
00505 function void vmm_log::is_above(vmm_log log);
00506    if (log == null) return;
00507    this.below.push_back(log);
00508 
00509 
00510 endfunction: is_above
00511 
00512   
00513 function vmm_log vmm_log::copy(vmm_log to);
00514    if (to == null) to = new(this.name, this.inst);
00515    else begin
00516       to.name = this.name;
00517       to.inst = this.inst;
00518    end
00519 
00520    to.enabled_typs = this.enabled_typs;
00521    to.log_lvl      = this.log_lvl;
00522    to.fp           = this.fp;
00523 
00524    copy = to;
00525 endfunction: copy
00526 
00527 
00528 function void vmm_log::set_name(string name);
00529    this.name = name;
00530 endfunction: set_name
00531 
00532   
00533 function string vmm_log::get_name();
00534    get_name = this.name;
00535 endfunction: get_name
00536 
00537   
00538 function void vmm_log::set_instance(string inst);
00539    this.inst = inst;
00540 endfunction: set_instance
00541    
00542 
00543 function string vmm_log::get_instance();
00544    get_instance = this.inst;
00545 endfunction: get_instance
00546    
00547 
00548 function void vmm_log::list(string name,
00549                             string inst,
00550                             bit    recurse);
00551    this.reset(name, inst, recurse);
00552    for (vmm_log log = this.for_each(); log != null; log = this.for_each()) begin   
00553       $write("%s(%s) [%s] F/E/W/e/w=%0d/%0d/%0d/%0d/%0d\n", log.name, log.inst, this.sev_image(log.log_lvl), log.n_msg[FATAL_SEV], log.n_msg[ERROR_SEV], log.n_msg[WARNING_SEV], log.n_demoted[ERROR_SEV], log.n_demoted[WARNING_SEV]);
00554       for(int i = 0; i < log.below.size(); i++) begin
00555          $write("  +--- %s(%s)\n", log.below[i].name, log.below[i].inst);
00556       end
00557    end
00558 endfunction: list
00559    
00560 
00561 function void vmm_log::display(string prefix);
00562    $display("%s", this.psdisplay(prefix));
00563 endfunction
00564 
00565 
00566 function string vmm_log::psdisplay(string prefix);
00567    $sformat(psdisplay, "%s%s(%s) [%s]", prefix, this.name, this.inst,
00568             this.sev_image(this.log_lvl));
00569    for (int i = 0; i < this.below.size(); i++) begin
00570       $sformat(psdisplay, "%s\n%s   +--- %s(%s)", psdisplay, prefix,
00571                this.below[i].name, this.below[i].inst);
00572    end
00573    for (int i = 0; i < this.modifier_ids.size(); i++) begin
00574       $sformat(psdisplay, "%s\n%s", psdisplay, this.modifier_cache[this.modifier_ids[i]].psdisplay({prefix, "   "}));
00575    end
00576 endfunction
00577 
00578 
00579 function void vmm_log::kill();
00580    foreach(this.known[i]) begin
00581       if (this.known[i] == this) this.known.delete(i);
00582    end
00583 endfunction: kill
00584 
00585 
00586 function vmm_log_format vmm_log::set_format(vmm_log_format fmt);
00587    if (fmt == null) begin
00588       `vmm_error(this, "Cannot use NULL formatter in vmm_log::set_format(). Unchanged");
00589       return null;
00590    end
00591 
00592    set_format = this.fmt;
00593    this.fmt = fmt;
00594 endfunction: set_format
00595 
00596   
00597 function string vmm_log::set_typ_image(int    typ,
00598                                        string image);
00599    if (!this.type_images.exists(typ)) begin
00600       `vmm_error(this, "Invalid message type specified to vmm_log::set_typ_image()");
00601       return "";
00602    end
00603 
00604    set_typ_image = this.type_images[typ];
00605    this.type_images[typ] = image;
00606 
00607 
00608 
00609 endfunction: set_typ_image
00610    
00611 
00612 function string vmm_log::typ_image(int typ);
00613    string sep = "";
00614 
00615    if (this.type_images.exists(typ)) begin
00616       return this.type_images[typ];
00617    end
00618 
00619    // Special types
00620    if (typ == DEFAULT) begin
00621       return "(default)";
00622    end
00623    if (typ == UNCHANGED) begin
00624       return "(unchanged)";
00625    end
00626 
00627    // Composite type?
00628    typ_image = "";
00629    foreach(this.type_list[i]) begin
00630       if (typ & this.type_list[i]) begin
00631          typ_image = {typ_image, sep, this.type_images[this.type_list[i]]};
00632          sep = "/";
00633       end
00634    end
00635    if (typ_image == "") typ_image = "?MSG_TYP?";
00636 endfunction: typ_image
00637    
00638 
00639 function string vmm_log::set_sev_image(int    severity,
00640                                        string image);
00641    if (!this.sev_images.exists(severity)) begin
00642       `vmm_error(this, "Invalid message severity specified to vmm_log::set_sev_image()");
00643       return "";
00644    end
00645 
00646    set_sev_image = this.sev_images[severity];
00647    this.sev_images[severity] = image;
00648 
00649 
00650 
00651 endfunction: set_sev_image
00652 
00653   
00654 function string vmm_log::sev_image(int severity);
00655    string sep = "";
00656 
00657    if (this.sev_images.exists(severity)) begin
00658       return this.sev_images[severity];
00659    end
00660 
00661    // Special severities
00662    if (severity == DEFAULT) begin
00663       return "(default)";
00664    end
00665    if (severity == UNCHANGED) begin
00666       return "(unchanged)";
00667    end
00668    if (severity == IGNORE_SEV) begin
00669       return "(ignored)";
00670    end
00671 
00672    // Composite severity?
00673    sev_image = "";
00674    foreach(this.sev_list[i]) begin
00675       if (severity & this.sev_list[i]) begin
00676          sev_image = {sev_image, sep, this.sev_images[this.sev_list[i]]};
00677          sep = "/";
00678       end
00679    end
00680    if (sev_image == "") sev_image = "?SEV_TYP?";
00681 endfunction: sev_image
00682 
00683 
00684 function string vmm_log::handling_image(int handling);
00685    case (handling)
00686       ABORT_SIM        : handling_image = "ABORT";
00687       COUNT_ERROR      : handling_image = "ERROR";
00688       STOP_PROMPT      : handling_image = "STOP";
00689       DEBUGGER         : handling_image = "DEBUGGER";
00690       DUMP_STACK       : handling_image = "DUMPSTACK";
00691       CONTINUE         : handling_image = "CONTINUE";
00692       IGNORE           : handling_image = "IGNORE";
00693       DEFAULT          : handling_image = "(default)";
00694       UNCHANGED        : handling_image = "(unchanged)";
00695       default          : handling_image = "?HANDLING?";
00696    endcase
00697 endfunction: handling_image
00698 
00699    
00700 function int vmm_log::default_handling(int severity);
00701    case (severity)
00702       FATAL_SEV   : default_handling = ABORT_SIM;
00703       ERROR_SEV   : default_handling = COUNT_ERROR;
00704       default     : default_handling = CONTINUE;
00705    endcase
00706 endfunction: default_handling
00707    
00708 
00709 function void vmm_log::report(string name,
00710                               string inst,
00711                               bit    recurse);
00712    vmm_log log;
00713    int    n_fatals = 0;
00714    int    n_errs   = 0;
00715    int    n_warns  = 0;
00716    int    n_derrs  = 0;
00717    int    n_dwarns = 0;
00718    string msg;
00719 
00720    this.reset(name, inst, recurse);
00721    for(log = this.for_each(); log != null; log = this.for_each()) begin
00722 
00723       n_fatals += log.n_msg[FATAL_SEV];
00724       n_errs   += log.n_msg[ERROR_SEV];
00725       n_warns  += log.n_msg[WARNING_SEV];
00726       n_derrs  += log.n_demoted[ERROR_SEV];
00727       n_dwarns += log.n_demoted[WARNING_SEV];
00728    end
00729 
00730    msg = this.fmt.pass_or_fail(n_fatals == 0 && n_errs == 0,
00731                                name, inst, n_fatals, n_errs, n_warns,
00732                                n_derrs, n_dwarns);
00733    if (msg != "") $display("%s", msg);
00734 endfunction: report
00735    
00736 
00737 function bit vmm_log::start_msg(int typ,
00738                                 int severity);
00739 
00740    if (this.msg != null && !this.msg.invalid && this.msg.issued !== 1'b0) this.end_msg();
00741 
00742    // Provide a default severity if none specified
00743    if (severity < 0) begin
00744       case (typ)
00745          FAILURE_TYP    :  severity = ERROR_SEV;
00746          NOTE_TYP       :  severity = NORMAL_SEV;
00747          DEBUG_TYP      :  severity = DEBUG_SEV;
00748          REPORT_TYP     :  severity = DEBUG_SEV;
00749          NOTIFY_TYP     :  severity = HIDDEN_SEV;
00750          TIMING_TYP     :  severity = WARNING_SEV;
00751          XHANDLING_TYP  :  severity = WARNING_SEV;
00752          PROTOCOL_TYP   :  severity = DEBUG_SEV;
00753          TRANSACTION_TYP:  severity = TRACE_SEV;
00754          COMMAND_TYP    :  severity = TRACE_SEV;
00755          CYCLE_TYP      :  severity = VERBOSE_SEV;
00756          default        :  severity = NORMAL_SEV;
00757       endcase
00758    end
00759 
00760    // Perform a quick, less expensive filtering here for loggers without
00761    // promotion/demotion or watchpoints.  Return immediately if the
00762    // message is not printed based on severity and enabled categories
00763    if (this.modifier_ids.size() == 0 &&
00764        this.watchpoint_ids.size() == 0) begin
00765 
00766       if ((this.force_lvl != DEFAULT_SEV && severity > this.force_lvl) || // Forced?
00767           (this.force_lvl == DEFAULT_SEV && severity > this.log_lvl) ||   // Above?
00768           (!(typ & this.enabled_typs) && (severity >= WARNING_SEV)) // Disabled?
00769           ) begin
00770          this.msg.invalid = 1;
00771          return 0;
00772       end
00773    end
00774 
00775    this.msg.invalid = 0;
00776    this.msg.original_typ = typ;
00777    this.msg.original_severity = severity;
00778    this.msg.effective_typ = typ;
00779    this.msg.effective_severity = severity;
00780    this.msg.flushed = 0;
00781 `ifdef VCS2006_06
00782    // Work-around for NYI feature in 2006.06
00783    // *NOT* IEEE compliant :-(
00784    this.msg.text.delete();
00785 `else
00786    // Works in VCS 2008.03
00787    this.msg.text = '{};
00788 `endif
00789    this.msg.handling = DEFAULT;
00790    this.msg.issued = 1'bx;
00791 
00792    start_msg = 1;
00793 
00794    // Do property-based promotion and filtering
00795    // if there are no text-based filters
00796    if (!this.has_text_modifiers) begin
00797       this.promote();
00798       this.filter();
00799 
00800       if (this.msg.issued === 1'b0) begin
00801          start_msg = 0;
00802 
00803          // Record risky demotions
00804          if (this.msg.effective_severity > this.msg.original_severity) begin
00805             case (this.msg.original_severity)
00806                ERROR_SEV  : this.n_demoted[ERROR_SEV]++;
00807                WARNING_SEV: this.n_demoted[WARNING_SEV]++;
00808             endcase
00809          end
00810 
00811          this.msg.invalid = 1;
00812       end
00813    end
00814 endfunction: start_msg
00815    
00816 
00817 function bit vmm_log::text(string msg);
00818    if (this.msg.invalid)
00819    begin
00820       `vmm_error(this, "Malformed message: vmm_log::text() called before vmm_log::start_msg()");
00821       return 0;
00822    end
00823 
00824    text = 1;
00825 
00826    if (msg == "")
00827    begin
00828       this.flush_msg();
00829       return 1;
00830    end
00831 
00832    this.msg.text.push_back(msg);
00833 
00834 endfunction: text
00835    
00836 
00837 function void vmm_log::end_msg();
00838    int handling;
00839 
00840    if (this.msg.invalid)
00841    begin
00842       `vmm_error(this, "Malformed message: vmm_log::end_msg() called before vmm_log::start_msg()");
00843       return;
00844    end
00845 
00846    this.flush_msg();
00847 
00848 
00849 
00850 
00851    handling = this.msg.handling;
00852    if (handling == DEFAULT) handling = default_handling(this.msg.effective_severity);
00853 
00854    // Avoid recursive handling in callbacks
00855    if (this.in_callbacks) handling = CONTINUE;
00856 
00857    case (handling)
00858 
00859      ABORT_SIM: begin
00860         this.in_callbacks = 1;
00861         `vmm_callback(vmm_log_callbacks, pre_abort(this));
00862         this.in_callbacks = 0;
00863         $finish;
00864      end
00865 
00866      DUMP_STACK,
00867      DEBUGGER: begin
00868         this.in_callbacks = 1;
00869         `vmm_callback(vmm_log_callbacks, pre_debug(this));
00870         this.in_callbacks = 0;
00871         $stop;
00872      end
00873 
00874      STOP_PROMPT: begin
00875         this.in_callbacks = 1;
00876         `vmm_callback(vmm_log_callbacks, pre_stop(this));
00877         this.in_callbacks = 0;
00878         $stop;
00879      end
00880 
00881      COUNT_ERROR: begin
00882         this.error_count++;
00883         if (this.error_limit > 0 && this.error_count >= this.error_limit) begin
00884            string msg = this.fmt.abort_on_error(this.error_count,
00885                                                 this.error_limit);
00886            if (msg != "") $display("%s", msg);
00887            this.in_callbacks = 1;
00888            //`vmm_callback(vmm_log_callbacks, pre_abort(this));
00889            do for (int i = 0; i < this.callbacks.size(); i++) begin
00890               vmm_log_callbacks cb;
00891               if (!$cast(cb, this.callbacks[i])) continue;
00892               cb.pre_abort(this);
00893            end while (0);
00894            this.in_callbacks = 0;
00895            $finish;
00896         end                                          
00897      end
00898    endcase
00899 
00900    this.msg.invalid = 1;
00901 endfunction: end_msg
00902 
00903 
00904 function void vmm_log::flush_msg();
00905    string msg;
00906 
00907    if (this.msg.flushed == 0) begin
00908 
00909       // Perform promotion/demotion if there are text filters
00910       // (it will have been done in start_msg() if there were none)
00911       if (this.has_text_modifiers) begin
00912          this.promote();
00913          this.filter();
00914       end
00915       this.notify();
00916 
00917       // Record risky demotions
00918       if (this.msg.effective_severity > this.msg.original_severity) begin
00919          case (this.msg.original_severity)
00920             ERROR_SEV  : this.n_demoted[ERROR_SEV]++;
00921             WARNING_SEV: this.n_demoted[WARNING_SEV]++;
00922          endcase
00923       end
00924 
00925       if (this.msg.issued === 1'b0) return;
00926 
00927 
00928 
00929 
00930       msg = this.fmt.format_msg(this.name, this.inst, 
00931                                 this.typ_image(this.msg.effective_typ),
00932                                 this.sev_image(this.msg.effective_severity),
00933                                 this.msg.text);
00934       foreach(this.fp[i]) begin
00935          $fdisplay(this.fp[i], "%s", msg);
00936       end
00937       // Did we just send an ERROR or FATAL message to /dev/null??
00938       if (this.fp.size() == 0 && this.msg.effective_severity <= ERROR_SEV) begin
00939          // Force it to appear on STDOUT
00940          $display("%s", msg);
00941       end
00942       this.msg.flushed++;
00943 `ifdef VCS2006_06
00944       // Work-around for NYI feature in 2006.06
00945       // *NOT* IEEE compliant :-(
00946       this.msg.text.delete();
00947 `else
00948       // Works in VCS 2008.03
00949       this.msg.text = '{};
00950 `endif
00951    end
00952    else begin
00953       if (this.msg.text.size() > 0) begin
00954          msg = this.fmt.continue_msg(this.name, this.inst, 
00955                                      this.typ_image(this.msg.effective_typ),
00956                                      this.sev_image(this.msg.effective_severity),
00957                                      this.msg.text);
00958          foreach(this.fp[i]) begin
00959             $fdisplay(this.fp[i], "%s", msg);
00960          end
00961          // Did we just send an ERROR or FATAL message to /dev/null??
00962          if (this.fp.size() == 0 && this.msg.effective_severity <= ERROR_SEV) begin
00963             // Force it to appear on STDOUT
00964             $display("%s", msg);
00965          end
00966          this.msg.flushed++;
00967 `ifdef VCS2006_06
00968          // Work-around for NYI feature in 2006.06
00969          // *NOT* IEEE compliant :-(
00970          this.msg.text.delete();
00971 `else
00972          // Works in VCS 2008.03
00973          this.msg.text = '{};
00974 `endif
00975       end
00976       return;
00977    end
00978 
00979    this.n_msg[this.msg.effective_severity]++;
00980 endfunction: flush_msg
00981 
00982 
00983 function void vmm_log::enable_types(int    typs,
00984                                     string name,
00985                                     string inst,
00986                                     bit    recursive);
00987    if (typs == DEFAULT_TYP ) typs = ALL_TYPS ;
00988    if (typs < 0) begin
00989       `vmm_error(this, "Invalid message type specified to vmm_log::enable_types");
00990       return;
00991    end
00992 
00993    //
00994    // Enable specified types in all specified log insts
00995    //
00996    this.reset(name, inst, recursive);
00997    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
00998       log.enabled_typs |= typs;
00999    end
01000 endfunction: enable_types
01001 
01002 
01003 function void vmm_log::disable_types(int    typs,
01004                                      string name,
01005                                      string inst,
01006                                      bit    recursive);
01007    if (typs < 0) begin
01008       `vmm_error(this, "Invalid message type specified to vmm_log::disable_types");
01009       return;
01010    end
01011    // Cannot disable failure messages
01012    if (typs & FAILURE_TYP) begin
01013       `vmm_warning(this, "Cannot disable FAILURE_TYP messages");
01014       typs -= FAILURE_TYP;
01015    end
01016 
01017    //
01018    // Disable specified types in all specified log insts
01019    //
01020    this.reset(name, inst, recursive);
01021    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01022       log.enabled_typs &= ~(typs);
01023    end
01024 endfunction: disable_types
01025 
01026    
01027 function int vmm_log::modify(string name,
01028                              string inst,
01029                              bit    recursive,
01030                              int    typ,
01031                              int    severity,
01032                              string text,
01033                              int    new_typ,
01034                              int    new_severity,
01035                              int    handling);
01036    vmm_log_modifier modifier;
01037    int          mod_id;
01038 
01039    // Some severities cannot be demoted too far
01040    if (severity == FATAL_SEV &&
01041        new_severity > ERROR_SEV) begin
01042       `vmm_error(this, "Cannot demote FATAL_SEV severity to less than ERROR_SEV");
01043       return -2;
01044    end
01045    if (severity == ERROR_SEV &&
01046        new_severity > WARNING_SEV) begin
01047       `vmm_error(this, "Cannot demote ERROR severity to less than WARNING");
01048       return -2;
01049    end
01050 
01051    //
01052    // Add a description of the modification to the cache
01053    //
01054    modifier = new;
01055    modifier.typ          = typ;
01056    modifier.severity     = severity;
01057    modifier.pattern      = text;
01058    modifier.new_typ      = new_typ;
01059    modifier.new_severity = new_severity;
01060    modifier.handling     = handling;
01061 
01062    // Remove "/" surrounding the pattern, if any
01063    if (`vmm_str_match(modifier.pattern, "^/(.*)/$")) begin
01064       modifier.pattern = `vmm_str_backref(modifier.pattern, 0);
01065    end
01066 
01067    mod_id = this.modifier_cache.num();
01068    this.modifier_cache[mod_id] = modifier;
01069 
01070    //
01071    // Link all affected log instances
01072    //
01073    this.reset(name, inst, recursive);
01074    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01075       log.modifier_ids.push_back(mod_id);
01076       if (modifier.pattern != "") log.has_text_modifiers++;
01077    end
01078 
01079    modify = mod_id;
01080 endfunction: modify
01081 
01082 
01083 function void vmm_log::unmodify(int    modification_id,
01084                                 string name,
01085                                 string inst,
01086                                 bit    recursive);
01087    if (modification_id < -1) begin
01088       `vmm_error(this, `vmm_sformatf("Invalid modification ID %0d specified to vmm_log::unmodify()",
01089                                      modification_id));
01090       return;
01091    end
01092 
01093    // Does it exist?
01094    if (modification_id >= 0) begin
01095       if (!this.modifier_cache.exists(modification_id)) begin
01096          `vmm_error(this, `vmm_sformatf("Unknown modification ID %0d specified to vmm_log::unmodify()",
01097                                         modification_id));
01098          return;
01099       end
01100    end
01101    
01102    //
01103    // Unlink all affected log instances
01104    //
01105    this.reset(name, inst, recursive);
01106    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01107 
01108       // Find the specified modifier...
01109       foreach(log.modifier_ids[i]) begin
01110          if (modification_id >= 0 && log.modifier_ids[i] != modification_id) continue;
01111 
01112          if (this.modifier_cache[log.modifier_ids[i]].pattern != "") begin
01113             log.has_text_modifiers--;
01114             if (log.has_text_modifiers < 0) begin
01115                $write("***** vmm_log Internal ERROR: has_text_modifiers < 0\n");
01116                log.has_text_modifiers = 0;
01117             end
01118          end
01119          if (modification_id >= 0) begin
01120             log.modifier_ids.delete(i);
01121             break;
01122          end
01123       end
01124       if (modification_id < 0) begin
01125 `ifdef VCS2006_06
01126          // Work-around for NYI feature in 2006.06
01127          // *NOT* IEEE compliant :-(
01128          log.modifier_ids.delete();
01129 `else
01130          // Works in VCS 2008.03
01131          log.modifier_ids = '{};
01132 `endif
01133       end
01134    end
01135 endfunction: unmodify
01136 
01137 
01138 function void vmm_log::promote();
01139 
01140    // Apply modifiers in the order they were created
01141    foreach(this.modifier_ids[i]) begin
01142       vmm_log_modifier mod;
01143       
01144       mod = this.modifier_cache[this.modifier_ids[i]];
01145 
01146       // Does it apply to this message?
01147 
01148       // Message type must be included
01149       if (!(mod.typ & this.msg.effective_typ)) continue;
01150 
01151       // Message severity must be included
01152       if (!(mod.severity & this.msg.effective_severity)) continue;
01153 
01154       // If specified, the text pattern must match
01155       if (mod.pattern != "") begin
01156          bit matched = 0;
01157          int idx;
01158          foreach (this.msg.text[idx]) begin
01159             if (`vmm_str_match(this.msg.text[idx], mod.pattern)) begin
01160                matched = 1;
01161                break;
01162             end
01163          end
01164          if (!matched) continue;
01165       end
01166 
01167       // Promote message!
01168       if (mod.new_typ != UNCHANGED) begin
01169          if (mod.new_typ == DEFAULT) begin
01170             this.msg.effective_typ = this.msg.original_typ;
01171          end else begin
01172             this.msg.effective_typ = mod.new_typ;
01173          end
01174       end
01175 
01176       if (mod.new_severity != UNCHANGED) begin
01177          if (mod.new_severity == DEFAULT) begin
01178             this.msg.effective_severity = this.msg.original_severity;
01179          end else begin
01180             this.msg.effective_severity = mod.new_severity;
01181          end
01182          // Some severities cannot be demoted too far
01183          if (this.msg.original_severity == FATAL_SEV &&
01184              this.msg.effective_severity > ERROR_SEV) begin
01185             this.msg.effective_severity = ERROR_SEV ;
01186          end
01187          if (this.msg.original_severity == ERROR_SEV &&
01188              this.msg.effective_severity > WARNING_SEV) begin
01189             this.msg.effective_severity = WARNING_SEV;
01190          end
01191       end
01192 
01193       if (mod.handling != UNCHANGED) begin
01194          this.msg.handling = mod.handling;
01195       end
01196    end
01197 endfunction: promote
01198    
01199 
01200 function void vmm_log::filter();
01201 
01202    if (this.msg.issued === 1'b0 ||  // Already filtered out
01203        this.msg.effective_severity == IGNORE_SEV ||  // Demoted to be ignored
01204        // Cannot disable any types with severity FATAL or ERROR
01205        (!(this.msg.effective_typ & this.enabled_typs) &&     // Disabled
01206         (this.msg.effective_severity >= WARNING_SEV)) ||
01207        (this.force_lvl != DEFAULT_SEV && this.msg.effective_severity > this.force_lvl) ||
01208        (this.force_lvl == DEFAULT_SEV && this.log_lvl < this.msg.effective_severity)) begin
01209       this.msg.issued = 1'b0;
01210 
01211       return;
01212    end
01213 
01214    this.msg.issued = 1'b1;
01215 endfunction: filter
01216    
01217 
01218 function void vmm_log::notify();
01219    // Check notifiers in the order they were created
01220    foreach(this.watchpoint_ids[i]) begin
01221       vmm_log_watchpoint wp;
01222 
01223       wp = this.watchpoint_cache[this.watchpoint_ids[i]];
01224 
01225       // Does it apply to this message?
01226 
01227       // Message type must be included
01228       if (!(wp.typ & this.msg.effective_typ)) continue;
01229 
01230       // Message severity must be included
01231       if (!(wp.severity & this.msg.effective_severity)) continue;
01232 
01233       // The message must be issued or not
01234       if (wp.issued !== 1'bx && wp.issued !== this.msg.issued) begin
01235          continue;
01236       end
01237 
01238       // If specified, the text pattern must match
01239       if (wp.pattern != "") begin
01240          bit matched = 0;
01241          integer idx;
01242          foreach(this.msg.text[idx]) begin
01243             if (`vmm_str_match(this.msg.text[idx], wp.pattern)) begin
01244                matched = 1;
01245                break;
01246             end
01247          end
01248          if (!matched) continue; // to the next watchpt
01249       end
01250 
01251       // This is a watched message
01252       wp.msg = this.msg.copy();
01253       -> wp.seen;
01254    end
01255 endfunction: notify
01256 
01257 
01258 function void vmm_log::set_verbosity(int    severity,
01259                                      string name,
01260                                      string inst,
01261                                      bit    recursive);
01262    if (!this.sev_images.exists(severity) ||
01263        severity < ERROR_SEV ||
01264        severity > VERBOSE_SEV) begin
01265       `vmm_error(this, "Invalid severity specified to vmm_log::set_verbosity()");
01266       return;
01267    end
01268 
01269    this.reset(name, inst, recursive);
01270    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01271       log.log_lvl = severity;
01272    end
01273 endfunction: set_verbosity
01274    
01275 
01276 function int vmm_log::get_verbosity();
01277    get_verbosity = this.log_lvl;
01278 endfunction: get_verbosity
01279 
01280 
01281 function void vmm_log::log_start(int    file,
01282                                  string name,
01283                                  string inst,
01284                                  bit    recurse);
01285    // Find the loggers in question
01286    vmm_log log;
01287       
01288    this.reset(name, inst, recurse);
01289    for(log = this.for_each(); log != null; log = this.for_each()) begin
01290       
01291       // Check that we are not already logging to this file
01292       foreach(log.fp[i]) begin
01293          if (log.fp[i] == file) return;
01294       end
01295       log.fp.push_back(file);
01296 
01297 
01298    end
01299 endfunction: log_start
01300 
01301 
01302 function void vmm_log::log_stop(int    file,
01303                                 string name,
01304                                 string inst,
01305                                 bit    recurse);
01306    // Find the loggers in question
01307    vmm_log log;
01308       
01309    this.reset(name, inst, recurse);
01310    for(log = this.for_each(); log != null; log = this.for_each()) begin
01311       
01312       // Check that we are indeed logging to this file
01313       foreach(log.fp[i]) begin
01314          if (log.fp[i] == file) log.fp.delete(i);
01315          // Cannot close this file because it may still be used by other loggers
01316       end
01317    end
01318 endfunction: log_stop
01319 
01320 
01321 function void vmm_log::stop_after_n_errors(int n);
01322    this.error_count = 0;
01323    this.error_limit = n;
01324 endfunction: stop_after_n_errors
01325    
01326 function int vmm_log::get_message_count(int    severity,
01327                                         string name,
01328                                         string inst,
01329                                         bit    recurse);
01330    get_message_count = 0;
01331 
01332    this.reset(name, inst, recurse);
01333    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01334 
01335       if (severity & FATAL_SEV)   get_message_count += log.n_msg[FATAL_SEV];
01336       if (severity & ERROR_SEV)   get_message_count += log.n_msg[ERROR_SEV];
01337       if (severity & WARNING_SEV) get_message_count += log.n_msg[WARNING_SEV];
01338       if (severity & NORMAL_SEV)  get_message_count += log.n_msg[NORMAL_SEV];
01339       if (severity & TRACE_SEV)   get_message_count += log.n_msg[TRACE_SEV];
01340       if (severity & DEBUG_SEV)   get_message_count += log.n_msg[DEBUG_SEV];
01341       if (severity & VERBOSE_SEV) get_message_count += log.n_msg[VERBOSE_SEV];
01342       if (severity & HIDDEN_SEV)  get_message_count += log.n_msg[HIDDEN_SEV];
01343       if (severity & IGNORE_SEV)  get_message_count += log.n_msg[IGNORE_SEV];
01344    end
01345 endfunction: get_message_count
01346 
01347 
01348 task vmm_log::wait_for_msg(string          name,
01349                            string          inst,
01350                            bit             recurse,
01351                            int             typs,
01352                            int             severity,
01353                            string          text,
01354                            logic           issued,
01355                            ref vmm_log_msg msg);
01356    int wp_id;
01357 
01358    wp_id = this.create_watchpoint(typs, severity, text, issued);
01359    this.add_watchpoint(wp_id, name, inst, recurse);
01360    this.wait_for_watchpoint(wp_id, msg);
01361    this.remove_watchpoint(wp_id, name, inst, recurse);
01362 endtask: wait_for_msg
01363 
01364 
01365 function int vmm_log::create_watchpoint(int     typs,
01366                                         int     severity,
01367                                         string  text,
01368                                         logic   issued);
01369    vmm_log_watchpoint wp = new;
01370    int                wp_id;
01371 
01372    //
01373    // Add a description of the watchpoint to the cache
01374    //
01375    wp.typ          = typs;
01376    wp.severity     = severity;
01377    wp.pattern      = text;
01378    wp.issued       = issued;
01379 
01380    // Remove "/" surrounding the pattern, if any
01381    if (`vmm_str_match(wp.pattern, "^/(.*)/$")) begin
01382       wp.pattern = `vmm_str_backref(wp.pattern, 0);
01383    end
01384 
01385    wp_id = this.watchpoint_cache.num();
01386    this.watchpoint_cache[wp_id] = wp;
01387 
01388    create_watchpoint = wp_id;
01389 endfunction: create_watchpoint
01390 
01391 
01392 function void vmm_log::add_watchpoint(int     watchpoint_id,
01393                                       string  name,
01394                                       string  inst,
01395                                       bit     recurse);
01396    vmm_log            log;
01397    vmm_log_watchpoint wp;
01398 
01399    if (!this.watchpoint_cache.exists(watchpoint_id)) begin
01400       `vmm_warning(this, `vmm_sformatf("Watchpoint #%0d does not exist", watchpoint_id));
01401       return;
01402    end
01403    wp = this.watchpoint_cache[watchpoint_id];
01404    
01405    //
01406    // Link all affected log insts
01407    //
01408    this.reset(name, inst, recurse);
01409    for(log = this.for_each(); log != null; log = this.for_each()) begin
01410       log.watchpoint_ids.push_back(watchpoint_id);
01411       if (wp.pattern != "") log.has_text_modifiers++;
01412    end
01413 endfunction: add_watchpoint
01414    
01415 
01416 function void vmm_log::remove_watchpoint(int     watchpoint_id,
01417                                          string  name,
01418                                          string  inst,
01419                                          bit     recurse);
01420    vmm_log log;
01421    
01422    //
01423    // Unlink all affected log insts
01424    //
01425    this.reset(name, inst, recurse);
01426    for(log = this.for_each(); log != null; log = this.for_each()) begin
01427 
01428       // Find the specified watchpoint...
01429       foreach(log.watchpoint_ids[i]) begin
01430          if (watchpoint_id < 0 || log.watchpoint_ids[i] == watchpoint_id) begin
01431             if (this.watchpoint_cache[log.watchpoint_ids[i]].pattern != "") begin
01432                log.has_text_modifiers--;
01433                if (log.has_text_modifiers < 0) begin
01434                   $write("***** vmm_log Internal ERROR: has_text_modifiers < 0\n");
01435                   log.has_text_modifiers = 0;
01436                end
01437             end
01438             log.watchpoint_ids.delete(i);
01439             if (watchpoint_id >= 0) break;
01440          end
01441       end
01442    end
01443 endfunction: remove_watchpoint
01444 
01445    
01446 task vmm_log::wait_for_watchpoint(int             watchpoint_id,
01447                                   ref vmm_log_msg msg);
01448    vmm_log_watchpoint wp;
01449    
01450    if (!this.watchpoint_cache.exists(watchpoint_id)) begin
01451       `vmm_warning(this, `vmm_sformatf("Watchpoint #%0d does not exist", watchpoint_id));
01452       msg = null;
01453    end
01454    else begin
01455       //
01456       // Wait for a triggering of the watchpoint
01457       //
01458       wp = this.watchpoint_cache[watchpoint_id];
01459       @wp.seen;
01460       msg = wp.msg;
01461    end
01462 endtask: wait_for_watchpoint
01463 
01464 function void vmm_log::prepend_callback(vmm_log_callbacks cb);
01465    // Check if callback has already been registered...
01466    foreach (this.callbacks[i]) begin
01467       if (this.callbacks[i] == cb) begin
01468          if (this.start_msg(FAILURE_TYP, WARNING_SEV)) begin
01469             this.text("Callback has already been registered");
01470             this.end_msg();
01471          end
01472          return;
01473       end
01474    end
01475 
01476    // Register new callback
01477    this.callbacks.push_front(cb);
01478 endfunction: prepend_callback
01479    
01480 
01481 function void vmm_log::append_callback(vmm_log_callbacks cb);
01482    // Check if callback has already been registered...
01483    foreach (this.callbacks[i]) begin
01484       if (this.callbacks[i] == cb) begin
01485          if (this.start_msg(FAILURE_TYP, WARNING_SEV)) begin
01486             this.text("Callback has already been registered");
01487             this.end_msg();
01488          end
01489          return;
01490       end
01491    end
01492 
01493    // Register new callback
01494    this.callbacks.push_back(cb);
01495 endfunction: append_callback
01496    
01497 
01498 function void vmm_log::unregister_callback(vmm_log_callbacks cb);
01499    // Look for callback
01500    foreach (this.callbacks[i]) begin
01501       if (this.callbacks[i] == cb) begin
01502          // Unregister it
01503          this.callbacks.delete(i);
01504          return;
01505       end
01506    end
01507 
01508    if (this.start_msg(FAILURE_TYP, WARNING_SEV)) begin
01509       this.text("Callback was not registered");
01510       this.end_msg();
01511    end
01512 endfunction: unregister_callback   
01513 
01514 
01515   //
01516   // vmm_log_format
01517   //
01518 
01519 function string vmm_log_format::format_msg(string name,
01520                                            string inst,
01521                                            string msg_typ,
01522                                            string severity,
01523                                            ref string lines[$]);
01524    $sformat(format_msg, "%s[%s] on %s(%s) at %t:",
01525             severity, msg_typ, name, inst, $realtime());
01526    foreach(lines[i]) begin
01527       string line = lines[i];
01528       string t;
01529 
01530       format_msg = {format_msg, "\n    "};
01531 
01532       while (1) begin
01533          string pre;
01534          if (!`vmm_str_match(line, "\n")) begin
01535             format_msg = {format_msg, line};
01536             break;
01537          end
01538 
01539          pre = `vmm_str_prematch(line);
01540          format_msg = {format_msg, pre, "\n    "};
01541          line = `vmm_str_postmatch(line);
01542       end
01543    end
01544 endfunction: format_msg
01545   
01546 
01547 function string vmm_log_format::continue_msg(string name,
01548                                              string inst,
01549                                              string msg_typ,
01550                                              string severity,
01551                                              ref string lines[$]);
01552    continue_msg = "";
01553    foreach(lines[i]) begin
01554       if (i > 0) continue_msg = {continue_msg, "\n"};
01555       $sformat(continue_msg, "%s    %s", continue_msg, lines[i]);
01556    end
01557 endfunction: continue_msg
01558 
01559 
01560 function string vmm_log_format::abort_on_error(int count,
01561                                                int limit);
01562    abort_on_error = "Maximum number of error messages exceeded. Aborting\nUse method stop_after_n_errors() of vmm_log to increase threshold.";
01563 endfunction: abort_on_error
01564 
01565 
01566 function string vmm_log_format::pass_or_fail(bit    pass,
01567                                              string name,
01568                                              string inst,
01569                                              int    fatals,
01570                                              int    errors,
01571                                              int    warnings,
01572                                              int    dem_errs,
01573                                              int    dem_warns);
01574    if (pass) begin
01575       $sformat(pass_or_fail, "Simulation PASSED on %s (%s) at %t (%0d warnings, %0d demoted errors & %0d demoted warnings)",
01576                name, inst, $realtime(), warnings, dem_errs, dem_warns);
01577    end else begin
01578       $sformat(pass_or_fail, "Simulation *FAILED* on %s (%s) at %t: %0d errors, %0d warnings",
01579              name, inst, $realtime(), fatals + errors, warnings);
01580    end
01581 endfunction: pass_or_fail
01582 
01583 
01584 
01585