Up

Here is the complete map of the HP35 ROM 0. All routines are programmed in three ROM chips (each of which contains 256 instructions of 10 bits each).

Only one of each is used at any time: if one is turned on, unselected ROMs turn off.

In the following tables, instruction addresses are given in octal.

I have never seen any original assembly listing of the HP35 ROMs. All information given below are pure reverse engineering.

Labels and symbolic instruction codes can be inferred from the HP45 "US Patent n° 4001569" listing.

Object code can be dumped by optical ways (P. Monta) or by electronic ways (E. Smith and J. Laporte).
ROM simulators had been developed and they reproduce faithfully the results given by the genuine hardware (even the bugs, if any).

I dumped myself (2006) -key by key- the object code of two real HP35 (old buggy ROM and new ROM) and could confirm bit by bit the object listing.    

As the HP35 micro code is now completely deciphered and understood, it could have been easy to "guess" the real labels of the unknown symbolic listing. For example, address 00376, labeled l00376 by Smith was certainly "rcl0" in the original listing, as it handles the RCL key and can be directly compared with its HP45 counterpart.

But I decided though to keep the original naming by Eric Smith for the sake of consistency.

This hard work has a story : One day at the beginning of the 80's, I found in San Francisco a book by James Farvour, “Microsoft Basic decoded & other mysteries” that I still own and open from time to time. Farvour commented step by step TRS-80's Rom : the Microsoft Basic.

At that time my HPs (35 and 65) were always close at hand.
I remember well having said to myself : I must do the same for the HP 35!
It took me 25 years!

Now the real stuff.

ROM 0 contains the code for:
- 35 KEY entry points,
- PWO routine,
- output format routine (formatting number in displayable and normalized forms back from math routines),
- data entry routine (number digits and exponents),
- stack push handling,
- part of add and sub routines,
- CHS handling,
- fix to floating point formatting,
- the main idle loop (wait a key and display routine).

All the operating software of the calculator is here.

ROM 0 existed in two versions:

- old 1972 version with 3 major bugs "CHS" handling, exp(ln(2.02), arc,
- new ROM end of 1972 and post 1972 models + updated models.

I explain below the mapping of the new ROM, but you can have a look at my explanation on the two major bugs: the "exp(ln (2.02))=2" and the "arc tan" bug.

(to fully understand the code, please refer to the corresponding pages, on this site).

1) Entry points

