# Copyright (c) 2020 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.
#
# Copyright 2019 Google, Inc.
#
# 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.

from itertools import cycle
import shlex

Import('*')

from m5.util.grammar import Grammar

from gem5_scons import Transform, warning, error

import os.path

if env['USE_ARM_FASTMODEL']:
    if not env['USE_SYSTEMC']:
        warning('ARM Fast Models require systemc support')
        env['USE_ARM_FASTMODEL'] = False
        Return()

if not env['USE_ARM_FASTMODEL']:
    Return()


systemc_home = Dir('#/src/systemc/ext/systemc_home')
env['ENV']['SYSTEMC_HOME'] = systemc_home.abspath

def extract_var(name):
    if name not in env:
        error('Error: %s is not set' % name)
    print('%s = %s' % (name, env[name]))
    # Make sure the value of this variable shows up as an environment variable
    # for commands scons runs.
    env['ENV'][name] = env[name]
    return env[name]

pvlib_home, maxcore_home, armlmd_license_file = \
    list(map(extract_var, ('PVLIB_HOME', 'MAXCORE_HOME',
                           'ARMLMD_LICENSE_FILE')))

pvlib_home = Dir(pvlib_home)
maxcore_home = Dir(maxcore_home)
armlmd_license_file = File(armlmd_license_file)


pvlib_flavor = env['PVLIB_FLAVOR']
pvlib_lib_dir = pvlib_home.Dir('lib').Dir(pvlib_flavor)

simulation_engine_name = 'libMAXCOREInitSimulationEngine.3.so'
simulation_engine_lib = pvlib_lib_dir.File(simulation_engine_name)


def staticify(env, name):
    ''' Check for a static version of the library named 'name', and if it
        exists return a File node for it explicitly. Otherwise pass 'name'
        through for normal processing.'''

    static_name = env.subst('${LIBPREFIX}' + name + '${LIBSUFFIX}')

    for path in env.Flatten(env['LIBPATH']):
        full_name = Dir(path).File(static_name).get_abspath()
        if os.path.isfile(full_name):
            return File(full_name)

    return name


# Adjust the build environment to support building in Fast Models.

env.Append(CCFLAGS='-pthread')

cpppaths = (
    pvlib_home.Dir('include/fmruntime'),
    pvlib_home.Dir('include/fmruntime/eslapi'),
    pvlib_home.Dir('Iris/include'),

    systemc_home.Dir('include'),

    maxcore_home.Dir('AMBA-PV/include'),
)
env.Append(CPPPATH=cpppaths)

lib_paths = (
    pvlib_lib_dir,
    pvlib_home.Dir('Iris').Dir(pvlib_flavor),
)
env.Append(LIBPATH=lib_paths)
env.Append(RPATH=lib_paths)

libs = (
    'components',
    'pvbus',
    'armctmodel',
    'fmruntime',
    'IrisSupport',
    'atomic',
    'dl',
    'rt',
)
env.Append(LIBS=list(staticify(env, lib) for lib in libs))


