summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xSConstruct3
-rw-r--r--configs/example/read_config.py531
-rwxr-xr-xsrc/SConscript67
-rw-r--r--src/python/m5/SimObject.py278
-rw-r--r--src/python/m5/params.py150
-rw-r--r--src/sim/SConscript4
-rw-r--r--src/sim/cxx_config.cc45
-rw-r--r--src/sim/cxx_config.hh241
-rw-r--r--src/sim/cxx_config_ini.cc104
-rw-r--r--src/sim/cxx_config_ini.hh87
-rw-r--r--src/sim/cxx_manager.cc740
-rw-r--r--src/sim/cxx_manager.hh314
-rw-r--r--util/cxx_config/Makefile65
-rw-r--r--util/cxx_config/README44
-rw-r--r--util/cxx_config/main.cc319
-rw-r--r--util/cxx_config/stats.cc115
-rw-r--r--util/cxx_config/stats.hh61
17 files changed, 3168 insertions, 0 deletions
diff --git a/SConstruct b/SConstruct
index 1078a3e96..8fb649143 100755
--- a/SConstruct
+++ b/SConstruct
@@ -173,6 +173,9 @@ AddLocalOption('--colors', dest='use_colors', action='store_true',
help="Add color to abbreviated scons output")
AddLocalOption('--no-colors', dest='use_colors', action='store_false',
help="Don't add color to abbreviated scons output")
+AddLocalOption('--with-cxx-config', dest='with_cxx_config',
+ action='store_true',
+ help="Build with support for C++-based configuration")
AddLocalOption('--default', dest='default', type='string', action='store',
help='Override which build_opts file to use for defaults')
AddLocalOption('--ignore-style', dest='ignore_style', action='store_true',
diff --git a/configs/example/read_config.py b/configs/example/read_config.py
new file mode 100644
index 000000000..ecb2950e6
--- /dev/null
+++ b/configs/example/read_config.py
@@ -0,0 +1,531 @@
+# 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.
+#
+# Author: Andrew Bardsley
+
+# This script allows .ini and .json system config file generated from a
+# previous gem5 run to be read in and instantiated.
+#
+# This may be useful as a way of allowing variant run scripts (say,
+# with more complicated than usual checkpointing/stats dumping/
+# simulation control) to read pre-described systems from config scripts
+# with better system-description capabilities. Splitting scripts
+# between system construction and run control may allow better
+# debugging.
+
+import argparse
+import ConfigParser
+import inspect
+import json
+import re
+import sys
+
+import m5
+import m5.ticks as ticks
+
+sim_object_classes_by_name = {
+ cls.__name__: cls for cls in m5.objects.__dict__.itervalues()
+ if inspect.isclass(cls) and issubclass(cls, m5.objects.SimObject) }
+
+# Add some parsing functions to Param classes to handle reading in .ini
+# file elements. This could be moved into src/python/m5/params.py if
+# reading .ini files from Python proves to be useful
+
+def no_parser(cls, flags, param):
+ raise Exception('Can\'t parse string: %s for parameter'
+ ' class: %s' % (str(param), cls.__name__))
+
+def simple_parser(suffix='', cast=lambda i: i):
+ def body(cls, flags, param):
+ return cls(cast(param + suffix))
+ return body
+
+# def tick_parser(cast=m5.objects.Latency): # lambda i: i):
+def tick_parser(cast=lambda i: i):
+ def body(cls, flags, param):
+ old_param = param
+ ret = cls(cast(str(param) + 't'))
+ return ret
+ return body
+
+def addr_range_parser(cls, flags, param):
+ sys.stdout.flush()
+ low, high = param.split(':')
+ return m5.objects.AddrRange(long(low), long(high))
+
+def memory_bandwidth_parser(cls, flags, param):
+ # The string will be in tick/byte
+ # Convert to byte/tick
+ value = 1.0 / float(param)
+ # Convert to byte/s
+ value = ticks.fromSeconds(value)
+ return cls('%fB/s' % value)
+
+# These parameters have trickier parsing from .ini files than might be
+# expected
+param_parsers = {
+ 'Bool': simple_parser(),
+ 'ParamValue': no_parser,
+ 'NumericParamValue': simple_parser(cast=long),
+ 'TickParamValue': tick_parser(),
+ 'Frequency': tick_parser(cast=m5.objects.Latency),
+ 'Voltage': simple_parser(suffix='V'),
+ 'Enum': simple_parser(),
+ 'MemorySize': simple_parser(suffix='B'),
+ 'MemorySize32': simple_parser(suffix='B'),
+ 'AddrRange': addr_range_parser,
+ 'String': simple_parser(),
+ 'MemoryBandwidth': memory_bandwidth_parser,
+ 'Time': simple_parser()
+ }
+
+for name, parser in param_parsers.iteritems():
+ setattr(m5.params.__dict__[name], 'parse_ini', classmethod(parser))
+
+class PortConnection(object):
+ """This class is similar to m5.params.PortRef but with just enough
+ information for ConfigManager"""
+
+ def __init__(self, object_name, port_name, index):
+ self.object_name = object_name
+ self.port_name = port_name
+ self.index = index
+
+ @classmethod
+ def from_string(cls, str):
+ m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', str)
+ object_name, port_name, whole_index, index = m.groups()
+ if index is not None:
+ index = int(index)
+ else:
+ index = 0
+
+ return PortConnection(object_name, port_name, index)
+
+ def __str__(self):
+ return '%s.%s[%d]' % (self.object_name, self.port_name, self.index)
+
+ def __cmp__(self, right):
+ return cmp((self.object_name, self.port_name, self.index),
+ (right.object_name, right.port_name, right.index))
+
+def to_list(v):
+ """Convert any non list to a singleton list"""
+ if isinstance(v, list):
+ return v
+ else:
+ return [v]
+
+class ConfigManager(object):
+ """Manager for parsing a Root configuration from a config file"""
+ def __init__(self, config):
+ self.config = config
+ self.objects_by_name = {}
+ self.flags = config.get_flags()
+
+ def find_object(self, object_name):
+ """Find and configure (with just non-SimObject parameters)
+ a single object"""
+
+ if object_name == 'Null':
+ return NULL
+
+ if object_name in self.objects_by_name:
+ return self.objects_by_name[object_name]
+
+ object_type = self.config.get_param(object_name, 'type')
+
+ if object_type not in sim_object_classes_by_name:
+ raise Exception('No SimObject type %s is available to'
+ ' build: %s' % (object_type, object_name))
+
+ object_class = sim_object_classes_by_name[object_type]
+
+ parsed_params = {}
+
+ for param_name, param in object_class._params.iteritems():
+ if issubclass(param.ptype, m5.params.ParamValue):
+ if isinstance(param, m5.params.VectorParamDesc):
+ param_values = self.config.get_param_vector(object_name,
+ param_name)
+
+ param_value = [ param.ptype.parse_ini(self.flags, value)
+ for value in param_values ]
+ else:
+ param_value = param.ptype.parse_ini(
+ self.flags, self.config.get_param(object_name,
+ param_name))
+
+ parsed_params[param_name] = param_value
+
+ obj = object_class(**parsed_params)
+ self.objects_by_name[object_name] = obj
+
+ return obj
+
+ def fill_in_simobj_parameters(self, object_name, obj):
+ """Fill in all references to other SimObjects in an objects
+ parameters. This relies on all referenced objects having been
+ created"""
+
+ if object_name == 'Null':
+ return NULL
+
+ for param_name, param in obj.__class__._params.iteritems():
+ if issubclass(param.ptype, m5.objects.SimObject):
+ if isinstance(param, m5.params.VectorParamDesc):
+ param_values = self.config.get_param_vector(object_name,
+ param_name)
+
+ setattr(obj, param_name, [ self.objects_by_name[name]
+ for name in param_values ])
+ else:
+ param_value = self.config.get_param(object_name,
+ param_name)
+
+ if param_value != 'Null':
+ setattr(obj, param_name, self.objects_by_name[
+ param_value])
+
+ return obj
+
+ def fill_in_children(self, object_name, obj):
+ """Fill in the children of this object. This relies on all the
+ referenced objects having been created"""
+
+ children = self.config.get_object_children(object_name)
+
+ for child_name, child_paths in children:
+ param = obj.__class__._params.get(child_name, None)
+
+ if isinstance(child_paths, list):
+ child_list = [ self.objects_by_name[path]
+ for path in child_paths ]
+ else:
+ child_list = self.objects_by_name[child_paths]
+
+ obj.add_child(child_name, child_list)
+
+ for path in to_list(child_paths):
+ self.fill_in_children(path, self.objects_by_name[path])
+
+ return obj
+
+ def parse_port_name(self, port):
+ """Parse the name of a port"""
+
+ m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', port)
+ peer, peer_port, whole_index, index = m.groups()
+ if index is not None:
+ index = int(index)
+ else:
+ index = 0
+
+ return (peer, self.objects_by_name[peer], peer_port, index)
+
+ def gather_port_connections(self, object_name, obj):
+ """Gather all the port-to-port connections from the named object.
+ Returns a list of (PortConnection, PortConnection) with unordered
+ (wrt. master/slave) connection information"""
+
+ if object_name == 'Null':
+ return NULL
+
+ parsed_ports = []
+ for port_name, port in obj.__class__._ports.iteritems():
+ # Assume that unnamed ports are unconnected
+ peers = self.config.get_port_peers(object_name, port_name)
+
+ for index, peer in zip(xrange(0, len(peers)), peers):
+ parsed_ports.append((
+ PortConnection(object_name, port.name, index),
+ PortConnection.from_string(peer)))
+
+ return parsed_ports
+
+ def bind_ports(self, connections):
+ """Bind all ports from the given connection list. Note that the
+ connection list *must* list all connections with both (slave,master)
+ and (master,slave) orderings"""
+
+ # Markup a dict of how many connections are made to each port.
+ # This will be used to check that the next-to-be-made connection
+ # has a suitable port index
+ port_bind_indices = {}
+ for from_port, to_port in connections:
+ port_bind_indices[
+ (from_port.object_name, from_port.port_name)] = 0
+
+ def port_has_correct_index(port):
+ return port_bind_indices[
+ (port.object_name, port.port_name)] == port.index
+
+ def increment_port_index(port):
+ port_bind_indices[
+ (port.object_name, port.port_name)] += 1
+
+ # Step through the sorted connections. Exactly one of
+ # each (slave,master) and (master,slave) pairs will be
+ # bindable because the connections are sorted.
+ # For example: port_bind_indices
+ # left right left right
+ # a.b[0] -> d.f[1] 0 0 X
+ # a.b[1] -> e.g 0 0 BIND!
+ # e.g -> a.b[1] 1 X 0
+ # d.f[0] -> f.h 0 0 BIND!
+ # d.f[1] -> a.b[0] 1 0 BIND!
+ connections_to_make = []
+ for connection in sorted(connections):
+ from_port, to_port = connection
+
+ if (port_has_correct_index(from_port) and
+ port_has_correct_index(to_port)):
+
+ connections_to_make.append((from_port, to_port))
+
+ increment_port_index(from_port)
+ increment_port_index(to_port)
+
+ # Exactly half of the connections (ie. all of them, one per
+ # direction) must now have been made
+ if (len(connections_to_make) * 2) != len(connections):
+ raise Exception('Port bindings can\'t be ordered')
+
+ # Actually do the binding
+ for from_port, to_port in connections_to_make:
+ from_object = self.objects_by_name[from_port.object_name]
+ to_object = self.objects_by_name[to_port.object_name]
+
+ setattr(from_object, from_port.port_name,
+ getattr(to_object, to_port.port_name))
+
+ def find_all_objects(self):
+ """Find and build all SimObjects from the config file and connect
+ their ports together as described. Does not instantiate system"""
+
+ # Build SimObjects for all sections of the config file
+ # populating not-SimObject-valued parameters
+ for object_name in self.config.get_all_object_names():
+ self.find_object(object_name)
+
+ # Add children to objects in the hierarchy from root
+ self.fill_in_children('root', self.find_object('root'))
+
+ # Now fill in SimObject-valued parameters in the knowledge that
+ # this won't be interpreted as becoming the parent of objects
+ # which are already in the root hierarchy
+ for name, obj in self.objects_by_name.iteritems():
+ self.fill_in_simobj_parameters(name, obj)
+
+ # Gather a list of all port-to-port connections
+ connections = []
+ for name, obj in self.objects_by_name.iteritems():
+ connections += self.gather_port_connections(name, obj)
+
+ # Find an acceptable order to bind those port connections and
+ # bind them
+ self.bind_ports(connections)
+
+class ConfigFile(object):
+ def get_flags(self):
+ return set()
+
+ def load(self, config_file):
+ """Load the named config file"""
+ pass
+
+ def get_all_object_names(self):
+ """Get a list of all the SimObject paths in the configuration"""
+ pass
+
+ def get_param(self, object_name, param_name):
+ """Get a single param or SimObject reference from the configuration
+ as a string"""
+ pass
+
+ def get_param_vector(self, object_name, param_name):
+ """Get a vector param or vector of SimObject references from the
+ configuration as a list of strings"""
+ pass
+
+ def get_object_children(self, object_name):
+ """Get a list of (name, paths) for each child of this object.
+ paths is either a single string object path or a list of object
+ paths"""
+ pass
+
+ def get_port_peers(self, object_name, port_name):
+ """Get the list of connected port names (in the string form
+ object.port(\[index\])?) of the port object_name.port_name"""
+ pass
+
+class ConfigIniFile(ConfigFile):
+ def __init__(self):
+ self.parser = ConfigParser.ConfigParser()
+
+ def load(self, config_file):
+ self.parser.read(config_file)
+
+ def get_all_object_names(self):
+ return self.parser.sections()
+
+ def get_param(self, object_name, param_name):
+ return self.parser.get(object_name, param_name)
+
+ def get_param_vector(self, object_name, param_name):
+ return self.parser.get(object_name, param_name).split()
+
+ def get_object_children(self, object_name):
+ if self.parser.has_option(object_name, 'children'):
+ children = self.parser.get(object_name, 'children')
+ child_names = children.split()
+ else:
+ child_names = []
+
+ def make_path(child_name):
+ if object_name == 'root':
+ return child_name
+ else:
+ return '%s.%s' % (object_name, child_name)
+
+ return [ (name, make_path(name)) for name in child_names ]
+
+ def get_port_peers(self, object_name, port_name):
+ if self.parser.has_option(object_name, port_name):
+ peer_string = self.parser.get(object_name, port_name)
+ return peer_string.split()
+ else:
+ return []
+
+class ConfigJsonFile(ConfigFile):
+ def __init__(self):
+ pass
+
+ def is_sim_object(self, node):
+ return isinstance(node, dict) and 'path' in node
+
+ def find_all_objects(self, node):
+ if self.is_sim_object(node):
+ self.object_dicts[node['path']] = node
+
+ if isinstance(node, list):
+ for elem in node:
+ self.find_all_objects(elem)
+ elif isinstance(node, dict):
+ for elem in node.itervalues():
+ self.find_all_objects(elem)
+
+ def load(self, config_file):
+ root = json.load(open(config_file, 'r'))
+ self.object_dicts = {}
+ self.find_all_objects(root)
+
+ def get_all_object_names(self):
+ return sorted(self.object_dicts.keys())
+
+ def parse_param_string(self, node):
+ if node is None:
+ return "Null"
+ elif self.is_sim_object(node):
+ return node['path']
+ else:
+ return str(node)
+
+ def get_param(self, object_name, param_name):
+ obj = self.object_dicts[object_name]
+
+ return self.parse_param_string(obj[param_name])
+
+ def get_param_vector(self, object_name, param_name):
+ obj = self.object_dicts[object_name]
+
+ return [ self.parse_param_string(p) for p in obj[param_name] ]
+
+ def get_object_children(self, object_name):
+ """It is difficult to tell which elements are children in the
+ JSON file as there is no explicit 'children' node. Take any
+ element which is a full SimObject description or a list of
+ SimObject descriptions. This will not work with a mixed list of
+ references and descriptions but that's a scenario that isn't
+ possible (very likely?) with gem5's binding/naming rules"""
+ obj = self.object_dicts[object_name]
+
+ children = []
+ for name, node in obj.iteritems():
+ if self.is_sim_object(node):
+ children.append((name, node['path']))
+ elif isinstance(node, list) and node != [] and all([
+ self.is_sim_object(e) for e in node ]):
+ children.append((name, [ e['path'] for e in node ]))
+
+ return children
+
+ def get_port_peers(self, object_name, port_name):
+ """Get the 'peer' element of any node with 'peer' and 'role'
+ elements"""
+ obj = self.object_dicts[object_name]
+
+ peers = []
+ if port_name in obj and 'peer' in obj[port_name] and \
+ 'role' in obj[port_name]:
+ peers = to_list(obj[port_name]['peer'])
+
+ return peers
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('config_file', metavar='config-file.ini',
+ help='.ini configuration file to load and run')
+
+args = parser.parse_args(sys.argv[1:])
+
+if args.config_file.endswith('.ini'):
+ config = ConfigIniFile()
+ config.load(args.config_file)
+else:
+ config = ConfigJsonFile()
+ config.load(args.config_file)
+
+ticks.fixGlobalFrequency()
+
+mgr = ConfigManager(config)
+
+mgr.find_all_objects()
+
+m5.instantiate()
+
+exit_event = m5.simulate()
+print 'Exiting @ tick %i because %s' % (
+ m5.curTick(), exit_event.getCause())
diff --git a/src/SConscript b/src/SConscript
index ef729cb33..8fe22d9ec 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -579,6 +579,18 @@ def createSimObjectParamStruct(target, source, env):
obj.cxx_param_decl(code)
code.write(target[0].abspath)
+def createSimObjectCxxConfig(is_header):
+ def body(target, source, env):
+ assert len(target) == 1 and len(source) == 1
+
+ name = str(source[0].get_contents())
+ obj = sim_objects[name]
+
+ code = code_formatter()
+ obj.cxx_config_param_file(code, is_header)
+ code.write(target[0].abspath)
+ return body
+
def createParamSwigWrapper(target, source, env):
assert len(target) == 1 and len(source) == 1
@@ -644,6 +656,61 @@ for name,simobj in sorted(sim_objects.iteritems()):
env.Depends(hh_file, depends + extra_deps)
env.Depends(SWIG, hh_file)
+# C++ parameter description files
+if GetOption('with_cxx_config'):
+ for name,simobj in sorted(sim_objects.iteritems()):
+ py_source = PySource.modules[simobj.__module__]
+ extra_deps = [ py_source.tnode ]
+
+ cxx_config_hh_file = File('cxx_config/%s.hh' % name)
+ cxx_config_cc_file = File('cxx_config/%s.cc' % name)
+ env.Command(cxx_config_hh_file, Value(name),
+ MakeAction(createSimObjectCxxConfig(True),
+ Transform("CXXCPRHH")))
+ env.Command(cxx_config_cc_file, Value(name),
+ MakeAction(createSimObjectCxxConfig(False),
+ Transform("CXXCPRCC")))
+ env.Depends(cxx_config_hh_file, depends + extra_deps +
+ [File('params/%s.hh' % name), File('sim/cxx_config.hh')])
+ env.Depends(cxx_config_cc_file, depends + extra_deps +
+ [cxx_config_hh_file])
+ Source(cxx_config_cc_file)
+
+ cxx_config_init_cc_file = File('cxx_config/init.cc')
+
+ def createCxxConfigInitCC(target, source, env):
+ assert len(target) == 1 and len(source) == 1
+
+ code = code_formatter()
+
+ for name,simobj in sorted(sim_objects.iteritems()):
+ if not hasattr(simobj, 'abstract') or not simobj.abstract:
+ code('#include "cxx_config/${name}.hh"')
+ code()
+ code('void cxxConfigInit()')
+ code('{')
+ code.indent()
+ for name,simobj in sorted(sim_objects.iteritems()):
+ not_abstract = not hasattr(simobj, 'abstract') or \
+ not simobj.abstract
+ if not_abstract and 'type' in simobj.__dict__:
+ code('cxx_config_directory["${name}"] = '
+ '${name}CxxConfigParams::makeDirectoryEntry();')
+ code.dedent()
+ code('}')
+ code.write(target[0].abspath)
+
+ py_source = PySource.modules[simobj.__module__]
+ extra_deps = [ py_source.tnode ]
+ env.Command(cxx_config_init_cc_file, Value(name),
+ MakeAction(createCxxConfigInitCC, Transform("CXXCINIT")))
+ cxx_param_hh_files = ["cxx_config/%s.hh" % simobj
+ for simobj in sorted(sim_objects.itervalues())
+ if not hasattr(simobj, 'abstract') or not simobj.abstract]
+ Depends(cxx_config_init_cc_file, cxx_param_hh_files +
+ [File('sim/cxx_config.hh')])
+ Source(cxx_config_init_cc_file)
+
# Generate any needed param SWIG wrapper files
params_i_files = []
for name,param in params_to_swig.iteritems():
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index 9f4c2c155..40203a307 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -114,6 +114,279 @@ def public_value(key, value):
isinstance(value, (FunctionType, MethodType, ModuleType,
classmethod, type))
+def createCxxConfigDirectoryEntryFile(code, name, simobj, is_header):
+ entry_class = 'CxxConfigDirectoryEntry_%s' % name
+ param_class = '%sCxxConfigParams' % name
+
+ code('#include "params/%s.hh"' % name)
+
+ if not is_header:
+ for param in simobj._params.values():
+ if isSimObjectClass(param.ptype):
+ code('#include "%s"' % param.ptype._value_dict['cxx_header'])
+ code('#include "params/%s.hh"' % param.ptype.__name__)
+ else:
+ param.ptype.cxx_ini_predecls(code)
+
+ if is_header:
+ member_prefix = ''
+ end_of_decl = ';'
+ code('#include "sim/cxx_config.hh"')
+ code()
+ code('class ${param_class} : public CxxConfigParams,'
+ ' public ${name}Params')
+ code('{')
+ code(' private:')
+ code.indent()
+ code('class DirectoryEntry : public CxxConfigDirectoryEntry')
+ code('{')
+ code(' public:')
+ code.indent()
+ code('DirectoryEntry();');
+ code()
+ code('CxxConfigParams *makeParamsObject() const')
+ code('{ return new ${param_class}; }')
+ code.dedent()
+ code('};')
+ code()
+ code.dedent()
+ code(' public:')
+ code.indent()
+ else:
+ member_prefix = '%s::' % param_class
+ end_of_decl = ''
+ code('#include "%s"' % simobj._value_dict['cxx_header'])
+ code('#include "base/str.hh"')
+ code('#include "cxx_config/${name}.hh"')
+
+ if simobj._ports.values() != []:
+ code('#include "mem/mem_object.hh"')
+ code('#include "mem/port.hh"')
+
+ code()
+ code('${member_prefix}DirectoryEntry::DirectoryEntry()');
+ code('{')
+
+ def cxx_bool(b):
+ return 'true' if b else 'false'
+
+ code.indent()
+ for param in simobj._params.values():
+ is_vector = isinstance(param, m5.params.VectorParamDesc)
+ is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
+
+ code('parameters["%s"] = new ParamDesc("%s", %s, %s);' %
+ (param.name, param.name, cxx_bool(is_vector),
+ cxx_bool(is_simobj)));
+
+ for port in simobj._ports.values():
+ is_vector = isinstance(port, m5.params.VectorPort)
+ is_master = port.role == 'MASTER'
+
+ code('ports["%s"] = new PortDesc("%s", %s, %s);' %
+ (port.name, port.name, cxx_bool(is_vector),
+ cxx_bool(is_master)))
+
+ code.dedent()
+ code('}')
+ code()
+
+ code('bool ${member_prefix}setSimObject(const std::string &name,')
+ code(' SimObject *simObject)${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ code.indent()
+ code('bool ret = true;')
+ code()
+ code('if (false) {')
+ for param in simobj._params.values():
+ is_vector = isinstance(param, m5.params.VectorParamDesc)
+ is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
+
+ if is_simobj and not is_vector:
+ code('} else if (name == "${{param.name}}") {')
+ code.indent()
+ code('this->${{param.name}} = '
+ 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);')
+ code('if (simObject && !this->${{param.name}})')
+ code(' ret = false;')
+ code.dedent()
+ code('} else {')
+ code(' ret = false;')
+ code('}')
+ code()
+ code('return ret;')
+ code.dedent()
+ code('}')
+
+ code()
+ code('bool ${member_prefix}setSimObjectVector('
+ 'const std::string &name,')
+ code(' const std::vector<SimObject *> &simObjects)${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ code.indent()
+ code('bool ret = true;')
+ code()
+ code('if (false) {')
+ for param in simobj._params.values():
+ is_vector = isinstance(param, m5.params.VectorParamDesc)
+ is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
+
+ if is_simobj and is_vector:
+ code('} else if (name == "${{param.name}}") {')
+ code.indent()
+ code('this->${{param.name}}.clear();')
+ code('for (auto i = simObjects.begin(); '
+ 'ret && i != simObjects.end(); i ++)')
+ code('{')
+ code.indent()
+ code('${{param.ptype.cxx_type}} object = '
+ 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);')
+ code('if (*i && !object)')
+ code(' ret = false;')
+ code('else')
+ code(' this->${{param.name}}.push_back(object);')
+ code.dedent()
+ code('}')
+ code.dedent()
+ code('} else {')
+ code(' ret = false;')
+ code('}')
+ code()
+ code('return ret;')
+ code.dedent()
+ code('}')
+
+ code()
+ code('void ${member_prefix}setName(const std::string &name_)'
+ '${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ code.indent()
+ code('this->name = name_;')
+ code('this->pyobj = NULL;')
+ code.dedent()
+ code('}')
+
+ if is_header:
+ code('const std::string &${member_prefix}getName()')
+ code('{ return this->name; }')
+
+ code()
+ code('bool ${member_prefix}setParam(const std::string &name,')
+ code(' const std::string &value, const Flags flags)${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ code.indent()
+ code('bool ret = true;')
+ code()
+ code('if (false) {')
+ for param in simobj._params.values():
+ is_vector = isinstance(param, m5.params.VectorParamDesc)
+ is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
+
+ if not is_simobj and not is_vector:
+ code('} else if (name == "${{param.name}}") {')
+ code.indent()
+ param.ptype.cxx_ini_parse(code,
+ 'value', 'this->%s' % param.name, 'ret =')
+ code.dedent()
+ code('} else {')
+ code(' ret = false;')
+ code('}')
+ code()
+ code('return ret;')
+ code.dedent()
+ code('}')
+
+ code()
+ code('bool ${member_prefix}setParamVector('
+ 'const std::string &name,')
+ code(' const std::vector<std::string> &values,')
+ code(' const Flags flags)${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ code.indent()
+ code('bool ret = true;')
+ code()
+ code('if (false) {')
+ for param in simobj._params.values():
+ is_vector = isinstance(param, m5.params.VectorParamDesc)
+ is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
+
+ if not is_simobj and is_vector:
+ code('} else if (name == "${{param.name}}") {')
+ code.indent()
+ code('${{param.name}}.clear();')
+ code('for (auto i = values.begin(); '
+ 'ret && i != values.end(); i ++)')
+ code('{')
+ code.indent()
+ code('${{param.ptype.cxx_type}} elem;')
+ param.ptype.cxx_ini_parse(code,
+ '*i', 'elem', 'ret =')
+ code('if (ret)')
+ code(' this->${{param.name}}.push_back(elem);')
+ code.dedent()
+ code('}')
+ code.dedent()
+ code('} else {')
+ code(' ret = false;')
+ code('}')
+ code()
+ code('return ret;')
+ code.dedent()
+ code('}')
+
+ code()
+ code('bool ${member_prefix}setPortConnectionCount('
+ 'const std::string &name,')
+ code(' unsigned int count)${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ code.indent()
+ code('bool ret = true;')
+ code()
+ code('if (false)')
+ code(' ;')
+ for port in simobj._ports.values():
+ code('else if (name == "${{port.name}}")')
+ code(' this->port_${{port.name}}_connection_count = count;')
+ code('else')
+ code(' ret = false;')
+ code()
+ code('return ret;')
+ code.dedent()
+ code('}')
+
+ code()
+ code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}')
+
+ if not is_header:
+ code('{')
+ if hasattr(simobj, 'abstract') and simobj.abstract:
+ code(' return NULL;')
+ else:
+ code(' return this->create();')
+ code('}')
+
+ if is_header:
+ code()
+ code('static CxxConfigDirectoryEntry'
+ ' *${member_prefix}makeDirectoryEntry()')
+ code('{ return new DirectoryEntry; }')
+
+ if is_header:
+ code.dedent()
+ code('};')
+
# The metaclass for SimObject. This class controls how new classes
# that derive from SimObject are instantiated, and provides inherited
# class behavior (just like a class controls how instances of that
@@ -583,6 +856,11 @@ struct PyObject;
code('#endif // __PARAMS__${cls}__')
return code
+ # Generate the C++ declaration/definition files for this SimObject's
+ # param struct to allow C++ initialisation
+ def cxx_config_param_file(cls, code, is_header):
+ createCxxConfigDirectoryEntryFile(code, cls.__name__, cls, is_header)
+ return code
# This *temporary* definition is required to support calls from the
# SimObject class definition to the MetaSimObject methods (in
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index f16cabaff..b7df7c660 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -120,6 +120,18 @@ class ParamValue(object):
def config_value(self):
return str(self)
+ # Prerequisites for .ini parsing with cxx_ini_parse
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ pass
+
+ # parse a .ini file entry for this param from string expression
+ # src into lvalue dest (of the param's C++ type)
+ @classmethod
+ def cxx_ini_parse(cls, code, src, dest, ret):
+ code('// Unhandled param type: %s' % cls.__name__)
+ code('%s false;' % ret)
+
# allows us to blithely call unproxy() on things without checking
# if they're really proxies or not
def unproxy(self, base):
@@ -454,6 +466,11 @@ class String(ParamValue,str):
self = value
return value
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s = %s;' % (dest, src))
+ code('%s true;' % ret)
+
def getValue(self):
return self
@@ -500,6 +517,19 @@ class NumericParamValue(ParamValue):
def config_value(self):
return self.value
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ # Assume that base/str.hh will be included anyway
+ # code('#include "base/str.hh"')
+ pass
+
+ # The default for parsing PODs from an .ini entry is to extract from an
+ # istringstream and let overloading choose the right type according to
+ # the dest type.
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s to_number(%s, %s);' % (ret, src, dest))
+
# Metaclass for bounds-checked integer parameters. See CheckedInt.
class CheckedIntType(MetaParamValue):
def __init__(cls, name, bases, dict):
@@ -592,6 +622,20 @@ class Cycles(CheckedInt):
from m5.internal.core import Cycles
return Cycles(self.value)
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ # Assume that base/str.hh will be included anyway
+ # code('#include "base/str.hh"')
+ pass
+
+ @classmethod
+ def cxx_ini_parse(cls, code, src, dest, ret):
+ code('uint64_t _temp;')
+ code('bool _ret = to_number(%s, _temp);' % src)
+ code('if (_ret)')
+ code(' %s = Cycles(_temp);' % dest)
+ code('%s _ret;' % ret)
+
class Float(ParamValue, float):
cxx_type = 'double'
cmdLineSettable = True
@@ -613,6 +657,14 @@ class Float(ParamValue, float):
def config_value(self):
return self
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
class MemorySize(CheckedInt):
cxx_type = 'uint64_t'
ex_str = '512MB'
@@ -738,6 +790,24 @@ class AddrRange(ParamValue):
def swig_predecls(cls, code):
Addr.swig_predecls(code)
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ @classmethod
+ def cxx_ini_parse(cls, code, src, dest, ret):
+ code('uint64_t _start, _end;')
+ code('char _sep;')
+ code('std::istringstream _stream(${src});')
+ code('_stream >> _start;')
+ code('_stream.get(_sep);')
+ code('_stream >> _end;')
+ code('bool _ret = !_stream.fail() &&'
+ '_stream.eof() && _sep == \':\';')
+ code('if (_ret)')
+ code(' ${dest} = AddrRange(_start, _end);')
+ code('${ret} _ret;')
+
def getValue(self):
# Go from the Python class to the wrapped C++ class generated
# by swig
@@ -783,6 +853,16 @@ class Bool(ParamValue):
def config_value(self):
return self.value
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ # Assume that base/str.hh will be included anyway
+ # code('#include "base/str.hh"')
+ pass
+
+ @classmethod
+ def cxx_ini_parse(cls, code, src, dest, ret):
+ code('%s to_bool(%s, %s);' % (ret, src, dest))
+
def IncEthernetAddr(addr, val = 1):
bytes = map(lambda x: int(x, 16), addr.split(':'))
bytes[5] += val
@@ -850,6 +930,11 @@ class EthernetAddr(ParamValue):
def ini_str(self):
return self.value
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s = Net::EthAddr(%s);' % (dest, src))
+ code('%s true;' % ret)
+
# When initializing an IpAddress, pass in an existing IpAddress, a string of
# the form "a.b.c.d", or an integer representing an IP.
class IpAddress(ParamValue):
@@ -1154,6 +1239,16 @@ class Time(ParamValue):
assert false
return str(self)
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <time.h>')
+
+ @classmethod
+ def cxx_ini_parse(cls, code, src, dest, ret):
+ code('char *_parse_ret = strptime((${src}).c_str(),')
+ code(' "%a %b %d %H:%M:%S %Y", &(${dest}));')
+ code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
+
# Enumerated types are a little more complex. The user specifies the
# type as Enum(foo) where foo is either a list or dictionary of
# alternatives (typically strings, but not necessarily so). (In the
@@ -1306,6 +1401,19 @@ class Enum(ParamValue):
def swig_predecls(cls, code):
code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
+ @classmethod
+ def cxx_ini_parse(cls, code, src, dest, ret):
+ code('if (false) {')
+ for elem_name in cls.map.iterkeys():
+ code('} else if (%s == "%s") {' % (src, elem_name))
+ code.indent()
+ code('%s = Enums::%s;' % (dest, elem_name))
+ code('%s true;' % ret)
+ code.dedent()
+ code('} else {')
+ code(' %s false;' % ret)
+ code('}')
+
def getValue(self):
return int(self.map[self.value])
@@ -1336,6 +1444,16 @@ class TickParamValue(NumericParamValue):
def getValue(self):
return long(self.value)
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ # Ticks are expressed in seconds in JSON files and in plain
+ # Ticks in .ini files. Switch based on a config flag
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('${ret} to_number(${src}, ${dest});')
+
class Latency(TickParamValue):
ex_str = "100ns"
@@ -1485,6 +1603,14 @@ class Voltage(float,ParamValue):
def ini_str(self):
return '%f' % self.getValue()
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
class Current(float, ParamValue):
cxx_type = 'double'
ex_str = "1mA"
@@ -1510,6 +1636,14 @@ class Current(float, ParamValue):
def ini_str(self):
return '%f' % self.getValue()
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
class NetworkBandwidth(float,ParamValue):
cxx_type = 'float'
ex_str = "1Gbps"
@@ -1541,6 +1675,14 @@ class NetworkBandwidth(float,ParamValue):
def config_value(self):
return '%f' % self.getValue()
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
class MemoryBandwidth(float,ParamValue):
cxx_type = 'float'
ex_str = "1GB/s"
@@ -1571,6 +1713,14 @@ class MemoryBandwidth(float,ParamValue):
def config_value(self):
return '%f' % self.getValue()
+ @classmethod
+ def cxx_ini_predecls(cls, code):
+ code('#include <sstream>')
+
+ @classmethod
+ def cxx_ini_parse(self, code, src, dest, ret):
+ code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
#
# "Constants"... handy aliases for various values.
#
diff --git a/src/sim/SConscript b/src/sim/SConscript
index 7987afa00..7583b53cb 100644
--- a/src/sim/SConscript
+++ b/src/sim/SConscript
@@ -43,6 +43,9 @@ SimObject('SubSystem.py')
Source('arguments.cc')
Source('async.cc')
Source('core.cc')
+Source('cxx_config.cc')
+Source('cxx_manager.cc')
+Source('cxx_config_ini.cc')
Source('debug.cc')
Source('py_interact.cc', skip_no_python=True)
Source('eventq.cc')
@@ -76,6 +79,7 @@ if env['TARGET_ISA'] != 'null':
DebugFlag('Checkpoint')
DebugFlag('Config')
+DebugFlag('CxxConfig')
DebugFlag('Drain')
DebugFlag('Event')
DebugFlag('Fault')
diff --git a/src/sim/cxx_config.cc b/src/sim/cxx_config.cc
new file mode 100644
index 000000000..f99afac8a
--- /dev/null
+++ b/src/sim/cxx_config.cc
@@ -0,0 +1,45 @@
+/*
+ * 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 "sim/cxx_config.hh"
+
+const std::string CxxConfigParams::invalidName = "<invalid>";
+
+/** Directory of all SimObject classes config details */
+std::map<std::string, CxxConfigDirectoryEntry *> cxx_config_directory;
diff --git a/src/sim/cxx_config.hh b/src/sim/cxx_config.hh
new file mode 100644
index 000000000..da2752b4b
--- /dev/null
+++ b/src/sim/cxx_config.hh
@@ -0,0 +1,241 @@
+/*
+ * 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
+ *
+ * C++-only configuration and instantiation support. This allows a
+ * config to be read back from a .ini and instantiated without
+ * Python. Useful if you want to embed gem5 within a larger system
+ * without carrying the integration cost of the fully-featured
+ * configuration system.
+ *
+ * This file contains definitions needed to store summaries of a
+ * SimObject's parameter structure
+ */
+
+#ifndef __SIM_CXX_CONFIG_HH__
+#define __SIM_CXX_CONFIG_HH__
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "mem/port.hh"
+#include "params/SimObject.hh"
+#include "sim/sim_object.hh"
+
+class CxxConfigParams;
+
+/** Config details entry for a SimObject. Instances of this class contain
+ * enough configuration layout information to popular a ...Param structure
+ * and build a SimObject from it with the help of the 'set' functions in
+ * each ...Param class */
+class CxxConfigDirectoryEntry
+{
+ public:
+ /* Class to represent parameters and SimObject references within
+ * SimObjects */
+ class ParamDesc
+ {
+ public:
+ const std::string name;
+
+ /* Is this a vector or singleton parameters/SimObject */
+ const bool isVector;
+
+ /** Is this a SimObject, and so is to be set with setSimObject...
+ * or another from-string parameter set with setParam... */
+ const bool isSimObject;
+
+ ParamDesc(const std::string &name_,
+ bool isVector_, bool isSimObject_) :
+ name(name_), isVector(isVector_), isSimObject(isSimObject_)
+ { }
+ };
+
+ /** Similar to ParamDesc to describe ports */
+ class PortDesc
+ {
+ public:
+ const std::string name;
+
+ /* Is this a vector or singleton parameters/SimObject */
+ const bool isVector;
+
+ /** Is this a master or slave port */
+ const bool isMaster;
+
+ PortDesc(const std::string &name_,
+ bool isVector_, bool isMaster_) :
+ name(name_), isVector(isVector_), isMaster(isMaster_)
+ { }
+ };
+
+ /** All parameters (including SimObjects) in order */
+ std::map<std::string, ParamDesc *> parameters;
+
+ /** Ports */
+ std::map<std::string, PortDesc *> ports;
+
+ /** Make a ...Param structure for the SimObject class of this entry */
+ virtual CxxConfigParams *makeParamsObject() const { return NULL; }
+
+ virtual ~CxxConfigDirectoryEntry() { }
+};
+
+/** Base for peer classes of SimObjectParams derived classes with parameter
+ * modifying member functions. C++ configuration will offer objects of
+ * these classes to SimObjects as params rather than SimObjectParams
+ * objects */
+class CxxConfigParams
+{
+ private:
+ static const std::string invalidName;
+
+ public:
+ /** Flags passable to setParam... to smooth over any parsing difference
+ * between different config files */
+ typedef uint32_t FlagsType;
+ typedef ::Flags<FlagsType> Flags;
+
+ /** Example flag */
+ /* static const FlagsType MY_NEW_FLAG = 0x00000001; */
+
+ public:
+ /** Set future object's full path name */
+ virtual void setName(const std::string &name_) { }
+
+ /** Get full path name string */
+ virtual const std::string &getName() { return invalidName; }
+
+ /** Set a SimObject valued parameter with a reference to the given
+ * SimObject. This will return false if the parameter name is not
+ * valid or the object is of the wrong type */
+ virtual bool setSimObject(const std::string &name,
+ SimObject *simObject)
+ { return false; }
+
+ /** As setSimObjectVector but set a whole vector of references */
+ virtual bool setSimObjectVector(const std::string &name,
+ const std::vector<SimObject *> &simObjects)
+ { return false; }
+
+ /** Set a parameter with a value parsed from the given string. The
+ * parsing regime matches the format of .ini config files. Returns
+ * false if the parameter name is not valid or the string cannot be
+ * parsed as the type of the parameter */
+ virtual bool setParam(const std::string &name,
+ const std::string &value, const Flags flags)
+ { return false; }
+
+ /** As setParamVector but for parameters given as vectors pre-separated
+ * into elements */
+ virtual bool setParamVector(const std::string &name,
+ const std::vector<std::string> &values, const Flags flags)
+ { return false; }
+
+ /** Set the number of connections expected for the named port. Returns
+ * false if the port name is not valid */
+ virtual bool setPortConnectionCount(const std::string &name,
+ unsigned int count)
+ { return false; }
+
+ /** Create the associated SimObject */
+ virtual SimObject *simObjectCreate() { return NULL; }
+
+ CxxConfigParams() { }
+
+ virtual ~CxxConfigParams() { }
+};
+
+/** Config file wrapper providing a common interface to CxxConfigManager */
+class CxxConfigFileBase
+{
+ public:
+ CxxConfigFileBase() { }
+ virtual ~CxxConfigFileBase() { }
+
+ /** Get a single parameter value as a string returned in value.
+ * For booleans, the function expects "true" or "false" in value.
+ * For NULL SimObjects, it expects "Null" */
+ virtual bool getParam(const std::string &object_name,
+ const std::string &param_name,
+ std::string &value) const = 0;
+
+ /** Get a list/vector parameter */
+ virtual bool getParamVector(const std::string &object_name,
+ const std::string &param_name,
+ std::vector<std::string> &values) const = 0;
+
+ /** Get the peer (connected) ports of the named ports */
+ virtual bool getPortPeers(const std::string &object_name,
+ const std::string &port_name,
+ std::vector<std::string> &peers) const = 0;
+
+ /** Does an object with this path exist? */
+ virtual bool objectExists(const std::string &object_name) const = 0;
+
+ /** Get all SimObjects in the config */
+ virtual void getAllObjectNames(std::vector<std::string> &list) const = 0;
+
+ /** Get the names or paths of all the children SimObjects of this
+ * SimObject. If return_paths is true then full paths are returned.
+ * If false, only the last name component for each object is returned */
+ virtual void getObjectChildren(const std::string &object_name,
+ std::vector<std::string> &children,
+ bool return_paths = false) const = 0;
+
+ /** Load config file */
+ virtual bool load(const std::string &filename) = 0;
+
+ /** Get the flags which should be used to modify parameter parsing
+ * behaviour */
+ virtual CxxConfigParams::Flags getFlags() const { return 0; }
+};
+
+/** Directory of all SimObject classes config details */
+extern std::map<std::string, CxxConfigDirectoryEntry *>
+ cxx_config_directory;
+
+/** Initialise cxx_config_directory. This is defined in the
+ * auto-generated .../cxx_config/init.cc */
+void cxxConfigInit();
+
+#endif // __SIM_CXX_CONFIG_HH__
diff --git a/src/sim/cxx_config_ini.cc b/src/sim/cxx_config_ini.cc
new file mode 100644
index 000000000..3df6d72d4
--- /dev/null
+++ b/src/sim/cxx_config_ini.cc
@@ -0,0 +1,104 @@
+/*
+ * 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 "sim/cxx_config_ini.hh"
+
+bool
+CxxIniFile::getParam(const std::string &object_name,
+ const std::string &param_name,
+ std::string &value) const
+{
+ return iniFile.find(object_name, param_name, value);
+}
+
+bool
+CxxIniFile::getParamVector(const std::string &object_name,
+ const std::string &param_name,
+ std::vector<std::string> &values) const
+{
+ std::string value;
+ bool ret = iniFile.find(object_name, param_name, value);
+
+ if (ret) {
+ std::vector<std::string> sub_object_names;
+
+ tokenize(values, value, ' ', true);
+ }
+
+ return ret;
+}
+
+bool
+CxxIniFile::getPortPeers(const std::string &object_name,
+ const std::string &port_name,
+ std::vector<std::string> &peers) const
+{
+ return getParamVector(object_name, port_name, peers);
+}
+
+bool
+CxxIniFile::objectExists(const std::string &object) const
+{
+ return iniFile.sectionExists(object);
+}
+
+void
+CxxIniFile::getAllObjectNames(std::vector<std::string> &list) const
+{
+ iniFile.getSectionNames(list);
+}
+
+void
+CxxIniFile::getObjectChildren(const std::string &object_name,
+ std::vector<std::string> &children, bool return_paths) const
+{
+ if (!getParamVector(object_name, "children", children))
+ return;
+
+ if (return_paths && object_name != "root") {
+ for (auto i = children.begin(); i != children.end(); ++i)
+ *i = object_name + "." + *i;
+ }
+}
+
+bool
+CxxIniFile::load(const std::string &filename)
+{
+ return iniFile.load(filename);
+}
diff --git a/src/sim/cxx_config_ini.hh b/src/sim/cxx_config_ini.hh
new file mode 100644
index 000000000..9ea61976e
--- /dev/null
+++ b/src/sim/cxx_config_ini.hh
@@ -0,0 +1,87 @@
+/*
+ * 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
+ *
+ * .ini file reading wrapper for use with CxxConfigManager
+ */
+
+#ifndef __SIM_CXX_CONFIG_INI_HH__
+#define __SIM_CXX_CONFIG_INI_HH__
+
+#include "base/inifile.hh"
+#include "base/str.hh"
+#include "sim/cxx_config.hh"
+
+/** CxxConfigManager interface for using .ini files */
+class CxxIniFile : public CxxConfigFileBase
+{
+ protected:
+ IniFile iniFile;
+
+ public:
+ CxxIniFile() { }
+
+ /* Most of these functions work by mapping 'object' onto 'section' */
+
+ bool getParam(const std::string &object_name,
+ const std::string &param_name,
+ std::string &value) const;
+
+ bool getParamVector(const std::string &object_name,
+ const std::string &param_name,
+ std::vector<std::string> &values) const;
+
+ bool getPortPeers(const std::string &object_name,
+ const std::string &port_name,
+ std::vector<std::string> &peers) const;
+
+ bool objectExists(const std::string &object_name) const;
+
+ void getAllObjectNames(std::vector<std::string> &list) const;
+
+ void getObjectChildren(const std::string &object_name,
+ std::vector<std::string> &children,
+ bool return_paths = false) const;
+
+ bool load(const std::string &filename);
+};
+
+#endif // __SIM_CXX_CONFIG_INI_HH__
diff --git a/src/sim/cxx_manager.cc b/src/sim/cxx_manager.cc
new file mode 100644
index 000000000..7f6a03398
--- /dev/null
+++ b/src/sim/cxx_manager.cc
@@ -0,0 +1,740 @@
+/*
+ * 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 <sstream>
+
+#include "base/str.hh"
+#include "debug/CxxConfig.hh"
+#include "mem/mem_object.hh"
+#include "sim/cxx_manager.hh"
+#include "sim/serialize.hh"
+
+CxxConfigManager::CxxConfigManager(CxxConfigFileBase &configFile_) :
+ configFile(configFile_), flags(configFile_.getFlags()),
+ simObjectResolver(*this)
+{
+}
+
+const CxxConfigDirectoryEntry &
+CxxConfigManager::findObjectType(const std::string &object_name,
+ std::string &object_type)
+{
+ if (!configFile.objectExists(object_name))
+ throw Exception(object_name, "Can't find sim object");
+
+ if (!configFile.getParam(object_name, "type", object_type))
+ throw Exception(object_name, "Sim object has no 'type' field");
+
+ if (cxx_config_directory.find(object_type) ==
+ cxx_config_directory.end())
+ {
+ throw Exception(object_name, csprintf(
+ "No sim object type %s is available", object_type));
+ }
+
+ const CxxConfigDirectoryEntry *entry = cxx_config_directory[object_type];
+
+ return *entry;
+}
+
+std::string
+CxxConfigManager::rename(const std::string &from_name)
+{
+ for (auto i = renamings.begin(); i != renamings.end(); ++ i) {
+ const Renaming &renaming = *i;
+
+ if (from_name.find(renaming.fromPrefix) == 0) {
+ return renaming.toPrefix +
+ from_name.substr(renaming.fromPrefix.length());
+ }
+ }
+
+ return from_name;
+}
+
+std::string
+CxxConfigManager::unRename(const std::string &to_name)
+{
+ for (auto i = renamings.begin(); i != renamings.end(); ++ i) {
+ const Renaming &renaming = *i;
+
+ if (to_name.find(renaming.toPrefix) == 0) {
+ return renaming.fromPrefix +
+ to_name.substr(renaming.toPrefix.length());
+ }
+ }
+
+ return to_name;
+}
+
+static
+std::string formatParamList(const std::vector<std::string> &param_values)
+{
+ std::ostringstream params;
+
+ auto i = param_values.begin();
+ auto end_i = param_values.end();
+
+ params << '[';
+ while (i != end_i) {
+ params << (*i);
+ ++i;
+
+ if (i != end_i)
+ params << ", ";
+ }
+ params << ']';
+
+ return params.str();
+}
+
+SimObject *
+CxxConfigManager::findObject(const std::string &object_name,
+ bool visit_children)
+{
+ std::string instance_name = rename(object_name);
+
+ if (object_name == "Null")
+ return NULL;
+
+ /* Already constructed */
+ if (objectsByName.find(instance_name) != objectsByName.end())
+ return objectsByName[instance_name];
+
+ if (inVisit.find(instance_name) != inVisit.end())
+ throw Exception(instance_name, "Cycle in configuration");
+
+ std::string object_type;
+ const CxxConfigDirectoryEntry &entry =
+ findObjectType(object_name, object_type);
+
+ SimObject *object = NULL;
+
+ CxxConfigParams *object_params = findObjectParams(object_name);
+
+ try {
+ DPRINTF(CxxConfig, "Configuring sim object references for: %s"
+ " (%s from object %s)\n", instance_name, object_type,
+ object_name);
+
+ /* Remember the path back to the top of the recursion to detect
+ * cycles */
+ inVisit.insert(instance_name);
+
+ /* Resolve pointed-to SimObjects by recursing into them */
+ for (auto i = entry.parameters.begin();
+ i != entry.parameters.end(); ++i)
+ {
+ const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
+
+ if (param->isSimObject) {
+ if (param->isVector) {
+ std::vector<std::string> sub_object_names;
+
+ if (!configFile.getParamVector(object_name, param->name,
+ sub_object_names))
+ {
+ throw Exception(object_name, csprintf(
+ "Element not found: %s", param->name));
+ }
+
+ std::vector<SimObject *> sub_objects;
+
+ for (auto n = sub_object_names.begin();
+ n != sub_object_names.end(); ++n)
+ {
+ SimObject *sub_object = findObject(*n,
+ visit_children);
+
+ if (sub_object)
+ sub_objects.push_back(sub_object);
+ }
+
+ if (!object_params->setSimObjectVector(param->name,
+ sub_objects))
+ {
+ throw Exception(object_name, csprintf(
+ "Can't assign sim object element %s from \"%s\"",
+ param->name, formatParamList(sub_object_names)));
+ }
+
+ DPRINTF(CxxConfig, "Setting sim object(s): %s.%s=%s\n",
+ object_name, param->name,
+ formatParamList(sub_object_names));
+ } else {
+ std::string sub_object_name;
+
+ if (!configFile.getParam(object_name, param->name,
+ sub_object_name))
+ {
+ throw Exception(object_name, csprintf(
+ "Element not found: %s", param->name));
+ }
+
+ SimObject *sub_object = findObject(sub_object_name,
+ visit_children);
+
+ if (sub_object) {
+ if (!object_params->setSimObject(param->name,
+ sub_object))
+ {
+ throw Exception(object_name, csprintf(
+ "Can't assign sim object element %s from"
+ " \"%s\"", param->name, sub_object_name));
+ }
+ }
+
+ DPRINTF(CxxConfig, "Setting sim object(s):"
+ " %s.%s=%s\n", object_name, param->name,
+ sub_object_name);
+ }
+ }
+ }
+
+ DPRINTF(CxxConfig, "Creating SimObject: %s\n", instance_name);
+ object = object_params->simObjectCreate();
+
+ if (!object) {
+ throw Exception(object_name, csprintf("Couldn't create object of"
+ " type: %s", object_type));
+ }
+
+ objectsByName[instance_name] = object;
+ objectParamsByName[instance_name] = object_params;
+
+ if (visit_children) {
+ std::vector<std::string> children;
+ configFile.getObjectChildren(object_name, children, true);
+
+ /* Visit all your children */
+ for (auto i = children.begin(); i != children.end(); ++i)
+ findObject(*i, visit_children);
+ }
+ } catch (Exception &) {
+ delete object_params;
+ throw;
+ }
+
+ /* Mark that we've exited object
+ * construction and so 'find'ing this object again won't be a
+ * configuration loop */
+ inVisit.erase(object_name);
+ return object;
+}
+
+CxxConfigParams *
+CxxConfigManager::findObjectParams(const std::string &object_name)
+{
+ std::string instance_name = rename(object_name);
+
+ /* Already constructed */
+ if (objectParamsByName.find(instance_name) != objectParamsByName.end())
+ return objectParamsByName[instance_name];
+
+ std::string object_type;
+ const CxxConfigDirectoryEntry &entry =
+ findObjectType(object_name, object_type);
+
+ DPRINTF(CxxConfig, "Configuring parameters of object: %s (%s)\n",
+ instance_name, object_type);
+
+ CxxConfigParams *object_params = entry.makeParamsObject();
+
+ try {
+ /* Fill in the implicit parameters that don't necessarily
+ * appear in config files */
+ object_params->setName(instance_name);
+
+ /* Fill in parameters */
+ for (auto i = entry.parameters.begin();
+ i != entry.parameters.end(); ++i)
+ {
+ const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
+
+ if (!param->isSimObject) {
+ /* Only handle non-SimObject parameters here (see below) */
+
+ if (param->isVector) {
+ std::vector<std::string> param_values;
+
+ if (!configFile.getParamVector(object_name, param->name,
+ param_values))
+ {
+ throw Exception(object_name, csprintf(
+ "Element not found for parameter: %s",
+ param->name));
+ }
+
+ if (!object_params->setParamVector(param->name,
+ param_values, flags))
+ {
+ throw Exception(instance_name, csprintf(
+ "Bad parameter value: .%s=X=\"%s\"",
+ param->name, formatParamList(param_values)));
+ }
+
+ DPRINTF(CxxConfig, "Setting parameter"
+ " %s.%s=%s\n", instance_name, param->name,
+ formatParamList(param_values));
+ } else {
+ std::string param_value;
+
+ if (!configFile.getParam(object_name, param->name,
+ param_value))
+ {
+ throw Exception(object_name, csprintf(
+ "Element not found for parameter: %s",
+ param->name));
+ }
+
+ if (!object_params->setParam(param->name, param_value,
+ flags))
+ {
+ throw Exception(instance_name, csprintf(
+ "Bad parameter value: .%s=X=\"%s\"",
+ param->name, param_value));
+ }
+
+ DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
+ instance_name, param->name, param_value);
+ }
+ }
+ }
+
+ /* Find the number of ports that will need binding and set the
+ * appropriate port_..._connection_count parameters */
+ for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
+ const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
+ std::vector<std::string> peers;
+
+ if (!configFile.getPortPeers(object_name, port->name, peers)) {
+ DPRINTF(CxxConfig, "Port not found: %s.%s,"
+ " assuming there are no connections\n",
+ instance_name, port->name);
+ }
+
+ unsigned int peer_count = peers.size();
+
+ /* It would be more efficient to split the peer list and
+ * save the values for peer binding later but that would
+ * require another annoying intermediate structure to
+ * hold for little performance increase */
+
+ if (!object_params->setPortConnectionCount(port->name,
+ peer_count))
+ {
+ throw Exception(instance_name, csprintf(
+ "Unconnected port: %s", port->name));
+ }
+
+ DPRINTF(CxxConfig, "Setting port connection count"
+ " for: %s.%s to %d\n",
+ instance_name, port->name, peer_count);
+ }
+
+ /* Set pointed-to SimObjects to NULL */
+ for (auto i = entry.parameters.begin();
+ i != entry.parameters.end(); ++i)
+ {
+ const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
+
+ if (param->isSimObject) {
+ bool ret;
+
+ DPRINTF(CxxConfig, "Nulling sim object reference: %s.%s\n",
+ instance_name, param->name);
+
+ if (param->isVector) {
+ /* Clear the reference list. */
+ std::vector<SimObject *> empty;
+ ret = object_params->setSimObjectVector(param->name,
+ empty);
+ } else {
+ ret = object_params->setSimObject(param->name, NULL);
+ }
+
+ if (!ret) {
+ throw Exception(instance_name, csprintf(
+ "Error nulling sim object reference(s): %s",
+ param->name));
+ }
+ }
+ }
+ } catch (Exception &) {
+ delete object_params;
+ throw;
+ }
+
+ objectParamsByName[instance_name] = object_params;
+
+ return object_params;
+}
+
+void
+CxxConfigManager::findAllObjects()
+{
+ std::vector<std::string> objects;
+ configFile.getAllObjectNames(objects);
+
+ /* Sort the object names to get a consistent initialisation order
+ * even with config file reorganisation */
+ std::sort(objects.begin(), objects.end());
+
+ for (auto i = objects.begin(); i != objects.end(); ++i)
+ findObject(*i);
+
+ /* Set the traversal order for further iterators */
+ objectsInOrder.clear();
+ findTraversalOrder("root");
+}
+
+void
+CxxConfigManager::findTraversalOrder(const std::string &object_name)
+{
+ SimObject *object = findObject(object_name);
+
+ if (object) {
+ objectsInOrder.push_back(object);
+
+ std::vector<std::string> children;
+ configFile.getObjectChildren(object_name, children, true);
+
+ /* Visit all your children */
+ for (auto i = children.begin(); i != children.end(); ++i)
+ findTraversalOrder(*i);
+ }
+}
+
+void
+CxxConfigManager::bindAllPorts()
+{
+ for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
+ bindObjectPorts(*i);
+}
+
+void
+CxxConfigManager::bindPort(
+ SimObject *master_object, const std::string &master_port_name,
+ PortID master_port_index,
+ SimObject *slave_object, const std::string &slave_port_name,
+ PortID slave_port_index)
+{
+ MemObject *master_mem_object = dynamic_cast<MemObject *>(master_object);
+ MemObject *slave_mem_object = dynamic_cast<MemObject *>(slave_object);
+
+ if (!master_mem_object) {
+ throw Exception(master_object->name(), csprintf(
+ "Object isn't a mem object and so can have master port:"
+ " %s[%d]", master_port_name, master_port_index));
+ }
+
+ if (!slave_mem_object) {
+ throw Exception(slave_object->name(), csprintf(
+ "Object isn't a mem object and so can have slave port:"
+ " %s[%d]", slave_port_name, slave_port_index));
+ }
+
+ /* FIXME, check slave_port_index against connection_count
+ * defined for port, need getPortConnectionCount and a
+ * getCxxConfigDirectoryEntry for each object. */
+
+ /* It would be nice to be able to catch the errors from these calls. */
+ BaseMasterPort &master_port = master_mem_object->getMasterPort(
+ master_port_name, master_port_index);
+ BaseSlavePort &slave_port = slave_mem_object->getSlavePort(
+ slave_port_name, slave_port_index);
+
+ if (master_port.isConnected()) {
+ throw Exception(master_object->name(), csprintf(
+ "Master port: %s[%d] is already connected\n", master_port_name,
+ master_port_index));
+ }
+
+ if (slave_port.isConnected()) {
+ throw Exception(slave_object->name(), csprintf(
+ "Slave port: %s[%d] is already connected\n", slave_port_name,
+ slave_port_index));
+ }
+
+ DPRINTF(CxxConfig, "Binding port %s.%s[%d]"
+ " to %s:%s[%d]\n",
+ master_object->name(), master_port_name, master_port_index,
+ slave_object->name(), slave_port_name, slave_port_index);
+
+ master_port.bind(slave_port);
+}
+
+void
+CxxConfigManager::bindMasterPort(SimObject *object,
+ const CxxConfigDirectoryEntry::PortDesc &port,
+ const std::vector<std::string> &peers)
+{
+ unsigned int master_port_index = 0;
+
+ for (auto peer_i = peers.begin(); peer_i != peers.end();
+ ++peer_i)
+ {
+ const std::string &peer = *peer_i;
+ std::string slave_object_name;
+ std::string slave_port_name;
+ unsigned int slave_port_index;
+
+ parsePort(peer, slave_object_name, slave_port_name,
+ slave_port_index);
+
+ std::string slave_instance_name = rename(slave_object_name);
+
+ if (objectsByName.find(slave_instance_name) == objectsByName.end()) {
+ throw Exception(object->name(), csprintf(
+ "Can't find slave port object: %s", slave_instance_name));
+ }
+
+ SimObject *slave_object = objectsByName[slave_instance_name];
+
+ bindPort(object, port.name, master_port_index,
+ slave_object, slave_port_name, slave_port_index);
+
+ master_port_index++;
+ }
+}
+
+void
+CxxConfigManager::bindObjectPorts(SimObject *object)
+{
+ /* We may want to separate object->name() from the name in configuration
+ * later to allow (for example) repetition of fragments of configs */
+ const std::string &instance_name = object->name();
+
+ std::string object_name = unRename(instance_name);
+
+ std::string object_type;
+ const CxxConfigDirectoryEntry &entry =
+ findObjectType(object_name, object_type);
+
+ DPRINTF(CxxConfig, "Binding ports of object: %s (%s)\n",
+ instance_name, object_type);
+
+ for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
+ const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
+
+ DPRINTF(CxxConfig, "Binding port: %s.%s\n", instance_name,
+ port->name);
+
+ std::vector<std::string> peers;
+ configFile.getPortPeers(object_name, port->name, peers);
+
+ /* Only handle master ports as binding only needs to happen once
+ * for each observed pair of ports */
+ if (port->isMaster) {
+ if (!port->isVector && peers.size() > 1) {
+ throw Exception(instance_name, csprintf(
+ "Too many connections to non-vector port %s (%d)\n",
+ port->name, peers.size()));
+ }
+
+ bindMasterPort(object, *port, peers);
+ }
+ }
+}
+
+void
+CxxConfigManager::parsePort(const std::string &inp,
+ std::string &path, std::string &port, unsigned int &index)
+{
+ std::size_t dot_i = inp.rfind('.');
+ std::size_t open_square_i = inp.rfind('[');
+
+ if (dot_i == std::string::npos) {
+ DPRINTF(CxxConfig, "Bad port string: %s\n", inp);
+ path = "";
+ port = "";
+ index = 0;
+ } else {
+ path = std::string(inp, 0, dot_i);
+
+ if (open_square_i == std::string::npos) {
+ /* Singleton port */
+ port = std::string(inp, dot_i + 1, inp.length() - dot_i);
+ index = 0;
+ } else {
+ /* Vectored port elemnt */
+ port = std::string(inp, dot_i + 1, (open_square_i - 1) - dot_i);
+ index = std::atoi(inp.c_str() + open_square_i + 1);
+ }
+ }
+}
+
+void
+CxxConfigManager::forEachObject(void (SimObject::*mem_func)())
+{
+ for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
+ ((*i)->*mem_func)();
+}
+
+void
+CxxConfigManager::instantiate(bool build_all)
+{
+ if (build_all) {
+ findAllObjects();
+ bindAllPorts();
+ }
+
+ DPRINTF(CxxConfig, "Initialising all objects\n");
+ forEachObject(&SimObject::init);
+
+ DPRINTF(CxxConfig, "Registering stats\n");
+ forEachObject(&SimObject::regStats);
+
+ DPRINTF(CxxConfig, "Registering probe points\n");
+ forEachObject(&SimObject::regProbePoints);
+
+ DPRINTF(CxxConfig, "Connecting probe listeners\n");
+ forEachObject(&SimObject::regProbeListeners);
+}
+
+void
+CxxConfigManager::initState()
+{
+ DPRINTF(CxxConfig, "Calling initState on all objects\n");
+ forEachObject(&SimObject::initState);
+}
+
+void
+CxxConfigManager::startup()
+{
+ DPRINTF(CxxConfig, "Starting up all objects\n");
+ forEachObject(&SimObject::startup);
+}
+
+unsigned int
+CxxConfigManager::drain(DrainManager *drain_manager)
+{
+ unsigned int ret = 0;
+
+ for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i)
+ ret += (*i)->drain(drain_manager);
+
+ return ret;
+}
+
+void
+CxxConfigManager::drainResume()
+{
+ forEachObject(&SimObject::drainResume);
+}
+
+void
+CxxConfigManager::serialize(std::ostream &os)
+{
+ for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) {
+ // (*i)->nameOut(os); FIXME, change access spec. for nameOut
+ os << '[' << (*i)->name() << "]\n";
+ (*i)->serialize(os);
+ }
+}
+
+void
+CxxConfigManager::loadState(Checkpoint *checkpoint)
+{
+ for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i)
+ (*i)->loadState(checkpoint);
+}
+
+void
+CxxConfigManager::deleteObjects()
+{
+ for (auto i = objectsInOrder.rbegin(); i != objectsInOrder.rend(); ++i) {
+ DPRINTF(CxxConfig, "Freeing sim object: %s\n", (*i)->name());
+ delete *i;
+ }
+
+ for (auto i = objectParamsByName.rbegin();
+ i != objectParamsByName.rend(); ++i)
+ {
+ CxxConfigParams *params = (*i).second;
+
+ DPRINTF(CxxConfig, "Freeing sim object params: %s\n",
+ params->getName());
+ delete params;
+ }
+
+ objectsInOrder.clear();
+ objectsByName.clear();
+}
+
+void
+CxxConfigManager::setParam(const std::string &object_name,
+ const std::string &param_name, const std::string &param_value)
+{
+ CxxConfigParams *params = findObjectParams(object_name);
+
+ if (!params->setParam(param_name, param_value, flags)) {
+ throw Exception(object_name, csprintf("Bad parameter value:"
+ " .%s=X=\"%s\"", param_name, param_value));
+ } else {
+ std::string instance_name = rename(object_name);
+
+ DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
+ instance_name, param_name, param_value);
+ }
+}
+
+void
+CxxConfigManager::setParamVector(const std::string &object_name,
+ const std::string &param_name,
+ const std::vector<std::string> &param_values)
+{
+ CxxConfigParams *params = findObjectParams(object_name);
+
+ if (!params->setParamVector(param_name, param_values, flags)) {
+ throw Exception(object_name, csprintf("Bad vector parameter value:"
+ " .%s=X=\"%s\"", param_name, formatParamList(param_values)));
+ } else {
+ std::string instance_name = rename(object_name);
+
+ DPRINTF(CxxConfig, "Setting parameter %s.%s=\"%s\"\n",
+ instance_name, param_name, formatParamList(param_values));
+ }
+}
+
+void CxxConfigManager::addRenaming(const Renaming &renaming)
+{
+ renamings.push_back(renaming);
+}
diff --git a/src/sim/cxx_manager.hh b/src/sim/cxx_manager.hh
new file mode 100644
index 000000000..caa115f03
--- /dev/null
+++ b/src/sim/cxx_manager.hh
@@ -0,0 +1,314 @@
+/*
+ * 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
+ *
+ * C++-only configuration and instantiation support. This allows a
+ * config to be read back from a config file and instantiated without
+ * Python. Useful if you want to embed gem5 within a larger system
+ * without carrying the integration cost of the fully-featured
+ * configuration system.
+ *
+ * This file contains the config loading/storing manager class
+ */
+
+#ifndef __SIM_CXX_MANAGER_HH__
+#define __SIM_CXX_MANAGER_HH__
+
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/cprintf.hh"
+#include "sim/cxx_config.hh"
+
+class Checkpoint;
+
+/** This class allows a config file to be read into gem5 (generating the
+ * appropriate SimObjects) from C++ */
+class CxxConfigManager
+{
+ protected:
+ /** Configuration file being read */
+ CxxConfigFileBase &configFile;
+
+ /** Flags to pass to affect param setting */
+ CxxConfigParams::Flags flags;
+
+ public:
+ /** Exception for instantiate/post-instantiate errors */
+ class Exception : public std::exception
+ {
+ public:
+ std::string name;
+ std::string message;
+
+ public:
+ Exception(const std::string &name_, const std::string &message_) :
+ name(name_), message(message_)
+ { }
+
+ const char *what() const throw() { return message.c_str(); }
+
+ ~Exception() throw() { }
+ };
+
+ /** Name substitution when instantiating any object whose name starts
+ * with fromPrefix. Where both renamed and unrenamed names are used
+ * in the code, `object' as part of a name usually refers to the
+ * unrenamed name (the name as it appears in the config file) and
+ * `instance' is part of the renamed name */
+ struct Renaming
+ {
+ std::string fromPrefix;
+ std::string toPrefix;
+
+ Renaming(const std::string &from_prefix,
+ const std::string &to_prefix) :
+ fromPrefix(from_prefix),
+ toPrefix(to_prefix)
+ { }
+ };
+
+ public:
+ /** SimObject indexed by name */
+ std::map<std::string, SimObject *> objectsByName;
+
+ /** ...Params objects created by this manager */
+ std::map<std::string, CxxConfigParams *> objectParamsByName;
+
+ /** SimObjects in order. This is populated by findAllObjects */
+ std::list<SimObject *> objectsInOrder;
+
+ protected:
+ /** While configuring, inVisit contains names of SimObjects visited in
+ * this recursive configuration walk */
+ std::set<std::string> inVisit;
+
+ /** All the renamings applicable when instantiating objects */
+ std::list<Renaming> renamings;
+
+ /** Bind a single connection between two objects' ports */
+ void bindPort(SimObject *masterObject, const std::string &masterPort,
+ PortID masterPortIndex, SimObject *slaveObject,
+ const std::string &slavePort, PortID slavePortIndex);
+
+ /** Bind a single (possibly vectored) master port to peers from the
+ * unparsed list peers with elements in the .ini connection format:
+ * path(.path)*.port[index] */
+ void bindMasterPort(SimObject *object,
+ const CxxConfigDirectoryEntry::PortDesc &port,
+ const std::vector<std::string> &peers);
+
+ /** Apply the first matching renaming in renamings to the given name */
+ std::string rename(const std::string &from_name);
+
+ /** Apply the first matching renaming in reverse (toPrefix -> fromPrefix
+ * for the given name */
+ std::string unRename(const std::string &to_name);
+
+ protected:
+ /** Bind the ports of all the objects in objectInOrder order.
+ * Also */
+ void bindAllPorts();
+
+ /** Class for resolving SimObject names to SimObjects usable by the
+ * checkpoint restore mechanism */
+ class SimObjectResolver : public ::SimObjectResolver
+ {
+ protected:
+ CxxConfigManager &configManager;
+
+ public:
+ SimObjectResolver(CxxConfigManager &configManager_) :
+ configManager(configManager_)
+ { }
+
+ SimObject *resolveSimObject(const std::string &name)
+ { return &(configManager.getObject<SimObject>(name)); }
+ };
+
+ /** Singleton instance of SimObjectResolver */
+ SimObjectResolver simObjectResolver;
+
+ public:
+ CxxConfigManager(CxxConfigFileBase &configFile_);
+
+ /** Find the type field for a named object and return both the
+ * name of the type to object_type and the object's directory
+ * entry as the return value */
+ const CxxConfigDirectoryEntry &findObjectType(
+ const std::string &object_name, std::string &object_type);
+
+ /** Add a name prefix renaming to those currently applied. Call this
+ * before trying to instantiate any object as the name mappings are
+ * not applied to the config tree read from the config file but are
+ * applied while processing instantiations */
+ void addRenaming(const Renaming &renaming);
+
+ public:
+ /** Bind the ports of a single SimObject */
+ void bindObjectPorts(SimObject *object);
+
+ /** Walk the configuration starting with object object_name and fill
+ * in all the elements of this object on the way. This involves:
+ * <ul>
+ * <li>Calling findObjectParams to make the ...Params object
+ * If findObjectParams has already been called for this object,
+ * the ...Params object generated by that called (stored in
+ * (objectParamsByName[object_name] will be used)</li>
+ * <li>Populating the ...Params object references to other
+ * SimObjects by recursively descending into the trees formed
+ * by SimObject references</li>
+ * <li>Building the final SimObject and adding it to
+ * objectsByName</li>
+ * <li>If visit_children is true, recursively visit all this
+ * object's children and build/find them too</li>
+ * </ul>
+ * After the first call, this function will return
+ * objectsByName[object_name] */
+ SimObject *findObject(const std::string &object_name,
+ bool visit_children = false);
+
+ /** Find the parameters for the named object. Returns NULL if the
+ * object isn't in the configuration. For the first call with a
+ * particular object name, a new CxxConfigParams descended object
+ * is made with the configuration file contents for this object.
+ * This involves populating that ...Params object with:
+ * <ul>
+ * <li>parameter values from the configuration file</li>
+ * <li>port connection connection counts from the connection counts
+ * indicated by the number of peer ports in the configuration
+ * file</li>
+ * <li>nulled (or vector<>::clear'ed) SimObject references for
+ * SimObject-values parameters</li>
+ * </ul>
+ * The ...Params object is then added to objectParamsByName
+ * After the first call, this function will return
+ * objectParamsByName[object_name] */
+ CxxConfigParams *findObjectParams(const std::string &object_name);
+
+ /** Populate objectsInOrder with a preorder, depth first traversal from
+ * the given object name down through all its children */
+ void findTraversalOrder(const std::string &object_name);
+
+ /** Find an object from objectsByName with a type-checking cast.
+ * This function is provided for manipulating objects after
+ * instantiate as it assumes the named object exists. */
+ template<typename SimObjectType>
+ SimObjectType &
+ getObject(const std::string &object_name)
+ {
+ if (objectsByName.find(object_name) == objectsByName.end()) {
+ throw Exception("", csprintf("No sim object named: %s",
+ object_name));
+ }
+
+ SimObjectType *object = dynamic_cast<SimObjectType *>(
+ objectsByName[object_name]);
+
+ if (!object) {
+ throw Exception("", csprintf("Sim object: %s has the wrong"
+ " type", object_name));
+ }
+
+ return *object;
+ }
+
+ /** Perform mem_func on each SimObject */
+ void forEachObject(void (SimObject::*mem_func)());
+
+ /** Find all objects by iterating over the object names in the config
+ * file with findObject. Also populate the traversal order */
+ void findAllObjects();
+
+ /** Parse a port string of the form 'path(.path)*.port[index]' into
+ * path, port and index */
+ static void parsePort(const std::string &inp,
+ std::string &path, std::string &port, unsigned int &index);
+
+ /** Build all objects (if build_all is true, otherwise objects must
+ * have been individually findObject-ed and added to the traversal
+ * order) and perform all the configuration specific actions up to,
+ * but not including initState.
+ *
+ * If you want to set some parameters before completing instantiation,
+ * call findObjectParams on the objects you want to modify, then call
+ * instantiate */
+ void instantiate(bool build_all = true);
+
+ /** Call initState on all objects */
+ void initState();
+
+ /** Call startup on all objects */
+ void startup();
+
+ /** Drain all objects */
+ unsigned int drain(DrainManager *drain_manager);
+
+ /** Resume from drain */
+ void drainResume();
+
+ /** Serialize (checkpoint) all objects to the given stream */
+ void serialize(std::ostream &os);
+
+ /** Load all objects' state from the given Checkpoint */
+ void loadState(Checkpoint *checkpoint);
+
+ /** Delete all objects and clear objectsByName and objectsByOrder */
+ void deleteObjects();
+
+ /** Get the resolver used to map SimObject names to SimObjects for
+ * checkpoint restore */
+ SimObjectResolver &getSimObjectResolver() { return simObjectResolver; }
+
+ /** Convenience functions for calling set... member functions on a
+ * CxxConfigParams for an object. These functions throw Exception
+ * rather than return a bool on failure */
+ void setParam(const std::string &object_name,
+ const std::string &param_name, const std::string &param_value);
+ void setParamVector(const std::string &object_name,
+ const std::string &param_name,
+ const std::vector<std::string> &param_values);
+};
+
+#endif // __SIM_CXX_MANAGER_HH__
diff --git a/util/cxx_config/Makefile b/util/cxx_config/Makefile
new file mode 100644
index 000000000..e8f491225
--- /dev/null
+++ b/util/cxx_config/Makefile
@@ -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
+
+ARCH = ARM
+VARIANT = opt
+
+CXXFLAGS = -I../../build/$(ARCH) -L../../build/$(ARCH)
+CXXFLAGS += -std=c++0x
+LIBS = -lgem5_$(VARIANT)
+
+## You may also need protobuf flags
+# CXXFLAGS += $(shell pkg-config --cflags --libs-only-L protobuf)
+# LIBS += $(shell pkg-config --libs protobuf)
+
+ALL = gem5.$(VARIANT).cxx
+
+all: $(ALL)
+
+.cc.o:
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
+stats.o: stats.cc stats.hh
+main.o: main.cc stats.hh
+
+gem5.$(VARIANT).cxx: main.o stats.o
+ $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
+
+clean:
+ $(RM) $(ALL)
+ $(RM) *.o
+ $(RM) -r m5out
diff --git a/util/cxx_config/README b/util/cxx_config/README
new file mode 100644
index 000000000..a80f7ad8f
--- /dev/null
+++ b/util/cxx_config/README
@@ -0,0 +1,44 @@
+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 demo implements a few of the simulation control mechanisms of the Python
+gem5 on top of a C++ configured system.
+
+Read main.cc for more details of the implementation.
+
+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/cxx_config
+
+Then edit Makefile to set the paths for PYTHON and 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_config.py m5out/config.ini
diff --git a/util/cxx_config/main.cc b/util/cxx_config/main.cc
new file mode 100644
index 000000000..a9a86b424
--- /dev/null
+++ b/util/cxx_config/main.cc
@@ -0,0 +1,319 @@
+/*
+ * 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
+ *
+ * C++-only configuration and instantiation support. This allows a
+ * config to be read back from a .ini and instantiated without
+ * Python. Useful if you want to embed gem5 within a larger system
+ * without carrying the integration cost of the fully-featured
+ * configuration system.
+ *
+ * This file contains a demonstration main using CxxConfigManager.
+ * Build with something like:
+ *
+ * scons --without-python build/ARM/libgem5_opt.so
+ *
+ * g++ -DTRACING_ON -std=c++0x -Ibuild/ARM src/sim/cxx_main.cc \
+ * -o gem5cxx.opt -Lbuild/ARM -lgem5_opt
+ */
+
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+#include "base/inifile.hh"
+#include "base/statistics.hh"
+#include "base/str.hh"
+#include "base/trace.hh"
+#include "cpu/base.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"
+
+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"
+ );
+
+ std::exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char **argv)
+{
+ std::string prog_name(argv[0]);
+ unsigned int arg_ptr = 1;
+
+ if (argc == 1)
+ usage(prog_name);
+
+ cxxConfigInit();
+
+ initSignals();
+
+ setClockFrequency(1000000000000);
+ curEventQueue(getEventQueue(0));
+
+ Stats::initSimStats();
+ Stats::registerHandlers(CxxConfig::statsReset, CxxConfig::statsDump);
+
+ Trace::enabled = true;
+ setDebugFlag("Terminal");
+ // setDebugFlag("CxxConfig");
+
+ const std::string config_file(argv[arg_ptr]);
+
+ CxxConfigFileBase *conf = new CxxIniFile();
+
+ if (!conf->load(config_file.c_str())) {
+ std::cerr << "Can't open config file: " << config_file << '\n';
+ return EXIT_FAILURE;
+ }
+ arg_ptr++;
+
+ CxxConfigManager *config_manager = new CxxConfigManager(*conf);
+
+ bool checkpoint_restore = false;
+ bool checkpoint_save = false;
+ bool switch_cpus = false;
+ std::string checkpoint_dir = "";
+ std::string from_cpu = "";
+ std::string to_cpu = "";
+ Tick pre_run_time = 1000000;
+ Tick pre_switch_time = 1000000;
+
+ 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[arg_ptr + 2], ',');
+ config_manager->setParamVector(argv[arg_ptr],
+ argv[arg_ptr + 1], 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 {
+ usage(prog_name);
+ }
+ }
+ } catch (CxxConfigManager::Exception &e) {
+ std::cerr << e.name << ": " << e.message << "\n";
+ return EXIT_FAILURE;
+ }
+
+ if (checkpoint_save && checkpoint_restore) {
+ std::cerr << "Don't try and save and restore a checkpoint in the"
+ " same run\n";
+ return EXIT_FAILURE;
+ }
+
+ CxxConfig::statsEnable();
+ getEventQueue(0)->dump();
+
+ try {
+ config_manager->instantiate();
+ if (!checkpoint_restore) {
+ config_manager->initState();
+ config_manager->startup();
+ }
+ } catch (CxxConfigManager::Exception &e) {
+ std::cerr << "Config problem in sim object " << e.name
+ << ": " << e.message << "\n";
+
+ return EXIT_FAILURE;
+ }
+
+ GlobalSimLoopExitEvent *exit_event = NULL;
+
+ if (checkpoint_save) {
+
+ exit_event = simulate(pre_run_time);
+
+ DrainManager drain_manager;
+ unsigned int drain_count = 1;
+ do {
+ drain_count = config_manager->drain(&drain_manager);
+
+ std::cerr << "Draining " << drain_count << '\n';
+
+ if (drain_count > 0) {
+ drain_manager.setCount(drain_count);
+ 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 (checkpoint_restore) {
+ std::cerr << "Restoring checkpoint\n";
+
+ Checkpoint *checkpoint = new Checkpoint(checkpoint_dir,
+ config_manager->getSimObjectResolver());
+
+ Serializable::unserializeGlobals(checkpoint);
+ config_manager->loadState(checkpoint);
+
+ config_manager->drainResume();
+
+ std::cerr << "Restored from checkpoint\n";
+ }
+
+ if (switch_cpus) {
+ exit_event = simulate(pre_switch_time);
+
+ std::cerr << "Switching CPU\n";
+
+ /* Assume the system is called system */
+ System &system = config_manager->getObject<System>("system");
+ BaseCPU &old_cpu = config_manager->getObject<BaseCPU>(from_cpu);
+ BaseCPU &new_cpu = config_manager->getObject<BaseCPU>(to_cpu);
+
+ DrainManager drain_manager;
+ unsigned int drain_count = 1;
+ do {
+ drain_count = config_manager->drain(&drain_manager);
+
+ std::cerr << "Draining " << drain_count << '\n';
+
+ if (drain_count > 0) {
+ drain_manager.setCount(drain_count);
+ exit_event = simulate();
+ }
+ } while (drain_count > 0);
+
+ old_cpu.switchOut();
+ system.setMemoryMode(Enums::timing);
+ new_cpu.takeOverFrom(&old_cpu);
+ config_manager->drainResume();
+
+ std::cerr << "Switched CPU\n";
+ }
+
+ 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
+
+ delete config_manager;
+
+ return EXIT_SUCCESS;
+}
diff --git a/util/cxx_config/stats.cc b/util/cxx_config/stats.cc
new file mode 100644
index 000000000..ef5d9b5d3
--- /dev/null
+++ b/util/cxx_config/stats.cc
@@ -0,0 +1,115 @@
+/*
+ * 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
+ *
+ * C++-only configuration stats handling example
+ *
+ * Register with: Stats::registerHandlers(statsReset, statsDump)
+ */
+
+#include "base/statistics.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)
+ (*i)->prepare();
+}
+
+void statsDump()
+{
+ std::cerr << "Stats dump\n";
+
+ Stats::processDumpQueue();
+
+ std::list<Stats::Info *> stats = Stats::statsList();
+
+ statsPrepare();
+
+ /* gather_stats -> convert_value */
+ for (auto i = stats.begin(); i != stats.end(); ++i) {
+ Stats::Info *stat = *i;
+
+ Stats::ScalarInfo *scalar = dynamic_cast<Stats::ScalarInfo *>(stat);
+ Stats::VectorInfo *vector = dynamic_cast<Stats::VectorInfo *>(stat);
+
+ if (scalar) {
+ std::cerr << "SCALAR " << stat->name << ' '
+ << scalar->value() << '\n';
+ } else if (vector) {
+ Stats::VResult results = vector->value();
+
+ unsigned int index = 0;
+ for (auto e = results.begin(); e != results.end(); ++e) {
+ std::cerr << "VECTOR " << stat->name << '[' << index
+ << "] " << (*e) << '\n';
+ index++;
+ }
+ std::cerr << "VTOTAL " << stat->name << ' '
+ << vector->total() << '\n';
+ } else {
+ std::cerr << "?????? " << stat->name << '\n';
+ }
+ }
+}
+
+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)
+ (*i)->enable();
+}
+
+}
diff --git a/util/cxx_config/stats.hh b/util/cxx_config/stats.hh
new file mode 100644
index 000000000..360cb6293
--- /dev/null
+++ b/util/cxx_config/stats.hh
@@ -0,0 +1,61 @@
+/*
+ * 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
+ *
+ * C++-only configuration stats handling example
+ *
+ * Register with: Stats::registerHandlers(statsReset, statsDump)
+ */
+
+#ifndef __UTIL_CXX_CONFIG_STATS_H__
+#define __UTIL_CXX_CONFIG_STATS_H__
+
+namespace CxxConfig
+{
+
+void statsDump();
+void statsReset();
+void statsEnable();
+void statsPrepare();
+
+}
+
+#endif // __UTIL_CXX_CONFIG_STATS_H__