# Copyright (c) 2014,2019 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 list(m5.objects.__dict__.values())
    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()
    _param = param.split(':')
    (start, end) = _param[0:2]
    if len(_param) == 2:
        return m5.objects.AddrRange(start=int(start), end=int(end))
    else:
        assert len(_param) > 2
        intlv_match = _param[2]
        masks = [ int(m) for m in _param[3:] ]
        return m5.objects.AddrRange(start=int(start), end=int(end),
                                    masks=masks, intlvMatch=int(intlv_match))


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=int),
    'TickParamValue': tick_parser(),
    'Frequency': tick_parser(cast=m5.objects.Latency),
    'Current': simple_parser(suffix='A'),
    '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(),
    'EthernetAddr': simple_parser()
    }

for name, parser in list(param_parsers.items()):
    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 list(object_class._params.items()):
            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 list(obj.__class__._params.items()):
            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]
                                  if name != 'Null' else m5.params.NULL
                              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 child_name == 'Null':
                continue

            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 list(obj.__class__._ports.items()):
            # Assume that unnamed ports are unconnected
            peers = self.config.get_port_peers(object_name, port_name)

            for index, peer in zip(list(range(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 list(self.objects_by_name.items()):
            self.fill_in_simobj_parameters(name, obj)

        # Gather a list of all port-to-port connections
        connections = []
        for name, obj in list(self.objects_by_name.items()):
            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 list(node.values()):
                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 list(obj.items()):
            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')
parser.add_argument('--checkpoint-dir', type=str, default=None,
                    help='A checkpoint to directory to restore when starting '
                         'the simulation')

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(args.checkpoint_dir)

exit_event = m5.simulate()
print('Exiting @ tick %i because %s' % (m5.curTick(), exit_event.getCause()))
