Here is the complete map of the HP35 ROM 1 (256 instructions of 10 bits each).
ROM 1 contains the
code for:
- Cordic routines for trigo and inverse trigo (tan, sin, cos, arc tan, arc sin,
arc cos)
- root square routine,
- part of addition, multiplication and division routines.
01000: | go to tan13 | Control comes from “tan14” 01377 (Cordic rotations) | ||
01001: | tan15: | a exchange b[w] | End of Cordic rotations, A=X C=Y (vectors) | |
01002: | jsb tnm11 | Goto normalize both vector numbers | ||
01003: | stack -> a | |||
01004: | jsb tnm11 | Get the other from the stack | ||
01005: | stack -> a | |||
01006: | if s9 = 0 | If cos case, we need cot(θ) then we exchange X and Y | ||
01007: | then go to tan16 | to compute cot(θ) in place of tan(θ) | ||
01010: | a exchange c[w] | |||
01011: | tan16: | if s5 = 0 | If tan(θ) the exit door is “asn12” | |
01012: | then go to asn12 | Else if sin or cos : | ||
01013: | 0 -> c[s] | we compute tan calling “div11” X/Y | ||
01014: | jsb div11 | |||
01015: | l01015: | c -> stack | Code for arc sin | |
01016: | jsb mpy11 | compute tan2 to use in formula sin= tan / SQR (1 + tan2 ) | ||
01017: | jsb add10 | “add10” makes 1 + tan2 | ||
01020: | jsb sqt11 | get other vector from the stack before calling “div11” | ||
01021: | stack -> a | |||
01022: | asn12: | jsb div11 | “asn12” : normal path for tan(θ) computing A/C or tan/SQR(1 + tan2 ) | |
01023: | if s10 = 0 | if direct trigo returns via “rtn12” to dsp loop 0333 | ||
01024: | then go to rtn12 | or execute a return if came from a jsb in Cordic rotations | ||
01025: | atn11: | 0 -> a[w] | arc tan main entry point | |
01026: | a + 1 -> a[p] | arc tan(Z) angle Z in C | ||
01027: | a -> b[m] | B=1 | ||
01030: | a exchange c[m] | The “atn12” loop aligns A and B according exp of C | ||
01031: | atn12: | c - 1 -> c[x] | ||
01032: | shift right b[wp] | |||
01033: | if c[xs] = 0 | |||
01034: | then go to atn12 | “atn13”: A= Z /10 B= X/100 C= exp | ||
01035: | atn13: | shift right a[wp] | ||
01036: | c + 1 -> c[x] | |||
01037: | if no carry go to atn13 | |||
01040: | shift right a[w] | A = Z | ||
01041: | shift right b[w] | B = qj | ||
01042: | c -> stack | C = X | ||
01043: | atn14: | b exchange c[w] | ||
01044: | go to atn18 | Goto Cordic rotations (pseudo division) | ||
01045: | sqt11: | b exchange c[w] | SQR(X) Entry point | |
01046: | 4 -> p | A=X B=X C=0 | ||
01047: | go to sqt14 | p=4 | ||
01050: | tnm11: | c -> stack | Called in tan15 (means “to normalization”: relay to nrm21, via add15) | |
01051: | a exchange c[w] | A is popped from stack | ||
01052: | if c[p] = 0 | C is pushed, p=12 | ||
01053: | then go to tnm12 | |||
01054: | 0 - c -> c[w] | |||
01055: | tnm12: | c -> a[w] | absolute value of C is copied to A | |
01056: | b -> c[x] | format registers to normalize C with std routine “nrm21” | ||
01057: | go to add15 | |||
01060: | c -> a[w] | The BIG SWITCH | ||
01061: | if s1 = 0 | S1 S5 S9 S10 (S1 = 0 : SQR) | ||
01062: | then go to sqt11 | TAN 1 (S10=0 : direct trigo) | ||
01063: | if s10 = 0 | ARC TAN 1 1 | ||
01064: | then go to l01155 | SIN 1 1 | ||
01065: | if s5 = 0 | ARC SIN 1 1 1 | ||
01066: | then go to atn11 | COS 1 1 1 | ||
01067: | 0 - c - 1 -> c[s] | ARC COS 1 1 1 1 | ||
01070: | a exchange c[s] | |||
01071: | go to l01015 | |||
01072: | atn15: | shift right b[wp] | ARC TAN | |
01073: | atn16: | a - 1 -> a[s] | 1) Cordic rotations to compute the qj – pseudo quotients) | |
01074: | if no carry go to atn15 | To reduce component Y to zero (pseudo division) | ||
01075: | c + 1 -> c[s] | |||
01076: | a exchange b[wp] | |||
01077: | a + c -> c[wp] | 01077 is the rotation | ||
01100: | a exchange b[w] | |||
01101: | atn18: | a -> b[w] | pseudo division entry point is “atn18” | |
01102: | a - c -> a[wp] | |||
01103: | if no carry go to atn16 | |||
01104: | stack -> a | 2) Pseudo multiplication (starting at 01104) | ||
01105: | shift right a[w] | ∑ qj tan-1 10 –j | ||
01106: | a exchange c[wp] | use stack to store intermediate results (top of stack lost) | ||
01107: | a exchange b[w] | |||
01110: | shift left a[wp] | |||
01111: | c -> stack | |||
01112: | a + 1 -> a[s] | 01114 Test for more rotations (max = 5) | ||
01113: | a + 1 -> a[s] | |||
01114: | if no carry go to atn14 | |||
01115: | 0 -> c[w] | No more rotations | ||
01116: | 0 -> b[x] | Clear context | ||
01117: | shift right a[ms] | And compute Y/X | ||
01120: | jsb div14 | If direct trigo S1=1 then after “div” : rtn12 and return at 01121 | ||
01121: | c - 1 -> c[p] | Control gets back here via “rtn11”, “rtn12” and “return” | ||
01122: | stack -> a | |||
01123: | a exchange c[w] | Prepare context | ||
01124: | 4 -> p | |||
01125: | jsb pqo13 | Call pseudo multiplication PM ( note in pqo13, select rom 2, use the log routines) | ||
01126: | 6 -> p | load constant arc (0.0001) = 0.000099999999666 | ||
01127: | jsb pmu11 | and do the PM | ||
01130: | 8 -> p | load arc ( 0.001) = 0.000999999666 | ||
01131: | jsb pmu11 | and do the PM | ||
01132: | 2 -> p | load arc ( 0.01) = 0.0099996666866 | ||
01133: | load constant 8 | |||
01134: | 10 -> p | |||
01135: | jsb pmu11 | and do the PM | ||
01136: | jsb atcd1 | load arc ( 0.1) = 0.099668652496 | ||
01137: | jsb pmu11 | and do the PM | ||
01140: | jsb atc1 | load arc ( 1) = π / 4 | ||
01141: | shift left a[w] | and do the PM | ||
01142: | jsb pmu11 | Angle in A in radians | ||
01143: | b -> c[w] | |||
01144: | jsb add15 | goto normalize | ||
01145: | jsb atc1 | convert to degree (load π / 4) | ||
01146: | c + c -> c[w] | double it | ||
01147: | jsb div11 | divide A by π / 2 so a multiplication by 90 will do the job | ||
01150: | if s9 = 0 | If S9 = 0 arc tan, arc sin | ||
01151: | then go to l01154 | |||
01152: | 0 - c - 1 -> c[s] | Else it’s “arc cos” : negate previous result : - arc sin | ||
01153: | jsb add10 | add it to π / 2 ( arc cos = π / 2 – arc sin) | ||
01154: | l01154: | 0 -> s1 | To return via “rtn2” at 01160 and in “rtn11” (after “mpy11”:nrm21,rtn11, rtn12, 0333. | |
01155: | l01155: | 0 -> c[w] | Direct Trigo (tan, cos, sin) | |
01156: | c - 1 -> c[p] | Build number 90 in C | ||
01157: | c + 1 -> c[x] | |||
01160: | if s1 = 0 | Multiplication in “mpy11” will convert to degree | ||
01161: | then go to mpy11 | |||
01162: | jsb div11 | θ/90 in (θ/90 x π / 2 = π / 180) | ||
01163: | jsb atc1 | |||
01164: | c + c -> c[w] | |||
01165: | jsb mpy11 | |||
01166: | jsb atc1 | load π / 4 | ||
01167: | c + c -> c[w] | double | ||
01170: | c + c -> c[w] | double = π | ||
01171: | jsb rtn11 | exit door when S1=0 (SQR) | ||
01172: | c + c -> c[w] | double again = 2π | ||
01173: | jsb pre11 | angle prescaling : 0 <= θ < 2π | ||
01174: | jsb atc1 | load π / 4, arc tan(1) | ||
01175: | 10 -> p | |||
01176: | jsb pqo11 | pseudo division | ||
01177: | jsb atcd1 | load arc tan(0.1) | ||
01200: | 8 -> p | |||
01201: | jsb pqo12 | 2nd pdiv | ||
01202: | 2 -> p | load arc tan(0.01) | ||
01203: | load constant 8 | |||
01204: | 6 -> p | 3th pdiv | ||
01205: | jsb pqo11 | load arc tan(0.001) | ||
01206: | 4 -> p | 4th pdiv | ||
01207: | jsb pqo11 | load arc tan(0.0001) | ||
01210: | jsb pqo11 | 5th pdiv | ||
01211: | a exchange b[w] | |||
01212: | shift right c[w] | |||
01213: | 13 -> p | |||
01214: | load constant 5 | remainder in A, pq in B | ||
01215: | go to tan14 | goto cordic PM 5 times | ||
01216: | atcd1: | 6 -> p | Forge constant constant arc tan(0.1) with pattern “865249” | |
01217: | load constant 8 | See note on Cst forging | ||
01220: | load constant 6 | |||
01221: | load constant 5 | |||
01222: | load constant 2 | |||
01223: | load constant 4 | |||
01224: | load constant 9 | |||
01225: | rtn11: | if s1 = 0 | Locally S1 is used to switch return from “asn12” | |
01226: | then go to rtn12 | via rtn12 and finally to 0333 -> dsp loop | ||
01227: | return | if S1=1 = trigo, if S1=0 ) ln and e^x ; s1 is set ot zero at 01154 | ||
01230: | add10: | 0 -> a[w] | Arc cos | |
01231: | a + 1 -> a[p] | = π / 2 – arc sin | ||
01232: | select rom 0 | ; -> l00233 | ||
01233: | pmu11: | select rom 2 | WARNING destructured code : read it dynamically | |
01234: | pqo11: | shift left a[w] | Pseudo division entry point in direct trigo | |
01235: | pqo12: | shift right b[ms] | ||
01236: | b exchange c[w] | Prepare registers | ||
01237: | go to pqo16 | |||
01240: | pqo15: | c + 1 -> c[s] | ||
01241: | pqo16: | a - b -> a[w] | (01241) the pseudo division, by repeated subtractions | |
01242: | if no carry go to pqo15 | |||
01243: | a + b -> a[w] | Restore previous | ||
01244: | pqo13: | select rom 2 | goto 02245 (rom 2) “pqo23” to load constant and do the pm | |
01245: | mpy11: | select rom 2 | Computes tan2 and cot2 in sin and cos formulas | |
01246: | div11: | a - c -> c[x] | A/C in direct trio (vectors dividing) | |
01247: | select rom 2 | |||
01250: | sqt15: | c + 1 -> c[p] | ||
01251: | sqt16: | a - c -> a[w] | 12 bit mantissa longhand routine | |
01252: | if no carry go to sqt15 | using a 5delta remainder | ||
01253: | a + c -> a[w] | |||
01254: | shift left a[w] | |||
01255: | p - 1 -> p | |||
01256: | sqt17: | shift right c[wp] | ||
01257: | if p # 0 | |||
01260: | then go to sqt16 | |||
01261: | go to tnm12 | goto normalization | ||
01262: | div14: | c + 1 -> c[p] | p = 12 | Core dividing loop |
01263: | div15: | a - b -> a[ms] | C holds subtractions count | |
01264: | if no carry go to div14 | performs division by repeated subtractions | ||
01265: | a + b -> a[ms] | here we reverse gear : on step too far | ||
01266: | shift left a[ms] | |||
01267: | p - 1 -> p | sweeps C from 12 to 0 | ||
01270: | if p # 0 | |||
01271: | then go to div15 | Routine Entry point = 01271 !! | ||
01272: | go to tnm12 | goto normalization | ||
01273: | sqt12: | p - 1 -> p | ||
01274: | a + b -> a[ms] | |||
01275: | if no carry go to sqt18 | SQR(negative) -> error or loop to build delta remainder | ||
01276: | select rom 0 | go to blinking display 0277 | ||
01277: | add12: | c - 1 -> c[xs] | came from 00276 | |
01300: | c - 1 -> c[xs] | Restore exp C | ||
01301: | 0 -> a[x] | zero exp A | ||
01302: | a - c -> a[s] | exp comparison | ||
01303: | if a[s] >= 1 | if exp C < exp A | ||
01304: | then go to add13 | |||
01305: | select rom 2 | goto core adder 02306 | ||
01306: | add13: | if a >= b[m] | else compare fraction part | |
01307: | then go to add14 | if FP A < FP B then change sign before subtraction | ||
01310: | 0 - c - 1 -> c[s] | |||
01311: | a exchange b[w] | |||
01312: | add14: | a - b -> a[w] | simply perform subtraction in the other case | |
01313: | add15: | select rom 2 | goto normalize at "nrm21" | |
01314: | atc1: | 0 -> c[w] | load π / 4 | |
01315: | 11 -> p | |||
01316: | load constant 7 | |||
01317: | load constant 8 | |||
01320: | load constant 5 | |||
01321: | load constant 3 | |||
01322: | load constant 9 | |||
01323: | load constant 8 | |||
01324: | load constant 1 | |||
01325: | load constant 6 | |||
01326: | load constant 3 | |||
01327: | load constant 5 | |||
01330: | 12 -> p | |||
01331: | return | |||
01332: | rtn12: | select rom 0 | back to the LOOP 0333 | |
01333: | sqt18: | a + b -> a[x] | mantissa multimplied by 5 | |
01334: | if no carry go to sqt14 | p point 5 to 0 | ||
01335: | c - 1 -> c[p] | |||
01336: | sqt14: | c + 1 -> c[s] | delta remainder is built | |
01337: | if p # 0 | |||
01340: | then go to sqt12 | |||
01341: | a exchange c[x] | prepare registers for core routine | ||
01342: | 0 -> a[x] | |||
01343: | if c[p] >= 1 | A and C are aligned | ||
01344: | then go to sqt13 | |||
01345: | shift right a[w] | |||
01346: | sqt13: | shift right c[w] | ||
01347: | b exchange c[x] | |||
01350: | 0 -> c[x] | |||
01351: | 12 -> p | |||
01352: | go to sqt17 | go to core routine | ||
01353: | pre11: | select rom 2 | go to prescaling in rom 2 ("pre21") | |
01354: | tan18: | shift right b[wp] | do the SR twice | |
01355: | shift right b[wp] | |||
01356: | tan19: | c - 1 -> c[s] | again | |
01357: | if no carry go to tan18 | |||
01360: | a + c -> c[wp] | no more SR | ||
01361: | a - b -> a[wp] | X + Z -> Z | ||
01362: | b exchange c[wp] | A – B -> A | ||
01363: | tan13: | b -> c[w] | Continuation if Cordic rotation | |
01364: | a - 1 -> a[s] | update “ of times this rotation was made (pqj) | ||
01365: | if no carry go to tan19 | check if over | ||
01366: | a exchange c[wp] | |||
01367: | stack -> a | |||
01370: | if b[s] = 0 | if no more rotation for a pqj goto “tan15” (01001) | ||
01371: | then go to tan15 | next pqj | ||
01372: | shift left a[w] | |||
01373: | tan14: | a exchange c[wp] | entry point in tan cordic rotations | |
01374: | c -> stack | Result saved in the stack | ||
01375: | shift right b[wp] | Prepare for rotation, A = X B = Y (angle) | ||
01376: | c - 1 -> c[s] | update #of rotations c[s] | ||
01377: | b exchange c[s] | continuation at 01000 “tan13” |
J. LAPORTE
November 2006.