113372Sgabeblack@google.com/*
213372Sgabeblack@google.com * Copyright (c) 2014 ARM Limited
313372Sgabeblack@google.com * All rights reserved
413372Sgabeblack@google.com *
513372Sgabeblack@google.com * The license below extends only to copyright in the software and shall
613372Sgabeblack@google.com * not be construed as granting a license to any other intellectual
713372Sgabeblack@google.com * property including but not limited to intellectual property relating
813372Sgabeblack@google.com * to a hardware implementation of the functionality of the software
913372Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1013372Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1113372Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1213372Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1313372Sgabeblack@google.com *
1413372Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1513372Sgabeblack@google.com * modification, are permitted provided that the following conditions are
1613372Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
1713372Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
1813372Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1913372Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2013372Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2113372Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2213372Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2313372Sgabeblack@google.com * this software without specific prior written permission.
2413372Sgabeblack@google.com *
2513372Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2613372Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2713372Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2813372Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2913372Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3013372Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3113372Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3213372Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3313372Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3413372Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3513372Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3613372Sgabeblack@google.com *
3713372Sgabeblack@google.com * Authors: Andrew Bardsley
3813372Sgabeblack@google.com *          Abdul Mutaal Ahmad
3913372Sgabeblack@google.com */
4013372Sgabeblack@google.com
4113372Sgabeblack@google.com/**
4213372Sgabeblack@google.com * @file
4313372Sgabeblack@google.com *
4413372Sgabeblack@google.com *  Example top level file for SystemC integration with C++-only
4513372Sgabeblack@google.com *  instantiation.
4613372Sgabeblack@google.com *
4713372Sgabeblack@google.com *  Build with something like:
4813372Sgabeblack@google.com *
4913372Sgabeblack@google.com *      scons --without-python build/ARM/libgem5_opt.so
5013372Sgabeblack@google.com *
5113372Sgabeblack@google.com *      g++ -std=c++0x -Ibuild/ARM -Isrc -DTRACING_ON \
5213372Sgabeblack@google.com *          -o gem5cxx.opt -Lbuild/ARM -lgem5_opt \
5313372Sgabeblack@google.com *          src/sim/sc_main_cxx.cc src/sim/cxx_stats.cc \
5413372Sgabeblack@google.com *          src/sim/sc_module.cc src/sim/sc_logger.cc
5513372Sgabeblack@google.com */
5613372Sgabeblack@google.com
5713372Sgabeblack@google.com#include <cstdlib>
5813372Sgabeblack@google.com#include <iostream>
5913372Sgabeblack@google.com#include <sstream>
6013372Sgabeblack@google.com#include <systemc>
6113372Sgabeblack@google.com
6213372Sgabeblack@google.com#include "base/statistics.hh"
6313372Sgabeblack@google.com#include "base/str.hh"
6413372Sgabeblack@google.com#include "base/trace.hh"
6513372Sgabeblack@google.com#include "cpu/base.hh"
6613372Sgabeblack@google.com#include "sc_logger.hh"
6713372Sgabeblack@google.com#include "sc_module.hh"
6813372Sgabeblack@google.com#include "sim/cxx_config_ini.hh"
6913372Sgabeblack@google.com#include "sim/cxx_manager.hh"
7013372Sgabeblack@google.com#include "sim/init_signals.hh"
7113372Sgabeblack@google.com#include "sim/serialize.hh"
7213372Sgabeblack@google.com#include "sim/simulate.hh"
7313372Sgabeblack@google.com#include "sim/stat_control.hh"
7413372Sgabeblack@google.com#include "sim/system.hh"
7513372Sgabeblack@google.com#include "stats.hh"
7613372Sgabeblack@google.com
7713372Sgabeblack@google.com// Defining global string variable decalred in stats.hh
7813372Sgabeblack@google.comstd::string filename;
7913372Sgabeblack@google.com
8013372Sgabeblack@google.comvoid
8113372Sgabeblack@google.comusage(const std::string &prog_name)
8213372Sgabeblack@google.com{
8313372Sgabeblack@google.com    std::cerr << "Usage: " << prog_name << (
8413372Sgabeblack@google.com        " <config_file.ini> [ <option> ]\n\n"
8513372Sgabeblack@google.com        "OPTIONS:\n"
8613372Sgabeblack@google.com        "    -p <object> <param> <value>  -- set a parameter\n"
8713372Sgabeblack@google.com        "    -v <object> <param> <values> -- set a vector parameter from"
8813372Sgabeblack@google.com        " a comma\n"
8913372Sgabeblack@google.com        "                                    separated values string\n"
9013372Sgabeblack@google.com        "    -d <flag>                    -- set a debug flag (-<flag>\n"
9113372Sgabeblack@google.com        "                                    clear a flag)\n"
9213372Sgabeblack@google.com        "    -s <dir> <ticks>             -- save checkpoint to dir after"
9313372Sgabeblack@google.com        " the given\n"
9413372Sgabeblack@google.com        "                                    number of ticks\n"
9513372Sgabeblack@google.com        "    -r <dir>                     -- restore checkpoint to dir\n"
9613372Sgabeblack@google.com        "    -c <from> <to> <ticks>       -- switch from cpu 'from' to cpu"
9713372Sgabeblack@google.com        " 'to' after\n"
9813372Sgabeblack@google.com        "                                    the given number of ticks\n"
9913372Sgabeblack@google.com        "    -n <#cpus>                      the number of cpus to switch\n"
10013372Sgabeblack@google.com        "                                    (appended to 'to' and 'from'"
10113372Sgabeblack@google.com        " cpus above)\n"
10213372Sgabeblack@google.com        "\n"
10313372Sgabeblack@google.com        );
10413372Sgabeblack@google.com
10513372Sgabeblack@google.com    std::exit(EXIT_FAILURE);
10613372Sgabeblack@google.com}
10713372Sgabeblack@google.com
10813372Sgabeblack@google.comclass SimControl : public Gem5SystemC::Module
10913372Sgabeblack@google.com{
11013372Sgabeblack@google.com  protected:
11113372Sgabeblack@google.com    int argc;
11213372Sgabeblack@google.com    char **argv;
11313372Sgabeblack@google.com    CxxConfigManager *config_manager;
11413372Sgabeblack@google.com    Gem5SystemC::Logger logger;
11513372Sgabeblack@google.com
11613372Sgabeblack@google.com    bool checkpoint_restore;
11713372Sgabeblack@google.com    bool checkpoint_save;
11813372Sgabeblack@google.com    bool switch_cpus;
11913372Sgabeblack@google.com    std::string checkpoint_dir;
12013372Sgabeblack@google.com    std::string from_cpu;
12113372Sgabeblack@google.com    std::string to_cpu;
12213372Sgabeblack@google.com    Tick pre_run_time;
12313372Sgabeblack@google.com    Tick pre_switch_time;
12413372Sgabeblack@google.com    unsigned num_switch_cpus;
12513372Sgabeblack@google.com
12613372Sgabeblack@google.com  public:
12713372Sgabeblack@google.com    SC_HAS_PROCESS(SimControl);
12813372Sgabeblack@google.com
12913372Sgabeblack@google.com    SimControl(sc_core::sc_module_name name, int argc_, char **argv_);
13013372Sgabeblack@google.com
13113372Sgabeblack@google.com    void run();
13213372Sgabeblack@google.com  private:
13313372Sgabeblack@google.com    /**
13413372Sgabeblack@google.com     * Switch a single CPU
13513372Sgabeblack@google.com     *
13613372Sgabeblack@google.com     * If numTotalCpus is greater than 1, the CPU index will be appended to
13713372Sgabeblack@google.com     * the object name when searching config manager for the CPU name
13813372Sgabeblack@google.com     *
13913372Sgabeblack@google.com     * @param The CPU number to switch
14013372Sgabeblack@google.com     * @param The total number of CPUs in the system
14113372Sgabeblack@google.com     */
14213372Sgabeblack@google.com    void switchCpu(unsigned cpuNum, unsigned numTotalCpus);
14313372Sgabeblack@google.com
14413372Sgabeblack@google.com};
14513372Sgabeblack@google.com
14613372Sgabeblack@google.comSimControl::SimControl(sc_core::sc_module_name name,
14713372Sgabeblack@google.com    int argc_, char **argv_) :
14813372Sgabeblack@google.com    Gem5SystemC::Module(name),
14913372Sgabeblack@google.com    argc(argc_),
15013372Sgabeblack@google.com    argv(argv_)
15113372Sgabeblack@google.com{
15213372Sgabeblack@google.com    SC_THREAD(run);
15313372Sgabeblack@google.com
15413372Sgabeblack@google.com    std::string prog_name(argv[0]);
15513372Sgabeblack@google.com    unsigned int arg_ptr = 1;
15613372Sgabeblack@google.com
15713372Sgabeblack@google.com    if (argc == 1)
15813372Sgabeblack@google.com        usage(prog_name);
15913372Sgabeblack@google.com
16013372Sgabeblack@google.com    cxxConfigInit();
16113372Sgabeblack@google.com
16213372Sgabeblack@google.com    /* Pass DPRINTF messages to SystemC */
16313372Sgabeblack@google.com    Trace::setDebugLogger(&logger);
16413372Sgabeblack@google.com
16513372Sgabeblack@google.com    /* @todo need this as an option */
16613372Sgabeblack@google.com    Gem5SystemC::setTickFrequency();
16713372Sgabeblack@google.com
16813372Sgabeblack@google.com    /* Make a SystemC-synchronising event queue and install it as the
16913372Sgabeblack@google.com     *  sole top level gem5 EventQueue */
17013372Sgabeblack@google.com    Gem5SystemC::Module::setupEventQueues(*this);
17113372Sgabeblack@google.com
17213372Sgabeblack@google.com    if (sc_core::sc_get_time_resolution() !=
17313372Sgabeblack@google.com        sc_core::sc_time(1, sc_core::SC_PS))
17413372Sgabeblack@google.com    {
17513372Sgabeblack@google.com        fatal("Time resolution must be set to 1 ps for gem5 to work");
17613372Sgabeblack@google.com    }
17713372Sgabeblack@google.com
17813372Sgabeblack@google.com    /* Enable keyboard interrupt, async I/O etc. */
17913372Sgabeblack@google.com    initSignals();
18013372Sgabeblack@google.com
18113372Sgabeblack@google.com    /* Enable stats */
18213372Sgabeblack@google.com    Stats::initSimStats();
18313372Sgabeblack@google.com    Stats::registerHandlers(CxxConfig::statsReset, CxxConfig::statsDump);
18413372Sgabeblack@google.com
18513372Sgabeblack@google.com    Trace::enable();
18613372Sgabeblack@google.com    setDebugFlag("Terminal");
18713372Sgabeblack@google.com
18813372Sgabeblack@google.com    checkpoint_restore = false;
18913372Sgabeblack@google.com    checkpoint_save = false;
19013372Sgabeblack@google.com    switch_cpus = false;
19113372Sgabeblack@google.com    checkpoint_dir = "";
19213372Sgabeblack@google.com    from_cpu = "";
19313372Sgabeblack@google.com    to_cpu = "";
19413372Sgabeblack@google.com    pre_run_time = 1000000;
19513372Sgabeblack@google.com    pre_switch_time = 1000000;
19613372Sgabeblack@google.com    num_switch_cpus = 1;
19713372Sgabeblack@google.com
19813372Sgabeblack@google.com    const std::string config_file(argv[arg_ptr]);
19913372Sgabeblack@google.com
20013372Sgabeblack@google.com    CxxConfigFileBase *conf = new CxxIniFile();
20113372Sgabeblack@google.com
20213372Sgabeblack@google.com    if (!conf->load(config_file.c_str()))
20313372Sgabeblack@google.com        fatal("Can't open config file: %s", config_file);
20413372Sgabeblack@google.com
20513372Sgabeblack@google.com    arg_ptr++;
20613372Sgabeblack@google.com
20713372Sgabeblack@google.com    config_manager = new CxxConfigManager(*conf);
20813372Sgabeblack@google.com
20913372Sgabeblack@google.com    try {
21013372Sgabeblack@google.com        while (arg_ptr < argc) {
21113372Sgabeblack@google.com            std::string option(argv[arg_ptr]);
21213372Sgabeblack@google.com            arg_ptr++;
21313372Sgabeblack@google.com            unsigned num_args = argc - arg_ptr;
21413372Sgabeblack@google.com
21513372Sgabeblack@google.com            if (option == "-p") {
21613372Sgabeblack@google.com                if (num_args < 3)
21713372Sgabeblack@google.com                    usage(prog_name);
21813372Sgabeblack@google.com                config_manager->setParam(argv[arg_ptr], argv[arg_ptr + 1],
21913372Sgabeblack@google.com                    argv[arg_ptr + 2]);
22013372Sgabeblack@google.com                arg_ptr += 3;
22113372Sgabeblack@google.com            } else if (option == "-v") {
22213372Sgabeblack@google.com                std::vector<std::string> values;
22313372Sgabeblack@google.com
22413372Sgabeblack@google.com                if (num_args < 3)
22513372Sgabeblack@google.com                    usage(prog_name);
22613372Sgabeblack@google.com                tokenize(values, argv[2], ',');
22713372Sgabeblack@google.com                config_manager->setParamVector(argv[arg_ptr],
22813372Sgabeblack@google.com                    argv[arg_ptr], values);
22913372Sgabeblack@google.com                arg_ptr += 3;
23013372Sgabeblack@google.com            } else if (option == "-d") {
23113372Sgabeblack@google.com                if (num_args < 1)
23213372Sgabeblack@google.com                    usage(prog_name);
23313372Sgabeblack@google.com                if (argv[arg_ptr][0] == '-')
23413372Sgabeblack@google.com                    clearDebugFlag(argv[arg_ptr] + 1);
23513372Sgabeblack@google.com                else
23613372Sgabeblack@google.com                    setDebugFlag(argv[arg_ptr]);
23713372Sgabeblack@google.com                arg_ptr++;
23813372Sgabeblack@google.com            } else if (option == "-r") {
23913372Sgabeblack@google.com                if (num_args < 1)
24013372Sgabeblack@google.com                    usage(prog_name);
24113372Sgabeblack@google.com                checkpoint_dir = argv[arg_ptr];
24213372Sgabeblack@google.com                checkpoint_restore = true;
24313372Sgabeblack@google.com                arg_ptr++;
24413372Sgabeblack@google.com            } else if (option == "-s") {
24513372Sgabeblack@google.com                if (num_args < 2)
24613372Sgabeblack@google.com                    usage(prog_name);
24713372Sgabeblack@google.com                checkpoint_dir = argv[arg_ptr];
24813372Sgabeblack@google.com                std::istringstream(argv[arg_ptr + 1]) >> pre_run_time;
24913372Sgabeblack@google.com                checkpoint_save = true;
25013372Sgabeblack@google.com                arg_ptr += 2;
25113372Sgabeblack@google.com            } else if (option == "-c") {
25213372Sgabeblack@google.com                if (num_args < 3)
25313372Sgabeblack@google.com                    usage(prog_name);
25413372Sgabeblack@google.com                switch_cpus = true;
25513372Sgabeblack@google.com                from_cpu = argv[arg_ptr];
25613372Sgabeblack@google.com                to_cpu = argv[arg_ptr + 1];
25713372Sgabeblack@google.com                std::istringstream(argv[arg_ptr + 2]) >> pre_switch_time;
25813372Sgabeblack@google.com                arg_ptr += 3;
25913372Sgabeblack@google.com            } else if (option == "-n") {
26013372Sgabeblack@google.com                if (num_args < 1)
26113372Sgabeblack@google.com                    usage(prog_name);
26213372Sgabeblack@google.com                std::istringstream(argv[arg_ptr]) >> num_switch_cpus;
26313372Sgabeblack@google.com                arg_ptr++;
26413372Sgabeblack@google.com            } else {
26513372Sgabeblack@google.com                usage(prog_name);
26613372Sgabeblack@google.com            }
26713372Sgabeblack@google.com        }
26813372Sgabeblack@google.com    } catch (CxxConfigManager::Exception &e) {
26913372Sgabeblack@google.com        fatal("Config problem in sim object %s: %s", e.name, e.message);
27013372Sgabeblack@google.com    }
27113372Sgabeblack@google.com
27213372Sgabeblack@google.com    if (checkpoint_save && checkpoint_restore) {
27313372Sgabeblack@google.com        fatal("Don't try to save and restore a checkpoint in the same"
27413372Sgabeblack@google.com                "run");
27513372Sgabeblack@google.com    }
27613372Sgabeblack@google.com
27713372Sgabeblack@google.com    CxxConfig::statsEnable();
27813372Sgabeblack@google.com    getEventQueue(0)->dump();
27913372Sgabeblack@google.com
28013372Sgabeblack@google.com    try {
28113372Sgabeblack@google.com        config_manager->instantiate();
28213372Sgabeblack@google.com    } catch (CxxConfigManager::Exception &e) {
28313372Sgabeblack@google.com        fatal("Config problem in sim object %s: %s", e.name, e.message);
28413372Sgabeblack@google.com    }
28513372Sgabeblack@google.com}
28613372Sgabeblack@google.com
28713372Sgabeblack@google.comvoid SimControl::run()
28813372Sgabeblack@google.com{
28913372Sgabeblack@google.com    EventQueue *eventq = getEventQueue(0);
29013372Sgabeblack@google.com    GlobalSimLoopExitEvent *exit_event = NULL;
29113372Sgabeblack@google.com
29213372Sgabeblack@google.com    /* There *must* be no scheduled events yet */
29313372Sgabeblack@google.com    fatal_if(!eventq->empty(), "There must be no posted events"
29413372Sgabeblack@google.com        " before SimControl::run");
29513372Sgabeblack@google.com
29613372Sgabeblack@google.com    try {
29713372Sgabeblack@google.com        if (checkpoint_restore) {
29813372Sgabeblack@google.com            std::cerr << "Restoring checkpoint\n";
29913372Sgabeblack@google.com
30013372Sgabeblack@google.com            CheckpointIn *checkpoint = new CheckpointIn(checkpoint_dir,
30113372Sgabeblack@google.com                config_manager->getSimObjectResolver());
30213372Sgabeblack@google.com
30313372Sgabeblack@google.com            /* Catch SystemC up with gem5 after checkpoint restore.
30413372Sgabeblack@google.com             *  Note that gem5 leading SystemC is always a violation of the
30513372Sgabeblack@google.com             *  required relationship between the two, hence this careful
30613372Sgabeblack@google.com             *  catchup */
30713372Sgabeblack@google.com
30813372Sgabeblack@google.com            DrainManager::instance().preCheckpointRestore();
30913372Sgabeblack@google.com            Serializable::unserializeGlobals(*checkpoint);
31013372Sgabeblack@google.com
31113372Sgabeblack@google.com            Tick systemc_time = sc_core::sc_time_stamp().value();
31213372Sgabeblack@google.com            if (curTick() > systemc_time) {
31313372Sgabeblack@google.com                Tick wait_period = curTick() - systemc_time;
31413372Sgabeblack@google.com
31513372Sgabeblack@google.com                std::cerr << "Waiting for " << wait_period << "ps for"
31613372Sgabeblack@google.com                    " SystemC to catch up to gem5\n";
31713372Sgabeblack@google.com                wait(sc_core::sc_time::from_value(wait_period));
31813372Sgabeblack@google.com            }
31913372Sgabeblack@google.com
32013372Sgabeblack@google.com            config_manager->loadState(*checkpoint);
32113372Sgabeblack@google.com            config_manager->startup();
32213372Sgabeblack@google.com            config_manager->drainResume();
32313372Sgabeblack@google.com
32413372Sgabeblack@google.com            std::cerr << "Restored from Checkpoint\n";
32513372Sgabeblack@google.com        } else {
32613372Sgabeblack@google.com            config_manager->initState();
32713372Sgabeblack@google.com            config_manager->startup();
32813372Sgabeblack@google.com        }
32913372Sgabeblack@google.com    } catch (CxxConfigManager::Exception &e) {
33013372Sgabeblack@google.com        fatal("Config problem in sim object %s: %s", e.name, e.message);
33113372Sgabeblack@google.com    }
33213372Sgabeblack@google.com
33313372Sgabeblack@google.com    fatal_if(eventq->empty(), "No events to process after system startup");
33413372Sgabeblack@google.com
33513372Sgabeblack@google.com    if (checkpoint_save) {
33613372Sgabeblack@google.com        exit_event = simulate(pre_run_time);
33713372Sgabeblack@google.com
33813372Sgabeblack@google.com        unsigned int drain_count = 1;
33913372Sgabeblack@google.com        do {
34013372Sgabeblack@google.com            drain_count = config_manager->drain();
34113372Sgabeblack@google.com
34213372Sgabeblack@google.com            std::cerr << "Draining " << drain_count << '\n';
34313372Sgabeblack@google.com
34413372Sgabeblack@google.com            if (drain_count > 0) {
34513372Sgabeblack@google.com                exit_event = simulate();
34613372Sgabeblack@google.com            }
34713372Sgabeblack@google.com        } while (drain_count > 0);
34813372Sgabeblack@google.com
34913372Sgabeblack@google.com        std::cerr << "Simulation stop at tick " << curTick()
35013372Sgabeblack@google.com            << ", cause: " << exit_event->getCause() << '\n';
35113372Sgabeblack@google.com
35213372Sgabeblack@google.com        std::cerr << "Checkpointing\n";
35313372Sgabeblack@google.com
35413372Sgabeblack@google.com        /* FIXME, this should really be serialising just for
35513372Sgabeblack@google.com         *  config_manager rather than using serializeAll's ugly
35613372Sgabeblack@google.com         *  SimObject static object list */
35713372Sgabeblack@google.com        Serializable::serializeAll(checkpoint_dir);
35813372Sgabeblack@google.com
35913372Sgabeblack@google.com        std::cerr << "Completed checkpoint\n";
36013372Sgabeblack@google.com
36113372Sgabeblack@google.com        config_manager->drainResume();
36213372Sgabeblack@google.com    }
36313372Sgabeblack@google.com
36413372Sgabeblack@google.com    if (switch_cpus) {
36513372Sgabeblack@google.com        exit_event = simulate(pre_switch_time);
36613372Sgabeblack@google.com
36713372Sgabeblack@google.com        unsigned int drain_count = 1;
36813372Sgabeblack@google.com        do {
36913372Sgabeblack@google.com            drain_count = config_manager->drain();
37013372Sgabeblack@google.com
37113372Sgabeblack@google.com            std::cerr << "Draining " << drain_count << '\n';
37213372Sgabeblack@google.com
37313372Sgabeblack@google.com            if (drain_count > 0) {
37413372Sgabeblack@google.com                exit_event = simulate();
37513372Sgabeblack@google.com            }
37613372Sgabeblack@google.com        } while (drain_count > 0);
37713372Sgabeblack@google.com
37813372Sgabeblack@google.com        for (unsigned cpu_num = 0; cpu_num < num_switch_cpus; ++cpu_num) {
37913372Sgabeblack@google.com            switchCpu(cpu_num, num_switch_cpus);
38013372Sgabeblack@google.com        }
38113372Sgabeblack@google.com
38213372Sgabeblack@google.com        config_manager->drainResume();
38313372Sgabeblack@google.com
38413372Sgabeblack@google.com    }
38513372Sgabeblack@google.com
38613372Sgabeblack@google.com    exit_event = simulate();
38713372Sgabeblack@google.com
38813372Sgabeblack@google.com    std::cerr << "Exit at tick " << curTick()
38913372Sgabeblack@google.com        << ", cause: " << exit_event->getCause() << '\n';
39013372Sgabeblack@google.com
39113372Sgabeblack@google.com    getEventQueue(0)->dump();
39213372Sgabeblack@google.com
39313372Sgabeblack@google.com#if TRY_CLEAN_DELETE
39413372Sgabeblack@google.com    config_manager->deleteObjects();
39513372Sgabeblack@google.com#endif
39613372Sgabeblack@google.com}
39713372Sgabeblack@google.com
39813372Sgabeblack@google.comint
39913372Sgabeblack@google.comsc_main(int argc, char **argv)
40013372Sgabeblack@google.com{
40113372Sgabeblack@google.com    SimControl sim_control("gem5", argc, argv);
40213372Sgabeblack@google.com
40313372Sgabeblack@google.com    filename = "m5out/stats-systemc.txt";
40413372Sgabeblack@google.com
40513372Sgabeblack@google.com    sc_core::sc_start();
40613372Sgabeblack@google.com
40713372Sgabeblack@google.com    CxxConfig::statsDump();
40813372Sgabeblack@google.com
40913372Sgabeblack@google.com    return EXIT_SUCCESS;
41013372Sgabeblack@google.com}
41113372Sgabeblack@google.com
41213372Sgabeblack@google.comvoid
41313372Sgabeblack@google.comSimControl::switchCpu(unsigned cpuNum, unsigned numTotalCpus) {
41413372Sgabeblack@google.com    assert(cpuNum < numTotalCpus);
41513372Sgabeblack@google.com    std::ostringstream from_cpu_name;
41613372Sgabeblack@google.com    std::ostringstream to_cpu_name;
41713372Sgabeblack@google.com
41813372Sgabeblack@google.com    from_cpu_name << from_cpu;
41913372Sgabeblack@google.com    to_cpu_name << to_cpu;
42013372Sgabeblack@google.com
42113372Sgabeblack@google.com    if (numTotalCpus > 1) {
42213372Sgabeblack@google.com        from_cpu_name << cpuNum;
42313372Sgabeblack@google.com        to_cpu_name << cpuNum;
42413372Sgabeblack@google.com    }
42513372Sgabeblack@google.com
42613372Sgabeblack@google.com    std::cerr << "Switching CPU "<< cpuNum << "(from='" << from_cpu_name.str()
42713372Sgabeblack@google.com        <<"' to '"<< to_cpu_name.str() << "')\n";
42813372Sgabeblack@google.com
42913372Sgabeblack@google.com    /* Assume the system is called system */
43013372Sgabeblack@google.com    System &system = config_manager->getObject<System>("system");
43113372Sgabeblack@google.com    BaseCPU &old_cpu = config_manager->getObject<BaseCPU>(from_cpu_name.str());
43213372Sgabeblack@google.com    BaseCPU &new_cpu = config_manager->getObject<BaseCPU>(to_cpu_name.str());
43313372Sgabeblack@google.com
43413372Sgabeblack@google.com    old_cpu.switchOut();
43513372Sgabeblack@google.com
43613372Sgabeblack@google.com    // I'm not sure if this can be called before old_cpu.switchOut(). If so,
43713372Sgabeblack@google.com    // it is best to just move this call before the switchCpu loop in run()
43813372Sgabeblack@google.com    // where it previously was
43913372Sgabeblack@google.com    if (cpuNum == 0)
44013372Sgabeblack@google.com        system.setMemoryMode(Enums::timing);
44113372Sgabeblack@google.com
44213372Sgabeblack@google.com    new_cpu.takeOverFrom(&old_cpu);
44313372Sgabeblack@google.com
44413372Sgabeblack@google.com
44513372Sgabeblack@google.com    std::cerr << "Switched CPU"<<cpuNum<<"\n";
44613372Sgabeblack@google.com}
447