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)
 
 <!-- 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
 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;