113511Sgabeblack@google.com/* 213511Sgabeblack@google.com * Copyright 2018 Google, Inc. 313511Sgabeblack@google.com * 413511Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 513511Sgabeblack@google.com * modification, are permitted provided that the following conditions are 613511Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 713511Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 813511Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 913511Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 1013511Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 1113511Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 1213511Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 1313511Sgabeblack@google.com * this software without specific prior written permission. 1413511Sgabeblack@google.com * 1513511Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1613511Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1713511Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1813511Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1913511Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2013513Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2113513Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2213511Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2313513Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2413511Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2513586Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2613586Sgabeblack@google.com * 2713586Sgabeblack@google.com * Authors: Gabe Black 2813586Sgabeblack@google.com */ 2913586Sgabeblack@google.com 3013743Sgabeblack@google.com#include "systemc/core/scheduler.hh" 3113586Sgabeblack@google.com 3213513Sgabeblack@google.com#include "base/fiber.hh" 3313513Sgabeblack@google.com#include "base/logging.hh" 3413511Sgabeblack@google.com#include "sim/eventq.hh" 3513511Sgabeblack@google.com#include "sim/sim_exit.hh" 3613511Sgabeblack@google.com#include "systemc/core/kernel.hh" 3713511Sgabeblack@google.com#include "systemc/core/sc_main_fiber.hh" 3813513Sgabeblack@google.com#include "systemc/ext/core/messages.hh" 3913513Sgabeblack@google.com#include "systemc/ext/core/sc_main.hh" 4013513Sgabeblack@google.com#include "systemc/ext/utils/sc_report.hh" 4113513Sgabeblack@google.com#include "systemc/ext/utils/sc_report_handler.hh" 4213513Sgabeblack@google.com#include "systemc/utils/report.hh" 4313513Sgabeblack@google.com#include "systemc/utils/tracefile.hh" 4413513Sgabeblack@google.com 4513513Sgabeblack@google.comnamespace sc_gem5 4613513Sgabeblack@google.com{ 4713513Sgabeblack@google.com 4813513Sgabeblack@google.comScheduler::Scheduler() : 4913513Sgabeblack@google.com eq(nullptr), readyEvent(this, false, ReadyPriority), 5013511Sgabeblack@google.com pauseEvent(this, false, PausePriority), 5113513Sgabeblack@google.com stopEvent(this, false, StopPriority), _throwUp(nullptr), 5213513Sgabeblack@google.com starvationEvent(this, false, StarvationPriority), 5313513Sgabeblack@google.com _elaborationDone(false), _started(false), _stopNow(false), 5413513Sgabeblack@google.com _status(StatusOther), maxTick(::MaxTick), 5513511Sgabeblack@google.com maxTickEvent(this, false, MaxTickPriority), 5613513Sgabeblack@google.com timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0), 5713513Sgabeblack@google.com _changeStamp(0), _current(nullptr), initDone(false), runToTime(true), 5813513Sgabeblack@google.com runOnce(false) 5913511Sgabeblack@google.com{} 6013513Sgabeblack@google.com 6113513Sgabeblack@google.comScheduler::~Scheduler() 6213513Sgabeblack@google.com{ 6313513Sgabeblack@google.com // Clear out everything that belongs to us to make sure nobody tries to 6413513Sgabeblack@google.com // clear themselves out after the scheduler goes away. 6513513Sgabeblack@google.com clear(); 6613513Sgabeblack@google.com} 6713513Sgabeblack@google.com 6813513Sgabeblack@google.comvoid 6913511Sgabeblack@google.comScheduler::clear() 7013511Sgabeblack@google.com{ 7113513Sgabeblack@google.com // Delta notifications. 7213513Sgabeblack@google.com while (!deltas.empty()) 7313513Sgabeblack@google.com deltas.front()->deschedule(); 7413513Sgabeblack@google.com 7513513Sgabeblack@google.com // Timed notifications. 7613513Sgabeblack@google.com for (auto &tsp: timeSlots) { 7713513Sgabeblack@google.com TimeSlot *&ts = tsp.second; 7813511Sgabeblack@google.com while (!ts->events.empty()) 7913513Sgabeblack@google.com ts->events.front()->deschedule(); 8013513Sgabeblack@google.com deschedule(ts); 8113513Sgabeblack@google.com } 8213513Sgabeblack@google.com timeSlots.clear(); 8313513Sgabeblack@google.com 8413513Sgabeblack@google.com // gem5 events. 8513513Sgabeblack@google.com if (readyEvent.scheduled()) 8613513Sgabeblack@google.com deschedule(&readyEvent); 8713513Sgabeblack@google.com if (pauseEvent.scheduled()) 8813513Sgabeblack@google.com deschedule(&pauseEvent); 8913513Sgabeblack@google.com if (stopEvent.scheduled()) 9013513Sgabeblack@google.com deschedule(&stopEvent); 9113513Sgabeblack@google.com if (starvationEvent.scheduled()) 9213513Sgabeblack@google.com deschedule(&starvationEvent); 9313513Sgabeblack@google.com if (maxTickEvent.scheduled()) 9413513Sgabeblack@google.com deschedule(&maxTickEvent); 9513513Sgabeblack@google.com if (timeAdvancesEvent.scheduled()) 9613513Sgabeblack@google.com deschedule(&timeAdvancesEvent); 9713513Sgabeblack@google.com 9813513Sgabeblack@google.com Process *p; 9913513Sgabeblack@google.com while ((p = initList.getNext())) 10013513Sgabeblack@google.com p->popListNode(); 10113513Sgabeblack@google.com while ((p = readyListMethods.getNext())) 10213513Sgabeblack@google.com p->popListNode(); 10313513Sgabeblack@google.com while ((p = readyListThreads.getNext())) 10413513Sgabeblack@google.com p->popListNode(); 10513513Sgabeblack@google.com 10613513Sgabeblack@google.com Channel *c; 10713511Sgabeblack@google.com while ((c = updateList.getNext())) 10813513Sgabeblack@google.com c->popListNode(); 10913513Sgabeblack@google.com} 11013513Sgabeblack@google.com 11113513Sgabeblack@google.comvoid 11213513Sgabeblack@google.comScheduler::initPhase() 11313513Sgabeblack@google.com{ 11413513Sgabeblack@google.com runUpdate(); 11513513Sgabeblack@google.com 11613513Sgabeblack@google.com for (Process *p = initList.getNext(); p; p = initList.getNext()) { 11713513Sgabeblack@google.com p->popListNode(); 11813513Sgabeblack@google.com 11913511Sgabeblack@google.com if (p->dontInitialize()) { 12013511Sgabeblack@google.com if (!p->hasStaticSensitivities() && !p->internal()) { 12113513Sgabeblack@google.com SC_REPORT_WARNING(sc_core::SC_ID_DISABLE_WILL_ORPHAN_PROCESS_, 12213513Sgabeblack@google.com p->name()); 12313513Sgabeblack@google.com } 12413513Sgabeblack@google.com } else { 12513513Sgabeblack@google.com p->ready(); 12613511Sgabeblack@google.com } 12713511Sgabeblack@google.com } 12813511Sgabeblack@google.com 12913511Sgabeblack@google.com runDelta(); 13013511Sgabeblack@google.com 13113511Sgabeblack@google.com for (auto ets: eventsToSchedule) 13213511Sgabeblack@google.com eq->schedule(ets.first, ets.second); 13313511Sgabeblack@google.com eventsToSchedule.clear(); 13413513Sgabeblack@google.com 13513513Sgabeblack@google.com if (_started) { 13613511Sgabeblack@google.com if (!runToTime && starved()) 13713513Sgabeblack@google.com scheduleStarvationEvent(); 13813513Sgabeblack@google.com kernel->status(::sc_core::SC_RUNNING); 13913513Sgabeblack@google.com } 14013513Sgabeblack@google.com 14113511Sgabeblack@google.com initDone = true; 14213513Sgabeblack@google.com 14313513Sgabeblack@google.com status(StatusOther); 14413513Sgabeblack@google.com 14513513Sgabeblack@google.com scheduleTimeAdvancesEvent(); 14613513Sgabeblack@google.com} 14713513Sgabeblack@google.com 14813513Sgabeblack@google.comvoid 14913513Sgabeblack@google.comScheduler::reg(Process *p) 15013511Sgabeblack@google.com{ 15113513Sgabeblack@google.com if (initDone) { 15213513Sgabeblack@google.com // If not marked as dontInitialize, mark as ready. 15313513Sgabeblack@google.com if (!p->dontInitialize()) 15413513Sgabeblack@google.com p->ready(); 15513513Sgabeblack@google.com } else { 15613513Sgabeblack@google.com // Otherwise, record that this process should be initialized once we 15713513Sgabeblack@google.com // get there. 15813513Sgabeblack@google.com initList.pushLast(p); 15913513Sgabeblack@google.com } 16013513Sgabeblack@google.com} 16113513Sgabeblack@google.com 16213513Sgabeblack@google.comvoid 16313513Sgabeblack@google.comScheduler::yield() 16413513Sgabeblack@google.com{ 16513513Sgabeblack@google.com // Pull a process from the active list. 16613513Sgabeblack@google.com _current = getNextReady(); 16713513Sgabeblack@google.com if (!_current) { 16813513Sgabeblack@google.com // There are no more processes, so return control to evaluate. 16913513Sgabeblack@google.com Fiber::primaryFiber()->run(); 17013513Sgabeblack@google.com } else { 17113513Sgabeblack@google.com _current->popListNode(); 17213513Sgabeblack@google.com _current->scheduled(false); 17313513Sgabeblack@google.com // Switch to whatever Fiber is supposed to run this process. All 17413513Sgabeblack@google.com // Fibers which aren't running should be parked at this line. 17513513Sgabeblack@google.com _current->fiber()->run(); 17613513Sgabeblack@google.com // If the current process needs to be manually started, start it. 17713511Sgabeblack@google.com if (_current && _current->needsStart()) { 17813513Sgabeblack@google.com _current->needsStart(false); 17913513Sgabeblack@google.com // If a process hasn't started yet, "resetting" it just starts it 18013513Sgabeblack@google.com // and signals its reset event. 18113513Sgabeblack@google.com if (_current->inReset()) 18213513Sgabeblack@google.com _current->resetEvent().notify(); 18313513Sgabeblack@google.com try { 18413513Sgabeblack@google.com _current->run(); 18513513Sgabeblack@google.com } catch (...) { 18613513Sgabeblack@google.com throwUp(); 18713513Sgabeblack@google.com } 18813513Sgabeblack@google.com } 18913511Sgabeblack@google.com } 19013511Sgabeblack@google.com if (_current && !_current->needsStart()) { 19113513Sgabeblack@google.com if (_current->excWrapper) { 19213513Sgabeblack@google.com auto ew = _current->excWrapper; 19313513Sgabeblack@google.com _current->excWrapper = nullptr; 19413513Sgabeblack@google.com ew->throw_it(); 19513513Sgabeblack@google.com } else if (_current->inReset()) { 19613513Sgabeblack@google.com _current->reset(false); 19713513Sgabeblack@google.com } 19813513Sgabeblack@google.com } 19913513Sgabeblack@google.com} 20013511Sgabeblack@google.com 20113511Sgabeblack@google.comvoid 20213513Sgabeblack@google.comScheduler::ready(Process *p) 20313513Sgabeblack@google.com{ 20413513Sgabeblack@google.com if (_stopNow) 20513513Sgabeblack@google.com return; 20613513Sgabeblack@google.com 20713513Sgabeblack@google.com p->scheduled(true); 20813513Sgabeblack@google.com 20913513Sgabeblack@google.com if (p->procKind() == ::sc_core::SC_METHOD_PROC_) 21013513Sgabeblack@google.com readyListMethods.pushLast(p); 21113513Sgabeblack@google.com else 21213513Sgabeblack@google.com readyListThreads.pushLast(p); 21313513Sgabeblack@google.com 21413513Sgabeblack@google.com if (!inEvaluate()) 21513513Sgabeblack@google.com scheduleReadyEvent(); 21613513Sgabeblack@google.com} 21713513Sgabeblack@google.com 21813513Sgabeblack@google.comvoid 21913513Sgabeblack@google.comScheduler::resume(Process *p) 22013513Sgabeblack@google.com{ 22113513Sgabeblack@google.com if (initDone) 22213511Sgabeblack@google.com ready(p); 22313511Sgabeblack@google.com else 22413513Sgabeblack@google.com initList.pushLast(p); 22513513Sgabeblack@google.com} 22613513Sgabeblack@google.com 22713513Sgabeblack@google.combool 22813513Sgabeblack@google.comlistContains(ListNode *list, ListNode *target) 22913511Sgabeblack@google.com{ 23013511Sgabeblack@google.com ListNode *n = list->nextListNode; 23113513Sgabeblack@google.com while (n != list) 23213513Sgabeblack@google.com if (n == target) 23313513Sgabeblack@google.com return true; 23413513Sgabeblack@google.com return false; 23513513Sgabeblack@google.com} 23613513Sgabeblack@google.com 23713513Sgabeblack@google.combool 23813513Sgabeblack@google.comScheduler::suspend(Process *p) 23913513Sgabeblack@google.com{ 24013511Sgabeblack@google.com bool was_ready; 24113511Sgabeblack@google.com if (initDone) { 24213513Sgabeblack@google.com // After initialization, check if we're on a ready list. 24313513Sgabeblack@google.com was_ready = (p->nextListNode != nullptr); 24413513Sgabeblack@google.com p->popListNode(); 24513513Sgabeblack@google.com } else { 24613513Sgabeblack@google.com // Nothing is ready before init. 24713513Sgabeblack@google.com was_ready = false; 24813513Sgabeblack@google.com } 24913513Sgabeblack@google.com return was_ready; 25013513Sgabeblack@google.com} 25113513Sgabeblack@google.com 25213511Sgabeblack@google.comvoid 25313513Sgabeblack@google.comScheduler::requestUpdate(Channel *c) 25413513Sgabeblack@google.com{ 25513513Sgabeblack@google.com updateList.pushLast(c); 25613513Sgabeblack@google.com if (!inEvaluate()) 25713513Sgabeblack@google.com scheduleReadyEvent(); 25813513Sgabeblack@google.com} 25913513Sgabeblack@google.com 26013513Sgabeblack@google.comvoid 26113513Sgabeblack@google.comScheduler::asyncRequestUpdate(Channel *c) 26213513Sgabeblack@google.com{ 26313513Sgabeblack@google.com std::lock_guard<std::mutex> lock(asyncListMutex); 26413513Sgabeblack@google.com asyncUpdateList.pushLast(c); 26513513Sgabeblack@google.com} 26613513Sgabeblack@google.com 26713513Sgabeblack@google.comvoid 26813513Sgabeblack@google.comScheduler::scheduleReadyEvent() 26913513Sgabeblack@google.com{ 27013513Sgabeblack@google.com // Schedule the evaluate and update phases. 27113513Sgabeblack@google.com if (!readyEvent.scheduled()) { 27213513Sgabeblack@google.com schedule(&readyEvent); 27313513Sgabeblack@google.com if (starvationEvent.scheduled()) 27413511Sgabeblack@google.com deschedule(&starvationEvent); 27513513Sgabeblack@google.com } 27613513Sgabeblack@google.com} 27713513Sgabeblack@google.com 27813511Sgabeblack@google.comvoid 27913513Sgabeblack@google.comScheduler::scheduleStarvationEvent() 28013513Sgabeblack@google.com{ 28113513Sgabeblack@google.com if (!starvationEvent.scheduled()) { 28213513Sgabeblack@google.com schedule(&starvationEvent); 28313513Sgabeblack@google.com if (readyEvent.scheduled()) 28413513Sgabeblack@google.com deschedule(&readyEvent); 28513513Sgabeblack@google.com } 28613513Sgabeblack@google.com} 28713513Sgabeblack@google.com 28813513Sgabeblack@google.comvoid 28913513Sgabeblack@google.comScheduler::runReady() 29013513Sgabeblack@google.com{ 29113513Sgabeblack@google.com scheduleTimeAdvancesEvent(); 29213513Sgabeblack@google.com 29313513Sgabeblack@google.com bool empty = readyListMethods.empty() && readyListThreads.empty(); 29413513Sgabeblack@google.com lastReadyTick = getCurTick(); 29513513Sgabeblack@google.com 29613513Sgabeblack@google.com // The evaluation phase. 29713513Sgabeblack@google.com status(StatusEvaluate); 29813513Sgabeblack@google.com do { 29913513Sgabeblack@google.com yield(); 30013511Sgabeblack@google.com } while (getNextReady()); 30113511Sgabeblack@google.com _current = nullptr; 30213513Sgabeblack@google.com 30313511Sgabeblack@google.com if (!empty) { 30413513Sgabeblack@google.com _numCycles++; 305 _changeStamp++; 306 } 307 308 if (_stopNow) { 309 status(StatusOther); 310 return; 311 } 312 313 runUpdate(); 314 if (!traceFiles.empty()) 315 trace(true); 316 runDelta(); 317 318 if (!runToTime && starved()) 319 scheduleStarvationEvent(); 320 321 if (runOnce) 322 schedulePause(); 323 324 status(StatusOther); 325} 326 327void 328Scheduler::runUpdate() 329{ 330 status(StatusUpdate); 331 { 332 std::lock_guard<std::mutex> lock(asyncListMutex); 333 Channel *channel; 334 while ((channel = asyncUpdateList.getNext()) != nullptr) 335 updateList.pushLast(channel); 336 } 337 338 try { 339 Channel *channel = updateList.getNext(); 340 while (channel) { 341 channel->popListNode(); 342 channel->update(); 343 channel = updateList.getNext(); 344 } 345 } catch (...) { 346 throwUp(); 347 } 348} 349 350void 351Scheduler::runDelta() 352{ 353 status(StatusDelta); 354 355 try { 356 while (!deltas.empty()) 357 deltas.back()->run(); 358 } catch (...) { 359 throwUp(); 360 } 361} 362 363void 364Scheduler::pause() 365{ 366 status(StatusPaused); 367 kernel->status(::sc_core::SC_PAUSED); 368 runOnce = false; 369 if (scMainFiber.called()) { 370 if (!scMainFiber.finished()) 371 scMainFiber.run(); 372 } else { 373 if (scMainFiber.finished()) 374 fatal("Pausing systemc after sc_main completed."); 375 else 376 exitSimLoopNow("systemc pause"); 377 } 378} 379 380void 381Scheduler::stop() 382{ 383 status(StatusStopped); 384 kernel->stop(); 385 386 clear(); 387 388 runOnce = false; 389 if (scMainFiber.called()) { 390 if (!scMainFiber.finished()) 391 scMainFiber.run(); 392 } else { 393 if (scMainFiber.finished()) 394 fatal("Stopping systemc after sc_main completed."); 395 else 396 exitSimLoopNow("systemc stop"); 397 } 398} 399 400void 401Scheduler::start(Tick max_tick, bool run_to_time) 402{ 403 _started = true; 404 status(StatusOther); 405 runToTime = run_to_time; 406 407 maxTick = max_tick; 408 lastReadyTick = getCurTick(); 409 410 if (initDone) { 411 if (!runToTime && starved()) 412 scheduleStarvationEvent(); 413 kernel->status(::sc_core::SC_RUNNING); 414 } 415 416 schedule(&maxTickEvent, maxTick); 417 scheduleTimeAdvancesEvent(); 418 419 // Return to gem5 to let it run events, etc. 420 Fiber::primaryFiber()->run(); 421 422 if (pauseEvent.scheduled()) 423 deschedule(&pauseEvent); 424 if (stopEvent.scheduled()) 425 deschedule(&stopEvent); 426 if (maxTickEvent.scheduled()) 427 deschedule(&maxTickEvent); 428 if (starvationEvent.scheduled()) 429 deschedule(&starvationEvent); 430 431 if (_throwUp) { 432 const ::sc_core::sc_report *to_throw = _throwUp; 433 _throwUp = nullptr; 434 throw *to_throw; 435 } 436} 437 438void 439Scheduler::oneCycle() 440{ 441 runOnce = true; 442 scheduleReadyEvent(); 443 start(::MaxTick, false); 444} 445 446void 447Scheduler::schedulePause() 448{ 449 if (pauseEvent.scheduled()) 450 return; 451 452 schedule(&pauseEvent); 453} 454 455void 456Scheduler::throwUp() 457{ 458 if (scMainFiber.called() && !scMainFiber.finished()) { 459 ::sc_core::sc_report report = reportifyException(); 460 _throwUp = &report; 461 status(StatusOther); 462 scMainFiber.run(); 463 } else { 464 reportHandlerProc(reportifyException(), 465 ::sc_core::sc_report_handler::get_catch_actions()); 466 } 467} 468 469void 470Scheduler::scheduleStop(bool finish_delta) 471{ 472 if (stopEvent.scheduled()) 473 return; 474 475 if (!finish_delta) { 476 _stopNow = true; 477 // If we're not supposed to finish the delta cycle, flush all 478 // pending activity. 479 clear(); 480 } 481 schedule(&stopEvent); 482} 483 484void 485Scheduler::trace(bool delta) 486{ 487 for (auto tf: traceFiles) 488 tf->trace(delta); 489} 490 491Scheduler scheduler; 492Process *getCurrentProcess() { return scheduler.current(); } 493 494namespace { 495 496void 497throwingReportHandler(const ::sc_core::sc_report &r, 498 const ::sc_core::sc_actions &) 499{ 500 throw r; 501} 502 503} // anonymous namespace 504 505const ::sc_core::sc_report 506reportifyException() 507{ 508 ::sc_core::sc_report_handler_proc old_handler = reportHandlerProc; 509 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler); 510 511 try { 512 try { 513 // Rethrow the current exception so we can catch it and throw an 514 // sc_report instead if it's not a type we recognize/can handle. 515 throw; 516 } catch (const ::sc_core::sc_report &) { 517 // It's already a sc_report, so nothing to do. 518 throw; 519 } catch (const ::sc_core::sc_unwind_exception &) { 520 panic("Kill/reset exception escaped a Process::run()"); 521 } catch (const std::exception &e) { 522 SC_REPORT_ERROR( 523 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, e.what()); 524 } catch (const char *msg) { 525 SC_REPORT_ERROR( 526 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, msg); 527 } catch (...) { 528 SC_REPORT_ERROR( 529 sc_core::SC_ID_SIMULATION_UNCAUGHT_EXCEPTION_, 530 "UNKNOWN EXCEPTION"); 531 } 532 } catch (const ::sc_core::sc_report &r) { 533 ::sc_core::sc_report_handler::set_handler(old_handler); 534 return r; 535 } 536 panic("No exception thrown in reportifyException."); 537} 538 539} // namespace sc_gem5 540