diff options
author | Curtis Dunham <Curtis.Dunham@arm.com> | 2015-04-08 15:56:06 -0500 |
---|---|---|
committer | Curtis Dunham <Curtis.Dunham@arm.com> | 2015-04-08 15:56:06 -0500 |
commit | f05cb84ed1a61f81c26e4ea22f98454d12f069aa (patch) | |
tree | 271f47eceadbf5a52597ab4c767ecf7d3ee2e0ff /ext/sst/gem5.cc | |
parent | b5770ff5e06a2ef169a648c2abb72dde488dec98 (diff) | |
download | gem5-f05cb84ed1a61f81c26e4ea22f98454d12f069aa.tar.xz |
ext: Add SST connector
This patch adds a connector that allows gem5 to be used as a component
in SST (Structural Simulation Toolkit, sst-simulator.org). At a high
level, this allows memory traffic to pass between the two simulators.
SST Links are roughly analogous to gem5 Ports, although Links do not
have a notion of master and slave. This distinction is important to
gem5, so when connecting a gem5 CPU to an SST cache, an ExternalSlave
must be used, and similarly when connecting the memory side of SST cache
to a gem5 port (for memory <-> I/O), an ExternalMaster must be used.
These connectors handle the administrative aspects of gem5
(initialization, simulation, shutdown) as well as translating SST's
MemEvents into gem5 Packets and vice-versa.
Diffstat (limited to 'ext/sst/gem5.cc')
-rw-r--r-- | ext/sst/gem5.cc | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/ext/sst/gem5.cc b/ext/sst/gem5.cc new file mode 100644 index 000000000..29cea8363 --- /dev/null +++ b/ext/sst/gem5.cc @@ -0,0 +1,272 @@ +// Copyright (c) 2015 ARM Limited +// All rights reserved. +// +// The license below extends only to copyright in the software and shall +// not be construed as granting a license to any other intellectual +// property including but not limited to intellectual property relating +// to a hardware implementation of the functionality of the software +// licensed hereunder. You may use the software subject to the license +// terms below provided that you ensure that this notice is replicated +// unmodified and in its entirety in all distributions of the software, +// modified or unmodified, in source code or in binary form. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer; +// redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution; +// neither the name of the copyright holders nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Copyright 2009-2014 Sandia Coporation. Under the terms +// of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2014, Sandia Corporation +// All rights reserved. +// +// For license information, see the LICENSE file in the current directory. + +#include <sst_config.h> +#include <Python.h> // Before serialization to prevent spurious warnings +#include <sst/core/serialization.h> + +#include "gem5.hh" + +// System headers +#include <boost/tokenizer.hpp> +#include <string> + +// gem5 Headers +#include <sim/core.hh> +#include <sim/init.hh> +#include <sim/init_signals.hh> +#include <sim/system.hh> +#include <sim/sim_object.hh> +#include <base/misc.hh> +#include <base/debug.hh> + +#ifdef fatal // gem5 sets this +#undef fatal +#endif + +// More SST Headers +#include <sst/core/params.h> +#include <sst/core/link.h> +#include <sst/core/timeConverter.h> +#include <sst/core/debug.h> + +using namespace SST; +using namespace SST::gem5; + +gem5Component::gem5Component(ComponentId_t id, Params ¶ms) : + SST::Component(id) +{ + dbg.init("@t:gem5:@p():@l " + getName() + ": ", 0, 0, + (Output::output_location_t)params.find_integer("comp_debug", 0)); + info.init("gem5:" + getName() + ": ", 0, 0, Output::STDOUT); + + TimeConverter *clock = registerClock( + params.find_string("frequency", "1GHz"), + new Clock::Handler<gem5Component>(this, &gem5Component::clockTick)); + + // This sets how many gem5 cycles we'll need to simulate per clock tick + sim_cycles = clock->getFactor(); + + // Disable gem5's inform() messages. + want_info = false; + + std::string cmd = params.find_string("cmd", ""); + if (cmd.empty()) { + _abort(gem5Component, "Component %s must have a 'cmd' parameter.\n", + getName().c_str()); + } + + std::vector<char*> args; + args.push_back(const_cast<char*>("sst.x")); // TODO: Compute this somehow? + splitCommandArgs(cmd, args); + args.push_back(const_cast<char*>("--initialize-only")); + dbg.output(CALL_INFO, "Command string: [sst.x %s --initialize-only]\n", + cmd.c_str()); + for (size_t i = 0; i < args.size(); ++i) { + dbg.output(CALL_INFO, " Arg [%02zu] = %s\n", i, args[i]); + } + + std::vector<char*> flags; + std::string gem5DbgFlags = params.find_string("gem5DebugFlags", ""); + splitCommandArgs(gem5DbgFlags, flags); + for (auto flag : flags) { + dbg.output(CALL_INFO, " Setting Debug Flag [%s]\n", flag); + setDebugFlag(flag); + } + + ExternalMaster::registerHandler("sst", this); // these are idempotent + ExternalSlave ::registerHandler("sst", this); + + // Initialize m5 special signal handling. + initSignals(); + + initPython(args.size(), &args[0]); + + // tell the simulator not to end without us + registerAsPrimaryComponent(); + primaryComponentDoNotEndSim(); + + clocks_processed = 0; +} + +gem5Component::~gem5Component(void) +{ + Py_Finalize(); +} + +void +gem5Component::init(unsigned phase) +{ + for (auto m : masters) { + m->init(phase); + } + for (auto s : slaves) { + s->init(phase); + } +} + +void +gem5Component::setup(void) +{ + // Switch connectors from initData to regular Sends + for (auto m : masters) { + m->setup(); + } + for (auto s : slaves) { + s->setup(); + } +} + +void +gem5Component::finish(void) +{ + for (auto m : masters) { + m->finish(); + } + info.output("Complete. Clocks Processed: %"PRIu64"\n", clocks_processed); +} + +bool +gem5Component::clockTick(Cycle_t cycle) +{ + dbg.output(CALL_INFO, "Cycle %lu\n", cycle); + + for (auto m : masters) { + m->clock(); + } + + GlobalSimLoopExitEvent *event = simulate(sim_cycles); + ++clocks_processed; + if (event != simulate_limit_event) { + info.output("exiting: curTick()=%lu cause=`%s` code=%d\n", + curTick(), event->getCause().c_str(), event->getCode()); + primaryComponentOKToEndSim(); + return true; + } + + return false; +} + + +void +gem5Component::splitCommandArgs(std::string &cmd, + std::vector<char *> &args) +{ + std::string sep1("\\"); + std::string sep2(" "); + std::string sep3("\"\'"); + + boost::escaped_list_separator<char> els(sep1, sep2, sep3); + boost::tokenizer<boost::escaped_list_separator<char>> tok(cmd, els); + + for (auto beg : tok) { + args.push_back(strdup(beg.c_str())); + } +} + + +void +gem5Component::initPython(int argc, char *argv[]) +{ + const char * m5MainCommands[] = { + "import m5", + "m5.main()", + 0 // sentinel is required + }; + + PyObject *mainModule,*mainDict; + + Py_SetProgramName(argv[0]); // optional but recommended + + Py_Initialize(); + + int ret = initM5Python(); + if (ret != 0) { + _abort(gem5Component, "Python failed to initialize. Code: %d\n", ret); + } + + PySys_SetArgv(argc, argv); + + mainModule = PyImport_AddModule("__main__"); + assert(mainModule); + + mainDict = PyModule_GetDict(mainModule); + assert(mainDict); + + PyObject *result; + const char **command = m5MainCommands; + + // evaluate each command in the m5MainCommands array (basically a + // bunch of python statements. + while (*command) { + result = PyRun_String(*command, Py_file_input, mainDict, mainDict); + if (!result) { + PyErr_Print(); + break; + } + Py_DECREF(result); + + command++; + } +} + +ExternalMaster::Port* +gem5Component::getExternalPort(const std::string &name, + ExternalMaster &owner, const std::string &port_data) +{ + std::string s(name); // bridges non-& result and &-arg + auto master = new ExtMaster(this, info, owner, s); + masters.push_back(master); + return master; +} + +ExternalSlave::Port* +gem5Component::getExternalPort(const std::string &name, + ExternalSlave &owner, const std::string &port_data) +{ + std::string s(name); // bridges non-& result and &-arg + auto slave = new ExtSlave(this, info, owner, s); + slaves.push_back(slave); + return slave; +} |