Up

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 ais 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 e 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).