[comp.sys.handhelds] HP28S PROCESSOR NOTES

alonzo@microsoft.UUCP (Alonzo Gariepy) (11/20/89)

		 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 <uunet!microsoft!alonzo>.

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.
________________________________________________________________

alonzo@microsoft.UUCP (Alonzo Gariepy) (11/20/89)

	       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).

alonzo@microsoft.UUCP (Alonzo Gariepy) (11/20/89)

	    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		***

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

alonzo@microsoft.UUCP (Alonzo Gariepy) (11/20/89)

	    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

alonzo@microsoft.UUCP (Alonzo Gariepy) (11/22/89)

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

billw@hpcvra.CV.HP.COM (Bill Wickes) (11/22/89)

Whoa--where's my Babelfish?  I thought the 28 opcode mnemonics were
"standard" thanks to the publication of the HP-71 IDS.  If so, why
are we inventing new ones?  If not, then it's a shame, given that
the operating system symbol names have not been published, and
one set of nonstandardized names is enough.

Sigh.

Bill Wickes

dan@Apple.COM (Dan Allen) (12/02/89)

>"standard" thanks to the publication of the HP-71 IDS.  If so, why
>are we inventing new ones?  If not, then it's a shame, given that
>the operating system symbol names have not been published, and
>one set of nonstandardized names is enough.
>
>Sigh.
However, the HP-71 IDS is not available any longer, and when it did it
cost $150 or more.  If you posted the HP-71 IDS stuff then we could use
the proper"mnemonics.

Dan Allen
Apple Computer