There are some interesting parallels between how the HP-65 card reader works and the new CRC instructions in the HP-67. There seems to be a bit more to it than we’ve heard before.
The HP-65 card reader is rather simplistic. It was the starting point. It worked well but it had some limitations and at the same time the simplistic hardware was complex to control. You’ve got a 600 bit shift register that is continuously rotating and you need to syncronise that with “what instruction am I looking for” and with “I’ve just loaded a card I need to write from the start”.
It’s quite messy in many ways but learning often comes from starting somewhere.
For the HP-67 they learned a lot and changed a lot. It is a vastly better system. Just look at the extras built into it: a control to tell you to load the second side, a write protect feature, checksumming and so on. There’s even extra microinstructions to allow the CPU to directly control the card reader.
The ’65 was almost entirely controlled by hardware – you poked a card in and the circuitry did something. The ’67 is almost entirely controlled by software – it often tells YOU to put the card in.
A lot changed. A lot.
What is less understood is that some things haven’t changed. There are some surprising parallels between the two.
With the HP-65 you’d control the card reader by setting or waiting for f flags. These are similar to the s flags and are separate to the F register (which contains 14 binary-coded decimal (BCD) digits like the other general purpose registers). With the ’65 you’d do things like wait for f5 to get to zero (card reader not busy), set or wait for f2 (card reader memory at start), or check if f0 is set. An example is:
12042: dflt1: 0 -> f5 12043: if s11 # 1 12044: then go to dflt1 12045: 0 -> f5 12046: return
With the HP-67, the f flags are gone and we have CRC instructions instead. The CRC instructions are vaguely named, at least in the microcode that we see outside of where it was developed. We see instructions like:
00131: CRC 1500 00132: if 1 = s 3 00133: then go to 0257
There is no information present in the instruction name (CRC 1500) that tells you what it does. We have a good idea of what it does do (check if we need to wait for side2) because some people in the past spent a lot of time reverse engineering it. All of the other CRC instructions are similar – they have “number names” and no obvious indication of what they do.
There is also a tantalizing almost-pattern to them too. They all end in “00” or “60”. They look like they are a not quite complete set. There are similarities in similarly numbered instructions.
For example, “CRC 260” turns the motor on and “CRC 360” turns it off; “CRC 660” turns write-mode on and “CRC 760” turns it off. There is a suggestion of a pattern there; but it isn’t evident across all of what was reverse engineered. For instance “CRC 560” is “card insert detected” rather than turning anything on or off.
The trick to the mystery is looking at the binary for the CRC opcodes, and then COMPARING them to the older HP-65 instructions.
Here’s the HP-67 CRC opcodes:
|0||0 00x 000 000||CRC 000 - not used/valid||CRC 100 - ready?|
|1||0 01x 000 000||CRC 200 - not used/valid||CRC 300 - W/PRGM?|
|2||0 10x 000 000||CRC 400 - set keypressed||CRC 500 - keypressed?|
|3||0 11x 000 000||CRC 600 - not used/valid||CRC 700 - not used/valid|
|4||1 00x 000 000||CRC 1000 - set defaults||CRC 1100 - defaults?|
|5||1 01x 000 000||CRC 1200 - set merge||CRC 1300 - merge?|
|6||1 10x 000 000||CRC 1400 - set side2||CRC 1500 - side2?|
|7||1 11x 000 000||CRC 1600 - not used/valid||CRC 1700 - r/w operation|
|0||0 00x 110 000||CRC 060 - set digits||CRC 160 - digits?|
|1||0 01x 110 000||CRC 260 - motor on||CRC 360 - motor off|
|2||0 10x 110 000||CRC 460 - not used/valid||CRC 560 - card?|
|3||0 11x 110 000||CRC 660 - write mode||CRC 760 - read mode|
Here’s the HP-65 f flag opcodes:
|0||0 00x 100 000||1 -> f0||0 -> f0|
|1||0 01x 100 000||1 -> f1||0 -> f1|
|2||0 10x 100 000||1 -> f2||0 -> f2|
|3||0 11x 100 000||1 -> f3||0 -> f3|
|4||1 00x 100 000||1 -> f4||0 -> f4|
|5||1 01x 100 000||1 -> f5||0 -> f5|
|6||1 10x 100 000||1 -> f6||0 -> f6|
|7||1 11x 100 000||1 -> f7||0 -> f7|
Aside from the CRC opcodes ending in 00 or 60 and the f flag ones ending in 40, there is a similarity in the first 4 bits of the code. All three sets of instructions start with “nnnx” where “nnn” is a number from 0-7 and “x” is 0 to “set” something (or “1 -> something”); or 1 to test something or clear (“0 ->”) something.
One of the interesting twists with the f flags in the HP-65 was that you’d test them by setting them to 0. This is like the “test cleared” flags in the HP-67 user programs. Testing the flag also clears it. With the HP-65 microcode, you’d set an f flag to 0 and, if it was previously a 1, the s11 flag would get set. This is why you see sequences like:
12042: dflt1: 0 -> f5 12043: if s11 # 1
The code suggests you are clearing the f5 flag; but f5 is connected to the HP-65 card reader ready/busy wire. You are not able to change the state of that from the CPU. It is an input. If the card reader was busy and it isn’t now, the instruction will zero f5. The wire from the card reader is already low/off so it works and s11 gets set on the transition from 1->0. If the card reader was busy and it still is, nothing happens. f5 stays at 1 and s11 stays as it was. If the card reader wasn’t busy and f5 had previously been tested/cleared, f5 stays cleared. No transition from 1->0 occurs and s11 doesn’t get set either.
This is how the f flags get tested: set them to 0 and see if s11 is set.
Interestingly, the HP-67 CRC instructions that test things, all set the s3 flag if the thing tested was set. This is not that different to the HP-65 setting the s11 flag. Most (all?) of the CRC opcodes that test things, also clear what they are testing.
If the CRC instructions follow the same opcode pattern, and if the f flag instructions test/clear the flags, there’s a good chance that the CRC instructions are working the same way.
The “CRC 360 – Motor Off” command could be considered as “Motor?” with a side-effect of clearing (turning off) the motor. It would be interesting to see what happens to the s3 flag in a real HP-67 after you issue the “motor off” command. My guess is that, if the motor was on beforehand, s3 would get set.
“CRC 760 – read mode” could be considered “write?” with a side effect of clearing write mode. Again, you could tell by seeing if s3 is affected on a real calculator.
“CRC 1700 – r/w operation” does a lot of things. After you’ve turned on the motor and selected read or write mode, it transfers 7 nibbles of data between a storage register and the magnetic card. It’s a lot more than just a flag. That said, it is likely that clearing this bit sends a syncronising signal to the card reader circuit that starts the transfer of 28 bits.
This is more for understanding than a statement of what is physically inside the box. After the serial data from the CPU is converted inside the CRC chip to a set of values to go into a logic element, the rest of the CRC could be considered as:
Power ----*---- | +-------+ s3 <----| | | |<----> i/o 0 | |<----> i/o 1 n ----->| |<----> i/o 2 n ----->| |<----> i/o 3 n ----->| |<----> i/o 4 | |<----> i/o 5 x ----->| |<----> i/o 6 | |<----> i/o 7 enable->| | +-------+ | ----- / / /
“Enable” selects the chip if the lower 6 bits of the opcode is 00 or 60 (for a HP-67), or if it’s 40 (for a HP-65).
The i/o lines get wired up to different things. With a bit of thought, any of the i/o lines can be wired up as an output (to control something) or as an input (where you check if something was high then went low and set the s3 output).
For a HP-67 the CRC nnnx00 chip connects to:
i/o 0 <-- card reader ready i/o 1 <-- the W/PRGM switch i/o 2 x not connected. internal flag "keypressed". i/o 3 x not connected. not used. i/o 4 x not connected. internal flag "defaults". i/o 5 x not connected. internal flag "merge". i/o 6 x not connected. internal flag "side2". i/o 7 --> card reader sync/start
For a HP-67 the CRC nnnx60 chip connects to:
i/o 0 x not connected. internal flag "digits". i/o 1 --> motor i/o 2 <-- card present. i/o 3 --> write mode. others unused
A similar list could be done for the HP-65 nnnx40 f flags and what they get connected to. (The “s3 <---" pin would be "s11 <---" on a HP-65).