# 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.

from __future__ import print_function
from __future__ import absolute_import

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, intlv_high_bit, xor_high_bit,
     intlv_bits, intlv_match) = param.split(':')
    return m5.objects.AddrRange(
        start=long(low), end=long(high),
        intlvHighBit=long(intlv_high_bit), xorHighBit=long(xor_high_bit),
        intlvBits=long(intlv_bits), intlvMatch=long(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=long),
    '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 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]
                                  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 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(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 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')
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()))
