VMM OpenSource - (expanded) sv/std_lib/vmm_log.sv

Expanded versions of source files are the output of the preprocessor. Lines subject to conditional compilation are not shown and all compiler pragmas have been stripped. Macros have been completely expanded.

sv/std_lib/vmm_log.sv unexpanded source

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