Path: utzoo!mnetor!uunet!mcvax!jurjen From: jurjen@cwi.nl (Jurjen N.E. Bos) Newsgroups: comp.sys.hp Subject: HP28C (version 1BB) SYSEVALs - revised repost (long) Message-ID: <7515@boring.cwi.nl> Date: 3 Mar 88 19:06:21 GMT Organization: CWI, Amsterdam Lines: 207 Keywords: HP28C, SYSEVAL I heard my earlier message did not reach everyone -- so I repost a clarified version. Introduction Warning: people not having version 1BB can get disastous results. The HP28 objects consists of a routine pointer, followed by the data field. The HP28C is adressed in nibbles. Pointers are, as you will know, 5 nibbles. The routine pointer points directly to a machinecode subroutine that executes the code for that kind of object. The only objects having a printable form are the "normal" objects that are in the manual. Other objects give "System Object", whatever they are. The data field of an object can be anything. Types, as far as I know: Pointer Type Followed by (size in parentheses) 02911 word value(5) 02933 real sign(1),mantissa(12),exponent+500(3) 02955 high r. sign(1),mantissa(15),exponent+50000(5) 02977 complex real,imag part (2*16) 0299D high c. real,imag part (2*21) 029BF byte value(2) 029E1 ? 02A0A array size(5),type(5),#dim(5),dimensions(5)...,data 02A2C ? 02A4E string size(5),data(2)... 02A70 binary size(5),data(1)... 02A96 list data(5)...,02F90 02AB8 ? 02ADA algebr. data(5)...,02F90 02C67 program 27F0A,data(5)...,27F1F,02F90 02C96 code size(5),... 02D12 name #letters(2),data(2)... 02D37 local n. #letters(2),data(2)... 02D5C function number(2*3) 067A1 true 067E0 false Interesting addresses: (routines use word arguments, and don't check anything!) 0201E DEPTH 0205A DUP 0207E DUP2 020AB DUPN 020F5 SWAP 02116 DROP 0212A DROP2 02140 DROPN 02067 ROT 02094 OVER 020B4 PICK 020F7 ROLL 02241 ROLLD 03495 CDR (the LISP one) 034DC + for strings 03422 convert string to byte 03599 + for lists O369D + string+byte 0372B make structure given type and size 03845 ->PROG 03859 ->LIST 0386D ->ALG ebraic 0389B STRUCT-> 067FA XOR 06812 NOT 0684E == for reals 06866 AND 06895 OR 068B7 == for any object 06982 get type 069C4 000000h = 069E5 000000h != 06A02 < 06A37 == for words 06A6C != for words 06AA1 > 06ADA + 06AFE - 06B0D 1+ 06B2C 1- 06B4B 2+ 06B6C 2- 06B8D 2* 06BAC 2/ 06BCF * 06C04 DIVMOD 06C98-06F04 are word constants of all kinds of values. 177F1-1BF4C are the routine for the user commands; they check stack depth, do LAST and call an internal routine. examples: + 18F9D pi 18EB7 1A242 STO The following routines are handy conversions. 1C490 number->word 1C565 word->number 1C952 bool to number 1EA55 number to bool Interesting programs: Instead of SYSEVAL one can put the pointer to n directly in the program code, as will be shown later. I write h if I mean either SYSEVAL or the replacement. SYS without EVAL (very nice for peeking in the ROM): This routine makes a pointer to the given address. This means, for example, that #18F9D SYS gives the object +, while #18F9D SYSEVAL adds two numbers. SYS << 06D6Ah 32F25h >> READ read contents of ROM at given address. << 10 - HEX 4 1 FOR R "" 1 4 START OVER 06D6Ah 32F25h 04358h 1C565h R->B #100000 + ->STR DUP SIZE DUP 4 - SWAP SUB " " + SWAP + SWAP 5 + SWAP NEXT 1 23 SUB R DISP -1 STEP 10 + >> SS << DEPTH ->LIST 'T' STO 4FFABh READ DROP T LIST-> DROP 'T' PURGE >> READ displays the contents of memory addresses *backwards*: this is very handy because addresses are stored backwards, and thus directly readable. Furthermore, READ increments the address with the amount it displays, so that it is easy to continue. ->PRG Convert contents of stack to program. You don't get << and >>, but they're unnecessary anyway (except for debugging, don't use HALT!). << 0201Eh 03845h >> Usage of ->PRG: 1) put #27F0A SYS on stack, if you want a << before your program. 2) put all object for the program on stack, in order (a pointer can be put on stack with #value SYS) 4) put #27F1F SYS on stack, if you want a >> after the program. 5) execute ->PRG, an there's your program. A->P convert algebraic to program that does the same. << #27F0A SYS SWAP 32F11h #27F1F SYS ->PRG >> A handy way of getting an address of a known object is putting it in a brand new variable and looking at address #4FFB0: this gives the top 80 nibbles of RAM. You'll soon find out how variables are stored and see your object. This is the most reliable way for observing something. Example: {+} 1 GET gives a single +. Putting this in the variable TP gives as result of #4FFB0 READ: 03A00 202D5 C0250 54020 008B0 2F902 7F1F1 A2B62 7F4E2 79BC2 7F341 783F1 7B0B2 79BC1 783F4 44145 This means: (still backwards) 03A 002 02D5C 02 50 54 02 3A 2 function 2 P T 2 Otherwise said: function number 3A,2 stored in variable PT. The name PT has two letters. More informative is << + >> 'TP' STO #$FFB0 READ: 02F90 27F1F 18F9D 27F0A end >> + << 02C67 02 50 54 02 program 2 P T 2 This learns us that the function + is to be found in ROM at 18F9D. You'll find there the code that does +, written normal way: 02C67 program 1C3A5 check two levels stack & save LAST registers 1C6FA CASE statement on type of top levels 06E00 word 00011: this means two reals 1EC68 + for two reals 06E0A word 00012: real and complex 3323C + for real and complex ... 02F90 end The amount of FORTH code is almost endless: you don't have to know the machine code to come rather far (but it helps). I hope this is clear; please mail me any special requests; I'll post the answers, if it isn't too much. Enjoy the internals of your machine! -- Jurjen No I'm NOT a saint!