Files
gem5/src/arch/arm/fastmodel/SConscript
Gabe Black d9a51177fc scons: Tone down a fast model error into a warning.
If a fast model static library can't be found, we should treat that as
a warning instead of an error, and pass back the original library name
so that it can at least be added and potentially come from somewhere
else.

In practice, this is important because gem5 will be configured by SCons
indirectly in the future, using kconfig based tools that SCons runs on
the user's behalf. If SCons is misconfigured or not configured, this
error can trip, preventing those tools from starting. That creates a
catch 22, since you'd need SCons to fix the config, and SCons can't
run because of the config.

We can avoid that problem by making SCons more lenient, so that it can
still run even if it doesn't find static libraries where it might have
expected to.

Change-Id: Iadfd823b61fe96b937c2650250487d290492f265
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/58352
Maintainer: Gabe Black <gabe.black@gmail.com>
Reviewed-by: Yu-hsin Wang <yuhsingw@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
2022-04-01 02:28:56 +00:00

407 lines
14 KiB
Python

# 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 grammar import Grammar
from gem5_scons import Transform, warning, error
import os.path
if env['CONF']['USE_ARM_FASTMODEL']:
if not env['CONF']['USE_SYSTEMC']:
warning('ARM Fast Models require systemc support')
env['CONF']['USE_ARM_FASTMODEL'] = False
Return()
if not env['CONF']['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['CONF']:
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)
pvlib_flavor = env['CONF']['PVLIB_FLAVOR']
pvlib_lib_dir = pvlib_home.Dir('lib').Dir(pvlib_flavor)
simulation_engine_name = 'libMAXCOREInitSimulationEngine.3.so'
simulation_engine_lib = env.Command(
Dir(env['BUILDDIR']).File(simulation_engine_name),
pvlib_lib_dir.File(simulation_engine_name),
MakeAction("cp ${SOURCE} ${TARGET}", Transform('COPY')))
arm_singleton_registry_name = 'arm_singleton_registry.so'
arm_singleton_registry_lib = env.Command(
Dir(env['BUILDDIR']).File(arm_singleton_registry_name),
pvlib_lib_dir.File(arm_singleton_registry_name),
MakeAction("cp ${SOURCE} ${TARGET}", Transform('COPY')))
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)
warning("Failed to find FM static lib: " + name)
return name
# Adjust the build environment to support building in Fast Models.
env.Append(CCFLAGS='-pthread')
cpppaths = (
pvlib_home.Dir('examples/SystemCExport/Common/include'),
pvlib_home.Dir('include'),
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)
# Per ARM's 11.16 release note, a platform build with simgen automatically
# copies libraries into the build target directory along with the other
# dependencies. Therefore, we only need to add each simgen result into rpath and
# no other shared librarires are required here.
fm_static_libs = (
'components',
'pvbus',
'armctmodel',
'fmruntime',
'IrisSupport',
)
for lib in fm_static_libs:
SourceLib(staticify(env, lib))
SourceLib('atomic')
SourceLib('dl')
SourceLib('rt')
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().__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().__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['CONF']['ARMLMD_LICENSE_COUNT'])
arm_licenses = list((Value(object()) for i in range(license_count)))
license_cycle = cycle(arm_licenses)
# 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}'))
# Since we are copying the source files to a different directory, Scons's
# dependency scanner does not pick up the dependency between these files.
# Specify them manually.
env.Depends(gic_protocol_dest.File('gicv3_comms_base.h'),
gic_protocol_dest.File('gicv3_comms_if.h'))
env.Depends(gic_protocol_dest.File('gicv3_comms_sockets.h'),
gic_protocol_dest.File('gicv3_comms_if.h'))
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}'))
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]
# Simgen also puts required share library under the project folder.
self.rpaths = [simgen_dir, project_file_dir]
self.log = gen_dir.File('build_%s.log' % tlc)
self.simgen_cmd = env.subst('${CONF["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)
# The simgen-generated .lisa files may #include these gicv3 files, but
# SCons does not detect this dependency since they are generated files.
# Add the dependencies manually.
sources.extend([gic_protocol_dest.File('gicv3_comms_sockets.h'),
gic_protocol_dest.File('gicv3_comms_base.h')])
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])
# We need a copy of the simulation engine lib and arm_singleton_registry
# (introduced in 11.16) alongside the executable.
Depends(lib_nodes[0], simulation_engine_lib)
Depends(lib_nodes[0], arm_singleton_registry_lib)
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
Export('ArmFastModelComponent')
PySource('m5', 'arm_fast_model.py')
Source('fastmodel.cc')
SimObject('FastModel.py', sim_objects=[
'AmbaToTlmBridge64', 'AmbaFromTlmBridge64'])
Source('amba_to_tlm_bridge.cc')
Source('amba_from_tlm_bridge.cc')