VMM OpenSource - sv/std_lib/vmm_log.sv

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