2 * Copyright (c) 2014 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2006 The Regents of The University of Michigan
15 * Copyright (c) 2013 Advanced Micro Devices, Inc.
16 * Copyright (c) 2013 Mark D. Hill and David A. Wood
17 * All rights reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met: redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer;
23 * redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution;
26 * neither the name of the copyright holders nor the names of its
27 * contributors may be used to endorse or promote products derived from
28 * this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 * Authors: Nathan Binkert
52 * Defines an sc_module type to wrap a gem5 simulation. The 'evaluate'
53 * thread on that module implements the gem5 event loop.
55 * This currently only supports a single event queue and strictly
56 * cooperatively threaded SystemC threads and so there should be at
57 * most one Gem5Module instantiated in any simulation.
60 #include "base/misc.hh"
61 #include "base/pollevent.hh"
62 #include "base/trace.hh"
63 #include "debug/Event.hh"
64 #include "sc_module.hh"
65 #include "sim/async.hh"
66 #include "sim/core.hh"
67 #include "sim/eventq.hh"
68 #include "sim/sim_exit.hh"
69 #include "sim/stat_control.hh"
74 /** There are assumptions throughout Gem5SystemC file that a tick is 1ps.
75 * Make this the case */
79 ::setClockFrequency(1000000000000);
82 Module::Module(sc_core::sc_module_name name
) : sc_core::sc_channel(name
),
86 sensitive
<< eventLoopEnterEvent
;
89 SC_METHOD(serviceExternalEvent
);
90 sensitive
<< externalSchedulingEvent
;
95 Module::SCEventQueue::wakeup(Tick when
)
97 DPRINTF(Event
, "waking up SCEventQueue\n");
98 /* Don't bother to use 'when' for now */
103 Module::setupEventQueues(Module
&module
)
105 fatal_if(mainEventQueue
.size() != 0,
106 "Gem5SystemC::Module::setupEventQueues must be called"
107 " before any gem5 event queues are set up");
109 numMainEventQueues
= 1;
110 mainEventQueue
.push_back(new SCEventQueue("events", module
));
111 curEventQueue(getEventQueue(0));
117 EventQueue
*eventq
= getEventQueue(0);
118 Tick systemc_time
= sc_core::sc_time_stamp().value();
119 Tick gem5_time
= curTick();
121 /* gem5 time *must* lag SystemC as SystemC is the master */
122 fatal_if(gem5_time
> systemc_time
, "gem5 time must lag SystemC time"
123 " gem5: %d SystemC: %d", gem5_time
, systemc_time
);
125 eventq
->setCurTick(systemc_time
);
127 if (!eventq
->empty()) {
128 Tick next_event_time M5_VAR_USED
= eventq
->nextTick();
130 fatal_if(gem5_time
> next_event_time
,
131 "Missed an event at time %d gem5: %d, SystemC: %d",
132 next_event_time
, gem5_time
, systemc_time
);
137 Module::notify(sc_core::sc_time time_from_now
)
139 externalSchedulingEvent
.notify(time_from_now
);
143 Module::serviceAsyncEvent()
145 EventQueue
*eventq
= getEventQueue(0);
146 std::lock_guard
<EventQueue
> lock(*eventq
);
150 /* Catch up gem5 time with SystemC time so that any event here won't
151 * be in the past relative to the current time */
152 Tick systemc_time
= sc_core::sc_time_stamp().value();
154 /* Move time on to match SystemC */
158 if (async_statdump
|| async_statreset
) {
159 Stats::schedStatEvent(async_statdump
, async_statreset
);
160 async_statdump
= false;
161 async_statreset
= false;
166 exitSimLoop("user interrupt received");
175 fatal("received async_exception, shouldn't be possible");
179 Module::serviceExternalEvent()
181 EventQueue
*eventq
= getEventQueue(0);
183 if (!in_simulate
&& !async_event
)
184 warn("Gem5SystemC external event received while not in simulate");
189 if (in_simulate
&& !eventq
->empty())
196 EventQueue
*eventq
= getEventQueue(0);
198 fatal_if(!in_simulate
, "Gem5SystemC event loop entered while"
199 " outside Gem5SystemC::Module::simulate");
204 while (!eventq
->empty()) {
205 Tick next_event_time
= eventq
->nextTick();
207 /* Move time on to match SystemC */
210 Tick gem5_time
= curTick();
213 if (wait_exit_time
> sc_core::sc_time_stamp().value()) {
214 DPRINTF(Event
, "Woken up early\n");
215 wait_exit_time
= sc_core::sc_time_stamp().value();
218 if (gem5_time
< next_event_time
) {
219 Tick wait_period
= next_event_time
- gem5_time
;
220 wait_exit_time
= gem5_time
+ wait_period
;
222 DPRINTF(Event
, "Waiting for %d ticks for next gem5 event\n",
225 /* The next event is scheduled in the future, wait until
226 * then or until externalSchedulingEvent */
227 eventLoopEnterEvent
.notify(sc_core::sc_time::from_value(
228 sc_dt::uint64(wait_period
)));
231 } else if (gem5_time
> next_event_time
) {
232 Tick systemc_time
= sc_core::sc_time_stamp().value();
234 /* Missed event, for some reason the above test didn't work
235 * or an event was scheduled in the past */
236 fatal("Missed an event at time %d gem5: %d, SystemC: %d",
237 next_event_time
, gem5_time
, systemc_time
);
239 /* Service an event */
240 exitEvent
= eventq
->serviceOne();
243 eventLoopExitEvent
.notify(sc_core::SC_ZERO_TIME
);
249 fatal("Ran out of events without seeing exit event");
252 GlobalSimLoopExitEvent
*
253 Module::simulate(Tick num_cycles
)
255 inform("Entering event queue @ %d. Starting simulation...", curTick());
257 if (num_cycles
< MaxTick
- curTick())
258 num_cycles
= curTick() + num_cycles
;
259 else /* counter would roll over or be set to MaxTick anyhow */
260 num_cycles
= MaxTick
;
262 GlobalEvent
*limit_event
= new GlobalSimLoopExitEvent(num_cycles
,
263 "simulate() limit reached", 0, 0);
267 /* Cancel any outstanding events */
268 eventLoopExitEvent
.cancel();
269 externalSchedulingEvent
.cancel();
272 eventLoopEnterEvent
.notify(sc_core::SC_ZERO_TIME
);
274 /* Wait for event queue to exit, guarded by exitEvent just incase
275 * it already has exited and we don't want to completely rely
276 * on notify semantics */
278 wait(eventLoopExitEvent
);
280 /* Cancel any outstanding event loop entries */
281 eventLoopEnterEvent
.cancel();
284 /* Locate the global exit event */
285 BaseGlobalEvent
*global_event
= exitEvent
->globalEvent();
286 assert(global_event
!= NULL
);
288 GlobalSimLoopExitEvent
*global_exit_event
=
289 dynamic_cast<GlobalSimLoopExitEvent
*>(global_event
);
290 assert(global_exit_event
!= NULL
);
292 if (global_exit_event
!= limit_event
) {
293 limit_event
->deschedule();
297 return global_exit_event
;