systemc: Implement signal based resets.

The implementation is based on sc_event sensitivities.

Also of note is that the way reset works in the Accellera
implementation isn't consistent with the spec. That says that
wait(int n) is supposed to be equivalent to calling wait() n times,
assuming n is greater than 0.

Instead, Accellera stores that count and then doesn't wake up the
process until the count is 0, decrementing it otherwise.

That means that when the process is in reset, it won't actually reset
for those intermediate wait()s which it would if wait() was called
repeatedly. Also, oddly, when a reset becomes asserted, it will clear
the count to 0 explicitly. That may have been an attempt to make the
behavior of wait(int n) match the spec, but it doesn't handle cases
where the reset is already set when wait(int n) is called.

Change-Id: I92f8e9a128e6618af94dc048ce570a4436e17e4b
Reviewed-on: https://gem5-review.googlesource.com/c/13186
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
This commit is contained in:
Gabe Black
2018-09-26 03:20:09 -07:00
parent f4ab64a588
commit 0cfce45800
13 changed files with 363 additions and 52 deletions

View File

@@ -154,6 +154,13 @@ Event::notify(DynamicSensitivities &senses)
senses.resize(size);
}
void
Event::notify(ResetSensitivities &senses)
{
for (auto s: senses)
s->notify(this);
}
void
Event::notify()
{
@@ -167,7 +174,7 @@ Event::notify()
scheduler.deschedule(&delayedNotify);
_triggeredStamp = scheduler.changeStamp();
notify(resetSense);
notify(staticSenseMethod);
notify(dynamicSenseMethod);
notify(staticSenseThread);

View File

@@ -74,6 +74,7 @@ class Event
void notify(StaticSensitivities &senses);
void notify(DynamicSensitivities &senses);
void notify(ResetSensitivities &senses);
void notify();
void notify(const sc_core::sc_time &t);
@@ -137,6 +138,22 @@ class Event
}
}
}
void
addSensitivity(ResetSensitivity *s) const
{
resetSense.push_back(s);
}
void
delSensitivity(ResetSensitivity *s) const
{
for (auto &t: resetSense) {
if (t == s) {
t = resetSense.back();
resetSense.pop_back();
break;
}
}
}
private:
sc_core::sc_event *_sc_event;
@@ -154,6 +171,7 @@ class Event
mutable StaticSensitivities staticSenseThread;
mutable DynamicSensitivities dynamicSenseMethod;
mutable DynamicSensitivities dynamicSenseThread;
mutable ResetSensitivities resetSense;
};
extern Events topLevelEvents;

View File

