1/*
2 * Copyright 2018 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Authors: Gabe Black
28 */
29
30#include "systemc/core/event.hh"
31
32#include <algorithm>
33#include <cstring>
34#include <utility>
35
36#include "sim/core.hh"
37#include "systemc/core/module.hh"
38#include "systemc/core/scheduler.hh"
39#include "systemc/ext/core/messages.hh"
40#include "systemc/ext/core/sc_main.hh"
41#include "systemc/ext/core/sc_module.hh"
42
43namespace sc_gem5
44{
45
46Event::Event(sc_core::sc_event *_sc_event, bool internal) :
47    Event(_sc_event, nullptr, internal)
48{}
49
50Event::Event(sc_core::sc_event *_sc_event, const char *_basename_cstr,
51        bool internal) :
52    _sc_event(_sc_event), _basename(_basename_cstr ? _basename_cstr : ""),
53    _inHierarchy(!internal), delayedNotify([this]() { this->notify(); }),
54    _triggeredStamp(~0ULL)
55{
56    if (_basename == "" && ::sc_core::sc_is_running())
57        _basename = ::sc_core::sc_gen_unique_name("event");
58
59    parent = internal ? nullptr : pickParentObj();
60
61    if (internal) {
62        _basename = globalNameGen.gen(_basename);
63        _name = _basename;
64    } else {
65        std::string original_name = _basename;
66        _basename = pickUniqueName(parent, _basename);
67
68        if (parent) {
69            Object *obj = Object::getFromScObject(parent);
70            obj->addChildEvent(_sc_event);
71        } else {
72            topLevelEvents.emplace(topLevelEvents.end(), _sc_event);
73        }
74
75        std::string path = parent ? (std::string(parent->name()) + ".") : "";
76
77        if (original_name != "" && _basename != original_name) {
78            std::string message = path + original_name +
79                ". Latter declaration will be renamed to " +
80                path + _basename;
81            SC_REPORT_WARNING(sc_core::SC_ID_INSTANCE_EXISTS_,
82                    message.c_str());
83        }
84
85        _name = path + _basename;
86    }
87
88    allEvents.emplace(allEvents.end(), _sc_event);
89
90    // Determine if we're in the hierarchy (created once initialization starts
91    // means no).
92}
93
94Event::~Event()
95{
96    if (parent) {
97        Object *obj = Object::getFromScObject(parent);
98        obj->delChildEvent(_sc_event);
99    } else if (inHierarchy()) {
100        EventsIt it = find(topLevelEvents.begin(), topLevelEvents.end(),
101                           _sc_event);
102        assert(it != topLevelEvents.end());
103        std::swap(*it, topLevelEvents.back());
104        topLevelEvents.pop_back();
105    }
106
107    EventsIt it = findEvent(_name);
108    std::swap(*it, allEvents.back());
109    allEvents.pop_back();
110
111    if (delayedNotify.scheduled())
112        scheduler.deschedule(&delayedNotify);
113}
114
115const std::string &
116Event::name() const
117{
118    return _name;
119}
120
121const std::string &
122Event::basename() const
123{
124    return _basename;
125}
126
127bool
128Event::inHierarchy() const
129{
130    return _inHierarchy;
131}
132
133sc_core::sc_object *
134Event::getParentObject() const
135{
136    return parent;
137}
138
139void
140Event::notify(StaticSensitivities &senses)
141{
142    for (auto s: senses)
143        s->notify(this);
144}
145
146void
147Event::notify(DynamicSensitivities &senses)
148{
149    int size = senses.size();
150    int pos = 0;
151    while (pos < size) {
152        if (senses[pos]->notify(this))
153            senses[pos] = senses[--size];
154        else
155            pos++;
156    }
157    senses.resize(size);
158}
159
160void
161Event::notify()
162{
163    if (scheduler.inUpdate())
164        SC_REPORT_ERROR(sc_core::SC_ID_IMMEDIATE_NOTIFICATION_, "");
165
166    // An immediate notification overrides any pending delayed notification.
167    if (delayedNotify.scheduled())
168        scheduler.deschedule(&delayedNotify);
169
170    _triggeredStamp = scheduler.changeStamp();
171    notify(staticSenseMethod);
172    notify(dynamicSenseMethod);
173    notify(staticSenseThread);
174    notify(dynamicSenseThread);
175}
176
177void
178Event::notify(const sc_core::sc_time &t)
179{
180    if (delayedNotify.scheduled()) {
181        if (scheduler.delayed(t) >= delayedNotify.when())
182            return;
183
184        scheduler.deschedule(&delayedNotify);
185    }
186    scheduler.schedule(&delayedNotify, t);
187}
188
189void
190Event::notifyDelayed(const sc_core::sc_time &t)
191{
192    if (delayedNotify.scheduled())
193        SC_REPORT_ERROR(sc_core::SC_ID_NOTIFY_DELAYED_, "");
194    notify(t);
195}
196
197void
198Event::cancel()
199{
200    if (delayedNotify.scheduled())
201        scheduler.deschedule(&delayedNotify);
202}
203
204bool
205Event::triggered() const
206{
207    return _triggeredStamp == scheduler.changeStamp();
208}
209
210void
211Event::clearParent()
212{
213    if (!parent)
214        return;
215    Object::getFromScObject(parent)->delChildEvent(sc_event());
216    parent = nullptr;
217    topLevelEvents.emplace(topLevelEvents.end(), sc_event());
218}
219
220Events topLevelEvents;
221Events allEvents;
222
223EventsIt
224findEvent(const std::string &name)
225{
226    EventsIt it;
227    for (it = allEvents.begin(); it != allEvents.end(); it++)
228        if (!strcmp((*it)->name(), name.c_str()))
229            break;
230
231    return it;
232}
233
234} // namespace sc_gem5
235