| // Copyright (c) 2015-2016 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 <core/sst_config.h> | |
| #include <Python.h> // Before serialization to prevent spurious warnings | |
| #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/logging.hh> | |
| #include <base/debug.hh> | |
| #ifdef fatal // gem5 sets this | |
| #undef fatal | |
| #endif | |
| // More SST Headers | |
| #include <core/timeConverter.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<int>("comp_debug", 0)); | |
| info.init("gem5:" + getName() + ": ", 0, 0, Output::STDOUT); | |
| TimeConverter *clock = registerClock( | |
| params.find<std::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<std::string>("cmd", ""); | |
| if (cmd.empty()) { | |
| dbg.fatal(CALL_INFO, -1, "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<std::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) { | |
| dbg.fatal(CALL_INFO, -1, "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; | |
| } |