@@ -30,6 +30,7 @@
#include "systemc/core/port.hh"
#include "systemc/core/sensitivity.hh"
#include "systemc/ext/channel/sc_signal_in_if.hh"
namespace sc_gem5
{
@@ -48,6 +49,18 @@ Port::finalizeFinder(StaticSensitivityFinder *finder)
finder->addEvent(&finder->find(getInterface(i)));
}
void
Port::finalizeReset(ResetSensitivityPort *reset)
{
assert(size() <= 1);
if (size()) {
auto iface =
dynamic_cast<sc_core::sc_signal_in_if<bool> *>(getInterface(0));
assert(iface);
reset->setSignal(iface);
}
}
void
Port::sensitive(StaticSensitivityPort *port)
{
@@ -66,6 +79,15 @@ Port::sensitive(StaticSensitivityFinder *finder)
sensitivities.push_back(new Sensitivity(finder));
}
void
Port::sensitive(ResetSensitivityPort *reset)
{
if (finalized)
finalizeReset(reset);
else
sensitivities.push_back(new Sensitivity(reset));
}
void
Port::finalize()
{
@@ -88,8 +110,10 @@ Port::finalize()
for (auto &s: sensitivities) {
if (s->port)
finalizePort(s->port);
else
else if (s->finder)
finalizeFinder(s->finder);
else
finalizeReset(s->reset);
delete s;
}

View File

@@ -42,6 +42,7 @@ namespace sc_gem5
class StaticSensitivityPort;
class StaticSensitivityFinder;
class ResetSensitivityPort;
class Port;
@@ -58,6 +59,7 @@ class Port
void finalizePort(StaticSensitivityPort *port);
void finalizeFinder(StaticSensitivityFinder *finder);
void finalizeReset(ResetSensitivityPort *reset);
void
addInterface(::sc_core::sc_interface *iface)
@@ -105,15 +107,20 @@ class Port
struct Sensitivity
{
Sensitivity(StaticSensitivityPort *port) :
port(port), finder(nullptr)
port(port), finder(nullptr), reset(nullptr)
{}
Sensitivity(StaticSensitivityFinder *finder) :
port(nullptr), finder(finder)
port(nullptr), finder(finder), reset(nullptr)
{}
Sensitivity(ResetSensitivityPort *reset) :
port(nullptr), finder(nullptr), reset(reset)
{}
StaticSensitivityPort *port;
StaticSensitivityFinder *finder;
ResetSensitivityPort *reset;
};
std::vector<Binding *> bindings;
@@ -148,6 +155,7 @@ class Port
void sensitive(StaticSensitivityPort *port);
void sensitive(StaticSensitivityFinder *finder);
void sensitive(ResetSensitivityPort *reset);
void finalize();

View File

@@ -235,6 +235,27 @@ Process::syncResetOff(bool inc_kids)
_syncReset = false;
}
void
Process::signalReset(bool set, bool sync)
{
if (set) {
waitCount(0);
if (sync) {
syncResetCount++;
} else {
asyncResetCount++;
cancelTimeout();
clearDynamic();
scheduler.runNext(this);
}
} else {
if (sync)
syncResetCount--;
else
asyncResetCount--;
}
}
void
Process::run()
{
@@ -271,6 +292,12 @@ Process::setDynamic(DynamicSensitivity *s)
dynamicSensitivity = s;
}
void
Process::addReset(ResetSensitivity *s)
{
resetSensitivities.push_back(s);
}
void
Process::cancelTimeout()
{
@@ -302,6 +329,11 @@ Process::timeout()
void
Process::satisfySensitivity(Sensitivity *s)
{
if (_waitCount) {
_waitCount--;
return;
}
// If there's a dynamic sensitivity and this wasn't it, ignore.
if ((dynamicSensitivity || timeoutEvent.scheduled()) &&
dynamicSensitivity != s) {
@@ -346,7 +378,8 @@ Process::Process(const char *name, ProcessFuncWrapper *func, bool internal) :
timeoutEvent([this]() { this->timeout(); }),
func(func), _internal(internal), _timedOut(false), _dontInitialize(false),
_needsStart(true), _isUnwinding(false), _terminated(false),
_suspended(false), _disabled(false), _syncReset(false), refCount(0),
_suspended(false), _disabled(false), _syncReset(false), syncResetCount(0),
asyncResetCount(0), _waitCount(0), refCount(0),
stackSize(::Fiber::DefaultStackSize), dynamicSensitivity(nullptr)
{
_dynamic =

View File

@@ -87,6 +87,8 @@ class Process : public ::sc_core::sc_process_b, public ListNode
void syncResetOn(bool inc_kids);
void syncResetOff(bool inc_kids);
void signalReset(bool set, bool sync);
void incref() { refCount++; }
void decref() { refCount--; }
@@ -100,6 +102,7 @@ class Process : public ::sc_core::sc_process_b, public ListNode
void addStatic(StaticSensitivity *);
void setDynamic(DynamicSensitivity *);
void clearDynamic() { setDynamic(nullptr); }
void addReset(ResetSensitivity *);
ScEvent timeoutEvent;
void setTimeout(::sc_core::sc_time t);
@@ -119,13 +122,15 @@ class Process : public ::sc_core::sc_process_b, public ListNode
bool hasStaticSensitivities() { return !staticSensitivities.empty(); }
bool internal() { return _internal; }
bool timedOut() { return _timedOut; }
bool syncReset() { return _syncReset; }
bool inReset() { return _syncReset || syncResetCount || asyncResetCount; }
bool dontInitialize() { return _dontInitialize; }
void dontInitialize(bool di) { _dontInitialize = di; }
void joinWait(::sc_core::sc_join *join) { joinWaiters.push_back(join); }
void waitCount(int count) { _waitCount = count; }
protected:
void timeout();
@@ -170,12 +175,18 @@ class Process : public ::sc_core::sc_process_b, public ListNode
bool _syncReset;
int syncResetCount;
int asyncResetCount;
int _waitCount;
int refCount;
size_t stackSize;
StaticSensitivities staticSensitivities;
DynamicSensitivity *dynamicSensitivity;
ResetSensitivities resetSensitivities;
std::unique_ptr<::sc_core::sc_report> _lastReport;

View File

@@ -35,6 +35,7 @@
#include "systemc/core/kernel.hh"
#include "systemc/core/module.hh"
#include "systemc/core/process_types.hh"
#include "systemc/core/sensitivity.hh"
#include "systemc/ext/channel/sc_signal_in_if.hh"
#include "systemc/ext/core/sc_module.hh"
#include "systemc/ext/core/sc_module_name.hh"
@@ -244,52 +245,60 @@ sc_module::end_module()
}
void
sc_module::reset_signal_is(const sc_in<bool> &, bool)
sc_module::reset_signal_is(const sc_in<bool> &port, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivityPort(
::sc_gem5::Process::newest(), &port, val, true);
}
void
sc_module::reset_signal_is(const sc_inout<bool> &, bool)
sc_module::reset_signal_is(const sc_inout<bool> &port, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivityPort(
::sc_gem5::Process::newest(), &port, val, true);
}
void
sc_module::reset_signal_is(const sc_out<bool> &, bool)
sc_module::reset_signal_is(const sc_out<bool> &port, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivityPort(
::sc_gem5::Process::newest(), &port, val, true);
}
void
sc_module::reset_signal_is(const sc_signal_in_if<bool> &, bool)
sc_module::reset_signal_is(const sc_signal_in_if<bool> &signal, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivitySignal(
::sc_gem5::Process::newest(), &signal, val, true);
}
void
sc_module::async_reset_signal_is(const sc_in<bool> &, bool)
sc_module::async_reset_signal_is(const sc_in<bool> &port, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivityPort(
::sc_gem5::Process::newest(), &port, val, false);
}
void
sc_module::async_reset_signal_is(const sc_inout<bool> &, bool)
sc_module::async_reset_signal_is(const sc_inout<bool> &port, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivityPort(
::sc_gem5::Process::newest(), &port, val, false);
}
void
sc_module::async_reset_signal_is(const sc_out<bool> &, bool)
sc_module::async_reset_signal_is(const sc_out<bool> &port, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivityPort(
::sc_gem5::Process::newest(), &port, val, false);
}
void
sc_module::async_reset_signal_is(const sc_signal_in_if<bool> &, bool)
sc_module::async_reset_signal_is(const sc_signal_in_if<bool> &signal, bool val)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
sc_gem5::newResetSensitivitySignal(
::sc_gem5::Process::newest(), &signal, val, false);
}
@@ -626,8 +635,9 @@ wait(int n)
std::string msg = csprintf("n = %d", n);
SC_REPORT_ERROR("(E525) wait(n) is only valid for n > 0", msg.c_str());
}
for (int i = 0; i < n; i++)
wait();
sc_gem5::Process *p = sc_gem5::scheduler.current();
p->waitCount(n - 1);
wait();
}
void

