// 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 #include // Before serialization to prevent spurious warnings #include "gem5.hh" // System headers #include #include // gem5 Headers #include #include #include #include #include #include #include #ifdef fatal // gem5 sets this #undef fatal #endif // More SST Headers #include 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("comp_debug", 0)); info.init("gem5:" + getName() + ": ", 0, 0, Output::STDOUT); TimeConverter *clock = registerClock( params.find("frequency", "1GHz"), new Clock::Handler(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("cmd", ""); if (cmd.empty()) { dbg.fatal(CALL_INFO, -1, "Component %s must have a 'cmd' parameter.\n", getName().c_str()); } std::vector args; args.push_back(const_cast("sst.x")); // TODO: Compute this somehow? splitCommandArgs(cmd, args); args.push_back(const_cast("--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 flags; std::string gem5DbgFlags = params.find("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 &args) { std::string sep1("\\"); std::string sep2(" "); std::string sep3("\"\'"); boost::escaped_list_separator els(sep1, sep2, sep3); boost::tokenizer> 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; }