summaryrefslogtreecommitdiff
path: root/ext/sst/gem5.cc
diff options
context:
space:
mode:
authorCurtis Dunham <Curtis.Dunham@arm.com>2015-04-08 15:56:06 -0500
committerCurtis Dunham <Curtis.Dunham@arm.com>2015-04-08 15:56:06 -0500
commitf05cb84ed1a61f81c26e4ea22f98454d12f069aa (patch)
tree271f47eceadbf5a52597ab4c767ecf7d3ee2e0ff /ext/sst/gem5.cc
parentb5770ff5e06a2ef169a648c2abb72dde488dec98 (diff)
downloadgem5-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.cc272
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 &params) :
+ 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;
+}