View File

@@ -83,6 +83,18 @@ spawnWork(ProcessFuncWrapper *func, const char *name,
for (auto f: opts->_finders)
newStaticSensitivityFinder(proc, f);
for (auto p: opts->_in_resets)
newResetSensitivityPort(proc, p.target, p.value, p.sync);
for (auto p: opts->_inout_resets)
newResetSensitivityPort(proc, p.target, p.value, p.sync);
for (auto p: opts->_out_resets)
newResetSensitivityPort(proc, p.target, p.value, p.sync);
for (auto i: opts->_if_resets)
newResetSensitivitySignal(proc, i.target, i.value, i.sync);
}
if (opts && opts->_dontInitialize &&
@@ -161,59 +173,54 @@ sc_spawn_options::set_sensitivity(sc_event_finder *f)
void
sc_spawn_options::reset_signal_is(const sc_in<bool> &, bool)
sc_spawn_options::reset_signal_is(const sc_in<bool> &port, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_in_resets.emplace_back(&port, value, true);
}
void
sc_spawn_options::reset_signal_is(const sc_inout<bool> &, bool)
sc_spawn_options::reset_signal_is(const sc_inout<bool> &port, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_inout_resets.emplace_back(&port, value, true);
}
void
sc_spawn_options::reset_signal_is(const sc_out<bool> &, bool)
sc_spawn_options::reset_signal_is(const sc_out<bool> &port, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_out_resets.emplace_back(&port, value, true);
}
void
sc_spawn_options::reset_signal_is(const sc_signal_in_if<bool> &, bool)
sc_spawn_options::reset_signal_is(
const sc_signal_in_if<bool> &iface, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_if_resets.emplace_back(&iface, value, true);
}
void
sc_spawn_options::async_reset_signal_is(const sc_in<bool> &, bool)
sc_spawn_options::async_reset_signal_is(const sc_in<bool> &port, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_in_resets.emplace_back(&port, value, false);
}
void
sc_spawn_options::async_reset_signal_is(const sc_inout<bool> &, bool)
sc_spawn_options::async_reset_signal_is(const sc_inout<bool> &port, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_inout_resets.emplace_back(&port, value, false);
}
void
sc_spawn_options::async_reset_signal_is(const sc_out<bool> &, bool)
sc_spawn_options::async_reset_signal_is(const sc_out<bool> &port, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
_out_resets.emplace_back(&port, value, false);
}
void
sc_spawn_options::async_reset_signal_is(const sc_signal_in_if<bool> &, bool)
sc_spawn_options::async_reset_signal_is(
const sc_signal_in_if<bool> &iface, bool value)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
}
void
sc_spawn_warn_unimpl(const char *func)
{
warn("%s not implemented.\n", func);
_if_resets.emplace_back(&iface, value, false);
}
} // namespace sc_core

