SearchA-ZP › PDP-11

PDP-11

2013 Free · attribution Online

The PDP-11 is Digital Equipment Corporation's 16-bit minicomputer, launched in 1970 and one of the most influential computers ever made, the machine on which early Unix and the C language grew up. This entry runs Paul Nankervis's pure-JavaScript PDP-11/70, a faithful emulation of the top-of-the-range model, entirely in the browser.

By default it boots DEC RT-11 v4.0 to its . keyboard monitor over a VT52 serial console; a second configuration boots Bell Labs Unix V5. Because the whole machine - the CPU registers, the memory and the fetch-decode-execute loop - is ordinary JavaScript, it plugs into the site's in-page debugger: you can pause it, single-step real PDP-11 instructions, set breakpoints and watchpoints, and read and write the R0-R7 registers, the PSW and memory live.

Visit the original emulator ↗

Visit the official site ↗

Runs on: any modern web browser

PDP-11 Online Emulator

Play PDP-11 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
RT-11 v4.0 consolePDP-11greyOpen ⛶
Unix V5 consolePDP-11greyOpen ⛶

Notes

Embedding

The emulator is Paul Nankervis's pure-JavaScript PDP-11/70. Vendor the engine (pdp11.js CPU core, fpp.js floating point, iopage.js device I/O page, vt52.js terminal, bootcode.js boot ROM) and load them in order. There is no wasm heap; the machine is plain objects on the global CPU.

Own the loop. The stock engine drives itself with a chain of setTimeout(pdp11Processor, 4) calls, which cannot be paused or stepped from outside. We disable that self-scheduling and call pdp11Processor() ourselves: a batch when running, or one instruction at a time for the debugger:

boot();                                  // load boot ROM at 0120000, RUN
(function frame(){
  if (running) {
    if (breakpoints.size === 0) {
      pdp11Processor();                    // run a ~12ms batch of instructions
    } else {
      CPU.runState = 4;                    // STATE_STEP: exactly one instruction
      pdp11Processor();
    }
  }
  setTimeout(frame, 4);
})();

The machine is plain objects. Everything the debugger needs is a field or function on the global CPU:

MemberKindWhat it does
CPU.runState = 4; pdp11Processor()callRun in STATE_STEP: execute exactly one PDP-11 instruction, then halt. The single-step primitive.
CPU.registerValfieldThe live Uint16Array register file R0-R7 (R6 = SP, R7 = PC) - read and write directly.
readPSW() / writePSW(v)fnAssemble / load the 16-bit Processor Status Word (mode, priority and the N Z V C flags).
CPU.memoryfieldPhysical memory as 16-bit words (byte address >> 1); read side-effect-free for the memory view.
writeWordByPhysical(a,v)fnThe physical memory write path, wrapped host-side to implement watchpoints.
vt52Initialize(unit, recv, ...)fnThe DL11 registers its console receive routine here; we capture it to inject console keystrokes.

Because the CPU and memory are ordinary JavaScript, the debugger single-steps with a STATE_STEP call, reads and writes CPU.registerVal straight off the core, and implements breakpoints and watchpoints as host-side checks around the loop, no changes to the CPU decode.

Debugger integration

The plug-in (pdp11-debug.js) describes the machine to the shared debugger and nothing more:

  • Registers are read live from CPU.registerVal each refresh: R0-R5, SP (R6), PC (R7) and the full PSW, plus the N Z V C condition flags decoded from readPSW() - and written back through the same array and writePSW.
  • Disassembly uses the shared pdp11 decoder: a 16-bit word machine over byte-addressable, little-endian memory. At the RT-11 monitor the MMU maps virtual to physical one-to-one in low memory, so the disassembly at PC lines up with the code.
  • Memory is the low 64 KB of physical store, read straight from CPU.memory (side-effect-free, no bus cycle, so device I/O is never triggered).
  • Single step is one STATE_STEP call - a genuine single PDP-11 instruction; breakpoints (checked against PC) and watchpoints (wrapping writeWordByPhysical / writeByteByPhysical) are host-side checks around the loop.

Architecture

The PDP-11 is Digital Equipment Corporation's hugely influential 16-bit minicomputer (1970). This is a faithful PDP-11/70, the top of the line, with memory management and 22-bit physical addressing, implemented entirely in JavaScript:

  • CPU (pdp11.js) - the 11/70 instruction set with eight general registers (R6 = SP, R7 = PC), kernel/supervisor/user modes and the KT11 MMU. pdp11Processor() is the fetch-decode-execute loop.
  • FPP (fpp.js) - the FP11 floating-point processor.
  • I/O page (iopage.js) - the device registers at 0760000+: the DL11 serial consoles, the KW11 line clock, and the RK11 / RL11 / RP11 disk and TM11 tape controllers. Disk images are fetched by block (with a compressed .zst fallback via fzstd) and cached.
  • Console (vt52.js) - a VT52/VT100 hybrid glass terminal, rendered into a <textarea>, wired to the DL11 console line (unit 0).
  • Boot ROM (bootcode.js) - a small bootstrap loaded at 0120000 that prints Boot> and loads a guest OS from a disk unit.

The bundled RK05 pack (grey historic DEC software) carries RT-11 v4.0 on RK1 and Unix V5 on RK0. We auto-type boot rk1 so the machine comes up at the RT-11 "." monitor, a live, single-steppable minicomputer.