SearchA-ZH › HP-15C

HP-15C

1982 Open source · GPL-3.0 Online

This is a browser build of the HP-15C, HP's beloved advanced scientific RPN calculator - complex numbers, matrix arithmetic, root-finding (SOLVE) and numerical integration in a slim credit-card-sized case, launched in 1982. The HP-15C is a member of HP's Voyager series, built on the same HP Nut - a 56-bit serial BCD processor - as the HP-12C, and boots to its RPN display showing 0.0000, ready for entry. The core is written from scratch in JavaScript, ported behaviour-for-behaviour from Eric Smith's nonpareil, so the whole machine, the NUT microcode ROM, the nibble RAM, the memory-mapped Voyager LCD and the scanned keyboard, is emulated with no wasm.

Because the loop is ours, the Nut plugs into the shared debugger: single-step the processor, read and write the A/B/C/M/N field registers and nibble RAM, disassemble Nut code, and set breakpoints and RAM write-watchpoints. Type on the on-screen HP-15C keyboard or your physical keyboard (ESC = ON, ← = back), and reach the gold f and blue g scientific functions. The HP-15C system ROM is © Hewlett-Packard, self-hosted here (the redistributable nonpareil dump) for emulation.

Core project (nonpareil) ↗

Visit the official site ↗

Runs on: Web browser

HP-15C Online Emulator

Play HP-15C using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
HP-15C RPNHP-15CHP-15CgreyOpen ⛶

Machines emulated

Chips

Notes

Embedding

There is no upstream runtime to vendor: the HP Nut CPU, the Voyager LCD driver and the keyboard scanner are written from scratch in JavaScript, ported behaviour-for-behaviour from Eric Smith's nonpareil (proc_nut.c, digit_ops.c, voyager_lcd.c; GPL-3.0). Two plain-global scripts load in order:

// 1. the system ROM image, 2. the Nut core + Voyager LCD, 3. our boot loop
<script src="hp15c-rom.js"></script>   // window.HP15C_ROM: 12288 10-bit words (two ROM chips)
<script src="hp15c-nut.js"></script>   // window.HP15CNut(rom) -> the machine

Boot. Construct the machine, run the Nut from address 0 so the ROM powers on (a cold machine shows the authentic Pr Error continuous-memory message), tap a key to clear it so it settles to 0.0000, then paint the 11-digit 7-segment LCD each frame from the display registers:

var M = HP15CNut(HP15C_ROM);
runToSleep();                 // power-on -> deep sleep
M.press(0x18); runToSleep(); M.release(0x18); // ON -> "Pr Error"
M.press(0x81); runToSleep(); M.release(0x81); // any key clears -> 0.0000
(function loop(){
  for (var i=0; i<budget; i++) M.step();  // one Nut instruction each
  render(M.segments());               // 11 x 7-segment bitmaps -> canvas
  requestAnimationFrame(loop);
})();

The machine is ordinary objects - no wasm heap - so the debugger reaches every nibble directly:

MemberKindWhat it does
M.step()methodRun exactly one Nut instruction (one or more machine cycles). The single-step primitive.
M.executeCycle()methodRun one machine cycle: fire the per-cycle keyboard scan and LCD refresh, then execute one word.
M.a / M.b / M.c / M.m / M.nfieldThe five 56-bit working registers as 14-nibble arrays. Also M.g, M.p, M.q, M.fo, M.s[], M.pc, M.stack[], M.carry, M.decimal.
M.getUcode(a)methodRead a 10-bit ROM word (side-effect free), for the hex/disassembly views.
M.ramPeek/ramPoke(reg,nib)methodRead/write one RAM nibble with no side effects - the debugger's memory + watchpoint surface. RAM registers 9 and 10 are the live LCD bitmap.
M.press(kc) / M.release(kc)methodPress/release a key by Nut hardware keycode - how both the on-screen keyboard and the physical keyboard inject keys.
M.segments()methodThe 11 current 7-segment display bitmaps (with decimal/comma/annunciator bits) for the canvas.

