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