CMake: Make generate.py reusable

Make generate.py resuable outside of open-simh, as suggested and
motivated by Richard Cornwell's simulator repository.

- Make the "experimental" rule optional. Do not generate a Python
  "KeyError" if the rule is missing.

- Add documentation on how to use the CMake infrastructure outside
  of open-simh: Customize the packaging.py script, season to taste.

- Update the KA10 simulator customization, moving it to its own
  Python script, simgen/pdp10_simulator.py. Preparatory move that
  anticipates additional frontpanel and display options.

- generate.py option "--skip-orphans": Skip the orphaned simulator
  check (i.e., don't cross-reference the simulators in packaging.py
  with what was scraped from the makefile.)

- Add "TEST_ARGS" argument to CMake's add_simulator function so that the
  IBM 1130 simulator can pass to "-g" on the command line to disable the
  GUI when running RegisterSanityCheck, i.e.:

    ibm1130 RegisterSanityCheck -g

  This fixes an edge case Heisenbug encountered during Github CI/CD
  tests where ibm1130 appears to hang indefinitely on the Windows
  runners.

  The cause is the GUI's Pump() thread function being prematurely
  terminated before all GUI resources are acquired. The net result is an
  infinite loop in the MS C runtime trying to exit the process with
  unstable internal state. (Separate patch: synchronization across main
  and Pump() threads to ensure resource acquisition completes.)

  This issue never shows up on non-Windows platforms or the SIMH makefile.

- cmake/generator.py, cmake/simgen: Add a "test_args" keyword argument
  to the BasicSimulator constructor that holds the tests argument
  parameter emitted as the "TEST_ARGS" argument to a simulator's
  add_simulator(). Ensure that the IBM 1130 emits 'TEST_ARG "-g"' in its
  add_simulator().

- scp.c: reset_all_p() adds 'P' to the existing switches, versus saving
  sim_switches and ONLY setting the 'P' power-up reset switch. Net effect
  is that the IBM 1130 simulator actually sees the 'G' flag that inhibits
  the GUI during the console device reset.
This commit is contained in:
B. Scott Michel 2024-03-15 20:44:34 -07:00 committed by Paul Koning
parent 24f145ad16
commit 191b2131e9
15 changed files with 342 additions and 169 deletions

View file

