vmm_log.sv

Go to the documentation of this file.
00001 // 
00002 // -------------------------------------------------------------
00003 //    Copyright 2004-2008 Synopsys, Inc.
00004 //    All Rights Reserved Worldwide
00005 // 
00006 //    Licensed under the Apache License, Version 2.0 (the
00007 //    "License"); you may not use this file except in
00008 //    compliance with the License.  You may obtain a copy of
00009 //    the License at
00010 // 
00011 //        http://www.apache.org/licenses/LICENSE-2.0
00012 // 
00013 //    Unless required by applicable law or agreed to in
00014 //    writing, software distributed under the License is
00015 //    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00016 //    CONDITIONS OF ANY KIND, either express or implied.  See
00017 //    the License for the specific language governing
00018 //    permissions and limitations under the License.
00019 // -------------------------------------------------------------
00020 // 
00021 
00022 
00023 `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    this.recurse_stack.delete();
00181 
00182    // Trivial iterators?
00183    if (name == "" && inst == "") begin
00184       this.is_self = 1;
00185       return;
00186    end
00187    if (name == "/./" && inst == "/./") begin
00188       this.is_all = 1;
00189       this.recurse = 0; // No point in recursion
00190       return;
00191    end
00192    
00193    if (name == "") name = this.name;
00194    if (inst == "") inst = this.inst;
00195  
00196    this.pattern[0] = name;
00197    this.is_pattern[0] = `vmm_str_match(this.pattern[0], "^/(.*)/$");
00198    if (is_pattern[0]) begin
00199       this.pattern[0] = `vmm_str_backref(this.pattern[0], 0);
00200    end
00201 
00202    this.pattern[1] = inst;
00203    this.is_pattern[1] = `vmm_str_match(this.pattern[1], "^/(.*)/$");
00204    if (is_pattern[1]) begin
00205       this.pattern[1] = `vmm_str_backref(this.pattern[1], 0);
00206    end
00207 endfunction: reset
00208    
00209 
00210 `ifdef VCS
00211 (* vmm_private_class, _vcs_vmm_class = 1 *)
00212 `endif
00213 class vmm_log_below_iter;
00214    local vmm_log log;
00215    local int idx;
00216 
00217    function new(vmm_log log);
00218       this.log = log;
00219       this.idx = 0;
00220    endfunction
00221 
00222    function vmm_log data();
00223       if (this.idx >= this.log.below.size()) data = null;
00224       else data = this.log.below[idx];
00225    endfunction
00226 
00227    function vmm_log start();
00228       this.idx = 0;
00229       start = this.data();
00230    endfunction
00231 
00232    function vmm_log next();
00233       if (idx < this.log.below.size()) idx++;
00234       next = this.data();
00235    endfunction
00236 endclass
00237 
00238 
00239 function vmm_log vmm_log::for_each();
00240    if (this.is_self) begin
00241       if (this.is_self == 1) begin
00242          this.is_self = 2;
00243          if (this.recurse) begin
00244             vmm_log_below_iter j = new(this);
00245             this.visited = this.recurse_id;
00246             this.recurse_stack.push_back(j);
00247          end
00248          return this;
00249       end else if (!this.recurse) begin
00250          return null;
00251       end
00252    end
00253 
00254    while (this.recurse && this.recurse_stack.size() > 0) begin
00255       vmm_log_below_iter i = recurse_stack[$];
00256 
00257       while (i.data() != null) begin
00258          vmm_log that = i.data();
00259          i.next();
00260          if (that.visited != this.recurse_id) begin
00261             vmm_log_below_iter j = new(that);
00262             that.visited = this.recurse_id;
00263             this.recurse_stack.push_back(j);
00264             return that;
00265          end
00266       end
00267       this.recurse_stack.pop_back();
00268    end
00269 
00270    if (this.is_self) begin
00271       return null;
00272    end
00273 
00274    while (this.known_idx < this.known.size()) begin
00275       vmm_log that = this.known[this.known_idx++];
00276       bit name_ok;
00277       bit inst_ok;
00278 
00279       if (this.is_all) begin
00280          return that;
00281       end
00282 
00283       if (is_pattern[0]) name_ok = `vmm_str_match(that.name, this.pattern[0]);
00284       else               name_ok = (that.name == this.pattern[0]);
00285 
00286       if (is_pattern[1]) inst_ok = `vmm_str_match(that.inst, this.pattern[1]);
00287       else               inst_ok = (that.inst == this.pattern[1]);
00288 
00289       if (name_ok && inst_ok) begin
00290          if (that.visited != this.recurse_id) begin
00291             that.visited = this.recurse_id;
00292             if (this.recurse) begin
00293                vmm_log_below_iter j = new(that);
00294                this.recurse_stack.push_back(j);
00295             end
00296             return that;
00297          end
00298       end
00299    end
00300    for_each = null;
00301 endfunction: for_each
00302 
00303    
00304 function vmm_log::new(string  name,
00305                       string  inst,
00306                       vmm_log under);
00307 `ifdef VMM_LOG_BASE_NEW_CALL
00308    super.new(`VMM_LOG_BASE_NEW_CALL);
00309 `endif
00310 
00311    this.name = name;
00312    this.inst = inst;
00313    if (under != null) under.is_above(this);
00314 
00315    this.msg   = new(this);
00316 
00317    this.n_msg[FATAL_SEV]   = 0;
00318    this.n_msg[ERROR_SEV]   = 0;
00319    this.n_msg[WARNING_SEV] = 0;
00320    this.n_msg[NORMAL_SEV] = 0;
00321    this.n_msg[TRACE_SEV] = 0;
00322    this.n_msg[DEBUG_SEV] = 0;
00323    this.n_msg[VERBOSE_SEV] = 0;
00324    this.n_msg[HIDDEN_SEV] = 0;
00325    this.n_msg[IGNORE_SEV] = 0;
00326 
00327    this.has_text_modifiers = 0;
00328    this.n_demoted[ERROR_SEV] = 0;
00329    this.n_demoted[WARNING_SEV] = 0;
00330 
00331    this.known.push_back(this);
00332 
00333    this.enabled_typs = ALL_TYPS;
00334 
00335    if (this.known.size() == 1) begin
00336       this.type_list.push_back(FAILURE_TYP);
00337       this.type_list.push_back(NOTE_TYP);
00338       this.type_list.push_back(DEBUG_TYP);
00339       this.type_list.push_back(REPORT_TYP);
00340       this.type_list.push_back(NOTIFY_TYP);
00341       this.type_list.push_back(TIMING_TYP);
00342       this.type_list.push_back(XHANDLING_TYP);
00343       this.type_list.push_back(PROTOCOL_TYP);
00344       this.type_list.push_back(TRANSACTION_TYP);
00345       this.type_list.push_back(COMMAND_TYP);
00346       this.type_list.push_back(CYCLE_TYP);
00347       this.type_list.push_back(USER_TYP_0);
00348       this.type_list.push_back(USER_TYP_1);
00349       this.type_list.push_back(USER_TYP_2);
00350       this.type_list.push_back(INTERNAL_TYP);
00351 
00352       this.sev_list.push_back(FATAL_SEV);
00353       this.sev_list.push_back(ERROR_SEV);
00354       this.sev_list.push_back(WARNING_SEV);
00355       this.sev_list.push_back(NORMAL_SEV);
00356       this.sev_list.push_back(TRACE_SEV);
00357       this.sev_list.push_back(DEBUG_SEV);
00358       this.sev_list.push_back(VERBOSE_SEV);
00359 
00360       // Define default images
00361       this.type_images[FAILURE_TYP    ] = "FAILURE";
00362       this.type_images[NOTE_TYP       ] = "NOTE";
00363       this.type_images[DEBUG_TYP      ] = "DEBUG";
00364       this.type_images[REPORT_TYP     ] = "REPORT";
00365       this.type_images[NOTIFY_TYP     ] = "NOTIFY";
00366       this.type_images[TIMING_TYP     ] = "TIMING";
00367       this.type_images[XHANDLING_TYP  ] = "XHANDLING";
00368       this.type_images[PROTOCOL_TYP   ] = "PROTOCOL";
00369       this.type_images[TRANSACTION_TYP] = "XACTION";
00370       this.type_images[COMMAND_TYP    ] = "COMMAND";
00371       this.type_images[CYCLE_TYP      ] = "CYCLE";
00372       this.type_images[USER_TYP_0     ] = "USER_0";
00373       this.type_images[USER_TYP_1     ] = "USER_1";
00374       this.type_images[USER_TYP_2     ] = "USER_2";
00375       this.type_images[INTERNAL_TYP   ] = "INTERNAL";
00376 
00377 `ifdef VMM_LOG_ANSI_COLOR
00378       this.sev_images[FATAL_SEV  ] = "\033[41m*FATAL*\033[0m";
00379       this.sev_images[ERROR_SEV  ] = "\033[31m!ERROR!\033[0m";
00380       this.sev_images[WARNING_SEV] = "\033[33mWARNING\033[0m";
00381 `else
00382       this.sev_images[FATAL_SEV  ] = "*FATAL*";
00383       this.sev_images[ERROR_SEV  ] = "!ERROR!";
00384       this.sev_images[WARNING_SEV] = "WARNING";
00385 `endif
00386       this.sev_images[NORMAL_SEV ] = "Normal";
00387       this.sev_images[TRACE_SEV  ] = "Trace";
00388       this.sev_images[DEBUG_SEV  ] = "Debug";
00389       this.sev_images[VERBOSE_SEV] = "Verbose";
00390 
00391 
00392       // Process command-line options
00393       if ($test$plusargs("rvm_log_debug")) begin
00394          this.plus_debug = 1;
00395       end
00396 
00397       begin
00398          bit    plusarg;
00399          string arg;
00400          string level;
00401 
00402          plusarg = $value$plusargs("rvm_log_default=%s", arg);
00403          if (!plusarg) begin
00404             plusarg = $value$plusargs("vmm_log_default=%s", arg);
00405          end
00406          if (plusarg) begin
00407             level = arg.substr(0, 1); // Only look at the 1st 2 chars
00408 
00409             level = level.tolower();
00410             if (level == "er")
00411                this.dflt_lvl = ERROR_SEV;
00412             else if (level == "wa")
00413                this.dflt_lvl = WARNING_SEV;
00414             else if (level == "no")
00415                this.dflt_lvl = NORMAL_SEV;
00416             else if (level == "tr")
00417                this.dflt_lvl = TRACE_SEV;
00418             else if (level == "de")
00419                this.dflt_lvl = DEBUG_SEV;
00420             else if (level == "ve")
00421                this.dflt_lvl = VERBOSE_SEV;
00422             else if (level == "hi")
00423                this.dflt_lvl = HIDDEN_SEV;
00424             else
00425                $write("Warning: Invalid +rvm_log_default specification: \"%s\"\n",
00426                       arg);
00427          end
00428          // Sometimes, VCS screws up static initialization order
00429          else this.dflt_lvl = NORMAL_SEV;
00430 
00431          plusarg = $value$plusargs("rvm_force_verbosity=%s", arg);
00432          if (!plusarg) begin
00433             plusarg = $value$plusargs("vmm_force_verbosity=%s", arg);
00434          end
00435          if (plusarg) begin
00436             level = arg.substr(0, 1); // Only look at the 1st 2 chars
00437 
00438             level = level.tolower();
00439             if (level == "er")
00440               this.force_lvl = ERROR_SEV;
00441             else if (level == "wa")
00442               this.force_lvl = WARNING_SEV;
00443             else if (level == "no")
00444               this.force_lvl = NORMAL_SEV;
00445             else if (level == "tr")
00446               this.force_lvl = TRACE_SEV;
00447             else if (level == "de")
00448               this.force_lvl = DEBUG_SEV;
00449             else if (level == "ve")
00450               this.force_lvl = VERBOSE_SEV;
00451             else if (level == "hi")
00452               this.force_lvl = HIDDEN_SEV;
00453             else
00454               $write("Warning: Invalid +rvm_force_verbosity level: \"%s\"\n",
00455                      arg);
00456          end
00457       end
00458 
00459 `ifdef VCS
00460 `ifdef VCS_SMARTLOG
00461       // Define vmm_log enums in the SmartLog db.
00462       if (this.plus_sml) begin
00463           for (types_e t = t.first; t != t.last; t = t.next) begin
00464               $smartlog(4, t.name, this.typ_image(t), t);
00465           end
00466           for (severities_e s = s.first; s != s.last; s = s.next) begin
00467               $smartlog(3, s.name, this.sev_image(s), s);
00468           end
00469       end
00470 `endif
00471 `endif
00472    end
00473 
00474    this.log_lvl = this.dflt_lvl;
00475    this.log_start(STDOUT);
00476 
00477    //
00478    // Catch a common usage error
00480    if (this.known.size() == 200) begin
00481       if (!$test$plusargs("vmm_log_nowarn_at_200") &&
00482           !$test$plusargs("rvm_log_nowarn_at_200")) begin
00483          if (this.start_msg(FAILURE_TYP, WARNING_SEV)) begin
00484             this.text("Over 200 vmm_log instances have been created.");
00485             this.text("Check that all vmm_data extensions use a static instance");
00486             this.text("or use +vmm_log_nowarn_at_200 to disable this warning.");
00487             this.end_msg();
00488          end
00489       end
00490    end
00491       
00492    if (this.known.size() == 1000) begin
00493       if (!$test$plusargs("vmm_log_nofatal_at_1000") &&
00494           !$test$plusargs("rvm_log_nofatal_at_1000")) begin
00495          if (this.start_msg(FAILURE_TYP, FATAL_SEV)) begin
00496             this.text("Over 1000 vmm_log instances have been created.");
00497             this.text("Check that all vmm_data extensions use a static instance");
00498             this.text("or use +vmm_log_nofatal_at_1000 to disable this failure.");
00499             this.end_msg();
00500          end
00501       end
00502    end
00503 
00504 `ifdef VCS
00505 `ifdef VCS_SMARTLOG
00506    // Define this vmm_log object in the SmartLog db.
00507    if (this.plus_sml) $smartlog(0, this.sml_id, this.name, this.inst);
00508 `endif
00509 `endif
00510 endfunction: new
00511 
00512 
00513 function void vmm_log::is_above(vmm_log log);
00514    if (log == null) return;
00515    this.below.push_back(log);
00516 `ifdef VCS
00517 `ifdef VCS_SMARTLOG
00518    // Define parent-child relation in the SmartLog db.
00519    if (this.plus_sml) $smartlog(8, this.sml_id, log.sml_id);
00520 `endif
00521   `endif
00522 endfunction: is_above
00523 
00524   
00525 function vmm_log vmm_log::copy(vmm_log to);
00526    if (to == null) to = new(this.name, this.inst);
00527    else begin
00528       to.name = this.name;
00529       to.inst = this.inst;
00530    end
00531 
00532    to.enabled_typs = this.enabled_typs;
00533    to.log_lvl      = this.log_lvl;
00534    to.fp           = this.fp;
00535 
00536    copy = to;
00537 endfunction: copy
00538 
00539 
00540 function void vmm_log::set_name(string name);
00541    this.name = name;
00542 endfunction: set_name
00543 
00544   
00545 function string vmm_log::get_name();
00546    get_name = this.name;
00547 endfunction: get_name
00548 
00549   
00550 function void vmm_log::set_instance(string inst);
00551    this.inst = inst;
00552 endfunction: set_instance
00553    
00554 
00555 function string vmm_log::get_instance();
00556    get_instance = this.inst;
00557 endfunction: get_instance
00558    
00559 
00560 function void vmm_log::list(string name,
00561                             string inst,
00562                             bit    recurse);
00563    this.reset(name, inst, recurse);
00564    for (vmm_log log = this.for_each(); log != null; log = this.for_each()) begin   
00565       $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]);
00566       for(int i = 0; i < log.below.size(); i++) begin
00567          $write("  +--- %s(%s)\n", log.below[i].name, log.below[i].inst);
00568       end
00569    end
00570 endfunction: list
00571    
00572 
00573 function void vmm_log::display(string prefix);
00574    $display("%s", this.psdisplay(prefix));
00575 endfunction
00576 
00577 
00578 function string vmm_log::psdisplay(string prefix);
00579    $sformat(psdisplay, "%s%s(%s) [%s]", prefix, this.name, this.inst,
00580             this.sev_image(this.log_lvl));
00581    for (int i = 0; i < this.below.size(); i++) begin
00582       $sformat(psdisplay, "%s\n%s   +--- %s(%s)", psdisplay, prefix,
00583                this.below[i].name, this.below[i].inst);
00584    end
00585    for (int i = 0; i < this.modifier_ids.size(); i++) begin
00586       $sformat(psdisplay, "%s\n%s", psdisplay, this.modifier_cache[this.modifier_ids[i]].psdisplay({prefix, "   "}));
00587    end
00588 endfunction
00589 
00590 
00591 function void vmm_log::kill();
00592    foreach(this.known[i]) begin
00593       if (this.known[i] == this) this.known.delete(i);
00594    end
00595 endfunction: kill
00596 
00597 
00598 function vmm_log_format vmm_log::set_format(vmm_log_format fmt);
00599    if (fmt == null) begin
00600       `vmm_error(this, "Cannot use NULL formatter in vmm_log::set_format(). Unchanged");
00601       return null;
00602    end
00603 
00604    set_format = this.fmt;
00605    this.fmt = fmt;
00606 endfunction: set_format
00607 
00608   
00609 function string vmm_log::set_typ_image(int    typ,
00610                                        string image);
00611    if (!this.type_images.exists(typ)) begin
00612       `vmm_error(this, "Invalid message type specified to vmm_log::set_typ_image()");
00613       return "";
00614    end
00615 
00616    set_typ_image = this.type_images[typ];
00617    this.type_images[typ] = image;
00618 
00619 `ifdef VCS
00620 `ifdef VCS_SMARTLOG
00621    // Redefine image for type in the SmartLog db.
00622    if (this.plus_sml) begin
00623       types_e t;
00624       $cast(t, typ);
00625       $smartlog(4, t.name, image, typ);
00626    end
00627 `endif
00628 `endif
00629 endfunction: set_typ_image
00630    
00631 
00632 function string vmm_log::typ_image(int typ);
00633    string sep = "";
00634 
00635    if (this.type_images.exists(typ)) begin
00636       return this.type_images[typ];
00637    end
00638 
00639    // Special types
00640    if (typ == DEFAULT) begin
00641       return "(default)";
00642    end
00643    if (typ == UNCHANGED) begin
00644       return "(unchanged)";
00645    end
00646 
00647    // Composite type?
00648    typ_image = "";
00649    foreach(this.type_list[i]) begin
00650       if (typ & this.type_list[i]) begin
00651          typ_image = {typ_image, sep, this.type_images[this.type_list[i]]};
00652          sep = "/";
00653       end
00654    end
00655    if (typ_image == "") typ_image = "?MSG_TYP?";
00656 endfunction: typ_image
00657    
00658 
00659 function string vmm_log::set_sev_image(int    severity,
00660                                        string image);
00661    if (!this.sev_images.exists(severity)) begin
00662       `vmm_error(this, "Invalid message severity specified to vmm_log::set_sev_image()");
00663       return "";
00664    end
00665 
00666    set_sev_image = this.sev_images[severity];
00667    this.sev_images[severity] = image;
00668 
00669 `ifdef VCS
00670 `ifdef VCS_SMARTLOG
00671    // Redefine image for severity in the SmartLog db.
00672    if (this.plus_sml) begin
00673       severities_e s;
00674       $cast(s, severity);
00675       $smartlog(3, s.name, image, severity);
00676    end
00677 `endif
00678 `endif
00679 endfunction: set_sev_image
00680 
00681   
00682 function string vmm_log::sev_image(int severity);
00683    string sep = "";
00684 
00685    if (this.sev_images.exists(severity)) begin
00686       return this.sev_images[severity];
00687    end
00688 
00689    // Special severities
00690    if (severity == DEFAULT) begin
00691       return "(default)";
00692    end
00693    if (severity == UNCHANGED) begin
00694       return "(unchanged)";
00695    end
00696    if (severity == IGNORE_SEV) begin
00697       return "(ignored)";
00698    end
00699 
00700    // Composite severity?
00701    sev_image = "";
00702    foreach(this.sev_list[i]) begin
00703       if (severity & this.sev_list[i]) begin
00704          sev_image = {sev_image, sep, this.sev_images[this.sev_list[i]]};
00705          sep = "/";
00706       end
00707    end
00708    if (sev_image == "") sev_image = "?SEV_TYP?";
00709 endfunction: sev_image
00710 
00711 
00712 function string vmm_log::handling_image(int handling);
00713    case (handling)
00714       ABORT_SIM        : handling_image = "ABORT";
00715       COUNT_ERROR      : handling_image = "ERROR";
00716       STOP_PROMPT      : handling_image = "STOP";
00717       DEBUGGER         : handling_image = "DEBUGGER";
00718       DUMP_STACK       : handling_image = "DUMPSTACK";
00719       CONTINUE         : handling_image = "CONTINUE";
00720       IGNORE           : handling_image = "IGNORE";
00721       DEFAULT          : handling_image = "(default)";
00722       UNCHANGED        : handling_image = "(unchanged)";
00723       default          : handling_image = "?HANDLING?";
00724    endcase
00725 endfunction: handling_image
00726 
00727    
00728 function int vmm_log::default_handling(int severity);
00729    case (severity)
00730       FATAL_SEV   : default_handling = ABORT_SIM;
00731       ERROR_SEV   : default_handling = COUNT_ERROR;
00732       default     : default_handling = CONTINUE;
00733    endcase
00734 endfunction: default_handling
00735    
00736 
00737 function void vmm_log::report(string name,
00738                               string inst,
00739                               bit    recurse);
00740    vmm_log log;
00741    int    n_fatals = 0;
00742    int    n_errs   = 0;
00743    int    n_warns  = 0;
00744    int    n_derrs  = 0;
00745    int    n_dwarns = 0;
00746    string msg;
00747 
00748    this.reset(name, inst, recurse);
00749    for(log = this.for_each(); log != null; log = this.for_each()) begin
00750 
00751       n_fatals += log.n_msg[FATAL_SEV];
00752       n_errs   += log.n_msg[ERROR_SEV];
00753       n_warns  += log.n_msg[WARNING_SEV];
00754       n_derrs  += log.n_demoted[ERROR_SEV];
00755       n_dwarns += log.n_demoted[WARNING_SEV];
00756    end
00757 
00758    msg = this.fmt.pass_or_fail(n_fatals == 0 && n_errs == 0,
00759                                name, inst, n_fatals, n_errs, n_warns,
00760                                n_derrs, n_dwarns);
00761    if (msg != "") $display("%s", msg);
00762 endfunction: report
00763    
00764 
00765 function bit vmm_log::start_msg(int typ,
00766                                 int severity);
00767 
00768    if (this.msg != null && !this.msg.invalid && this.msg.issued !== 1'b0) this.end_msg();
00769 
00770    // Provide a default severity if none specified
00771    if (severity < 0) begin
00772       case (typ)
00773          FAILURE_TYP    :  severity = ERROR_SEV;
00774          NOTE_TYP       :  severity = NORMAL_SEV;
00775          DEBUG_TYP      :  severity = DEBUG_SEV;
00776          REPORT_TYP     :  severity = DEBUG_SEV;
00777          NOTIFY_TYP     :  severity = HIDDEN_SEV;
00778          TIMING_TYP     :  severity = WARNING_SEV;
00779          XHANDLING_TYP  :  severity = WARNING_SEV;
00780          PROTOCOL_TYP   :  severity = DEBUG_SEV;
00781          TRANSACTION_TYP:  severity = TRACE_SEV;
00782          COMMAND_TYP    :  severity = TRACE_SEV;
00783          CYCLE_TYP      :  severity = VERBOSE_SEV;
00784          default        :  severity = NORMAL_SEV;
00785       endcase
00786    end
00787 
00788    // Perform a quick, less expensive filtering here for loggers without
00789    // promotion/demotion or watchpoints.  Return immediately if the
00790    // message is not printed based on severity and enabled categories
00791    if (this.modifier_ids.size() == 0 &&
00792        this.watchpoint_ids.size() == 0) begin
00793 
00794       if ((this.force_lvl != DEFAULT_SEV && severity > this.force_lvl) || // Forced?
00795           (this.force_lvl == DEFAULT_SEV && severity > this.log_lvl) ||   // Above?
00796           (!(typ & this.enabled_typs) && (severity >= WARNING_SEV)) // Disabled?
00797           ) begin
00798          this.msg.invalid = 1;
00799          return 0;
00800       end
00801    end
00802 
00803    this.msg.invalid = 0;
00804    this.msg.original_typ = typ;
00805    this.msg.original_severity = severity;
00806    this.msg.effective_typ = typ;
00807    this.msg.effective_severity = severity;
00808    this.msg.flushed = 0;
00809    this.msg.text.delete();
00810    this.msg.handling = DEFAULT;
00811    this.msg.issued = 1'bx;
00812 
00813    start_msg = 1;
00814 
00815    // Do property-based promotion and filtering
00816    // if there are no text-based filters
00817    if (!this.has_text_modifiers) begin
00818       this.promote();
00819       this.filter();
00820 
00821       if (this.msg.issued === 1'b0) begin
00822          start_msg = 0;
00823 
00824          // Record risky demotions
00825          if (this.msg.effective_severity > this.msg.original_severity) begin
00826             case (this.msg.original_severity)
00827                ERROR_SEV  : this.n_demoted[ERROR_SEV]++;
00828                WARNING_SEV: this.n_demoted[WARNING_SEV]++;
00829             endcase
00830          end
00831 
00832          this.msg.invalid = 1;
00833       end
00834    end
00835 endfunction: start_msg
00836    
00837 
00838 function bit vmm_log::text(string msg);
00839    if (this.msg.invalid)
00840    begin
00841       `vmm_error(this, "Malformed message: vmm_log::text() called before vmm_log::start_msg()");
00842       return 0;
00843    end
00844 
00845    text = 1;
00846 
00847    if (msg == "")
00848    begin
00849       this.flush_msg();
00850       return 1;
00851    end
00852 
00853    this.msg.text.push_back(msg);
00854 
00855 endfunction: text
00856    
00857 
00858 function void vmm_log::end_msg();
00859    int handling;
00860 
00861    if (this.msg.invalid)
00862    begin
00863       `vmm_error(this, "Malformed message: vmm_log::end_msg() called before vmm_log::start_msg()");
00864       return;
00865    end
00866 
00867    this.flush_msg();
00868 
00869 `ifdef VCS
00870 `ifdef VCS_SMARTLOG
00871     if (this.plus_sml)
00872     // Mark the end of a VMM message in the SmartLog db.
00873    foreach(this.fp[i]) begin
00874         $smartlog(5, this.fp[i], this.sml_id);
00875     end
00876 `endif
00877 `endif
00878 
00879    handling = this.msg.handling;
00880    if (handling == DEFAULT) handling = default_handling(this.msg.effective_severity);
00881 
00882    // Avoid recursive handling in callbacks
00883    if (this.in_callbacks) handling = CONTINUE;
00884 
00885    case (handling)
00886 
00887      ABORT_SIM: begin
00888         this.in_callbacks = 1;
00889         `vmm_callback(vmm_log_callbacks, pre_abort(this));
00890         this.in_callbacks = 0;
00891         $finish;
00892      end
00893 
00894      DUMP_STACK,
00895      DEBUGGER: begin
00896         this.in_callbacks = 1;
00897         `vmm_callback(vmm_log_callbacks, pre_debug(this));
00898         this.in_callbacks = 0;
00899         $stop;
00900      end
00901 
00902      STOP_PROMPT: begin
00903         this.in_callbacks = 1;
00904         `vmm_callback(vmm_log_callbacks, pre_stop(this));
00905         this.in_callbacks = 0;
00906         $stop;
00907      end
00908 
00909      COUNT_ERROR: begin
00910         this.error_count++;
00911         if (this.error_limit > 0 && this.error_count >= this.error_limit) begin
00912            string msg = this.fmt.abort_on_error(this.error_count,
00913                                                 this.error_limit);
00914            if (msg != "") $display("%s", msg);
00915            this.in_callbacks = 1;
00916            //`vmm_callback(vmm_log_callbacks, pre_abort(this));
00917            do for (int i = 0; i < this.callbacks.size(); i++) begin
00918               vmm_log_callbacks cb;
00919               if (!$cast(cb, this.callbacks[i])) continue;
00920               cb.pre_abort(this);
00921            end while (0);
00922            this.in_callbacks = 0;
00923            $finish;
00924         end                                          
00925      end
00926    endcase
00927 
00928    this.msg.invalid = 1;
00929 endfunction: end_msg
00930 
00931 
00932 function void vmm_log::flush_msg();
00933    string msg;
00934 
00935    if (this.msg.flushed == 0) begin
00936 
00937       // Perform promotion/demotion if there are text filters
00938       // (it will have been done in start_msg() if there were none)
00939       if (this.has_text_modifiers) begin
00940          this.promote();
00941          this.filter();
00942       end
00943       this.notify();
00944 
00945       // Record risky demotions
00946       if (this.msg.effective_severity > this.msg.original_severity) begin
00947          case (this.msg.original_severity)
00948             ERROR_SEV  : this.n_demoted[ERROR_SEV]++;
00949             WARNING_SEV: this.n_demoted[WARNING_SEV]++;
00950          endcase
00951       end
00952 
00953       if (this.msg.issued === 1'b0) return;
00954 
00955 `ifdef VCS
00956 `ifdef VCS_SMARTLOG
00957       // Mark the start of a VMM message in the SmartLog db.
00958       if (this.plus_sml)
00959       foreach(this.fp[i]) begin
00960           $smartlog(9, this.fp[i], this.sml_id,
00961               this.msg.effective_typ,
00962               this.msg.effective_severity);
00963       end
00964 `endif
00965 `endif
00966 
00967       msg = this.fmt.format_msg(this.name, this.inst, 
00968                                 this.typ_image(this.msg.effective_typ),
00969                                 this.sev_image(this.msg.effective_severity),
00970                                 this.msg.text);
00971       foreach(this.fp[i]) begin
00972          $fdisplay(this.fp[i], "%s", msg);
00973       end
00974       // Did we just send an ERROR or FATAL message to /dev/null??
00975       if (this.fp.size() == 0 && this.msg.effective_severity <= ERROR_SEV) begin
00976          // Force it to appear on STDOUT
00977          $display("%s", msg);
00978       end
00979       this.msg.flushed++;
00980       this.msg.text.delete();
00981    end
00982    else begin
00983       if (this.msg.text.size() > 0) begin
00984          msg = this.fmt.continue_msg(this.name, this.inst, 
00985                                      this.typ_image(this.msg.effective_typ),
00986                                      this.sev_image(this.msg.effective_severity),
00987                                      this.msg.text);
00988          foreach(this.fp[i]) begin
00989             $fdisplay(this.fp[i], "%s", msg);
00990          end
00991          // Did we just send an ERROR or FATAL message to /dev/null??
00992          if (this.fp.size() == 0 && this.msg.effective_severity <= ERROR_SEV) begin
00993             // Force it to appear on STDOUT
00994             $display("%s", msg);
00995          end
00996          this.msg.flushed++;
00997          this.msg.text.delete();
00998       end
00999       return;
01000    end
01001 
01002    this.n_msg[this.msg.effective_severity]++;
01003 endfunction: flush_msg
01004 
01005 
01006 function void vmm_log::enable_types(int    typs,
01007                                     string name,
01008                                     string inst,
01009                                     bit    recursive);
01010    if (typs == DEFAULT_TYP ) typs = ALL_TYPS ;
01011    if (typs < 0) begin
01012       `vmm_error(this, "Invalid message type specified to vmm_log::enable_types");
01013       return;
01014    end
01015 
01016    //
01017    // Enable specified types in all specified log insts
01018    //
01019    this.reset(name, inst, recursive);
01020    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01021       log.enabled_typs |= typs;
01022    end
01023 endfunction: enable_types
01024 
01025 
01026 function void vmm_log::disable_types(int    typs,
01027                                      string name,
01028                                      string inst,
01029                                      bit    recursive);
01030    if (typs < 0) begin
01031       `vmm_error(this, "Invalid message type specified to vmm_log::disable_types");
01032       return;
01033    end
01034    // Cannot disable failure messages
01035    if (typs & FAILURE_TYP) begin
01036       `vmm_warning(this, "Cannot disable FAILURE_TYP messages");
01037       typs -= FAILURE_TYP;
01038    end
01039 
01040    //
01041    // Disable specified types in all specified log insts
01042    //
01043    this.reset(name, inst, recursive);
01044    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01045       log.enabled_typs &= ~(typs);
01046    end
01047 endfunction: disable_types
01048 
01049    
01050 function int vmm_log::modify(string name,
01051                              string inst,
01052                              bit    recursive,
01053                              int    typ,
01054                              int    severity,
01055                              string text,
01056                              int    new_typ,
01057                              int    new_severity,
01058                              int    handling);
01059    vmm_log_modifier modifier;
01060    int          mod_id;
01061 
01062    // Some severities cannot be demoted too far
01063    if (severity == FATAL_SEV &&
01064        new_severity > ERROR_SEV) begin
01065       `vmm_error(this, "Cannot demote FATAL_SEV severity to less than ERROR_SEV");
01066       return -2;
01067    end
01068    if (severity == ERROR_SEV &&
01069        new_severity > WARNING_SEV) begin
01070       `vmm_error(this, "Cannot demote ERROR severity to less than WARNING");
01071       return -2;
01072    end
01073 
01074    //
01075    // Add a description of the modification to the cache
01076    //
01077    modifier = new;
01078    modifier.typ          = typ;
01079    modifier.severity     = severity;
01080    modifier.pattern      = text;
01081    modifier.new_typ      = new_typ;
01082    modifier.new_severity = new_severity;
01083    modifier.handling     = handling;
01084 
01085    // Remove "/" surrounding the pattern, if any
01086    if (`vmm_str_match(modifier.pattern, "^/(.*)/$")) begin
01087       modifier.pattern = `vmm_str_backref(modifier.pattern, 0);
01088    end
01089 
01090    mod_id = this.modifier_cache.num();
01091    this.modifier_cache[mod_id] = modifier;
01092 
01093    //
01094    // Link all affected log instances
01095    //
01096    this.reset(name, inst, recursive);
01097    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01098       log.modifier_ids.push_back(mod_id);
01099       if (modifier.pattern != "") log.has_text_modifiers++;
01100    end
01101 
01102    modify = mod_id;
01103 endfunction: modify
01104 
01105 
01106 function void vmm_log::unmodify(int    modification_id,
01107                                 string name,
01108                                 string inst,
01109                                 bit    recursive);
01110    if (modification_id < -1) begin
01111       `vmm_error(this, `vmm_sformatf("Invalid modification ID %0d specified to vmm_log::unmodify()",
01112                                      modification_id));
01113       return;
01114    end
01115 
01116    // Does it exist?
01117    if (modification_id >= 0) begin
01118       if (!this.modifier_cache.exists(modification_id)) begin
01119          `vmm_error(this, `vmm_sformatf("Unknown modification ID %0d specified to vmm_log::unmodify()",
01120                                         modification_id));
01121          return;
01122       end
01123    end
01124    
01125    //
01126    // Unlink all affected log instances
01127    //
01128    this.reset(name, inst, recursive);
01129    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01130 
01131       // Find the specified modifier...
01132       foreach(log.modifier_ids[i]) begin
01133          if (modification_id >= 0 && log.modifier_ids[i] != modification_id) continue;
01134 
01135          if (this.modifier_cache[log.modifier_ids[i]].pattern != "") begin
01136             log.has_text_modifiers--;
01137             if (log.has_text_modifiers < 0) begin
01138                $write("***** vmm_log Internal ERROR: has_text_modifiers < 0\n");
01139                log.has_text_modifiers = 0;
01140             end
01141          end
01142          if (modification_id >= 0) begin
01143             log.modifier_ids.delete(i);
01144             break;
01145          end
01146       end
01147       if (modification_id < 0) log.modifier_ids.delete();
01148    end
01149 endfunction: unmodify
01150 
01151 
01152 function void vmm_log::promote();
01153 
01154    // Apply modifiers in the order they were created
01155    foreach(this.modifier_ids[i]) begin
01156       vmm_log_modifier mod;
01157       
01158       mod = this.modifier_cache[this.modifier_ids[i]];
01159 
01160       // Does it apply to this message?
01161 
01162       // Message type must be included
01163       if (!(mod.typ & this.msg.effective_typ)) continue;
01164 
01165       // Message severity must be included
01166       if (!(mod.severity & this.msg.effective_severity)) continue;
01167 
01168       // If specified, the text pattern must match
01169       if (mod.pattern != "") begin
01170          bit matched = 0;
01171          int idx;
01172          foreach (this.msg.text[idx]) begin
01173             if (`vmm_str_match(this.msg.text[idx], mod.pattern)) begin
01174                matched = 1;
01175                break;
01176             end
01177          end
01178          if (!matched) continue;
01179       end
01180 
01181       // Promote message!
01182       if (mod.new_typ != UNCHANGED) begin
01183          if (mod.new_typ == DEFAULT) begin
01184             this.msg.effective_typ = this.msg.original_typ;
01185          end else begin
01186             this.msg.effective_typ = mod.new_typ;
01187          end
01188       end
01189 
01190       if (mod.new_severity != UNCHANGED) begin
01191          if (mod.new_severity == DEFAULT) begin
01192             this.msg.effective_severity = this.msg.original_severity;
01193          end else begin
01194             this.msg.effective_severity = mod.new_severity;
01195          end
01196          // Some severities cannot be demoted too far
01197          if (this.msg.original_severity == FATAL_SEV &&
01198              this.msg.effective_severity > ERROR_SEV) begin
01199             this.msg.effective_severity = ERROR_SEV ;
01200          end
01201          if (this.msg.original_severity == ERROR_SEV &&
01202              this.msg.effective_severity > WARNING_SEV) begin
01203             this.msg.effective_severity = WARNING_SEV;
01204          end
01205       end
01206 
01207       if (mod.handling != UNCHANGED) begin
01208          this.msg.handling = mod.handling;
01209       end
01210    end
01211 endfunction: promote
01212    
01213 
01214 function void vmm_log::filter();
01215 
01216    if (this.msg.issued === 1'b0 ||  // Already filtered out
01217        this.msg.effective_severity == IGNORE_SEV ||  // Demoted to be ignored
01218        // Cannot disable any types with severity FATAL or ERROR
01219        (!(this.msg.effective_typ & this.enabled_typs) &&     // Disabled
01220         (this.msg.effective_severity >= WARNING_SEV)) ||
01221        (this.force_lvl != DEFAULT_SEV && this.msg.effective_severity > this.force_lvl) ||
01222        (this.force_lvl == DEFAULT_SEV && this.log_lvl < this.msg.effective_severity)) begin
01223       this.msg.issued = 1'b0;
01224 
01225       return;
01226    end
01227 
01228    this.msg.issued = 1'b1;
01229 endfunction: filter
01230    
01231 
01232 function void vmm_log::notify();
01233    // Check notifiers in the order they were created
01234    foreach(this.watchpoint_ids[i]) begin
01235       vmm_log_watchpoint wp;
01236 
01237       wp = this.watchpoint_cache[this.watchpoint_ids[i]];
01238 
01239       // Does it apply to this message?
01240 
01241       // Message type must be included
01242       if (!(wp.typ & this.msg.effective_typ)) continue;
01243 
01244       // Message severity must be included
01245       if (!(wp.severity & this.msg.effective_severity)) continue;
01246 
01247       // The message must be issued or not
01248       if (wp.issued !== 1'bx && wp.issued !== this.msg.issued) begin
01249          continue;
01250       end
01251 
01252       // If specified, the text pattern must match
01253       if (wp.pattern != "") begin
01254          bit matched = 0;
01255          integer idx;
01256          foreach(this.msg.text[idx]) begin
01257             if (`vmm_str_match(this.msg.text[idx], wp.pattern)) begin
01258                matched = 1;
01259                break;
01260             end
01261          end
01262          if (!matched) continue; // to the next watchpt
01263       end
01264 
01265       // This is a watched message
01266       wp.msg = this.msg.copy();
01267       -> wp.seen;
01268    end
01269 endfunction: notify
01270 
01271 
01272 function void vmm_log::set_verbosity(int    severity,
01273                                      string name,
01274                                      string inst,
01275                                      bit    recursive);
01276    if (!this.sev_images.exists(severity) ||
01277        severity < ERROR_SEV ||
01278        severity > VERBOSE_SEV) begin
01279       `vmm_error(this, "Invalid severity specified to vmm_log::set_verbosity()");
01280       return;
01281    end
01282 
01283    this.reset(name, inst, recursive);
01284    for(vmm_log log = this.for_each(); log != null; log = this.for_each()) begin
01285       log.log_lvl = severity;
01286    end
01287 endfunction: set_verbosity
01288    
01289 
01290 function int vmm_log::get_verbosity();
01291    get_verbosity = this.log_lvl;
01292 endfunction: get_verbosity
01293 
01294 
01295 function void vmm_log::log_start(int    file,
01296                                  string name,
01297                                  string inst,
01298                                  bit    recurse);
01299    // Find the loggers in question
01300    vmm_log log;
01301       
01302    this.reset(name, inst, recurse);
01303    for(log = this.for_each(); log != null; log = this.for_each()) begin
01304       
01305       // Check that we are not already logging to this file
01306       foreach(log.fp[i]) begin
01307          if (log.fp[i] == file) return;
01308       end
01309       log.f