1/*
2 * Copyright (c) 2014 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andrew Bardsley
38 */
39
40#include <cstdlib>
41#include <iostream>
42#include <list>
43
44#include "base/statistics.hh"
45#include "sc_gem5_control.hh"
46#include "sc_logger.hh"
47#include "sc_module.hh"
48#include "sim/cxx_config_ini.hh"
49#include "sim/cxx_manager.hh"
50#include "sim/debug.hh"
51#include "sim/init_signals.hh"
52#include "sim/stat_control.hh"
53#include "stats.hh"
54
55namespace Gem5SystemC
56{
57
58/** This is the private side of Gem5Control */
59class Gem5TopLevelModule : public Gem5SystemC::Module
60{
61    friend class Gem5Control;
62
63  protected:
64    CxxConfigFileBase *config_file;
65    CxxConfigManager *root_manager;
66    Gem5SystemC::Logger logger;
67
68    /** Things to do at end_of_elaborate */
69    std::list<void (*)()> endOfElaborationFuncs;
70
71  public:
72    SC_HAS_PROCESS(Gem5TopLevelModule);
73
74    Gem5TopLevelModule(sc_core::sc_module_name name,
75        const std::string &config_filename);
76    ~Gem5TopLevelModule();
77
78    /** gem5 simulate.  @todo for more interesting simulation control,
79     *  this needs to be more complicated */
80    void run();
81
82    /* Register an action to happen at the end of elaboration */
83    void registerEndOfElaboration(void (*func)())
84    {
85        endOfElaborationFuncs.push_back(func);
86    }
87
88    /** SystemC startup */
89    void end_of_elaboration();
90};
91
92Gem5System::Gem5System(CxxConfigManager *manager_,
93    const std::string &system_name, const std::string &instance_name) :
94    manager(manager_),
95    systemName(system_name),
96    instanceName(instance_name)
97{
98    manager->addRenaming(CxxConfigManager::Renaming(
99        system_name, instance_name));
100}
101
102Gem5System::~Gem5System()
103{
104    delete manager;
105}
106
107void
108Gem5System::setParam(const std::string &object,
109    const std::string &param_name, const std::string &param_value)
110{
111    manager->setParam(systemName + (object != "" ? "." + object : ""),
112        param_name, param_value);
113}
114
115void
116Gem5System::setParamVector(const std::string &object,
117    const std::string &param_name,
118    const std::vector<std::string> &param_values)
119{
120    manager->setParamVector(systemName +
121        (object != "" ? "." + object : ""), param_name, param_values);
122}
123
124void
125Gem5System::instantiate()
126{
127    try {
128        /* Make a new System */
129        SimObject *obj = manager->findObject(systemName, true);
130
131        /* Add the System's objects to the list of managed
132         *  objects for initialisation */
133        manager->findTraversalOrder(systemName);
134
135        /* Bound ports *must* be internal to System */
136        for (auto i = manager->objectsInOrder.begin();
137             i != manager->objectsInOrder.end();
138             ++ i)
139        {
140            manager->bindObjectPorts(*i);
141        }
142
143        /* gem5 startup sequence */
144        manager->instantiate(false);
145        manager->initState();
146        manager->startup();
147    } catch (CxxConfigManager::Exception &e) {
148        fatal("Config problem in Gem5System: %s: %s",
149            e.name, e.message);
150    }
151}
152
153Gem5Control::Gem5Control(const std::string &config_filename)
154{
155    module = new Gem5TopLevelModule("gem5", config_filename);
156}
157
158Gem5Control::~Gem5Control()
159{ }
160
161void
162Gem5Control::registerEndOfElaboration(void (*func)())
163{
164    module->registerEndOfElaboration(func);
165}
166
167void
168Gem5Control::setDebugFlag(const char *flag)
169{
170    ::setDebugFlag(flag);
171}
172
173void
174Gem5Control::clearDebugFlag(const char *flag)
175{
176    ::clearDebugFlag(flag);
177}
178
179void
180Gem5Control::setRemoteGDBPort(unsigned int port)
181{
182    ::setRemoteGDBPort(port);
183}
184
185Gem5System *
186Gem5Control::makeSystem(const std::string &system_name,
187    const std::string &instance_name)
188{
189    Gem5System *ret = new Gem5System(
190        new CxxConfigManager(*(module->config_file)),
191        system_name, instance_name);
192
193    return ret;
194}
195
196const std::string &
197Gem5Control::getVersion() const
198{
199    return version;
200}
201
202void
203Gem5Control::setVersion(const std::string &new_version)
204{
205    if (version != "")
206        fatal("Gem5Control::setVersion called for a second time");
207
208    version = new_version;
209}
210
211Gem5TopLevelModule::Gem5TopLevelModule(sc_core::sc_module_name name,
212    const std::string &config_filename) :
213    Gem5SystemC::Module(name),
214    config_file(NULL),
215    root_manager(NULL)
216{
217    SC_THREAD(run);
218
219    cxxConfigInit();
220
221    /* Pass DPRINTF messages to SystemC */
222    Trace::setDebugLogger(&logger);
223
224    /* @todo need this as an option */
225    Gem5SystemC::setTickFrequency();
226
227    /* Make a SystemC-synchronising event queue and install it as the
228     *  sole top level gem5 EventQueue */
229    Gem5SystemC::Module::setupEventQueues(*this);
230
231    if (sc_core::sc_get_time_resolution() !=
232        sc_core::sc_time(1, sc_core::SC_PS))
233    {
234        fatal("Time resolution must be set to 1 ps for gem5 to work");
235    }
236
237    /* Enable keyboard interrupt, async I/O etc. */
238    initSignals();
239
240    /* Enable stats */
241    Stats::initSimStats();
242    Stats::registerHandlers(CxxConfig::statsReset, CxxConfig::statsDump);
243
244    Trace::enable();
245
246    config_file = new CxxIniFile();
247
248    if (!config_file->load(config_filename)) {
249        fatal("Gem5TopLevelModule: Can't open config file: %s",
250            config_filename);
251    }
252
253    root_manager = new CxxConfigManager(*config_file);
254
255    CxxConfig::statsEnable();
256
257    /* Make the root object */
258    try {
259        SimObject *root = root_manager->findObject("root", false);
260
261        /* Make sure we don't traverse into root's children */
262        root_manager->objectsInOrder.push_back(root);
263
264        root_manager->instantiate(false);
265        root_manager->initState();
266        root_manager->startup();
267    } catch (CxxConfigManager::Exception &e) {
268        fatal("Config problem in Gem5TopLevelModule: %s: %s",
269            e.name, e.message);
270    }
271}
272
273Gem5TopLevelModule::~Gem5TopLevelModule()
274{
275    delete config_file;
276    delete root_manager;
277}
278
279void
280Gem5TopLevelModule::run()
281{
282    GlobalSimLoopExitEvent *exit_event = NULL;
283
284    exit_event = simulate();
285
286    std::cerr << "Exit at tick " << curTick()
287        << ", cause: " << exit_event->getCause() << '\n';
288
289    getEventQueue(0)->dump();
290}
291
292void
293Gem5TopLevelModule::end_of_elaboration()
294{
295    for (auto i = endOfElaborationFuncs.begin();
296         i != endOfElaborationFuncs.end(); ++i)
297    {
298        (*i)();
299    }
300}
301
302}
303
304Gem5SystemC::Gem5Control *
305makeGem5Control(const std::string &config_filename)
306{
307    return new Gem5SystemC::Gem5Control(config_filename);
308}
309
310