| // 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; |
| } |