# 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.
#
# Authors: Gabe Black

from __future__ import print_function

Import('*')

from m5.util.terminal import termcap
from m5.util.grammar import Grammar

from gem5_scons import Transform

import os.path

if env['USE_ARM_FASTMODEL']:
    if not env['USE_SYSTEMC']:
        print(termcap.Yellow + termcap.Bold +
                'Warning: ARM Fast Models require systemc support' +
                termcap.Normal)
        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:
        print(termcap.Red + termcap.Bold +
                ('Error: %s is not set' % name) +
                termcap.Normal)
        Exit(1)
    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',
    '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]


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 = map(simgen_static, static_libs)
        shared_lib_nodes = 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]

        simgen_cmd = env.subst('${SIMGEN} -p %s --configuration %s -b ' +
            '--verbose off --num-build-cpus 100 --build-dir %s') % \
            (project_file.srcnode().abspath, config_name, simgen_dir.abspath)
        if not GetOption('verbose'):
            simgen_cmd += ' > /dev/null'
        simgen_action = MakeAction(simgen_cmd, Transform('SIMGEN'))
        sources = [project_file]
        sources.extend(extra_deps)
        env.Command(lib_nodes + self.headers, sources, simgen_action)

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


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}'))

lisa_protocol_types_header_path = 'include/lisa_protocol_types.h'
lisa_protocol_types_header_target = \
    gic_protocol_dest.File(lisa_protocol_types_header_path)
lisa_protocol_types_header_src = \
    examples_common_dir.File(lisa_protocol_types_header_path)
Command(lisa_protocol_types_header_target, lisa_protocol_types_header_src,
        Copy('${TARGET}', '${SOURCE}'))
