diff options
Diffstat (limited to 'util/systemc/gem5_within_systemc')
-rw-r--r-- | util/systemc/gem5_within_systemc/Makefile | 70 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/README | 83 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/main.cc | 446 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/sc_gem5_control.cc | 309 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/sc_gem5_control.hh | 168 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/sc_logger.cc | 152 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/sc_logger.hh | 80 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/sc_module.cc | 300 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/sc_module.hh | 165 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/stats.cc | 159 | ||||
-rw-r--r-- | util/systemc/gem5_within_systemc/stats.hh | 65 |
11 files changed, 1997 insertions, 0 deletions
diff --git a/util/systemc/gem5_within_systemc/Makefile b/util/systemc/gem5_within_systemc/Makefile new file mode 100644 index 000000000..100402c15 --- /dev/null +++ b/util/systemc/gem5_within_systemc/Makefile @@ -0,0 +1,70 @@ +# Copyright (c) 2012-2014 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. +# +# Authors: Andrew Bardsley + +ARCH = ARM +VARIANT = opt + +SYSTEMC_INC = ./systemc/include +SYSTEMC_LIB = ./systemc/lib-linux64 + +CXXFLAGS = -I../../../build/$(ARCH) -L../../../build/$(ARCH) +CXXFLAGS += -I$(SYSTEMC_INC) -L$(SYSTEMC_LIB) +CXXFLAGS += -std=c++0x +CXXFLAGS += -g +LIBS = -lgem5_$(VARIANT) -lsystemc + +ALL = gem5.$(VARIANT).sc + +all: $(ALL) + +.cc.o: + $(CXX) $(CXXFLAGS) -c -o $@ $< + +sc_gem5_control.o: sc_gem5_control.cc sc_gem5_control.hh +sc_logger.o: sc_logger.cc sc_logger.hh +sc_module.o: sc_module.cc sc_module.hh +stats.o: stats.cc stats.hh +main.o: main.cc sc_logger.hh sc_module.hh stats.hh + +gem5.$(VARIANT).sc: main.o stats.o \ + sc_gem5_control.o sc_logger.o sc_module.o + $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) $(ALL) + $(RM) *.o + $(RM) -r m5out diff --git a/util/systemc/gem5_within_systemc/README b/util/systemc/gem5_within_systemc/README new file mode 100644 index 000000000..9ee1103a8 --- /dev/null +++ b/util/systemc/gem5_within_systemc/README @@ -0,0 +1,83 @@ +This directory contains a demo of C++ configuration of gem5. The intention +is to provide a mechanism to allow pre-generated config.ini files generated +by Python-based gem5 to be reloaded in library-base versions of gem5 +embedded in other systems using C++ calls for simulation control. + +This directory contain a demo of hosting a C++ configured version of gem5 +onto SystemC's event loop. The hosting is achieved by replacing 'simulate' +with a SystemC object which implements an event loop using SystemC scheduler +mechanisms. + +The sc_... files here should probably be hosted in a diferent directory and +buildable as a library. + +Files: + + main.cc -- demonstration top level + sc_logger.{cc,hh} -- rehosting of DPRINTF onto SC_REPORT + sc_module.{cc,hh} -- SystemC simulation loop base class + sc_gem5_control.{cc,hh} -- Alternative extra wrapping to allow gem5 + Systems to be instantiated as single + sc_module objects. + stats.{cc,hh} -- Stats dumping (copied from util/cxx_config) + +Read main.cc for more details of the implementation and sc_... files for + +To build: + +First build gem5 as a library with cxx-config support and (optionally) +without python. Also build a normal gem5 (cxx-config not needed, Python +needed): + +> cd ../../.. +> scons build/ARM/gem5.opt +> scons --with-cxx-config --without-python build/ARM/libgem5_opt.so +> cd util/systemc + +Note: For MAC / OSX this command should be used: +> scons --with-cxx-config --without-python build/ARM/libgem5_opt.dylib + +Set a proper LD_LIBRARY_PATH e.g. for bash: +> export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/path/to/gem5/build/ARM/" + +or for MAC / OSX: +> export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:/path/to/gem5/build/ARM/" + + +Then edit the Makefile to set the paths for SystemC, e.g: + + Linux: + SYSTEMC_INC = /opt/systemc/include + SYSTEMC_LIB = /opt/systemc/lib-linux64 + + MAC / OSX: + SYSTEMC_INC = /opt/systemc/include + SYSTEMC_LIB = /opt/systemc/lib-macosx64 + +Then run make: + +> make + +Make a config file for the C++-configured gem5 using normal gem5 + +> ../../../build/ARM/gem5.opt ../../../configs/example/se.py -c \ +> ../../../tests/test-progs/hello/bin/arm/linux/hello + +The binary 'gem5.opt.cxx' can now be used to load in the generated config +file from the previous normal gem5 run. + +Try: + +> ./gem5.opt.cxx m5out/config.ini + +This should print: + +> Hello world! + +The .ini file can also be read by the Python .ini file reader example: + +> ../../../build/ARM/gem5.opt ../../../configs/example/read_ini.py \ +> m5out/config.ini + +If you are interested in SystemC Transaction Level Modeling (TLM2) please have +a look into /util/tlm. diff --git a/util/systemc/gem5_within_systemc/main.cc b/util/systemc/gem5_within_systemc/main.cc new file mode 100644 index 000000000..9d88b63cb --- /dev/null +++ b/util/systemc/gem5_within_systemc/main.cc @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + * Abdul Mutaal Ahmad + */ + +/** + * @file + * + * Example top level file for SystemC integration with C++-only + * instantiation. + * + * Build with something like: + * + * scons --without-python build/ARM/libgem5_opt.so + * + * g++ -std=c++0x -Ibuild/ARM -Isrc -DTRACING_ON \ + * -o gem5cxx.opt -Lbuild/ARM -lgem5_opt \ + * src/sim/sc_main_cxx.cc src/sim/cxx_stats.cc \ + * src/sim/sc_module.cc src/sim/sc_logger.cc + */ + +#include <cstdlib> +#include <iostream> +#include <sstream> +#include <systemc> + +#include "base/statistics.hh" +#include "base/str.hh" +#include "base/trace.hh" +#include "cpu/base.hh" +#include "sc_logger.hh" +#include "sc_module.hh" +#include "sim/cxx_config_ini.hh" +#include "sim/cxx_manager.hh" +#include "sim/init_signals.hh" +#include "sim/serialize.hh" +#include "sim/simulate.hh" +#include "sim/stat_control.hh" +#include "sim/system.hh" +#include "stats.hh" + +// Defining global string variable decalred in stats.hh +std::string filename; + +void +usage(const std::string &prog_name) +{ + std::cerr << "Usage: " << prog_name << ( + " <config_file.ini> [ <option> ]\n\n" + "OPTIONS:\n" + " -p <object> <param> <value> -- set a parameter\n" + " -v <object> <param> <values> -- set a vector parameter from" + " a comma\n" + " separated values string\n" + " -d <flag> -- set a debug flag (-<flag>\n" + " clear a flag)\n" + " -s <dir> <ticks> -- save checkpoint to dir after" + " the given\n" + " number of ticks\n" + " -r <dir> -- restore checkpoint to dir\n" + " -c <from> <to> <ticks> -- switch from cpu 'from' to cpu" + " 'to' after\n" + " the given number of ticks\n" + " -n <#cpus> the number of cpus to switch\n" + " (appended to 'to' and 'from'" + " cpus above)\n" + "\n" + ); + + std::exit(EXIT_FAILURE); +} + +class SimControl : public Gem5SystemC::Module +{ + protected: + int argc; + char **argv; + CxxConfigManager *config_manager; + Gem5SystemC::Logger logger; + + bool checkpoint_restore; + bool checkpoint_save; + bool switch_cpus; + std::string checkpoint_dir; + std::string from_cpu; + std::string to_cpu; + Tick pre_run_time; + Tick pre_switch_time; + unsigned num_switch_cpus; + + public: + SC_HAS_PROCESS(SimControl); + + SimControl(sc_core::sc_module_name name, int argc_, char **argv_); + + void run(); + private: + /** + * Switch a single CPU + * + * If numTotalCpus is greater than 1, the CPU index will be appended to + * the object name when searching config manager for the CPU name + * + * @param The CPU number to switch + * @param The total number of CPUs in the system + */ + void switchCpu(unsigned cpuNum, unsigned numTotalCpus); + +}; + +SimControl::SimControl(sc_core::sc_module_name name, + int argc_, char **argv_) : + Gem5SystemC::Module(name), + argc(argc_), + argv(argv_) +{ + SC_THREAD(run); + + std::string prog_name(argv[0]); + unsigned int arg_ptr = 1; + + if (argc == 1) + usage(prog_name); + + cxxConfigInit(); + + /* Pass DPRINTF messages to SystemC */ + Trace::setDebugLogger(&logger); + + /* @todo need this as an option */ + Gem5SystemC::setTickFrequency(); + + /* Make a SystemC-synchronising event queue and install it as the + * sole top level gem5 EventQueue */ + Gem5SystemC::Module::setupEventQueues(*this); + + if (sc_core::sc_get_time_resolution() != + sc_core::sc_time(1, sc_core::SC_PS)) + { + fatal("Time resolution must be set to 1 ps for gem5 to work"); + } + + /* Enable keyboard interrupt, async I/O etc. */ + initSignals(); + + /* Enable stats */ + Stats::initSimStats(); + Stats::registerHandlers(CxxConfig::statsReset, CxxConfig::statsDump); + + Trace::enable(); + setDebugFlag("Terminal"); + + checkpoint_restore = false; + checkpoint_save = false; + switch_cpus = false; + checkpoint_dir = ""; + from_cpu = ""; + to_cpu = ""; + pre_run_time = 1000000; + pre_switch_time = 1000000; + num_switch_cpus = 1; + + const std::string config_file(argv[arg_ptr]); + + CxxConfigFileBase *conf = new CxxIniFile(); + + if (!conf->load(config_file.c_str())) + fatal("Can't open config file: %s", config_file); + + arg_ptr++; + + config_manager = new CxxConfigManager(*conf); + + try { + while (arg_ptr < argc) { + std::string option(argv[arg_ptr]); + arg_ptr++; + unsigned num_args = argc - arg_ptr; + + if (option == "-p") { + if (num_args < 3) + usage(prog_name); + config_manager->setParam(argv[arg_ptr], argv[arg_ptr + 1], + argv[arg_ptr + 2]); + arg_ptr += 3; + } else if (option == "-v") { + std::vector<std::string> values; + + if (num_args < 3) + usage(prog_name); + tokenize(values, argv[2], ','); + config_manager->setParamVector(argv[arg_ptr], + argv[arg_ptr], values); + arg_ptr += 3; + } else if (option == "-d") { + if (num_args < 1) + usage(prog_name); + if (argv[arg_ptr][0] == '-') + clearDebugFlag(argv[arg_ptr] + 1); + else + setDebugFlag(argv[arg_ptr]); + arg_ptr++; + } else if (option == "-r") { + if (num_args < 1) + usage(prog_name); + checkpoint_dir = argv[arg_ptr]; + checkpoint_restore = true; + arg_ptr++; + } else if (option == "-s") { + if (num_args < 2) + usage(prog_name); + checkpoint_dir = argv[arg_ptr]; + std::istringstream(argv[arg_ptr + 1]) >> pre_run_time; + checkpoint_save = true; + arg_ptr += 2; + } else if (option == "-c") { + if (num_args < 3) + usage(prog_name); + switch_cpus = true; + from_cpu = argv[arg_ptr]; + to_cpu = argv[arg_ptr + 1]; + std::istringstream(argv[arg_ptr + 2]) >> pre_switch_time; + arg_ptr += 3; + } else if (option == "-n") { + if (num_args < 1) + usage(prog_name); + std::istringstream(argv[arg_ptr]) >> num_switch_cpus; + arg_ptr++; + } else { + usage(prog_name); + } + } + } catch (CxxConfigManager::Exception &e) { + fatal("Config problem in sim object %s: %s", e.name, e.message); + } + + if (checkpoint_save && checkpoint_restore) { + fatal("Don't try to save and restore a checkpoint in the same" + "run"); + } + + CxxConfig::statsEnable(); + getEventQueue(0)->dump(); + + try { + config_manager->instantiate(); + } catch (CxxConfigManager::Exception &e) { + fatal("Config problem in sim object %s: %s", e.name, e.message); + } +} + +void SimControl::run() +{ + EventQueue *eventq = getEventQueue(0); + GlobalSimLoopExitEvent *exit_event = NULL; + + /* There *must* be no scheduled events yet */ + fatal_if(!eventq->empty(), "There must be no posted events" + " before SimControl::run"); + + try { + if (checkpoint_restore) { + std::cerr << "Restoring checkpoint\n"; + + CheckpointIn *checkpoint = new CheckpointIn(checkpoint_dir, + config_manager->getSimObjectResolver()); + + /* Catch SystemC up with gem5 after checkpoint restore. + * Note that gem5 leading SystemC is always a violation of the + * required relationship between the two, hence this careful + * catchup */ + + DrainManager::instance().preCheckpointRestore(); + Serializable::unserializeGlobals(*checkpoint); + + Tick systemc_time = sc_core::sc_time_stamp().value(); + if (curTick() > systemc_time) { + Tick wait_period = curTick() - systemc_time; + + std::cerr << "Waiting for " << wait_period << "ps for" + " SystemC to catch up to gem5\n"; + wait(sc_core::sc_time::from_value(wait_period)); + } + + config_manager->loadState(*checkpoint); + config_manager->startup(); + config_manager->drainResume(); + + std::cerr << "Restored from Checkpoint\n"; + } else { + config_manager->initState(); + config_manager->startup(); + } + } catch (CxxConfigManager::Exception &e) { + fatal("Config problem in sim object %s: %s", e.name, e.message); + } + + fatal_if(eventq->empty(), "No events to process after system startup"); + + if (checkpoint_save) { + exit_event = simulate(pre_run_time); + + unsigned int drain_count = 1; + do { + drain_count = config_manager->drain(); + + std::cerr << "Draining " << drain_count << '\n'; + + if (drain_count > 0) { + exit_event = simulate(); + } + } while (drain_count > 0); + + std::cerr << "Simulation stop at tick " << curTick() + << ", cause: " << exit_event->getCause() << '\n'; + + std::cerr << "Checkpointing\n"; + + /* FIXME, this should really be serialising just for + * config_manager rather than using serializeAll's ugly + * SimObject static object list */ + Serializable::serializeAll(checkpoint_dir); + + std::cerr << "Completed checkpoint\n"; + + config_manager->drainResume(); + } + + if (switch_cpus) { + exit_event = simulate(pre_switch_time); + + unsigned int drain_count = 1; + do { + drain_count = config_manager->drain(); + + std::cerr << "Draining " << drain_count << '\n'; + + if (drain_count > 0) { + exit_event = simulate(); + } + } while (drain_count > 0); + + for (unsigned cpu_num = 0; cpu_num < num_switch_cpus; ++cpu_num) { + switchCpu(cpu_num, num_switch_cpus); + } + + config_manager->drainResume(); + + } + + exit_event = simulate(); + + std::cerr << "Exit at tick " << curTick() + << ", cause: " << exit_event->getCause() << '\n'; + + getEventQueue(0)->dump(); + +#if TRY_CLEAN_DELETE + config_manager->deleteObjects(); +#endif +} + +int +sc_main(int argc, char **argv) +{ + SimControl sim_control("gem5", argc, argv); + + filename = "m5out/stats-systemc.txt"; + + sc_core::sc_start(); + + CxxConfig::statsDump(); + + return EXIT_SUCCESS; +} + +void +SimControl::switchCpu(unsigned cpuNum, unsigned numTotalCpus) { + assert(cpuNum < numTotalCpus); + std::ostringstream from_cpu_name; + std::ostringstream to_cpu_name; + + from_cpu_name << from_cpu; + to_cpu_name << to_cpu; + + if (numTotalCpus > 1) { + from_cpu_name << cpuNum; + to_cpu_name << cpuNum; + } + + std::cerr << "Switching CPU "<< cpuNum << "(from='" << from_cpu_name.str() + <<"' to '"<< to_cpu_name.str() << "')\n"; + + /* Assume the system is called system */ + System &system = config_manager->getObject<System>("system"); + BaseCPU &old_cpu = config_manager->getObject<BaseCPU>(from_cpu_name.str()); + BaseCPU &new_cpu = config_manager->getObject<BaseCPU>(to_cpu_name.str()); + + old_cpu.switchOut(); + + // I'm not sure if this can be called before old_cpu.switchOut(). If so, + // it is best to just move this call before the switchCpu loop in run() + // where it previously was + if (cpuNum == 0) + system.setMemoryMode(Enums::timing); + + new_cpu.takeOverFrom(&old_cpu); + + + std::cerr << "Switched CPU"<<cpuNum<<"\n"; +} diff --git a/util/systemc/gem5_within_systemc/sc_gem5_control.cc b/util/systemc/gem5_within_systemc/sc_gem5_control.cc new file mode 100644 index 000000000..ae3dc241f --- /dev/null +++ b/util/systemc/gem5_within_systemc/sc_gem5_control.cc @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + */ + +#include <cstdlib> +#include <iostream> +#include <list> + +#include "base/statistics.hh" +#include "sc_gem5_control.hh" +#include "sc_logger.hh" +#include "sc_module.hh" +#include "sim/cxx_config_ini.hh" +#include "sim/cxx_manager.hh" +#include "sim/debug.hh" +#include "sim/init_signals.hh" +#include "sim/stat_control.hh" +#include "stats.hh" + +namespace Gem5SystemC +{ + +/** This is the private side of Gem5Control */ +class Gem5TopLevelModule : public Gem5SystemC::Module +{ + friend class Gem5Control; + + protected: + CxxConfigFileBase *config_file; + CxxConfigManager *root_manager; + Gem5SystemC::Logger logger; + + /** Things to do at end_of_elaborate */ + std::list<void (*)()> endOfElaborationFuncs; + + public: + SC_HAS_PROCESS(Gem5TopLevelModule); + + Gem5TopLevelModule(sc_core::sc_module_name name, + const std::string &config_filename); + ~Gem5TopLevelModule(); + + /** gem5 simulate. @todo for more interesting simulation control, + * this needs to be more complicated */ + void run(); + + /* Register an action to happen at the end of elaboration */ + void registerEndOfElaboration(void (*func)()) + { + endOfElaborationFuncs.push_back(func); + } + + /** SystemC startup */ + void end_of_elaboration(); +}; + +Gem5System::Gem5System(CxxConfigManager *manager_, + const std::string &system_name, const std::string &instance_name) : + manager(manager_), + systemName(system_name), + instanceName(instance_name) +{ + manager->addRenaming(CxxConfigManager::Renaming( + system_name, instance_name)); +} + +Gem5System::~Gem5System() +{ + delete manager; +} + +void +Gem5System::setParam(const std::string &object, + const std::string ¶m_name, const std::string ¶m_value) +{ + manager->setParam(systemName + (object != "" ? "." + object : ""), + param_name, param_value); +} + +void +Gem5System::setParamVector(const std::string &object, + const std::string ¶m_name, + const std::vector<std::string> ¶m_values) +{ + manager->setParamVector(systemName + + (object != "" ? "." + object : ""), param_name, param_values); +} + +void +Gem5System::instantiate() +{ + try { + /* Make a new System */ + SimObject *obj = manager->findObject(systemName, true); + + /* Add the System's objects to the list of managed + * objects for initialisation */ + manager->findTraversalOrder(systemName); + + /* Bound ports *must* be internal to System */ + for (auto i = manager->objectsInOrder.begin(); + i != manager->objectsInOrder.end(); + ++ i) + { + manager->bindObjectPorts(*i); + } + + /* gem5 startup sequence */ + manager->instantiate(false); + manager->initState(); + manager->startup(); + } catch (CxxConfigManager::Exception &e) { + fatal("Config problem in Gem5System: %s: %s", + e.name, e.message); + } +} + +Gem5Control::Gem5Control(const std::string &config_filename) +{ + module = new Gem5TopLevelModule("gem5", config_filename); +} + +Gem5Control::~Gem5Control() +{ } + +void +Gem5Control::registerEndOfElaboration(void (*func)()) +{ + module->registerEndOfElaboration(func); +} + +void +Gem5Control::setDebugFlag(const char *flag) +{ + ::setDebugFlag(flag); +} + +void +Gem5Control::clearDebugFlag(const char *flag) +{ + ::clearDebugFlag(flag); +} + +void +Gem5Control::setRemoteGDBPort(unsigned int port) +{ + ::setRemoteGDBPort(port); +} + +Gem5System * +Gem5Control::makeSystem(const std::string &system_name, + const std::string &instance_name) +{ + Gem5System *ret = new Gem5System( + new CxxConfigManager(*(module->config_file)), + system_name, instance_name); + + return ret; +} + +const std::string & +Gem5Control::getVersion() const +{ + return version; +} + +void +Gem5Control::setVersion(const std::string &new_version) +{ + if (version != "") + fatal("Gem5Control::setVersion called for a second time"); + + version = new_version; +} + +Gem5TopLevelModule::Gem5TopLevelModule(sc_core::sc_module_name name, + const std::string &config_filename) : + Gem5SystemC::Module(name), + config_file(NULL), + root_manager(NULL) +{ + SC_THREAD(run); + + cxxConfigInit(); + + /* Pass DPRINTF messages to SystemC */ + Trace::setDebugLogger(&logger); + + /* @todo need this as an option */ + Gem5SystemC::setTickFrequency(); + + /* Make a SystemC-synchronising event queue and install it as the + * sole top level gem5 EventQueue */ + Gem5SystemC::Module::setupEventQueues(*this); + + if (sc_core::sc_get_time_resolution() != + sc_core::sc_time(1, sc_core::SC_PS)) + { + fatal("Time resolution must be set to 1 ps for gem5 to work"); + } + + /* Enable keyboard interrupt, async I/O etc. */ + initSignals(); + + /* Enable stats */ + Stats::initSimStats(); + Stats::registerHandlers(CxxConfig::statsReset, CxxConfig::statsDump); + + Trace::enable(); + + config_file = new CxxIniFile(); + + if (!config_file->load(config_filename)) { + fatal("Gem5TopLevelModule: Can't open config file: %s", + config_filename); + } + + root_manager = new CxxConfigManager(*config_file); + + CxxConfig::statsEnable(); + + /* Make the root object */ + try { + SimObject *root = root_manager->findObject("root", false); + + /* Make sure we don't traverse into root's children */ + root_manager->objectsInOrder.push_back(root); + + root_manager->instantiate(false); + root_manager->initState(); + root_manager->startup(); + } catch (CxxConfigManager::Exception &e) { + fatal("Config problem in Gem5TopLevelModule: %s: %s", + e.name, e.message); + } +} + +Gem5TopLevelModule::~Gem5TopLevelModule() +{ + delete config_file; + delete root_manager; +} + +void +Gem5TopLevelModule::run() +{ + GlobalSimLoopExitEvent *exit_event = NULL; + + exit_event = simulate(); + + std::cerr << "Exit at tick " << curTick() + << ", cause: " << exit_event->getCause() << '\n'; + + getEventQueue(0)->dump(); +} + +void +Gem5TopLevelModule::end_of_elaboration() +{ + for (auto i = endOfElaborationFuncs.begin(); + i != endOfElaborationFuncs.end(); ++i) + { + (*i)(); + } +} + +} + +Gem5SystemC::Gem5Control * +makeGem5Control(const std::string &config_filename) +{ + return new Gem5SystemC::Gem5Control(config_filename); +} + diff --git a/util/systemc/gem5_within_systemc/sc_gem5_control.hh b/util/systemc/gem5_within_systemc/sc_gem5_control.hh new file mode 100644 index 000000000..a5a372344 --- /dev/null +++ b/util/systemc/gem5_within_systemc/sc_gem5_control.hh @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + */ + +/** + * @file + * + * Top level definitions for exporting gem5 across a dlopen interface. + * + * Gem5Control should be instantiated once to build the gem5 root. + * Systems from that root's config file can then be instantiated as + * Gem5System's using Gem5Control::makeSystem. + * + * Gem5Control contains a Gem5TopLevelModule which is a SystemC + * module providing the gem5 `simulate' function as its sole + * thread action. + */ + +#ifndef __SIM_SC_GEM5_CONTROL_HH__ +#define __SIM_SC_GEM5_CONTROL_HH__ + +#include <string> +#include <vector> + +class CxxConfigManager; + +namespace Gem5SystemC +{ + +class Gem5TopLevelModule; +class Gem5Control; + +/** Gem5System's wrap CxxConfigManager's instantiating a gem5 System + * object (and its children). New Gem5Systems are created by + * Gem5Control::makeSystem. A new system can have its parameters + * tweaked using setParam{,Vector} before being instantiated using + * Gem5System::instantiate. After instantiation, any external ports + * declared by the system should be visible in SystemC. + * + * It is recommended that a SystemC wrapper sc_module is declared to + * own each Gem5System with the call to Gem5System::instantiate being + * made in that wrapper's constructor + * + * Note that *every* `normal' member function in this class *must* + * be virtual to ensure that references to the functions go through + * the pointer acquired using makeSystem and not looked up as + * name-mangled symbols + * + * */ +class Gem5System +{ + private: + /** Config management for *just* this system's objects (notably + * excluding root */ + CxxConfigManager *manager; + + /** The config file prototype for the system */ + std::string systemName; + + /** The instantiated (in gem5) name of the system */ + std::string instanceName; + + public: + /** A constructor only used by Gem5Control */ + Gem5System(CxxConfigManager *manager_, + const std::string &system_name, const std::string &instance_name); + + virtual ~Gem5System(); + + /** Parameter setting functions callable before instantiate */ + virtual void setParam(const std::string &object, + const std::string ¶m_name, const std::string ¶m_value); + + virtual void setParamVector(const std::string &system_name, + const std::string ¶m_name, + const std::vector<std::string> ¶m_values); + + /** Build the system's gem5 infrastructure, bind its ports (note + * that all ports *must* be internal to the system), init and + * SimObject::startup the system */ + virtual void instantiate(); +}; + +/** Singleton class containing gem5 simulation control. + * + * Note that *every* `normal' member function in this class *must* + * be virtual to ensure that references to the functions go through + * the pointer acquired using makeGem5Control and not looked up as + * name-mangled symbols + */ +class Gem5Control +{ + private: + /** Private SystemC module containing top level simulation control */ + Gem5TopLevelModule *module; + + /** One-time-settable version string */ + std::string version; + + public: + Gem5Control(const std::string &config_filename); + + virtual ~Gem5Control(); + + /** Set/clear a gem5 debug flag */ + virtual void setDebugFlag(const char *flag); + virtual void clearDebugFlag(const char *flag); + + /** Choose a base port number for GDB to connect to the model + * (0 disables connections) */ + virtual void setRemoteGDBPort(unsigned int port); + + /* Register an action to happen at the end of elaboration */ + virtual void registerEndOfElaboration(void (*func)()); + + /** Make a System from the config file description for system + * system_name and call it instance_name in gem5 */ + virtual Gem5System *makeSystem(const std::string &system_name, + const std::string &top_instance); + + /** set/get version string */ + virtual const std::string &getVersion() const; + virtual void setVersion(const std::string &new_version); +}; + +} + +/** Instantiate a Gem5Control. This can be called using dlopen/dlsym + * to kick-start gem5 */ +extern "C" Gem5SystemC::Gem5Control *makeGem5Control( + const std::string &config_filename); + +#endif // __SIM_SC_GEM5_CONTROL_HH__ diff --git a/util/systemc/gem5_within_systemc/sc_logger.cc b/util/systemc/gem5_within_systemc/sc_logger.cc new file mode 100644 index 000000000..a8b9020f4 --- /dev/null +++ b/util/systemc/gem5_within_systemc/sc_logger.cc @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + */ + +/** + * @file + * + * A logger to allow SystemC to capture DPRINTF messages (and similar things) + * using sc_report + */ + +#include <cstdlib> +#include <cstring> +#include <sstream> + +#include "sc_logger.hh" + +namespace Gem5SystemC +{ + +/** Class to act as a streambuf for std::ostream which cuts output strings + * into lines and offers them to a logger */ +class CuttingStreambuf : public std::streambuf +{ + public: + /** Accumulate line so far */ + std::ostringstream line; + + /** Logger to send complete lines to */ + Trace::Logger *logger; + + CuttingStreambuf(Trace::Logger *logger_) : logger(logger_) + { } + + /** Accumulate to line up to \n and then emit */ + int overflow(int i); + int sync(); + + /** Push a line out to the logger */ + void outputLine(); + + ~CuttingStreambuf(); +}; + +void CuttingStreambuf::outputLine() +{ + logger->logMessage((Tick)-1, "gem5", line.str()); + line.clear(); + line.str(""); +} + +/** This is pretty much the least efficient way of doing this, but it has the + * advantage of having very few corners to get wrong. + * + * A newly allocated streambuf will have no buffer to serve to its + * [oi]stream. It will, therefore, call overflow for every character it + * wants to insert into the output stream. Those characters are captured one + * by one here and added to this->line. */ +int +CuttingStreambuf::overflow(int chr) +{ + if (chr == '\n') + outputLine(); + else if (chr != EOF) + line << (char) chr; + + /* Always succeeds */ + return 0; +} + +int +CuttingStreambuf::sync() +{ + if (!line.str().empty()) + outputLine(); + + /* Always succeeds */ + return 0; +} + +CuttingStreambuf::~CuttingStreambuf() +{ + sync(); +} + +Logger::Logger() : + cuttingStreambuf(new CuttingStreambuf(this)), + stream(cuttingStreambuf) +{ +} + +Logger::~Logger() +{ + stream.flush(); + delete cuttingStreambuf; +} + +/** Log a single message as a single sc_report call */ +void +Logger::logMessage(Tick when, const std::string &name, + const std::string &message) +{ + /* Need to chop the newline off the message */ + std::string message_without_nl = message; + message_without_nl.erase( + message_without_nl.find_last_not_of(" \n\r") + 1); + + SC_REPORT_INFO(name.c_str(), message_without_nl.c_str()); +} + +std::ostream & +Logger::getOstream() +{ + return stream; +} + +} diff --git a/util/systemc/gem5_within_systemc/sc_logger.hh b/util/systemc/gem5_within_systemc/sc_logger.hh new file mode 100644 index 000000000..4143f8bb8 --- /dev/null +++ b/util/systemc/gem5_within_systemc/sc_logger.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + */ + +/** + * @file + * + * A logger to allow SystemC to capture DPRINTF messages (and similar things) + * using sc_report + */ + +#ifndef __SIM_SC_LOGGER_H__ +#define __SIM_SC_LOGGER_H__ + +#include <systemc> + +#include "base/trace.hh" + +namespace Gem5SystemC +{ + +/** sc_report logging class */ +class Logger : public Trace::Logger +{ + protected: + /** Stream to offer getOstream. This will cut messages up newlines and + * offer them to logMessage */ + std::streambuf *cuttingStreambuf; + std::ostream stream; + + public: + Logger(); + + ~Logger(); + + /** Log a single message as a single sc_report call */ + void logMessage(Tick when, const std::string &name, + const std::string &message); + + std::ostream &getOstream(); +}; + +} + +#endif // __SIM_SC_LOGGER_H__ diff --git a/util/systemc/gem5_within_systemc/sc_module.cc b/util/systemc/gem5_within_systemc/sc_module.cc new file mode 100644 index 000000000..dafa80ee9 --- /dev/null +++ b/util/systemc/gem5_within_systemc/sc_module.cc @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2014 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. + * + * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. + * Copyright (c) 2013 Mark D. Hill and David A. Wood + * All rights reserved. + * + * 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. + * + * Authors: Nathan Binkert + * Steve Reinhardt + * Andrew Bardsley + * Matthias Jung + * Christian Menard + */ + +/** + * @file + * + * Defines an sc_module type to wrap a gem5 simulation. The 'evaluate' + * thread on that module implements the gem5 event loop. + * + * This currently only supports a single event queue and strictly + * cooperatively threaded SystemC threads and so there should be at + * most one Gem5Module instantiated in any simulation. + */ + +#include "base/logging.hh" +#include "base/pollevent.hh" +#include "base/trace.hh" +#include "debug/Event.hh" +#include "sc_module.hh" +#include "sim/async.hh" +#include "sim/core.hh" +#include "sim/eventq.hh" +#include "sim/sim_exit.hh" +#include "sim/stat_control.hh" + +namespace Gem5SystemC +{ + +/** There are assumptions throughout Gem5SystemC file that a tick is 1ps. + * Make this the case */ +void +setTickFrequency() +{ + ::setClockFrequency(1000000000000); +} + +Module::Module(sc_core::sc_module_name name) : sc_core::sc_channel(name), + in_simulate(false) +{ + SC_METHOD(eventLoop); + sensitive << eventLoopEnterEvent; + dont_initialize(); + + SC_METHOD(serviceExternalEvent); + sensitive << externalSchedulingEvent; + dont_initialize(); +} + +void +Module::SCEventQueue::wakeup(Tick when) +{ + DPRINTF(Event, "waking up SCEventQueue\n"); + /* Don't bother to use 'when' for now */ + module.notify(); +} + +void +Module::setupEventQueues(Module &module) +{ + fatal_if(mainEventQueue.size() != 0, + "Gem5SystemC::Module::setupEventQueues must be called" + " before any gem5 event queues are set up"); + + numMainEventQueues = 1; + mainEventQueue.push_back(new SCEventQueue("events", module)); + curEventQueue(getEventQueue(0)); +} + +void +Module::catchup() +{ + EventQueue *eventq = getEventQueue(0); + Tick systemc_time = sc_core::sc_time_stamp().value(); + Tick gem5_time = curTick(); + + /* gem5 time *must* lag SystemC as SystemC is the master */ + fatal_if(gem5_time > systemc_time, "gem5 time must lag SystemC time" + " gem5: %d SystemC: %d", gem5_time, systemc_time); + + eventq->setCurTick(systemc_time); + + if (!eventq->empty()) { + Tick next_event_time M5_VAR_USED = eventq->nextTick(); + + fatal_if(gem5_time > next_event_time, + "Missed an event at time %d gem5: %d, SystemC: %d", + next_event_time, gem5_time, systemc_time); + } +} + +void +Module::notify(sc_core::sc_time time_from_now) +{ + externalSchedulingEvent.notify(time_from_now); +} + +void +Module::serviceAsyncEvent() +{ + EventQueue *eventq = getEventQueue(0); + std::lock_guard<EventQueue> lock(*eventq); + + assert(async_event); + + /* Catch up gem5 time with SystemC time so that any event here won't + * be in the past relative to the current time */ + Tick systemc_time = sc_core::sc_time_stamp().value(); + + /* Move time on to match SystemC */ + catchup(); + + async_event = false; + if (async_statdump || async_statreset) { + Stats::schedStatEvent(async_statdump, async_statreset); + async_statdump = false; + async_statreset = false; + } + + if (async_exit) { + async_exit = false; + exitSimLoop("user interrupt received"); + } + + if (async_io) { + async_io = false; + pollQueue.service(); + } + + if (async_exception) + fatal("received async_exception, shouldn't be possible"); +} + +void +Module::serviceExternalEvent() +{ + EventQueue *eventq = getEventQueue(0); + + if (!in_simulate && !async_event) + warn("Gem5SystemC external event received while not in simulate"); + + if (async_event) + serviceAsyncEvent(); + + if (in_simulate && !eventq->empty()) + eventLoop(); +} + +void +Module::eventLoop() +{ + EventQueue *eventq = getEventQueue(0); + + fatal_if(!in_simulate, "Gem5SystemC event loop entered while" + " outside Gem5SystemC::Module::simulate"); + + if (async_event) + serviceAsyncEvent(); + + while (!eventq->empty()) { + Tick next_event_time = eventq->nextTick(); + + /* Move time on to match SystemC */ + catchup(); + + Tick gem5_time = curTick(); + + /* Woken up early */ + if (wait_exit_time > sc_core::sc_time_stamp().value()) { + DPRINTF(Event, "Woken up early\n"); + wait_exit_time = sc_core::sc_time_stamp().value(); + } + + if (gem5_time < next_event_time) { + Tick wait_period = next_event_time - gem5_time; + wait_exit_time = gem5_time + wait_period; + + DPRINTF(Event, "Waiting for %d ticks for next gem5 event\n", + wait_period); + + /* The next event is scheduled in the future, wait until + * then or until externalSchedulingEvent */ + eventLoopEnterEvent.notify(sc_core::sc_time::from_value( + sc_dt::uint64(wait_period))); + + return; + } else if (gem5_time > next_event_time) { + Tick systemc_time = sc_core::sc_time_stamp().value(); + + /* Missed event, for some reason the above test didn't work + * or an event was scheduled in the past */ + fatal("Missed an event at time %d gem5: %d, SystemC: %d", + next_event_time, gem5_time, systemc_time); + } else { + /* Service an event */ + exitEvent = eventq->serviceOne(); + + if (exitEvent) { + eventLoopExitEvent.notify(sc_core::SC_ZERO_TIME); + return; + } + } + } + + fatal("Ran out of events without seeing exit event"); +} + +GlobalSimLoopExitEvent * +Module::simulate(Tick num_cycles) +{ + inform("Entering event queue @ %d. Starting simulation...", curTick()); + + if (num_cycles < MaxTick - curTick()) + num_cycles = curTick() + num_cycles; + else /* counter would roll over or be set to MaxTick anyhow */ + num_cycles = MaxTick; + + GlobalEvent *limit_event = new GlobalSimLoopExitEvent(num_cycles, + "simulate() limit reached", 0, 0); + + exitEvent = NULL; + + /* Cancel any outstanding events */ + eventLoopExitEvent.cancel(); + externalSchedulingEvent.cancel(); + + in_simulate = true; + eventLoopEnterEvent.notify(sc_core::SC_ZERO_TIME); + + /* Wait for event queue to exit, guarded by exitEvent just incase + * it already has exited and we don't want to completely rely + * on notify semantics */ + if (!exitEvent) + wait(eventLoopExitEvent); + + /* Cancel any outstanding event loop entries */ + eventLoopEnterEvent.cancel(); + in_simulate = false; + + /* Locate the global exit event */ + BaseGlobalEvent *global_event = exitEvent->globalEvent(); + assert(global_event != NULL); + + GlobalSimLoopExitEvent *global_exit_event = + dynamic_cast<GlobalSimLoopExitEvent *>(global_event); + assert(global_exit_event != NULL); + + if (global_exit_event != limit_event) { + limit_event->deschedule(); + delete limit_event; + } + + return global_exit_event; +} + +} diff --git a/util/systemc/gem5_within_systemc/sc_module.hh b/util/systemc/gem5_within_systemc/sc_module.hh new file mode 100644 index 000000000..ff4e56e53 --- /dev/null +++ b/util/systemc/gem5_within_systemc/sc_module.hh @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014 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. + * + * Copyright (c) 2006 The Regents of The University of Michigan + * Copyright (c) 2013 Advanced Micro Devices, Inc. + * Copyright (c) 2013 Mark D. Hill and David A. Wood + * All rights reserved. + * + * 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. + * + * Authors: Nathan Binkert + * Steve Reinhardt + * Andrew Bardsley + * Christian Menard + */ + +/** + * @file + * + * Defines an sc_module type to wrap a gem5 simulation. The 'evaluate' + * thread on that module implements the gem5 event loop. + * + * This currently only supports a single event queue and strictly + * cooperatively threaded SystemC threads and so there should be at + * most one Gem5Module instantiated in any simulation. + */ + +#ifndef __SIM_SC_MODULE_HH__ +#define __SIM_SC_MODULE_HH__ + +#include <systemc> + +#include "sim/eventq.hh" +#include "sim/sim_events.hh" + +namespace Gem5SystemC +{ + +/** A SystemC module implementing the gem5 event queue. This object + * doesn't actually own any of the simulation SimObjects (those need + * to be administered separately) but it does control the event + * queue. + * + * The event loop here services gem5 events in order at the current time + * and then yielding to another SystemC thread. gem5 events are not + * individually scheduled in SystemC. For this reason, asynchronous events + * and function interaction (for example TLM) with gem5 from SystemC must + * notify the module so that the yielding 'wait' can be interrupted. + * From the point of view of another SystemC module calling into gem5, + * curTick can lag SystemC time, be exactly the same time but *never* + * lead SystemC time. + * + * This functionality is wrapped in an sc_module as its intended that + * the a class representing top level simulation control should be derived + * from this class. */ +class Module : public sc_core::sc_channel +{ + protected: + /** Event to trigger (via. ::notify) for event scheduling from + * outside gem5 */ + sc_core::sc_event externalSchedulingEvent; + + /** Event to trigger on exit of eventLoop */ + sc_core::sc_event eventLoopExitEvent; + + /** Event to trigger to enter eventLoop */ + sc_core::sc_event eventLoopEnterEvent; + + /** Expected exit time of last eventLoop sleep */ + Tick wait_exit_time; + + /** Are we in Module::simulate? Used to mask events when not inside + * the simulate loop */ + bool in_simulate; + + /** Placeholder base class for a variant event queue if this becomes + * useful */ + class SCEventQueue : public EventQueue + { + protected: + Module &module; + + public: + SCEventQueue(const std::string &name, + Module &module_) : EventQueue(name), module(module_) + { } + + /** Signal module to wakeup */ + void wakeup(Tick when); + }; + + /** Service any async event marked up in the globals event_... */ + void serviceAsyncEvent(); + + public: + /** Simulate is a process */ + SC_HAS_PROCESS(Module); + + Module(sc_core::sc_module_name name); + + /** Last exitEvent from eventLoop */ + Event *exitEvent; + + /** Setup global event queues. Call this before any other event queues + * are created */ + static void setupEventQueues(Module &module); + + /** Catch gem5 time up with SystemC */ + void catchup(); + + /** Notify an externalSchedulingEvent at the given time from the + * current SystemC time */ + void notify(sc_core::sc_time time_from_now = sc_core::SC_ZERO_TIME); + + /** Process an event triggered by externalSchedulingEvent and also + * call eventLoop (to try and mop up any events at this time) if there + * are any scheduled events */ + void serviceExternalEvent(); + + /** Process gem5 events up until an exit event or there are no events + * left. */ + void eventLoop(); + + /** Run eventLoop up to num_cycles and return the final event */ + GlobalSimLoopExitEvent *simulate(Tick num_cycles = MaxTick); +}; + +/** There are assumptions throughout Gem5SystemC file that a tick is 1ps. + * Make this the case */ +void setTickFrequency(); + +} + +#endif // __SIM_SC_MODULE_HH__ diff --git a/util/systemc/gem5_within_systemc/stats.cc b/util/systemc/gem5_within_systemc/stats.cc new file mode 100644 index 000000000..54d149474 --- /dev/null +++ b/util/systemc/gem5_within_systemc/stats.cc @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + * Matthias Jung + * Abdul Mutaal Ahmad + */ + +/** + * @file + * + * C++-only configuration stats handling example + * + * Register with: Stats::registerHandlers(statsReset, statsDump) + */ + +#include "base/output.hh" +#include "base/statistics.hh" +#include "base/stats/text.hh" +#include "stats.hh" + +namespace CxxConfig +{ + +void statsPrepare() +{ + std::list<Stats::Info *> stats = Stats::statsList(); + + /* gather_stats -> prepare */ + for (auto i = stats.begin(); i != stats.end(); ++i){ + Stats::Info *stat = *i; + Stats::VectorInfo *vector = dynamic_cast<Stats::VectorInfo *>(stat); + if (vector){ + (dynamic_cast<Stats::VectorInfo *>(*i))->prepare(); + } + else { + (*i)->prepare(); + } + + } +} + +void statsDump() +{ + bool desc = true; + Stats::Output *output = Stats::initText(filename, desc); + + Stats::processDumpQueue(); + + std::list<Stats::Info *> stats = Stats::statsList(); + + statsEnable(); + statsPrepare(); + + output->begin(); + /* gather_stats -> convert_value */ + for (auto i = stats.begin(); i != stats.end(); ++i) { + Stats::Info *stat = *i; + + const Stats::ScalarInfo *scalar = dynamic_cast<Stats::ScalarInfo + *>(stat); + Stats::VectorInfo *vector = dynamic_cast<Stats::VectorInfo *>(stat); + const Stats::Vector2dInfo *vector2d = dynamic_cast<Stats::Vector2dInfo + *>(vector); + const Stats::DistInfo *dist = dynamic_cast<Stats::DistInfo *>(stat); + const Stats::VectorDistInfo *vectordist = + dynamic_cast<Stats::VectorDistInfo *>(stat); + const Stats::SparseHistInfo *sparse = + dynamic_cast<Stats::SparseHistInfo *>(stat); + const Stats::InfoProxy <Stats::Vector2d,Stats::Vector2dInfo> *info = + dynamic_cast<Stats::InfoProxy + <Stats::Vector2d,Stats::Vector2dInfo>*>(stat); + + if (vector) { + const Stats::FormulaInfo *formula = dynamic_cast<Stats::FormulaInfo + *>(vector); + if (formula){ + output->visit(*formula); + } else { + const Stats::VectorInfo *vector1 = vector; + output->visit(*vector1); + } + } else if (vector2d) { + output->visit(*vector2d); + } else if (info){ + output->visit(*info); + } else if (vectordist){ + output->visit(*vectordist); + } else if (dist) { + output->visit(*dist); + } else if (sparse) { + output->visit(*sparse); + } else if (scalar) { + output->visit(*scalar); + } else { + warn("Stat not dumped: %s\n", stat->name); + } + } + output->end(); +} + +void statsReset() +{ + std::cerr << "Stats reset\n"; + + Stats::processResetQueue(); +} + +void statsEnable() +{ + std::list<Stats::Info *> stats = Stats::statsList(); + + for (auto i = stats.begin(); i != stats.end(); ++i){ + Stats::Info *stat = *i; + Stats::VectorInfo *vector = dynamic_cast<Stats::VectorInfo *>(stat); + if (vector){ + (dynamic_cast<Stats::VectorInfo *>(*i))->enable(); + } + else { + (*i)->enable(); + } + + } +} + +} diff --git a/util/systemc/gem5_within_systemc/stats.hh b/util/systemc/gem5_within_systemc/stats.hh new file mode 100644 index 000000000..9dac960ee --- /dev/null +++ b/util/systemc/gem5_within_systemc/stats.hh @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 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. + * + * Authors: Andrew Bardsley + * Matthias Jung + * Abdul Mutaal Ahmad + */ + +/** + * @file + * + * C++-only configuration stats handling example + * + * Register with: Stats::registerHandlers(statsReset, statsDump) + */ + +#ifndef __UTIL_CXX_CONFIG_STATS_H__ +#define __UTIL_CXX_CONFIG_STATS_H__ + +extern std::string filename; + +namespace CxxConfig +{ + +void statsDump(); +void statsReset(); +void statsEnable(); +void statsPrepare(); + +} + +#endif // __UTIL_CXX_CONFIG_STATS_H__ |