SearchA-ZH › HP-35

HP-35

1972 Open source · GPL-3.0 Online

This is a browser build of the HP-35, the world's first handheld scientific calculator - the 1972 machine that made the slide rule obsolete. The HP-35 is built on HP's first-generation Classic chipset - a 56-bit serial BCD processor (the CTC and ARC chips) - and boots to its red LED display showing 0., ready for RPN entry. The core is written from scratch in JavaScript, ported behaviour-for-behaviour from Eric Smith's nonpareil, so the whole machine - the Classic microcode ROM, the working registers and the scanned LED display - is emulated with no wasm.

Because the loop is ours, the Classic plugs into the shared debugger: single-step the processor, read and write the A/B/C/D/E/F/M field registers, disassemble the ROM, and set breakpoints and register write-watchpoints. Type on the on-screen HP-35 keyboard or your physical keyboard (Escape = CLR, Backspace = CLx). The bundled ROM is the original first-production HP-35 microcode (© Hewlett-Packard, self-hosted here for emulation), which famously carries the early exp/trig rounding bugs.

Core project (nonpareil) ↗

Visit the official site ↗

Runs on: Web browser

HP-35 Online Emulator

Play HP-35 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
HP-35 RPNHP-35HP-35greyOpen ⛶

Machines emulated

Chips

Notes

Embedding

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

// 1. the system ROM image, 2. the Classic core + display scanner, 3. our boot loop
<script src="hp35-rom.js"></script>       // window.HP35_ROM: 768 10-bit words (3 ROM chips)
<script src="hp35-classic.js"></script>   // window.HP35Classic(rom) -> the machine

Boot. The Classic never sleeps: on power-up the CPU simply starts executing at address 0, which on the HP-35 is the CLR key handler - so a plain reset settles the machine to the 0. display. Construct the machine, run a warm-up, then paint the 15-digit red LED display each frame from the A (digit) and B (format) registers:

var M = HP35Classic(HP35_ROM);
M.reset();
for (var i=0; i<120000; i++) M.step();   // power-on -> CLR -> "0."
(function loop(){
  for (var i=0; i<budget; i++) M.step();   // one Classic instruction each
  render(M.segments());                 // 15 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 Classic instruction (on this CPU one cycle IS one instruction). The single-step primitive.
M.a / M.b / M.c / M.d / M.e / M.f / M.mfieldThe seven 56-bit working registers as 14-nibble arrays. C/D/E/F are the RPN stack X/Y/Z/T, A/B double as the display registers, M is the STO/RCL store. Also M.p, M.s[], M.pc, M.rom, M.group, M.retPc, M.carry.
M.getUcode(a)methodRead a 10-bit ROM word (side-effect free), for the hex/disassembly views.
M.press(kc) / M.release()methodPress/release a key by Classic hardware keycode (the ROM address the key jumps to) - how both the on-screen keyboard and the physical keyboard inject keys.
M.segments()methodThe 15 current 7-segment display bitmaps (segments a-g plus a decimal-point cell) for the canvas.

Debugger integration

The plug-in (hp35-debug.js) reads the live core from window.EMU_BOOT and calls EmuKit.defineMachine with a transport, the Classic register set and the memory. The disassembler is a new /debugger/src/cpus/hp-classic.js (a port of nonpareil's proc_classic.c op map), registered as decoder hp-classic.

The Classic 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 one-level subroutine call jsb (8-bit ROM target), 10 the field-select arithmetic on A/B/C over one of eight fields (p m x w wp ms xs s), and 11 the branch-if-no-carry goto. The misc table is built the exact same way init_ops builds the executable op table, so disassembly and execution stay in lock-step. One wrinkle: the shared hex/disasm views mask memory reads to 8 bits, but Classic words are 10 bits - so the embed publishes window.CLASSIC_WORD_READ and the decoder pulls full-width words through it.

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. The HP-35 has no continuous memory, so a plain reset boots to 0. (power-on runs the CLR handler at address 0). Breakpoints are a host-side Set of ROM word addresses ((group<<11)|(rom<<8)|pc): when any are set the loop steps one instruction at a time and compares the fetch address. Write watchpoints sample the machine's data words - the seven working registers A/B/C/D/E/F/M, the HP-35's only read/write store (STO/RCL live in M) - after each stepped instruction and halt on a change, so a write to any watched nibble trips them. A/B/C etc. are 56 bits, shown as a low and a high 28-bit half.

Architecture

The HP-35 (1972) is the world's first handheld scientific calculator - the machine that made the slide rule obsolete - built on HP's first-generation Classic chipset: the CTC (Control & Timing, HP 1818-0078) and ARC (Arithmetic, Register & Control, HP 1820-1169), a serial BCD processor.

  • Classic core - seven 56-bit working registers A B C D E F M (fourteen 4-bit digits each) operated a FIELD at a time (p m x w wp ms xs s). C D E F are the RPN stack X Y Z T; A and B double as the display registers (A holds the digits, B the format mask); M is the single storage register behind STO/RCL. There is a 4-bit digit pointer P, twelve status flags S0..S11, a carry, and a single-level subroutine return ret_pc. Arithmetic is always BCD decimal (the Classic has no hex mode).
  • ROM - the HP-35 operating system is 768 ten-bit words across three 256-word ROM chips (1818-0006, 1818-0017, 1818-0020). The address is (group<<11)|(rom<<8)|pc with an 8-bit program counter, a 3-bit ROM select and a 1-bit group; ROM/group changes are one instruction delayed, which is why the microcode pairs "select rom" with the following "go to".
  • Keyboard - each key latches a hardware keycode that is literally the ROM address its handler starts at; the idle loop, on seeing a key (status flag S0), does "keys -> ROM address" to jump straight there. ENTER pushes the stack; CLR (the power-on entry) clears everything.
  • Display - bare red LEDs, not an LCD: a hardware scanner walks register A digit by digit (word 13 down to 0) while register B selects the format - a digit shows when B≤7, words 2 and 13 are the exponent/mantissa sign (A≥8 shows "-"), and B=2 lights a decimal point in the next LED cell. Fifteen 7-segment positions in all.
  • Note on this ROM. The bundled dump is the original first-production HP-35 microcode, which carries the famous early rounding bugs (e.g. e^ln 2.02 not returning 2.02). It is the authentic 1972 code; HP later revised it.

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