class ProjectFileParser(Grammar):
    class Param(object):
        def __init__(self, is_object):
            self.is_object = is_object

        def __str__(self):
            return self._to_str(0)

    class StringParam(Param):
        def __init__(self, name, value):
            super(ProjectFileParser.StringParam, self).__init__(
                    is_object=False)
            self.name = name
            self.value = value

        def _to_str(self, indent):
            indent_str = "    " * indent
            return indent_str + self.name + ' = \"' + self.value + '\"'

    class ObjectParam(Param):
        def __init__(self, type_name, name, params):
            super(ProjectFileParser.ObjectParam, self).__init__(
                    is_object=True)
            self.type_name = type_name
            self.name = name
            self.params = params

        def _to_str(self, indent):
            indent_str = "    " * indent
            val = indent_str + self.type_name
            if self.name is not None:
                val += ' "' + self.name + '"'
            val += "\n" + indent_str + "{\n"
            for param in self.params:
                val += param._to_str(indent + 1) + "\n"
            val += indent_str + "}"
            return val

    #########
    # Lexer #
    #########

    tokens = (
        # identifier
        'ID',

        # string literal
        'STRLIT',

        # = { } ;
        'EQUALS',
        'LBRACE',
        'RBRACE',
        'SEMI',
    )

    t_ID = r'[A-Za-z_]\w*'

    def t_STRLIT(self, t):
        r'(?m)"([^"])*"'
        # strip off quotes
        t.value = t.value[1:-1]
        t.lexer.lineno += t.value.count('\n')
        return t

    t_EQUALS = r'='
    t_LBRACE = r'\{'
    t_RBRACE = r'\}'
    t_SEMI = r';'

    def t_NEWLINE(self, t):
        r'\n+'
        t.lexer.lineno += t.value.count('\n')

    t_ignore = ' \t\x0c'

    ##########
    # Parser #
    ##########

    def p_object(self, t):
        'object : object_heading LBRACE params RBRACE'
        t[0] = self.ObjectParam(t[1][0], t[1][1], t[3])

    def p_object_heading_0(self, t):
        'object_heading : ID STRLIT'
        t[0] = (t[1], t[2])

    def p_object_heading_1(self, t):
        'object_heading : ID'
        t[0] = (t[1], None)

    def p_params_0(self, t):
        'params : '
        t[0] = []

    def p_params_1(self, t):
        'params : param params'
        t[0] = [t[1]] + t[2]

    def p_param_0(self, t):
        'param : ID EQUALS STRLIT SEMI'
        t[0] = self.StringParam(t[1], t[3])

    def p_param_1(self, t):
        'param : object'
        t[0] = t[1]


license_count = int(env['ARMLMD_LICENSE_COUNT'])
arm_licenses = list((Value(object()) for i in range(license_count)))
license_cycle = cycle(arm_licenses)

class ArmFastModelComponent(object):
    def __init__(self, project_file, *extra_deps):
        project_file = File(project_file)
        project_file_dir = project_file.Dir('.')

        parser = ProjectFileParser()
        proj = parser.parse_file(project_file.srcnode().abspath)

        # Top level component.
        tlc = None
        # Config name.
        config_name = None

        # Scan for particular properties of the project.
        for param in proj.params:
            if not param.is_object:
                if param.name == 'TOP_LEVEL_COMPONENT':
                    tlc = param.value
                elif param.name == 'ACTIVE_CONFIG_LINUX':
                    config_name = param.value

        assert tlc is not None and config_name is not None

        simgen_dir = project_file_dir.Dir(config_name)

        def simgen_static(name):
            return simgen_dir.File(env.subst(
                        '${LIBPREFIX}%s${LIBSUFFIX}' % name))

        def simgen_shared(name):
            return simgen_dir.File(env.subst(
                        '${SHLIBPREFIX}%s${SHLIBSUFFIX}' % name))

        static_libs = [
            'scx-%s-%s' % (tlc, config_name),
            'scx',
        ]
        shared_libs = [
            '%s-%s' % (tlc, config_name),
        ]

        static_lib_nodes = list(map(simgen_static, static_libs))
        shared_lib_nodes = list(map(simgen_shared, shared_libs))
        # We need to use the static libraries as files so that the linker
        # doesn't use the shared versions of them instead. We need to use
        # the shared libraries by name so that the linker will apply RPATH
        # and be able to find them at run time. If a shared libary includes
        # a path, the dynamic linker will apparently ignore RPATH when looking
        # for it.
        lib_nodes = static_lib_nodes + shared_lib_nodes

        gen_dir = simgen_dir.Dir('gen')

        header = gen_dir.File('scx_evs_%s.h' % tlc)

        self.headers = [header]
        self.headerpaths = [gen_dir]
        self.libs = static_lib_nodes + shared_libs
        self.libpaths = [simgen_dir]
        self.rpaths = [simgen_dir]
        self.log = gen_dir.File('build_%s.log' % tlc)
        self.simgen_cmd = env.subst('${SIMGEN} -p %s --configuration %s -b ' +
            '--verbose off --num-build-cpus 100 --build-dir %s >%s') % \
            (shlex.quote(project_file.srcnode().abspath),
             shlex.quote(config_name),
             shlex.quote(simgen_dir.abspath),
             shlex.quote(self.log.abspath))

        sources = [project_file]
        sources.extend(extra_deps)
        env.Command(lib_nodes + self.headers + [self.log], sources,
                    Action(self.simgen_builder, Transform('SIMGEN')))
        # Distribute simgen actions among ARM license slots. All actions which
        # have a given license as a "side effect" will be serialized relative
        # to each other, meaning the number of licenses being used concurrently
        # will never be larger than the number of license nodes.
        #
        # This allocation is fixed and may not be as optimal as a dynamic one,
        # but the difference is probably not significant.
        env.SideEffect(next(license_cycle), lib_nodes[0])

    def prepare_env(self, env):
        env.Append(LIBPATH=self.libpaths)
        env.AddLocalRPATH(*self.rpaths)
        env.Append(CPPPATH=self.headerpaths)
        env.Prepend(LIBS=self.libs)

    def simgen_builder(self, target, source, env):
        cmd = self.simgen_cmd
        if not GetOption('verbose'):
            cmd = "@" + cmd
        res = env.Execute(cmd)
        # Print output when execution return non-zero or in verbose mode.
        if res or GetOption('verbose'):
            env.Execute('@cat %s' % self.log.abspath)
        return res


