# simh [Open SIMH](https://opensimh.org/), the computer history simulators, built with the Zig build system. This project builds all 79 of Open SIMH's simulators, from the PDP-1 to the VAX 8600 and the IBM 650 to the AT&T 3B2, with `zig build` in place of upstream's makefile and CMake. Upstream's source is pulled in as a Zig package dependency, pinned to one commit. Nothing is vendored here and nothing is patched. ## Source ```sh git clone https://git.jcollie.dev/jeff/simh.git ``` It is mirrored on Tangled at , and on Radicle as `rad:z3JiuVAJRjprhsKfBqKfJycWW1D9Z`: ```sh rad clone rad:z3JiuVAJRjprhsKfBqKfJycWW1D9Z ``` ## Requirements - [Zig](https://ziglang.org/) 0.17 - Optional, each one found through `pkg-config` and each one able to be switched off (see [Build options](#build-options)): - SDL2, libpng and zlib, for the graphical displays - PCRE2 and zlib, for regular expressions in `EXPECT` - libedit, for command line editing and history - libvdeplug, for VDE networking (off unless asked for) Zig compiles the C itself, so no separate C compiler is needed. libpcap is not needed to build: simh loads it with `dlopen` when a network device is attached to a host interface, and its headers come from the libpcap source named in `build.zig.zon`. ## Building ```sh zig build ``` Every simulator lands in `zig-out/bin/`, under upstream's names: `vax`, `pdp11`, `pdp10-ka`, `i650`, `altairz80` and so on. As upstream does, the VAX simulator is installed a second time as `microvax3900`. To build just one or a few, name them: ```sh zig build -Dsimulator=vax -Dsimulator=pdp11 ``` Each simulator has a run step, with anything after `--` passed through: ```sh zig build run-pdp11 -- boot.ini ``` ### Tests ```sh zig build test # all of them zig build test-vax # one ``` Each simulator is tested the way upstream's CTest does it: the register sanity check, then the simulator's own script from its `tests` directory, if it has one. 27 simulators have a script, and those exercise real software: the VAX tests run DEC's hardware diagnostics, and the i650 test assembles and runs programs from punched card decks. Some scripts write files beside themselves, so each simulator directory a test uses is first copied into the build cache by `tools/copy_tree.zig`. The scripts run on that copy and never touch the fetched package. ### Build options | Option | Default | Description | | --- | --- | --- | | `-Dsimulator=NAME` | all | Build only this simulator; may be given more than once. | | `-Dvideo` | `true` | Graphical displays, with SDL2 and libpng. | | `-Dregex` | `true` | Regular expressions in `EXPECT`, with PCRE2 and zlib. | | `-Deditline` | `true` | Command line editing and history, with libedit. | | `-Dnetwork` | `true` | Ethernet device support. Turning it off turns off the four below. | | `-Dpcap` | `true` | Host Ethernet through libpcap, loaded at run time. | | `-Dslirp` | `true` | Built-in user-mode NAT networking. | | `-Dtap` | `true` on Linux | TUN/TAP networking. | | `-Dvde` | `false` | Virtual Distributed Ethernet, with libvdeplug. | | `-Daio` | `true` | Asynchronous I/O on threads, which the network devices want. | | `-Dsanitize` | `false` | Compile the C with the undefined behavior sanitizer. simh relies on wrapping arithmetic and shifts, so expect it to stop almost at once. | | `-Doptimize=...` | `Debug` | Standard Zig optimization mode, e.g. `ReleaseSafe` or `ReleaseFast`. | | `-Dtarget=...` | native | Standard Zig cross-compilation target. | Only Linux has been built and tested. `build.zig` has the macOS and Windows differences that upstream's CMake has, but neither has been tried. `SHOW VERSION` reports the upstream commit, which GitHub's archive fills in through `export-subst`, and `Build Tool: Zig 0.17.0`. ### What is left out - **BESM6's panel display.** Upstream compiles the BESM6 panel only when CMake finds a Cyrillic TrueType font on the build machine and bakes its path into the binary, and that cannot be reproducible. `besm6` is built without it, just as upstream builds it when no font is found. - **Upstream's optional extras:** the PDP-10 KA panel lights and PiDP-10 front panel, the Windows GUI resources for the IBM 1130, the `frontpaneltest` program, and the `BuildROMs` tool. The ROM headers that `BuildROMs` would write are already in upstream's tree. ## How the build is put together `simulators.zon` is the table of simulators: each one's sources, include directories, definitions, the features it asks for, and its test script. Upstream generates a `CMakeLists.txt` in each simulator directory from its makefile, and `tools/generate.py` reads those back into this table. Following upstream is therefore three steps: move the pin in `build.zig.zon`, then regenerate the table from the fetched package and the Nix expression from the manifest. ```sh url=https://github.com/open-simh/simh/archive/.tar.gz nix develop -c zig fetch --save=simh "$url" nix develop -c zig build --fetch python3 tools/generate.py zig-pkg/"$(nix develop -c zig fetch "$url")" > simulators.zon nix develop -c zon2nix --17 --nix=build.zig.zon.nix build.zig.zon ``` `zig build --fetch` unpacks the dependencies into `zig-pkg/`, each in a directory named by its hash, and `zig fetch` without `--save` prints that hash. `build.zig` follows upstream's CMake in building the simulator framework (`scp.c` and the `sim_*.c` device libraries) as a static library once for each combination of 64-bit data, 64-bit addresses, video and asynchronous I/O that some simulator asks for. Each simulator is linked against the one it needs. The built-in SLiRP NAT stack is one more static library, shared by all of them. Upstream's own compiler settings carry over: `-std=gnu99`, `-U__STRICT_ANSI__` and `-fno-strict-overflow`. Zig adds two of its own that have to be undone. It turns on the undefined behavior sanitizer in Debug, which simh trips immediately, so the sanitizer is off unless `-Dsanitize` asks for it. And it makes `__DATE__` and `__TIME__` an error in release builds, which `SHOW VERSION` uses. That error is switched off. Clang takes both values from `SOURCE_DATE_EPOCH` when that is set, as it is in a Nix build, so the result is still reproducible there. ## Nix ```sh nix build # every simulator, with zig build test in the check phase nix develop # Zig 0.17, pkg-config, the libraries, zon2nix and reuse ``` The package builds with Zig's `--system` mode, using the dependencies that [zon2nix](https://github.com/jcollie/zon2nix) wrote out to `build.zig.zon.nix`, so the build itself fetches nothing. Zig 0.17 comes from nixpkgs. ## License The build files here are under the MIT license and follow the [REUSE](https://reuse.software/) specification. Open SIMH itself, which is fetched and not included, is under its own MIT-style license. ## References cited The entries are kept in the `simh` collection in Zotero. - Ollie, J. C. (n.d.). *zon2nix* [Zig]. Retrieved September 22, 2026, from - Open SIMH Project. (2026). *Open SIMH: The computer history simulation project* (Version 87eb7d5e96f9ce0ee6ac183e20160e5c486b0712) [C]. Retrieved October 8, 2026, from - The Tcpdump Group. (2026). *libpcap: A portable C/C++ library for network traffic capture* (Version 1.11.0) [C]. Retrieved October 8, 2026, from - Zig Software Foundation. (2026). *Zig 0.17.0: lib/std/Build.zig* (Version 0.17.0) [Zig]. - Zig Software Foundation. (2026). *Zig 0.17.0: lib/std/Build/Step/Run.zig* (Version 0.17.0) [Zig]. - Zig Software Foundation. (2026). *Zig 0.17.0: lib/std/Build/Step/WriteFile.zig* (Version 0.17.0) [Zig]. - Zig Software Foundation. (2026). *Zig 0.17.0: lib/std/Io/Dir.zig* (Version 0.17.0) [Zig].