Finally, here is the complete map of the HP35 ROM 2 (256 instructions of 10 bits each).
ROM 2 contains the
code for:
- Cordic routines for log (ln), ex and
xy,
- prescaling routines,
- mutiplication and division,
- and result normalization.
| 02000: | err21: | select rom 0 | goto blinking display (0001) | |
| 02001: | ln24: | a exchange b[s] | Computation of a new constant (2, 1.1, 1.01, 1.001 etc) | |
| 02002: | a + 1 -> a[s] | # SR ++ | ||
| 02003: | shift right c[ms] | Make room for the next qj | ||
| 02004: | shift left a[wp] | align left | ||
| 02005: | go to ln26 | |||
| 02006: | xty22: | stack -> a | ax is evaluated as ln(a) . x (see at 02074) | |
| 02007: | jsb mpy21 | |||
| 02010: | c -> a[w] | Main entry point for ex and log | ||
| 02011: | if s8 = 0 | If S8 = 0 -> ex | ||
| 02012: | then go to exp21 | If S8 = 1 -> log (ln) | ||
| 02013: | 0 -> a[w] | |||
| 02014: | a - c -> a[m] | Complement X for ln(X) | ||
| 02015: | if no carry go to err21 | Goto error if ln(negative) | ||
| 02016: | shift right a[w] | |||
| 02017: | c - 1 -> c[s] | |||
| 02020: | if no carry go to err21 | |||
| 02021: | ln25: | c + 1 -> c[s] | Prepare registers to compute pseudo quotients q0 q1 q5 | |
| 02022: | ln26: | a -> b[w] | ||
| 02023: | jsb eca22 | Call the "eca" routine to compute qj | ||
| 02024: | a - 1 -> a[p] | complementation | ||
| 02025: | if no carry go to ln25 | one more time for the same constant | ||
| 02026: | a exchange b[wp] | |||
| 02027: | a + b -> a[s] | # of SR x 2 | ||
| 02030: | if no carry go to ln24 | test for 5 constants only | ||
| 02031: | 7 -> p | Part 2 : pseudo multiplications to compute ∑ qj ln (1 + 10 j) | ||
| 02032: | jsb pqo23 | |||
| 02033: | 8 -> p | |||
| 02034: | jsb pmu22 | q5 ln(1.00001) | ||
| 02035: | 9 -> p | |||
| 02036: | jsb pmu21 | q4 ln(1.0001) | ||
| 02037: | jsb lncd3 | S2 S5 S9 | ||
| 02040: | 10 -> p | ln 1 0 1 | ||
| 02041: | jsb pmu21 | q3 ln(1.001) | log 1 1 0 | |
| 02042: | jsb lncd2 | ex 1 0 1 | ||
| 02043: | 11 -> p | xy 1 0 0 | ||
| 02044: | jsb pmu21 | q2 ln(1.01) | ||
| 02045: | jsb lncd1 | |||
| 02046: | jsb pmu21 | q1 ln(1.1) | ||
| 02047: | jsb lnc2 | |||
| 02050: | jsb pmu21 | q0 ln 2 | ||
| 02051: | jsb lnc10 | load ln 10 | ||
| 02052: | a exchange c[w] | |||
| 02053: | a - c -> c[w] | final sum, result in C | ||
| 02054: | if b[xs] = 0 | Exponent processing | ||
| 02055: | then go to ln27 | |||
| 02056: | a - c -> c[w] | |||
| 02057: | ln27: | a exchange b[w] | ||
| 02060: | ln28: | p - 1 -> p | p=12 on entry (nrm27) | |
| 02061: | shift left a[w] | SL A (A = X) | ||
| 02062: | if p # 1 | to prepare A and have A sign in 12th position | ||
| 02063: | then go to ln28 | and A exp digits in 11 and 10th positions | ||
| 02064: | a exchange c[w] | A -> C | ||
| 02065: | if c[s] = 0 | test sign of exponent | ||
| 02066: | then go to ln29 | |||
| 02067: | 0 - c - 1 -> c[m] | invert if negative | ||
| 02070: | ln29: | c + 1 -> c[x] | go to normalize C (mantissa in A, exponent in C) | |
| 02071: | 11 -> p | (eg if ln(7.3 1043) C = [04300 ] | ||
| 02072: | jsb mpy27 | |||
| 02073: | if s9 = 0 | case xy | ||
| 02074: | then go to xty22 | |||
| 02075: | if s5 = 0 | log or ln | ||
| 02076: | then go to rtn21 | |||
| 02077: | jsb lnc10 | if log -> multiply by ln(10) | ||
| 02100: | jsb mpy22 | return to normalize and loop. | ||
| 02101: | go to rtn21 | |||
| 02102: | exp21: | jsb lnc10 | Load ln(10) | |
| 02103: | jsb pre21 | prescaling x between 0 and 1 | ||
| 02104: | jsb lnc2 | pseudo division by repeating subtraction to find the qj | ||
| 02105: | 11 -> p | load ln(2) | ||
| 02106: | jsb pqo21 | compute q0 by pseudo division | ||
| 02107: | jsb lncd1 | load ln(1.1) | ||
| 02110: | 10 -> p | |||
| 02111: | jsb pqo21 | compute q1 by pseudo division | ||
| 02112: | jsb lncd2 | load ln(1.01) | ||
| 02113: | 9 -> p | |||
| 02114: | jsb pqo21 | compute q2 by pseudo division | ||
| 02115: | jsb lncd3 | load ln(1.001) | ||
| 02116: | 8 -> p | |||
| 02117: | jsb pqo21 | compute q3 by pseudo division | ||
| 02120: | jsb pqo21 | load ln(1.0001) compute q4 by pseudo division | ||
| 02121: | jsb pqo21 | load ln(1.00001) compute q5 by pseudo division | ||
| 02122: | 6 -> p | precision rectification to avoid algorithm flaw e ln(2.02) = 2 | ||
| 02123: | 0 -> a[wp] | |||
| 02124: | 13 -> p | Part 2 : Pseudo multiplication | ||
| 02125: | b exchange c[w] | |||
| 02126: | a exchange c[w] | |||
| 02127: | load constant 6 | |||
| 02130: | go to exp23 | ex = (1 + r) Π ( 1 + 10-j) qj | ||
| 02131: | pre23: | if s2 = 0 | Trigo prescaling | |
| 02132: | then go to pre24 | Θ - 2 π by repeated subtractions until remainder is between 0 and 2 π | ||
| 02133: | a + 1 -> a[x] | |||
| 02134: | pre29: | if a[xs] >= 1 | ||
| 02135: | then go to pre27 | |||
| 02136: | pre24: | a - b -> a[ms] | Sub in loop | |
| 02137: | if no carry go to pre23 | |||
| 02140: | a + b -> a[ms] | Restore one step too far | ||
| 02141: | shift left a[w] | Save accuracy | ||
| 02142: | c - 1 -> c[x] | # of decades in C | ||
| 02143: | if no carry go to pre29 | |||
| 02144: | pre25: | shift right a[w] | ||
| 02145: | 0 -> c[wp] | |||
| 02146: | a exchange c[x] | |||
| 02147: | pre26: | if c[s] = 0 | common part for prescaling trigo end ex | |
| 02150: | then go to pre28 | |||
| 02151: | a exchange b[w] | if sign is negative | ||
| 02152: | a - b -> a[w] | exchange A and C, A scaled argument B = ln(10) | ||
| 02153: | 0 - c - 1 -> c[w] | invert sign | ||
| 02154: | pre28: | shift right a[w] | Align A then follow thru pqo to compute pseudo quotients. | |
| 02155: | pqo23: | b exchange c[w] | Part of pseudo multiplication | |
| 02156: | 0 -> c[w] | This routine is use by ln, ex, direct and inverse trigov (s2=0) | ||
| 02157: | c - 1 -> c[m] | |||
| 02160: | if s2 = 0 | |||
| 02161: | then go to pqo28 | |||
| 02162: | load constant 4 | The rest of the code use to forge constants with repeated patterns (see note) | ||
| 02163: | c + 1 -> c[m] | |||
| 02164: | if no carry go to pqo24 | |||
| 02165: | pqo27: | load constant 6 | ||
| 02166: | pqo28: | if p # 1 | ||
| 02167: | then go to pqo27 | |||
| 02170: | shift right c[w] | |||
| 02171: | pqo24: | shift right c[w] | ||
| 02172: | nrm26: | if s2 = 0 | Use by ln or trigo | |
| 02173: | then go to rtn21 | trigo (S2=0) goto rtn21 | ||
| 02174: | return | and test S1 to do a "rtn12" or a "return" | ||
| 02175: | lncd2: | 7 -> p | Forge constant see note | |
| 02176: | lnc6: | load constant 3 | load part of constant | |
| 02177: | load constant 3 | ln(1.001) = 0.999500330850 | ||
| 02200: | load constant 0 | |||
| 02201: | lnc7: | load constant 8 | ||
| 02202: | load constant 5 | |||
| 02203: | load constant 0 | |||
| 02204: | load constant 9 | |||
| 02205: | go to lnc9 | |||
| 02206: | exp29: | jsb eca22 | ex processing by pseudo multiplication (called by exp21) after computation of pqj | |
| 02207: | a + 1 -> a[p] | |||
| 02210: | exp22: | a -> b[w] | ||
| 02211: | c - 1 -> c[s] | |||
| 02212: | if no carry go to exp29 | loop for the next call to eca22 | ||
| 02213: | shift right a[wp] | A/10 | ||
| 02214: | a exchange c[w] | |||
| 02215: | shift left a[ms] | next qj | ||
| 02216: | exp23: | a exchange c[w] | entry point | |
| 02217: | a - 1 -> a[s] | dec # of SR for a constant | ||
| 02220: | if no carry go to exp22 | test for a next cst | ||
| 02221: | a exchange b[w] | No the end | ||
| 02222: | a + 1 -> a[p] | Correct mantissa | ||
| 02223: | jsb nrm21 | Goto normalize | ||
| 02224: | rtn21: | select rom 1 | relay to "rtn11" | |
| 02225: | eca21: | shift right a[wp] | Exponent calculation in | ( 1 + 10-j) qj |
| 02226: | eca22: | a - 1 -> a[s] | ||
| 02227: | if no carry go to eca21 | do the #of SR for a cst | ||
| 02230: | 0 -> a[s] | |||
| 02231: | a + b -> a[w] | thA = A +B == B 1.01 if 2 SR | ||
| 02232: | return | |||
| 02233: | pqo21: | select rom 1 | relay to "pqo11" | |
| 02234: | pmu21: | shift right a[w] | ||
| 02235: | pmu22: | b exchange c[w] | Entry point for ln part 2 (pseudo multiplication) | |
| 02236: | go to pmu24 | |||
| 02237: | pmu23: | a + b -> a[w] | do the PM | |
| 02240: | pmu24: | c - 1 -> c[s] | dec count | |
| 02241: | if no carry go to pmu23 | |||
| 02242: | a exchange c[w] | keep accuracy | ||
| 02243: | shift left a[ms] | |||
| 02244: | a exchange c[w] | |||
| 02245: | go to pqo23 | another cst ? | ||
| 02246: | mpy21: | 3 -> p | Came from 01245 "mpy11" (pqo) | |
| 02247: | mpy22: | a + c -> c[x] | ||
| 02250: | a - c -> c[s] | |||
| 02251: | if no carry go to div22 | entry point for "div" | ||
| 02252: | 0 - c -> c[s] | |||
| 02253: | div22: | a exchange b[m] | ||
| 02254: | 0 -> a[w] | |||
| 02255: | if p # 12 | |||
| 02256: | then go to mpy27 | |||
| 02257: | if c[m] >= 1 | if FP of X > 0 then div23 | ||
| 02260: | then go to div23 | |||
| 02261: | if s1 = 0 | else blinking display | ||
| 02262: | then go to err21 | |||
| 02263: | b -> c[wp] | separate FP and Y | ||
| 02264: | a - 1 -> a[m] | and prepare A for repeated subtractions | ||
| 02265: | c + 1 -> c[xs] | C holds the count | ||
| 02266: | div23: | b exchange c[wp] | ||
| 02267: | a exchange c[m] | |||
| 02270: | select rom 1 | go to 01271 | ||
| 02271: | lnc2: | 0 -> s8 | load ln(2) | |
| 02272: | load constant 6 | 0.6931471 | ||
| 02273: | load constant 9 | |||
| 02274: | load constant 3 | |||
| 02275: | load constant 1 | |||
| 02276: | load constant 4 | |||
| 02277: | load constant 7 | |||
| 02300: | load constant 1 | |||
| 02301: | go to lnc8 | +0.000000080553 | ||
| 02302: | pre27: | a + 1 -> a[m] | Part of prescaling for ex | |
| 02303: | if no carry go to pre25 | |||
| 02304: | myp26: | a + b -> a[w] | Use by addition (place saving) | |
| 02305: | mpy27: | c - 1 -> c[p] | ||
| 02306: | if no carry go to myp26 | |||
| 02307: | mpy28: | shift right a[w] | ||
| 02310: | p + 1 -> p | Normalization process | ||
| 02311: | if p # 13 | |||
| 02312: | then go to mpy27 | Right scaling loop | ||
| 02313: | c + 1 -> c[x] | |||
| 02314: | nrm21: | 0 -> a[s] | FP in A | |
| 02315: | 12 -> p | EXP in C | ||
| 02316: | 0 -> b[w] | Left scaling | ||
| 02317: | nrm23: | if a[p] >= 1 | SLA and adjust EXP | |
| 02320: | then go to nrm24 | |||
| 02321: | shift left a[w] | |||
| 02322: | c - 1 -> c[x] | |||
| 02323: | if a[w] >= 1 | |||
| 02324: | then go to nrm23 | Left scaling loop | ||
| 02325: | 0 -> c[w] | |||
| 02326: | nrm24: | a -> b[x] | ||
| 02327: | a + b -> a[w] | |||
| 02330: | if a[s] >= 1 | |||
| 02331: | then go to mpy28 | Fractionoverflow ? | ||
| 02332: | a exchange c[m] | If yes go to right scaling | ||
| 02333: | c -> a[w] | result in C | ||
| 02334: | 0 -> b[w] | zap B | ||
| 02335: | nrm27: | 12 -> p | point to 12 | |
| 02336: | go to nrm26 | back to the farm via "rtn21" (S1=0) or "return" | ||
| 02337: | lncd1: | 9 -> p | load ln(1.1) | |
| 02340: | load constant 3 | =0.99531017980553 | ||
| 02341: | load constant 1 | |||
| 02342: | load constant 0 | |||
| 02343: | load constant 1 | |||
| 02344: | load constant 7 | |||
| 02345: | load constant 9 | |||
| 02346: | lnc8: | load constant 8 | ||
| 02347: | load constant 0 | |||
| 02350: | load constant 5 | |||
| 02351: | load constant 5 | |||
| 02352: | lnc9: | load constant 3 | ||
| 02353: | go to nrm27 | to to normalize | ||
| 02354: | pre21: | a exchange c[w] | Entry point for prescaling of ex | |
| 02355: | a -> b[w] | between 0 <= x < 1 | ||
| 02356: | c -> a[m] | |||
| 02357: | c + c -> c[xs] | repeated subtractions of ln(10) | ||
| 02360: | if no carry go to pre24 | if positive "pre24" | ||
| 02361: | c + 1 -> c[xs] | if negative | ||
| 02362: | pre22: | shift right a[w] | ||
| 02363: | c + 1 -> c[x] | |||
| 02364: | if no carry go to pre22 | |||
| 02365: | go to pre26 | go to "prev26" to finish | ||
| 02366: | lnc10: | 0 -> c[w] | load ln(10) | |
| 02367: | 12 -> p | 2.3025 | ||
| 02370: | load constant 2 | |||
| 02371: | load constant 3 | |||
| 02372: | load constant 0 | |||
| 02373: | load constant 2 | |||
| 02374: | load constant 5 | |||
| 02375: | go to lnc7 | + .00008509 | ||
| 02376: | lncd3: | 5 -> p | ||
| 02377: | go to lnc6 | + .000000003 | ||
J. LAPORTE
12 November 2006
Note : How
to forge constants when there is no room in Rom.
Only 3 constants
- π/4 = tan-1
= arc tan(1) = 0.7853981635
- ln (2) = 0.693147190553
- and ln(10) = 2.302585093
are loaded
completely from rom.
The rest is forged (I used this term instead of calculated which makes no sense
regarding a constant).
The pattern found in the ln(x) constants and in the angles in radians are
singular: digits 6 and 9 are often used.
1) Inverse trigo
arc tan(0.1) =
0.099668652496
arc tan(0.01) = 0.0099996666866
arc tan(0.001) = 0.000999999666
arc tan(0.0001) = 0.000099999999666
2) ln and e^x
ln(1.00001) =
0.999995
ln(1.0001) = 0.9995
ln(1.001) = 0.999500330850
ln(1.01) = 0.99503085093
ln(1.1) = 0.09531017980553
The relevant code is at 02156
| 02156: | 0 -> c[w] | |
| 02157: | c - 1 -> c[m] | |
| 02160: | if s2 = 0 | |
| 02161: | then go to pqo28 | |
| 02162: | load constant 4 | |
| 02163: | c + 1 -> c[m] | |
| 02164: | if no carry go to pqo24 | |
| 02165: | pqo27: | load constant 6 |
| 02166: | pqo28: | if p # 1 |
| 02167: | then go to pqo27 | |
| 02170: | shift right c[w] | |
| 02171: | pqo24: | shift right c[w] |
The scheme is
identical: register C is zapped and C=0
Then c 1 -> c[m] makes C=09999999999000
Pointer p is positioned load constant 4 makes C=09999499999000
And c + 1 -> c[m] finish the job C=09999500000000,
(this is the case of ln(1.00001).
Sometimes this scheme is completed with a few figures loaded from rom, eg.
Ln(1.01) : C=00995033085093.
The case of const arc tan 0.001 and arc tan 0.0001 is simpler only digits 9
and 6!
That was surely a space saving strategy, but when memory was not so sparse : this code remain (in the Woodstock machines for example).