class ArmFastModelBin(Executable):
    def __init__(self, target, *components_and_sources):
        def is_component(x):
            return isinstance(x, ArmFastModelComponent)

        def not_component(x):
            return not is_component(x)

        components = list(filter(is_component, components_and_sources))
        sources = list(filter(not_component, components_and_sources))

        self.components = components
        super(ArmFastModelBin, self).__init__(target, *sources)

    @classmethod
    def declare_all(cls, env):
        env = env.Clone()
        env.Prepend(LIBS=env['STATIC_LIB'][0])
        super(ArmFastModelBin, cls).declare_all(env)

    def declare(self, env):
        env = env.Clone()

        sources = list(self.sources)
        for f in self.filters:
            sources += Source.all.apply_filter(f)

        objs = self.srcs_to_objs(env, sources)
        objs = objs + env['MAIN_OBJS']

        for component in self.components:
            component.prepare_env(env)

        binary = super(ArmFastModelBin, self).declare(env, objs)[0]

        # We need a copy of the simulation engine lib alongside the executable
        # so that the license check works properly.
        local_engine = binary.File(simulation_engine_name)
        Depends(binary, local_engine)
        main.Command(local_engine, simulation_engine_lib,
                MakeAction("cp ${SOURCE} ${TARGET}", Transform('COPY')))

Export('ArmFastModelComponent')
Export('ArmFastModelBin')

PySource('m5', 'arm_fast_model.py')
Source('fastmodel.cc')

SimObject('FastModel.py')
Source('amba_to_tlm_bridge.cc')
Source('amba_from_tlm_bridge.cc')

# HACK: Make sure the gic protocol headers are somewhere we can find them.
# These should start out alongside other headers fast model provides which we
# are already able to include, but unfortunately they're in the examples
# directory.
gicv3_comms_headers = (
        'gicv3_comms_base.h', 'gicv3_comms_if.h', 'gicv3_comms_sockets.h')
examples_common_dir = pvlib_home.Dir('examples/SystemCExport/Common')
gic_protocol_path = 'Protocols/GICv3Comms'
gic_protocol_dest = Dir(env['BUILDDIR']).Dir(gic_protocol_path)
gic_protocol_src = examples_common_dir.Dir(gic_protocol_path)

for header in gicv3_comms_headers:
    Command(gic_protocol_dest.File(header), gic_protocol_src.File(header),
            Copy('${TARGET}', '${SOURCE}'))

common_headers = ('lisa_protocol_types.h', 'tlm_has_get_protocol_types.h')
for header in common_headers:
    header_target = gic_protocol_dest.Dir('include').File(header)
    header_src = examples_common_dir.Dir('include').File(header)
    Command(header_target, header_src, Copy('${TARGET}', '${SOURCE}'))
