[comp.sys.handhelds] routines to enter HP48 machine language programs

chekmate@athena.mit.edu (Adam Kao) (03/15/90)

=====================================================================

NOTE1: This is being posted for me by a friend, since I have no usenet
       or email access right now.  If you want to respond to something
       in this article, you'll have to use (gasp) regular mail.  Hurry
       up while it's still $.25.


NOTE2: All of the SYSEVAL addresses contained in these routines are
       valid for the HP48SX Version A only.


In a previous article, Alonzo Gariepy posted information on using the 
memory scanning utility built into the HP48 to enter machine language
programs.  The three routines below provide a similar capability, without
having to use the memory scanner.  They are adapted from routines that
I have been using on the HP28S.  The main routine, STR->OBJ, takes a string
of hex digits and returns the object whose representation is those digits.
This can be used to create just about anything you want, including 
machine language routines.  Some examples are shown below.

I have provided a little documentation on the SYSEVALs used, but I am
assuming some familiarity with how HP28/HP48 objects are represented, 
and with the machine code of the Saturn CPU.


Dave Kaffine
33 Agassiz Ave.
Belmont, MA  02178
(617) 484-3393


==================================================================


RVRS  [2022h]  75.5 bytes    ; Reverses the characters in a string

<<   -> s 
     << ""                           ; Start with empty string on stack
        s SIZE 1 FOR x               ; Loop from end to beginning
           s x x SUB +               ;  and add each character
        -1 STEP
     >>
>>


SYSRCL  [6E80h]  54 bytes
                            ; Given an address (as a binary integer), 
                            ;   puts the object at that address
                            ;   on the stack without evaluating it.
                            ;   Can also be used with other data types - see
                            ;   detailed description below.
                            ;   NOTE: For the most part, this should not be
                            ;         dangerous until you try to do something
                            ;         with the recalled item.

<< #4003h SYSEVAL              ; <2h>  (short integer - prolog 02911)
   #56B6h SYSEVAL              ; described below
   DROP                        ; DROPs boolean value
>>

The routine at 056B6 works as follows:

    2:  COMP    ==>     2: Object     or    
    1:  <Nh>            1: TRUE              1: FALSE

The routine ignores the type of the object in level 2.  It assumes that
COMP consists of a series of objects, one after another (e.g. a list).
Each list object either consists of a known prolog and the associated data for
that object type, or is a 5-nibble address that is assumed to point to
some data object.  The routine locates the Nth object and puts it on the
stack as follows: If the Nth object in the list starts with a prolog, a
pointer to the object within the list is put on the stack.  If the Nth
object in the list is an address pointing to an actual object, that address
is copied to the stack.  If N is out of range, a FALSE value is put on the
stack, otherwise a TRUE value is put on the stack (FALSE and TRUE are
special objects used by internal routines.  They are displayed as 
"External").

Some notes:  This routine works well with lists, but since the prolog of
the level 2 object is not checked, it gives interesting results with other
data types.  For example, with a binary integer argument:

             Binary integer                      <-- Increasing addresses
           MSB-------------LSB   length  prolog (ignored)
           b bbbbb bbbbb aaaaa   00015   02A4E   <-- Level 2
                          \       \      
                           \       \-- 1st object
                            \
                             \-- 2nd object (interpreted as an address
                                  unless aaaaa = known prolog)

So, if the level one argument has the value 2 (as in the SYSRCL routine),
and the level 2 argument is # aaaaah, the address aaaaa will be put on the
stack, which is the same as RCLing the object located at address aaaaa.

