scheduler.cc (13308:30e825b4fd46) scheduler.cc (13312:a7685ffbead8)
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/scheduler.hh"
31
32#include "base/fiber.hh"
33#include "base/logging.hh"
34#include "sim/eventq.hh"
35#include "systemc/core/kernel.hh"
36#include "systemc/ext/core/sc_main.hh"
37#include "systemc/ext/utils/sc_report.hh"
38#include "systemc/ext/utils/sc_report_handler.hh"
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/scheduler.hh"
31
32#include "base/fiber.hh"
33#include "base/logging.hh"
34#include "sim/eventq.hh"
35#include "systemc/core/kernel.hh"
36#include "systemc/ext/core/sc_main.hh"
37#include "systemc/ext/utils/sc_report.hh"
38#include "systemc/ext/utils/sc_report_handler.hh"
39#include "systemc/utils/report.hh"
39#include "systemc/utils/tracefile.hh"
40
41namespace sc_gem5
42{
43
44Scheduler::Scheduler() :
45 eq(nullptr), readyEvent(this, false, ReadyPriority),
46 pauseEvent(this, false, PausePriority),
47 stopEvent(this, false, StopPriority),
48 scMain(nullptr), _throwToScMain(nullptr),
49 starvationEvent(this, false, StarvationPriority),
50 _elaborationDone(false), _started(false), _stopNow(false),
51 _status(StatusOther), maxTickEvent(this, false, MaxTickPriority),
52 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
53 _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
54{}
55
56Scheduler::~Scheduler()
57{
58 // Clear out everything that belongs to us to make sure nobody tries to
59 // clear themselves out after the scheduler goes away.
60 clear();
61}
62
63void
64Scheduler::clear()
65{
66 // Delta notifications.
67 while (!deltas.empty())
68 deltas.front()->deschedule();
69
70 // Timed notifications.
71 for (auto &tsp: timeSlots) {
72 TimeSlot *&ts = tsp.second;
73 while (!ts->events.empty())
74 ts->events.front()->deschedule();
75 deschedule(ts);
76 }
77 timeSlots.clear();
78
79 // gem5 events.
80 if (readyEvent.scheduled())
81 deschedule(&readyEvent);
82 if (pauseEvent.scheduled())
83 deschedule(&pauseEvent);
84 if (stopEvent.scheduled())
85 deschedule(&stopEvent);
86 if (starvationEvent.scheduled())
87 deschedule(&starvationEvent);
88 if (maxTickEvent.scheduled())
89 deschedule(&maxTickEvent);
90 if (timeAdvancesEvent.scheduled())
91 deschedule(&timeAdvancesEvent);
92
93 Process *p;
94 while ((p = initList.getNext()))
95 p->popListNode();
96 while ((p = readyListMethods.getNext()))
97 p->popListNode();
98 while ((p = readyListThreads.getNext()))
99 p->popListNode();
100
101 Channel *c;
102 while ((c = updateList.getNext()))
103 c->popListNode();
104}
105
106void
107Scheduler::initPhase()
108{
109 for (Process *p = initList.getNext(); p; p = initList.getNext()) {
110 p->popListNode();
111
112 if (p->dontInitialize()) {
113 if (!p->hasStaticSensitivities() && !p->internal()) {
114 SC_REPORT_WARNING(
115 "(W558) disable() or dont_initialize() called on "
116 "process with no static sensitivity, it will be "
117 "orphaned", p->name());
118 }
119 } else {
120 p->ready();
121 }
122 }
123
124 runUpdate();
125 runDelta();
126
127 for (auto ets: eventsToSchedule)
128 eq->schedule(ets.first, ets.second);
129 eventsToSchedule.clear();
130
131 if (_started) {
132 if (!runToTime && starved())
133 scheduleStarvationEvent();
134 kernel->status(::sc_core::SC_RUNNING);
135 }
136
137 initDone = true;
138
139 status(StatusOther);
140
141 scheduleTimeAdvancesEvent();
142}
143
144void
145Scheduler::reg(Process *p)
146{
147 if (initDone) {
148 // If not marked as dontInitialize, mark as ready.
149 if (!p->dontInitialize())
150 p->ready();
151 } else {
152 // Otherwise, record that this process should be initialized once we
153 // get there.
154 initList.pushLast(p);
155 }
156}
157
158void
159Scheduler::yield()
160{
161 // Pull a process from the active list.
162 _current = getNextReady();
163 if (!_current) {
164 // There are no more processes, so return control to evaluate.
165 Fiber::primaryFiber()->run();
166 } else {
167 _current->popListNode();
168 // Switch to whatever Fiber is supposed to run this process. All
169 // Fibers which aren't running should be parked at this line.
170 _current->fiber()->run();
171 // If the current process needs to be manually started, start it.
172 if (_current && _current->needsStart()) {
173 _current->needsStart(false);
174 // If a process hasn't started yet, "resetting" it just starts it
175 // and signals its reset event.
176 if (_current->inReset())
177 _current->resetEvent().notify();
178 try {
179 _current->run();
180 } catch (...) {
181 throwToScMain();
182 }
183 }
184 }
185 if (_current && !_current->needsStart()) {
186 if (_current->excWrapper) {
187 auto ew = _current->excWrapper;
188 _current->excWrapper = nullptr;
189 ew->throw_it();
190 } else if (_current->inReset()) {
191 _current->reset(false);
192 }
193 }
194}
195
196void
197Scheduler::ready(Process *p)
198{
199 if (_stopNow)
200 return;
201
202 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
203 readyListMethods.pushLast(p);
204 else
205 readyListThreads.pushLast(p);
206
207 if (!inEvaluate())
208 scheduleReadyEvent();
209}
210
211void
212Scheduler::resume(Process *p)
213{
214 if (initDone)
215 ready(p);
216 else
217 initList.pushLast(p);
218}
219
220bool
221listContains(ListNode *list, ListNode *target)
222{
223 ListNode *n = list->nextListNode;
224 while (n != list)
225 if (n == target)
226 return true;
227 return false;
228}
229
230bool
231Scheduler::suspend(Process *p)
232{
233 bool was_ready;
234 if (initDone) {
235 // After initialization, check if we're on a ready list.
236 was_ready = (p->nextListNode != nullptr);
237 p->popListNode();
238 } else {
239 // Nothing is ready before init.
240 was_ready = false;
241 }
242 return was_ready;
243}
244
245void
246Scheduler::requestUpdate(Channel *c)
247{
248 updateList.pushLast(c);
249 if (!inEvaluate())
250 scheduleReadyEvent();
251}
252
253void
254Scheduler::scheduleReadyEvent()
255{
256 // Schedule the evaluate and update phases.
257 if (!readyEvent.scheduled()) {
258 schedule(&readyEvent);
259 if (starvationEvent.scheduled())
260 deschedule(&starvationEvent);
261 }
262}
263
264void
265Scheduler::scheduleStarvationEvent()
266{
267 if (!starvationEvent.scheduled()) {
268 schedule(&starvationEvent);
269 if (readyEvent.scheduled())
270 deschedule(&readyEvent);
271 }
272}
273
274void
275Scheduler::runReady()
276{
277 scheduleTimeAdvancesEvent();
278
279 bool empty = readyListMethods.empty() && readyListThreads.empty();
280 lastReadyTick = getCurTick();
281
282 // The evaluation phase.
283 status(StatusEvaluate);
284 do {
285 yield();
286 } while (getNextReady());
287 _current = nullptr;
288
289 if (!empty) {
290 _numCycles++;
291 _changeStamp++;
292 }
293
294 if (_stopNow) {
295 status(StatusOther);
296 return;
297 }
298
299 runUpdate();
300 if (!traceFiles.empty())
301 trace(true);
302 runDelta();
303
304 if (!runToTime && starved())
305 scheduleStarvationEvent();
306
307 if (runOnce)
308 schedulePause();
309
310 status(StatusOther);
311}
312
313void
314Scheduler::runUpdate()
315{
316 status(StatusUpdate);
317
318 try {
319 Channel *channel = updateList.getNext();
320 while (channel) {
321 channel->popListNode();
322 channel->update();
323 channel = updateList.getNext();
324 }
325 } catch (...) {
326 throwToScMain();
327 }
328}
329
330void
331Scheduler::runDelta()
332{
333 status(StatusDelta);
334
335 try {
336 while (!deltas.empty())
337 deltas.back()->run();
338 } catch (...) {
339 throwToScMain();
340 }
341}
342
343void
344Scheduler::pause()
345{
346 status(StatusPaused);
347 kernel->status(::sc_core::SC_PAUSED);
348 runOnce = false;
349 if (scMain && !scMain->finished())
350 scMain->run();
351}
352
353void
354Scheduler::stop()
355{
356 status(StatusStopped);
357 kernel->stop();
358
359 clear();
360
361 runOnce = false;
362 if (scMain && !scMain->finished())
363 scMain->run();
364}
365
366void
367Scheduler::start(Tick max_tick, bool run_to_time)
368{
369 // We should be running from sc_main. Keep track of that Fiber to return
370 // to later.
371 scMain = Fiber::currentFiber();
372
373 _started = true;
374 status(StatusOther);
375 runToTime = run_to_time;
376
377 maxTick = max_tick;
378 lastReadyTick = getCurTick();
379
380 if (initDone) {
381 if (!runToTime && starved())
382 scheduleStarvationEvent();
383 kernel->status(::sc_core::SC_RUNNING);
384 }
385
386 schedule(&maxTickEvent, maxTick);
387 scheduleTimeAdvancesEvent();
388
389 // Return to gem5 to let it run events, etc.
390 Fiber::primaryFiber()->run();
391
392 if (pauseEvent.scheduled())
393 deschedule(&pauseEvent);
394 if (stopEvent.scheduled())
395 deschedule(&stopEvent);
396 if (maxTickEvent.scheduled())
397 deschedule(&maxTickEvent);
398 if (starvationEvent.scheduled())
399 deschedule(&starvationEvent);
400
401 if (_throwToScMain) {
402 const ::sc_core::sc_report *to_throw = _throwToScMain;
403 _throwToScMain = nullptr;
404 throw *to_throw;
405 }
406}
407
408void
409Scheduler::oneCycle()
410{
411 runOnce = true;
412 scheduleReadyEvent();
413 start(::MaxTick, false);
414}
415
416void
417Scheduler::schedulePause()
418{
419 if (pauseEvent.scheduled())
420 return;
421
422 schedule(&pauseEvent);
423}
424
425void
426Scheduler::throwToScMain()
427{
428 ::sc_core::sc_report report = reportifyException();
429 _throwToScMain = &report;
430 status(StatusOther);
431 scMain->run();
432}
433
434void
435Scheduler::scheduleStop(bool finish_delta)
436{
437 if (stopEvent.scheduled())
438 return;
439
440 if (!finish_delta) {
441 _stopNow = true;
442 // If we're not supposed to finish the delta cycle, flush all
443 // pending activity.
444 clear();
445 }
446 schedule(&stopEvent);
447}
448
449void
450Scheduler::trace(bool delta)
451{
452 for (auto tf: traceFiles)
453 tf->trace(delta);
454}
455
456Scheduler scheduler;
457
458namespace {
459
460void
461throwingReportHandler(const ::sc_core::sc_report &r,
462 const ::sc_core::sc_actions &)
463{
464 throw r;
465}
466
467} // anonymous namespace
468
469const ::sc_core::sc_report
470reportifyException()
471{
40#include "systemc/utils/tracefile.hh"
41
42namespace sc_gem5
43{
44
45Scheduler::Scheduler() :
46 eq(nullptr), readyEvent(this, false, ReadyPriority),
47 pauseEvent(this, false, PausePriority),
48 stopEvent(this, false, StopPriority),
49 scMain(nullptr), _throwToScMain(nullptr),
50 starvationEvent(this, false, StarvationPriority),
51 _elaborationDone(false), _started(false), _stopNow(false),
52 _status(StatusOther), maxTickEvent(this, false, MaxTickPriority),
53 timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0),
54 _changeStamp(0), _current(nullptr), initDone(false), runOnce(false)
55{}
56
57Scheduler::~Scheduler()
58{
59 // Clear out everything that belongs to us to make sure nobody tries to
60 // clear themselves out after the scheduler goes away.
61 clear();
62}
63
64void
65Scheduler::clear()
66{
67 // Delta notifications.
68 while (!deltas.empty())
69 deltas.front()->deschedule();
70
71 // Timed notifications.
72 for (auto &tsp: timeSlots) {
73 TimeSlot *&ts = tsp.second;
74 while (!ts->events.empty())
75 ts->events.front()->deschedule();
76 deschedule(ts);
77 }
78 timeSlots.clear();
79
80 // gem5 events.
81 if (readyEvent.scheduled())
82 deschedule(&readyEvent);
83 if (pauseEvent.scheduled())
84 deschedule(&pauseEvent);
85 if (stopEvent.scheduled())
86 deschedule(&stopEvent);
87 if (starvationEvent.scheduled())
88 deschedule(&starvationEvent);
89 if (maxTickEvent.scheduled())
90 deschedule(&maxTickEvent);
91 if (timeAdvancesEvent.scheduled())
92 deschedule(&timeAdvancesEvent);
93
94 Process *p;
95 while ((p = initList.getNext()))
96 p->popListNode();
97 while ((p = readyListMethods.getNext()))
98 p->popListNode();
99 while ((p = readyListThreads.getNext()))
100 p->popListNode();
101
102 Channel *c;
103 while ((c = updateList.getNext()))
104 c->popListNode();
105}
106
107void
108Scheduler::initPhase()
109{
110 for (Process *p = initList.getNext(); p; p = initList.getNext()) {
111 p->popListNode();
112
113 if (p->dontInitialize()) {
114 if (!p->hasStaticSensitivities() && !p->internal()) {
115 SC_REPORT_WARNING(
116 "(W558) disable() or dont_initialize() called on "
117 "process with no static sensitivity, it will be "
118 "orphaned", p->name());
119 }
120 } else {
121 p->ready();
122 }
123 }
124
125 runUpdate();
126 runDelta();
127
128 for (auto ets: eventsToSchedule)
129 eq->schedule(ets.first, ets.second);
130 eventsToSchedule.clear();
131
132 if (_started) {
133 if (!runToTime && starved())
134 scheduleStarvationEvent();
135 kernel->status(::sc_core::SC_RUNNING);
136 }
137
138 initDone = true;
139
140 status(StatusOther);
141
142 scheduleTimeAdvancesEvent();
143}
144
145void
146Scheduler::reg(Process *p)
147{
148 if (initDone) {
149 // If not marked as dontInitialize, mark as ready.
150 if (!p->dontInitialize())
151 p->ready();
152 } else {
153 // Otherwise, record that this process should be initialized once we
154 // get there.
155 initList.pushLast(p);
156 }
157}
158
159void
160Scheduler::yield()
161{
162 // Pull a process from the active list.
163 _current = getNextReady();
164 if (!_current) {
165 // There are no more processes, so return control to evaluate.
166 Fiber::primaryFiber()->run();
167 } else {
168 _current->popListNode();
169 // Switch to whatever Fiber is supposed to run this process. All
170 // Fibers which aren't running should be parked at this line.
171 _current->fiber()->run();
172 // If the current process needs to be manually started, start it.
173 if (_current && _current->needsStart()) {
174 _current->needsStart(false);
175 // If a process hasn't started yet, "resetting" it just starts it
176 // and signals its reset event.
177 if (_current->inReset())
178 _current->resetEvent().notify();
179 try {
180 _current->run();
181 } catch (...) {
182 throwToScMain();
183 }
184 }
185 }
186 if (_current && !_current->needsStart()) {
187 if (_current->excWrapper) {
188 auto ew = _current->excWrapper;
189 _current->excWrapper = nullptr;
190 ew->throw_it();
191 } else if (_current->inReset()) {
192 _current->reset(false);
193 }
194 }
195}
196
197void
198Scheduler::ready(Process *p)
199{
200 if (_stopNow)
201 return;
202
203 if (p->procKind() == ::sc_core::SC_METHOD_PROC_)
204 readyListMethods.pushLast(p);
205 else
206 readyListThreads.pushLast(p);
207
208 if (!inEvaluate())
209 scheduleReadyEvent();
210}
211
212void
213Scheduler::resume(Process *p)
214{
215 if (initDone)
216 ready(p);
217 else
218 initList.pushLast(p);
219}
220
221bool
222listContains(ListNode *list, ListNode *target)
223{
224 ListNode *n = list->nextListNode;
225 while (n != list)
226 if (n == target)
227 return true;
228 return false;
229}
230
231bool
232Scheduler::suspend(Process *p)
233{
234 bool was_ready;
235 if (initDone) {
236 // After initialization, check if we're on a ready list.
237 was_ready = (p->nextListNode != nullptr);
238 p->popListNode();
239 } else {
240 // Nothing is ready before init.
241 was_ready = false;
242 }
243 return was_ready;
244}
245
246void
247Scheduler::requestUpdate(Channel *c)
248{
249 updateList.pushLast(c);
250 if (!inEvaluate())
251 scheduleReadyEvent();
252}
253
254void
255Scheduler::scheduleReadyEvent()
256{
257 // Schedule the evaluate and update phases.
258 if (!readyEvent.scheduled()) {
259 schedule(&readyEvent);
260 if (starvationEvent.scheduled())
261 deschedule(&starvationEvent);
262 }
263}
264
265void
266Scheduler::scheduleStarvationEvent()
267{
268 if (!starvationEvent.scheduled()) {
269 schedule(&starvationEvent);
270 if (readyEvent.scheduled())
271 deschedule(&readyEvent);
272 }
273}
274
275void
276Scheduler::runReady()
277{
278 scheduleTimeAdvancesEvent();
279
280 bool empty = readyListMethods.empty() && readyListThreads.empty();
281 lastReadyTick = getCurTick();
282
283 // The evaluation phase.
284 status(StatusEvaluate);
285 do {
286 yield();
287 } while (getNextReady());
288 _current = nullptr;
289
290 if (!empty) {
291 _numCycles++;
292 _changeStamp++;
293 }
294
295 if (_stopNow) {
296 status(StatusOther);
297 return;
298 }
299
300 runUpdate();
301 if (!traceFiles.empty())
302 trace(true);
303 runDelta();
304
305 if (!runToTime && starved())
306 scheduleStarvationEvent();
307
308 if (runOnce)
309 schedulePause();
310
311 status(StatusOther);
312}
313
314void
315Scheduler::runUpdate()
316{
317 status(StatusUpdate);
318
319 try {
320 Channel *channel = updateList.getNext();
321 while (channel) {
322 channel->popListNode();
323 channel->update();
324 channel = updateList.getNext();
325 }
326 } catch (...) {
327 throwToScMain();
328 }
329}
330
331void
332Scheduler::runDelta()
333{
334 status(StatusDelta);
335
336 try {
337 while (!deltas.empty())
338 deltas.back()->run();
339 } catch (...) {
340 throwToScMain();
341 }
342}
343
344void
345Scheduler::pause()
346{
347 status(StatusPaused);
348 kernel->status(::sc_core::SC_PAUSED);
349 runOnce = false;
350 if (scMain && !scMain->finished())
351 scMain->run();
352}
353
354void
355Scheduler::stop()
356{
357 status(StatusStopped);
358 kernel->stop();
359
360 clear();
361
362 runOnce = false;
363 if (scMain && !scMain->finished())
364 scMain->run();
365}
366
367void
368Scheduler::start(Tick max_tick, bool run_to_time)
369{
370 // We should be running from sc_main. Keep track of that Fiber to return
371 // to later.
372 scMain = Fiber::currentFiber();
373
374 _started = true;
375 status(StatusOther);
376 runToTime = run_to_time;
377
378 maxTick = max_tick;
379 lastReadyTick = getCurTick();
380
381 if (initDone) {
382 if (!runToTime && starved())
383 scheduleStarvationEvent();
384 kernel->status(::sc_core::SC_RUNNING);
385 }
386
387 schedule(&maxTickEvent, maxTick);
388 scheduleTimeAdvancesEvent();
389
390 // Return to gem5 to let it run events, etc.
391 Fiber::primaryFiber()->run();
392
393 if (pauseEvent.scheduled())
394 deschedule(&pauseEvent);
395 if (stopEvent.scheduled())
396 deschedule(&stopEvent);
397 if (maxTickEvent.scheduled())
398 deschedule(&maxTickEvent);
399 if (starvationEvent.scheduled())
400 deschedule(&starvationEvent);
401
402 if (_throwToScMain) {
403 const ::sc_core::sc_report *to_throw = _throwToScMain;
404 _throwToScMain = nullptr;
405 throw *to_throw;
406 }
407}
408
409void
410Scheduler::oneCycle()
411{
412 runOnce = true;
413 scheduleReadyEvent();
414 start(::MaxTick, false);
415}
416
417void
418Scheduler::schedulePause()
419{
420 if (pauseEvent.scheduled())
421 return;
422
423 schedule(&pauseEvent);
424}
425
426void
427Scheduler::throwToScMain()
428{
429 ::sc_core::sc_report report = reportifyException();
430 _throwToScMain = &report;
431 status(StatusOther);
432 scMain->run();
433}
434
435void
436Scheduler::scheduleStop(bool finish_delta)
437{
438 if (stopEvent.scheduled())
439 return;
440
441 if (!finish_delta) {
442 _stopNow = true;
443 // If we're not supposed to finish the delta cycle, flush all
444 // pending activity.
445 clear();
446 }
447 schedule(&stopEvent);
448}
449
450void
451Scheduler::trace(bool delta)
452{
453 for (auto tf: traceFiles)
454 tf->trace(delta);
455}
456
457Scheduler scheduler;
458
459namespace {
460
461void
462throwingReportHandler(const ::sc_core::sc_report &r,
463 const ::sc_core::sc_actions &)
464{
465 throw r;
466}
467
468} // anonymous namespace
469
470const ::sc_core::sc_report
471reportifyException()
472{
472 ::sc_core::sc_report_handler_proc old_handler =
473 ::sc_core::sc_report_handler::get_handler();
473 ::sc_core::sc_report_handler_proc old_handler = reportHandlerProc;
474 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
475
476 try {
477 try {
478 // Rethrow the current exception so we can catch it and throw an
479 // sc_report instead if it's not a type we recognize/can handle.
480 throw;
481 } catch (const ::sc_core::sc_report &) {
482 // It's already a sc_report, so nothing to do.
483 throw;
484 } catch (const ::sc_core::sc_unwind_exception &) {
485 panic("Kill/reset exception escaped a Process::run()");
486 } catch (const std::exception &e) {
487 SC_REPORT_ERROR("uncaught exception", e.what());
488 } catch (const char *msg) {
489 SC_REPORT_ERROR("uncaught exception", msg);
490 } catch (...) {
491 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
492 }
493 } catch (const ::sc_core::sc_report &r) {
494 ::sc_core::sc_report_handler::set_handler(old_handler);
495 return r;
496 }
497 panic("No exception thrown in reportifyException.");
498}
499
500} // namespace sc_gem5
474 ::sc_core::sc_report_handler::set_handler(&throwingReportHandler);
475
476 try {
477 try {
478 // Rethrow the current exception so we can catch it and throw an
479 // sc_report instead if it's not a type we recognize/can handle.
480 throw;
481 } catch (const ::sc_core::sc_report &) {
482 // It's already a sc_report, so nothing to do.
483 throw;
484 } catch (const ::sc_core::sc_unwind_exception &) {
485 panic("Kill/reset exception escaped a Process::run()");
486 } catch (const std::exception &e) {
487 SC_REPORT_ERROR("uncaught exception", e.what());
488 } catch (const char *msg) {
489 SC_REPORT_ERROR("uncaught exception", msg);
490 } catch (...) {
491 SC_REPORT_ERROR("uncaught exception", "UNKNOWN EXCEPTION");
492 }
493 } catch (const ::sc_core::sc_report &r) {
494 ::sc_core::sc_report_handler::set_handler(old_handler);
495 return r;
496 }
497 panic("No exception thrown in reportifyException.");
498}
499
500} // namespace sc_gem5