Contributed by Claus Buchholz
The TMC0501 architecture underlying the TI SR-5x and TI-58/9 calculators of the 70s is well known. One of its features is the Constant ROM, which holds several 16-digit BCD constants required for CORDIC and other algorithms. In later calculators of the series, TI even took advantage of extra CROM space to store subroutines written not in the native CPU instructions but rather in the user programming language. This was discovered in the day and was a big topic in the user group newsletters.
Less well known is the architecture of the low end TI programmables, the TI-57, -55, and MBA. The TMC1500 single-chip design did not include any Constant ROM. One might expect then that the instruction set allowed for loading of data from instruction ROM tables, but it did not. Also lacking were immediate load instructions found in most any microprocessor. So how did those calculators store their constants? The answer is interesting and surprising.
A few years ago HrastProgrammer found TI-57 object listings and instruction descriptions in various patent disclosures. He used them to write an emulator. This has proven the only way yet to see how the -57 really works inside. Maybe decappers will map an actual -57 chip someday.
In the disassembly I found these routines based on a sequence of 9 increment instructions:
LD8 A=ASL MAEX BRNC SUM8 LD77 CALL LD7 LD7 A=ASL MAEX BRNC SUM7 LD66 CALL LD6 LD6 A=ASL MAEX BRNC SUM6 LD95 CALL LD9 LD5 A=ASL MAEX BRNC SUM5 LD4 A=ASL MAEX BRNC SUM4 LD63 CALL LD6 LD3 A=ASL MAEX BRNC SUM3 LD2 A=ASL MAEX BRNC SUM2 L59S CALL LD9 L49S CALL LD9 L39S CALL LD9 LD99 CALL LD9 LD9 A=ASL MAEX A=A+1 MAEX SUM8 A=A+1 MAEX SUM7 A=A+1 MAEX SUM6 A=A+1 MAEX SUM5 A=A+1 MAEX SUM4 A=A+1 MAEX SUM3 A=A+1 MAEX SUM2 A=A+1 MAEX SUM1 A=A+1 EXP RTN
Each routine puts a digit from 1 to 9 into the low end of the 16-digit Accumulator, A. When an algorithm needs a 5, for example, it calls the LD5 subroutine, which shifts A left one digit and jumps to SUM5, which increments A 5 times. So every digit is generated by such a subroutine call, and up to 12 calls are made to generate one constant.
Take the constant $\pi$:
A=A-A MAEX CALL LD7 0.785398163400 pi/4 CALL LD8 CALL LD5 CALL LD3 CALL LD9 CALL LD8 CALL LD1 CALL LD63 CALL LD4 CALL LD00 D=A MAEX A=A+A MAEX pi/2 B=A MAEX A=A+A MAEX pi RTN
The code starts by generating $\pi/4$. First A is cleared by subtracting it from itself. Then routines are called in the order LD7, LD8, LD5, LD3, LD9, and so on. Notice that some digits are doubled up to save a little ROM space. Finally, $\pi/4$ moves to the D register, A is doubled, $\pi/2$ moves to B, A doubles again, and $\pi$ remains in A.
Here are other trig constants:
CALL LD5 57.295779513 deg/rad CALL LD7 CALL LD2 CALL LD95 CALL LD77 CALL LD95 CALL LD1 CALL LD3 CALL LD63 63.661977237 grd/rad CALL LD66 CALL LD1 CALL LD9 CALL LD77 CALL LD2 CALL LD3 CALL LD7
And here are constants for the logarithmic and trigonometric CORDIC routines:
A=A-A FMAEX CALL LD2 2.302585093000 ln 10 CALL LD3 A=ASL MAEX CALL LD2 CALL LD5 CALL LD8 CALL LD5 A=ASL MAEX CALL LD9 CALL LD3 L30S A=ASL MAEX LD00 A=ASL MAEX A=ASL MAEX CALL LD95 0.095310179800 ln 1.1 CALL LD3 CALL LD1 A=ASL MAEX CALL LD1 CALL LD7 CALL LD9 L800 CALL LD8 L00 CALL LD00 CALL LD99 0.009950330800 ln 1.01 CALL LD5 A=ASL MAEX CALL LD3 CALL LD3 A=ASL MAEX BRNC L800 CALL L39S 0.000999500200 ln 1.001 CALL LD5 CALL LD00 CALL LD2 BRNC L00 CALL L49S 0.000099995000 ln 1.0001 CALL LD5 CALL L30S CALL LD99 0.099668652491 atan .1 CALL LD66 CALL LD8 CALL LD6 CALL LD5 CALL LD2 CALL LD4 LD91 CALL LD9 LD1 A=ASL MAEX BRNC SUM1 CALL L49S 0.009999666691 atan .01 CALL LD66 CALL LD66 BRNC LD91 CALL L59S 0.000999999667 atan .001 CALL LD9 CALL LD66 BRNC LD7
Notice there are many 9s in these constants. To save some more ROM space (the whole calculator has to fit into only 2K instructions), there are routines to generate from one to five consecutive 9s.
You can see that it takes very many instruction cycles to generate one constant. Emulator execution traces show that these constants are generated as needed and not saved for later reuse, as register and RAM spaces are tight. All this explains why the TI-57 executes trig and log functions much more slowly than the SR-56 or TI-58.
Especially inefficient is the generation of a 9. Instead of shifting left and incrementing nine times, you could increment once, shift left, and decrement once, using three cycles instead of ten. Even better is to generate 99 in four cycles rather than twenty. I have rewritten LD9 and LD99 and fit them into five spare words at the end of the ROM:
LD99 BRNC 7FB LD9 A=A+1 MAEX BRNC 7FD 7FB A=A+1 MAEX 7FC A=ASL MAEX 7FD A=ASL MAEX 7FE A=A-1 MAEX 7FF RTN
I patched them into the emulator and tested them. They speed up trig functions by about 10%. A better optimization would be to store the smaller constants [$ 10^{-N} - {\rm atan}(10^{-N}) $] rather than ${\rm atan}(10^{-N})$. I estimate that would reduce constant generation time by half.
No one cares much about the TI-57 these days, but it is still impressive to see how much TI could squeeze into a small chip back in 1976.
Claus Buchholz
Michigan, USA
Credit: TI-57 ROM Listing Disassembled by HrastProgrammer
ROM dump retyped/analyzed/fixed by HrastProgrammer from the following US patents: 4078251 4079459 4100600 4107781 4125901 4164037
P.S. There are also three two-digit constants in the ROM whose function I do not know:
CALL SUM5 CALL LD1 CALL SUM4 CALL LD8 CALL SUM7 CALL LD6