HP-21 DSP

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.

It's only fair to share...Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUponDigg thisPin on PinterestEmail this to someone

Leave a Reply

Your email address will not be published. Required fields are marked *