00000   jsb  00067 Key CLR Entry Points
00001   go to  00277 Error go to blinking display  
00002   0 -> s8 Key e^x When a key is hit, the row and column detected form a
00003   go to  00005 Key ln 6 bit key code and a “key down” signal is raised (status S0).
00004   1 -> s5 Key log This is only one hard wired flag S0.
00005   1 -> s9   In other machines (Woodstock) more flags are used
00006   1 -> s2 Key x^y (PRGM, battery ok, etc).
00007   goto   02010   The key code is “token”, a displacement to be added
00010   jsb  00264 Key RCL to 0000 to build the entry point address of the code
00011   go to  00376   serving the key. 
00012   go to  00027 Key STO For a math function key (eg. “sin”), the context is preserved
00013   go to  00060 Key ! (rdwn) and parameters are stored in the registers ; for a “digit key”
00014   stack -> a Key x <> y (forming a number) the exponent of register A (a[x]) is used ;
00015   go to  00331   saved before entering the entry point (eg. “dig6”) and restored after. 
00016   0 -> a[w] Key 1/x  Here are from (hp35 keyboard) top to bottom,
00017   a + 1 -> a[p]   the key codes (entry points) generated:
00020   0 -> b[w]    
00021   select rom 1 goto  asn12 CLR=0, which is also the entry point for PWO (slide ON)
00022 dig6 a + 1 -> a[x] Key "6" e^x = 02, "ln" =  03, "log" = 04, "x^y" = 06
00023 dig5 a + 1 -> a[x] Key "5"  
00024 dig4 a + 1 -> a[x] Key "4" tan = 50, "cos" = 52, "sin" = 53, "arc" = 54, "sqrt(x) = 56
00025   go to dig3    
00026   jsb  00232 Key "+" RCL = 10, "STO" = 12, "Rdwn" = 13, "x<>y" = 14, "1/x" = 16
00027   c exchange m Relay to "STO" routine  
00030   m -> c   CLX = 70, "EEX" = 72, "CHS" = 73, "ENTER^ = 76
00031   go to  00077    
00032 dig3 a + 1 -> a[x] Key "3" "9" = 62, "8" = 63, "7" = 64, "-" = 66,
00033 dig2 a + 1 -> a[x] Key "2"  
00034 dig1 a + 1 -> a[x] Key "1" "6" = 22, "5" = 23, "4" = 24, "+" = 26
00035   return    
00036   3 -> p Key "*" (mult) "3" = 32, "2" = 33, "1" = 34,"x" = 36
00037   0 - c -> c[x]    
00040   stack -> a   Pi=42, "." = 43,"0" = 44,"/" = 46
00041   go to  00020    
00042   go to  00164 Key PI The “arc” key is a prefix : it raises flag 10.
00043   3 -> p Key "," (dec. Point)  
00044   return Key "0' The memory locations of missing key codes (11, 15 etc) are used
00045   no operation   by the code at the start of the routine)
00046   go to  00040 Key "/" e.g. 00076 Key ENTER :
00047   1 -> s5 Relay for "sin" c -> stack
00050   1 -> s1 Key ""tan" clear status
00051   go to  00056   shift right a[w]
00052   1 -> s9 Key "cos" jsb fst2zx
00053   go to  00047 Key "sin" …/…
00054   1 -> s10 Key "arc"  
00055   go to  00302    
00056   0 -> b[w] Key SQR One exception though: missing key code 45 is a "no operation"
00057   goto   01060   the only case on the HP 35 ROM
00060   down rotate Relay for rotate  
00061   go to  00333   These entry points must be studied dynamically as part
00062 dig9 a + 1 -> a[x] Key "9" of the "display and wait" routine. This is the paradigm of this class
00063 dig8 a + 1 -> a[x] Key "8" of calculators (Classic, Woodstock, Spice etc.
00064 dig7 a + 1 -> a[x] Key "7" One entry point is not the location where control starts
00065   go to dig6   but where it passes to service a key.
00066   go to sub0 Key "-" (sub)  
00067   clear registers Relay for PWO and CLR General references are:
00070   jsb of12 Key Clx "The key code tokens"
00071   go to fst2zx   "The display and wait routine"
00072   go to eex2 Key EEX  
00073   shift right a[w] Key CHS Math key routines are explained in the dedicated chapter:
00074   1 -> s3   e.g. "ln" is described in "HP 35 Logarithm Algorithm"
00075   go to  00166   Utility routines activated by keys like "ENTER" are
00076   c -> stack Key ENTER described in
00077   clear status    
00100   shift right a[w]   “Status bit flags”,
00101   jsb fst2zx   “Digit Entry”.
      You should start with "HP35 Operating software",
       “Overall firmware architecture”.

2) Other code in ROM 0

00102 l00102: a -> b[w] Number format conversion Ref : “Output format”
00103   0 -> a[xs] 0102-0113  
00104   shift left a[ms] Routines 0102-0113 and 0340-0361 handle the 4 type of display and automatic conversion
00105 l00105: a - 1 -> a[x]  in scientific notation (SN):  
00106   if no carry go to l00340 1- numbers to be displayed as "100." : 107-346-361
00107   if c[xs] = 0 2- numbers to be displayed as ".01"   : 107-111-346-361
00110        then go to l00346 3- numbers to be displayed as "1 10-12  : 106-340-346-361
00111   a exchange b[ms] 4- numbers to be displayed as “1012” :106-340-346-361
00112   13 -> p (results > than 1010 or < are 10-2 automatically converted in SN).
00113   go to l00346    
      At 0106 the floating-point exponent sign (in A) is tested <> 0 : if no carry (<> 0)
       control branches at 0340, if carry (fp = 0) goto 0107.
      This is the two SN cases (no carry) forms like : "1 10-12 and “1012”
      At 0107 the normalized exponent signed is tested = 0 or not.
      If = 0 goto 0346 and not follow thru 110 etc.
      This is the two other cases : exp. sign = 0 (0346) forms like “100.” and exp sign <> 0
       forms like “.01” (decimal point first).
      Code between 0102-0113 is roughly sorting the 4 cases.
      Code between 0340–0361 is building the mask and adjusting floating point
      representation. The loop 0342-0105 is decrementing and SR A and
      decrementing pointer p is doing the SN conversion.
