Article 1500 of comp.sys.handhelds: Path: en.ecn.purdue.edu!pur-ee!mentor.cc.purdue.edu!purdue!bu.edu!snorkelwacker!bloom-beacon!bloom-beacon!athena.mit.edu!chekmate From: chekmate@athena.mit.edu (Adam Kao) Newsgroups: comp.sys.handhelds Subject: routines to enter HP48 machine language programs Message-ID: <1990Mar14.183918.15326@athena.mit.edu> Date: 14 Mar 90 18:39:18 GMT Sender: news@athena.mit.edu (News system) Reply-To: chekmate@athena.mit.edu (Adam Kao) Organization: Massachusetts Institute of Technology Lines: 242 ===================================================================== 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: 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!