Debugger integration

The plug-in (hp15c-debug.js) reads the live core from window.EMU_BOOT and calls EmuKit.defineMachine with a transport, the Nut register set and the memory. The Nut disassembler is the shared /debugger/src/cpus/nut.js - the same decoder the HP-41C and HP-12C use, because all three are the same HP Nut CPU.

The Nut decoder splits on the low two bits of the 10-bit word: 00 the large misc/special family (status, pointer, register moves, RAM & display I/O), 01 the two-word long branch (gosub/golong with a 16-bit absolute target), 10 the field-select arithmetic on A/B/C over one of eight fields (p x wp w pq xs m s), and 11 the short conditional branch. One wrinkle: the shared hex/disasm views mask memory reads to 8 bits, but Nut words are 10 bits - so the embed publishes window.NUT_WORD_READ and the decoder pulls full-width words through it, keeping true word addresses. The 15C's ROM is two 1.5K-word chips at 0x0000-0x17FF and 0x2000-0x37FF in one flat instruction space; the gap between them reads as 0.

What was customised for the debugger. The whole core is authored to be inspected: registers are read and written straight off the machine object, single-step is M.step(), and the run loop is ours. A cold-boot to 0.0000 was scripted (power-on, then a keystroke to clear the authentic Pr Error). Breakpoints are a host-side Set of 16-bit PC word addresses: when any are set the loop steps one instruction at a time and compares the PC. Write watchpoints sample the watched RAM nibble addresses after each stepped instruction and halt on a change, so a write anywhere on the RAM bus - including the memory-mapped LCD registers 9 and 10 - trips them. A/B/C/M/N are 56 bits, shown as a low and a high 28-bit half.

Architecture

The HP-15C (1982) is HP's beloved advanced scientific RPN calculator - complex numbers, matrix arithmetic, root-finding (SOLVE) and numerical integration in a slim credit-card-sized case - and a member of HP's Voyager series, built on the same HP Nut (a 56-bit serial BCD CPU, HP part 1LF5) as the HP-12C.

  • Nut core - five 56-bit working registers A B C M N (fourteen 4-bit digits each) operated a FIELD at a time (p x wp w pq xs m s), the two-digit scratch G, two 4-bit digit pointers P/Q, the 8-bit flag-output FO, fourteen status flags S0..S13, a 4-level return stack and a carry. Arithmetic runs in BCD decimal or hex mode. Program memory is 10-bit words.
  • ROM - the HP-15C operating system is twice the 12C's: two 1536-word pages (0x0000-0x17FF and 0x2000-0x37FF, 12288 10-bit words across two R2D2 chips, 1LE2-0321 and 1LH1-0302). It implements the RPN stack, the transcendental and statistical functions, the complex-number and matrix engines, and the SOLVE / integrate root-finders.
  • RAM - nibble-register data store spread over both chips: status/user registers 0x00-0x07 and 0x10-0x17, and the main store 0xC0-0xFF, each register 14 digits - the extra bank is what gives the 15C its larger program / data memory.
  • Voyager LCD driver - unlike the HP-41C's Coconut peripheral, the Voyager LCD is memory-mapped: the ROM writes the segment bitmaps straight into RAM registers 9 and 10 (on chip 0), and the driver reads them through a per-segment (register, bit) map to light an 11-digit, 7-segment display (segments a-g plus a decimal point, a comma tail and a per-digit annunciator). The segment map is identical across the Voyager family.
  • Keyboard - a scanned matrix; each key is a hardware keycode (column<<4 | row) latched into a buffer the ROM reads. The f (gold) and g (blue) prefixes select the alternate scientific function printed above/below each key. The ON key (0x18) wakes the Nut from deep sleep.

Every part is a plain JavaScript object, which is what makes the Nut a clear, fully steppable debugging target in the browser.