SearchA-ZH › HP-16C

HP-16C

1982 Open source · GPL-3.0 Online

This is a browser build of the HP-16C Computer Scientist, the only calculator HP ever made specifically for programmers - it works directly in hexadecimal, octal, binary and decimal, with bitwise logic (AND / OR / XOR / NOT), shifts and rotates, arbitrary word sizes (WSIZE), bit masks, and 1's / 2's complement arithmetic, launched in 1982. The HP-16C 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 HP-15C, and boots to its display showing 0 in HEX mode, 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 keypad, 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-16C keypad or your physical keyboard (ESC = ON, ← = back, hex digits 0-9 and A-F), and reach the gold f and blue g programmer functions - base switching (HEX / DEC / OCT / BIN), word size, logic, shifts and rotates. The HP-16C 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-16C Online Emulator

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

Configurations

ConfigurationEmulatorMachineOSLegal
HP-16C ProgrammerHP-16CHP-16CgreyOpen ⛶

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="hp16c-rom.js"></script>   // window.HP16C_ROM: 6144 10-bit words (one ROM chip)
<script src="hp16c-nut.js"></script>   // window.HP16CNut(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 in HEX mode, then paint the 11-digit 7-segment LCD each frame from the display registers:

var M = HP16CNut(HP16C_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 (hex)
(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 (0 = hex mode).
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 (hp16c-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, HP-12C and HP-15C use, because all four 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 16C's ROM is a single 6K-word chip at 0x0000-0x17FF in one flat instruction space.

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 (HEX mode) 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. The DEC flag reads 0 in the machine's default HEX mode.

Architecture

The HP-16C (1982) is the legendary programmer's calculator - the only one HP ever built specifically for programmers - working directly in hex, octal, binary and decimal with bitwise logic, shifts and rotates, arbitrary word sizes and 1's / 2's complement arithmetic. It is a member of HP's Voyager series, built on the same HP Nut (a 56-bit serial BCD CPU, HP part 1LF5-0301) as the HP-12C and HP-15C.

  • 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 hex or BCD decimal mode; the 16C spends most of its time in hex/integer mode. Program memory is 10-bit words.
  • ROM - the HP-16C operating system is a single 6144-word page (0x0000-0x17FF, 6144 10-bit words in one R2D2 chip, HP 1LE2-0322). It implements the RPN stack, radix conversion, the word-size / complement logic, the bit and shift/rotate operators, and the masking and floating-window display code.
  • RAM - nibble-register data store on the one chip: status/user registers 0x00-0x07 and the main store 0xE0-0xFF, each register 14 digits. This space is repartitioned on the fly between program steps and data registers as you change the word size.
  • 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, 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 top row doubles as the hex digits A-F. The f (gold) and g (blue) prefixes select the alternate programmer 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.