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=0);
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 function void vmm_consensus::unregister_all();
00217 foreach (this.voters[i]) begin
00218 vmm_voter voter = this.voters[i];
00219 voter.kill_voter();
00220 end
00221 `ifdef VCS2006_06
00222 // Work-around required by VCS 2006.06
00223 // but IEEE 1800-2009 compliant
00224 this.voters.delete();
00225 `else
00226 // Works in VCS2008.03 or later
00227 // IEEE 1800-2005 compliant
00228 this.voters = '{};
00229 `endif
00230
00231 this.n_dissenters = 0;
00232 this.n_forcing = 0;
00233 endfunction: unregister_all
00234
00235
00236 task vmm_consensus::wait_for_consensus();
00237 wait (this.n_forcing > 0 || this.n_dissenters == 0);
00238 endtask: wait_for_consensus
00239
00240
00241 task vmm_consensus::wait_for_no_consensus();
00242 wait (this.n_forcing == 0 && this.n_dissenters != 0);
00243 endtask: wait_for_no_consensus
00244
00245
00246 function bit vmm_consensus::is_reached();
00247 return this.n_forcing > 0 || this.n_dissenters == 0;
00248 endfunction: is_reached
00249
00250
00251 function bit vmm_consensus::is_forced();
00252 return this.n_forcing > 0;
00253 endfunction: is_forced
00254
00255
00256 function string vmm_consensus::psdisplay(string prefix="");
00257 $sformat(psdisplay, "%sConsensus %s(%s) is %0s", prefix,
00258 this.log.get_name(), this.log.get_instance(),
00259 (this.is_reached() ? (this.is_forced() ? "forced" : "reached")
00260 : "NOT reached"));
00261 if (this.voters.size() == 0) begin
00262 psdisplay = {psdisplay, " by default"};
00263 end
00264 else begin
00265 foreach (this.voters[i]) begin
00266 vmm_consensus subvote;
00267 $sformat(psdisplay, "%s\n%s %s %0s because %s", psdisplay, prefix,
00268 this.voters[i].get_name(),
00269 (this.voters[i].get_vote() ?
00270 (this.voters[i].get_forced() ? "forces" : "consents")
00271 : "opposes"),
00272 this.voters[i].get_reason());
00273 subvote = this.voters[i].get_consensus();
00274 if (subvote != null) begin
00275 psdisplay = {psdisplay, "\n", subvote.psdisplay({prefix, " "})};
00276 end
00277 end
00278 end
00279 endfunction: psdisplay
00280
00281
00282 function void vmm_consensus::yeas(ref string who[],
00283 ref string why[]);
00284 int n = 0;
00285
00286 foreach (this.voters[i]) begin
00287 if (this.voters[i].get_vote()) n++;
00288 end
00289
00290 who = new [n];
00291 why = new [n];
00292
00293 n = 0;
00294 foreach (this.voters[i]) begin
00295 if (this.voters[i].get_vote()) begin
00296 who[n] = this.voters[i].get_name();
00297 why[n] = this.voters[i].get_reason();
00298 n++;
00299 end
00300 end
00301 endfunction: yeas
00302
00303
00304 function void vmm_consensus::nays(ref string who[],
00305 ref string why[]);
00306 int n = 0;
00307
00308 foreach (this.voters[i]) begin
00309 if (!this.voters[i].get_vote()) n++;
00310 end
00311
00312 who = new [n];
00313 why = new [n];
00314
00315 n = 0;
00316 foreach (this.voters[i]) begin
00317 if (!this.voters[i].get_vote()) begin
00318 who[n] = this.voters[i].get_name();
00319 why[n] = this.voters[i].get_reason();
00320 n++;
00321 end
00322 end
00323 endfunction: nays
00324
00325
00326 function void vmm_consensus::forcing(ref string who[],
00327 ref string why[]);
00328 int n = 0;
00329
00330 foreach (this.voters[i]) begin
00331 if (this.voters[i].get_vote() &&
00332 this.voters[i].get_forced()) n++;
00333 end
00334
00335 who = new [n];
00336 why = new [n];
00337
00338 n = 0;
00339 foreach (this.voters[i]) begin
00340 if (this.voters[i].get_vote() &&
00341 this.voters[i].get_forced()) begin
00342 who[n] = this.voters[i].get_name();
00343 why[n] = this.voters[i].get_reason();
00344 n++;
00345 end
00346 end
00347 endfunction: forcing
00348
00349
00350 function void vmm_consensus::XvoteX(bit was_agree,
00351 bit agree,
00352 bit was_forced,
00353 bit forced);
00354 if (agree && !was_agree) begin
00355 this.n_dissenters--;
00356 if (this.n_dissenters == 0) ->this.new_results;
00357 end
00358 else if (!agree && was_agree) begin
00359 if (this.n_dissenters == 0) ->this.new_results;
00360 this.n_dissenters++;
00361 end
00362
00363 if (forced && !was_forced) begin
00364 if (this.n_forcing == 0) ->this.new_results;
00365 this.n_forcing++;
00366 end
00367 else if (!forced && was_forced) begin
00368 this.n_forcing--;
00369 if (this.n_forcing == 0) ->this.new_results;
00370 end
00371
00372 endfunction: XvoteX
00373
00374
00375 function vmm_voter::new(string name,
00376 vmm_consensus vote);
00377 this.name = name;
00378 this.consensus = vote;
00379
00380 this.vote = 0;
00381 this.is_forced = 0;
00382 this.why = "Opposes by default";
00383
00384 this.xactor_voter = null;
00385 this.channel_voter = null;
00386 this.sub_vote = null;
00387 endfunction: new
00388
00389
00390 function void vmm_voter::oppose(string why="No reason specified");
00391 if (this.consensus != null) begin
00392 this.consensus.XvoteX(this.vote, 0, this.is_forced, 0);
00393 end
00394 this.vote = 0;
00395 this.is_forced = 0;
00396 this.why = why;
00397 endfunction: oppose
00398
00399
00400 function void vmm_voter::consent(string why="No reason specified");
00401 if (this.consensus != null) begin
00402 this.consensus.XvoteX(this.vote, 1, this.is_forced, 0);
00403 end
00404 this.vote = 1;
00405 this.is_forced = 0;
00406 this.why = why;
00407 endfunction: consent
00408
00409
00410 function void vmm_voter::forced(string why="No reason specified");
00411 if (this.consensus != null) begin
00412 this.consensus.XvoteX(this.vote, 1, this.is_forced, 1);
00413 end
00414 this.vote = 1;
00415 this.is_forced = 1;
00416 this.why = why;
00417 endfunction: forced
00418
00419
00420 function string vmm_voter::get_name();
00421 return this.name;
00422 endfunction: get_name
00423
00424
00425 function bit vmm_voter::get_vote();
00426 return this.vote;
00427 endfunction: get_vote
00428
00429
00430 function bit vmm_voter::get_forced();
00431 return this.is_forced;
00432 endfunction: get_forced
00433
00434
00435 function string vmm_voter::get_reason();
00436 return this.why;
00437 endfunction: get_reason
00438
00439
00440 function void vmm_voter::xactor(vmm_xactor xact);
00441 this.xactor_voter = xact;
00442 if (xact.notify.is_on(vmm_xactor::XACTOR_BUSY)) begin
00443 this.oppose("Transactor is BUSY");
00444 end
00445 else this.consent("Transactor is IDLE");
00446 fork
00447 begin
00448 fork
00449 begin
00450 // The transactor might have become busy while
00451 // the forked thread was getting started...
00452 if (xact.notify.is_on(vmm_xactor::XACTOR_BUSY)) begin
00453 this.oppose("Transactor is BUSY");
00454 end
00455 forever begin
00456 // Wait for transactor to be IDLE
00457 xact.notify.wait_for(vmm_xactor::XACTOR_IDLE);
00458 this.consent("Transactor is IDLE");
00459 // Prevent an infinite loop
00460 if (xact.notify.is_on(vmm_xactor::XACTOR_BUSY)) begin
00461 `vmm_fatal(this.xactor_voter.log,
00462 "Transactor is indicating both IDLE and BUSY");
00463 end
00464 // Wait for transactor to be BUSY
00465 xact.notify.wait_for(vmm_xactor::XACTOR_BUSY);
00466 this.oppose("Transactor is BUSY");
00467 // Prevent an infinite loop
00468 if (xact.notify.is_on(vmm_xactor::XACTOR_IDLE)) begin
00469 `vmm_fatal(this.xactor_voter.log,
00470 "Transactor is indicating both IDLE and BUSY");
00471 end
00472 end
00473 end
00474 join_none
00475
00476 @(this.killme);
00477 disable fork;
00478 end
00479 join_none
00480 endfunction: xactor
00481
00482
00483 function void vmm_voter::channel(vmm_channel chan);
00484 this.channel_voter = chan;
00485 if (!chan.notify.is_on(vmm_channel::EMPTY)) begin
00486 this.oppose("Channel is not empty");
00487 end
00488 else this.consent("Channel is empty");
00489 fork
00490 begin
00491 fork
00492 forever begin
00493 // Wait for channel to be empty
00494 chan.notify.wait_for(vmm_channel::EMPTY);
00495 this.consent("Channel is empty");
00496 // Wait for channel to be not empty
00497 chan.notify.wait_for_off(vmm_channel::EMPTY);
00498 this.oppose("Channel is not empty");
00499 end
00500 join_none
00501
00502 @(this.killme);
00503 disable fork;
00504 end
00505 join_none
00506 endfunction: channel
00507
00508
00509 function void vmm_voter::notify(vmm_notify ntfy,
00510 int notification,
00511 bit is_on);
00512 this.notify_voter = ntfy;
00513 if (is_on) begin
00514 if (!ntfy.is_on(notification)) begin
00515 this.oppose("Notification is not indicated");
00516 end
00517 else this.consent("Notification is indicated");
00518 end
00519 else begin
00520 if (ntfy.is_on(notification)) begin
00521 this.oppose("Notification is indicated");
00522 end
00523 else this.consent("Notification is not indicated");
00524 end
00525 fork
00526 begin
00527 fork
00528 if (is_on) begin
00529 // Check again as it could have change while
00530 // the thread was forked
00531 if (!ntfy.is_on(notification)) begin
00532 this.oppose("Notification is not indicated");
00533 end
00534 else this.consent("Notification is indicated");
00535
00536 forever begin
00537 // Wait for indication
00538 ntfy.wait_for(notification);
00539 this.consent("Notification is indicated");
00540 // Wait for indication to be reset
00541 ntfy.wait_for_off(notification);
00542 this.oppose("Notification is not indicated");
00543 end
00544 end
00545 if (!is_on) begin
00546 // Check again as it could have change while
00547 // the thread was forked
00548 if (ntfy.is_on(notification)) begin
00549 this.oppose("Notification is indicated");
00550 end
00551 else this.consent("Notification is not indicated");
00552
00553 forever begin
00554 // Wait for indication
00555 ntfy.wait_for_off(notification);
00556 this.consent("Notification is not indicated");
00557 // Wait for indication to be reset
00558 ntfy.wait_for(notification);
00559 this.oppose("Notification is indicated");
00560 end
00561 end
00562 join_none
00563
00564 @(this.killme);
00565 disable fork;
00566 end
00567 join_none
00568 endfunction: notify
00569
00570
00571 function void vmm_voter::sub_consensus(vmm_consensus vote,
00572 bit force_through);
00573 this.sub_vote = vote;
00574 if (!vote.is_reached()) begin
00575 this.oppose("Sub-consensus is not reached");
00576 end
00577 else this.consent("Sub-consensus is reached");
00578
00579 fork
00580 begin
00581 fork
00582 forever begin
00583 if (vote.is_forced() && force_through) begin
00584 this.forced("Sub-consensus forces");
00585 end
00586 else if (vote.is_reached()) this.consent("Sub-consensus consents");
00587 else this.oppose("Sub-consensus opposes");
00588 // Wait for sub-consensus to reach new results
00589 @vote.new_results;
00590 end
00591 join_none
00592
00593 @(this.killme);
00594 disable fork;
00595 end
00596 join_none
00597 endfunction: sub_consensus
00598
00599
00600 function void vmm_voter::kill_voter();
00601 ->this.killme;
00602 this.consensus = null;
00603 endfunction: kill_voter
00604
00605
00606 function vmm_xactor vmm_voter::get_xactor();
00607 return this.xactor_voter;
00608 endfunction: get_xactor
00609
00610
00611 function vmm_channel vmm_voter::get_channel();
00612 return this.channel_voter;
00613 endfunction: get_channel
00614
00615
00616 function vmm_notify vmm_voter::get_notify();
00617 return this.notify_voter;
00618 endfunction: get_notify
00619
00620
00621 function int vmm_voter::get_notification();
00622 return this.notification;
00623 endfunction: get_notification
00624
00625
00626 function vmm_consensus vmm_voter::get_consensus();
00627 return this.sub_vote;
00628 endfunction: get_consensus
00629
00630
00631 `endif // RVM_CONSENSUS__SV