113372Sgabeblack@google.com/*
213372Sgabeblack@google.com * Copyright (c) 2014 ARM Limited
313372Sgabeblack@google.com * All rights reserved
413372Sgabeblack@google.com *
513372Sgabeblack@google.com * The license below extends only to copyright in the software and shall
613372Sgabeblack@google.com * not be construed as granting a license to any other intellectual
713372Sgabeblack@google.com * property including but not limited to intellectual property relating
813372Sgabeblack@google.com * to a hardware implementation of the functionality of the software
913372Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1013372Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1113372Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1213372Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1313372Sgabeblack@google.com *
1413372Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan
1513372Sgabeblack@google.com * Copyright (c) 2013 Advanced Micro Devices, Inc.
1613372Sgabeblack@google.com * Copyright (c) 2013 Mark D. Hill and David A. Wood
1713372Sgabeblack@google.com * All rights reserved.
1813372Sgabeblack@google.com *
1913372Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
2013372Sgabeblack@google.com * modification, are permitted provided that the following conditions are
2113372Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
2213372Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
2313372Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
2413372Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2513372Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2613372Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2713372Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2813372Sgabeblack@google.com * this software without specific prior written permission.
2913372Sgabeblack@google.com *
3013372Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3113372Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3213372Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3313372Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3413372Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3513372Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3613372Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3713372Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3813372Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3913372Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4013372Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4113372Sgabeblack@google.com *
4213372Sgabeblack@google.com * Authors: Nathan Binkert
4313372Sgabeblack@google.com *          Steve Reinhardt
4413372Sgabeblack@google.com *          Andrew Bardsley
4513372Sgabeblack@google.com *          Matthias Jung
4613372Sgabeblack@google.com *          Christian Menard
4713372Sgabeblack@google.com */
4813372Sgabeblack@google.com
4913372Sgabeblack@google.com/**
5013372Sgabeblack@google.com * @file
5113372Sgabeblack@google.com *
5213372Sgabeblack@google.com * Defines an sc_module type to wrap a gem5 simulation.  The 'evaluate'
5313372Sgabeblack@google.com * thread on that module implements the gem5 event loop.
5413372Sgabeblack@google.com *
5513372Sgabeblack@google.com * This currently only supports a single event queue and strictly
5613372Sgabeblack@google.com * cooperatively threaded SystemC threads and so there should be at
5713372Sgabeblack@google.com * most one Gem5Module instantiated in any simulation.
5813372Sgabeblack@google.com */
5913372Sgabeblack@google.com
6013372Sgabeblack@google.com#include "base/logging.hh"
6113372Sgabeblack@google.com#include "base/pollevent.hh"
6213372Sgabeblack@google.com#include "base/trace.hh"
6313372Sgabeblack@google.com#include "debug/Event.hh"
6413372Sgabeblack@google.com#include "sc_module.hh"
6513372Sgabeblack@google.com#include "sim/async.hh"
6613372Sgabeblack@google.com#include "sim/core.hh"
6713372Sgabeblack@google.com#include "sim/eventq.hh"
6813372Sgabeblack@google.com#include "sim/sim_exit.hh"
6913372Sgabeblack@google.com#include "sim/stat_control.hh"
7013372Sgabeblack@google.com
7113372Sgabeblack@google.comnamespace Gem5SystemC
7213372Sgabeblack@google.com{
7313372Sgabeblack@google.com
7413372Sgabeblack@google.com/** There are assumptions throughout Gem5SystemC file that a tick is 1ps.
7513372Sgabeblack@google.com *  Make this the case */
7613372Sgabeblack@google.comvoid
7713372Sgabeblack@google.comsetTickFrequency()
7813372Sgabeblack@google.com{
7913372Sgabeblack@google.com    ::setClockFrequency(1000000000000);
8013372Sgabeblack@google.com}
8113372Sgabeblack@google.com
8213372Sgabeblack@google.comModule::Module(sc_core::sc_module_name name) : sc_core::sc_channel(name),
8313372Sgabeblack@google.com    in_simulate(false)
8413372Sgabeblack@google.com{
8513372Sgabeblack@google.com    SC_METHOD(eventLoop);
8613372Sgabeblack@google.com    sensitive << eventLoopEnterEvent;
8713372Sgabeblack@google.com    dont_initialize();
8813372Sgabeblack@google.com
8913372Sgabeblack@google.com    SC_METHOD(serviceExternalEvent);
9013372Sgabeblack@google.com    sensitive << externalSchedulingEvent;
9113372Sgabeblack@google.com    dont_initialize();
9213372Sgabeblack@google.com}
9313372Sgabeblack@google.com
9413372Sgabeblack@google.comvoid
9513372Sgabeblack@google.comModule::SCEventQueue::wakeup(Tick when)
9613372Sgabeblack@google.com{
9713372Sgabeblack@google.com    DPRINTF(Event, "waking up SCEventQueue\n");
9813372Sgabeblack@google.com    /* Don't bother to use 'when' for now */
9913372Sgabeblack@google.com    module.notify();
10013372Sgabeblack@google.com}
10113372Sgabeblack@google.com
10213372Sgabeblack@google.comvoid
10313372Sgabeblack@google.comModule::setupEventQueues(Module &module)
10413372Sgabeblack@google.com{
10513372Sgabeblack@google.com    fatal_if(mainEventQueue.size() != 0,
10613372Sgabeblack@google.com        "Gem5SystemC::Module::setupEventQueues must be called"
10713372Sgabeblack@google.com        " before any gem5 event queues are set up");
10813372Sgabeblack@google.com
10913372Sgabeblack@google.com    numMainEventQueues = 1;
11013372Sgabeblack@google.com    mainEventQueue.push_back(new SCEventQueue("events", module));
11113372Sgabeblack@google.com    curEventQueue(getEventQueue(0));
11213372Sgabeblack@google.com}
11313372Sgabeblack@google.com
11413372Sgabeblack@google.comvoid
11513372Sgabeblack@google.comModule::catchup()
11613372Sgabeblack@google.com{
11713372Sgabeblack@google.com    EventQueue *eventq = getEventQueue(0);
11813372Sgabeblack@google.com    Tick systemc_time = sc_core::sc_time_stamp().value();
11913372Sgabeblack@google.com    Tick gem5_time = curTick();
12013372Sgabeblack@google.com
12113372Sgabeblack@google.com    /* gem5 time *must* lag SystemC as SystemC is the master */
12213372Sgabeblack@google.com    fatal_if(gem5_time > systemc_time, "gem5 time must lag SystemC time"
12313372Sgabeblack@google.com        " gem5: %d SystemC: %d", gem5_time, systemc_time);
12413372Sgabeblack@google.com
12513372Sgabeblack@google.com    eventq->setCurTick(systemc_time);
12613372Sgabeblack@google.com
12713372Sgabeblack@google.com    if (!eventq->empty()) {
12813372Sgabeblack@google.com        Tick next_event_time M5_VAR_USED = eventq->nextTick();
12913372Sgabeblack@google.com
13013372Sgabeblack@google.com        fatal_if(gem5_time > next_event_time,
13113372Sgabeblack@google.com            "Missed an event at time %d gem5: %d, SystemC: %d",
13213372Sgabeblack@google.com            next_event_time, gem5_time, systemc_time);
13313372Sgabeblack@google.com    }
13413372Sgabeblack@google.com}
13513372Sgabeblack@google.com
13613372Sgabeblack@google.comvoid
13713372Sgabeblack@google.comModule::notify(sc_core::sc_time time_from_now)
13813372Sgabeblack@google.com{
13913372Sgabeblack@google.com    externalSchedulingEvent.notify(time_from_now);
14013372Sgabeblack@google.com}
14113372Sgabeblack@google.com
14213372Sgabeblack@google.comvoid
14313372Sgabeblack@google.comModule::serviceAsyncEvent()
14413372Sgabeblack@google.com{
14513372Sgabeblack@google.com    EventQueue *eventq = getEventQueue(0);
14613372Sgabeblack@google.com    std::lock_guard<EventQueue> lock(*eventq);
14713372Sgabeblack@google.com
14813372Sgabeblack@google.com    assert(async_event);
14913372Sgabeblack@google.com
15013372Sgabeblack@google.com    /* Catch up gem5 time with SystemC time so that any event here won't
15113372Sgabeblack@google.com     * be in the past relative to the current time */
15213372Sgabeblack@google.com    Tick systemc_time = sc_core::sc_time_stamp().value();
15313372Sgabeblack@google.com
15413372Sgabeblack@google.com    /* Move time on to match SystemC */
15513372Sgabeblack@google.com    catchup();
15613372Sgabeblack@google.com
15713372Sgabeblack@google.com    async_event = false;
15813372Sgabeblack@google.com    if (async_statdump || async_statreset) {
15913372Sgabeblack@google.com        Stats::schedStatEvent(async_statdump, async_statreset);
16013372Sgabeblack@google.com        async_statdump = false;
16113372Sgabeblack@google.com        async_statreset = false;
16213372Sgabeblack@google.com    }
16313372Sgabeblack@google.com
16413372Sgabeblack@google.com    if (async_exit) {
16513372Sgabeblack@google.com        async_exit = false;
16613372Sgabeblack@google.com        exitSimLoop("user interrupt received");
16713372Sgabeblack@google.com    }
16813372Sgabeblack@google.com
16913372Sgabeblack@google.com    if (async_io) {
17013372Sgabeblack@google.com        async_io = false;
17113372Sgabeblack@google.com        pollQueue.service();
17213372Sgabeblack@google.com    }
17313372Sgabeblack@google.com
17413372Sgabeblack@google.com    if (async_exception)
17513372Sgabeblack@google.com        fatal("received async_exception, shouldn't be possible");
17613372Sgabeblack@google.com}
17713372Sgabeblack@google.com
17813372Sgabeblack@google.comvoid
17913372Sgabeblack@google.comModule::serviceExternalEvent()
18013372Sgabeblack@google.com{
18113372Sgabeblack@google.com    EventQueue *eventq = getEventQueue(0);
18213372Sgabeblack@google.com
18313372Sgabeblack@google.com    if (!in_simulate && !async_event)
18413372Sgabeblack@google.com        warn("Gem5SystemC external event received while not in simulate");
18513372Sgabeblack@google.com
18613372Sgabeblack@google.com    if (async_event)
18713372Sgabeblack@google.com        serviceAsyncEvent();
18813372Sgabeblack@google.com
18913372Sgabeblack@google.com    if (in_simulate && !eventq->empty())
19013372Sgabeblack@google.com        eventLoop();
19113372Sgabeblack@google.com}
19213372Sgabeblack@google.com
19313372Sgabeblack@google.comvoid
19413372Sgabeblack@google.comModule::eventLoop()
19513372Sgabeblack@google.com{
19613372Sgabeblack@google.com    EventQueue *eventq = getEventQueue(0);
19713372Sgabeblack@google.com
19813372Sgabeblack@google.com    fatal_if(!in_simulate, "Gem5SystemC event loop entered while"
19913372Sgabeblack@google.com        " outside Gem5SystemC::Module::simulate");
20013372Sgabeblack@google.com
20113372Sgabeblack@google.com    if (async_event)
20213372Sgabeblack@google.com        serviceAsyncEvent();
20313372Sgabeblack@google.com
20413372Sgabeblack@google.com    while (!eventq->empty()) {
20513372Sgabeblack@google.com        Tick next_event_time = eventq->nextTick();
20613372Sgabeblack@google.com
20713372Sgabeblack@google.com        /* Move time on to match SystemC */
20813372Sgabeblack@google.com        catchup();
20913372Sgabeblack@google.com
21013372Sgabeblack@google.com        Tick gem5_time = curTick();
21113372Sgabeblack@google.com
21213372Sgabeblack@google.com        /* Woken up early */
21313372Sgabeblack@google.com        if (wait_exit_time > sc_core::sc_time_stamp().value()) {
21413372Sgabeblack@google.com            DPRINTF(Event, "Woken up early\n");
21513372Sgabeblack@google.com            wait_exit_time = sc_core::sc_time_stamp().value();
21613372Sgabeblack@google.com        }
21713372Sgabeblack@google.com
21813372Sgabeblack@google.com        if (gem5_time < next_event_time) {
21913372Sgabeblack@google.com            Tick wait_period = next_event_time - gem5_time;
22013372Sgabeblack@google.com            wait_exit_time = gem5_time + wait_period;
22113372Sgabeblack@google.com
22213372Sgabeblack@google.com            DPRINTF(Event, "Waiting for %d ticks for next gem5 event\n",
22313372Sgabeblack@google.com                wait_period);
22413372Sgabeblack@google.com
22513372Sgabeblack@google.com            /* The next event is scheduled in the future, wait until
22613372Sgabeblack@google.com             *  then or until externalSchedulingEvent */
22713372Sgabeblack@google.com            eventLoopEnterEvent.notify(sc_core::sc_time::from_value(
22813372Sgabeblack@google.com                sc_dt::uint64(wait_period)));
22913372Sgabeblack@google.com
23013372Sgabeblack@google.com            return;
23113372Sgabeblack@google.com        } else if (gem5_time > next_event_time) {
23213372Sgabeblack@google.com            Tick systemc_time = sc_core::sc_time_stamp().value();
23313372Sgabeblack@google.com
23413372Sgabeblack@google.com            /* Missed event, for some reason the above test didn't work
23513372Sgabeblack@google.com             *  or an event was scheduled in the past */
23613372Sgabeblack@google.com            fatal("Missed an event at time %d gem5: %d, SystemC: %d",
23713372Sgabeblack@google.com                next_event_time, gem5_time, systemc_time);
23813372Sgabeblack@google.com        } else {
23913372Sgabeblack@google.com            /* Service an event */
24013372Sgabeblack@google.com            exitEvent = eventq->serviceOne();
24113372Sgabeblack@google.com
24213372Sgabeblack@google.com            if (exitEvent) {
24313372Sgabeblack@google.com                eventLoopExitEvent.notify(sc_core::SC_ZERO_TIME);
24413372Sgabeblack@google.com                return;
24513372Sgabeblack@google.com            }
24613372Sgabeblack@google.com        }
24713372Sgabeblack@google.com    }
24813372Sgabeblack@google.com
24913372Sgabeblack@google.com    fatal("Ran out of events without seeing exit event");
25013372Sgabeblack@google.com}
25113372Sgabeblack@google.com
25213372Sgabeblack@google.comGlobalSimLoopExitEvent *
25313372Sgabeblack@google.comModule::simulate(Tick num_cycles)
25413372Sgabeblack@google.com{
25513372Sgabeblack@google.com    inform("Entering event queue @ %d.  Starting simulation...", curTick());
25613372Sgabeblack@google.com
25713372Sgabeblack@google.com    if (num_cycles < MaxTick - curTick())
25813372Sgabeblack@google.com        num_cycles = curTick() + num_cycles;
25913372Sgabeblack@google.com    else /* counter would roll over or be set to MaxTick anyhow */
26013372Sgabeblack@google.com        num_cycles = MaxTick;
26113372Sgabeblack@google.com
26213372Sgabeblack@google.com    GlobalEvent *limit_event = new GlobalSimLoopExitEvent(num_cycles,
26313372Sgabeblack@google.com        "simulate() limit reached", 0, 0);
26413372Sgabeblack@google.com
26513372Sgabeblack@google.com    exitEvent = NULL;
26613372Sgabeblack@google.com
26713372Sgabeblack@google.com    /* Cancel any outstanding events */
26813372Sgabeblack@google.com    eventLoopExitEvent.cancel();
26913372Sgabeblack@google.com    externalSchedulingEvent.cancel();
27013372Sgabeblack@google.com
27113372Sgabeblack@google.com    in_simulate = true;
27213372Sgabeblack@google.com    eventLoopEnterEvent.notify(sc_core::SC_ZERO_TIME);
27313372Sgabeblack@google.com
27413372Sgabeblack@google.com    /* Wait for event queue to exit, guarded by exitEvent just incase
27513372Sgabeblack@google.com     *  it already has exited and we don't want to completely rely
27613372Sgabeblack@google.com     *  on notify semantics */
27713372Sgabeblack@google.com    if (!exitEvent)
27813372Sgabeblack@google.com        wait(eventLoopExitEvent);
27913372Sgabeblack@google.com
28013372Sgabeblack@google.com    /* Cancel any outstanding event loop entries */
28113372Sgabeblack@google.com    eventLoopEnterEvent.cancel();
28213372Sgabeblack@google.com    in_simulate = false;
28313372Sgabeblack@google.com
28413372Sgabeblack@google.com    /* Locate the global exit event */
28513372Sgabeblack@google.com    BaseGlobalEvent *global_event = exitEvent->globalEvent();
28613372Sgabeblack@google.com    assert(global_event != NULL);
28713372Sgabeblack@google.com
28813372Sgabeblack@google.com    GlobalSimLoopExitEvent *global_exit_event =
28913372Sgabeblack@google.com        dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
29013372Sgabeblack@google.com    assert(global_exit_event != NULL);
29113372Sgabeblack@google.com
29213372Sgabeblack@google.com    if (global_exit_event != limit_event) {
29313372Sgabeblack@google.com        limit_event->deschedule();
29413372Sgabeblack@google.com        delete limit_event;
29513372Sgabeblack@google.com    }
29613372Sgabeblack@google.com
29713372Sgabeblack@google.com    return global_exit_event;
29813372Sgabeblack@google.com}
29913372Sgabeblack@google.com
30013372Sgabeblack@google.com}
301