From 191b2131e91c85ee04d5de0ea47bd0c5ca802bba Mon Sep 17 00:00:00 2001 From: "B. Scott Michel" Date: Fri, 15 Mar 2024 20:44:34 -0700 Subject: [PATCH] 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. --- CMakeLists.txt | 3 - PDP10/CMakeLists.txt | 22 +++- README-CMake.md | 24 ++++- cmake/CMake-Maintainers.md | 166 ++++++++++++++++++++++++++---- cmake/add_simulator.cmake | 6 ++ cmake/generate.py | 39 ++++--- cmake/simgen/basic_simulator.py | 50 +++------ cmake/simgen/ibm1130_simulator.py | 30 ++++++ cmake/simgen/packaging.py | 20 ++-- cmake/simgen/parse_makefile.py | 16 ++- cmake/simgen/pdp10_simulator.py | 45 ++++++++ cmake/simgen/sim_collection.py | 6 +- cmake/simgen/simulators.py | 75 -------------- cmake/simgen/vax_simulators.py | 2 + scp.c | 7 +- 15 files changed, 342 insertions(+), 169 deletions(-) create mode 100644 cmake/simgen/ibm1130_simulator.py create mode 100644 cmake/simgen/pdp10_simulator.py delete mode 100644 cmake/simgen/simulators.py diff --git a/CMakeLists.txt b/CMakeLists.txt index a715f9a6..beeda95d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,9 +202,6 @@ option(WITH_TAP option(WITH_VIDEO "Enable (=1)/disable (=0) simulator display and graphics support (def: enabled)" TRUE) -option(PANDA_LIGHTS - "Enable (=1)/disable (=0) KA-10/KI-11 simulator's Panda display. (def: disabled)" - FALSE) option(DONT_USE_ROMS "Enable (=1)/disable (=0) building support ROMs. (def: disabled)" FALSE) diff --git a/PDP10/CMakeLists.txt b/PDP10/CMakeLists.txt index c8b68033..20d60dde 100644 --- a/PDP10/CMakeLists.txt +++ b/PDP10/CMakeLists.txt @@ -46,6 +46,20 @@ add_simulator(pdp10 NO_INSTALL 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 SOURCES ${KA10D}/kx10_cpu.c @@ -103,10 +117,14 @@ add_simulator(pdp10-ka TEST ka10) 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_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 SOURCES diff --git a/README-CMake.md b/README-CMake.md index 406a3db5..eacf2dae 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -1288,6 +1288,13 @@ add_simulator(simulator_name ## in its sim_instr() instruction simulation loop: 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, ## for packagers that support grouping (Windows: NSIS .exe, ## WIX .msi; macOS) @@ -1386,9 +1393,19 @@ solution is `cmake/generate.py` to update the affected simulator ```sh ## You have to be in the cmake subdirectory to run the generate.py script $ 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 -$ python -m generate -generate.py: Expecting to emit 77 simulators. +$ python -m generate --orphans generate.py: Looking for makefile, starting in [simh-source]/open-simh/cmake generate.py: Looking for makefile, trying [simh-source]/open-simh 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 vaxstation4000vlc generate.py: all target infoserver1000 +generate.py: all target nd100 generate.py: all target nova generate.py: all target eclipse generate.py: all target hp2100 @@ -1475,6 +1493,7 @@ generate.py: all target sel32 generate.py: exp target alpha generate.py: exp target pdq3 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/ALTAIR/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/Interdata/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/PDP1/CMakeLists.txt ==== writing to [simh-source]/open-simh/PDP10/CMakeLists.txt diff --git a/cmake/CMake-Maintainers.md b/cmake/CMake-Maintainers.md index ce44d196..927f1beb 100644 --- a/cmake/CMake-Maintainers.md +++ b/cmake/CMake-Maintainers.md @@ -17,6 +17,8 @@ - [`dep-locate.cmake`, `dep-link.cmake`: Dependency libraries](#dep-locatecmake-dep-linkcmake-dependency-libraries) - [`simh-simulators.cmake`](#simh-simulatorscmake) - [`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) @@ -468,33 +470,47 @@ case in the future. 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 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 -`makefile` when new simulators are added to the `makefile`, when compiler command lines change or new -simulator source code is added: +the `simh-simulators.cmake` files. + +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 -$ 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: -`CMakeBuildSystem` (`cmake_container.py`), `SimCollection` (`sim_collection.py`) and `SIMHBasicSimulator` -(`basic_simulator.py`). +Note that `generate.py` ensures that it has collected all of the `makefile`-s simulators by cross-referencing +the simulators enumerated in the `cmake/simgen/packaging.py` script to the collected simulators scraped from +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 - `CMakeBuildSystem.extract` method interprets the `makefile`'s parsed contents, and builds up the + +#### `generate.py` Internals + +`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. -- `SimCollection`: A group of simulators, e.g., all of the VAX or PDP-11 simulators, or the PDP-8 - simulator. It also maps simulator source macro names to source lists that become *CMake* variables to - make the emitted `CMakeLists.txt` files more readable. The `SimCollection.write_simulators` method emits - the simulator subdirectory `CMakeLists.txt` file. +- `SimCollection` (`sim_collection.py`): A group of simulators, e.g., all of the VAX or PDP-11 simulators, + or the PDP-8 simulator. It also maps simulator source macro names to source lists that become *CMake* + variables to make the emitted `CMakeLists.txt` files more readable. The `SimCollection.write_simulators` + method emits the simulator subdirectory `CMakeLists.txt` file. -- `SIMHBasicSimulator`: An individual SIMH simulator stored inside a `SimCollection`. This class keeps - track of the simulator's sources, simulator-specific defines and include paths, as well as detects when - the simulator requires 64-bit address and 64-bit data, when the simulator requires video support. The - `SIMHBasicSimulator.write_section` method emits the individual simulator's `add_simulator` function call - to the `CMakeLists.txt` file stream passed by the parent `SimCollection`. +- `SIMHBasicSimulator` (`basic_simulator.py`): An individual SIMH simulator stored inside a `SimCollection`. + This class tracks of the simulator's sources, simulator-specific defines and include paths, as well as + detects when the simulator requires 64-bit address and 64-bit data, when the simulator requires video + support. The `SIMHBasicSimulator.write_section` method emits the individual simulator's `add_simulator` + 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 *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, `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*][cpack] is the *CMake* utility for packaging SIMH's pre-built binaries. Like *CMake*, *CPack* has diff --git a/cmake/add_simulator.cmake b/cmake/add_simulator.cmake index d56ccd19..e87ef16c 100644 --- a/cmake/add_simulator.cmake +++ b/cmake/add_simulator.cmake @@ -171,10 +171,13 @@ list(APPEND ADD_SIMULATOR_1ARG ## DEFINES: List of extra command line manifest constants ("-D" items) ## INCLUDES: List of extra include directories ## SOURCES: List of source files +## TEST_ARGS: Additional arguments to append to the command line after +## "RegisterSanityCheck" list(APPEND ADD_SIMULATOR_NARG "DEFINES" "INCLUDES" "SOURCES" + "TEST_ARGS" ) function (simh_executable_template _targ) @@ -281,6 +284,9 @@ function (add_simulator _targ) ## Simulator-specific tests: list(APPEND test_cmd "${_targ}" "RegisterSanityCheck") + if (SIMH_TEST_ARGS) + list(APPEND test_cmd ${SIMH_TEST_ARGS}) + endif () if (DEFINED SIMH_TEST) string(APPEND test_fname ${CMAKE_CURRENT_SOURCE_DIR} "/tests/${SIMH_TEST}_test.ini") diff --git a/cmake/generate.py b/cmake/generate.py index c1993645..50e1def0 100644 --- a/cmake/generate.py +++ b/cmake/generate.py @@ -32,9 +32,9 @@ def process_makefile(makefile_dir, debug=0): if debug >= 4: pprint.pp(defs) - all_rule = rules.get('all') + all_rule = rules.get('all') or rules.get('ALL') 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() for all_targ in SPM.shallow_expand_vars(all_rule, defs).split(): @@ -42,9 +42,10 @@ def process_makefile(makefile_dir, debug=0): walk_target_deps(all_targ, defs, rules, actions, simulators, debug=debug) experimental_rule = rules.get('experimental') - for experimental_targ in SPM.shallow_expand_vars(experimental_rule, defs).split(): - print("{0}: exp target {1}".format(GEN_SCRIPT_NAME, experimental_targ)) - walk_target_deps(experimental_targ, defs, rules, actions, simulators, debug=debug) + if experimental_rule is not None: + for experimental_targ in SPM.shallow_expand_vars(experimental_rule, defs).split(): + print("{0}: exp target {1}".format(GEN_SCRIPT_NAME, experimental_targ)) + walk_target_deps(experimental_targ, defs, rules, actions, simulators, debug=debug) simulators.collect_vars(defs, debug=debug) return simulators @@ -70,6 +71,8 @@ def walk_target_deps(target, defs, rules, actions, simulators, depth='', debug=0 print('{0}-- target: {1}'.format(depth, target)) 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)) if debug >= 1: @@ -131,15 +134,14 @@ if __name__ == '__main__': help='Debug level (0-3, 0 == off)') args.add_argument('--srcdir', default=None, help='makefile source directory.') - ## args.add_argument('--file', '-f', default=os.path.join(GEN_SCRIPT_DIR, 'simh_makefile.cmake'), - ## help='Output file for "all-in-one" CMakeLists.txt, default is simh_makefile.cmake') + args.add_argument('--skip-orphans', action='store_true', + help='Skip the check for packaging orphans') + flags = vars(args.parse_args()) debug_level = flags.get('debug') makefile_dir = flags.get('srcdir') - print('{0}: Expecting to emit {1} simulators.'.format(GEN_SCRIPT_NAME, len(SPKG.package_info.keys()))) - found_makefile = True if makefile_dir is None: ## 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 ## been encountered 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(): SPKG.package_info[sim].encountered() - orphans = [ sim for sim, pkg_info in SPKG.package_info.items() if not pkg_info.was_processed() ] - if len(orphans) > 0: - print('{0}: Simulators not extracted from makefile:'.format(GEN_SCRIPT_NAME)) - for orphan in orphans: - print('{0}{1}'.format(' ' * 4, orphan)) - sys.exit(1) + 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() ] + if len(orphans) > 0: + print('{0}: Simulators not extracted from makefile:'.format(GEN_SCRIPT_NAME)) + for orphan in orphans: + print('{0}{1}'.format(' ' * 4, orphan)) + sys.exit(1) + else: + print('{0}: All simulators present and accounted for!'.format(GEN_SCRIPT_NAME)) if debug_level >= 1: pp = pprint.PrettyPrinter() diff --git a/cmake/simgen/basic_simulator.py b/cmake/simgen/basic_simulator.py index 4959ada9..9d3eb9d6 100644 --- a/cmake/simgen/basic_simulator.py +++ b/cmake/simgen/basic_simulator.py @@ -7,8 +7,9 @@ import simgen.packaging as SPKG 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.dir_macro -> Directory macro (e.g., "${PDP11D}" for source self.dir_macro = dir_macro self.test_name = test_name self.int64 = False @@ -22,6 +23,11 @@ class SIMHBasicSimulator: self.besm6_sdl_hack = False ## self.uses_aio -> True if the simulator uses AIO 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.defines = [] self.includes = [] @@ -128,6 +134,13 @@ class SIMHBasicSimulator: stream.write('\n' + indent4 + "BESM6_SDL_HACK") if self.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: stream.write('\n' + indent4 + "BUILDROMS") stream.write('\n' + indent4 + "LABEL " + test_label) @@ -250,22 +263,6 @@ class BESM6Simulator(SIMHBasicSimulator): '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. @@ -293,25 +290,6 @@ class IBM650Simulator(SIMHBasicSimulator): '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__ diff --git a/cmake/simgen/ibm1130_simulator.py b/cmake/simgen/ibm1130_simulator.py new file mode 100644 index 00000000..84ef1d9f --- /dev/null +++ b/cmake/simgen/ibm1130_simulator.py @@ -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)', + '' + ])) + + diff --git a/cmake/simgen/packaging.py b/cmake/simgen/packaging.py index 6f088a2c..220eaa5f 100644 --- a/cmake/simgen/packaging.py +++ b/cmake/simgen/packaging.py @@ -30,16 +30,18 @@ class PkgFamily: pkg_description += '.' sims = [] 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.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") + + 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 diff --git a/cmake/simgen/parse_makefile.py b/cmake/simgen/parse_makefile.py index 73f98f58..eb11c2f3 100644 --- a/cmake/simgen/parse_makefile.py +++ b/cmake/simgen/parse_makefile.py @@ -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*(.*)") # Regex that recognizes variables. Group 1 is the variable's name. -_var_rx = re.compile(r"^\$[{(]([A-Za-z][\w_-]*)[)}]$") -_var_rx2 = re.compile(r"\$[{(]([A-Za-z][\w_-]*)[)}]") -_norm_var_rx = re.compile(r"\$\(([A-Za-z][\w_-]*)\)") +_var_pattern = r"[A-Za-z][\w_-]*" +_var_rx = re.compile(r"^\$[{(](" + _var_pattern + r")[)}]$") +_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): """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() 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) - rules[n] = v + rules[normalize_variables(n)] = normalize_variables(v) ## Collect the actions: collected = [] diff --git a/cmake/simgen/pdp10_simulator.py b/cmake/simgen/pdp10_simulator.py new file mode 100644 index 00000000..3a8ebf73 --- /dev/null +++ b/cmake/simgen/pdp10_simulator.py @@ -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') + diff --git a/cmake/simgen/sim_collection.py b/cmake/simgen/sim_collection.py index d4ca850c..dd866c70 100644 --- a/cmake/simgen/sim_collection.py +++ b/cmake/simgen/sim_collection.py @@ -2,6 +2,8 @@ import pprint import simgen.parse_makefile as SPM 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.utils as SU @@ -16,8 +18,8 @@ _special_vars = frozenset(['DISPLAYL', _special_simulators = { "besm6": SBS.BESM6Simulator, "i650": SBS.IBM650Simulator, - "ibm1130": SBS.IBM1130Simulator, - "pdp10-ka": SBS.KA10Simulator, + "ibm1130": IBM1130.IBM1130Simulator, + "pdp10-ka": PDP10.KA10Simulator, "vax": VAXen.VAXSimulator, "vax730": VAXen.BasicVAXSimulator } diff --git a/cmake/simgen/simulators.py b/cmake/simgen/simulators.py deleted file mode 100644 index 71e8b406..00000000 --- a/cmake/simgen/simulators.py +++ /dev/null @@ -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" \ No newline at end of file diff --git a/cmake/simgen/vax_simulators.py b/cmake/simgen/vax_simulators.py index e2cba2d2..60e19eb3 100644 --- a/cmake/simgen/vax_simulators.py +++ b/cmake/simgen/vax_simulators.py @@ -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 diff --git a/scp.c b/scp.c index 8c7a3f31..ae53b5e1 100644 --- a/scp.c +++ b/scp.c @@ -2738,6 +2738,7 @@ char cbuf[4*CBUFSIZE], *cptr, *cptr2; char nbuf[PATH_MAX + 7]; char **targv = NULL; int32 i, sw; +int first_arg = -1; t_bool lookswitch; t_bool register_check = FALSE; t_stat stat = SCPE_OK; @@ -2783,6 +2784,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */ if (*cbuf) /* concat args */ strlcat (cbuf, " ", sizeof (cbuf)); sprintf(&cbuf[strlen(cbuf)], "%s%s%s", strchr(argv[i], ' ') ? "\"" : "", argv[i], strchr(argv[i], ' ') ? "\"" : ""); + first_arg = i; lookswitch = FALSE; /* no more switches */ } } /* end for */ @@ -2894,7 +2896,7 @@ if (register_check) { goto cleanup_and_exit; } 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 */ goto cleanup_and_exit; } @@ -8053,7 +8055,8 @@ t_stat reset_all_p (uint32 start) t_stat r; 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); sim_switches = old_sw; return r;