This doesn't include support for the deprecated integer message ids. Change-Id: I309d58df1cdc464428189eb0b7180edf41ca4f67 Reviewed-on: https://gem5-review.googlesource.com/12048 Reviewed-by: Gabe Black <gabeblack@google.com> Maintainer: Gabe Black <gabeblack@google.com>
369 lines
8.5 KiB
C++
369 lines
8.5 KiB
C++
/*
|
|
* Copyright 2018 Google, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Authors: Gabe Black
|
|
*/
|
|
|
|
#include "systemc/core/process.hh"
|
|
|
|
#include "base/logging.hh"
|
|
#include "systemc/core/event.hh"
|
|
#include "systemc/core/scheduler.hh"
|
|
|
|
namespace sc_gem5
|
|
{
|
|
|
|
SensitivityTimeout::SensitivityTimeout(Process *p, ::sc_core::sc_time t) :
|
|
Sensitivity(p), timeoutEvent(this), time(t)
|
|
{
|
|
Tick when = scheduler.getCurTick() + time.value();
|
|
scheduler.schedule(&timeoutEvent, when);
|
|
}
|
|
|
|
SensitivityTimeout::~SensitivityTimeout()
|
|
{
|
|
if (timeoutEvent.scheduled())
|
|
scheduler.deschedule(&timeoutEvent);
|
|
}
|
|
|
|
void
|
|
SensitivityTimeout::timeout()
|
|
{
|
|
scheduler.eventHappened();
|
|
notify();
|
|
}
|
|
|
|
SensitivityEvent::SensitivityEvent(
|
|
Process *p, const ::sc_core::sc_event *e) : Sensitivity(p), event(e)
|
|
{
|
|
Event::getFromScEvent(event)->addSensitivity(this);
|
|
}
|
|
|
|
SensitivityEvent::~SensitivityEvent()
|
|
{
|
|
Event::getFromScEvent(event)->delSensitivity(this);
|
|
}
|
|
|
|
SensitivityEventAndList::SensitivityEventAndList(
|
|
Process *p, const ::sc_core::sc_event_and_list *list) :
|
|
Sensitivity(p), list(list), count(0)
|
|
{
|
|
for (auto e: list->events)
|
|
Event::getFromScEvent(e)->addSensitivity(this);
|
|
}
|
|
|
|
SensitivityEventAndList::~SensitivityEventAndList()
|
|
{
|
|
for (auto e: list->events)
|
|
Event::getFromScEvent(e)->delSensitivity(this);
|
|
}
|
|
|
|
void
|
|
SensitivityEventAndList::notifyWork(Event *e)
|
|
{
|
|
e->delSensitivity(this);
|
|
count++;
|
|
if (count == list->events.size())
|
|
process->satisfySensitivity(this);
|
|
}
|
|
|
|
SensitivityEventOrList::SensitivityEventOrList(
|
|
Process *p, const ::sc_core::sc_event_or_list *list) :
|
|
Sensitivity(p), list(list)
|
|
{
|
|
for (auto e: list->events)
|
|
Event::getFromScEvent(e)->addSensitivity(this);
|
|
}
|
|
|
|
SensitivityEventOrList::~SensitivityEventOrList()
|
|
{
|
|
for (auto e: list->events)
|
|
Event::getFromScEvent(e)->delSensitivity(this);
|
|
}
|
|
|
|
|
|
class UnwindExceptionReset : public ::sc_core::sc_unwind_exception
|
|
{
|
|
public:
|
|
UnwindExceptionReset() { _isReset = true; }
|
|
};
|
|
|
|
class UnwindExceptionKill : public ::sc_core::sc_unwind_exception
|
|
{
|
|
public:
|
|
UnwindExceptionKill() {}
|
|
};
|
|
|
|
template <typename T>
|
|
struct BuiltinExceptionWrapper : public ExceptionWrapperBase
|
|
{
|
|
public:
|
|
T t;
|
|
void throw_it() override { throw t; }
|
|
};
|
|
|
|
BuiltinExceptionWrapper<UnwindExceptionReset> resetException;
|
|
BuiltinExceptionWrapper<UnwindExceptionKill> killException;
|
|
|
|
|
|
void
|
|
Process::forEachKid(const std::function<void(Process *)> &work)
|
|
{
|
|
for (auto &kid: get_child_objects()) {
|
|
Process *p_kid = dynamic_cast<Process *>(kid);
|
|
if (p_kid)
|
|
work(p_kid);
|
|
}
|
|
}
|
|
|
|
void
|
|
Process::suspend(bool inc_kids)
|
|
{
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->suspend(true); });
|
|
|
|
if (!_suspended) {
|
|
_suspended = true;
|
|
_suspendedReady = false;
|
|
}
|
|
|
|
if (procKind() != ::sc_core::SC_METHOD_PROC_ &&
|
|
scheduler.current() == this) {
|
|
scheduler.yield();
|
|
}
|
|
}
|
|
|
|
void
|
|
Process::resume(bool inc_kids)
|
|
{
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->resume(true); });
|
|
|
|
if (_suspended) {
|
|
_suspended = false;
|
|
if (_suspendedReady)
|
|
ready();
|
|
_suspendedReady = false;
|
|
}
|
|
}
|
|
|
|
void
|
|
Process::disable(bool inc_kids)
|
|
{
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->disable(true); });
|
|
|
|
_disabled = true;
|
|
}
|
|
|
|
void
|
|
Process::enable(bool inc_kids)
|
|
{
|
|
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->enable(true); });
|
|
|
|
_disabled = false;
|
|
}
|
|
|
|
void
|
|
Process::kill(bool inc_kids)
|
|
{
|
|
// Propogate the kill to our children no matter what happens to us.
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->kill(true); });
|
|
|
|
// If we're in the middle of unwinding, ignore the kill request.
|
|
if (_isUnwinding)
|
|
return;
|
|
|
|
// Update our state.
|
|
_terminated = true;
|
|
_isUnwinding = true;
|
|
_suspendedReady = false;
|
|
_suspended = false;
|
|
_syncReset = false;
|
|
|
|
// Inject the kill exception into this process.
|
|
injectException(killException);
|
|
|
|
_terminatedEvent.notify();
|
|
}
|
|
|
|
void
|
|
Process::reset(bool inc_kids)
|
|
{
|
|
// Propogate the reset to our children no matter what happens to us.
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->reset(true); });
|
|
|
|
// If we're in the middle of unwinding, ignore the reset request.
|
|
if (_isUnwinding)
|
|
return;
|
|
|
|
// Update our state.
|
|
_isUnwinding = true;
|
|
|
|
// Inject the reset exception into this process.
|
|
injectException(resetException);
|
|
|
|
_resetEvent.notify();
|
|
}
|
|
|
|
void
|
|
Process::throw_it(ExceptionWrapperBase &exc, bool inc_kids)
|
|
{
|
|
if (inc_kids)
|
|
forEachKid([&exc](Process *p) { p->throw_it(exc, true); });
|
|
}
|
|
|
|
void
|
|
Process::injectException(ExceptionWrapperBase &exc)
|
|
{
|
|
excWrapper = &exc;
|
|
scheduler.runNow(this);
|
|
};
|
|
|
|
void
|
|
Process::syncResetOn(bool inc_kids)
|
|
{
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->syncResetOn(true); });
|
|
|
|
_syncReset = true;
|
|
}
|
|
|
|
void
|
|
Process::syncResetOff(bool inc_kids)
|
|
{
|
|
if (inc_kids)
|
|
forEachKid([](Process *p) { p->syncResetOff(true); });
|
|
|
|
_syncReset = false;
|
|
}
|
|
|
|
void
|
|
Process::dontInitialize()
|
|
{
|
|
scheduler.dontInitialize(this);
|
|
}
|
|
|
|
void
|
|
Process::finalize()
|
|
{
|
|
for (auto &s: pendingStaticSensitivities) {
|
|
s->finalize(staticSensitivities);
|
|
delete s;
|
|
s = nullptr;
|
|
}
|
|
pendingStaticSensitivities.clear();
|
|
};
|
|
|
|
void
|
|
Process::run()
|
|
{
|
|
bool reset;
|
|
do {
|
|
reset = false;
|
|
try {
|
|
func->call();
|
|
} catch(const ::sc_core::sc_unwind_exception &exc) {
|
|
reset = exc.is_reset();
|
|
_isUnwinding = false;
|
|
}
|
|
} while (reset);
|
|
_terminated = true;
|
|
}
|
|
|
|
void
|
|
Process::addStatic(PendingSensitivity *s)
|
|
{
|
|
pendingStaticSensitivities.push_back(s);
|
|
}
|
|
|
|
void
|
|
Process::setDynamic(Sensitivity *s)
|
|
{
|
|
delete dynamicSensitivity;
|
|
dynamicSensitivity = s;
|
|
}
|
|
|
|
void
|
|
Process::satisfySensitivity(Sensitivity *s)
|
|
{
|
|
// If there's a dynamic sensitivity and this wasn't it, ignore.
|
|
if (dynamicSensitivity && dynamicSensitivity != s)
|
|
return;
|
|
|
|
setDynamic(nullptr);
|
|
ready();
|
|
}
|
|
|
|
void
|
|
Process::ready()
|
|
{
|
|
if (disabled())
|
|
return;
|
|
if (suspended())
|
|
_suspendedReady = true;
|
|
else
|
|
scheduler.ready(this);
|
|
}
|
|
|
|
void
|
|
Process::lastReport(::sc_core::sc_report *report)
|
|
{
|
|
if (report) {
|
|
_lastReport = std::unique_ptr<::sc_core::sc_report>(
|
|
new ::sc_core::sc_report(*report));
|
|
} else {
|
|
_lastReport = nullptr;
|
|
}
|
|
}
|
|
|
|
::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); }
|
|
|
|
Process::Process(const char *name, ProcessFuncWrapper *func,
|
|
bool _dynamic, bool needs_start) :
|
|
::sc_core::sc_object(name), excWrapper(nullptr), func(func),
|
|
_needsStart(needs_start), _dynamic(_dynamic), _isUnwinding(false),
|
|
_terminated(false), _suspended(false), _disabled(false),
|
|
_syncReset(false), refCount(0), stackSize(::Fiber::DefaultStackSize),
|
|
dynamicSensitivity(nullptr)
|
|
{
|
|
_newest = this;
|
|
}
|
|
|
|
Process *Process::_newest;
|
|
|
|
void
|
|
throw_it_wrapper(Process *p, ExceptionWrapperBase &exc, bool inc_kids)
|
|
{
|
|
p->throw_it(exc, inc_kids);
|
|
}
|
|
|
|
} // namespace sc_gem5
|