Documentation
pdp11-apsim — a 2BSD PDP-11 user-mode runtime for Linux
apsim runs classic 2.8BSD PDP-11 binaries (a.out 0407/0410/0411, including separate I&D) directly on a modern Linux host, in the spirit of Apout and of user-mode personalities like qemu-user: PDP-11 instructions are emul…
apsim runs classic 2.8BSD PDP-11 binaries (a.out 0407/0410/0411, including
separate I&D) directly on a modern Linux host, in the spirit of Apout and of
user-mode personalities like qemu-user: PDP-11 instructions are emulated,
2.8BSD sys traps become host syscalls, and guest paths resolve inside a
bundled 2.8-style root directory.
It also runs First Edition (1971-72) binaries: a 0405 magic selects the
V1 personality automatically — the whole file loads at core 040000 (the
magic word is br .+14, hopping its own header), syscalls follow the 1971
convention (inline argument words, C-bit errors, time in AC/MQ), a KE11-A
extended arithmetic element appears at 0177300, and emt n performs the
V1 kernel's validated-rts service. The three surviving First Edition
binaries (ar, mv, chown) run correctly.
Grown from (and still verifying) the pdp11-bsd28 cross-toolchain project and now the execution engine of this merged tree: the oracle suites run the original 1981/1983 compiler, assembler, ar/ranlib, and ld binaries under it as ground truth, and boot the byte-exact reconstructed rogue.
Features
- CPU: full general instruction set, all addressing modes, EIS (MUL/DIV/ASH/ASHC), condition codes; separate I&D (0411) with split 64 KB instruction/data spaces.
- FP11 floating point, bit-faithful: true 56-bit D-format (24-bit F) integer-mantissa arithmetic with the FP11 rounding rule (round-half-up on the first discarded bit) — not host doubles. Verified against the 1981 compiler's constant conversion to the last bit. The KEV11 FIS instructions share the same exact engine (at F width), so there is no host floating point anywhere in the simulator and no libm dependency.
- Syscalls, per-universe: one canonical V7-numbered dispatcher plus
per-era kernel personalities selected by
--universe/-u/$PDP11_UNIVERSE— V5/V6 (16-bitseek, packed 36-byte stat, the era's nosys gates), V7/2.8/2.9 (the trunk: inline args, fork/wait/pipe via real host fork, 2.8sendsigsignal frames,localsub-calls), 2.10/2.11 (4.3/4.4-style renumbering via remap tables, stack-argument convention, 52-byte stat, 32-bit ioctl codes,sbrkabsolute-break semantics, minimal__sysctl), and sys3/Ultrix-11 stubs (utssys/ulimit/fcntl). Failing calls deliver the era errno (a host→guest map), and unknown numbers return ENOSYS instead of halting. - Job control: real host process groups back the guest's —
setpgrp/getpgrpmap tosetpgid/getpgid,TIOCSPGRP/TIOCGPGRPtotcsetpgrp/tcgetpgrp, and a default-stop signal (SIGTSTP/TTIN/TTOU) really stops the process soSIGCONTresumes it. Signals use the full 4.3 reliable frame (32-bitsigmask,sigvec/sigactionwith the libc trampoline,sigsuspend, andsigreturnrestoring the savedsigcontext), andwait/wait4report stopped children withWUNTRACED. The genuine 2.11 csh runs jobs, pipelines,foreachloops, command substitution, and background jobs withDonereports. - Auto-overlays: 0430 (shared I&D) and 0431 (separate I&D) with
the 2.10/2.11 15-overlay header — the overlay window lives in I-space
for 0431, which is how csh (55K base + window + data) fits 64K. The
sigreturnpath restores the overlay that was mapped when a signal hit. - Interpreter scripts:
#!lines exec the named interpreter with the classic argv rewrite (one optional argument, one level); a shebang-less text file on apsim's own command line runs through the guest/bin/sh(the execvp courtesy -- there is no calling shell to do the ENOEXEC fallback), while guest execs of such files fail authentically. The real 2.11 Bourne shell runs, soshscripts work end to end. - Directory listing: classic UNIX reads directories with read(2),
which Linux refuses — apsim snapshots an opened directory in the era's
on-disk record format (V1 10-byte, V5..2.9 16-byte, 2.10/2.11 4.3
variable records) and serves reads from it, so the real
lsworks. - Terminal: gtty/stty/ioctl
sgttybemulation mapped onto host termios (raw/cbreak/echo), enough for curses programs — rogue plays. - Runtime root:
root/provides/etc/passwd,/etc/termcap, etc.; guest absolute paths are resolved under$APSIM_ROOT.
Quick start
make # (repo root) builds ../../bin/pdp11-apsim
make check # this dir: the CIS/late-hardware golden probe
sh mkroot.sh --rogue # populate the runtime root (+ rogue demo)
APSIM_ROOT=root ../../bin/pdp11-apsim root/usr/games/rogue
Environment
APSIM_ROOT guest-root directory for absolute guest paths
APSIM_ENV guest environment (default provides TERM, HOME, PATH)
APSIM_UID / APSIM_GID guest credentials (default 1/1)
APSIM_PID deterministic getpid (also: -p flag)
-s trace syscalls
Roadmap
- populate
/binwith 2.8 userland built by the cross-toolchain; runsh - job-control signal set (SIGCHLD etc.) for csh
- the toolchain's self-hosted bootstrap runs under apsim (stage gates)
Provenance / license
apsim.c was developed in the pdp11-bsd28-toolchain repository (split out
at toolchain commit 9d30f45); history prior to the split lives there. The
2.8BSD-derived runtime content falls under the Caldera ancient-Unix license.
Documentation
- Design — the PDP-11 CPU emulation, the a.out loader, and the syscall personality.
- User guide — running guest binaries, the guest root, and the options.