[comp.sys.handhelds] HP28 resident disassembler

grue@lance.hss.bu.oz (Frobozz) (12/14/89)

hiya,

My next offering to the net: a resident disassembler for the HP-28S.
I've used Alonzo Gariepy's instruction set (posted recently) throughout with
the minor change of @X to (X). Constants are secified as #digits for decimal
and #$hex-deigits for hexidecimal notation.  Illegal (i.e. instructions I don't
know what they do) instructions are not handled correctly and may cause the
program to not run correctly. Tough luck!!  I'll fix this problem when it
starts annoying me too much.

To use the program: store the address to start dissembly in the variable PC.
The address should be a binary integer (i.e. #.... format).  The program will
automatically increment PC as instructions as disassembled.  To disassemble
a single instruction, run the program IN. The format of the output is:
xxxx yyyyy zzzzzzz
where xxxx is the address of the instruction; yyyyy is the operation.field and
zzzzzzz is the arguments of the instruction. The output is as a single string
on the top of stack.

Branch instructions correctly (?) figure out what the target address is and
output that. Hopefully, there are no bugs in the program (famous last words).
If you discover any bugs could I be informed about it/them so I can repair the
damage.  If there were errors in the original instruction set listings then
they are faithfully reproduced here. (I have some doubts about some of the
instructions starting 81A??q where q > 7, but since I've got no better
information to go by......)

The GETN GETB GET3 GETW and GETA rotutines could all be improved by
coding the actual memory reference in machine code. This would improve speed
quite considerably. Just recoding GETN would improve performace quite a lot.
If anybody does this, I'd really like to receive a copy of the new routines.

Also, the program could be made to output to a printer (I don't have one so
I am not going to do this).  A better output to the screen would also be nice
as well as a better user interface (i.e. #addr #length DISAS  sounds like a
good one then run it through my string display program [ posted ages ago ]).
I have some ideas in this respect but haven't had time to implement them yet.
(I wanted to get this out before Christmas so all you die-hard hackers can
have some fun with the roms)

This program is copyright (C) 1989 Paul Dale. All rights reserved.
Any non-profit usage of this program is permitted.  Any other usage requires
my permission.  You will probably also require the permission of Alonzo Gariepy
who posted the instruction set upon which this is based.



                                                     Paul Dale
seeya
SNIF

Language Centre              internet    : grue@lance.hss.bu.oz{.au}
Bond University              JANET       : grue%lance.hss.bu.oz@uk.ac.ukc
Gold Coast, Qld 4229         ARPA, bitnet: grue%lance.hss.bu.oz.au@uunet.uu.net
Australia                    UUCP        : ..!uunet!munnari!lance.hss.bu.oz!grue




--------------------------------------------------------------------------------
IN [ F708 ]               ; decode one instruction from PC
  << PC HX-> ": " +
      { IN0 IN1 IN2 IN3 IN4 IN5 IN 6 IN7 IN8 IN9 INA INB INC IND INE INF }
      GETN 1 + GET PARSE +
  >>

FIELDS [ A74F ]           ; legal fields inside instructions
  << { ".p" ".wp" ".xs" ".x" ".s" ".m" ".b" ".w" ".?" ".?" ".?" ".?" ".?"
       ".?" ".?" ".a" } SWAP 1 + GET
  >>

REGS [ F07B ]             ; table of register operands
  << { " B,A" " C,B" " A,C" " C,D" " A,B" " B,C" " C,A" " D,C" " A,A" " B,B"
       " C,C" " D,D" } SWAP 1 + GET
  >>

GETN [ D7E ]              ; load a nibble from memory at PC
  << PC #1h PEEK NUM 48 -
    IF DUP 9 >
    THEN 7 -
    END #1h PC + 'PC' STO
  >>

IN81 [ 914A ]             ; instructions starting 81
  << GETN -> a
    <<
      IF a 8 <
      THEN a 4 < "RLN.w " "RRN.w " IFTE a 4 MOD 65 + CHR +
      ELSE
        IF a 11 <
        THEN GETN FIELDS {
          << GETN SWAP OVER 7 > "SUB" "ADD" IFTE SWAP + " #" + GETN 1 + ->STR +
              "," + SWAP 4 MOD 65 + CHR +
          >>
          << "SRB" SWAP + " " + GETN 65 + CHR + >>
          << GETN GETN
            IF DUP 8 >
            THEN 9 - ->STR "C"
            ELSE ->STR "A"
            END ROT {
              << ROT "MOVE" SWAP + " " + SWAP + ",R" + SWAP + >>
              << ROT "MOVE" SWAP + " R" + ROT + "," + SWAP + >>
              << ROT "SWAP" SWAP + " " + SWAP + ",R" + SWAP + >>
            } SWAP 1 + GET
          >> } a 7 - GET
        ELSE
          IF a 11 >
          THEN "SRB.w " 53 a + CHR +
          ELSE { "JUMP.a A" "JUMP.a C" "MOVE.a PC,A" "MOVE.a PC,C"
                    "SWAP.a A,PC" "SWAP.a C,PC" } GETN 1 - GET
          END
        END
      END
    >>
  >>

I808 [ D0B ]              ; instructions starting 808
  << { "INTON" "RSI"
        << GETN 1 + -> n
          << "MOVE.p" n ->STR + " #$" + 1 n
            START GETN R->B
            NEXT
            IF n 1 >
            THEN 1 n OVER -
              START SL SL SL SL OR
              NEXT
            END HX-> + ",A" +
          >>
        >> "BUSCB"
        << "CLRB #" GETN ->STR + ",A" + >>
        << "SETB #" GETN ->STR + ",A" + >>
        << "BRBC #" GETN ->STR + ",A" + JPB >>
        << "BRBS #" GETN ->STR + ",A" + JPB >>
        << "CLRB #" GETN ->STR + ",C" + >>
        << "SETB #" GETN ->STR + ",C" + >>
        << "BRBC #" GETN ->STR + ",C" + JPB >>
        << "BRBS #" GETN ->STR + ",C" + JPB >>
        "JUMP.a (A)" "BUSCD" "JUMP.a (C)" "INTOFF"
    } GETN 1 + GET
  >>

IN80 [ C680 ]             ; all instructions starting with the byte 80
  << { "OUT.s C" "OUT.x C" "IN.4 A" "IN.4 C" "UNCNFG" "CONFIG" "MOVE.a ID,C"
        "SHUTDN" I808 "ADD.a P+1,C" "RESET" "BUSCC"
        << "MOVE.1 P,C," GETN ->STR + >>
        << "MOVE.1 C," GETN ->STR + ",P" + >>
        "SREQ"
        << "SWAP.1 P,C," GETN ->STR + >>
    } GETN 1 + GET
  >>

IN9F [ 95CF ]             ; process branch instructions (common code)
  << GETN -> a
    <<
      IF
      THEN { "BRGT" "BRLT" "BRGE" BRLE" } a 4 / IP 1 + GET SWAP + 4 a OVER MOD
        + REGS
      ELSE
        IF a 8 <
        THEN { "BREQ" "BRNE" } a 4 / IP 1 + GET SWAP + 4 a OVER MOD + REGS
        ELSE { "BRZ" "BRNZ" } a 4 / IP 1 - GET SWAP + " " + a 4 MOD 65 + CHR
        END
      END + JPB
    >>
  >>

IN9 [ 730D ]              ; instructions starting with a 9 nibble
  << GETN DUP 8 MOD FIELDS SWAP 7 > IN9F
  >>

HWFLGS [ BEB3 ]           ; concatenate the hardware flags oin intruction
  << GETN R->B -> f
    <<
      IF f #1h AND B->R
      THEN " XM" +
      END
      IF f #2h AND B->R
      THEN " SB" +
      END
      IF f #4h AND B->R
      THEN " SR" +
      END
      IF f #8h AND B->R
      THEN " MP" +
      END
    >>
  >>

IN8 [ 23F5 ]              ; instructions starting with the nibble 8
  << { IN80 IN81
      << "CLRB" HWFLGS >>
      << "BRBC" HWFLGS JPB >>
      << "CLRB #" GETN ->STR + ",ST" + >>
      << "SETB #" GETN ->STR + ",ST" + >>
      << "BRBC #" GETN ->STR + ",ST" + JPB >>
      << "BRBS #" GETN ->STR + ",ST" + JPB >>
      << "BRNE.1 P,#" GETN ->STR + JPB >>
      << "BREQ.1 P,#" GETN ->STR + JPB >>
      << ".a" 0 IN9F >>
      << ".a" 1 IN9F >>
      << "JUMP.4 " PC B->R GETW DUP
        IF 32767 >
        THEN 65536 -
        END + R->B #FFFFFh AND HX-> +
      >>
      << "JUMP.a " GETA R->B HX-> + >>
      << "CALL.4 " GETW DUP
        IF 32767 >
        THEN 65536 -
        END PC B->R + R->B #FFFFFh AND HX-> +
      >>
      << "CALL.a " GETA R->B HX-> + >>
    } GETN 1 + GET
  >>

JPB [ 8908 ]              ; process byte offset for jumps
  << "," + PC B->R GETB DUP
    IF 127 >
    THEN 256 -
    END + R->B #FFFFFh AND HX-> +
  >>

IN13 [ EBB ]              ; process instructions starting with the byte 13
  << GETN R->B -> a
    << a #2h AND B->R "SWAP" "MOVE" IFTE a #8h AND B->R ".4 " ".a " IFTE +
        a #4h AND B->R "C,D" "A,D" IFTE + a #1h AND B->R ->STR +
    >>
  >>

INK [ 3E93 ]              ; ADD DEC
  << GETN -> a
    <<
      IF a 11 >
      THEN "DEC" SWAP + " " + a 53 + CHR
      ELSE "ADD" SWAP + a 7 > a 4 - a 4 < a DUP 4 + IFTE IFTE REGS
      END +
    >>
  >>

INP [ 3E51 ]              ; CLR MOVE SWAP
  << GETN -> a
    <<
      IF a 11 >
      THEN "SWAP" SWAP + a 12 - REGS
      ELSE
        IF a 4 <
        THEN "CLR" SWAP + " " + a 65 + CHR
        ELSE "MOVE" SWAP + a 4 - REGS
        END
      END +
    >>
  >>

INQ [ 83F7 ]              ; SUB INC SUBN
  << GETN -> a
    <<
      IF a 11 >
      THEN "SUBN" SWAP + a 12 - REGS
      ELSE
        IF a 3 > a 8 < AND
        THEN "INC" SWAP + " " + 61 a + CHR
        ELSE "SUB" SWAP + a DUP 7 > 4 0 IFTE - REGS
        END
      END +
    >>
  >>

INR [ 4B5C ]              ; SLN SRN NEG NOT
  << GETN DUP 4 / IP 1 + { "SLN" "SRN" "NEG" "NOT" } SWAP GET ROT + " " + SWAP
      4 MOD 65 + CHR +
  >>

INF [ 8256 ]              ; decode all instructions that start with F
  << ".a" INR
  >>

INE [ 824E ]              ; decode all that start with E
  << ".a" INQ
  >>

IND [ 8246 ]              ; decode all that start with D
  << ".a" INP
  >>

INC [ 829E ]              ; decode all that start with C
  << ".a" INK
  >>

INB [ 47F4 ]              ; decode all that start with B
  << GETN DUP 8 MOD FIELDS SWAP
    IF 7 >
    THEN INR
    ELSE INQ
    END
  >>

INA [ 73D4 ]              ; decode all that start with A
  << GETN DUP 8 MOD FIELDS SWAP
    IF 7 >
    THEN INP
    ELSE INK
    END
  >>

IN7 [ F7F ]               ; handle CALL.3
  << "CALL.3 " GET3 DUP
    IF 2047 >
    THEN 4096 -
    END PC B->R + R->B #FFFFFh AND HX-> +
  >>

IN6 [ 76C2 ]              ; process the JUMP.3 instructions
  << "JUMP.3 " PC B->R GET3 DUP
    IF 2047 >
    THEN 4096 -
    END + R->B #FFFFFh AND HX-> +
  >>

IN5 [ 1F3B ]              ; process the BRCC instructions
  << "BRCC " PC B->R GETB DUP
    IF 127 >
    THEN 256 -
    END + R->B #FFFFFh AND HX-> +
  >>

IN4 [ 1F3A ]              ; process the BRCS instructions
  << "BRCS " PC B->R GETB DUP
    IF 127 >
    THEN 256 -
    END + R->B #FFFFFh AND HX-> +
  >>

IN3 [ 73B3 ]              ; decode the MOVE.Pn instructions
  << GETN 1 + -> n
    <<  "MOVE.p" n ->STR + " #$" + 1 n
      START GETN R->B NEXT
      IF n 1 >
      THEN 1 n OVER -
        START SL SL SL SL OR
        NEXT
      END HX-> + ",C" +
    >>
  >>

HX-> [ 5236 ]             ; convert a real into a hex string
  << ->STR 3 OVER SIZE 1 - SUB
  >>

GETHA [ A17A ]            ; get address as hex string
  << GETA R->B HX->
  >>

IN1XY [ F422 ]            ; decode addressing mode for 14 15 instructions
  << { "A,(D0)" "A,(D1)" "(D0),A" "(D1),A" "C,(D0)" "C,(D1)" "(D0),C" "(D1),C" }
      GETN SWAP OVER 8 MOD 1 + GET SWAP 8 <
  >>

IN1JK [ B069 ]            ; decode register for 10 11 12 instructions
  << GETN DUP 8 < "A" "C" IFTE SWAP 8 MOD ->STR
  >>

IN1 [ 511 ]               ; process all instructions starting with 1
  << {
      << IN1JK "MOVE.w " ROT + ",R" + SWAP + >>
      << IN1JK "MOVE.w R" SWAP + "," + SWAP + >>
      << IN1JK "SWAP.w " ROT + ",R" + SWAP + >>
      IN13
      << IN1XY "MOVE.a " "MOVE.b " IFTE SWAP + >>
      <<
        IF IN1XY
        THEN GETN FIELDS
        ELSE "." GETN 1 + ->STR +
        END "MOVE" SWAP + " " + SWAP +
      >>
      << "ADD.a #" GETN 1 + ->STR + ",D0" + >>
      << "ADD.a #" GETN 1 + ->STR + ",D1" + >>
      << "SUB.a #" GETN 1 + ->STR + ",D0" + >>
      << "MOVE.2 #" GETB ->STR + ",D0" + >>
      << "MOVE.4 #" GETW ->STR + ",D0" + >>
      << "MOVE.5 #$" GETHA ->STR + ",D0" + >>
      << "SUB.a #" GETN 1 + ->STR + ",D1" + >>
      << "MOVE.2 #" GETB ->STR + ",D1" + >>
      << "MOVE.4 #" GETW ->STR + ",D1" + >>
      << "MOVE.5 #$" GETHA ->STR + ",D1" + >>
    } GETN 1 + GET
  >>

IN2 [ 23DC ]              ; process all instructions with 2 as first nibble
  << "MOVE.1 #" GETN ->STR + ",P" +
  >>

PARSE [ AC79 ]            ; keep eval'ing top of stack until a string appears
  << -> z
    <<
      WHILE z TYPE 2 =/=
      REPEAT z EVAL 'z' STO
      END z
    >>
  >>

IN0 [ 8AE8 ]              ; decode all instructions starting with 0 nibble
  << { "RETSETXM" "RET" "RETSETC" "RETCLRC" "SETHEX" "SETDEC"
        "PUSH.a C" "POP.a C" "CLR.x ST" "MOVE.x ST,C" "MOVE.x C,ST"
        "SWAP.x C,ST" "INC.1 P" "DEC.1 P"
        << GETN FIELDS GETN DUP 7 > "AND" "OR" IFTE ROT + SWAP 8 MOD REGS + >>
        "RETI"
    } GETN 1 + GET
  >>

GET3 [ 869E ]             ; load a 12 bit thing from PC
  << GETB GETN 256 * +
  >>

GETA [ 25C0 ]             ; load a 20 bit pointer from PC
  << GETW GETN 65536 * +
  >>

GETW [ E69E ]             ; load a 16 bit thing from PC
  << GETB GETB 256 * +
  >>

GETB [ 44D4 ]             ; load a byte from PC
  << GETN GETN 16 * +
  >>
--------------------------------------------------------------------------------

khbsnsr@nmtsun.nmt.edu (Kenneth Brunell) (12/14/89)

I am sorta' new to this news group, so I guess I wasn't around for the posting
of Alonzo Gariepy's instruction set, could someone possibly EMAIL a copy of
it to me?  I would be eternally greatful :-)
Also, some information on the checksum program, apparently posted here some
time ago, to calculate the CRC that is proveded with every program that
people present here, would be VERY helpful, EMAIL, or reposted in the
newsgroup.

Thanx a million.

---
Ken    (khbsnsr@nmtsun.nmt.edu)