00114 eex7: p - 1 -> p Exponent building (loop "eex7-eex8")
00115   c + 1 -> c[x] Mask in B is used (swept from left to right) to build exponent part of C
00116 eex8: if b[p] = 0 in the loop "eex7"-"eex8"  
00117        then go to eex7    
00120   1 -> s11 number has been entered mantissa first (other case is "1 00")
00121   shift right a[ms] (tested in 0363)  
00122   a exchange c[m] Floating Point in A  
00123   if s4 = 0 S4=1 EEX has been pressed, if S4=0 goto "den1"
00124        then go to den1 (flag set in 0362)  
00125   jsb of14 Exponent entered with EEX, call output ofrmat
00126   go to fst2zx go display and wait  
00127 of11: 0 -> c[wp] OVER and UNDERFLOW conditions
00130   c - 1 -> c[wp] Math routines signal their out of limit status (exp C = 900 or 100)
00131   0 -> c[xs] display is built accordingly  
00132   a + b -> a[x] 9.999999999 or 0.  
00133   if no carry go to of13    
00134 of12: 0 -> c[w] CLR and PWO entry points
00135 of13: clear status Return form maths routine, format the output
00136   c -> a[w] build the output context (using normalized form in C, make FP in A and mask in B)
00137 of14: 12 -> p Init context  
00140   a -> b[x]    
00141   c -> a[x]    
00142   if c[xs] = 0 Normal negative or overflow/underflow ?
00143        then go to of15    
00144   0 - c -> c[x]    
00145   c - 1 -> c[xs]    
00146   if no carry go to of11 test for over/underflow  
00147   5 -> p    
00150 of15: a exchange c[x]    
00151   if s4 = 0 if EEX Not pressed goto 0102 (normal path)
00152        then go to l00102    
00153   a exchange b[x] If EEX key pressed  
00154   0 -> b[x] build the "1 00" mask  
00155   jsb dsp1    
00156   shift left a[x] and fall thru "eex3"  
00157 eex3: shift right a[w] Exponent entry (exponent digits)  Ref : “Digits entry”
00160   if p # 12 from eex2 0360 (see eex2 at 0363)
00161        then go to den7 if S11=0 mantissa entered, 2 cases
00162   a exchange c[wp] p=12, main case, eex4-eex5-eex6-eex7-eex8-0123-of14-fst2zx
00163   go to eex4 p=3 after a "." -> den7  
00164 l00164: jsb l00264 This is the code for the pi constant
00165   select rom 1 address = 1264  
00166 l00166: if s4 = 0 CHS entry point  
00167        then go to chs3 if EEX was pressed S4=1  
00170   a exchange c[wp] negate mantissa in C  
00171   0 - c - 1 -> c[xs] else goto "chs3" main entry point to negate C mantissa
00172 eex4: c -> a[w] Exponent entry (exponent digits)  Ref : “Digits entry”
00173   if c[xs] = 0 (this is new ROM algorithm, buggy old roms are different))
00174        then go to eex5 2 ways to enter exp digits:  
00175   0 -> c[xs] - sign digits "." digits  
00176   0 - c -> c[x] - sign digits EEX digits sign  
00177 eex5: 13 -> p Entry point is eex4 from den6
00200 eex6: shift left a[ms]    
00201   c - 1 -> c[x] When no exponent the loop 0204-eex6 preserves leading zeros (ex. "000123")
00202   if a[s] >= 1 The loop "eex8-exx7" actually build the normalized exponent in C
00203        then go to eex8 For numbers enterd with "." the âth is "den6" 0373 0375
00204   if a[ms] >= 1 For numbers entered with EEX the entry poin is "eex2 at 0362
00205        then go to eex6    
00206   0 -> c[x]    
00207 den1: jsb dsp1 Data entry (digits & numbers)  Ref : “Digits entry”
00210   shift right a[ms] A number is entered using numeric key, decimal point “.”, “EEX” key and CHS key.
00211 den7: c -> a[s] “den2” is the main entry point (the digit just got is in a[x]), pointer p = 12 when entering
00212 den2: if p # 12 digits but p=2 if dp “.” is pressed.
00213        then go to den4 Code between “den2” & “den4” places the new digit in place
00214   b -> c[w] according the current mask in B.
00215   c + 1 -> c[w] In "den3" digits are "slided" in place
00216   1 -> p Exit point is “den5” or “den6” whether dp has been used.
00217 den3: shift left a[wp] Normal exit thru “den6” updates the current mask (a digit can be part of a number).
00220   p + 1 -> p A call to “eex4” is made (regular entry point in EEX) to normalized the exponent in C.
00221   if c[p] = 0 If there is a “.” Control goes to “den5” and then “den6”
00222        then go to den3 where the current mask is updated.
00223 den4: a exchange c[w] This is the normal exit point.
00224   if p # 3 If no “.” control goes to “eex4” to form exponent in C
00225        then go to den5    
00226   0 -> c[x]    
00227   1 -> s6 (see "den 5" and "den6" below)
00230   go to eex4    
00231 sub0: 0 - c - 1 -> c[s] Floating point addition and subtraction (Ref: Floating point Arithmetic)  
00232 l00232: stack -> a If the operation is a subtraction, the code is exactly the same but entry point is "sub0"
00233   0 -> b[w] The first action of the code is to drop values from the stack, to have Y in A
00234   a + 1 -> a[xs] Next B is zeroed  
00235   a + 1 -> a[xs] Exponents of registers A and C are corrected so absolute values can be compared.
00236   c + 1 -> c[xs] The exponent comparison is by adding two to exponent and sign fields
00237   c + 1 -> c[xs] of both registers A and C.  
00240   if a >= c[x] At 0240 the comparison is done.
00241        then go to add4 If a[x] > = c[x] (exponent of C smaller then exponent of A), we will simply exchange
00242   a exchange c[w] both registers, so that the smallest number is always in C and the biggest in A.
00243 add4: a exchange c[m]    
00244   if c[m] = 0 Mantissa alignment : biggest fraction part will be shifted right (division by 10)
00245        then go to add5 and the exponent of biggest number will be incremented.
00246   a exchange c[w]    
00247 add5: b exchange c[m] Next in routine “add4”, exponent and fraction parts of both numbers
00250 add6: if a >= c[x] are separated. At “add6” fraction part alignment is done and exit at 0276
00251        then go to l00276 when both fractional part are aligned. In routine “add12”,
00252   shift right b[w] signs are processed to do the “addition” or “subtraction.
00253   a + 1 -> a[x]    
00254   if b[w] = 0    
00255        then go to l00276 goto "add12" thru a relay at 0276
00256   go to add6    
00257 fst3: 0 -> a[ms] Stack handling routine  
00260   if s3 = 0    
00261        then go to l00264    
00262   a - 1 -> a[s] If "CHS" flag S3=1  
00263   0 - c - 1 -> c[s] negate C mantissa sign  
00264 l00264: if s7 = 0 S7=1 automatic push  
00265        then go to fst5 S7 = 0 : no stack push  
00266   c -> stack stack push  
00267 fst5: 1 -> s7 mask as done  
00270   0 -> c[w] build mask for a digit "29999…999"
00271   c - 1 -> c[w]  
00272   0 - c -> c[s]  
00273   c + 1 -> c[s]  
00274   b exchange c[w]    
00275   return    
00276 l00276: select rom 1 relay to "add12" addr=1276  
00277 l00277: jsb of12 ERROR entry point  
00300   1 -> s5 Set flag for blinking display  
00301   go to fst2zx go to the farm  
00302 l00302: shift right a[w] DISPLAY AND WAIT FOR A KEY
00303 dsp7: c -> a[s] Entry point, called from disp1
00304 l00304: 0 -> s8    
305   go to dsp8    
306 dsp2: c + 1 -> c[xs]    
307 dsp3: 1 -> s8 dsp3-dsp5 Main IDLE loop  
310   if s5 = 0 In the middle of it, blink the display
00311        then go to dsp5    
00312   c + 1 -> c[x]    
00313   if no carry go to dsp2    
00314 dsp4: display toggle    
00315 dsp5: if s0 = 0 No key, so "once around"  
00316        then go to dsp3    
00317 dsp8: 0 -> s0 A KEY has been pressed  
00320 dsp6: p - 1 -> p    
00321   if p # 12 disp6-0322 : debounce loop  
00322        then go to dsp6    
00323   display off    
00324   if s8 = 0 make sure a key is served only once
00325        then go to dsp4    
00326   shift left a[w]    
00327   0 -> s5    
00330   keys -> rom address jump to token address  
00331 l00331: c -> stack Exchange x><y entry point
00332   a exchange c[w]    
00333 l00333: jsb of13 Return point Ref : “Digits entry”
00334   1 -> s7    
00335 fst2zx: jsb dsp1 00333 is the main return point when a math routine is completed.
00336   jsb fst3 A call to of13 is made to format the display (A & B with C)
00337   go to den2 Flag 7 is raised to request a stack push.
      Then back to the “display and wait” loop at “fst2zx”
      When a key is hit, the “return” instruction brings back to 00336 where the stack
      chore is made, before going servicing the key entry.
