Enter RPN

Files in hp15c/EML/ of trunk
Login

Files in hp15c/EML/ of trunk

Files in directory hp15c/EML from the latest check-in of branch trunk


EML/Suite for the HP-15C

This is EML/Suite ported to the HP-15C, SwissMicros DM15, and assorted simulators and emulators.

Rather than key in all this code on-device, I wrote the source code in the one true programmer’s text editor,1 then used rejig to produce the program file:

$ rejig Suite.hp15c -o Suite.15c

Or, thanks to the provided Makefile, just say make.

The result may be loaded into any of the machines linked above. I got much use of Torsten Manz’ simulator in producing this port, both directly on my development machines and as a USB I/O bridge to my DML15L and HP-15C Collector’s Edition, facilitating the benchmarks below.

Usage

This suite’s subroutines had to be renamed from those in the reference implementation to fit within the label scheme used on the 15C family. Rather than give rejig free rein in mapping names, I chose mnemonics:

Label Fn Stk Description, Mnemonic
A `y+x` 3 Add
B `y×x` 2 multiply By
C `π` 4 𝜋 = Circle ratio
D `y-x` 1 Debit = subtract
E `eml(x,y)` 0 Exp-Minus-Log
0 `0` 2 0 = zero
1 `ln(x)` 1 natural log; 1 ≈ “l”
2 `2` 3 2
3 `exp(x)` 1 3xponential, `e^x`
4 `x^2` 3 square = 4-sided
5 `sqrt(x^2+y^2)` 4 hypot; 5/4/3 triangle
6 expit(x) 3 logistic sigmoid; 6 ≈ sig
7 Im 1 7th heaven = imaginary
8 BPA 4 ballpark accuracy; 8-ball
9 none 4 stack usage test; 9=last
.0 `-x` 3 negate
.1 `-1` 3 negative 1
.2 `x÷2` 4 half = divide by 2
.3 `pow(x,y)` 2 power = .3xponent
.4 `sqrt(x)` 3 root = inverse of squaring
.5 `-x` 0 5 ≈ faux -x helper for D
.6 `avg` 4 averaGe; 6 ≈ G
.7 `y÷x` 2 divide; 7solidus
.9 `1÷x` 2 9vert (reciprocal)

Before running any of these, be sure your 15C is in complex mode by calling the 🟧 I function, above the TAN key.

Resources

Operands are consumed and replaced with results in the same manner as the builtin equivalents. Prior elements on the stack may be overwritten by intermediate results, but no “litter” is left behind.

The reference implementation uses the R47’s LocR feature to allocate local scratchpad registers at need. Lacking anything like that in the 15C series, this port uses global registers instead:

Regs Usage
R0-R1 general scratchpad
R3-R4 hypotenuse (LBL 5)
R5 ballpark accuracy test (LBL 8)

We need this many registers to avoid overlapping uses in nested calls even though it is never using more than two temporaries per subroutine.

Limitations

Labels

This port is incomplete primarily for lack of labels. The only one left is .8, and even then I had to drop inessentials and inline all the transcendentals into a monolithic ballpark accuracy test. The trigonometric and hyperbolic functions are present within subroutine 8, but without LBL targets and separate RTN for each, they aren’t readily called.

The scant mnemonics allowed by A-E and the predominance of numbered labels resulted in the jokey scheme you see above. I used English puns plus the rule that . labels are for inversions, divisions, and negations by riffing on .0 as the `-x` operation. Thus LBL 4 is for the squaring operation since squares are 4-sided, making the inverse `sqrt(x)` operation LBL .4.

Error 0

Since the HP-15C refuses to calculate `ln(0)=-oo`, we include a manual workaround for its lack. Unlike the HP-12C and HP-32S family ports, though, the 15C has full-featured complex number support, allowing it to calculate `ln(x<0)`, giving wide-ranging argument support to the included subroutines.

If you continue to get Error 0 while playing with this port, it is because you ignored the instruction above.

Subroutine Call Depth

Once you get beyond the division operation (LBL .7) the call depths exceed the 8-level call stack in the HP-15C.

Or they would, had I not perpetrated manual tail call optimization by replacing GSB+RTN pairs with GTO. This hack causes nearly all entrypoints to chain as one, with a final GTO E acting as the implicit RTN. The number of places I was able to do this makes perfect sense in retrospect since the very purpose of “1” in the EML scheme is to allow `eml(x,y)` to arrive at useful end-points.

I nevertheless chose to leave the RTN lines in, but purely because rejig does not yet recognize TCO, resulting in its --fmt feature indenting each LBL under the one prior as sub-sub-subroutines. These non-executing RTN calls allow make fmt to function sensibly.

Memory Use

The inclusion of the ballpark accuracy test (LBL 8) not only blows the original HP-15C memory limit, it pushes the size of the suite juuuust over the HP-15C Collector’s Edition’s expanded range. You can squeak it under that stock CE limit by removing the purely stylistic RTN calls mentioned above; that is, all except the ones terminating E, .5, and 7. Otherwise, you must shift an HP-15C CE into the double-memory mode via the hidden 15.2 option on the Easter egg menu to get this port of EML/Suite to fit.

None of that applies to the SwissMicros DM15 family or the common PC-based simulators. They lift this old limit sufficiently that you can use the code as-shipped.

Speed

When using an HP-15C simulator on a fast PC, it’s difficult to notice one of the several impracticalities of this software-coded version of EML: it’s terribly inefficient. On-device, things can begin to take human-scale time, though it remains easy to be misled; calculating `e` via 1 GSB 3 runs in an eyeblink even on that 1982 powerhouse, the original HP-15C, but realize that this is because it ends up calling into the native implementation of `e^x` after a few steps. Matters change when you ask it for something that should be as easy as 𝜋, via GSB C:

Device GSB Time Speedup
HP-15C 0:02:34 1.0
DM15L, 12 MHz 0:00:48 3.2
DM15L, 48 MHz 0:00:11 14.0
15C CE 0:00:01.8 85.5̅
Manz sim ~1 ms ludicrous

That’s bad enough, but let us now take the ballpark accuracy test via GSB 8:

Device GSB Time Speedup
HP-15C ~an hour 1.0
DM15L, 12 MHz 0:20:28 3-ish
DM15L, 48 MHz 0:04:45 14-ish
15C CE 0:00:40 86-ish
Manz sim a second plaid

Because it’s torture even on the fastest of these,2 once we set the simulator aside, I chose to estimate the baseline for this second test from the speedup column in the first. The alternative requires keying in the remaining ~250 instructions, then letting the machine cook for an hour while hovering with a stopwatch, never breaking attention long enough to skew the result meaningfully. Not gonna happen.

License

These programs are © 2026 by Warren Young and offered under the terms of the MIT License.


  1. ^ In this specific case Cursor with the Neovim plugin, but vi generically, being the proper baseline for writing software. I have spoken.
  2. ^ I did remove the redundant RTN lines since that affects the speed of the HP-15C’s scan-forward GSB/GTO implementation.