View File

@@ -183,7 +183,7 @@ Scheduler::yield()
auto ew = _current->excWrapper;
_current->excWrapper = nullptr;
ew->throw_it();
} else if (_current->syncReset()) {
} else if (_current->inReset()) {
_current->reset(false);
}
}

View File

@@ -209,6 +209,17 @@ class Scheduler
yield();
}
// Run this process at the next opportunity.
void
runNext(Process *p)
{
// Like above, it's ok if this isn't a method. Putting it on this list
// just gives it priority.
readyListMethods.pushFirst(p);
if (!inEvaluate())
scheduleReadyEvent();
}
// Set an event queue for scheduling events.
void setEventQueue(EventQueue *_eq) { eq = _eq; }

View File

@@ -33,6 +33,9 @@
#include "systemc/core/port.hh"
#include "systemc/core/process.hh"
#include "systemc/core/scheduler.hh"
#include "systemc/ext/channel/sc_in.hh"
#include "systemc/ext/channel/sc_inout.hh"
#include "systemc/ext/channel/sc_out.hh"
#include "systemc/ext/core/sc_export.hh"
#include "systemc/ext/core/sc_interface.hh"
#include "systemc/ext/core/sc_port.hh"
@@ -93,6 +96,18 @@ StaticSensitivity::delFromEvent(const ::sc_core::sc_event *e)
Event::getFromScEvent(e)->delSensitivity(this);
}
void
ResetSensitivity::addToEvent(const ::sc_core::sc_event *e)
{
Event::getFromScEvent(e)->addSensitivity(this);
}
void
ResetSensitivity::delFromEvent(const ::sc_core::sc_event *e)
{
Event::getFromScEvent(e)->delSensitivity(this);
}
/*
* Static sensitivities.
@@ -228,4 +243,71 @@ DynamicSensitivityEventAndList::notifyWork(Event *e)
return true;
}
/*
* Reset sensitivities.
*/
void
newResetSensitivitySignal(
Process *p, const sc_core::sc_signal_in_if<bool> *signal,
bool val, bool sync)
{
auto s = new ResetSensitivitySignal(p, signal, val, sync);
s->addToEvent(s->event);
p->addReset(s);
}
void
newResetSensitivityPort(Process *p, const sc_core::sc_in<bool> *port,
bool val, bool sync)
{
auto s = new ResetSensitivityPort(p, port, val, sync);
Port::fromPort(port)->sensitive(s);
p->addReset(s);
}
void
newResetSensitivityPort(Process *p, const sc_core::sc_inout<bool> *port,
bool val, bool sync)
{
auto s = new ResetSensitivityPort(p, port, val, sync);
Port::fromPort(port)->sensitive(s);
p->addReset(s);
}
void
newResetSensitivityPort(Process *p, const sc_core::sc_out<bool> *port,
bool val, bool sync)
{
auto s = new ResetSensitivityPort(p, port, val, sync);
Port::fromPort(port)->sensitive(s);
p->addReset(s);
}
ResetSensitivitySignal::ResetSensitivitySignal(
Process *p, const sc_core::sc_signal_in_if<bool> *signal,
bool _val, bool _sync) :
Sensitivity(p), ResetSensitivity(p, _val, _sync),
SensitivityEvent(p, signal ? &signal->value_changed_event() : nullptr),
_signal(signal)
{
if (signal && signal->read() == val())
process->signalReset(true, sync());
}
bool
ResetSensitivitySignal::notifyWork(Event *e)
{
process->signalReset(_signal->read() == val(), sync());
return true;
}
void
ResetSensitivityPort::setSignal(const ::sc_core::sc_signal_in_if<bool> *signal)
{
_signal = signal;
event = &_signal->value_changed_event();
addToEvent(event);
if (signal->read() == val())
process->signalReset(true, sync());
}
} // namespace sc_gem5

View File

