When you run a program in a programmable calculator, it goes through a standard process of:
- get a program step to run,
- update the program counter (PC) to point to the next step, and
- run the step we got.
It does that over and over again, mostly regardless of what the program step is. (The exception is a [R/S] program step, which stops the process).
Here’s what it looks like from the calculator’s side of the case:
RunLoop: ; aka $go 01754 if 1 = s 15 then goto 01707 ; if key_pressed 01756 display toggle 01757 jsb 01472 ; fetch ; (selects a data reg and sets P based on the PC (step number)) ; In : M1=20000000001202 so PC=01 ; Out: data=9 P=12 01760 jsb 01772 ; $inc ; (adds 1 to PC) ; In : M1=20000000001202 so PC=01 ; Out: M1=20000000002202 so PC=02 *** ram[9] -> c (=e5e5e5e5000000) 01761 data register -> c 0 ; C= e5e5e5e5000000 ; (just got program steps 01..07 to C register. Step 01 at LHS) ; 01762 if p # 0 then goto 01575 01575 shift right c[w] ; C= 0e5e5e5e500000 01576 p - 1 -> p ; P= 11 01577 if n/c goto 01762 ; 01762 ... ; C= 00e5e5e5e50000 P=10 01762 ... ; C= 000e5e5e5e5000 P= 9 01762 ... ; C= 0000e5e5e5e500 P= 8 01762 ... ; C= 00000e5e5e5e50 P= 7 01762 ... ; C= 000000e5e5e5e5 P= 6 01762 ... ; C= 0000000e5e5e5e P= 5 01762 ... ; C= 00000000e5e5e5 P= 4 01762 ... ; C= 000000000e5e5e P= 3 01762 ... ; C= 0000000000e5e5 P= 2 01762 ... ; C= 00000000000e5e P= 1 01762 ... ; C= 000000000000e5 P= 0 01762 if p # 0 then goto 01575 01764 0 -> c[ms] 01765 display off ; (P was 12 for PC=01. First step now in C[1,0]. pgmcode "e5") execut: 01766 0 -> c[xs] 01767 c -> a[x] ; A= 200000000000e5 01770 a + 1 -> a[xs] ; A= 200000000001e5 01771 a -> rom address ; (now running a prgcode in the range "e0" - "ef") ; 1400 tbl1 prgcode.lhs= "e" 01436 c + 1 -> c[xs] ; C= 000000000001e5 01437 delayed rom 4 01440 if n/c goto 01460 02060 shift left a[x] ; A= 20000000000e50 02061 a exchange c[xs] ; A= 20000000000150 C= 00000000000ee5 02062 m2 -> c ; C= 00000000000000 02063 p <- 12 ; P= 12 02064 decimal 02065 0 -> a[s] ; A= 00000000000150 02066 0 -> s 9 02067 a -> rom address ; (now running prgmcode "e5") ; 2000 tbl1 prgcode.rhs= "5" 02025 if n/c goto 02342 02342 select rom 3 01743 clear s ; S= .1.3.5.......... 01744 delayed rom 0 01745 jsb 01705 $overf: ; check for overflow. ; 1. if mantissa=0, entire word=0 (0.00 EEX 0) ; 2. if xs 5-8, must have underflowed. Set to 0.0 ; 3. if xs 1-4, must have overflowed. Set to 9.9999999e99 00305 ... 00273 return 01746 m2 exch c 01747 if p # 12 then goto 01752 ; =12 if overflow. stops running. 01752 if 0 = s 1 then goto 00247 ; if not running (but we are) RunLoop: 01754 ...
What just happened? Here it is again but with a slightly higher level view:
RunLoop: ; aka $go 01754 if 1 = s 15 then goto 01707 ; if key_pressed 01756 display toggle 01757 ... ; fetch - set data reg and P from PC 01760 ... ; PC++ 01761 ... ; get program steps 01762 ... ; shift right by P to get step in A[1,0] 01765 display off execut: 01766 0 -> c[xs] 01767 c -> a[x] ; A= 200000000000e5 01770 a + 1 -> a[xs] ; A= 200000000001e5 01771 a -> rom address (run program step) 01746 m2 exch c 01747 if p # 12 then goto 01752 ; =12 if overflow. stops running. 01752 if 0 = s 1 then goto 00247 ; if not running (but we are) RunLoop: 01754 ...
It’s basically: get the current program step, PC++, run the step; and then back again for the next one.
It has to increment the PC (step number) before it runs the current one, so that the current one can be a “GTO …” that changes PC.
Having overflow turn off “running” is a nice feature. I don’t recall seeing that in earlier calculators.
Let’s have a look at some of the subroutines we skipped over in our first look:
Fetch
; M1[m]= PC, nxt prg step ; out data= prg mem ie 9+int((PC-1)/7) ; P = 12-2*((PC-1)%7) ie shifts right to prgcode fetch: 01472 m1 -> c ; C= 20000000001202 01473 c -> a[w] ; A= 20000000001202 01474 0 -> c[w] ; C= 00000000000000 01475 p <- 0 01476 load constant 8 ; C= 00000000000008 P= 13 01477 p <- 3 ; P= 3 01500 load constant 7 ; C= 00000000007008 P= 2 // 7 steps per register 01501 p <- 0 ; P= 0 01502 decimal 01503 a - 1 -> a[m] ; A= 20000000000202 // PC-1 01504 if n/c goto 01701 ; subtract 7 from a[m] until it is -ve. c[p]++ each time to ref ram[9..15] ; a[m] is 0..48 for step 01..49 01701 binary 01702 c + 1 -> c[p] ; C= 00000000007009 // ram[9] 01703 if n/c goto 01545 ; can't go beyond ram[15] => 7 pgm regs 01545 decimal 01546 a - c -> a[m] ; A= 29999999993202 CY // (PC-1)-7 is -ve 01547 if n/c goto 01701 ; if not -ve, add 1 to pgm reg and repeat ; 01550 c -> addr ; determined pgm reg. set that. (9 in our case) 01551 a exchange c[w] ; A= 00000000007009 C= 29999999993202 01552 c -> a[w] ; A= 29999999993202 ; 01553 a + 1 -> a[m] ; A= 29999999994202 // add 1 again 01554 if n/c goto 01654 01654 p + 1 -> p ; P= 1 01655 p + 1 -> p ; P= 2 // and add 2 nibbles for ea step 01656 if n/c goto 01553 ; repeats until we get a[m] to 0 again ; 01553 ... ; A= 29999999995202 P= 3, 4 // a[m]=-5 01553 ... ; A= 29999999996202 P= 5, 6 // =-4 01553 ... ; A= 29999999997202 P= 7, 8 // =-3 01553 ... ; A= 29999999998202 P= 9,10 // =-2 01553 ... ; A= 29999999999202 P=11,12 // =-1 01553 a + 1 -> a[m] ; A= 20000000000202 CY // = 0 01554 if n/c goto 01654 01555 return
The microcode starts with PC in M1. It converts PC=01..49 to 00..48. It starts with ram[9] (01476 load constant 8; then 01702 c + 1 -> c[p]) and counts up from there whilst deducting 7 steps from (PC-1) each time.
When (PC-1) is negative, it knows it has the correct prg memory. Steps 01..07 are in ram[9], 08..14 in ram[10], …, and 43..49 in ram[15].
Then, depending on “how negative” (PC-1) is, it can work out where the prgcode is in the selected ram[]. It adds 1 to the (PC-1) value and 2 to the “number of nibbles to shift by” until it gets (PC-1) back to 0.
The result is this:
Step | PC-1 | ram[] | P |
01 | 00 | 9+int( 0/7)= 9 | 12-2*( 0%7)=12 |
02 | 01 | 9+int( 1/7)= 9 | 12-2*( 1%7)=10 |
03 | 02 | 9+int( 2/7)= 9 | 12-2*( 2%7)= 8 |
… | |||
07 | 06 | 9+int( 6/7)= 9 | 12-2*( 6%7)= 0 |
08 | 07 | 9+int( 7/7)=10 | 12-2*( 7%7)=12 |
09 | 08 | 9+int( 8/7)=10 | 12-2*( 8%7)=10 |
… | |||
49 | 48 | 9+int(48/7)=15 | 12-2*(48%7)= 0 |