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