114050Snikos.nikoleris@arm.com# Copyright (c) 2014,2019 ARM Limited
210458Sandreas.hansson@arm.com# All rights reserved.
310458Sandreas.hansson@arm.com#
410458Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall
510458Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual
610458Sandreas.hansson@arm.com# property including but not limited to intellectual property relating
710458Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software
810458Sandreas.hansson@arm.com# licensed hereunder.  You may use the software subject to the license
910458Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated
1010458Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software,
1110458Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form.
1210458Sandreas.hansson@arm.com#
1310458Sandreas.hansson@arm.com# Redistribution and use in source and binary forms, with or without
1410458Sandreas.hansson@arm.com# modification, are permitted provided that the following conditions are
1510458Sandreas.hansson@arm.com# met: redistributions of source code must retain the above copyright
1610458Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer;
1710458Sandreas.hansson@arm.com# redistributions in binary form must reproduce the above copyright
1810458Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer in the
1910458Sandreas.hansson@arm.com# documentation and/or other materials provided with the distribution;
2010458Sandreas.hansson@arm.com# neither the name of the copyright holders nor the names of its
2110458Sandreas.hansson@arm.com# contributors may be used to endorse or promote products derived from
2210458Sandreas.hansson@arm.com# this software without specific prior written permission.
2310458Sandreas.hansson@arm.com#
2410458Sandreas.hansson@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2510458Sandreas.hansson@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2610458Sandreas.hansson@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2710458Sandreas.hansson@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2810458Sandreas.hansson@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2910458Sandreas.hansson@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3010458Sandreas.hansson@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3110458Sandreas.hansson@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3210458Sandreas.hansson@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3310458Sandreas.hansson@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3410458Sandreas.hansson@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3510458Sandreas.hansson@arm.com#
3610458Sandreas.hansson@arm.com# Author: Andrew Bardsley
3710458Sandreas.hansson@arm.com
3810458Sandreas.hansson@arm.com# This script allows .ini and .json system config file generated from a
3910458Sandreas.hansson@arm.com# previous gem5 run to be read in and instantiated.
4010458Sandreas.hansson@arm.com#
4110458Sandreas.hansson@arm.com# This may be useful as a way of allowing variant run scripts (say,
4210458Sandreas.hansson@arm.com# with more complicated than usual checkpointing/stats dumping/
4310458Sandreas.hansson@arm.com# simulation control) to read pre-described systems from config scripts
4410458Sandreas.hansson@arm.com# with better system-description capabilities.  Splitting scripts
4510458Sandreas.hansson@arm.com# between system construction and run control may allow better
4610458Sandreas.hansson@arm.com# debugging.
4710458Sandreas.hansson@arm.com
4812564Sgabeblack@google.comfrom __future__ import print_function
4913774Sandreas.sandberg@arm.comfrom __future__ import absolute_import
5012564Sgabeblack@google.com
5110458Sandreas.hansson@arm.comimport argparse
5210458Sandreas.hansson@arm.comimport ConfigParser
5310458Sandreas.hansson@arm.comimport inspect
5410458Sandreas.hansson@arm.comimport json
5510458Sandreas.hansson@arm.comimport re
5614050Snikos.nikoleris@arm.comimport six
5710458Sandreas.hansson@arm.comimport sys
5810458Sandreas.hansson@arm.com
5910458Sandreas.hansson@arm.comimport m5
6010458Sandreas.hansson@arm.comimport m5.ticks as ticks
6110458Sandreas.hansson@arm.com
6214050Snikos.nikoleris@arm.comif six.PY3:
6314050Snikos.nikoleris@arm.com    long = int
6414050Snikos.nikoleris@arm.com
6510458Sandreas.hansson@arm.comsim_object_classes_by_name = {
6614050Snikos.nikoleris@arm.com    cls.__name__: cls for cls in m5.objects.__dict__.values()
6710458Sandreas.hansson@arm.com    if inspect.isclass(cls) and issubclass(cls, m5.objects.SimObject) }
6810458Sandreas.hansson@arm.com
6910458Sandreas.hansson@arm.com# Add some parsing functions to Param classes to handle reading in .ini
7010458Sandreas.hansson@arm.com#   file elements.  This could be moved into src/python/m5/params.py if
7110458Sandreas.hansson@arm.com#   reading .ini files from Python proves to be useful
7210458Sandreas.hansson@arm.com
7310458Sandreas.hansson@arm.comdef no_parser(cls, flags, param):
7410458Sandreas.hansson@arm.com    raise Exception('Can\'t parse string: %s for parameter'
7510458Sandreas.hansson@arm.com        ' class: %s' % (str(param), cls.__name__))
7610458Sandreas.hansson@arm.com
7710458Sandreas.hansson@arm.comdef simple_parser(suffix='', cast=lambda i: i):
7810458Sandreas.hansson@arm.com    def body(cls, flags, param):
7910458Sandreas.hansson@arm.com        return cls(cast(param + suffix))
8010458Sandreas.hansson@arm.com    return body
8110458Sandreas.hansson@arm.com
8210458Sandreas.hansson@arm.com# def tick_parser(cast=m5.objects.Latency): # lambda i: i):
8310458Sandreas.hansson@arm.comdef tick_parser(cast=lambda i: i):
8410458Sandreas.hansson@arm.com    def body(cls, flags, param):
8510458Sandreas.hansson@arm.com        old_param = param
8610458Sandreas.hansson@arm.com        ret = cls(cast(str(param) + 't'))
8710458Sandreas.hansson@arm.com        return ret
8810458Sandreas.hansson@arm.com    return body
8910458Sandreas.hansson@arm.com
9010458Sandreas.hansson@arm.comdef addr_range_parser(cls, flags, param):
9110458Sandreas.hansson@arm.com    sys.stdout.flush()
9214051Snikos.nikoleris@arm.com    _param = param.split(':')
9314051Snikos.nikoleris@arm.com    (start, end) = _param[0:2]
9414051Snikos.nikoleris@arm.com    if len(_param) == 2:
9514051Snikos.nikoleris@arm.com        return m5.objects.AddrRange(start=long(start), end=long(end))
9614051Snikos.nikoleris@arm.com    else:
9714051Snikos.nikoleris@arm.com        assert len(_param) > 2
9814051Snikos.nikoleris@arm.com        intlv_match = _param[2]
9914051Snikos.nikoleris@arm.com        masks = [ long(m) for m in _param[3:] ]
10014051Snikos.nikoleris@arm.com        return m5.objects.AddrRange(start=long(start), end=long(end),
10114051Snikos.nikoleris@arm.com                                    masks=masks, intlvMatch=long(intlv_match))
10214051Snikos.nikoleris@arm.com
10310458Sandreas.hansson@arm.com
10410458Sandreas.hansson@arm.comdef memory_bandwidth_parser(cls, flags, param):
10510458Sandreas.hansson@arm.com    # The string will be in tick/byte
10610458Sandreas.hansson@arm.com    # Convert to byte/tick
10710458Sandreas.hansson@arm.com    value = 1.0 / float(param)
10810458Sandreas.hansson@arm.com    # Convert to byte/s
10910458Sandreas.hansson@arm.com    value = ticks.fromSeconds(value)
11010458Sandreas.hansson@arm.com    return cls('%fB/s' % value)
11110458Sandreas.hansson@arm.com
11210458Sandreas.hansson@arm.com# These parameters have trickier parsing from .ini files than might be
11310458Sandreas.hansson@arm.com#   expected
11410458Sandreas.hansson@arm.comparam_parsers = {
11510458Sandreas.hansson@arm.com    'Bool': simple_parser(),
11610458Sandreas.hansson@arm.com    'ParamValue': no_parser,
11710458Sandreas.hansson@arm.com    'NumericParamValue': simple_parser(cast=long),
11810458Sandreas.hansson@arm.com    'TickParamValue': tick_parser(),
11910458Sandreas.hansson@arm.com    'Frequency': tick_parser(cast=m5.objects.Latency),
12011228SAndrew.Bardsley@arm.com    'Current': simple_parser(suffix='A'),
12110458Sandreas.hansson@arm.com    'Voltage': simple_parser(suffix='V'),
12210458Sandreas.hansson@arm.com    'Enum': simple_parser(),
12310458Sandreas.hansson@arm.com    'MemorySize': simple_parser(suffix='B'),
12410458Sandreas.hansson@arm.com    'MemorySize32': simple_parser(suffix='B'),
12510458Sandreas.hansson@arm.com    'AddrRange': addr_range_parser,
12610458Sandreas.hansson@arm.com    'String': simple_parser(),
12710458Sandreas.hansson@arm.com    'MemoryBandwidth': memory_bandwidth_parser,
12811228SAndrew.Bardsley@arm.com    'Time': simple_parser(),
12911228SAndrew.Bardsley@arm.com    'EthernetAddr': simple_parser()
13010458Sandreas.hansson@arm.com    }
13110458Sandreas.hansson@arm.com
13214050Snikos.nikoleris@arm.comfor name, parser in param_parsers.items():
13310458Sandreas.hansson@arm.com    setattr(m5.params.__dict__[name], 'parse_ini', classmethod(parser))
13410458Sandreas.hansson@arm.com
13510458Sandreas.hansson@arm.comclass PortConnection(object):
13610458Sandreas.hansson@arm.com    """This class is similar to m5.params.PortRef but with just enough
13710458Sandreas.hansson@arm.com    information for ConfigManager"""
13810458Sandreas.hansson@arm.com
13910458Sandreas.hansson@arm.com    def __init__(self, object_name, port_name, index):
14010458Sandreas.hansson@arm.com        self.object_name = object_name
14110458Sandreas.hansson@arm.com        self.port_name = port_name
14210458Sandreas.hansson@arm.com        self.index = index
14310458Sandreas.hansson@arm.com
14410458Sandreas.hansson@arm.com    @classmethod
14510458Sandreas.hansson@arm.com    def from_string(cls, str):
14610458Sandreas.hansson@arm.com        m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', str)
14710458Sandreas.hansson@arm.com        object_name, port_name, whole_index, index = m.groups()
14810458Sandreas.hansson@arm.com        if index is not None:
14910458Sandreas.hansson@arm.com            index = int(index)
15010458Sandreas.hansson@arm.com        else:
15110458Sandreas.hansson@arm.com            index = 0
15210458Sandreas.hansson@arm.com
15310458Sandreas.hansson@arm.com        return PortConnection(object_name, port_name, index)
15410458Sandreas.hansson@arm.com
15510458Sandreas.hansson@arm.com    def __str__(self):
15610458Sandreas.hansson@arm.com        return '%s.%s[%d]' % (self.object_name, self.port_name, self.index)
15710458Sandreas.hansson@arm.com
15810458Sandreas.hansson@arm.com    def __cmp__(self, right):
15910458Sandreas.hansson@arm.com        return cmp((self.object_name, self.port_name, self.index),
16010458Sandreas.hansson@arm.com            (right.object_name, right.port_name, right.index))
16110458Sandreas.hansson@arm.com
16210458Sandreas.hansson@arm.comdef to_list(v):
16310458Sandreas.hansson@arm.com    """Convert any non list to a singleton list"""
16410458Sandreas.hansson@arm.com    if isinstance(v, list):
16510458Sandreas.hansson@arm.com        return v
16610458Sandreas.hansson@arm.com    else:
16710458Sandreas.hansson@arm.com        return [v]
16810458Sandreas.hansson@arm.com
16910458Sandreas.hansson@arm.comclass ConfigManager(object):
17010458Sandreas.hansson@arm.com    """Manager for parsing a Root configuration from a config file"""
17110458Sandreas.hansson@arm.com    def __init__(self, config):
17210458Sandreas.hansson@arm.com        self.config = config
17310458Sandreas.hansson@arm.com        self.objects_by_name = {}
17410458Sandreas.hansson@arm.com        self.flags = config.get_flags()
17510458Sandreas.hansson@arm.com
17610458Sandreas.hansson@arm.com    def find_object(self, object_name):
17710458Sandreas.hansson@arm.com        """Find and configure (with just non-SimObject parameters)
17810458Sandreas.hansson@arm.com        a single object"""
17910458Sandreas.hansson@arm.com
18010458Sandreas.hansson@arm.com        if object_name == 'Null':
18110458Sandreas.hansson@arm.com            return NULL
18210458Sandreas.hansson@arm.com
18310458Sandreas.hansson@arm.com        if object_name in self.objects_by_name:
18410458Sandreas.hansson@arm.com            return self.objects_by_name[object_name]
18510458Sandreas.hansson@arm.com
18610458Sandreas.hansson@arm.com        object_type = self.config.get_param(object_name, 'type')
18710458Sandreas.hansson@arm.com
18810458Sandreas.hansson@arm.com        if object_type not in sim_object_classes_by_name:
18910458Sandreas.hansson@arm.com            raise Exception('No SimObject type %s is available to'
19010458Sandreas.hansson@arm.com                ' build: %s' % (object_type, object_name))
19110458Sandreas.hansson@arm.com
19210458Sandreas.hansson@arm.com        object_class = sim_object_classes_by_name[object_type]
19310458Sandreas.hansson@arm.com
19410458Sandreas.hansson@arm.com        parsed_params = {}
19510458Sandreas.hansson@arm.com
19614050Snikos.nikoleris@arm.com        for param_name, param in object_class._params.items():
19710458Sandreas.hansson@arm.com            if issubclass(param.ptype, m5.params.ParamValue):
19810458Sandreas.hansson@arm.com                if isinstance(param, m5.params.VectorParamDesc):
19910458Sandreas.hansson@arm.com                    param_values = self.config.get_param_vector(object_name,
20010458Sandreas.hansson@arm.com                        param_name)
20110458Sandreas.hansson@arm.com
20210458Sandreas.hansson@arm.com                    param_value = [ param.ptype.parse_ini(self.flags, value)
20310458Sandreas.hansson@arm.com                        for value in param_values ]
20410458Sandreas.hansson@arm.com                else:
20510458Sandreas.hansson@arm.com                    param_value = param.ptype.parse_ini(
20610458Sandreas.hansson@arm.com                        self.flags, self.config.get_param(object_name,
20710458Sandreas.hansson@arm.com                        param_name))
20810458Sandreas.hansson@arm.com
20910458Sandreas.hansson@arm.com                parsed_params[param_name] = param_value
21010458Sandreas.hansson@arm.com
21110458Sandreas.hansson@arm.com        obj = object_class(**parsed_params)
21210458Sandreas.hansson@arm.com        self.objects_by_name[object_name] = obj
21310458Sandreas.hansson@arm.com
21410458Sandreas.hansson@arm.com        return obj
21510458Sandreas.hansson@arm.com
21610458Sandreas.hansson@arm.com    def fill_in_simobj_parameters(self, object_name, obj):
21710458Sandreas.hansson@arm.com        """Fill in all references to other SimObjects in an objects
21810458Sandreas.hansson@arm.com        parameters.  This relies on all referenced objects having been
21910458Sandreas.hansson@arm.com        created"""
22010458Sandreas.hansson@arm.com
22110458Sandreas.hansson@arm.com        if object_name == 'Null':
22210458Sandreas.hansson@arm.com            return NULL
22310458Sandreas.hansson@arm.com
22414050Snikos.nikoleris@arm.com        for param_name, param in obj.__class__._params.items():
22510458Sandreas.hansson@arm.com            if issubclass(param.ptype, m5.objects.SimObject):
22610458Sandreas.hansson@arm.com                if isinstance(param, m5.params.VectorParamDesc):
22710458Sandreas.hansson@arm.com                    param_values = self.config.get_param_vector(object_name,
22810458Sandreas.hansson@arm.com                        param_name)
22910458Sandreas.hansson@arm.com
23012411Sgabeblack@google.com                    setattr(obj, param_name,
23112411Sgabeblack@google.com                            [ self.objects_by_name[name]
23212411Sgabeblack@google.com                                  if name != 'Null' else m5.params.NULL
23312411Sgabeblack@google.com                              for name in param_values ])
23410458Sandreas.hansson@arm.com                else:
23510458Sandreas.hansson@arm.com                    param_value = self.config.get_param(object_name,
23610458Sandreas.hansson@arm.com                        param_name)
23710458Sandreas.hansson@arm.com
23810458Sandreas.hansson@arm.com                    if param_value != 'Null':
23910458Sandreas.hansson@arm.com                        setattr(obj, param_name, self.objects_by_name[
24010458Sandreas.hansson@arm.com                            param_value])
24110458Sandreas.hansson@arm.com
24210458Sandreas.hansson@arm.com        return obj
24310458Sandreas.hansson@arm.com
24410458Sandreas.hansson@arm.com    def fill_in_children(self, object_name, obj):
24510458Sandreas.hansson@arm.com        """Fill in the children of this object.  This relies on all the
24610458Sandreas.hansson@arm.com        referenced objects having been created"""
24710458Sandreas.hansson@arm.com
24810458Sandreas.hansson@arm.com        children = self.config.get_object_children(object_name)
24910458Sandreas.hansson@arm.com
25010458Sandreas.hansson@arm.com        for child_name, child_paths in children:
25110458Sandreas.hansson@arm.com            param = obj.__class__._params.get(child_name, None)
25212411Sgabeblack@google.com            if child_name == 'Null':
25312411Sgabeblack@google.com                continue
25410458Sandreas.hansson@arm.com
25510458Sandreas.hansson@arm.com            if isinstance(child_paths, list):
25610458Sandreas.hansson@arm.com                child_list = [ self.objects_by_name[path]
25710458Sandreas.hansson@arm.com                    for path in child_paths ]
25810458Sandreas.hansson@arm.com            else:
25910458Sandreas.hansson@arm.com                child_list = self.objects_by_name[child_paths]
26010458Sandreas.hansson@arm.com
26110458Sandreas.hansson@arm.com            obj.add_child(child_name, child_list)
26210458Sandreas.hansson@arm.com
26310458Sandreas.hansson@arm.com            for path in to_list(child_paths):
26410458Sandreas.hansson@arm.com                self.fill_in_children(path, self.objects_by_name[path])
26510458Sandreas.hansson@arm.com
26610458Sandreas.hansson@arm.com        return obj
26710458Sandreas.hansson@arm.com
26810458Sandreas.hansson@arm.com    def parse_port_name(self, port):
26910458Sandreas.hansson@arm.com        """Parse the name of a port"""
27010458Sandreas.hansson@arm.com
27110458Sandreas.hansson@arm.com        m = re.match('(.*)\.([^.\[]+)(\[(\d+)\])?', port)
27210458Sandreas.hansson@arm.com        peer, peer_port, whole_index, index = m.groups()
27310458Sandreas.hansson@arm.com        if index is not None:
27410458Sandreas.hansson@arm.com            index = int(index)
27510458Sandreas.hansson@arm.com        else:
27610458Sandreas.hansson@arm.com            index = 0
27710458Sandreas.hansson@arm.com
27810458Sandreas.hansson@arm.com        return (peer, self.objects_by_name[peer], peer_port, index)
27910458Sandreas.hansson@arm.com
28010458Sandreas.hansson@arm.com    def gather_port_connections(self, object_name, obj):
28110458Sandreas.hansson@arm.com        """Gather all the port-to-port connections from the named object.
28210458Sandreas.hansson@arm.com        Returns a list of (PortConnection, PortConnection) with unordered
28310458Sandreas.hansson@arm.com        (wrt. master/slave) connection information"""
28410458Sandreas.hansson@arm.com
28510458Sandreas.hansson@arm.com        if object_name == 'Null':
28610458Sandreas.hansson@arm.com            return NULL
28710458Sandreas.hansson@arm.com
28810458Sandreas.hansson@arm.com        parsed_ports = []
28914050Snikos.nikoleris@arm.com        for port_name, port in obj.__class__._ports.items():
29010458Sandreas.hansson@arm.com            # Assume that unnamed ports are unconnected
29110458Sandreas.hansson@arm.com            peers = self.config.get_port_peers(object_name, port_name)
29210458Sandreas.hansson@arm.com
29313731Sandreas.sandberg@arm.com            for index, peer in zip(range(0, len(peers)), peers):
29410458Sandreas.hansson@arm.com                parsed_ports.append((
29510458Sandreas.hansson@arm.com                    PortConnection(object_name, port.name, index),
29610458Sandreas.hansson@arm.com                    PortConnection.from_string(peer)))
29710458Sandreas.hansson@arm.com
29810458Sandreas.hansson@arm.com        return parsed_ports
29910458Sandreas.hansson@arm.com
30010458Sandreas.hansson@arm.com    def bind_ports(self, connections):
30110458Sandreas.hansson@arm.com        """Bind all ports from the given connection list.  Note that the
30210458Sandreas.hansson@arm.com        connection list *must* list all connections with both (slave,master)
30310458Sandreas.hansson@arm.com        and (master,slave) orderings"""
30410458Sandreas.hansson@arm.com
30510458Sandreas.hansson@arm.com        # Markup a dict of how many connections are made to each port.
30610458Sandreas.hansson@arm.com        #   This will be used to check that the next-to-be-made connection
30710458Sandreas.hansson@arm.com        #   has a suitable port index
30810458Sandreas.hansson@arm.com        port_bind_indices = {}
30910458Sandreas.hansson@arm.com        for from_port, to_port in connections:
31010458Sandreas.hansson@arm.com            port_bind_indices[
31110458Sandreas.hansson@arm.com                (from_port.object_name, from_port.port_name)] = 0
31210458Sandreas.hansson@arm.com
31310458Sandreas.hansson@arm.com        def port_has_correct_index(port):
31410458Sandreas.hansson@arm.com            return port_bind_indices[
31510458Sandreas.hansson@arm.com                (port.object_name, port.port_name)] == port.index
31610458Sandreas.hansson@arm.com
31710458Sandreas.hansson@arm.com        def increment_port_index(port):
31810458Sandreas.hansson@arm.com            port_bind_indices[
31910458Sandreas.hansson@arm.com                (port.object_name, port.port_name)] += 1
32010458Sandreas.hansson@arm.com
32110458Sandreas.hansson@arm.com        # Step through the sorted connections.  Exactly one of
32210458Sandreas.hansson@arm.com        #   each (slave,master) and (master,slave) pairs will be
32310458Sandreas.hansson@arm.com        #   bindable because the connections are sorted.
32410458Sandreas.hansson@arm.com        # For example:        port_bind_indices
32510458Sandreas.hansson@arm.com        #   left      right   left right
32610458Sandreas.hansson@arm.com        #   a.b[0] -> d.f[1]  0    0 X
32710458Sandreas.hansson@arm.com        #   a.b[1] -> e.g     0    0    BIND!
32810458Sandreas.hansson@arm.com        #   e.g -> a.b[1]     1 X  0
32910458Sandreas.hansson@arm.com        #   d.f[0] -> f.h     0    0    BIND!
33010458Sandreas.hansson@arm.com        #   d.f[1] -> a.b[0]  1    0    BIND!
33110458Sandreas.hansson@arm.com        connections_to_make = []
33210458Sandreas.hansson@arm.com        for connection in sorted(connections):
33310458Sandreas.hansson@arm.com            from_port, to_port = connection
33410458Sandreas.hansson@arm.com
33510458Sandreas.hansson@arm.com            if (port_has_correct_index(from_port) and
33610458Sandreas.hansson@arm.com                port_has_correct_index(to_port)):
33710458Sandreas.hansson@arm.com
33810458Sandreas.hansson@arm.com                connections_to_make.append((from_port, to_port))
33910458Sandreas.hansson@arm.com
34010458Sandreas.hansson@arm.com                increment_port_index(from_port)
34110458Sandreas.hansson@arm.com                increment_port_index(to_port)
34210458Sandreas.hansson@arm.com
34310458Sandreas.hansson@arm.com        # Exactly half of the connections (ie. all of them, one per
34410458Sandreas.hansson@arm.com        #   direction) must now have been made
34510458Sandreas.hansson@arm.com        if (len(connections_to_make) * 2) != len(connections):
34610458Sandreas.hansson@arm.com            raise Exception('Port bindings can\'t be ordered')
34710458Sandreas.hansson@arm.com
34810458Sandreas.hansson@arm.com        # Actually do the binding
34910458Sandreas.hansson@arm.com        for from_port, to_port in connections_to_make:
35010458Sandreas.hansson@arm.com            from_object = self.objects_by_name[from_port.object_name]
35110458Sandreas.hansson@arm.com            to_object = self.objects_by_name[to_port.object_name]
35210458Sandreas.hansson@arm.com
35310458Sandreas.hansson@arm.com            setattr(from_object, from_port.port_name,
35410458Sandreas.hansson@arm.com                getattr(to_object, to_port.port_name))
35510458Sandreas.hansson@arm.com
35610458Sandreas.hansson@arm.com    def find_all_objects(self):
35710458Sandreas.hansson@arm.com        """Find and build all SimObjects from the config file and connect
35810458Sandreas.hansson@arm.com        their ports together as described.  Does not instantiate system"""
35910458Sandreas.hansson@arm.com
36010458Sandreas.hansson@arm.com        # Build SimObjects for all sections of the config file
36110458Sandreas.hansson@arm.com        #   populating not-SimObject-valued parameters
36210458Sandreas.hansson@arm.com        for object_name in self.config.get_all_object_names():
36310458Sandreas.hansson@arm.com            self.find_object(object_name)
36410458Sandreas.hansson@arm.com
36510458Sandreas.hansson@arm.com        # Add children to objects in the hierarchy from root
36610458Sandreas.hansson@arm.com        self.fill_in_children('root', self.find_object('root'))
36710458Sandreas.hansson@arm.com
36810458Sandreas.hansson@arm.com        # Now fill in SimObject-valued parameters in the knowledge that
36910458Sandreas.hansson@arm.com        #   this won't be interpreted as becoming the parent of objects
37010458Sandreas.hansson@arm.com        #   which are already in the root hierarchy
37114050Snikos.nikoleris@arm.com        for name, obj in self.objects_by_name.items():
37210458Sandreas.hansson@arm.com            self.fill_in_simobj_parameters(name, obj)
37310458Sandreas.hansson@arm.com
37410458Sandreas.hansson@arm.com        # Gather a list of all port-to-port connections
37510458Sandreas.hansson@arm.com        connections = []
37614050Snikos.nikoleris@arm.com        for name, obj in self.objects_by_name.items():
37710458Sandreas.hansson@arm.com            connections += self.gather_port_connections(name, obj)
37810458Sandreas.hansson@arm.com
37910458Sandreas.hansson@arm.com        # Find an acceptable order to bind those port connections and
38010458Sandreas.hansson@arm.com        #   bind them
38110458Sandreas.hansson@arm.com        self.bind_ports(connections)
38210458Sandreas.hansson@arm.com
38310458Sandreas.hansson@arm.comclass ConfigFile(object):
38410458Sandreas.hansson@arm.com    def get_flags(self):
38510458Sandreas.hansson@arm.com        return set()
38610458Sandreas.hansson@arm.com
38710458Sandreas.hansson@arm.com    def load(self, config_file):
38810458Sandreas.hansson@arm.com        """Load the named config file"""
38910458Sandreas.hansson@arm.com        pass
39010458Sandreas.hansson@arm.com
39110458Sandreas.hansson@arm.com    def get_all_object_names(self):
39210458Sandreas.hansson@arm.com        """Get a list of all the SimObject paths in the configuration"""
39310458Sandreas.hansson@arm.com        pass
39410458Sandreas.hansson@arm.com
39510458Sandreas.hansson@arm.com    def get_param(self, object_name, param_name):
39610458Sandreas.hansson@arm.com        """Get a single param or SimObject reference from the configuration
39710458Sandreas.hansson@arm.com        as a string"""
39810458Sandreas.hansson@arm.com        pass
39910458Sandreas.hansson@arm.com
40010458Sandreas.hansson@arm.com    def get_param_vector(self, object_name, param_name):
40110458Sandreas.hansson@arm.com        """Get a vector param or vector of SimObject references from the
40210458Sandreas.hansson@arm.com        configuration as a list of strings"""
40310458Sandreas.hansson@arm.com        pass
40410458Sandreas.hansson@arm.com
40510458Sandreas.hansson@arm.com    def get_object_children(self, object_name):
40610458Sandreas.hansson@arm.com        """Get a list of (name, paths) for each child of this object.
40710458Sandreas.hansson@arm.com        paths is either a single string object path or a list of object
40810458Sandreas.hansson@arm.com        paths"""
40910458Sandreas.hansson@arm.com        pass
41010458Sandreas.hansson@arm.com
41110458Sandreas.hansson@arm.com    def get_port_peers(self, object_name, port_name):
41210458Sandreas.hansson@arm.com        """Get the list of connected port names (in the string form
41310458Sandreas.hansson@arm.com        object.port(\[index\])?) of the port object_name.port_name"""
41410458Sandreas.hansson@arm.com        pass
41510458Sandreas.hansson@arm.com
41610458Sandreas.hansson@arm.comclass ConfigIniFile(ConfigFile):
41710458Sandreas.hansson@arm.com    def __init__(self):
41810458Sandreas.hansson@arm.com        self.parser = ConfigParser.ConfigParser()
41910458Sandreas.hansson@arm.com
42010458Sandreas.hansson@arm.com    def load(self, config_file):
42110458Sandreas.hansson@arm.com        self.parser.read(config_file)
42210458Sandreas.hansson@arm.com
42310458Sandreas.hansson@arm.com    def get_all_object_names(self):
42410458Sandreas.hansson@arm.com        return self.parser.sections()
42510458Sandreas.hansson@arm.com
42610458Sandreas.hansson@arm.com    def get_param(self, object_name, param_name):
42710458Sandreas.hansson@arm.com        return self.parser.get(object_name, param_name)
42810458Sandreas.hansson@arm.com
42910458Sandreas.hansson@arm.com    def get_param_vector(self, object_name, param_name):
43010458Sandreas.hansson@arm.com        return self.parser.get(object_name, param_name).split()
43110458Sandreas.hansson@arm.com
43210458Sandreas.hansson@arm.com    def get_object_children(self, object_name):
43310458Sandreas.hansson@arm.com        if self.parser.has_option(object_name, 'children'):
43410458Sandreas.hansson@arm.com            children = self.parser.get(object_name, 'children')
43510458Sandreas.hansson@arm.com            child_names = children.split()
43610458Sandreas.hansson@arm.com        else:
43710458Sandreas.hansson@arm.com            child_names = []
43810458Sandreas.hansson@arm.com
43910458Sandreas.hansson@arm.com        def make_path(child_name):
44010458Sandreas.hansson@arm.com            if object_name == 'root':
44110458Sandreas.hansson@arm.com                return child_name
44210458Sandreas.hansson@arm.com            else:
44310458Sandreas.hansson@arm.com                return '%s.%s' % (object_name, child_name)
44410458Sandreas.hansson@arm.com
44510458Sandreas.hansson@arm.com        return [ (name, make_path(name)) for name in child_names ]
44610458Sandreas.hansson@arm.com
44710458Sandreas.hansson@arm.com    def get_port_peers(self, object_name, port_name):
44810458Sandreas.hansson@arm.com        if self.parser.has_option(object_name, port_name):
44910458Sandreas.hansson@arm.com            peer_string = self.parser.get(object_name, port_name)
45010458Sandreas.hansson@arm.com            return peer_string.split()
45110458Sandreas.hansson@arm.com        else:
45210458Sandreas.hansson@arm.com            return []
45310458Sandreas.hansson@arm.com
45410458Sandreas.hansson@arm.comclass ConfigJsonFile(ConfigFile):
45510458Sandreas.hansson@arm.com    def __init__(self):
45610458Sandreas.hansson@arm.com        pass
45710458Sandreas.hansson@arm.com
45810458Sandreas.hansson@arm.com    def is_sim_object(self, node):
45910458Sandreas.hansson@arm.com        return isinstance(node, dict) and 'path' in node
46010458Sandreas.hansson@arm.com
46110458Sandreas.hansson@arm.com    def find_all_objects(self, node):
46210458Sandreas.hansson@arm.com        if self.is_sim_object(node):
46310458Sandreas.hansson@arm.com            self.object_dicts[node['path']] = node
46410458Sandreas.hansson@arm.com
46510458Sandreas.hansson@arm.com        if isinstance(node, list):
46610458Sandreas.hansson@arm.com            for elem in node:
46710458Sandreas.hansson@arm.com                self.find_all_objects(elem)
46810458Sandreas.hansson@arm.com        elif isinstance(node, dict):
46914050Snikos.nikoleris@arm.com            for elem in node.values():
47010458Sandreas.hansson@arm.com                self.find_all_objects(elem)
47110458Sandreas.hansson@arm.com
47210458Sandreas.hansson@arm.com    def load(self, config_file):
47310458Sandreas.hansson@arm.com        root = json.load(open(config_file, 'r'))
47410458Sandreas.hansson@arm.com        self.object_dicts = {}
47510458Sandreas.hansson@arm.com        self.find_all_objects(root)
47610458Sandreas.hansson@arm.com
47710458Sandreas.hansson@arm.com    def get_all_object_names(self):
47810458Sandreas.hansson@arm.com        return sorted(self.object_dicts.keys())
47910458Sandreas.hansson@arm.com
48010458Sandreas.hansson@arm.com    def parse_param_string(self, node):
48110458Sandreas.hansson@arm.com        if node is None:
48210458Sandreas.hansson@arm.com            return "Null"
48310458Sandreas.hansson@arm.com        elif self.is_sim_object(node):
48410458Sandreas.hansson@arm.com            return node['path']
48510458Sandreas.hansson@arm.com        else:
48610458Sandreas.hansson@arm.com            return str(node)
48710458Sandreas.hansson@arm.com
48810458Sandreas.hansson@arm.com    def get_param(self, object_name, param_name):
48910458Sandreas.hansson@arm.com        obj = self.object_dicts[object_name]
49010458Sandreas.hansson@arm.com
49110458Sandreas.hansson@arm.com        return self.parse_param_string(obj[param_name])
49210458Sandreas.hansson@arm.com
49310458Sandreas.hansson@arm.com    def get_param_vector(self, object_name, param_name):
49410458Sandreas.hansson@arm.com        obj = self.object_dicts[object_name]
49510458Sandreas.hansson@arm.com
49610458Sandreas.hansson@arm.com        return [ self.parse_param_string(p) for p in obj[param_name] ]
49710458Sandreas.hansson@arm.com
49810458Sandreas.hansson@arm.com    def get_object_children(self, object_name):
49910458Sandreas.hansson@arm.com        """It is difficult to tell which elements are children in the
50010458Sandreas.hansson@arm.com        JSON file as there is no explicit 'children' node.  Take any
50110458Sandreas.hansson@arm.com        element which is a full SimObject description or a list of
50210458Sandreas.hansson@arm.com        SimObject descriptions.  This will not work with a mixed list of
50310458Sandreas.hansson@arm.com        references and descriptions but that's a scenario that isn't
50410458Sandreas.hansson@arm.com        possible (very likely?) with gem5's binding/naming rules"""
50510458Sandreas.hansson@arm.com        obj = self.object_dicts[object_name]
50610458Sandreas.hansson@arm.com
50710458Sandreas.hansson@arm.com        children = []
50814050Snikos.nikoleris@arm.com        for name, node in obj.items():
50910458Sandreas.hansson@arm.com            if self.is_sim_object(node):
51010458Sandreas.hansson@arm.com                children.append((name, node['path']))
51110458Sandreas.hansson@arm.com            elif isinstance(node, list) and node != [] and all([
51210458Sandreas.hansson@arm.com                self.is_sim_object(e) for e in node ]):
51310458Sandreas.hansson@arm.com                children.append((name, [ e['path'] for e in node ]))
51410458Sandreas.hansson@arm.com
51510458Sandreas.hansson@arm.com        return children
51610458Sandreas.hansson@arm.com
51710458Sandreas.hansson@arm.com    def get_port_peers(self, object_name, port_name):
51810458Sandreas.hansson@arm.com        """Get the 'peer' element of any node with 'peer' and 'role'
51910458Sandreas.hansson@arm.com        elements"""
52010458Sandreas.hansson@arm.com        obj = self.object_dicts[object_name]
52110458Sandreas.hansson@arm.com
52210458Sandreas.hansson@arm.com        peers = []
52310458Sandreas.hansson@arm.com        if port_name in obj and 'peer' in obj[port_name] and \
52410458Sandreas.hansson@arm.com            'role' in obj[port_name]:
52510458Sandreas.hansson@arm.com            peers = to_list(obj[port_name]['peer'])
52610458Sandreas.hansson@arm.com
52710458Sandreas.hansson@arm.com        return peers
52810458Sandreas.hansson@arm.com
52910458Sandreas.hansson@arm.comparser = argparse.ArgumentParser()
53010458Sandreas.hansson@arm.com
53110458Sandreas.hansson@arm.comparser.add_argument('config_file', metavar='config-file.ini',
53210458Sandreas.hansson@arm.com    help='.ini configuration file to load and run')
53312409Sgabeblack@google.comparser.add_argument('--checkpoint-dir', type=str, default=None,
53412409Sgabeblack@google.com                    help='A checkpoint to directory to restore when starting '
53512409Sgabeblack@google.com                         'the simulation')
53610458Sandreas.hansson@arm.com
53710458Sandreas.hansson@arm.comargs = parser.parse_args(sys.argv[1:])
53810458Sandreas.hansson@arm.com
53910458Sandreas.hansson@arm.comif args.config_file.endswith('.ini'):
54010458Sandreas.hansson@arm.com    config = ConfigIniFile()
54110458Sandreas.hansson@arm.com    config.load(args.config_file)
54210458Sandreas.hansson@arm.comelse:
54310458Sandreas.hansson@arm.com    config = ConfigJsonFile()
54410458Sandreas.hansson@arm.com    config.load(args.config_file)
54510458Sandreas.hansson@arm.com
54610458Sandreas.hansson@arm.comticks.fixGlobalFrequency()
54710458Sandreas.hansson@arm.com
54810458Sandreas.hansson@arm.commgr = ConfigManager(config)
54910458Sandreas.hansson@arm.com
55010458Sandreas.hansson@arm.commgr.find_all_objects()
55110458Sandreas.hansson@arm.com
55212409Sgabeblack@google.comm5.instantiate(args.checkpoint_dir)
55310458Sandreas.hansson@arm.com
55410458Sandreas.hansson@arm.comexit_event = m5.simulate()
55512564Sgabeblack@google.comprint('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))
556