In this section, we will have a brief look at the ISA of the HP35, the first look into the system.
(The top image is a part of the cover of the advertisement brochure: HP35 technical data)
Note: To better understand this article, you need basic digital circuit and computer architecture knowledge. I'd recommend you read DDCA to have a brief look at both. The youtube video: How a CPU Works, is a very basic tutorial on CPU structure. Check 'em out!
FIG1. The HP 35 Internal Structural shown in HPJ 1972 issue 6.
FIG2. The HP 35 Motherboard (Source: the HP35 saga)
The HP35 architecture is very unique compared to the "classical" architectures. To understand what makes it tick, we can begin with the ISA. There's a page on hpmuseum.org that has a very comprehensive description of it.
In this passage, everything(register notion, mnemonics) will be written in the patent document format.
The original HP35 has 7 56-bit "arithmetic registers": A, B, C(X), D(Y), E(Z), F(T), and M. Each arithmetic register can hold 14 4-bit BCD encoded decimal number.
These registers are located in the ARC(Arithmetic and Register Circuit, also known as the A&R) chip. They are not usual general purpose registers, the transfers between them are very limited. As shown in the patent document of HP45
Fig3. The register transfer map (in ARC)
D, E, F are "stack registers" that can only be pushed or popped
A, B directly control the display when the display is enabled (More on that later)
In this map, only the registers in ARC is shown(which is one half of the CPU), no Program Counter or FLAGs register made their presence. Because in the original design, those registers belong to another half of the CPU: the CTC(Control and Timing Circuit, also known as the C&T) chip.
Control Registers (only the important ones)
[P(4)]: the pointer register, we'll talk about its use in the Word Select feature after this section.
[STATUS BITS(12)]: Just like a FLAGs register found in other CPUs. This register can be set, reset, tested, one bit each machine cycle.
[ROM ADDRESS(8)]: The Program Counter, Contains the address of the instruction that's to be fetched in this cycle. This register can only be set by the JSB (Jump to SuB) or BRH (BRancH) instruction.
[RETURN ADDRESS(8)]: You can RTN to this address after jumping to a subroutine via JSB.
[SYSTEM COUNTER(6)]: This register was designed for timing purpose. It's a 56-state self-increment counter that can be decoded for many timing control signals in the system. All chip mentioned(ARC, CTC, and ROM) contain their own version of the system counter(potentially implemented in different ways). They are synced by the SYNC line mastered by the CTC. This register can't be directly accessed by the programmer.
[KEY-CODE BUFFER(6)]: Once a key is pressed, this buffer will be filled with the content of the [SYSTEM COUNTER] (as mentioned, the sys counter was for timing purpose, the keyboard is accessed one by one in a machine cycle, and a pressed key will make its presence at a specific time. We can determine the pressed key's keycode by looking at the timing register.), this register can't be directly accessed by the user in earlier models.
All of these registers made their presence in the CTC chip.
There're many single-bit flip-flops in the design. A noticeable one is the :
[ROM ENABLE FF]: Each 256*10bit ROM chip contains one of these. The ROM chips are hard-wired to respond to one of the 8 possible ROM SELECT instructions. And these FFs will be set or reset to determine whether the current ROM is enabled or not. In HP35, there're 3 ROM chips. Later models contain QUADROM chips that, as the name suggests, contains 4 independent ROM chips.
BCD Arithmetic: In earlier HP models, everything is done in "decimal" fashion. The ARC only does 4-bit BCD arithmetic and no hexadecimal result should be found in those register (Later models added binary mode, enabling binary calculations).
HP assigned specific meaning for every section of a 56-bit arithmetic register, those sections were called "Fields". A picture from hpmuseum shows it clearly:
(The "Sign" and "Exponent Sign" fields are also 4-bit BCDs. digit "9" represents the negative sign.)
One might think that those "fields" have no real meaning, and the programmer can give their own version of field assignment. This is sometimes true, but the hardware was designed in a way that made this field division the most optimistic (for floating point arithmetic). We'll see why in a moment.
There're 8 fields defined(copied from hpmuseum):
|MS||101||Mantissa and Sign|
|P||000||Pointer (The nibble indicated by the P register)|
|W||011||Word (the entire register)|
|WP||100||Word up to and including nibble indicated by P register from right to left. For example, if P=3, WP would refer to nibbles 0, 1, 2, and 3.|
WS: WS or "Word Select" is a very unique and important feature of HP calculator architectures.The programmer can decide which part of the register that is the destination of an arithmetic operation "can be changed", and the non-WS'd part will remain the same.
An example: Say if we want to shift left only the mantissa part of register A. We can execute the instruction "SHIFT LEFT A [M]" where "[M]" stands for the Mantissa Field.
(Hexadecimal, remember we're talking about BCD numbers)
Fascinating! This "WS" feature is available for almost any operation that's executed in the ARC chip. Including "reg1 EXCHANGE reg2" and "0 -> reg". This feature has made HP architecture extremely powerful when it comes to decimal floating point arithmetic.
But I can't help thinking: how's that possible? It would be over-complicated if you're about to implement it in a parallel fashion. 4bit by 4bit serial micro-coded calculation is also not very elegant. But after we have a look at the "bit-serial" architecture that's going to be discussed in the next article. You'll immediately see why this feature made its presence. And how easy it is to implement such a feature in this architecture.
As mentioned, the calculator supports up to 8 ROMs paging. With 8-bit addressing capability, the calculator is capable of handling 2048 words ROM access. (Later models even added "ROM banking", each ROM bank can contain up to 8 ROMs.)
The HP architecture only supports direct addressing. Namely:
- JSB address,
- BRANCH address: Also known as "GOTO address", actually"IF NO CARRY GOTO address"
- ROM SELECT n
- KEY -> ROM ADDRESS: A special one.
The first four are quite general, but the last one is special. It actually substitutes the content of [ROM ADDRESS] register by [KEYCODE BUFFER] (with 2 zeros to make an 8-bit address) to jump to the address indicated by the keycode.
By today's standard, the ROM paging method in early HP models is horrific. First of all, bear in mind that it has no indirect addressing capability, and the programmers have no way to do manual indirect addressing using the "compare and jump" method since there're only have 256 instructions per page, 3 working registers, and no RAM. The reason why I said it's horrific is that after a "ROM SELECT n", the program counter remains the same (+1). Get it?
After this programming nightmare (I can hear the HP engineers saying "Fk it, that's how your grandpa did programming in the 70s, kid."), in later models a set of "DELAYED SELECT" instructions were added, allowing programmers to trigger a ROM select but change the ROM page only when a jump instruction is fetched sometime after the "DELAYED ROM SELECT n" instruction.
Try it out
CCE33 written by Tony at teenix.org is a full-featured microcode emulator and development environment for the entire LED classic series. The software allows you to see into a calculator, modify and interpret the assembly code, do dynamic memory monitoring and edit registers directly. On his website there're microcode files for almost every HP LED calculators ever made.
The author has also written a PIC based emulator called MultiCalc. One can connect the hardware to PC and download modified microcode to it thru CCE33. You can purchase a kit on his website, or with the files he released, you can make one yourself.
HP35 Instruction List
The detailed instruction list is very long. The following content is based on the opcode map provided by George Weigt in this forum article. HP45 specific (RAM chip access) opcodes were omitted.
|Type 00 Misc Instructions|
|nnnn_0001_00||1 -> Sn||Set status bit n|
|nnnn_0011_00||n -> P||Set P register|
|nnn0_0100_00||ROM SELECT n||Switch to ROM page n|
|0011_0100_00||KEY -> ROM ADDRESS||Jump to KEY|
|nnnn_0101_00||IF Sn = 0||Check status bit n|
|0000_0111_00||P - 1 -> P||Decrement P register|
|nnnn_1001_00||0 -> Sn||Clear status bit n|
|00101_010_00||C EXCHANGE M|
|01001_010_00||C -> STACK|
|01101_010_00||STACK -> A|
|10101_010_00||M -> C|
|11001_010_00||DOWN ROTATE||Just like the RDN key on the keyboard|
|nnnn_1011_00||IF p # n|
|0000_1100_00||RETURN||Return from a subroutine|
|0000_1101_00||CLEAR STATUS||Clear all status bits|
|0000_1111_00||P + 1 -> P||Increment P register|
|Type 01 & 11 Branching Instructions|
|aaaaaaaa_01||JSB addr||Jump to address, store return address|
|aaaaaaaa_11||(THEN) GO TO addr||If no Carry, jump to address|
|Type 10 Arithmetic Instructions|
|00000_fff_10||IF B[f] = 0||?B#0|
|00001_fff_10||0 -> B[f]||B=0|
|00010_fff_10||IF A >= C[f]||?A<C|
|00011_fff_10||IF C[f] >= 1||?C<1|
|00100_fff_10||B -> C[f]||C=B|
|00101_fff_10||0 - C -> C[f]||C=-C|
|00110_fff_10||0 -> C[f]||C=0|
|00111_fff_10||0 - C - 1 -> C[f]||C=-C-1|
|01000_fff_10||SHIFT LEFT A[f]||A SL|
|01001_fff_10||A -> B[f]||B=A|
|01010_fff_10||A - C -> C[f]||C=A-C|
|01011_fff_10||C - 1 -> C[f]||C=C-1|
|01100_fff_10||C -> A[f]||A=C|
|01101_fff_10||IF C[f] = 0||?C#0|
|01110_fff_10||A + C -> C[f]||C=A+C|
|01111_fff_10||C + 1 -> C[f]||C=C+1|
|10000_fff_10||IF A >= B[f]||?A<B|
|10001_fff_10||B EXCHANGE C[f]||BC EX|
|10010_fff_10||SHIFT RIGHT C[f]||C SR|
|10011_fff_10||IF A[f] >= 1||?A<1|
|10100_fff_10||SHIFT RIGHT B[f]||B SR|
|10101_fff_10||C + C -> C[f]||C=C+C|
|10110_fff_10||SHIFT RIGHT A[f]||A SR|
|10111_fff_10||0 -> A[f]||A=0|
|11000_fff_10||A - B _> A[f]||A=A-B|
|11001_fff_10||A EXCHANGE B[f]||AB EX|
|11010_fff_10||A - C -> A[f]||A=A-C|
|11011_fff_10||A - 1 -> A[f]||A=A-1|
|11100_fff_10||A + B -> A[f]||A=A+B|
|11101_fff_10||A EXCHANGE C[f]||AC EX|
|11110_fff_10||A + C -> A[f]||A=A+C|
|11111_fff_10||A + 1 -> A[f]||A=A+1|