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