From alonzo@microsoft.UUCP Sun Nov 19 13:55:11 1989 Path: gmu90x!pyrdc!uunet!microsoft!alonzo From: alonzo@microsoft.UUCP (Alonzo Gariepy) Newsgroups: comp.sys.handhelds Subject: HP28S PROCESSOR NOTES (1 of 4) Keywords: hp28s, cpu, processor, assembler, architecture, memory Message-ID: <9082@microsoft.UUCP> Date: 19 Nov 89 18:55:11 GMT Organization: Microsoft Corp., Redmond WA Lines: 131 HP28S PROCESSOR NOTES Version 1 Copyright (C) 1989, Alonzo Gariepy ================================================================ The next several postings contain my notes on the HP28's CPU. The information they hold should be sufficient for you to start machine language programming your calculator. I make no claims about their quality or fitness for any particular purpose. Please inform me of any errors. I'm on the net at . Copyright (C) 1989 Alonzo M. Gariepy. These notes are divided into four sections: HP28S PROCESSOR NOTES HP28S PROCESSOR ARCHITECTURE HP28S PROCESSOR INSTRUCTION SET HP28S MACHINE CODE USERS GUIDE Future notes may include: HP28S ASSEMBLER/DISASSEMBLER IN PROLOG HP28S MEMORY MANAGEMENT HP28S HARDWARE HP28S BIBLIOGRAPHY These notes may not be distributed for profit without the written consent of the author. ______________________________________________________________________ I have completely reorganized and renamed the instruction set for my own purposes. This may render these notes of no value to some people, for which I am sorry. The new oganization and names have the following properties: 1. One syntax for all instructions: OPERATION.FIELD ARGS ARGS is zero or more register names and constants separated by commas. This syntax simplifies reading, writing, assembly, and disassembly. 2. Translations emphasize orthogonality (what little there is). The hex translations of instructions are decomposed into tables according to the field and register(s) to be operated on. This has simplified the writing of a declaritive assembler/disassembler in Prolog. You can pick up the use of these tables very quickly. 3. All instructions that do the same operation have the same name. For example, all instructions that move data into register C have the form: MOVE.f x,C 4. The mnemonics are much more like those of other processors. Sample Program ============== Here is a sample program called SCR. It scrolls the display memory. SCR: ; scroll the display one pixel upwards. 132 swap.a a,d0 ; save D0 103 move.w a,r3 ; in A. D2 clr.a c ; set address field of C to 0. 3122 move.p2 #22,c ; each 1/2 of LCD is 34*2 columns (+1 on right) 27 move.1 7,p ; point to nibble 7. 307 move.p1 7,c ; nibble 7 gets 0111 bit mask. 10A move.w c,r2 ; we'll want to use these values twice. A81 clr.p b ; B is a flag, when set it is also a bit mask. 1B048FF move.5 #FF840,d0 ; starting address of left columns of LCD. LOOP: ; a 34 cycle loop in a 2 cycle loop: 2 * 34 * 2 = 136 columns. 1527 move.w @d0,a ; read two columns (64 bits) into A. 81C srb.w a ; shift them right (scroll up). 0E06 and.p c,a ; mask out bit shifted from first column. 1507 move.w a,@d0 ; put back the scrolled columns. 16F add.a 16,d0 ; next two columns (16 nibbles hence). CE dec.a c ; decrement and test the lower five nibbles of 8AE9E brnz.a c,LOOP ; C that we are using as a counter. 90D31 brnz.p b,FINISH ; B==1 means we have done both sides of LCD. 1B00CFF move.5 #FFC00,d0 ; starting address of right columns of LCD. 11A move.w r2,c ; yet another set of 34 double columns to do. A85 move.p c,b ; set the flag indicating last time through. 64DF jump LOOP FINISH: ; do the remaining column and exit. 1561 move.wp @d0,c ; read 32 bits (reg A didn't work). 81E srb.w c ; shift column right (scroll up). 0E05 and.p b,c ; mask out bit shifted from first column. 1541 move.wp c,@d0 ; put back (or maybe reg A didn't work here). 20 move.1 0,p ; you must always restore P to 0. 113 move.w r3,a ; time to restore D0. 132 move.a a,d0 ; start dispatch. 142 move.a @d0,a ; where we go next. 164 add.a 5,d0 ; make D0 ready for the next guy to dispatch. 808C jump @a ; bye-bye... ________________________________________________________________ The information in these notes comes from my own experiments, from public HP documents, and from some non-HP documents. Foremost among the latter is the book, "Customize Your HP-28" by W.A.C. Mier-Jedrzejowicz. This book contains a great deal of valuable information about every aspect of the HP28. It is available from: SYNTHETIX P.O. Box 1080 Berkeley, California 94701-1080, USA (415)339-0601 Thanks to Dave Kaffine for explaining the new instructions. ________________________________________________________________ From alonzo@microsoft.UUCP Sun Nov 19 13:56:02 1989 Path: gmu90x!pyrdc!uunet!microsoft!alonzo From: alonzo@microsoft.UUCP (Alonzo Gariepy) Newsgroups: comp.sys.handhelds Subject: HP28S PROCESSOR NOTES (2 of 4) Keywords: hp28s, cpu, processor, assembler, architecture, memory Message-ID: <9083@microsoft.UUCP> Date: 19 Nov 89 18:56:02 GMT Organization: Microsoft Corp., Redmond WA Lines: 284 HP28S PROCESSOR ARCHITECTURE Version 1 Copyright (C) 1989, Alonzo Gariepy ================================================================ Overview ======== The HP28 (Saturn) CPU uses 64 bit data registers and 20 bit address registers. The unit of addressibility is a four bit nibble, hence the address space of the processor is 2^20 nibbles or half a megabyte. The HP28S address space contains 128 kilobytes of ROM at addresses #00000 to #3FFFF, and 32 kilobytes of RAM at addresses #C0000 to #CFFFF. The RAM is aliased at addresses #D0000 to #DFFFF. Other little chunks of the address space are used here and there for hardware control. Most operations on data registers can be restricted to particlar ranges of nibbles, called fields. These fields have been chosen to optimize the floating point arithmetic of the calculator. The format for floating point numbers is a 1 nibble sign, followed by a 12 nibble mantissa and 3 nibble exponent, making 16 nibbles or 64 bits in all. The four data registers are called A, B, C, and D. The instruction set does not allow these registers to be used interchangeably. For example, registers A and B never interact with register D. Memory operations are restricted to data registers A and C with the bulk of the responsibility on register C. There is a 4 bit pointer register, called P, that is used to specify the position of a one nibble field (.P) or the length of a multi-nibble field (.WP). The two 20 bit address registers are called D0 and D1 (go figure) and can be used interchangeably. There are five 64 bit temporary registers called R0, R1, R2, R3, and R4. The operations they support are restricted to moving and swapping with registers A and C. The HP28S system software uses some of the above registers for its own purposes. Register B points to the end of the object heap growing up toward the stack. Register D1 points to the end of the stack growing down toward the heap. Register D holds the size of the free area in between. When it reaches zero, the stack and heap have met and its time to garbage collect. Garbage collection creates free space by discarding unused objects from the heap and compacting what is left. Memory is allocated in units of 5 nibbles. The MEM function calculates the number of free bytes by performing garbage collection and then multiplying D by 2.5. Register P is assumed always to be zero. D0 is the RPL instruction pointer. If you change any of these registers (B, D1, D, P, D0) in your machine code programs, restore their previous values before exiting. It is said that R4 is used by the interrupt handler, but I have yet to confirm this. If you do a SETDEC, make sure you restore the calculation mode with SETHEX before returning. See CPU Bugs section. Fields ====== Each 64 bit register comprises 16 nibbles that can be grouped into fields for calculation and data movement. These nibbles are numbered from right to left starting at 0; nibble 0 is the low order or least signficant nibble and nibble 15 is the high order or most significant nibble: +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ In the following diagrams, each nibble within a field is marked with its position, while those outside are blank. The vertical bar has been removed from between the nibbles of a field. Field: .P Name: Pointer Field Start: nibble P Size: 1 nibble Example: RETZ.P B +---+- - - -+---+---+---+- - - -+---+---+ | | | | P | | | | | +---+- - - -+---+---+---+- - - -+---+---+ Field: .WP Name: Word to Pointer Field Start: nibble 0 Size: P+1 nibbles Example: OR.WP C,D +---+- - - -+---+---+---+- - - -+---+---+ | | | | P P-1 1 0 | +---+- - - -+---+---+---+- - - -+---+---+ Field: .XS Name: Exponent Sign Field Start: nibble 2 Size: 1 nibble Example: NOT.XS C +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | | 2 | | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .X Name: Exponent Field Start: nibble 0 Size: 3 nibbles Example: SUB.X A,C +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | | 2 1 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .S Name: Sign Field Start: nibble 15 Size: 1 nibble Example: CLR.S B +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 15| | | | | | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .M Name: Mantissa Field Start: nibble 3 Size: 12 nibbles Example: MOVE.M B,C +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | 14 13 12 11 10 9 8 7 6 5 4 3 | | | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .B Name: Byte Field Start: nibble 0 Size: 2 nibbles Example: INC.B C +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | | | | 1 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .W Name: Word Field Start: nibble 0 Size: 16 nibbles Example: SWAP.W A,R2 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .A Name: Address Field Start: nibble 0 Size: 5 nibbles Example: ADD.A 5,D1 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | | 4 3 2 1 0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Field: .n Name: n Nibble Field Start: nibble 0 Size: n nibbles Example: MOVE.8 @D0,A +---+- - - -+---+---+---+- - - -+---+---+ | | | |n-1 n-2 1 0 | +---+- - - -+---+---+---+- - - -+---+---+ Field. .Pn Name: n from Pointer Field Start: nibble P Size: n nibbles Example: MOVE.P3 6,C +---+- - - -+---+---+- - - -+---+---+---+- - - -+---+ | | | |P+n-1 P+1 P | | | | +---+- - - -+---+---+- - - -+---+---+---+- - - -+---+ Control Registers ================= In addition to the data and address registers (A, B, C, D, R0, R1, R2, R3, R4, D0, D1, and P) the CPU also has some registers devoted to control, status, and I/O. The control registers are 20 bits long and include the program counter (PC) and the eight level return stack (RSTK). Instructions that directly reference the PC or the return stack use all five nibbles (the .A field). MOVE.A reg,PC ; reg A or C MOVE.A PC,reg ; reg A or C MOVE.A @reg,PC ; reg A or C SWAP.A reg,PC ; reg A or C PUSH.A C POP.A C The PC and RSTK are indirectly modified by JUMP, BRANCH, CALL, and RETURN instructions. One level of the return stack must be available for interrupt handling, leaving seven for program use. Status Registers ================ The status registers include: the carry bit (C), the 16 bit status register (ST), and the 4 bit hardware status register (HST). Each bit of these registers can be set or cleared individually and can be tested as part of a conditional branch or return. The lower 12 bits (.X field) of ST can be cleared, moved, or swapped together: CLR.X ST MOVE.X ST,C MOVE.X C,ST SWAP.X C,ST The carry bit is set or cleared indirectly by arithmetic operations. The RETSETC and RETCLRC instructions do this directly. The hardware status register is made up of the XM, SB, SR, and MP flags. These can be cleared together or in any combination. The XM bit (eXternal Module Missing) is set when the nibbles 00 are executed (the RETSETXM instruction) which happens when you jump to nonexistent memory. SB (the Sticky Bit) is set whenever a non-zero bit is shifted out the right end of a register. The SR bit (Service Request) is set by the SREQ instruction when there is an outstanding service requests (polling). I do not know how the MP (Module Pulled) bit is set (perhaps when power is lost). I/O Registers ============= Finally, there are a 16 bit input register (IN) and a 12 bit ouput register (OUT). The input register is used to read the keyboard, and the output register to control the beeper. Summary ======= Below is a table of all the registers in the CPU. Registers that are used by the system are marked with *. The system only uses the low 20 bits of these registers, which must be restored after use. Since R4 and RSTK are used by interrupts, you should never change the lower 20 bits of R4 nor PUSH/CALL more than seven addresses onto the return stack. 16 nibbles 5 nibbles Data Temp Addr Ctrl Stat I/O Pntr ------ ------ ------ ------ ------ ----- ------ A R0 D0* PC C IN P* B* R1 D1* RSTK* ST ? OUT C R2 HST D* R3 R4* CPU Bugs ======== The CPU has some bugs in it, instructions that do now work correctly. I have run into some, but they are difficult to accurately characterize. When NOTHING else explains your problem, suspect a bug in the processor. Two bugs that I have seen explicitly stated are: 1. SETHEX may not work unless preceded immediately by SETDEC. (Reference: W.Meir). 2. The 818 opcodes (ADD.f x,reg and SUB.f x,reg) don't always work as advertised. To be specific, when the field of such an instruction is XS, S, P, or WP, and a carry (or borrow) is generated out of the most significant nibble, it wraps around and affects the least significant nibble. (Reference: Dave Kaffine). From alonzo@microsoft.UUCP Sun Nov 19 13:57:12 1989 Path: gmu90x!pyrdc!uunet!microsoft!alonzo From: alonzo@microsoft.UUCP (Alonzo Gariepy) Newsgroups: comp.sys.handhelds Subject: HP28S PROCESSOR NOTES (3 of 4) Keywords: hp28s, cpu, processor, assembler, architecture, memory Message-ID: <9084@microsoft.UUCP> Date: 19 Nov 89 18:57:12 GMT Organization: Microsoft Corp., Redmond WA Lines: 1420 HP28S PROCESSOR INSTRUCTION SET Version 1 Copyright (C) 1989, Alonzo Gariepy ================================================================ ============================== ============================== == == == INSTRUCTIONS BY NUMBER == == == ============================== ============================== Here is a list of HP28 opcodes in numerical order. While the separation lines help in navigation, their primary purpose is to delimit the scope of each set of substitution tables. ________________________________________________________________ 00 RETSETXM 01 RET 02 RETSETC 03 RETCLRC 04 SETHEX 05 SETDEC 06 PUSH.A C *** 07 POP.A C *** 08 CLR.X ST *** 09 MOVE.X C,ST *** 0A MOVE.X ST,C *** 0B SWAP.X C,ST *** 0C INC.1 P *** 0D DEC.1 P *** ________________________________________________________________ 0Exy AND.f s,d 0Exz OR.f s,d x | f y z | s d ------- ----------- 0 | P 0 8 | B A 1 | WP 1 9 | C B 2 | XS 2 A | A C 3 | X 3 B | C D 4 | S 4 C | A B 5 | M 5 D | B C 6 | B 6 E | C A 7 | W 7 F | D C F | A ________________________________________________________________ 0F RETI ________________________________________________________________ 10j MOVE.W A,Rn *** 10k MOVE.W C,Rn *** 11j MOVE.W Rn,A *** 11k MOVE.W Rn,C *** 12j SWAP.W A,Rn *** 12k SWAP.W C,Rn *** j k | Rn ---------- 0 8 | R0 1 9 | R1 2 A | R2 3 B | R3 4 C | R4 ________________________________________________________________ 13w MOVE.A s,Dn *** 13x SWAP.A s,Dn *** 13y MOVE.4 s,Dn 13z SWAP.4 s,Dn w x y z | s Dn ---------------- 0 2 8 A | A D0 1 3 9 B | A D1 4 6 C E | C D0 5 7 D F | C D1 ________________________________________________________________ 14x MOVE.A s,d 14y MOVE.B s,d 15xt MOVE.f s,d 15yi MOVE.n s,d ; n = i + 1 x y | s d t | f --------------- ------- 0 8 | A @D0 0 | P 1 9 | A @D1 1 | WP 2 A | @D0 A 2 | XS 3 B | @D1 A 3 | X 4 C | C @D0 4 | S 5 D | C @D1 5 | M 6 E | @D0 C 6 | B 7 F | @D1 C 7 | W ________________________________________________________________ 16x ADD.A x+1,D0 *** 17x ADD.A x+1,D1 *** 18x SUB.A x+1,D0 *** 19xx MOVE.2 xx,D0 1Axxxx MOVE.4 xxxx,D0 1Bxxxxx MOVE.5 xxxxx,D0 1Cx SUB.A x+1,D1 *** 1Dxx MOVE.2 xx,D1 1Exxxx MOVE.4 xxxx,D1 1Fxxxxx MOVE.5 xxxxx,D1 2x MOVE.1 x,P *** 3ix...x MOVE.Pn x...x,C ; n = i + 1 ________________________________________________________________ 4xx BRCS PC+1+xx 420 NOP3 5xx BRCC PC+1+xx 6xxx JUMP.3 PC+1+xxx *** 6300 NOP4 64000 NOP5 7xxx CALL.3 PC+4+xxx *** ________________________________________________________________ 800 OUT.S C 801 OUT.X C 802 IN.4 A *** 803 IN.4 C *** 804 UNCNFG 805 CONFIG 806 MOVE.A ID,C 807 SHUTDN 8080 INTON 80810 RSI 8082ix...x MOVE.Pn x...x,A ; n = i + 1 8083 BUSCB 8084x CLRB x,A 8085x SETB x,A 8086xyy BRBC x,A,PC+5+yy 8087xyy BRBS x,A,PC+5+yy 8088x CLRB x,C 8089x SETB x,C 808Axyy BRBC x,C,PC+5+yy 808Bxyy BRBS x,C,PC+5+yy 808C JUMP.A @A *** 808C MOVE.A @A,PC *** 808D BUSCD 808E JUMP.A @C *** 808E MOVE.A @C,PC *** 808F INTOFF 809 ADD.A P+1,C 80A RESET 80B BUSCC 80Cx MOVE.1 P,C,x *** 80Dx MOVE.1 C,x,P *** 80E SREQ 80Fx SWAP.1 P,C,x *** ________________________________________________________________ 81w RLN.W d 81x RRN.W d 818twi ADD.f i+1,d 818tyi SUB.f i+1,d 819tw SRB.f d 81At0j MOVE.f A,Rn 81At0k MOVE.f C,Rn 81At1j MOVE.f Rn,A 81At1k MOVE.f Rn,C 81At2j SWAP.f A,Rn 81At2k SWAP.f C,Rn 81z SRB.W d t | f w x y z | d j k | Rn ------- ------------- ---------- 0 | P 0 4 8 C | A 0 9 | R0 1 | WP 1 5 9 D | B 1 A | R1 2 | XS 2 6 A E | C 2 B | R2 3 | X 3 7 B F | D 3 C | R3 4 | S 4 D | R4 5 | M 6 | B 7 | W F | A ________________________________________________________________ 81B2 JUMP.A A *** 81B2 MOVE.A A,PC *** 81B3 JUMP.A C *** 81B3 MOVE.A C,PC *** 81B4 MOVE.A PC,A *** 81B5 MOVE.A PC,C *** 81B6 SWAP.A A,PC *** 81B7 SWAP.A C,PC *** ________________________________________________________________ 82x CLRB d* 83xyy BRBC d,PC+3+yy x | d -------- 1 | XM 2 | SB 4 | SR 8 | MP ________________________________________________________________ 84x CLRB x,ST 85x SETB x,ST 86xyy BRBC x,ST,PC+3+yy 87xyy BRBS x,ST,PC+3+yy 88xyy BRNE.1 P,x,PC+3+yy *** 89xyy BREQ.1 P,x,PC+3+yy *** ________________________________________________________________ ttuyy BREQ.f s,d,PC+3+yy ttvyy BRNE.f s,d,PC+3+yy ttwyy BRZ.f s,PC+3+yy ttxyy BRNZ.f s,PC+3+yy zzuyy BRGT.f s,d,PC+3+yy zzvyy BRLT.f s,d,PC+3+yy zzwyy BRGE.f s,d,PC+3+yy zzxyy BRLE.f s,d,PC+3+yy tt zz | f u v w x | s d ----------- --------------- 8A 8B | A 0 4 8 C | A B 90 98 | P 1 5 9 D | B C 91 99 | WP 2 6 A E | C A 92 9A | XS 3 7 B F | D C 93 9B | X 94 9C | S 95 9D | M 96 9E | B 97 9F | W ________________________________________________________________ 8Cxxxx JUMP.4 PC+2+xxxx 8Dxxxxx JUMP.A xxxxx 8Exxxx CALL.4 PC+6+xxxx 8Fxxxxx CALL.A xxxxx ________________________________________________________________ kkx ADD.f s,d kkw DEC.f d ppt CLR.f d ppz MOVE.f s,d ppw SWAP.f s,d qqy SUB.f s,d qqu INC.f d qqw SUBN.f s,d rrt SLN.f d rru SRN.f d rrv NEG.f d rrw NOT.f d kk pp qq rr | f t u v w x y z | s d ----------------- --------------------- A0 A8 B0 B8 | P 0 4 8 C 0 0 4 | B A A1 A9 B1 B9 | WP 1 5 9 D 1 1 5 | C B A2 AA B2 BA | XS 2 6 A E 2 2 6 | A C A3 AB B3 BB | X 3 7 B F 3 3 7 | C D A4 AC B4 BC | S 4 | A A A5 AD B5 BD | M 5 | B B A6 AE B6 BE | B 6 | C C A7 AF B7 BF | W 7 | D D C D E F | A 8 8 8 | A B 9 9 9 | B C A A A | C A B B B | D C ================================================================ ================================================ ================================================ == == == INSTRUCTIONS WITH DEFAULT FIELD SUFFIXES == == == ================================================ ================================================ Here is a summary of all instructions in which you may omit the field suffix after the name. These instructions are marked with *** in the numeric and alphabetic listings. This summary uses the following abbreviations: ac = A or C; Dn = D0 or D1; Rn = R0, R1, R2, R3, or R4. These are the only instructions in which you can omit the field suffix: ________________________________________________________________ .A Instructions that reference D0, D1, PC, or RSTK use the Address Field by default when you omit the .A suffix: PUSH C POP C MOVE ac,Dn SWAP ac,Dn ADD const,Dn SUB const,Dn JUMP @ac MOVE @ac,PC JUMP ac MOVE ac,PC MOVE PC,ac SWAP ac,PC ________________________________________________________________ .1 Instructions that reference P use a one nibble field by default when you omit the .1 suffix: BREQ P,x,PC+3+offset BRNE P,x,PC+3+offset DEC P INC P MOVE x,P MOVE P,C,i MOVE C,i,P RETEQ P,x RETNE P,x SWAP P,C,i ________________________________________________________________ .W Instructions that reference the temporary registers use the entire word by default when you omit the .W suffix: MOVE ac,Rn MOVE Rn,ac SWAP ac,Rn ________________________________________________________________ .3 You can omit the .3 suffix from relative JUMP and CALL instructions that use three nibble offsets: JUMP PC+1+offset CALL PC+4+offset ________________________________________________________________ .X Instructions that reference ST use a three nibble field by default so you can omit the .X suffix: CLR ST MOVE C,ST MOVE ST,C SWAP C,ST ________________________________________________________________ .4 The IN instruction only uses a four nibble field so you can omit the .4 suffix: IN ac ________________________________________________________________ Here is a list of all the instructions that never take a suffix: BRBC BUSCD NOP4 RETCC SETB BRBS CLRB NOP5 RETCLRC SETDEC BRCC CONFIG RESET RETCS SETHEX BRCS INTOFF RET RETSETC SHUTDN BUSCB INTON RETBC RETSETXM SREQ BUSCC NOP3 RETBS RSI UNCNFG ________________________________________________________________ ALL OTHER INSTRUCTIONS REQUIRE A FIELD SUFFIX. The following instructions are similar to ones above but do require a field suffix: ADD.A P+1,C OUT.S C OUT.X C MOVE.2 const,Dn MOVE.4 const,Dn MOVE.5 const,Dn MOVE.4 ac,Dn JUMP.4 PC+2+offset CALL.4 PC+2+offset CALL.A const ================================================================ ============================ ============================ == == == INSTRUCTIONS BY TYPE == == == ============================ ============================ ================================================================ ADD ================================================================ ADD Register to Register kkx ADD.f s,d kk | f x | s d -------- --------- A0 | P 0 | B A A1 | WP 1 | C B A2 | XS 2 | A C A3 | X 3 | C D A4 | S 4 | A A A5 | M 5 | B B A6 | B 6 | C C A7 | W 7 | D D C | A 8 | A B 9 | B C A | C A B | D C Examples: C8 ADD.A A,B ; B = B + A (20 bits) A70 ADD.W B,A ; A = A + B (64 bits) A36 ADD.X C,C ; C = C + C (12 bits) ________________________________________________________________ ADD Constant to Register "The 818... opcodes don't always work as advertised. To be specific, when the field of such an instruction is XS, S, P, or WP, and a carry (or borrow) is generated out of the most significant nibble, it wraps around and affects the least significant nibble." -- D.K. 818twi ADD.f i+1,d t | f x | d ------- ------- 0 | P 0 | A 1 | WP 1 | B 2 | XS 2 | C 3 | X 3 | D 4 | S 5 | M 6 | B 7 | W F | A Examples: 818718 ADD.W 9,B ; B = B + 9 (64 bits) 81860F ADD.B 16,A ; A = A + 16 (8 bits) ________________________________________________________________ ADD Constant to Address Register These instructions let you add a constant from 1 to 16 to the contents of registers D0 or D1. 16x ADD.A x+1,D0 *** 17x ADD.A x+1,D1 *** Examples: 164 ADD 5,D0 ; D0 = D0 + 5 (20 bits) 17E ADD 15,D1 ; D1 = D1 + 15 (20 bits) ________________________________________________________________ ADD Pointer+1 to Register 809 ADD.A P+1,C Examples: 809 ADD.A P+1,C ; C = C + P + 1 (20 bits) ================================================================ AND ================================================================ AND Register to Register 0Exy AND.f s,d x | f y | s d ------- --------- 0 | P 0 | B A 1 | WP 1 | C B 2 | XS 2 | A C 3 | X 3 | C D 4 | S 4 | A B 5 | M 5 | B C 6 | B 6 | C A 7 | W 7 | D C F | A Examples: 0E63 AND.B C,D ; D = D & C (8 bits) 0EF5 AND.A B,C ; C = C & B (20 bits) ================================================================ BRANCH and RETURN ================================================================ These instructions branch or return when an associated test evaluates true. The destination of the branch is the sum of an 8 bit sign extended 2's complement offset and the address of that offset. When the offset is 00, the destination is reached by popping an address off the return stack. In the following, the destination argument is expressed relative to the address of the instruction (designated PC). In the case of a return, this argument can be omitted and the BR in the mnemonic substituted with RET. ________________________________________________________________ Branch/Return Bit Clear Branch/Return Bit Set These instructions branch/return depending on whether the specified bit in a register is 0 or 1. 8086xyy BRBC x,A,PC+5+yy 808Axyy BRBC x,C,PC+5+yy 83zyy BRBC hf,PC+3+yy 86xyy BRBC x,ST,PC+3+yy 8087xyy BRBS x,A,PC+5+yy 808Bxyy BRBS x,C,PC+5+yy 87xyy BRBS x,ST,PC+3+yy z | hf -------- 1 | XM 2 | SB 4 | SR 8 | MP Examples: 808B900 RETBS 9,C ; return if bit 9 of C is set 8765F BRBS 6,ST,PC-8 ; jump 8 nibbles before instruction ; if bit 6 of ST is set 8086E02 BRBC 14,A,PC+37 ; jump 37 nibbles from instruction ; if bit 14 of A is clear 83400 RETC SR ; return if Service Request clear 8380F BRBC MP,PC-13 ; jump -13 if Module Pulled clear ________________________________________________________________ Branch/Return Carry Clear Branch/Return Carry Set These instructions branch/return depending on whether the carry flag is clear or set. 5xx BRCC PC+1+xx 4xx BRCS PC+1+xx Examples: 500 RETCC ; return if carry clear 45F BRCS PC-10 ; branch -10 nibbles if carry set 550 BRCC PC+6 ; branch +6 nibbles if carry clear ________________________________________________________________ Branch/Return Pointer Equal Branch/Return Pointer Not Equal These instructions branch/return depending on whether the 4 bit register P is equal/not equal to a 4 bit constant. 89xyy BREQ.1 P,x,PC+3+yy *** 88xyy BRNE.1 P,x,PC+3+yy *** Examples: 89C31 BREQ P,12,PC+22 ; branch +22 if P equals 12 88500 RETNE P,5 ; return if P not equal to 5 ________________________________________________________________ Branch/Return Register Inequality These instructions branch/return depending on the result of an inequality between the fields of two registers. ttuyy BREQ.f s,d,PC+3+yy ttvyy BRNE.f s,d,PC+3+yy ttwyy BRZ.f s,PC+3+yy ttxyy BRNZ.f s,PC+3+yy zzuyy BRGT.f s,d,PC+3+yy zzvyy BRLT.f s,d,PC+3+yy zzwyy BRGE.f s,d,PC+3+yy zzxyy BRLE.f s,d,PC+3+yy tt zz | f u v w x | s d ----------- --------------- 8A 8B | A 0 4 8 C | A B 90 98 | P 1 5 9 D | B C 91 99 | WP 2 6 A E | C A 92 9A | XS 3 7 B F | D C 93 9B | X 94 9C | S 95 9D | M 96 9E | B 97 9F | W Examples: 8B500 RETLT.A B,C ; return if B < C (20 bits) 93BD0 BRZ.X D,PC+16 ; branch +16 if D is zero (12 bits) 9FA00 RETGE.W C,A ; return if C >= A (64 bits) ================================================================ BUS COMMANDS ================================================================ 8083 BUSCB 80B BUSCC 808D BUSCD 804 UNCNFG ; unconfig all chips 805 CONFIG ; config next chip 806 MOVE.A ID,C ; get ID of current chip 807 SHUTDN ; shutdown bus, stop cpu 80A RESET ; bus reset, resets chips 80E SREQ ; check for service request ================================================================ CALL ================================================================ Call Subroutine Relative Unlike the BR and relative JUMP commands, relative CALLs contain an offset from the next instruction. In the following these are expressed relative to the address of the CALL instruction itself (PC). Offsets are in stored in 2's complement form. 7xxx CALL.3 PC+4+xxx *** 8Exxxx CALL.4 PC+6+xxxx Examples: 7040 CALL PC+68 ; call 68 nibbles from this instruction 8E020E CALL.4 PC-8154 ; call 8154 nibbles back from insruction ________________________________________________________________ Call Subroutine Absolute 8Fxxxxx CALL.A xxxxx Examples: 8F0200C CALL.A #C0020 ; call to absolute address #C0020h ================================================================ CLEAR ================================================================ Clear Field of Register ppt CLR.f d pp | f t| d -------- ------ A8 | P 0| A A9 | WP 1| B AA | XS 2| C AB | X 3| D AC | S AD | M AE | B AF | W D | A Examples: D2 CLR.A C ; clear address field of C (20 bits) A83 CLR.P D ; clear nibble of D pointed to by P AF0 CLR.W A ; clear all of A (64 bits) ________________________________________________________________ Clear Bit 8084x CLRB x,A 8088x CLRB x,C 84x CLRB x,ST Examples: 8084D CLRB 13,A ; clear bit 13 of register A 80880 CLRB 0,C ; clear bit 0 of register C 847 CLRB 7,ST ; clear bit 7 of ST ________________________________________________________________ Clear Hardware Status Flag(s) The bits 1,2,4, and 8 can be ORed together to clear more than one hardware status flag at a time. 82x CLRB d* x | d -------- 1 | XM 2 | SB 4 | SR 8 | MP Examples: 825 CLR XM,SR 822 CLR SB ________________________________________________________________ Clear Bits 0-11 of ST 08 CLR.X ST *** ================================================================ DECREMENT ================================================================ Decrement register one unit. Adjust carry. 0D DEC.1 P *** kkw DEC.f d kk | f w | d -------- ------- A0 | P C | A A1 | WP D | B A2 | XS E | C A3 | X F | D A4 | S A5 | M A6 | B A7 | W C | A Examples: 0D DEC P ; P = P - 1 (4 bits) A3D DEC.X B ; B = B - 1 (12 bits) ================================================================ IN ================================================================ Copy IN register to register A or C 802 IN.4 A *** 803 IN.4 C *** ================================================================ INCREMENT ================================================================ Increment register one unit. Adjust carry. 0C INC.1 P *** qqu INC.f d qq | f u | d -------- ------- B0 | P 4 | A B1 | WP 5 | B B2 | XS 6 | C B3 | X 7 | D B4 | S B5 | M B6 | B B7 | W E | A Examples: 0C INC P ; P = P - 1 (4 bits) B77 INC.W D ; D = D - 1 (64 bits) ================================================================ INTERRUPT COMMANDS ================================================================ 808F INTOFF 8080 INTON 80810 RSI ================================================================ JUMP ================================================================ JUMP Relative The JUMP command takes a 2's complement offset relative to the address of the offset, stored with the least signficant bit first. In the following, the destination is expressed relative to the address of the JUMP instruction. 6xxx JUMP.3 PC+1+xxx *** 8Cxxxx JUMP.4 PC+2+xxxx Examples: 6C10 JUMP PC+29 6C1F JUMP PC-227 8C1001 JUMP.4 PC+4099 ________________________________________________________________ Jump Absolute 8Dxxxxx JUMP.A xxxxx ________________________________________________________________ Jump Register Indirect These opcodes are useful for implementing the threaded RPL interpreter of the HP28S. They can be expressed either as MOVE or JUMP instructions. The effect is to set the PC to the address pointed at by the address pointed at by the register. 808C JUMP.A @A *** 808C MOVE.A @A,PC *** 808E JUMP.A @C *** 808E MOVE.A @C,PC *** ________________________________________________________________ Jump Register Direct Opcodes 81B2 and 81B3 can be expressed either as MOVE or JUMP instructions. The SWAP instructions might be useful for implementing coroutines. 81B2 JUMP.A A *** 81B2 MOVE.A A,PC *** 81B3 JUMP.A C *** 81B3 MOVE.A C,PC *** 81B6 SWAP.A A,PC *** 81B7 SWAP.A C,PC *** ================================================================ MOVE ================================================================ There are so many MOVE instructions that it might make sense to distinguish them with their own names, but there is also virtue in limiting the number of mnemonics one must remember. ________________________________________________________________ MOVE Register to Register ppz MOVE.f s,d pp | f z | s d -------- --------- A8 | P 4 | B A A9 | WP 5 | C B AA | XS 6 | A C AB | X 7 | C D AC | S 8 | A B AD | M 9 | B C AE | B A | C A AF | W B | D C D | A Examples: D9 MOVE.A B,C ; C gets B (20 bits) AE4 MOVE.B B,A ; A gets B (8 bits) AFB MOVE.W D,C ; C gets D (64 bits) ________________________________________________________________ MOVE Memory to Register MOVE Register to Memory These instructions move between memory and registers A or C by indirecting through address registers D0 or D1. 14x MOVE.A s,d 14y MOVE.B s,d 15xt MOVE.f s,d 15yi MOVE.n s,d ; n = i + 1 x y | s d t | f -------------- ------- 0 8 | A @D0 0 | P 1 9 | A @D1 1 | WP 2 A | @D0 A 2 | XS 3 B | @D1 A 3 | X 4 C | C @D0 4 | S 5 D | C @D1 5 | M 6 E | @D0 C 6 | B 7 F | @D1 C 7 | W Examples: 142 MOVE.A @D0,A ; A gets 20 bits stored at D0 15D6 MOVE.7 C,@D1 ; Store 28 bits of C at D1 1577 MOVE.W @D1,C ; C gets 64 bits stored at D1 149 MOVE.B A,@D1 ; Store one byte of A at D1 1516 MOVE.B A,@D1 ; Store one byte of A at D1 1591 MOVE.2 A,@D1 ; Store one byte of A at D1 ________________________________________________________________ MOVE Register to Address Register 13w MOVE.A s,Da *** 13y MOVE.4 s,Da w y | s Da ----------- 0 8 | A D0 1 9 | A D1 4 C | C D0 5 D | C D1 Examples: 131 MOVE A,D1 ; D1 gets A (20 bits) 13C MOVE.4 C,D0 ; D0 gets C (16 bits) ________________________________________________________________ MOVE Register to Temporary Register MOVE Temporary Register to Register 10j MOVE.W A,Rn *** 10k MOVE.W C,Rn *** 11j MOVE.W Rn,A *** 11k MOVE.W Rn,C *** 81At0j MOVE.f A,Rn 81At0k MOVE.f C,Rn 81At1j MOVE.f Rn,A 81At1k MOVE.f Rn,C t | f j k | Rn ------- ---------- 0 | P 0 8 | R0 1 | WP 1 9 | R1 2 | XS 2 A | R2 3 | X 3 B | R3 4 | S 4 C | R4 5 | M 6 | B 7 | W F | A Examples: 100 MOVE A,R0 ; R0 gets A (64 bits) 11C MOVE R4,C ; C gets R4 (64 bits) 81A71C MOVE.W R4,C ; C gets R4 (64 bits) 81A309 MOVE.X C,R1 ; R1 gets C (12 bits) ________________________________________________________________ MOVE Register to PC MOVE PC to Register Opcodes 81B2 and 81B3 can be expressed either as MOVE or JUMP instructions. 81B2 MOVE.A A,PC *** 81B3 MOVE.A C,PC *** 81B4 MOVE.A PC,A *** 81B5 MOVE.A PC,C *** ________________________________________________________________ MOVE Register Indirect to PC These opcodes are useful for implementing the threaded RPL interpreter of the HP28S. They can be expressed either as MOVE or JUMP instructions. The effect is to set the PC to the address pointed at by the address pointed at by the register. 808C MOVE.A @A,PC *** 808E MOVE.A @C,PC *** ________________________________________________________________ MOVE Constant to Register These instructions move a variable length constant from the instruction stream into registers A or C beginning with the nibble pointed to by register P. This results in a unique field type, Pn, where P designates the position where the constant will be moved and n the size of the constant in nibbles. 3ix...x MOVE.Pn x...x,C ; n = i + 1 8082ix...x MOVE.Pn x...x,A ; n = i + 1 Examples: 34910C0 MOVE.P5 #C019,C 32310 MOVE.P3 19,C 808234000 MOVE.P4 4,A ________________________________________________________________ MOVE Constant to Address Register 19xx MOVE.2 xx,D0 1Axxxx MOVE.4 xxxx,D0 1Bxxxxx MOVE.5 xxxxx,D0 1Dxx MOVE.2 xx,D1 1Exxxx MOVE.4 xxxx,D1 1Fxxxxx MOVE.5 xxxxx,D1 Examples: 1940 MOVE.2 4,D0 ; D0 gets 4 (8 bits) 1E1234 MOVE.4 #4321,D1 ; D1 get #4321h (16 bits) 1B12340 MOVE.5 #4321,D0 ; D0 gets #04321h (20 bits) ________________________________________________________________ MOVE Constant to Pointer Register 2x MOVE.1 x,P *** Examples: 27 MOVE 7,P ; P points to nibble 7 2C MOVE 12,P ; P points to nibble 12 ________________________________________________________________ MOVE Pointer Register to Register Nibble MOVE Register Nibble to Pointer Register Move 4 bit P register value to or from the specified nibble (x) of regiester C. 80Cx MOVE.1 P,C,x *** 80Dx MOVE.1 C,x,P *** Examples: 80C0 MOVE P,C,0 ; nibble 0 of C gets P (4 bits) 80D7 MOVE C,7,P ; P gets nibble 7 of C (4 bits) ________________________________________________________________ MOVE Register to Status Register MOVE Status Register to Register 09 MOVE.X C,ST *** 0A MOVE.X ST,C *** ================================================================ NEGATE ================================================================ Negate Register (2's complement) rrv NEG.f d rr | f v | d -------- ------- B8 | P 8 | A B9 | WP 9 | B BA | XS A | C BB | X B | D BC | S BD | M BE | B BF | W F | A Examples: FA NEG.A C ; C = -C (20 bits) BEB NEG.B D ; D = -D (8 bits) ================================================================ NO OPERATION ================================================================ NOP These instructions do nothing. 420 NOP3 6300 NOP4 64000 NOP5 ================================================================ NOT ================================================================ Invert Register (1's complement) rrw NOT.f d rr | f w | d -------- ------- B8 | P C | A B9 | WP D | B BA | XS E | C BB | X F | D BC | S BD | M BE | B BF | W F | A Examples: BCE NOT.S C ; invert nibble 15 of C (4 bits) FF NOT.A D ; invert D (20 bits) ================================================================ OR ================================================================ OR Register to Register 0Exz OR.f s,d x | f z | s d ------- --------- 0 | P 8 | B A 1 | WP 9 | C B 2 | XS A | A C 3 | X B | C D 4 | S C | A B 5 | M D | B C 6 | B E | C A 7 | W F | D C F | A Examples: 0E6C OR.B A,B ; B = B & A (8 bits) 0EFF OR.A D,C ; C = C & D (20 bits) ================================================================ OUT ================================================================ Copy OUT register to register A or C 800 OUT.S C 801 OUT.X C ================================================================ POP ================================================================ POP Address from Stack 07 POP.A C *** ================================================================ PUSH ================================================================ PUSH Address onto Stack 06 PUSH.A C *** ================================================================ RETURN ================================================================ Return from Subroutine, popping return address from stack 01 RET ; return 02 RETSETC ; set carry and return 03 RETCLRC ; clear carry and return 0F RETI ; enable int and return 00 RETSETXM ; set XM flag and return ________________________________________________________________ Conditional Return See BRANCH. Branch instructions function as conditional returns when their destination offset is zero. ================================================================ ROTATE ================================================================ Rotate Left nibble Rotate Right nibble The SB flag is set when a non-zero nibble is shifted from postion 0 to 15 (RRN only). 81w RLN.W d 81x RRN.W d w x | d --------- 0 4 | A 1 5 | B 2 6 | C 3 7 | D Examples: 810 RLN.W A ; rotate A one nibble left 816 RRN.W C ; rotate C one nibble right ================================================================ SET ================================================================ Set Bit 8085x SETB x,A 8089x SETB x,C 85x SETB x,ST Examples: 8085D SETB 13,A ; clear bit 13 of register A 80890 SETB 0,C ; clear bit 0 of register C 857 SETB 7,ST ; clear bit 7 of ST ________________________________________________________________ Set Decimal Set Hexadecimal Sets the CPU to do register arithmetic in HEX (binary) or DEC (binary coded decimal) mode. 05 SETDEC 04 SETHEX ================================================================ SHIFT ================================================================ Shift Left nibble Shift Right nibble Shift Right Bit The SB flag is set when a non-zero nibble/bit is shifted out of position 0 (SRN/SRB only). Zeros shifted in. rrw SLN.f d rrx SRN.f d 819tw SRB.f d 81z SRB.W d rr t | f w x z | d ----------- ----------- B8 0 | P 0 4 C | A B9 1 | WP 1 5 D | B BA 2 | XS 2 6 E | C BB 3 | X 3 7 F | D BC 4 | S BD 5 | M BE 6 | B BF 7 | W F F | A Examples: F3 SLN.A D ; shift D left one nibble (20 bits) BE6 SRN.B C ; shift C right one nibble (8 bits) 81931 SRB.X B ; shift B right one bit (12 bits) ================================================================ SUB ================================================================ Subtract Register from Register The SUBN instruction stores the negative of the subtraction in the destination. qqy SUB.f s,d qqw SUBN.f s,d qq | f y w | s d -------- ----------- B0 | P 0 C | B A B1 | WP 1 D | C B B2 | XS 2 E | A C B3 | X 3 F | C D B4 | S 8 | A B B5 | M 9 | B C B6 | B A | C A B7 | W B | D C E | A Examples: E2 SUB.A A,C ; C = C - A (20 bits) EE SUBN.A A,C ; C = - (C - A) = A - C (20 bits) B70 SUB.W B,A ; A = A - B (64 bits) ________________________________________________________________ Subtract Constant from Register "The 818... opcodes don't always work as advertised. To be specific, when the field of such an instruction is XS, S, P, or WP, and a carry (or borrow) is generated out of the most significant nibble, it wraps around and affects the least significant nibble." -- D.K. 818tyi SUB.f i+1,d t | f y | d ------- ------- 0 | P 8 | A 1 | WP 9 | B 2 | XS A | C 3 | X B | D 4 | S 5 | M 6 | B 7 | W F | A Examples: 818594 SUB.M 5,B ; B = B - 5 (48 bits) 8186BD SUB.B 14,D ; D = D - 14 (8 bits) ________________________________________________________________ Subtract Constant from Address Register 18x SUB.A x+1,D0 *** 1Cx SUB.A x+1,D1 *** Examples: 184 SUB 5,D0 ; D0 = D0 - 5 (20 bits) 1C9 SUB 10,D1 ; D1 = D1 - 10 (20 bits) ================================================================ SWAP ================================================================ SWAP Register with Register ppw SWAP.f s,d pp | f w | s d -------- --------- A8 | P C | B A A9 | WP D | C B AA | XS E | A C AB | X F | C D AC | S AD | M AE | B AF | W D | A Examples: DF SWAP.A C,D ; interchange values of C and D ABC SWAP.X A,B ; interchange low 3 nibbles of A and B ________________________________________________________________ SWAP Register with Address Register 13x SWAP.A s,Da *** 13z SWAP.4 s,Da x z | s Da ------------ 2 A | A D0 3 B | A D1 6 E | C D0 7 F | C D1 Examples: 137 SWAP C,D1 ; interchange low 20 bits of C and D1 13A SWAP.4 A,D0 ; interchange low 16 bits of A and D0 ________________________________________________________________ SWAP Register with Temporary Register 12j SWAP.W A,Rn *** 12k SWAP.W C,Rn *** 81At2j SWAP.f A,Rn 81At2k SWAP.f C,Rn t | f j k | Rn ------- ---------- 0 | P 0 8 | R0 1 | WP 1 9 | R1 2 | XS 2 A | R2 3 | X 3 B | R3 4 | S 4 C | R4 5 | M 6 | B 7 | W F | A Examples: 121 SWAP A,R1 ; interchange A with R1 (64 bits) 12B SWAP C,R3 ; interchange C with R3 (64 bits) 81AF24 SWAP.A A,R4 ; interchange A with R4 (20 bits) ________________________________________________________________ SWAP Register with PC These operations have the effect of saving the PC of the next instruction and transferring control to the address contained in the register. This can be useful for implementing coroutines. 81B6 SWAP.A A,PC *** 81B7 SWAP.A C,PC *** ________________________________________________________________ SWAP Register with Pointer Register Swap 4 bit P register value with the high order nibble of the specified field of register C. 80Fx SWAP.1 P,C,x *** Examples: 80F0 SWAP P,C,0 ; interchange P with low nibble of C 80FF SWAP P,C,15 ; interchange P with high nibble of C ________________________________________________________________ SWAP Register with Status Register 0B SWAP.X C,ST *** ================================================================ From alonzo@microsoft.UUCP Sun Nov 19 13:59:57 1989 Path: gmu90x!pyrdc!uunet!microsoft!alonzo From: alonzo@microsoft.UUCP (Alonzo Gariepy) Newsgroups: comp.sys.handhelds Subject: HP28S PROCESSOR NOTES (4 of 4) Keywords: hp28s, cpu, processor, assembler, architecture, memory Message-ID: <9085@microsoft.UUCP> Date: 19 Nov 89 18:59:57 GMT Organization: Microsoft Corp., Redmond WA Lines: 442 HP28S MACHINE CODE USERS GUIDE Version 1 Copyright (C) 1989, Alonzo Gariepy ================================================================ HOW TO ENTER AND RUN MACHINE CODE PROGRAMS Inline Machine Code and SYSEVAL =============================== How do you execute machine code programs? There are two ways. The first is to place the program at a known location in memory and jump to it using SYSEVAL. The second is to wrap the program up as an inline machine code object (IMC). The second approach is best because you can store an IMC in any variable or function and you don't have to be concerned about its location as it gets moved around in memory. It also executes considerably faster. When you first open your calculator, there is no way to create IMCs, so you have to resort to SYSEVAL at least once to start. Since we're going to be writing lots of programs, we want an easy way to enter them. This section is an explanation of the techniques you can use. The easiest way to create an IMC is to take an object with the same structure, such as a string, and change its type. As an example, let us examine how the string "hello" and the following machine code program are stored in memory. Drop: 174 add 5,d1 ; drop top of stack E7 inc.a d ; increment free stack 142 move.a @d0,a ;\ 164 add 5,d0 ; return to system 808C jmp @a ;/ The string "hello" is stored in memory as E4A20F00008656C6C6F6, while the IMC, Drop, is stored as 69C2041000174E7142164808C. The objects are structured in the following way: type length data 02A4E 0000F 8656C6C6F6 "hello" 02C96 00014 174E7142164808C 174 E7 142 164 808C The type is an address that gets stored backwards. The length of the object includes everything but the type and is also stored backwards. Since the ASCII for "hello" is 68 65 6C 6C 6F, it is apparent that the HP stores characters with their nibbles swapped. The type and length are each 5 nibbles long, and the data part is (length - 5) nibbles long. The next step is to create a string object that has the right data for our machine program: ________________________________________________________________ First let's do it manually so you understand the process. We take the nibbles of the program two at a time, swap they're order, convert them to characters (using CH), and concatenate them into a string: CH << B->R CHR >> #71 CH #E4 CH + #17 CH + #24 CH + #61 CH + #84 CH + #80 CH + #0C CH + ________________________________________________________________ This can be done automatically by the function HEXIFY which takes the machine code in a string and does the conversion. HEXIFY [6AC9] << "" SWAP 1 OVER SIZE FOR j "#" OVER j 1 + DUP SUB + OVER j j SUB + "h" + STR-> B->R CHR ROT SWAP + SWAP 2 STEP DROP >> "174E7142164808C" HEXIFY ________________________________________________________________ Both methods yield the rather unusual string, "q..$a. .", which is represented internally as E4A2051000174E7142164808C0. It is almost exactly what we want for our IMC object. Since strings must have an even number of nibbles an extra zero gets added at the end of the program. All that's left to do is make the string into an IMC by changing E4A20 to 69C20. Changing Object Type ==================== So now let's write a little program that will take an object on the stack and change its type: 143 MOVE.A @D1,A ; new type integer 132 SWAP A,D0 169 ADD 10,D0 146 MOVE.A @D0,C ; contents of integer 132 SWAP A,D0 174 ADD 5,D1 ; pop stack E7 INC.A D ; free space 143 MOVE.A @D1,A ; object 132 SWAP A,D0 144 MOVE.A C,@D0 ; set new type 132 SWAP A,D0 142 MOVE.A @D0,A ;\ 164 ADD 5,D0 ; return to system 808C JUMP @A ;/ First we use HEXIFY to create a string with the code in it. "143132169146132174E7143132144132142164808C" HEXIFY resulting in: "A.#a.d1.G~A.#A.#A.F.." This string must now be turned into an IMC. Since this very string contains the code to do that, we want to run it on itself. At this point, the only way to do so is with SYSEVAL. ________________________________________________________________ First let's do it manually so you understand the process. To use SYSEVAL we follow these four steps. 1. Put the code in a known location. 2. Put the address of this location in another location. 3. Type in any arguments the program needs. 4. Type in address of the second location and SYSEVAL 1. The first variable in the HOME directory always goes at the top of memory, so we'll store the code string there. Since it is 42 nibbles long the code will begin at #CFFD6 (#D0000 - 42). 2. Now we need to put a copy of the address #CFFD6 somewhere. It turns out that the most convenient place is right inside the program just after the return. This will make the program 6 nibbles longer (HEXIFY pads it to an even 48) so our address becomes #CFFD0. "143132169146132174E7143132144132142164808C0DFFC" HEXIFY results in: "A.#a.d1.G~A.#A.#A.F....." So to complete steps 1 and 2 type: HOME 'CHT' DUP PURGE STO 3. We are changing the program itself to an IMC so we put these arguments on the stack: 'CHT' RCL #2C96 4. The address #CFFD0 is store just before the padding 0 at the top of memory, so we type: #CFFFA SYSEVAL CHT is magically changed to a System Object. Here are all the steps summarized as a program. MCHT [8B0C] << "143132169146132174E7143132144132142164808C0DFFC" HEXIFY HOME 'CHT' DUP PURGE STO 'CHT' RCL #2C96h #CFFFAh SYSEVAL DROP >> ________________________________________________________________ Caveat ====== The CHT function is dangerous because it doesn't do any error checking. If you call it with the wrong arguments or too few arguments you may lose memory. This problem is easily solved. There are only 12 type conversions that will work and not all of them make sense to do. They are: string <-> #integer list <-> program string <-> IMC list <-> algebraic IMC <-> #integer program <-> algebraic Here is a program that creates three useful type conversion functions: MTCF [3321] << << IF DUP TYPE 8 != OVER ->STR 1 1 SUB "<<" != OR THEN ABORT END #2A96h CHT >> 'PGM->' STO << IF DUP TYPE 5 != OVER 1 GET ->STR "<<" != OR THEN ABORT END #2C67h CHT >> '->PGM' STO << IF DUP TYPE 2 != THEN ABORT END #2C96h CHT >> '->IMC' STO 'PGM->' '->PGM' '->IMC' 1 3 START DUP RCL 1 ->LIST LIST-> DROP PGM-> 'CHT' DUP2 POS SWAP RCL PUT ->PGM SWAP STO NEXT 'CHT' PURGE >> What we end up with are the following functions: ->ICM converts a string to inline machine code PGM-> converts a program to a list ->PGM converts a list to a program We need all three of these to write a function that makes machine code programming practically effortless. Simple Machine Code Programming with PGM ======================================== PGM [71C6] << 1 + OVER PGM-> SWAP DUP2 GET HEXIFY ->IMC PUT ->PGM SWAP ->PGM DROP >> Here is an example of using PGM to create a peek program: PIGT [4919] << RCWS SWAP 64 STWS #0h OR SWAP STWS "13210314313016914613615671301691547113132142164808C" >> 'PIGT' RCL 9 PGM 'PIG' STO The arguments to PGM are a program and the position in the program of the machine code string, in this case the 9th position. This technique doesn't work if the string is inside an IF, a loop, or another set of << >> brackets. If you need to put other stuff before an IMC in a program, I recommend doing only the minimum necessary to check and prepare arguments for the IMC. ================================================================ STYLE CONVENTIONS FOR HP28S MACHINE CODE As in writing, use blank lines to divide your code into paragraphs that express a single thought. As in writing, if a paragraph gets too long, break it up to increase the amount of white space. Set labels apart and make them descriptive. Just as footnotes* are more effective than parentheses, documentation is more effective than inline comments. I recommend that you type programs entirely in lower case, except for labels, hex constants, and comments. Hex constants should be typed in upper case, and labels in mixed or all upper case. If a comment is close to being a sentence, capitalize the first letter and end the comment with a period. Certain forms of some instructions (marked with ***) have default field specifiers. I suggest you omit the field suffix in these cases. Instructions without a default should always be written with a field suffix. In cases where there could be confusion, you might as well put the suffix on all instructions. At the moment, we have no assembler program to ensure that your source corresponds to its machine code or to enforce the syntax rules of instructions. That is why I have made these rules as simple as possible. When I get time, I will write an assembler. When you are publishing programs, I recommend that you align the parts of each instruction on successive eight character tabs: Hex Name.f Args Comments 33A0D0 move.p4 #0D0A,c ; CR/LF characters ________________________________________________________________ * Too many parenthesized comments in text can destroy both readability and understanding. Footnotes are less obtrusive and provide more leeway for comprehensive explanation. In similar fashion, inline comments distract from the code and are so small they don't explain much. Do not, as I have seen, comment every line with a restatement of what the assembler instruction is doing. Do comment what you put into registers. The actions of a program are better understood at the level of functions and high level control constructs, such as loops and ifs. I have commented every line of my sample programs only because their purpose is to teach the instruction set. ________________________________________________________________ Another sample program: I wanted to write a really fast program to find bit patterns in memory. Most processors perform register operations much more quickly than memory operations, because the memory bus is slower than the internal bus. With even a minimal amount of caching or pipelining (e.g., prefetch) this difference is quite sizable. With that in mind, I designed the following program to minimize memory operations. It turns out only about 10% faster than the brute force approach. One reason is that the speed it gains in minimizing memory reads is partially lost in the more complicated loop structure. This small improvement is probably not worth the added complexity, but it is an interesting program to read: Find: 132 swap a,d0 ;\ 120 swap a,r0 ; save d0 and b AFC swap.w a,b ; 121 swap a,r1 ;/ 174 add 5,d1 ;\ 147 move.a @d1,c ; 134 move c,d0 ; put value in b 16A add 11,d0 ; 1567 move.w @d0,c ; AF5 move.w c,b ;/ 180 sub 1,d0 ;\ 1564 move.s @d0,c ; put number of nibbles (-1) in c(s) 1C4 sub 5,d1 ;/ 143 move.a @d1,a ;\ 130 move a,d0 ; 169 add 10,d0 ; put starting address in d0 142 move.a @d0,a ; 130 move a,d0 ;/ Fetchloop: 1527 move.w @d0,a ; get next word 80DF move c,15,p ; put length in p Panloop: 91052 breq.wp a,b,Found ; full length match! 160 add 1,d0 ;\ BF4 srn.w a ; shift alignment one nibble B46 inc.s c ;/ 51F brcc Panloop ; 80CF move p,c,15 ; put length in c Zoomloop: 0D dec p ; one less nibble to match against 40E brcs Fetchloop ; no more nibbles left 910BD breq.wp a,b,Fetchloop ; partial match BF4 srn.w a ; 160 add 1,d0 ; 5FE brcc Zoomloop ;-exit if we have wrapped memory Found: 143 move.a @d1,a ;\ 132 swap a,d0 ; 169 add 10,d0 ; replace starting address with d0 140 move.a a,@d0 ;/ 20 move 0,p ; restore p 121 swap a,r1 ;\ AFC swap.w a,b ; restore b and d0 120 swap a,r0 ; 132 swap a,d0 ;/ 142 move.a @d0,a ;\ 164 add 5,d0 ; return to system 808C jump @a ;/ FINDT [8AD6] << RCWS 20 STWS SWAP #0h OR SWAP STWS "132120AFC12117414713416A1567AF518015641C414313 0169142130152780DF91052160BF4B4651F80CF0D40E910 BDBF41605FE14313216914020121AFC120132142164808C" 1 + >> then type 'FINDT' RCL 9 PGM 'FIND' STO yielding: << RCWS 20 STWS SWAP #0h OR SWAP STWS System Object 1 +>> The way you use this program is to specify a memory pattern and a place to start looking. A memory pattern is a sequence of up to 15 nibbles and a one nibble length (1-the number of nibbles in the pattern). For, instance if you want to find instances of the instruction 808C in memory, you can type: #C8083 #0 FIND The effect of the 1 + at the end of FIND is to return the address 1 higher than where the pattern was found. That way you can just keep hitting FIND to get subsequent instances. This version doesn't stop until it finds an instance or scans the entire address space. ________________________________________________________________ Good luck! Alonzo Gariepy alonzo@microsoft From alonzo@microsoft.UUCP Tue Nov 21 11:21:50 1989 Path: gmu90x!pyrdc!uunet!microsoft!alonzo From: alonzo@microsoft.UUCP (Alonzo Gariepy) Newsgroups: comp.sys.handhelds Subject: Re: HP28S PROCESSOR NOTES Keywords: hp28s, cpu, processor, assembler, LED, correction Message-ID: <9114@microsoft.UUCP> Date: 21 Nov 89 16:21:50 GMT References: <9085@microsoft.UUCP> Reply-To: alonzo@microsoft.UUCP (Alonzo Gariepy) Organization: Microsoft Corp., Redmond WA Lines: 21 There are some minor corrections to these notes: 1. The hex for the following two instructions was reversed. Here are the correct translations: 09 MOVE.X ST,C *** 0A MOVE.X C,ST *** Make sure to fix this in both parts of the listing. 2. SETHEX and SETDEC work just fine on the HP28 cpu. 3. R4 is not used by interrupts and is available for program use. I have learned that the use of the LED for a remote control is not feasible. The range of the LED is only a few feet compared to much more powerful LEDs in remotes. The modulation frequency is wrong and would have to be simulated poorly. There is a great danger of frying the LED. I give up. Alonzo Gariepy alonzo@microsoft