00340 l00340: shift right a[ms] Mask building routines Ref : “Output format”
00341   p - 1 -> p 0340-0361  
00342   if p # 2 Code between 0340-0345 is run only by SN numbers (FP exponent in A <> 0).
00343        then go to l00105 Numbers are converted if possible to fixed format : 1. 03 -> 1000
00344   12 -> p    
00345   0 -> a[w] Note that in the 35 this conversion occurs
00346 l00346: 0 -> a[ms] only on math routine return.
00347   a + 1 -> a[p]    
00350   a + 1 -> a[p] Code between 0346-0361 is positioning the decimal point
00351   2 -> p in the mask “.” = “2” and filling the digits to be blanked with “9”.
00352 l00352: p + 1 -> p This code decides if exponent is blanked or not :
00353   a - 1 -> a[p] if entry point is 0346 the exponent in the mask is “999” = blanked.
00354   if no carry go to l00357         
00355   if b[p] = 0         
00356        then go to l00352    
00357 l00357: a + 1 -> a[p]    
00360   a exchange b[w]    
00361   return    
00362 eex2: 1 -> s4 Exponent entry (exponent digits) Ref : “Digits entry” 0362-0365
00363   if s11 = 0 3 cases : Exponent entered with EEX ( eex key fist or after mantissa)
00364        then go to dig1 If EEX key : entry point is “eex2”, If EEX pressed first, goto dig1, to make mask "1 00"
00365   go to eex3 If not (mantissa built first) goto “eex3” to build the exponent. In C and the display mask.
00366 chs3: 0 - c - 1 -> c[s] CHS was used, negate C sign
         
00367 dsp1: 0 -> s10 Entry point in "display and wait a key" loop fom point "fst2zx"
00370   go to dsp7 Route back from math routines : 0333-"of13"-"fst2zx-"dsp1"
00371 den5: if s6 = 0 If s6=0 make room for the decimal point "."  
00372        then go to den6    
00373   p - 1 -> p If s6=1 make 2 places  
00374 den6: shift right b[wp]    
00375   jsb eex4 and "eex4" will build the mask accordingly
00376 l00376: m -> c The code for RCL  
    go to l00333 Place m into register C and back to the farm

 

J. Laporte
20 October 2006