(BTW,  #18CEAh SYSEVAL   converts a real number to a short integer type, and
       #18DBFh SYSEVAL   converts the other way)


Example using SYSRCL:

       #1AB67h  SYSRCL         ==>              +      




STR->OBJ  [C2h]  169 bytes 
                      ;  STRing to OBJect :  This takes a string that is
                      ;    the sequence of nibbles that represent an object
                      ;    you want to create, and translates it into
                      ;    a new string that, when stored in memory,
                      ;    contains a nibble sequence that matches the digits
                      ;    in the original string.  It then uses SYSRCL
                      ;    (see explanation of how that works above,
                      ;    and see additional notes below) to bring the
                      ;    desired object to the stack.

<< RCLF SWAP 64 STWS
   -> s
       << ""                          ; Start with empty string
          1 s SIZE FOR x              ; Loop through string by pairs of
              "#"                     ;   characters
              s x DUP 1 + SUB         ; Get pair of digits (single digit
              RVRS                    ;   at end handled correctly)
              + "h" + OBJ->           ; Swap order, make binary integer
              B->R CHR +              ;  make into character and append
          2 STEP                      ; Loop by 2
       >>
    'obj' STO                         ; Store result so it won't move
    obj SYSRCL                        ; RCL desired object to stack
    NEWOB                             ; Make it a private copy
    SWAP STOF                         ; Clean up
>>

More notes about the routine at 056B6:

This time we're calling it with a "string" as the composite type.
Let's assume the string starts at address sssss.
                                          
      String (constructed to look like a program)
                           5th char    1st 
                             |           |  length    String prolog
      ... xx xx xx xx xx xx 23 61 E0 2D 9D  LLLLL     02A2C : sssss
                                    \       \
                                     \       \-- Object 1
                                      \
                                       \-- Object 2 - starts with 02D9D,
                                           the prolog for a program, so
                                           object consists of entire
                                           program.

SYSRCL  will RCL the program by placing the address (sssss+10) on the
stack.  Unfortunately, this address is not a 'good' address, since it
doesn't point to a 'real' object, it points inside of an object that is not
normally considered a composite type.  This means that if the string gets
moved (e.g. as a result of garbage collection), the address on the stack
will NOT be updated properly!!  That is the reason STR->P stores the
string in the global variable obj first (it must be a global variable - local
variables do not make copies of their contents) so its position won't be
affected by garbage collection.  After calling SYSRCL, NEWOB is used to 
make a separate copy of the item on the stack, so that the string it was 
derived from can be deleted safely.  Note that this program does not depend
upon being in the HOME directory - it does create one global variable called
'obj', but it doesn't matter where in memory 'obj' gets stored.



Here are some examples of the above routines in use:


Start with a simple, relatively safe example:

      Keystrokes                            Results
    -------------------------------------------------------
    "D9D20E163276BA193632B2130"       ==>   "..."
    DUP  BYTES                        ==>   #A0BDh 30
    DROP2                             ==>   "..."
    STR->OBJ                          ==>   <<  +  >>

Try it out - see if it's real.

    3 5 ROT                           ==>   3 5 << + >>
    EVAL                              ==>   8

!!!
          


Now for a more complicated example:

PEEK  [A1BCh]  50 bytes

      1: # aaaaah      ==>       1: # ddddddddddddddddh

      dddddddddddddddd is 16 nibbles of data from address aaaaa.
      The least significant nibble of data is from address aaaaa,
      the most significant is from aaaaa + F.


    D9D20                       ; Begin program
    E1632                       ; << 
      BB691                     ;  B->R  - make sure arg is binary integer,
      B9691                     ;  R->B  - and force new storage for it.
      CCD20                     ;  In-line code prolog
        03000                   ;  48 nibbles (includes these 5 nibbles)
          147      C=DAT1  A    ;    C -> level 1 object
          137      CD1EX        ;    D1 -> level 1 object, 
          06       RSTK=C       ;      save old D1 on stack
          179      D1=D1+  10   ;    D1 -> data of lvl 1 binary integer
          147      C=DAT1  A    ;    C = 5 nibs from binary (addr to PEEK)
          137      CD1EX        ;    D1 = PEEK addr, C -> lvl 1 data area
          15BF     A=DAT1  16   ;    peek 16 nibs into A
          137      CD1EX        ;    D1 -> lvl 1 data area
          159F     DAT1=A  16   ;    Replace binary data with peeked data
          07       C=RSTK       ;    Get old D1
          137      CD1EX        ;    and restore
          142      A=DAT0  A    ;    End every
          164      D0=D0+  5    ;      routine
          808C     PC=(A)       ;        this way.
    93632                       ; >>
    B2130                       ; End program

To enter this, do the following:
    "D9D20E1632BB691B                    ; Direct copy of sequence of
     9691CCD200300014                    ; nibbles above (NOTE: Do not
     7137061791471371                    ; put any extra characters in - 
     5BF137159F071371                    ; there are no spaces or newline
     42164808C93632B2                    ; characters)
     130"
     DUP  BYTES                          ; ==>  #1412h, 88
     DROP2
     STR->OBJ                            ; ==>  << B->R  R->B  Code >>
     'PEEK'    STO                       ;
     'PEEK'    BYTES                     ; ==>  #A1BCh, 50


Now test it out:
     #0  PEEK                ==>         # 8001FDAD801B9632h


That's all for now.  Enjoy!