@@ -36,6 +36,7 @@
#include "sim/eventq.hh"
#include "systemc/core/sched_event.hh"
#include "systemc/ext/core/sc_module.hh"
#include "systemc/ext/core/sc_port.hh"
namespace sc_core
{
@@ -84,14 +85,21 @@ class Sensitivity
void satisfy();
bool notify(Event *e);
virtual bool dynamic() = 0;
enum Category
{
Static,
Dynamic,
Reset
};
virtual Category category() = 0;
bool ofMethod();
};
/*
* Dynamic vs. static sensitivity.
* Dynamic vs. static vs. reset sensitivity.
*/
class DynamicSensitivity : virtual public Sensitivity
@@ -103,7 +111,7 @@ class DynamicSensitivity : virtual public Sensitivity
void delFromEvent(const ::sc_core::sc_event *e) override;
public:
bool dynamic() override { return true; }
Category category() override { return Dynamic; }
};
typedef std::vector<DynamicSensitivity *> DynamicSensitivities;
@@ -118,11 +126,34 @@ class StaticSensitivity : virtual public Sensitivity
void delFromEvent(const ::sc_core::sc_event *e) override;
public:
bool dynamic() override { return false; }
Category category() override { return Static; }
};
typedef std::vector<StaticSensitivity *> StaticSensitivities;
class ResetSensitivity : virtual public Sensitivity
{
private:
bool _val;
bool _sync;
protected:
ResetSensitivity(Process *p, bool _val, bool _sync) :
Sensitivity(p), _val(_val), _sync(_sync)
{}
void addToEvent(const ::sc_core::sc_event *e) override;
void delFromEvent(const ::sc_core::sc_event *e) override;
bool val() { return _val; }
bool sync() { return _sync; }
public:
Category category() override { return Reset; }
};
typedef std::vector<ResetSensitivity *> ResetSensitivities;
/*
* Sensitivity to an event or events, which can be static or dynamic.
@@ -295,6 +326,60 @@ class DynamicSensitivityEventAndList :
bool notifyWork(Event *e) override;
};
/*
* Reset sensitivities.
*/
void newResetSensitivitySignal(
Process *p, const sc_core::sc_signal_in_if<bool> *signal,
bool val, bool sync);
void newResetSensitivityPort(
Process *p, const sc_core::sc_in<bool> *port, bool val, bool sync);
void newResetSensitivityPort(
Process *p, const sc_core::sc_inout<bool> *port, bool val, bool sync);
void newResetSensitivityPort(
Process *p, const sc_core::sc_out<bool> *port, bool val, bool sync);
class ResetSensitivitySignal :
public ResetSensitivity, public SensitivityEvent
{
protected:
const sc_core::sc_signal_in_if<bool> *_signal;
friend void newResetSensitivitySignal(
Process *p, const sc_core::sc_signal_in_if<bool> *signal,
bool val, bool sync);
ResetSensitivitySignal(
Process *p, const sc_core::sc_signal_in_if<bool> *signal,
bool _val, bool _sync);
bool notifyWork(Event *e) override;
};
class ResetSensitivityPort : public ResetSensitivitySignal
{
private:
friend void newResetSensitivityPort(
Process *p, const sc_core::sc_in<bool> *port, bool val, bool sync);
friend void newResetSensitivityPort(
Process *p, const sc_core::sc_inout<bool> *port,
bool val, bool sync);
friend void newResetSensitivityPort(
Process *p, const sc_core::sc_out<bool> *port,
bool val, bool sync);
ResetSensitivityPort(
Process *p, const sc_core::sc_port_base *port,
bool _val, bool _sync) :
Sensitivity(p), ResetSensitivitySignal(p, nullptr, _val, _sync)
{}
public:
void setSignal(const ::sc_core::sc_signal_in_if<bool> *signal);
};
} // namespace sc_gem5
#endif //__SYSTEMC_CORE_SENSITIVITY_HH__

View File

@@ -130,6 +130,21 @@ class sc_spawn_options
std::vector<sc_interface *> _interfaces;
std::vector<sc_event_finder *> _finders;
template <typename T>
struct Reset
{
Reset(T *t, bool v, bool s) : target(t), value(v), sync(s) {}
T *target;
bool value;
bool sync;
};
std::vector<Reset<const sc_in<bool> > > _in_resets;
std::vector<Reset<const sc_inout<bool> > > _inout_resets;
std::vector<Reset<const sc_out<bool> > > _out_resets;
std::vector<Reset<const sc_signal_in_if<bool> > > _if_resets;
// Disabled
sc_spawn_options(const sc_spawn_options &) {}
sc_spawn_options &operator = (const sc_spawn_options &) { return *this; }