@ -202,9 +202,6 @@ option(WITH_TAP
option(WITH_VIDEO option(WITH_VIDEO
"Enable (=1)/disable (=0) simulator display and graphics support (def: enabled)" "Enable (=1)/disable (=0) simulator display and graphics support (def: enabled)"
TRUE) TRUE)
option(PANDA_LIGHTS
"Enable (=1)/disable (=0) KA-10/KI-11 simulator's Panda display. (def: disabled)"
FALSE)
option(DONT_USE_ROMS option(DONT_USE_ROMS
"Enable (=1)/disable (=0) building support ROMs. (def: disabled)" "Enable (=1)/disable (=0) building support ROMs. (def: disabled)"
FALSE) FALSE)

View file

@ -46,6 +46,20 @@ add_simulator(pdp10
NO_INSTALL NO_INSTALL
TEST pdp10) TEST pdp10)
option(PANDA_LIGHTS
"Enable (=1)/disable (=0) KA-10/KI-11 simulator's Panda display. (def: disabled)"
FALSE)
option(PIDP10
"Enable (=1)/disable (=0) PIDP10 display options (def: disabled)"
FALSE)
### Ensure that the options are mutually exclusive:
if (PANDA_LIGHTS AND PIDP10)
message(FATAL_ERROR "PANDA_LIGHTS and PIDP10 options are mutually exclusive. Choose one.")
endif ()
add_simulator(pdp10-ka add_simulator(pdp10-ka
SOURCES SOURCES
${KA10D}/kx10_cpu.c ${KA10D}/kx10_cpu.c
@ -103,10 +117,14 @@ add_simulator(pdp10-ka
TEST ka10) TEST ka10)
if (PANDA_LIGHTS) if (PANDA_LIGHTS)
target_sources(pdp10-ka PUBLIC ${PDP10D}/ka10_lights.c) target_sources(pdp10-ka PUBLIC ${PDP10D}/kx10_lights.c)
target_compile_definitions(pdp10-ka PUBLIC PANDA_LIGHTS) target_compile_definitions(pdp10-ka PUBLIC PANDA_LIGHTS)
target_link_libraries(pdp10-ka PUBLIC usb-1.0) target_link_libraries(pdp10-ka PUBLIC usb-1.0)
endif (PANDA_LIGHTS) endif ()
if (PIDP10)
target_sources(pdp10-ka PUBLIC ${PDP10D}/ka10_pipanel.c)
target_compile_definitions(pdp10-ka PUBLIC PIDP10=1)
endif ()
add_simulator(pdp10-ki add_simulator(pdp10-ki
SOURCES SOURCES

View file

@ -1288,6 +1288,13 @@ add_simulator(simulator_name
## in its sim_instr() instruction simulation loop: ## in its sim_instr() instruction simulation loop:
USES_AIO USES_AIO
## Arguments to append after "RegisterSanityCheck". These arguments
## appear between "RegisterSanityCheck" and the test script, if
## given, e.g.:
##
## mysimulator RegisterSanityCheck -r -t path/to/mysim_test.ini
TEST_ARGS "-r"
## Packaging "family" (group) to which the simulator belongs, ## Packaging "family" (group) to which the simulator belongs,
## for packagers that support grouping (Windows: NSIS .exe, ## for packagers that support grouping (Windows: NSIS .exe,
## WIX .msi; macOS) ## WIX .msi; macOS)
@ -1386,9 +1393,19 @@ solution is `cmake/generate.py` to update the affected simulator
```sh ```sh
## You have to be in the cmake subdirectory to run the generate.py script ## You have to be in the cmake subdirectory to run the generate.py script
$ cd cmake $ cd cmake
$ python -m generate --help
usage: generate.py [-h] [--debug [DEBUG]] [--srcdir SRCDIR] [--orphans]
SIMH simulator CMakeLists.txt generator.
options:
-h, --help show this help message and exit
--debug [DEBUG] Debug level (0-3, 0 == off)
--srcdir SRCDIR makefile source directory.
--orphans Check for packaging orphans
# [simh_source] is the absolute path to your top-level SIMH source directory # [simh_source] is the absolute path to your top-level SIMH source directory
$ python -m generate $ python -m generate --orphans
generate.py: Expecting to emit 77 simulators.
generate.py: Looking for makefile, starting in [simh-source]/open-simh/cmake generate.py: Looking for makefile, starting in [simh-source]/open-simh/cmake
generate.py: Looking for makefile, trying [simh-source]/open-simh generate.py: Looking for makefile, trying [simh-source]/open-simh
generate.py: Processing [simh-source]/open-simh/makefile generate.py: Processing [simh-source]/open-simh/makefile
@ -1423,6 +1440,7 @@ generate.py: all target vaxstation4000m60
generate.py: all target microvax3100m80 generate.py: all target microvax3100m80
generate.py: all target vaxstation4000vlc generate.py: all target vaxstation4000vlc
generate.py: all target infoserver1000 generate.py: all target infoserver1000
generate.py: all target nd100
generate.py: all target nova generate.py: all target nova
generate.py: all target eclipse generate.py: all target eclipse
generate.py: all target hp2100 generate.py: all target hp2100
@ -1475,6 +1493,7 @@ generate.py: all target sel32
generate.py: exp target alpha generate.py: exp target alpha
generate.py: exp target pdq3 generate.py: exp target pdq3
generate.py: exp target sage generate.py: exp target sage
generate.py: Expecting to emit 78 simulators.
==== writing to [simh-source]/open-simh/3B2/CMakeLists.txt ==== writing to [simh-source]/open-simh/3B2/CMakeLists.txt
==== writing to [simh-source]/open-simh/ALTAIR/CMakeLists.txt ==== writing to [simh-source]/open-simh/ALTAIR/CMakeLists.txt
==== writing to [simh-source]/open-simh/AltairZ80/CMakeLists.txt ==== writing to [simh-source]/open-simh/AltairZ80/CMakeLists.txt
@ -1495,6 +1514,7 @@ generate.py: exp target sage
==== writing to [simh-source]/open-simh/Intel-Systems/scelbi/CMakeLists.txt ==== writing to [simh-source]/open-simh/Intel-Systems/scelbi/CMakeLists.txt
==== writing to [simh-source]/open-simh/Interdata/CMakeLists.txt ==== writing to [simh-source]/open-simh/Interdata/CMakeLists.txt
==== writing to [simh-source]/open-simh/LGP/CMakeLists.txt ==== writing to [simh-source]/open-simh/LGP/CMakeLists.txt
==== writing to [simh-source]/open-simh/ND100/CMakeLists.txt
==== writing to [simh-source]/open-simh/NOVA/CMakeLists.txt ==== writing to [simh-source]/open-simh/NOVA/CMakeLists.txt
==== writing to [simh-source]/open-simh/PDP1/CMakeLists.txt ==== writing to [simh-source]/open-simh/PDP1/CMakeLists.txt
==== writing to [simh-source]/open-simh/PDP10/CMakeLists.txt ==== writing to [simh-source]/open-simh/PDP10/CMakeLists.txt

View file

@ -17,6 +17,8 @@
- [`dep-locate.cmake`, `dep-link.cmake`: Dependency libraries](#dep-locatecmake-dep-linkcmake-dependency-libraries) - [`dep-locate.cmake`, `dep-link.cmake`: Dependency libraries](#dep-locatecmake-dep-linkcmake-dependency-libraries)
- [`simh-simulators.cmake`](#simh-simulatorscmake) - [`simh-simulators.cmake`](#simh-simulatorscmake)
- [`generate.py`: Automagic `makefile` → CMake infrastructure](#generatepy-automagic-makefile--cmake-infrastructure) - [`generate.py`: Automagic `makefile` → CMake infrastructure](#generatepy-automagic-makefile--cmake-infrastructure)
- [`generate.py` Internals](#generatepy-internals)
- [Using `generate.py` outside of *open-simh*](#using-generatepy-outside-of-open-simh)
- [CPack configuration](#cpack-configuration) - [CPack configuration](#cpack-configuration)
<!-- markdown-toc end --> <!-- markdown-toc end -->
@ -468,33 +470,47 @@ case in the future.
The SIMH `makefile` is still considered the authoritative source for simulator compiler command lines and The SIMH `makefile` is still considered the authoritative source for simulator compiler command lines and
source code. `generate.py` was built to scrape the `makefile`'s `all` and `exp` rules, gather simulator source code. `generate.py` was built to scrape the `makefile`'s `all` and `exp` rules, gather simulator
source code lists, simulator-specific defines, and emit the simulator subdirectory `CMakeLists.txt` and source code lists, simulator-specific defines, and emit the simulator subdirectory `CMakeLists.txt` and
the `simh-simulators.cmake` files. To synchronize the SIMH *CMake* infrastructure with the SIMH the `simh-simulators.cmake` files.
`makefile` when new simulators are added to the `makefile`, when compiler command lines change or new
simulator source code is added: To synchronize the *CMake* infrastructure with the `makefile` when new simulators are added to the
`makefile`, when compiler command lines change or new simulator source code is added:
``` shell ``` shell
$ cd cmake; python3 -m generate $ (cd cmake; python3 -m generate)
## Alternatively:
$ python3 cmake/generate.py
``` ```
Internally, `generate.py` has three principal classes defined in the `cmake/simgen` subdirectory: Note that `generate.py` ensures that it has collected all of the `makefile`-s simulators by cross-referencing
`CMakeBuildSystem` (`cmake_container.py`), `SimCollection` (`sim_collection.py`) and `SIMHBasicSimulator` the simulators enumerated in the `cmake/simgen/packaging.py` script to the collected simulators scraped from
(`basic_simulator.py`). the `makefile`. When the expected simulators do not match the `generate.py`-collected simulator list,
`generate.py` will list the missing simulators and exit. If you are maintaining a separate simulator source
repository, please customize your `cmake/simgen/packaging.py` script to reflect the expected simulators in
your source tree.
- `CMakeBuildSystem`: The top-level container for the entire SIMH simulator collection scraped from the
`makefile`. It's a container that maps a `SimCollection` simulator group to a subdirectory. The #### `generate.py` Internals
`CMakeBuildSystem.extract` method interprets the `makefile`'s parsed contents, and builds up the
`generate.py` has three principal classes defined in the `cmake/simgen` subdirectory: `CMakeBuildSystem`,
`SimCollection` and `SIMHBasicSimulator`.
- `CMakeBuildSystem` (`cmake_container.py`): The top-level container for the entire SIMH simulator collection
scraped from the `makefile`. It's a container that maps a `SimCollection` simulator group to a subdirectory.
The `CMakeBuildSystem.extract` method interprets the `makefile`'s parsed contents, and builds up the
per-subdirectory `SimCollection` simulator groups. per-subdirectory `SimCollection` simulator groups.
- `SimCollection`: A group of simulators, e.g., all of the VAX or PDP-11 simulators, or the PDP-8 - `SimCollection` (`sim_collection.py`): A group of simulators, e.g., all of the VAX or PDP-11 simulators,
simulator. It also maps simulator source macro names to source lists that become *CMake* variables to or the PDP-8 simulator. It also maps simulator source macro names to source lists that become *CMake*
make the emitted `CMakeLists.txt` files more readable. The `SimCollection.write_simulators` method emits variables to make the emitted `CMakeLists.txt` files more readable. The `SimCollection.write_simulators`
the simulator subdirectory `CMakeLists.txt` file. method emits the simulator subdirectory `CMakeLists.txt` file.
- `SIMHBasicSimulator`: An individual SIMH simulator stored inside a `SimCollection`. This class keeps - `SIMHBasicSimulator` (`basic_simulator.py`): An individual SIMH simulator stored inside a `SimCollection`.
track of the simulator's sources, simulator-specific defines and include paths, as well as detects when This class tracks of the simulator's sources, simulator-specific defines and include paths, as well as
the simulator requires 64-bit address and 64-bit data, when the simulator requires video support. The detects when the simulator requires 64-bit address and 64-bit data, when the simulator requires video
`SIMHBasicSimulator.write_section` method emits the individual simulator's `add_simulator` function call support. The `SIMHBasicSimulator.write_section` method emits the individual simulator's `add_simulator`
to the `CMakeLists.txt` file stream passed by the parent `SimCollection`. function call to the `CMakeLists.txt` file stream passed by the parent `SimCollection`.
`SIMHBasicSimulator` has several subclasses that specialize the `write_section` method. For example, the `SIMHBasicSimulator` has several subclasses that specialize the `write_section` method. For example, the
*BESM6* simulator requires a Cyrillic font, which requires additional *CMake* code to search for an *BESM6* simulator requires a Cyrillic font, which requires additional *CMake* code to search for an
@ -504,6 +520,118 @@ Internally, `generate.py` has three principal classes defined in the `cmake/simg
subclasses. If the simulator's name is not present in the `special_simulators` dictionary, subclasses. If the simulator's name is not present in the `special_simulators` dictionary,
`SIMHBasicSimulator` is used. `SIMHBasicSimulator` is used.
#### Using `generate.py` outside of *open-simh*
`generate.py` can be used outside of the *open-simh* project for separately maintained simulator
repositories. If you do use `generate.py` in your own simulator repository, you **must** customize
the `simgen/packaging.py` script so that the expected simulators matches the collected simulators.
An example `packaging.py` script that can be copied, pasted and customized (leave the boilerplate
in place, edit and customize after the "Your customizations here...")
```python
### packaging.py boilerplate starts:
import os
import functools
## Initialize package_info to an empty dictionary here so
## that it's visible to write_packaging().
package_info = {}
class SIMHPackaging:
def __init__(self, family, install_flag = True) -> None:
self.family = family
self.processed = False
self.install_flag = install_flag
def was_processed(self) -> bool:
return self.processed == True
def encountered(self) -> None:
self.processed = True
class PkgFamily:
def __init__(self, component_name, display_name, description) -> None:
self.component_name = component_name
self.display_name = display_name
self.description = description
def write_component_info(self, stream, indent) -> None:
pkg_description = self.description
if pkg_description[-1] != '.':
pkg_description += '.'
sims = []
for sim, pkg in package_info.items():
if pkg.family is self and pkg.was_processed():
sims.append(sim)
sims.sort()
if len(sims) > 0:
sims.sort()
pkg_description += " Simulators: " + ', '.join(sims)
indent0 = ' ' * indent
indent4 = ' ' * (indent + 4)
stream.write(indent0 + "cpack_add_component(" + self.component_name + "\n")
stream.write(indent4 + "DISPLAY_NAME \"" + self.display_name + "\"\n")
stream.write(indent4 + "DESCRIPTION \"" + pkg_description + "\"\n")
stream.write(indent0 + ")\n")
def __lt__(self, obj):
return self.component_name < obj.component_name
def __eq__(self, obj):
return self.component_name == obj.component_name
def __gt__(self, obj):
return self.component_name > obj.component_name
def __hash__(self):
return hash(self.component_name)
def write_packaging(toplevel_dir) -> None:
families = set([sim.family for sim in package_info.values()])
pkging_file = os.path.join(toplevel_dir, 'cmake', 'simh-packaging.cmake')
print("==== writing {0}".format(pkging_file))
with open(pkging_file, "w") as stream:
## Runtime support family:
stream.write("""## The default runtime support component/family:
cpack_add_component(runtime_support
DISPLAY_NAME "Runtime support"
DESCRIPTION "Required SIMH runtime support (documentation, shared libraries)"
REQUIRED
)
## Basic documentation for SIMH
install(FILES doc/simh.doc TYPE DOC COMPONENT runtime_support)
""")
## Simulators:
for family in sorted(families):
family.write_component_info(stream, 0)
## The default packaging family for simulators not associated with
## any particular family. Also used for runtime and documentation:
default_family = PkgFamily("default_family", "Default SIMH simulator family.",
"""The SIMH simulator collection of historical processors and computing systems that do not belong to
any other simulated system family"""
)
### packaging.py boilerplate ends...
### Your customizations here:
### Instantiate a simulator package family:
foosim_family = PkgFamily("foosim_family", "A collection of simulators",
"""Description of your simulators, may span multiple lines within the three quote
marks."""
)
### Add simulators to the package famil(y|ies)
package_info["sim1"] = SIMHPackaging(foosim_family)
package_info["sim2"] = SIMHPackaging(foosim_family)
```
### CPack configuration ### CPack configuration
[*CPack*][cpack] is the *CMake* utility for packaging SIMH's pre-built binaries. Like *CMake*, *CPack* has [*CPack*][cpack] is the *CMake* utility for packaging SIMH's pre-built binaries. Like *CMake*, *CPack* has

View file

@ -171,10 +171,13 @@ list(APPEND ADD_SIMULATOR_1ARG
## DEFINES: List of extra command line manifest constants ("-D" items) ## DEFINES: List of extra command line manifest constants ("-D" items)
## INCLUDES: List of extra include directories ## INCLUDES: List of extra include directories
## SOURCES: List of source files ## SOURCES: List of source files
## TEST_ARGS: Additional arguments to append to the command line after
## "RegisterSanityCheck"
list(APPEND ADD_SIMULATOR_NARG list(APPEND ADD_SIMULATOR_NARG
"DEFINES" "DEFINES"
"INCLUDES" "INCLUDES"
"SOURCES" "SOURCES"
"TEST_ARGS"
) )
function (simh_executable_template _targ) function (simh_executable_template _targ)
@ -281,6 +284,9 @@ function (add_simulator _targ)
## Simulator-specific tests: ## Simulator-specific tests:
list(APPEND test_cmd "${_targ}" "RegisterSanityCheck") list(APPEND test_cmd "${_targ}" "RegisterSanityCheck")
if (SIMH_TEST_ARGS)
list(APPEND test_cmd ${SIMH_TEST_ARGS})
endif ()
if (DEFINED SIMH_TEST) if (DEFINED SIMH_TEST)
string(APPEND test_fname ${CMAKE_CURRENT_SOURCE_DIR} "/tests/${SIMH_TEST}_test.ini") string(APPEND test_fname ${CMAKE_CURRENT_SOURCE_DIR} "/tests/${SIMH_TEST}_test.ini")

View file

@ -32,9 +32,9 @@ def process_makefile(makefile_dir, debug=0):
if debug >= 4: if debug >= 4:
pprint.pp(defs) pprint.pp(defs)
all_rule = rules.get('all') all_rule = rules.get('all') or rules.get('ALL')
if all_rule is None: if all_rule is None:
print('{0}: "all" rule not found. Cannot process.'.format(GEN_SCRIPT_NAME)) print('{0}: "all" rule not found. Cannot proceed.'.format(GEN_SCRIPT_NAME))
simulators = SCC.CMakeBuildSystem() simulators = SCC.CMakeBuildSystem()
for all_targ in SPM.shallow_expand_vars(all_rule, defs).split(): for all_targ in SPM.shallow_expand_vars(all_rule, defs).split():
@ -42,6 +42,7 @@ def process_makefile(makefile_dir, debug=0):
walk_target_deps(all_targ, defs, rules, actions, simulators, debug=debug) walk_target_deps(all_targ, defs, rules, actions, simulators, debug=debug)
experimental_rule = rules.get('experimental') experimental_rule = rules.get('experimental')
if experimental_rule is not None:
for experimental_targ in SPM.shallow_expand_vars(experimental_rule, defs).split(): for experimental_targ in SPM.shallow_expand_vars(experimental_rule, defs).split():
print("{0}: exp target {1}".format(GEN_SCRIPT_NAME, experimental_targ)) print("{0}: exp target {1}".format(GEN_SCRIPT_NAME, experimental_targ))
walk_target_deps(experimental_targ, defs, rules, actions, simulators, debug=debug) walk_target_deps(experimental_targ, defs, rules, actions, simulators, debug=debug)
@ -70,6 +71,8 @@ def walk_target_deps(target, defs, rules, actions, simulators, depth='', debug=0
print('{0}-- target: {1}'.format(depth, target)) print('{0}-- target: {1}'.format(depth, target))
target_deps = SPM.target_dep_list(target, rules, defs) target_deps = SPM.target_dep_list(target, rules, defs)
if debug >= 2:
print('{0}target deps: {1}'.format(depth, target_deps))
has_buildrom = any(filter(lambda dep: dep == '${BUILD_ROMS}', target_deps)) has_buildrom = any(filter(lambda dep: dep == '${BUILD_ROMS}', target_deps))
if debug >= 1: if debug >= 1:
@ -131,15 +134,14 @@ if __name__ == '__main__':
help='Debug level (0-3, 0 == off)') help='Debug level (0-3, 0 == off)')
args.add_argument('--srcdir', default=None, args.add_argument('--srcdir', default=None,
help='makefile source directory.') help='makefile source directory.')
## args.add_argument('--file', '-f', default=os.path.join(GEN_SCRIPT_DIR, 'simh_makefile.cmake'), args.add_argument('--skip-orphans', action='store_true',
## help='Output file for "all-in-one" CMakeLists.txt, default is simh_makefile.cmake') help='Skip the check for packaging orphans')
flags = vars(args.parse_args()) flags = vars(args.parse_args())
debug_level = flags.get('debug') debug_level = flags.get('debug')
makefile_dir = flags.get('srcdir') makefile_dir = flags.get('srcdir')
print('{0}: Expecting to emit {1} simulators.'.format(GEN_SCRIPT_NAME, len(SPKG.package_info.keys())))
found_makefile = True found_makefile = True
if makefile_dir is None: if makefile_dir is None:
## Find the makefile, which should be one directory up from this Python ## Find the makefile, which should be one directory up from this Python
@ -171,15 +173,22 @@ if __name__ == '__main__':
## Sanity check: Make sure that all of the simulators in SPKG.package_info have ## Sanity check: Make sure that all of the simulators in SPKG.package_info have
## been encountered ## been encountered
for simdir in sims.dirs.keys(): for simdir in sims.dirs.keys():
if debug_level >= 2:
print('{}: simdir {}'.format(GEN_SCRIPT_NAME, simdir))
for sim in sims.dirs[simdir].simulators.keys(): for sim in sims.dirs[simdir].simulators.keys():
SPKG.package_info[sim].encountered() SPKG.package_info[sim].encountered()
if not flags.get('skip_orphans'):
print('{0}: Expecting to emit {1} simulators.'.format(GEN_SCRIPT_NAME, len(SPKG.package_info.keys())))
orphans = [ sim for sim, pkg_info in SPKG.package_info.items() if not pkg_info.was_processed() ] orphans = [ sim for sim, pkg_info in SPKG.package_info.items() if not pkg_info.was_processed() ]
if len(orphans) > 0: if len(orphans) > 0:
print('{0}: Simulators not extracted from makefile:'.format(GEN_SCRIPT_NAME)) print('{0}: Simulators not extracted from makefile:'.format(GEN_SCRIPT_NAME))
for orphan in orphans: for orphan in orphans:
print('{0}{1}'.format(' ' * 4, orphan)) print('{0}{1}'.format(' ' * 4, orphan))
sys.exit(1) sys.exit(1)
else:
print('{0}: All simulators present and accounted for!'.format(GEN_SCRIPT_NAME))
if debug_level >= 1: if debug_level >= 1:
pp = pprint.PrettyPrinter() pp = pprint.PrettyPrinter()

View file

@ -7,8 +7,9 @@ import simgen.packaging as SPKG
class SIMHBasicSimulator: class SIMHBasicSimulator:
""" """
""" """
def __init__(self, sim_name, dir_macro, test_name, buildrom): def __init__(self, sim_name, dir_macro, test_name, buildrom, test_args=None):
self.sim_name = sim_name self.sim_name = sim_name
## self.dir_macro -> Directory macro (e.g., "${PDP11D}" for source
self.dir_macro = dir_macro self.dir_macro = dir_macro
self.test_name = test_name self.test_name = test_name
self.int64 = False self.int64 = False
@ -22,6 +23,11 @@ class SIMHBasicSimulator:
self.besm6_sdl_hack = False self.besm6_sdl_hack = False
## self.uses_aio -> True if the simulator uses AIO ## self.uses_aio -> True if the simulator uses AIO
self.uses_aio = False self.uses_aio = False
## self.test_args -> Simulator flags to pass to the test phase. Used by ibm1130 to
## pass "-g" to disable to the GUI. This argument can be a single
## string or a list.
self.test_args = test_args
self.sources = [] self.sources = []
self.defines = [] self.defines = []
self.includes = [] self.includes = []
@ -128,6 +134,13 @@ class SIMHBasicSimulator:
stream.write('\n' + indent4 + "BESM6_SDL_HACK") stream.write('\n' + indent4 + "BESM6_SDL_HACK")
if self.uses_aio: if self.uses_aio:
stream.write('\n' + indent4 + "USES_AIO") stream.write('\n' + indent4 + "USES_AIO")
if self.test_args:
out_args = self.test_args
if isinstance(self.test_args, str):
out_args = self.test_args.split()
out_args = ' '.join('"{0}"'.format(w) for w in out_args)
stream.write('\n' + indent4 + 'TEST_ARGS {}'.format(out_args))
if self.buildrom: if self.buildrom:
stream.write('\n' + indent4 + "BUILDROMS") stream.write('\n' + indent4 + "BUILDROMS")
stream.write('\n' + indent4 + "LABEL " + test_label) stream.write('\n' + indent4 + "LABEL " + test_label)
@ -250,22 +263,6 @@ class BESM6Simulator(SIMHBasicSimulator):
'unset(cand_fonts)', 'unset(cand_fonts)',
'unset(cand_fontdirs)\n'])) '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): class IBM650Simulator(SIMHBasicSimulator):
'''The IBM650 simulator creates relatively deep stacks, which will fail on Windows. '''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. Adjust target simulator link flags to provide a 8M stack, similar to Linux.
@ -293,25 +290,6 @@ class IBM650Simulator(SIMHBasicSimulator):
'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__: if '_dispatch' in pprint.PrettyPrinter.__dict__:
def sim_pprinter(pprinter, sim, stream, indent, allowance, context, level): def sim_pprinter(pprinter, sim, stream, indent, allowance, context, level):
cls = sim.__class__ cls = sim.__class__

View file

@ -0,0 +1,30 @@
## IBM 1130 simulator customizations:
##
## - Add the Win32 resource file for Windows builds
## - Add the "-g" test flag to bypass/disable the simulator GUI when
## running RegisterSanityCheck test.
import simgen.basic_simulator as SBS
class IBM1130Simulator(SBS.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, test_args="-g")
def write_simulator(self, stream, indent, test_label='ibm650'):
super().write_simulator(stream, indent, test_label)
stream.write('\n'.join([
'',
'if (WIN32)',
' ## Add GUI support, compile in resources:',
' target_compile_definitions(ibm1130 PRIVATE GUI_SUPPORT)',
' target_sources(ibm1130 PRIVATE ibm1130.rc)',
'endif()',
'',
'# IBM 1130 utilities:',
'# add_subdirectory(utils)',
''
]))

View file

@ -30,8 +30,10 @@ class PkgFamily:
pkg_description += '.' pkg_description += '.'
sims = [] sims = []
for sim, pkg in package_info.items(): for sim, pkg in package_info.items():
if pkg.family is self: if pkg.family is self and pkg.was_processed():
sims.append(sim) sims.append(sim)
if len(sims) > 0:
sims.sort() sims.sort()
pkg_description += " Simulators: " + ', '.join(sims) pkg_description += " Simulators: " + ', '.join(sims)
indent0 = ' ' * indent indent0 = ' ' * indent

View file

@ -13,9 +13,10 @@ _variable_rx = re.compile(r"\s*([A-Za-z][\w_-]+)\s*=\s*(.*)")
_rule_rx = re.compile(r"(((\$[({])*\w[\w_-]+[)}]*)+)\s*:\s*(.*)") _rule_rx = re.compile(r"(((\$[({])*\w[\w_-]+[)}]*)+)\s*:\s*(.*)")
# Regex that recognizes variables. Group 1 is the variable's name. # Regex that recognizes variables. Group 1 is the variable's name.
_var_rx = re.compile(r"^\$[{(]([A-Za-z][\w_-]*)[)}]$") _var_pattern = r"[A-Za-z][\w_-]*"
_var_rx2 = re.compile(r"\$[{(]([A-Za-z][\w_-]*)[)}]") _var_rx = re.compile(r"^\$[{(](" + _var_pattern + r")[)}]$")
_norm_var_rx = re.compile(r"\$\(([A-Za-z][\w_-]*)\)") _var_rx2 = re.compile(r"\$[{(](" + _var_pattern + r")[)}]")
_norm_var_rx = re.compile(r"\$[(](" + _var_pattern + r")[)]")
def parse_makefile(fn, g_vars=None, g_rules=None, g_actions=None): def parse_makefile(fn, g_vars=None, g_rules=None, g_actions=None):
"""Parse a Makefile-style file. """Parse a Makefile-style file.
@ -56,8 +57,15 @@ def parse_makefile(fn, g_vars=None, g_rules=None, g_actions=None):
line = fp.readline() line = fp.readline()
elif rmatch: elif rmatch:
## make allows "$(VAR)" and "${VAR}" to be used interchangably, so there's a
## possibility that the sim developer used both forms in the target, e.g.:
##
## foosim: $(BIN)foosim$(EXE)
##
## ${BIN}foosim${EXE}: stuff that foosim depends on...
n, v = rmatch.group(1, 4) n, v = rmatch.group(1, 4)
rules[n] = v rules[normalize_variables(n)] = normalize_variables(v)
## Collect the actions: ## Collect the actions:
collected = [] collected = []

View file

@ -0,0 +1,45 @@
## KA10 simulator: Add the PANDA_LIGHTS and the PIDP10 options for frontpanel
## code.
import simgen.basic_simulator as SBS
class KA10Simulator(SBS.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'):
## Keep the CMake options separate, just in case they are needed for more
## than just the KA10 (and add a class variable so they are only written
## once.)
stream.write('''
option(PANDA_LIGHTS
"Enable (=1)/disable (=0) KA-10/KI-11 simulator\'s Panda display. (def: disabled)"
FALSE)
option(PIDP10
"Enable (=1)/disable (=0) PIDP10 display options (def: disabled)"
FALSE)
### Ensure that the options are mutually exclusive:
if (PANDA_LIGHTS AND PIDP10)
message(FATAL_ERROR "PANDA_LIGHTS and PIDP10 options are mutually exclusive. Choose one.")
endif ()
''')
## Emit the simulator:
super().write_simulator(stream, indent, test_label)
## Update the display sources for PANDA_LIGHTS or PIDP10:
stream.write('\n'.join([
'',
'if (PANDA_LIGHTS)',
' target_sources({0} PUBLIC {1}/kx10_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 ()',
'if (PIDP10)',
' target_sources({0} PUBLIC {1}/ka10_pipanel.c)'.format(self.sim_name, self.dir_macro),
' target_compile_definitions({0} PUBLIC PIDP10=1)'.format(self.sim_name),
'endif ()'
]))
stream.write('\n')

View file

@ -2,6 +2,8 @@ import pprint
import simgen.parse_makefile as SPM import simgen.parse_makefile as SPM
import simgen.basic_simulator as SBS import simgen.basic_simulator as SBS
import simgen.ibm1130_simulator as IBM1130
import simgen.pdp10_simulator as PDP10
import simgen.vax_simulators as VAXen import simgen.vax_simulators as VAXen
import simgen.utils as SU import simgen.utils as SU
@ -16,8 +18,8 @@ _special_vars = frozenset(['DISPLAYL',
_special_simulators = { _special_simulators = {
"besm6": SBS.BESM6Simulator, "besm6": SBS.BESM6Simulator,
"i650": SBS.IBM650Simulator, "i650": SBS.IBM650Simulator,
"ibm1130": SBS.IBM1130Simulator, "ibm1130": IBM1130.IBM1130Simulator,
"pdp10-ka": SBS.KA10Simulator, "pdp10-ka": PDP10.KA10Simulator,
"vax": VAXen.VAXSimulator, "vax": VAXen.VAXSimulator,
"vax730": VAXen.BasicVAXSimulator "vax730": VAXen.BasicVAXSimulator
} }

View file

@ -1,75 +0,0 @@
"3b2"
"3b2-700"
"altair"
"altairz80"
"b5500"
"besm6"
"cdc1700"
"eclipse"
"gri"
"h316"
"hp2100"
"hp3000"
"i1401"
"i1620"
"i650"
"i701"
"i7010"
"i704"
"i7070"
"i7080"
"i7090"
"i7094"
"ibm1130"
"id16"
"id32"
"imlac"
"infoserver100"
"infoserver1000"
"infoserver150vxt"
"intel-mds"
"lgp"
"microvax1"
"microvax2"
"microvax2000"
"microvax3100"
"microvax3100e"
"microvax3100m80"
"microvax3900"
"nova"
"pdp1"
"pdp10"
"pdp10-ka"
"pdp10-ki"
"pdp10-kl"
"pdp10-ks"
"pdp11"
"pdp15"
"pdp4"
"pdp6"
"pdp7"
"pdp8"
"pdp9"
"rtvax1000"
"s3"
"scelbi"
"sds"
"sel32"
"sigma"
"ssem"
"swtp6800mp-a"
"swtp6800mp-a2"
"tt2500"
"tx-0"
"uc15"
"vax"
"vax730"
"vax750"
"vax780"
"vax8200"
"vax8600"
"vaxstation3100m30"
"vaxstation3100m38"
"vaxstation3100m76"
"vaxstation4000m60"
"vaxstation4000vlc"

View file

@ -1,3 +1,5 @@
## VAX simulators require extra magic -- notably, 'microvax3900${EXE}' needs
## to be symlinked, hardlinked or copied (in that order) to 'vax${EXE}'.
import simgen.basic_simulator as SBS import simgen.basic_simulator as SBS

7
scp.c
View file

@ -2738,6 +2738,7 @@ char cbuf[4*CBUFSIZE], *cptr, *cptr2;
char nbuf[PATH_MAX + 7]; char nbuf[PATH_MAX + 7];
char **targv = NULL; char **targv = NULL;
int32 i, sw; int32 i, sw;
int first_arg = -1;
t_bool lookswitch; t_bool lookswitch;
t_bool register_check = FALSE; t_bool register_check = FALSE;
t_stat stat = SCPE_OK; t_stat stat = SCPE_OK;
@ -2783,6 +2784,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */
if (*cbuf) /* concat args */ if (*cbuf) /* concat args */
strlcat (cbuf, " ", sizeof (cbuf)); strlcat (cbuf, " ", sizeof (cbuf));
sprintf(&cbuf[strlen(cbuf)], "%s%s%s", strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); sprintf(&cbuf[strlen(cbuf)], "%s%s%s", strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : "");
first_arg = i;
lookswitch = FALSE; /* no more switches */ lookswitch = FALSE; /* no more switches */
} }
} /* end for */ } /* end for */
@ -2894,7 +2896,7 @@ if (register_check) {
goto cleanup_and_exit; goto cleanup_and_exit;
} }
sim_printf ("*** Good Registers in %s simulator.\n", sim_name); sim_printf ("*** Good Registers in %s simulator.\n", sim_name);
if (argc < 2) { /* No remaining command arguments? */ if (first_arg < 0) { /* No remaining command arguments? */
sim_exit_status = EXIT_SUCCESS; /* then we're done */ sim_exit_status = EXIT_SUCCESS; /* then we're done */
goto cleanup_and_exit; goto cleanup_and_exit;
} }
@ -8053,7 +8055,8 @@ t_stat reset_all_p (uint32 start)
t_stat r; t_stat r;
int32 old_sw = sim_switches; int32 old_sw = sim_switches;
sim_switches = SWMASK ('P'); /* Add power-up reset to the sim switches. */
sim_switches = sim_switches | SWMASK ('P');
r = reset_all (start); r = reset_all (start);
sim_switches = old_sw; sim_switches = old_sw;
return r; return r;