VMM - std_lib/vmm_consensus.sv

std_lib/vmm_consensus.sv expanded 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 
00023 `ifndef VMM_CONSENSUS__SV
00024 `define VMM_CONSENSUS__SV
00025 
00026 
00027 function vmm_consensus::new(string        name,
00028                             string        inst);
00029 `ifdef VMM_CONSENSUS_BASE_NEW_CALL
00030    super.new(`VMM_CONSENSUS_BASE_NEW_CALL);
00031 `endif
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    `vmm_error(this.log, {voter.get_name(), " is not a registered voter"});
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
00082    `vmm_error(this.log, {"Transactor ", xact.get_name(), "(",
00083                          xact.get_instance(), ") is not a registered voter"});
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
00105    `vmm_error(this.log, {"Channel ", chan.log.get_name(), "(",
00106                          chan.log.get_instance(),
00107                          ") is not a registered voter"});
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       `vmm_error(this.log, "Cannot register NULL vmm_notify reference");
00120       return;
00121    end
00122 
00123    mode = notify.is_configured(notification);
00124    if (!mode) begin
00125       `vmm_error(this.log, "Cannot register unconfigured notification");
00126       return;
00127    end
00128    if (mode != vmm_notify::ON_OFF) begin
00129       `vmm_error(this.log, "Can only register ON_OFF notification");
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       `vmm_error(this.log, "Cannot register NULL vmm_notify reference");
00150       return;
00151    end
00152 
00153    mode = notify.is_configured(notification);
00154    if (!mode) begin
00155       `vmm_error(this.log, "Cannot register unconfigured notification");
00156       return;
00157    end
00158    if (mode != vmm_notify::ON_OFF) begin
00159       `vmm_error(this.log, "Can only register ON_OFF notification");
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       `vmm_error(this.log, msg);
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
00211    `vmm_error(this.log, {"Consensus ", vote.log.get_instance(),
00212                          " is not a registered voter"});
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
00441                      `vmm_fatal(this.xactor_voter.log,
00442                                 "Transactor is indicating both IDLE and BUSY");
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
00449                      `vmm_fatal(this.xactor_voter.log,
00450                                 "Transactor is indicating both IDLE and BUSY");
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 
00593 `endif // RVM_CONSENSUS__SV