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