VMM - (expanded) std_lib/vmm_consensus.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.

std_lib/vmm_consensus.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: 
00024: `define VMM_CONSENSUS__SV
00025: 
00026: 
00027: function vmm_consensus::new(string        name,
00028:                             string        inst);
00032: 
00033:    this.log = new(name, inst);
00034: 
00035:    this.n_dissenters = 0;
00036:    this.n_forcing    = 0;
00037: endfunction: new
00038: 
00039: 
00040: function vmm_voter vmm_consensus::register_voter(string name);
00041:    vmm_voter voter = new(name, this);
00042: 
00043:    // Voters object by default
00044:    this.n_dissenters++;
00045: 
00046:    this.voters.push_back(voter);
00047: 
00048:    return voter;
00049: endfunction: register_voter
00050: 
00051: 
00052: function void vmm_consensus::unregister_voter(vmm_voter voter);
00053:    foreach (this.voters[i]) begin
00054:       if (this.voters[i] == voter) begin
00055:          if (!voter.get_vote()) voter.consent("Dead voter consents by default");
00056:          voter.kill_voter();
00057:          this.voters.delete(i);
00058:          return;
00059:       end
00060:    end
00061:    
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text({voter.get_name(), " is not a registered voter"})); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00062: endfunction: unregister_voter
00063: 
00064: 
00065: function void vmm_consensus::register_xactor(vmm_xactor xact);
00066:    vmm_voter voter = this.register_voter({"Transactor ", xact.get_name(),
00067:                                           "(", xact.get_instance(), ")"});
00068:    voter.xactor(xact);
00069: endfunction: register_xactor
00070: 
00071: 
00072: function void vmm_consensus::unregister_xactor(vmm_xactor xact);
00073:    foreach (this.voters[i]) begin
00074:       vmm_voter voter = this.voters[i];
00075:       if (voter.get_xactor() == xact) begin
00076:          if (!voter.get_vote()) voter.consent("Dead voter consents by default");
00077:          voter.kill_voter();
00078:          this.voters.delete(i);
00079:          return;
00080:       end
00081:    end
00083: 
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text({"Transactor ", xact.get_name(), "(",
     :                          xact.get_instance(), ") is not a registered voter"})); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00084: endfunction: unregister_xactor
00085: 
00086: 
00087: function void vmm_consensus::register_channel(vmm_channel chan);
00088:    vmm_voter voter = this.register_voter({"Channel ",
00089:                                           chan.log.get_name(), "(",
00090:                                           chan.log.get_instance(), ")"});
00091:    voter.channel(chan);
00092: endfunction: register_channel
00093: 
00094: 
00095: function void vmm_consensus::unregister_channel(vmm_channel chan);
00096:    foreach (this.voters[i]) begin
00097:       vmm_voter voter = this.voters[i];
00098:       if (voter.get_channel() == chan) begin
00099:          if (!voter.get_vote()) voter.consent("Dead voter consents by default");
00100:          voter.kill_voter();
00101:          this.voters.delete(i);
00102:          return;
00103:       end
00104:    end
00107: 
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text({"Channel ", chan.log.get_name(), "(",
     :                          chan.log.get_instance(),
     :                          ") is not a registered voter"})); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00108: endfunction: unregister_channel
00109: 
00110: 
00111: function void vmm_consensus::register_notification(vmm_notify notify,
00112:                                                    int notification);
00113: 
00114:    vmm_voter voter;
00115:    string    name;
00116:    int       mode;
00117: 
00118:    if (notify == null) begin
00119:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text("Cannot register NULL vmm_notify reference")); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00120:       return;
00121:    end
00122: 
00123:    mode = notify.is_configured(notification);
00124:    if (!mode) begin
00125:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text("Cannot register unconfigured notification")); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00126:       return;
00127:    end
00128:    if (mode != vmm_notify::ON_OFF) begin
00129:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text("Can only register ON_OFF notification")); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00130:       return;
00131:    end
00132: 
00133:    $sformat(name, "Notification #%0d %s(%s)",
00134:             notification, notify.log.get_name(),
00135:             notify.log.get_instance());
00136:    voter = this.register_voter(name);
00137:    voter.notify(notify, notification, 1);
00138: endfunction: register_notification
00139: 
00140: 
00141: function void vmm_consensus::register_no_notification(vmm_notify notify,
00142:                                                       int notification);
00143: 
00144:    vmm_voter voter;
00145:    string    name;
00146:    int       mode;
00147: 
00148:    if (notify == null) begin
00149:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text("Cannot register NULL vmm_notify reference")); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00150:       return;
00151:    end
00152: 
00153:    mode = notify.is_configured(notification);
00154:    if (!mode) begin
00155:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text("Cannot register unconfigured notification")); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00156:       return;
00157:    end
00158:    if (mode != vmm_notify::ON_OFF) begin
00159:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text("Can only register ON_OFF notification")); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00160:       return;
00161:    end
00162: 
00163:    $sformat(name, "Notification #%0d %s(%s)",
00164:             notification, notify.log.get_name(),
00165:             notify.log.get_instance());
00166:    voter = this.register_voter(name);
00167:    voter.notify(notify, notification, 0);
00168: endfunction: register_no_notification
00169: 
00170: 
00171: function void vmm_consensus::unregister_notification(vmm_notify notify,
00172:                                                      int notification);
00173:    foreach (this.voters[i]) begin
00174:       vmm_voter voter = this.voters[i];
00175:       if (voter.get_notify() == notify &&
00176:           voter.get_notification() == notification) begin
00177:          if (!voter.get_vote()) voter.consent("Dead voter consents by default");
00178:          voter.kill_voter();
00179:          this.voters.delete(i);
00180:          return;
00181:       end
00182:    end
00183:    begin
00184:       string msg;
00185:       $sformat(msg, "Notification #%0d %s(%s)",
00186:                notification, notify.log.get_name(),
00187:                notify.log.get_instance());
00188:       
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text(msg)); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00189:    end
00190: endfunction: unregister_notification
00191: 
00192: 
00193: function void vmm_consensus::register_consensus(vmm_consensus vote,
00194:                                                 bit force_through);
00195:    vmm_voter voter = this.register_voter({"Consensus ",
00196:                                           vote.log.get_instance()});
00197:    voter.sub_consensus(vote, force_through);
00198: endfunction: register_consensus
00199: 
00200: 
00201: function void vmm_consensus::unregister_consensus(vmm_consensus vote);
00202:    foreach (this.voters[i]) begin
00203:       vmm_voter voter = this.voters[i];
00204:       if (voter.get_consensus() == vote) begin
00205:          if (!voter.get_vote()) voter.consent("Dead voter consents by default");
00206:          voter.kill_voter();
00207:          this.voters.delete(i);
00208:          return;
00209:       end
00210:    end
00212: 
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text({"Consensus ", vote.log.get_instance(),
     :                          " is not a registered voter"})); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00213: endfunction: unregister_consensus
00214: 
00215: 
00216: task vmm_consensus::wait_for_consensus();
00217:    wait (this.n_forcing > 0 || this.n_dissenters == 0);
00218: endtask: wait_for_consensus
00219: 
00220: 
00221: task vmm_consensus::wait_for_no_consensus();
00222:    wait (this.n_forcing == 0 && this.n_dissenters != 0);
00223: endtask: wait_for_no_consensus
00224: 
00225: 
00226: function bit vmm_consensus::is_reached();
00227:    return this.n_forcing > 0 || this.n_dissenters == 0;
00228: endfunction: is_reached
00229: 
00230: 
00231: function bit vmm_consensus::is_forced();
00232:    return this.n_forcing > 0;
00233: endfunction: is_forced
00234: 
00235: 
00236: function string vmm_consensus::psdisplay(string prefix);
00237:    $sformat(psdisplay, "%sConsensus %s(%s) is %0s", prefix,
00238:             this.log.get_name(), this.log.get_instance(),
00239:             (this.is_reached() ? (this.is_forced() ? "forced" : "reached")
00240:                                : "NOT reached"));
00241:    if (this.voters.size() == 0) begin
00242:       psdisplay = {psdisplay, " by default"};
00243:    end
00244:    else begin
00245:       foreach (this.voters[i]) begin
00246:          vmm_consensus subvote;
00247:          $sformat(psdisplay, "%s\n%s   %s %0s because %s", psdisplay, prefix,
00248:                   this.voters[i].get_name(),
00249:                   (this.voters[i].get_vote() ?
00250:                    (this.voters[i].get_forced() ? "forces" : "consents")
00251:                    : "opposes"),
00252:                   this.voters[i].get_reason());
00253:          subvote = this.voters[i].get_consensus();
00254:          if (subvote != null) begin
00255:             psdisplay = {psdisplay, "\n", subvote.psdisplay({prefix, "      "})};
00256:          end
00257:       end
00258:    end
00259: endfunction: psdisplay
00260: 
00261: 
00262: function void vmm_consensus::yeas(ref string who[],
00263:                                   ref string why[]);
00264:    int n = 0;
00265: 
00266:    foreach (this.voters[i]) begin
00267:       if (this.voters[i].get_vote()) n++;
00268:    end
00269: 
00270:    who = new [n];
00271:    why = new [n];
00272: 
00273:    n = 0;
00274:    foreach (this.voters[i]) begin
00275:       if (this.voters[i].get_vote()) begin
00276:          who[n] = this.voters[i].get_name();
00277:          why[n] = this.voters[i].get_reason();
00278:          n++;
00279:       end
00280:    end
00281: endfunction: yeas
00282: 
00283: 
00284: function void vmm_consensus::nays(ref string who[],
00285:                                   ref string why[]);
00286:    int n = 0;
00287: 
00288:    foreach (this.voters[i]) begin
00289:       if (!this.voters[i].get_vote()) n++;
00290:    end
00291: 
00292:    who = new [n];
00293:    why = new [n];
00294: 
00295:    n = 0;
00296:    foreach (this.voters[i]) begin
00297:       if (!this.voters[i].get_vote()) begin
00298:          who[n] = this.voters[i].get_name();
00299:          why[n] = this.voters[i].get_reason();
00300:          n++;
00301:       end
00302:    end
00303: endfunction: nays
00304: 
00305: 
00306: function void vmm_consensus::forcing(ref string who[],
00307:                                      ref string why[]);
00308:    int n = 0;
00309: 
00310:    foreach (this.voters[i]) begin
00311:       if (this.voters[i].get_vote() &&
00312:           this.voters[i].get_forced()) n++;
00313:    end
00314: 
00315:    who = new [n];
00316:    why = new [n];
00317: 
00318:    n = 0;
00319:    foreach (this.voters[i]) begin
00320:       if (this.voters[i].get_vote() &&
00321:           this.voters[i].get_forced()) begin
00322:          who[n] = this.voters[i].get_name();
00323:          why[n] = this.voters[i].get_reason();
00324:          n++;
00325:       end
00326:    end
00327: endfunction: forcing
00328:    
00329: 
00330: function void vmm_consensus::XvoteX(bit was_agree,
00331:                                     bit agree,
00332:                                     bit was_forced,
00333:                                     bit forced);
00334:    if (agree && !was_agree) begin
00335:       this.n_dissenters--;
00336:       if (this.n_dissenters == 0) ->this.new_results;
00337:    end
00338:    else if (!agree && was_agree) begin
00339:       if (this.n_dissenters == 0) ->this.new_results;
00340:       this.n_dissenters++;
00341:    end
00342: 
00343:    if (forced && !was_forced) begin
00344:       if (this.n_forcing == 0) ->this.new_results;
00345:       this.n_forcing++;
00346:    end
00347:    else if (!forced && was_forced) begin
00348:       this.n_forcing--;
00349:       if (this.n_forcing == 0) ->this.new_results;
00350:    end
00351: 
00352: endfunction: XvoteX
00353: 
00354: 
00355: function vmm_voter::new(string        name,
00356:                         vmm_consensus vote);
00357:    this.name      = name;
00358:    this.consensus = vote;
00359: 
00360:    this.vote      = 0;
00361:    this.is_forced = 0;
00362:    this.why       = "Opposes by default";
00363: 
00364:    this.xactor_voter = null;
00365:    this.channel_voter = null;
00366:    this.sub_vote = null;
00367: endfunction: new
00368: 
00369: 
00370: function void vmm_voter::oppose(string why);
00371:    if (this.consensus != null) begin
00372:       this.consensus.XvoteX(this.vote, 0, this.is_forced, 0);
00373:    end
00374:    this.vote = 0;
00375:    this.is_forced = 0;
00376:    this.why = why;
00377: endfunction: oppose
00378: 
00379: 
00380: function void vmm_voter::consent(string why);
00381:    if (this.consensus != null) begin
00382:       this.consensus.XvoteX(this.vote, 1, this.is_forced, 0);
00383:    end
00384:    this.vote = 1;
00385:    this.is_forced = 0;
00386:    this.why = why;
00387: endfunction: consent
00388: 
00389: 
00390: function void vmm_voter::forced(string why);
00391:    if (this.consensus != null) begin
00392:       this.consensus.XvoteX(this.vote, 1, this.is_forced, 1);
00393:    end
00394:    this.vote = 1;
00395:    this.is_forced = 1;
00396:    this.why = why;
00397: endfunction: forced
00398: 
00399: 
00400: function string vmm_voter::get_name();
00401:    return this.name;
00402: endfunction: get_name
00403: 
00404: 
00405: function bit vmm_voter::get_vote();
00406:    return this.vote;
00407: endfunction: get_vote
00408: 
00409: 
00410: function bit vmm_voter::get_forced();
00411:    return this.is_forced;
00412: endfunction: get_forced
00413: 
00414: 
00415: function string vmm_voter::get_reason();
00416:    return this.why;
00417: endfunction: get_reason
00418: 
00419: 
00420: function void vmm_voter::xactor(vmm_xactor xact);
00421:    this.xactor_voter = xact;
00422:    if (xact.notify.is_on(vmm_xactor::XACTOR_BUSY)) begin
00423:       this.oppose("Transactor is BUSY");
00424:    end
00425:    else this.consent("Transactor is IDLE");
00426:    fork
00427:       begin
00428:          fork
00429:             begin
00430:                // The transactor might have become busy while
00431:                // the forked thread was getting started...
00432:                if (xact.notify.is_on(vmm_xactor::XACTOR_BUSY)) begin
00433:                   this.oppose("Transactor is BUSY");
00434:                end
00435:                forever begin
00436:                   // Wait for transactor to be IDLE
00437:                   xact.notify.wait_for(vmm_xactor::XACTOR_IDLE);
00438:                   this.consent("Transactor is IDLE");
00439:                   // Prevent an infinite loop
00440:                   if (xact.notify.is_on(vmm_xactor::XACTOR_BUSY)) begin
00442: 
     : do 
     :    if (this.xactor_voter.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin 
     :       void'(this.xactor_voter.log.text("Transactor is indicating both IDLE and BUSY")); 
     :       this.xactor_voter.log.end_msg(); 
     :    end 
     : while (0);
00443:                   end
00444:                   // Wait for transactor to be BUSY
00445:                   xact.notify.wait_for(vmm_xactor::XACTOR_BUSY);
00446:                   this.oppose("Transactor is BUSY");
00447:                   // Prevent an infinite loop
00448:                   if (xact.notify.is_on(vmm_xactor::XACTOR_IDLE)) begin
00450: 
     : do 
     :    if (this.xactor_voter.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin 
     :       void'(this.xactor_voter.log.text("Transactor is indicating both IDLE and BUSY")); 
     :       this.xactor_voter.log.end_msg(); 
     :    end 
     : while (0);
00451:                   end
00452:                end
00453:             end
00454:          join_none
00455: 
00456:          @(this.killme);
00457:          disable fork;
00458:       end
00459:    join_none
00460: endfunction: xactor
00461: 
00462: 
00463: function void vmm_voter::channel(vmm_channel chan);
00464:    this.channel_voter = chan;
00465:    if (!chan.notify.is_on(vmm_channel::EMPTY)) begin
00466:       this.oppose("Channel is not empty");
00467:    end
00468:    else this.consent("Channel is empty");
00469:    fork
00470:       begin
00471:          fork
00472:             forever begin
00473:                // Wait for channel to be empty
00474:                chan.notify.wait_for(vmm_channel::EMPTY);
00475:                this.consent("Channel is empty");
00476:                // Wait for channel to be not empty
00477:                chan.notify.wait_for_off(vmm_channel::EMPTY);
00478:                this.oppose("Channel is not empty");
00479:             end
00480:          join_none
00481: 
00482:          @(this.killme);
00483:          disable fork;
00484:       end
00485:    join_none
00486: endfunction: channel
00487: 
00488: 
00489: function void vmm_voter::notify(vmm_notify ntfy,
00490:                                 int notification,
00491:                                 bit is_on);
00492:    this.notify_voter = ntfy;
00493:    if (is_on) begin
00494:       if (!ntfy.is_on(notification)) begin
00495:          this.oppose("Notification is not indicated");
00496:       end
00497:       else this.consent("Notification is indicated");
00498:    end
00499:    else begin
00500:       if (ntfy.is_on(notification)) begin
00501:          this.oppose("Notification is indicated");
00502:       end
00503:       else this.consent("Notification is not indicated");
00504:    end
00505:    fork
00506:       begin
00507:          fork
00508:             if (is_on) forever begin
00509:                // Wait for indication
00510:                ntfy.wait_for(notification);
00511:                this.consent("Notification is indicated");
00512:                // Wait for indication to be reset
00513:                ntfy.wait_for_off(notification);
00514:                this.oppose("Notification is not indicated");
00515:             end
00516:             if (!is_on) forever begin
00517:                // Wait for indication
00518:                ntfy.wait_for_off(notification);
00519:                this.consent("Notification is not indicated");
00520:                // Wait for indication to be reset
00521:                ntfy.wait_for(notification);
00522:                this.oppose("Notification is indicated");
00523:             end
00524:          join_none
00525: 
00526:          @(this.killme);
00527:          disable fork;
00528:       end
00529:    join_none
00530: endfunction: notify
00531: 
00532: 
00533: function void vmm_voter::sub_consensus(vmm_consensus vote,
00534:                                        bit force_through);
00535:    this.sub_vote = vote;
00536:    if (!vote.is_reached()) begin
00537:       this.oppose("Sub-consensus is not reached");
00538:    end
00539:    else this.consent("Sub-consensus is reached");
00540: 
00541:    fork
00542:       begin
00543:          fork
00544:             forever begin
00545:                if (vote.is_forced() && force_through) begin
00546:                   this.forced("Sub-consensus forces");
00547:                end
00548:                else if (vote.is_reached()) this.consent("Sub-consensus consents");
00549:                else this.oppose("Sub-consensus opposes");
00550:                // Wait for sub-consensus to reach new results
00551:                @vote.new_results;
00552:             end
00553:          join_none
00554: 
00555:          @(this.killme);
00556:          disable fork;
00557:       end
00558:    join_none
00559: endfunction: sub_consensus
00560: 
00561: 
00562: function void vmm_voter::kill_voter();
00563:    ->this.killme;
00564:    this.consensus = null;
00565: endfunction: kill_voter
00566: 
00567: 
00568: function vmm_xactor vmm_voter::get_xactor();
00569:    return this.xactor_voter;
00570: endfunction: get_xactor
00571: 
00572: 
00573: function vmm_channel vmm_voter::get_channel();
00574:    return this.channel_voter;
00575: endfunction: get_channel
00576: 
00577: 
00578: function vmm_notify vmm_voter::get_notify();
00579:    return this.notify_voter;
00580: endfunction: get_notify
00581: 
00582: 
00583: function int vmm_voter::get_notification();
00584:    return this.notification;
00585: endfunction: get_notification
00586: 
00587: 
00588: function vmm_consensus vmm_voter::get_consensus();
00589:    return this.sub_vote;
00590: endfunction: get_consensus
00591: 
00592: