HP-55 Emulator Bug

The HP-55 was before my time. I never had one, never considered one and never used one. However, it seems to be the immediate predecessor to the HP-25 and I wondered, “how did we get to this point?” so I looked.

The problem though is: the very few HP-55 emulators that I found, don’t work. I know I’ve said similar things before, but it was true then too. Here’s the problem .

I only found two emulators. One fairly recent one in javascript; and the “mother of all inventions” – nonpareil.

Javascript

The javascript one did some strange things when you explored less commonly used (by scientific types at least) functions. The one sitting right there on the keyboard was ∑+. Press that and the world ends.

The microcode grinds to a complete halt and time, as it knows it, ceases to exist.

The cause is easily found, once you know to look for it. If you check the javascript errors for the page you’ll see one for it trying to access n[mem][i] (arithmeticAndRegister.js line 261). The problem is mem is 40 and there are only 30 data registers (including program storage) in a HP-55.

I’d like to thank Francois very much for doing his set of classic calculators. They are a really good starting point for understanding the older calculators. His collection also tends to be representative of our current state of knowledge of how the things worked. As a result, a bug in one of his is more likely to be due to the limits of what we know; rather than due to coding flaws.

Nonpareil

Eric’s nonpareil is the starting point for anything HP calculator related. I’m pretty sure that was start of microcode emulators.

I have a downloaded copy, probably version 0.79, and added the necessary GTK DLLs to run it on a Windows laptop.

It runs quite nicely and it does include a HP-55 emulation.

Pressing ∑+ on that one gives “1.00” which is what you’d expect.

So what’s different?

Having a look through Eric’s source code (it’s open source) shows there were still many things left to figure out. One of my favorites is a comment “I don’t know what this instruction is supposed to do!”. It is an honest and factual report of the state of play at the time. That one isn’t in the bit we’re interested in though.

The matching bit of code in nonpareil is protected by tests for invalid address values. There’s two bits, in proc_classic.c for op_c_to_data() and for op_data_to_c(), that either do nothing or set c to zero if the address value is out of range.

Nonpareil works because it doesn’t do anything (in these cases).

So does ∑+ actually work? It does seem to. You can do 8 ∑+ 9 ∑+ and then get an average of 8.5.

The fact that nonpareil works because it better guards against wrong values from the microcode; did get me really annoyed at whoever wrote the microcode for this calculator. Sending incorrect values to something for it to ignore, is really sloppy programming.

BUT the story isn’t quite that simple.

Whilst nonpareil APPEARS to work, if you look a little closer to tidy up loose ends, it doesn’t.

Try doing 4 STO . 4 RCL . 4″. You’ll get “0.00” in nonpareil and “4.00” (I assume) on a real calculator. I can’t find a HP-55 manual online but www.thimet.de created a quick reference that says statistical values are stored in registers “.0” through “.5”. If “STO . 4” isn’t working, why do the stats functions (∑+ etc) seem to work?

The count of items (n) is stored in “.0”, the total (∑x) is stored in “.1”. Those storage registers appear to work (you can STO to and RCL from them). “.2” seems to work but, as you’ll soon understand, corrupts programs. “.3” and above either crash (javascript) or disappear entirely (nonpareil).

If you put together an emulator for the HP-55 with logging so you can see where things go off the rails, you’ll see that a “STO n” looks like:

; (pressed STO then 5)
01402 12 -> p                            ; P= 12
01403 load 1                             ; C= 01500000000000 P= 11
01404 c + 1 -> c[x]                      ; C= 01500000000001
01405 c -> data address
...
01415 c <-> m                            ; C= 08500000000000 M= 00110020000905
*** c -> ram[15]
01416 c -> data

so “STO 5” uses ram[15]

A “STO . n” looks like:

; (pressed STO . 4)
01402 12 -> p                            ; P= 12
01403 load 1                             ; C= 01400000000000 P= 11
01404 c + 1 -> c[x]                      ; C= 01400000000001
01405 c -> data address
...
01515 a <-> c[w]                         ; A= 00110020000904 C= 04000000000000
01516 c -> data address
...
01415 c <-> m                            ; C= 05000000000000 M= 00110020000904
*** c -> ram[40]
01416 c -> data

so “STO . 4” sets up to use ram[14], realizes “.” was pressed, and changes to use ram[40] instead.

Now whilst changing one’s mind is messy, in the interests of fitting all this into limited ROM space, it might have worked out better to do it this way. The more important point though is: clearly, ram[40] is not what’s intended in a system with only 30 registers. ram[4] is a more likely intent for “STO . 4”.

It is no wonder nonpareil was having to guard against wrong address values.

It is also no wonder that “STO . 4” (and above, and “STO . 3”) were not storing anything.

The emulators really should store something when they are seeing values of 30, 40, 50, etc.

The interesting thing is the emulator code for “c -> data address” contains a comment saying “2 digits for HP-55”. That suggests it might have been 1 digit before then. One digit makes sense given what we’re seeing. That would give us “3”, “4”, “5” etc instead of “30”, “40”, “50” etc. One digit values work. Two digit ones don’t in the cases we’re looking at.

It can’t be something simple like a trailing “0” in digit position 2, or we’d never be able to access ram[10] or ram[20]. There has to be something else providing the clue or acting as a flag.

The obvious one in the code above, now we know to look, is c[0].

Every time we want a two-digit address, c[0] is 1. Every time we want/need/have to use a one digit address, c[0] is 0. See 01404 and 01515. I have done a number of additional tests and even added a “print statement” into the “c -> data address” statement to check what happens when I enter a program step. The c[0] value is always “1” for the newer, two-digit mode, and always “0” for single digit mode.

The Solution

Given what we’re seeing, this means we can change the javascript from:

function cdataaddr() {
	mem = 10*c[12] + c[11]; // 2-digit for HP-55 addressing
}

To:

function cdataaddr() {
	if (c[0]==0) mem= c[12];               // 1-digit for HP-55 and others
	if (c[0]==1) mem= 10*c[12] + c[11];    // 2-digit for HP-55 addressing
}

Perhaps it should be c[0]!=0 for two digit. Perhaps the door was left open for 1000 memories with c[0]==2 being three digit addresses. We’d need to write a ROM and feed instructions to the real thing and see what it does to know for sure. For now at least, the above fix (and equivalent for nonpareil and any C-based derivatives) seems to work well for the HP-55.

It's only fair to share...Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUponDigg thisPin on PinterestEmail this to someone

One thought on “HP-55 Emulator Bug”

  1. Congratulations Greg for your excellent analysis!

    This conditional 2-digit indexed C-register was probably created to ensure hardware backward compatibility with older Classic models.

    Under this new lighting, we could then build a single hardware emulator for all 6 Classic models, which would include the 30 memory (and program) registers of the HP-55 and even the 103 program steps user memory for the HP-65!

    With this conditional addressing, there will be no incompatibility between the 30 memory registers of the HP-55 and the 10 memory registers of the HP-45 and the HP-65.

    It is also probably in the same spirit that the multi-dot display mask for the HP-55 stopwatch (ie 0.00.00 00) uses the number 6 instead of the number 2 on all other Classic models, because all others never display more than 1 decimal dot simultaneously.

    Moreover it is already the case, since each JavaScript emulator (45, 55, 65, 70, 80) can load the firmware microcode of the HP-35 and work like it!

    It remains to verify this with a real HP-55, the one I inherited from Jacques Laporte (1946-2015).

    Thank you very much Greg for your essential contribution!
    Francois

Leave a Reply

Your email address will not be published. Required fields are marked *