simh-testsetgenerator/cmake/simgen/basic_simulator.py
B. Scott Michel d9d0e8bd74 CMake: Updates
Issue #294: "apple silicon build problem(s?)": If the "--flavor/-f" flag
is not specified on the command line, then complain loudly, print help
and exit. The script used to default to "Unix Makefiles".

Updates:

- Add missing "-DHAVE_LIBPNG" compiler command line define when the PNG
  library is detected/present for screen capture support.

- Add "clang64" to the list of MinGW64 platforms for which the
  .travis/deps.sh script can install build dependencies.

- Add PThread4W_FOUND to the condition that sets async I/O for Win32
  when using vcpkg for build dependencies.

- Add vs2022-x64, vs2019-x64 and vs2017-x64 build environments to
  build 64-bit Windows executables.

- Use simulator AIO only where needed by the simulator (i.e., the
  simulator calls/uses AIO_CHECK_EVENT in sim_instr())

  - Add "USES_AIO" flag to add_simulator() to mark a simulator that
    acutally uses asynchronous I/O.

  - Build "_aio" SIMH core library variants that have AIO turned on,
    link with the "_aio" variant when a simulator sets USES_AIO.

  - Emit a warning message when WITH_ASYNC is False (CMake configuration
    option) to notify the user/developer that some functionality will be
    crippled.

  Affected simulator builds: 3b2 family, PDP-6, PDP-11, VAX family,
  IMLAC and TT2500. The makefile and cmake/generate.py also updated
  to remain in sync with CMake.

  N.B.: Simulators still link with the underlying platform's threading
  library. SEL32 requires pthreads or equivalent threading library,
  independent of AIO.

- cmake/cmake-builder.sh

  - New "--no-aio" flag: Build simulators without async I/O.

  - New "--no-aio-intrinsics" flag: Don't build async I/O using compiler
    compare-exchange, atomic load intrinsics.

- cmake/cmake-builder.ps1

  - New "-noaio" flag: Build simulators without async I/O.

  - New "-noaiointrinsics" flag: Don't build async I/O using compiler
    compare-exchange, atomic load intrinsics.

CMake 3.28.1 INTERFACE_LINK_LIBRARIES behavior change: The file name
must now be an absolute path. Relative paths no longer accepted.
Internally, SIMH enforces this if CMAKE_VERSION >= 3.19, when REAL_PATH
was first implemented.
2024-02-01 12:51:13 -05:00

337 lines
14 KiB
Python

