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