This one should be remarkably straight forward; but it isn’t. There are standard ways of doing standard things. This is a standard thing. It just doesn’t follow any of the standard ways. Here’s what happens:
>>> dr A=0000FFFFFFFFFF D=00000000000000 M1=00000000000000 P= 0 B=21000000000000 E=00000000000000 M2=00000000000000 C=00000000000000 F=00000000000000 S =..23.5.......... >>> g,403 Breakpoint 1 at 00403 >>> ts200 00403: keys -> rom address ; 00621: select rom 0 ; 00222: 0 -> s 9 ; 00223: jsb 0363 ; 00363: 0 -> s 13 ; 00364: c -> a[s] ; 00365: display toggle ; ; do { 00366: 0 -> s 15 ; ; for (p=7; p>0; p--) 00367: p <- 7 ; P= 7 00370: p - 1 -> p ; P= 6, 5, 4, ..., 0 00371: if p # 0 then goto 00370 ; ; next ; } while (s 15 == 1) 00373: if 1 = s 15 then goto 00366 ; ; // S=..23.5.......... 00375: cpu woodstock ; 00376: if 0 = s 15 then goto 00376 ; ... >>>
All it does is clear s9 (the dot_pressed flag), wait for the DSP key to be released (until not “1 = s 15”) and then wait for a keypress.
What is doesn’t do is set any flag anywhere to note that DSP was pressed. It doesn’t store anything in any internal CPU register. It has no way of knowing, in future, that DSP was pressed previously. Yet it does, because it does work.
It is only when you press a digit afterwards that the trick becomes clearer. Here’s what happens when I pressed “3”:
>>> g,403 (((press 3))) Breakpoint 1 at 00403 >>> ts200 00403: keys -> rom address ; 00561: a + 1 -> a[p] ; A=0000FFFFFFFFF1 00562: a + 1 -> a[p] ; A=0000FFFFFFFFF2 00563: if n/c goto 0330 ; 00730: a + 1 -> a[p] ; A=0000FFFFFFFFF3 00731: return ;
Perfectly normal and as we’d expect so far (see HP-21 scan codes). A[0] now = 3.
What happens next is very different compared to earlier calculators:
00224: if p = 2 then goto 00223 ; 00226: 0 -> s 1 ; 00227: if 1 = s 9 then goto 00232 ; 00231: 1 -> s 1 ; S=.123.5.........F 00232: f exch a ; A=0000FFFFFFFFF2 00233: if n/c goto 0006 ; 00006: clear s ;
It’s not what it says that’s different. It’s where it is that’s different.
Ordinarily, we’d press a prefix key and expect a flag to get set. On a HP-67, HP-65 or pretty much any other calculator, that’s how it works. The prefix key might be a colored f, g, h or f-1 key. It might also be (on calculators with more than one memory register) a STO or RCL key, or a GTO, GSB or LBL key. Press the key, set a prefix flag.
Next you press another key and check prefix flag(s). Using “0” for an example, the concept looks like this:
key0: if f_prefix goto keyf0 ; eg calc percent if g_prefix goto keyg0 ; eg calc percent change if h_prefix goto keyh0 ; eg get Last X if sto_prefix goto sto0 ... ; no prefixes add 0 digit to display and X
So how does this know to do “DSP 3” instead of it just being a “3”? It is because we are at address 00224. We “return”ed to 00224 because, a long time back at 00223 in the DSP microcode, we did a “jsb 0363”.
We are still in the DSP microcode! I was not expecting that.
It is a clever approach; it’s kind of “if (key==DSP) { n=getkey(); … }”.
If you look at the internal state from before we did the return, you can see that we have in fact set a “prefix flag”. It is just that the “flag” set is the return stack. That’s how it knows a DSP key was pressed previously:
>>> di Display : on (12 digits) Arithmetic base : 10 Ram address : 0 f : 2 carry : false bank/dlyrom : 0/-1 sp, stack : 0 [00141,00224] lastkey : 91 voltage : 2.5 >>>
So, what does “DSP n” do (the point of this article)? If you look above at the code from 00226 to 00006 you’ll see that it sets s1 and puts the number of digits (“n”) into internal register f.
s1 affects the display routine. It causes exponent digits to be displayed so s1 is the SCIentific mode flag.
The more astute will raise concerns that there is a “clear s” afterwards and that is going to result in the calculator forgetting it should be in SCI mode. One of the peculiarities in the Woodstock CPU is that “clear s” doesn’t affect all of s. This makes sense with hardware flags such as s15 (a key is down), s3 (the switch is set to RADians) and s5 (power is good). It doesn’t make any sense at all for s1 and s2 but they are preserved despite a “clear s”.
My working guess, is that Woodstock evolved from the earlier classic processor and they just lifted the existing solution for “clear s” from that to Woodstock. The classic had a 12 bit s register, not 16, so perhaps all of s0-s3 are unaffected by “clear s” in Woodstock. This wouldn’t show with s3 as it’s connected to hardware. It might affect s0 for some Woodstock calculators but no one seems to have observed that, so I could be wrong.
Note that “0 -> s n” and “1 -> s n” work as expected for s1 and s2. The idiosyncrasy is only in “clear s”.
DSP . n
Here’s DSP . 2:
>>> g,403 (((press DSP))) Breakpoint 1 at 00403 >>> ts 200 00403: keys -> rom address ; 00621: select rom 0 ; DSP, scancode 0221 00222: 0 -> s 9 ; 00223: jsb 0363 ; n=getkey() 00363: 0 -> s 13 ; 00364: c -> a[s] ; 00365: display toggle ; ; while (s 15 == 1 ) ; 00366: ... ; S=.123.5.......... 00375: cpu woodstock ; 00376: if 0 = s 15 then goto 00376 ; ... >>> g,403 (((press .))) Breakpoint 1 at 00403 >>> ts200 00403: keys -> rom address ; 00622: if n/c goto 0023 ; ".", scancode 0222 00423: 1 -> s 9 ; S=.123.5...9.....F 00424: p <- 2 ; P= 2 00425: return ; ; back in DSP routine 00224: if p = 2 then goto 00223 ; 00223: jsb 0363 ; n=getkey() 00363: 0 -> s 13 ; 00364: c -> a[s] ; 00365: display toggle ; ; while (s 15 == 1 ) ; 00366: ... ; S=.123.5...9...... 00375: cpu woodstock ; 00376: if 0 = s 15 then goto 00376 ; ... >>> g,403 (((press 2))) Breakpoint 1 at 00403 >>> ts200 00403: keys -> rom address ; 00562: a + 1 -> a[p] ; A=00000FFFF00001 00563: if n/c goto 0330 ; 00730: a + 1 -> a[p] ; A=00000FFFF00002 00731: return ; ; back in DSP routine 00224: if p = 2 then goto 00223 ; note: p=0 00226: 0 -> s 1 ; S=..23.5...9.....F 00227: if 1 = s 9 then goto 00232 ; 00232: f exch a ; A=00000FFFF00003 00233: if n/c goto 0006 ; 00006: clear s ; S=..23.5.........F display: 00007: ... ; " 0.00" 00376: if 0 = s 15 then goto 00376 ; 00376: ...
s1 is the SCI flag.
s9 is a dot_pressed flag.
You could do DSP . . . 6 and still get DSP . 6
There are a lot of other combinations that you could do after DSP that are neither a “.” nor a digit. Each of those would have to be designed and checked to behave well with the DSP prefix. DSP DSP probably works as DSP. If we were already in a microcode subroutine, DSP DSP is likely to lose the parent address.
This is part of the HP-21 topic.
The examples shown are using the hp21w simulator for Windows.