import pprint
import simgen.parse_makefile as SPM
import simgen.utils as SU
import simgen.packaging as SPKG
class SIMHBasicSimulator:
"""
"""
def __init__(self, sim_name, dir_macro, test_name, buildrom):
self.sim_name = sim_name
self.dir_macro = dir_macro
self.test_name = test_name
self.int64 = False
self.full64 = False
self.buildrom = buildrom
## self.has_display -> True if there is a specific display used by the simulator.
self.has_display = False
## self.uses_video -> True if USE_SIM_VIDEO appears in the simulator's preprocessor defn's.
self.uses_video = False
## self.besm6_sdl_hack -> Only set/used by the BESM6 simulator.
self.besm6_sdl_hack = False
## self.uses_aio -> True if the simulator uses AIO
self.uses_aio = False
self.sources = []
self.defines = []
self.includes = []
def add_source(self, src):
if src not in self.sources:
self.sources.append(src)
def add_include(self, incl):
if incl not in self.includes:
self.includes.append(incl)
def add_define(self, define):
if define not in self.defines:
self.defines.append(define)
def scan_for_flags(self, defs):
"""Scan for USE_INT64/USE_ADDR64 in the simulator's defines and set the
'int64' and 'full64' instance variables. If found, these defines are
removed. Also look for any of the "DISPLAY" make macros, and, if found,
set the 'video' instance variable.
"""
use_int64 = 'USE_INT64' in self.defines
use_addr64 = 'USE_ADDR64' in self.defines
if use_int64 or use_addr64:
self.int64 = use_int64 and not use_addr64
self.full64 = use_int64 and use_addr64
for defn in ['USE_INT64', 'USE_ADDR64']:
try:
self.defines.remove(defn)
except:
pass
## Video support:
self.has_display = any(map(lambda s: 'DISPLAY' in SPM.shallow_expand_vars(s, defs), self.sources))
if self.has_display:
for src in ['${DISPLAYL}', '$(DISPLAYL)']:
try:
self.sources.remove(src)
except:
pass
self.uses_video = 'USE_SIM_VIDEO' in self.defines or self.has_display
## AIO support:
self.uses_aio = 'SIM_ASYNCH_IO' in self.defines
if self.uses_aio:
for defn in ['SIM_ASYNCH_IO', 'USE_READER_THREAD']:
try:
self.defines.remove(defn)
except:
pass
def cleanup_defines(self):
"""Remove command line defines that aren't needed (because the CMake interface libraries
already define them.)
"""
for define in ['USE_SIM_CARD', 'USE_SIM_VIDEO', 'USE_NETWORK', 'USE_SHARED']:
try:
self.defines.remove(define)
except:
pass
def get_source_vars(self):
srcvars = set()
for src in self.sources:
srcvars = srcvars.union(set(SPM.extract_variables(src)))
return srcvars
def get_include_vars(self):
incvars = set()
for inc in self.includes:
incvars = incvars.union(set(SPM.extract_variables(inc)))
return incvars
def write_section(self, stream, section, indent, test_label='default', additional_text=[],
section_name=None, section_srcs=None, section_incs=None):
indent4 = ' ' * (indent + 4)
indent8 = ' ' * (indent + 8)
pkg_info = SPKG.package_info.get(section_name)
install_flag = pkg_info.install_flag if pkg_info is not None else None
pkg_family = pkg_info.family.component_name if pkg_info is not None else None
stream.write(' ' * indent + '{}({}\n'.format(section, section_name))
stream.write(' ' * (indent + 4) + 'SOURCES\n')
stream.write('\n'.join(map(lambda src: indent8 + src, section_srcs)))
if len(self.includes) > 0:
stream.write('\n' + indent4 + 'INCLUDES\n')
stream.write('\n'.join([ indent8 + inc for inc in section_incs]))
if len(self.defines) > 0:
stream.write('\n' + indent4 + 'DEFINES\n')
stream.write('\n'.join(map(lambda dfn: indent8 + dfn, self.defines)))
if self.int64:
stream.write('\n' + indent4 + 'FEATURE_INT64')
if self.full64:
stream.write('\n' + indent4 + 'FEATURE_FULL64')
if self.uses_video:
stream.write('\n' + indent4 + "FEATURE_VIDEO")
if self.has_display:
stream.write('\n' + indent4 + "FEATURE_DISPLAY")
if self.besm6_sdl_hack:
stream.write('\n' + indent4 + "BESM6_SDL_HACK")
if self.uses_aio:
stream.write('\n' + indent4 + "USES_AIO")
if self.buildrom:
stream.write('\n' + indent4 + "BUILDROMS")
stream.write('\n' + indent4 + "LABEL " + test_label)
if install_flag:
if pkg_family:
stream.write('\n' + indent4 + "PKG_FAMILY " + pkg_family)
else:
stream.write('\n' + indent4 + "NO_INSTALL")
stream.write('\n' + '\n'.join(additional_text))
stream.write(')\n')
def write_simulator(self, stream, indent, test_label='default'):
## When writing an individual CMakeList.txt, we can take advantage of the CMAKE_CURRENT_SOURCE_DIR
## as a replacement for the SIMH directory macro.
srcs = [ src.replace(self.dir_macro + '/', '') for src in self.sources]
incs = [ inc if inc != self.dir_macro else '${CMAKE_CURRENT_SOURCE_DIR}' for inc in self.includes]
indent4 = ' ' * (indent + 4)
addl_text = [
indent4 + "TEST " + self.test_name,
]
self.write_section(stream, 'add_simulator', indent, test_label, additional_text=addl_text,
section_name=self.sim_name, section_srcs=srcs, section_incs=incs)
# Default: Don't generate a unit test CMakeFiles.txt. Yet.
def write_unit_test(self, stream, indent, test_label='default'):
pass
def __repr__(self):
return '{0}({1},{2},{3},{4})'.format(self.__class__.__name__, self.sim_name.__repr__(),
self.sources.__repr__(), self.includes.__repr__(), self.defines.__repr__())
class BESM6Simulator(SIMHBasicSimulator):
"""The (fine Communist) BESM6 simulator needs some extra code
in the CMakeLists.txt to detect a suitable font that supports
Cyrillic.
"""
def __init__(self, sim_name, dir_macro, test_name, buildrom):
super().__init__(sim_name, dir_macro, test_name, buildrom)
def scan_for_flags(self, defs):
super().scan_for_flags(defs)
def write_simulator(self, stream, indent, test_label='besm6'):
## Fixups... :-)
for macro in ['FONTFILE=$(FONTFILE)', 'FONTFILE=${FONTFILE}']:
try:
self.defines.remove(macro)
except:
pass
## Add the search for a font file.
stream.write('\n'.join([
'set(besm6_font)',
'set(cand_fonts',
' "DejaVuSans.ttf"',
' "LucidaSansRegular.ttf"',
' "FreeSans.ttf"',
' "AppleGothic.ttf"',
' "tahoma.ttf")',
'set(cand_fontdirs',
' "/usr/share/fonts"',
' "/usr/lib/jvm"',
' "/Library/Fonts"',
' "/System/Library/Fonts"',
' "/System/Library/Frameworks/JavaVM.framework/Versions"',
' "$ENV{WINDIR}/Fonts")',
'',
'foreach (fdir ${cand_fontdirs})',
' foreach (font ${cand_fonts})',
' if (EXISTS ${fdir}/${font})',
' get_filename_component(fontfile ${fdir}/${font} ABSOLUTE)',
' list(APPEND besm6_font ${fontfile})',
' endif ()',
'',
' file(GLOB besm6_font_cand_1 LIST_DIRECTORIES FALSE "${fdir}/*/${font}")',
' file(GLOB besm6_font_cand_2 LIST_DIRECTORIES FALSE "${fdir}/*/*/${font}")',
' file(GLOB besm6_font_cand_3 LIST_DIRECTORIES FALSE "${fdir}/*/*/*/${font}")',
' list(APPEND besm6_font ${besm6_font_cand_1} ${besm6_font_cand_2} ${besm6_font_cand_3})',
' endforeach()',
'endforeach()',
'',
'if (besm6_font)',
' set(besm6_found_fonts "BESM6: Fonts found")',
' foreach(bfont ${besm6_font})',
' string(APPEND besm6_found_fonts "\n .. ${bfont}")',
' endforeach ()',
' message(STATUS ${besm6_found_fonts})',
' unset(besm6_found_fonts)',
' list(GET besm6_font 0 besm6_font)',
' message(STATUS "BESM6: Using ${besm6_font}")',
'else ()',
' set(besm6_no_fonts "BESM6: No applicable Cyrillic fonts found.")',
' string(APPEND besm6_no_fonts "\n Font names tried:")',
' foreach (font ${cand_fonts})',
' string(APPEND besm6_no_fonts "\n .. ${font}")',
' endforeach ()',
' string(APPEND besm6_no_fonts "\n\n Looked in:")',
' foreach (fdir ${cand_fontdirs})',
' string(APPEND besm6_no_fonts "\n .. ${fdir}")',
' endforeach()',
' string(APPEND besm6_no_fonts "\n\nBESM6: Not building with panel display.")',
' message(STATUS ${besm6_no_fonts})',
' unset(besm6_no_fonts)',
'endif ()',
'',
'if (NOT (besm6_font AND WITH_VIDEO))\n']))
super().write_simulator(stream, indent + 4, test_label)
stream.write('else ()\n')
self.defines.append("FONTFILE=${besm6_font}")
self.has_display = True
self.uses_video = True
self.besm6_sdl_hack = True
super().write_simulator(stream, indent + 4, test_label)
stream.write('\n'.join([
'endif()',
'unset(cand_fonts)',
'unset(cand_fontdirs)\n']))
class KA10Simulator(SIMHBasicSimulator):
def __init__(self, sim_name, dir_macro, test_name, buildrom):
super().__init__(sim_name, dir_macro, test_name, buildrom)
def write_simulator(self, stream, indent, test_label='ka10'):
super().write_simulator(stream, indent, test_label)
stream.write('\n')
stream.write('\n'.join([
'if (PANDA_LIGHTS)',
' target_sources({0} PUBLIC {1}/ka10_lights.c)'.format(self.sim_name, self.dir_macro),
' target_compile_definitions({0} PUBLIC PANDA_LIGHTS)'.format(self.sim_name),
' target_link_libraries({0} PUBLIC usb-1.0)'.format(self.sim_name),
'endif (PANDA_LIGHTS)'
]))
stream.write('\n')
class IBM650Simulator(SIMHBasicSimulator):
'''The IBM650 simulator creates relatively deep stacks, which will fail on Windows.
Adjust target simulator link flags to provide a 8M stack, similar to Linux.
'''
def __init__(self, sim_name, dir_macro, test_name, buildrom):
super().__init__(sim_name, dir_macro, test_name, buildrom)
self.stack_size = 8 * 1024 * 1024
def write_simulator(self, stream, indent, test_label='ibm650'):
super().write_simulator(stream, indent, test_label)
stream.write('\n')
## Link i650 with a 8M stack on windows
stream.write('\n'.join([
'if (WIN32)',
' if (MSVC)',
' set(I650_STACK_FLAG "/STACK:{0}")'.format(self.stack_size),
' else ()',
' set(I650_STACK_FLAG "-Wl,--stack,{0}")'.format(self.stack_size),
' endif ()',
' if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.13")',
' target_link_options({0} PUBLIC "${{I650_STACK_FLAG}}")'.format(self.sim_name),
' else ()',
' set_property(TARGET {0} LINK_FLAGS " ${{I650_STACK_FLAG}}")'.format(self.sim_name),
' endif ()',
'endif()'
]))
class IBM1130Simulator(SIMHBasicSimulator):
'''The IBM650 simulator creates relatively deep stacks, which will fail on Windows.
Adjust target simulator link flags to provide a 8M stack, similar to Linux.
'''
def __init__(self, sim_name, dir_macro, test_name, buildrom):
super().__init__(sim_name, dir_macro, test_name, buildrom)
def write_simulator(self, stream, indent, test_label='ibm650'):
super().write_simulator(stream, indent, test_label)
stream.write('\n'.join([
'',
'if (WIN32)',
' target_compile_definitions(ibm1130 PRIVATE GUI_SUPPORT)',
' ## missing source in IBM1130?'
' ## target_sources(ibm1130 PRIVATE ibm1130.c)',
'endif()'
]))
if '_dispatch' in pprint.PrettyPrinter.__dict__:
def sim_pprinter(pprinter, sim, stream, indent, allowance, context, level):
cls = sim.__class__
stream.write(cls.__name__ + '(')
indent += len(cls.__name__) + 1
pprinter._format(sim.sim_name, stream, indent, allowance + 2, context, level)
stream.write(',')
pprinter._format(sim.dir_macro, stream, indent, allowance + 2, context, level)
stream.write(',')
pprinter._format(sim.int64, stream, indent, allowance + 2, context, level)
stream.write(',')
pprinter._format(sim.full64, stream, indent, allowance + 2, context, level)
stream.write(',')
pprinter._format(sim.has_display, stream, indent, allowance + 2, context, level)
stream.write(',')
pprinter._format(sim.sources, stream, indent, allowance + 2, context, level)
stream.write(',\n' + ' ' * indent)
pprinter._format(sim.defines, stream, indent, allowance + 2, context, level)
stream.write(',\n' + ' ' * indent)
pprinter._format(sim.includes, stream, indent, allowance + 2, context, level)
stream.write(')')
pprint.PrettyPrinter._dispatch[SIMHBasicSimulator.__repr__] = sim_pprinter