sc_module.cc revision 13372
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