summaryrefslogtreecommitdiff
path: root/opcodes.asm.m4
diff options
context:
space:
mode:
authorDuncan Smith2010-11-12 21:30:13 -0800
committerDuncan Smith2010-11-12 21:30:13 -0800
commit2164cc7b99ab44b9efe03d5f4dc2392fc34791f3 (patch)
tree160c87551ac0e6232408d8582c95bac04ed18ffe /opcodes.asm.m4
parent27a6de6da13ff3afc1740cf193ed11623a75829d (diff)
Reworked opcodes.asm to use m4. Soon, it will be clean.
Diffstat (limited to 'opcodes.asm.m4')
-rw-r--r--opcodes.asm.m42234
1 files changed, 2234 insertions, 0 deletions
diff --git a/opcodes.asm.m4 b/opcodes.asm.m4
new file mode 100644
index 0000000..9f3a3fe
--- /dev/null
+++ b/opcodes.asm.m4
@@ -0,0 +1,2234 @@
+;;; ========================================================================
+;;; ========================================================================
+;;; ___ ___ ======= ==============================
+;;; ___( _ ) / _ \ emulation core ====================================
+;;; |_ / _ \| | | | emulation core ===================================
+;;; / ( (_) | |_| | emulation core ==================================
+;;; /___\___/ \___/ emulation core =================================
+;;; ======= ==============================
+;;; ========================================================================
+;;; ========================================================================
+
+;;; http://z80.info/z80oplist.txt
+
+ ;; == Memory Macros ================================================
+
+ ;; Macro to read a byte from main memory at register \1. Puts
+ ;; the byte read in \2.
+FETCHB MACRO
+ move.w \1,d1
+ bsr deref
+ move.b (a0),\2
+ ENDM
+
+ ;; Macro to write a byte in \1 to main memory at \2
+PUTB MACRO
+ move.w \2,d1
+ bsr deref
+ move.b \1,(a0)
+ ENDM
+
+ ;; Macro to read a word from main memory at register \1
+ ;; (unaligned). Puts the word read in \2.
+FETCHW MACRO ; ?/16
+ move.w \1,d1 ; 4/2
+ bsr deref ; ?/4
+ ;; XXX SPEED
+ move.b (a0)+,d2
+ move.b (a0),\2
+ rol.w #8,\2
+ move.b d2,\2
+ ENDM
+
+ ;; Macro to write a word in \1 to main memory at \2 (regs only)
+PUTW MACRO ;
+ move.w \2,d1
+ bsr deref
+ move.w \1,d0
+ move.b d0,(a0)+
+ LOHI d0
+ move.b d0,(a0)
+ ENDM
+
+ ;; Push the word in \1 (register) using stack register a4.
+ ;; Sadly, I can't trust the stack register to be aligned.
+ ;; Destroys d2.
+
+ ;; (SP-2) <- \1_l
+ ;; (SP-1) <- \1_h
+ ;; SP <- SP - 2
+PUSHW MACRO
+ move.w \1,d2
+ LOHI d2 ;slow
+ move.b d2,-(a4) ; high byte
+ move.b \1,-(a4) ; low byte
+ ENDM
+
+ ;; Pop the word at the top of stack a4 into \1.
+ ;; Destroys d0.
+
+ ;; \1_h <- (SP+1)
+ ;; \1_l <- (SP)
+ ;; SP <- SP + 2
+POPW MACRO
+ move.b (esp)+,\1
+ LOHI \1 ;slow
+ move.b (esp)+,\1 ; high byte
+ HILO \1 ;slow
+ ENDM
+
+ ;; == Immediate Memory Macros ==
+
+ ;; Macro to read an immediate byte into \1.
+FETCHBI MACRO ; 8 cycles, 2 bytes
+ move.b (epc)+,\1 ; 8/2
+ ENDM
+
+ ;; Macro to read an immediate word (unaligned) into \1.
+FETCHWI MACRO ; 42 cycles, 8 bytes
+ ;; XXX SPEED
+ move.b (epc)+,d2
+ move.b (epc)+,\1
+ rol.w #8,\1
+ move.b d2,\1
+ ENDM
+
+ ;; == Common Opcode Macros =========================================
+
+ ;; To align opcode routines.
+_align SET 0
+
+START MACRO
+ ORG emu_plain_op+_align
+_align SET _align+$40
+ ENDM
+
+ ;; LOHI/HILO are hideously slow for instructions used often.
+ ;; Interleave registers instead:
+ ;;
+ ;; d4 = [B' B C' C]
+ ;;
+ ;; Thus access to B is fast (swap d4) while access to BC is
+ ;; slow.
+
+ ;; When you want to use the high reg of a pair, use this first
+LOHI MACRO ; 22 cycles, 2 bytes
+ ror.w #8,\1 ; 22/2
+ ENDM
+
+ ;; Then do your shit and finish with this
+HILO MACRO ; 22 cycles, 2 bytes
+ rol.w #8,\1
+ ENDM
+
+ ;; Rearrange a register: ABCD -> ACBD.
+WORD MACRO
+ move.l \1,-(sp) ;12 cycles / 2 bytes
+ movep.w 0(sp),\1 ;16 cycles / 4 bytes
+ swap \1 ; 4 cycles / 2 bytes
+ movep.w 1(sp),\1 ;16 cycles / 4 bytes
+ addq #4,sp ; 4 cycles / 2 bytes
+ ;; overhead: 52 cycles /14 bytes
+ ENDM
+
+ ;; == Special Opcode Macros ========================================
+
+ ;; Do an ADD \1,\2
+F_ADD_W MACRO
+ ENDM
+ ;; Do an SUB \1,\2
+F_SUB_W MACRO
+ ENDM
+
+ ;; INC and DEC macros
+F_INC_B MACRO
+ move.b #1,f_tmp_byte-flag_storage(a3)
+ move.b #1,f_tmp_src_b-flag_storage(a3)
+ move.b \1,f_tmp_dst_b-flag_storage(a3)
+ addq #1,\1
+ moveq #2,d0
+ F_CLEAR d0
+ F_OVFL
+ ENDM
+
+F_DEC_B MACRO
+ move.b #1,f_tmp_byte-flag_storage(a3)
+ st f_tmp_src_b-flag_storage(a3) ;; why did I do this?
+ move.b \1,f_tmp_dst_b-flag_storage(a3)
+ subq #1,\1
+ F_SET #2
+ ENDM
+
+F_INC_W MACRO
+ addq.w #1,\1
+ ENDM
+
+F_DEC_W MACRO
+ subq.w #1,\1
+ ENDM
+
+ ;; I might be able to unify rotation flags or maybe use a
+ ;; lookup table
+
+
+ ;; This is run at the end of every instruction routine.
+done:
+ clr.w d0 ; 4 cycles / 2 bytes
+ move.b (epc)+,d0 ; 8 cycles / 2 bytes
+ move.b d0,$4c00+32*(128/8)
+ rol.w #6,d0 ;18 cycles / 2 bytes
+ jmp 0(a5,d0.w) ;14 cycles / 4 bytes
+ ;; overhead: 42 cycles /10 bytes
+
+
+DONE MACRO
+ bra done
+ ENDM
+
+ ;; Timing correction for more precise emulation
+ ;;
+ ;; \1 is number of tstates the current instruction should take
+ ;; \2 is number of cycles taken already
+TIME MACRO
+ ENDM
+
+ CNOP 0,32
+
+emu_plain_op: ; Size(bytes) Time(cycles)
+ ; S0 T0
+ ;; NOP
+OPCODE(00,`',4)
+
+ ; S12 T36
+ ;; LD BC,immed.w
+ ;; Read a word and put it in BC
+ ;; No flags
+OPCODE(01,`
+ HOLD_INTS
+ FETCHWI ebc
+ CONTINUE_INTS
+ ')
+
+ ; S4 T14
+ ;; LD (BC),A
+ ;; (BC) <- A
+ ;; No flags
+OPCODE(02,`
+ PUTB eaf,ebc
+ ')
+
+ ; S2 T4
+ ;; INC BC
+ ;; BC <- BC+1
+ ;; No flags
+OPCODE(03,`
+ F_INC_W ebc
+ ')
+
+ ;; INC B
+ ;; B <- B+1
+OPCODE(04,`
+ LOHI ebc
+ F_INC_B ebc
+ HILO ebc
+ ')
+
+ ;; DEC B
+ ;; B <- B-1
+OPCODE(05,`
+ LOHI ebc
+ F_DEC_B ebc
+ HILO ebc
+ ') ;nok
+
+ ; S10 T26
+ ;; LD B,immed.b
+ ;; Read a byte and put it in B
+ ;; B <- immed.b
+ ;; No flags
+OPCODE(06,`
+ HOLD_INTS
+ LOHI ebc
+ FETCHBI ebc
+ CONTINUE_INTS
+ HILO ebc
+ ') ;nok
+
+ ;; RLCA
+ ;; Rotate A left, carry bit gets top bit
+ ;; Flags: H,N=0; C aff.
+ ;; XXX flags
+OPCODE(07,` ; S2 T4
+ rol.b #1,eaf
+ ') ;nok
+
+ ;; EX AF,AF'
+ ;; No flags
+ ;; XXX AF
+OPCODE(08,` ; S2 T4
+ swap eaf
+ ') ;nok
+
+ ;; ADD HL,BC
+ ;; HL <- HL+BC
+ ;; Flags: H, C aff.; N=0
+OPCODE(09,`
+ F_ADD_W ebc,ehl
+ ') ;nok
+
+ ; S4 T14
+ ;; LD A,(BC)
+ ;; A <- (BC)
+ ;; No flags
+OPCODE(0a,`
+ FETCHB ebc,eaf
+ ')
+
+ ;; DEC BC
+ ;; BC <- BC-1
+ ;; No flags
+OPCODE(0b,` ; S2 T4
+ F_DEC_W ebc
+ ') ;nok
+
+ ;; INC C
+ ;; C <- C+1
+ ;; Flags: S,Z,H aff.; P=overflow, N=0
+OPCODE(0c,`
+ F_INC_B ebc
+ ') ;nok
+
+ ;; DEC C
+ ;; C <- C-1
+ ;; Flags: S,Z,H aff., P=overflow, N=1
+OPCODE(0d,`
+ F_DEC_B ebc
+ ') ;nok
+
+ ; S6 T18
+ ;; LD C,immed.b
+ ;; No flags
+OPCODE(0e,`
+ HOLD_INTS
+ FETCHBI ebc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RRCA
+ ;; Rotate A right, carry bit gets top bit
+ ;; Flags: H,N=0; C aff.
+ ;; XXX FLAGS
+OPCODE(0f,`
+ ror.b #1,eaf
+ ') ;nok
+
+ ; S32
+ ;; DJNZ immed.w
+ ;; Decrement B
+ ;; and branch by immed.b
+ ;; if B not zero
+ ;; No flags
+OPCODE(10,`
+ HOLD_INTS
+ LOHI ebc
+ subq.b #1,ebc
+ beq.s end_10 ; slooooow
+ FETCHBI d1
+ move.l epc,a0
+ bsr underef
+ add.w d1,d0 ; ??? Can I avoid underef/deref cycle?
+ bsr deref
+ move.l a0,epc
+end_10:
+ HILO ebc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; LD DE,immed.w
+ ;; No flags
+OPCODE(11,`
+ HOLD_INTS
+ FETCHWI ede
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; LD (DE),A
+ ;; No flags
+OPCODE(12,`
+ move.w ede,d0
+ rol.w #8,d0
+ FETCHB d0,eaf
+ ') ;nok
+
+ ;; INC DE
+ ;; No flags
+OPCODE(13,`
+ F_INC_W ede
+ ') ;nok
+
+ ;; INC D
+ ;; Flags: S,Z,H aff.; P=overflow, N=0
+OPCODE(14,`
+ LOHI ede
+ F_INC_B ede
+ HILO ede
+ ') ;nok
+
+ ;; DEC D
+ ;; Flags: S,Z,H aff.; P=overflow, N=1
+OPCODE(15,`
+ LOHI ede
+ F_DEC_B ede
+ HILO ede
+ ') ;nok
+
+ ;; LD D,immed.b
+ ;; No flags
+OPCODE(16,`
+ HOLD_INTS
+ LOHI ede
+ FETCHBI ede
+ CONTINUE_INTS
+ HILO ede
+ ') ;nok
+
+ ;; RLA
+ ;; Flags: P,N=0; C aff.
+ ;; XXX flags
+OPCODE(17,`
+ roxl.b #1,eaf
+ ') ;nok
+
+ ;; JR immed.b
+ ;; PC <- immed.b
+ ;; Branch relative by a signed immediate byte
+ ;; No flags
+OPCODE(18,`
+ HOLD_INTS
+ clr.w d1
+ FETCHBI d1
+ move.l epc,a0
+ bsr underef
+ add.w d0,d1 ; ??? Can I avoid underef/deref cycle?
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; ADD HL,DE
+ ;; HL <- HL+DE
+ ;; Flags: H,C aff,; N=0
+OPCODE(19,`
+ F_ADD_W ede,ehl
+ ') ;nok
+
+ ;; LD A,(DE)
+ ;; A <- (DE)
+ ;; No flags
+OPCODE(1a,`
+ FETCHB ede,eaf
+ ') ;nok
+
+ ;; DEC DE
+ ;; No flags
+OPCODE(1b,`
+ subq.w #1,ede
+ ') ;nok
+
+ ;; INC E
+ ;; Flags: S,Z,H aff.; P=overflow; N=0
+OPCODE(1c,`
+ F_INC_B ede
+ ') ;nok
+
+ ;; DEC E
+ ;; Flags: S,Z,H aff.; P=overflow, N=1
+OPCODE(1d,`
+ F_DEC_B ede
+ ') ;nok
+
+ ;; LD E,immed.b
+ ;; No flags
+OPCODE(1e,`
+ HOLD_INTS
+ FETCHBI ede
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RRA
+ ;; Flags: H,N=0; C aff.
+ ;; XXX FLAGS
+OPCODE(1f,`
+ roxr.b #1,eaf
+ ') ;nok
+
+ ;; JR NZ,immed.b
+ ;; if ~Z,
+ ;; PC <- PC+immed.b
+ ;; No flags
+OPCODE(20,`
+ HOLD_INTS
+ bsr f_norm_z
+ ;; if the emulated Z flag is set, this will be clear
+ beq emu_op_18 ; branch taken: Z reset -> eq (zero set)
+ add.l #1,epc ; skip over the immediate byte
+ CONTINUE_INTS
+ ')
+
+ ;; LD HL,immed.w
+ ;; No flags
+OPCODE(21,`
+ HOLD_INTS
+ FETCHWI ehl
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; LD immed.w,HL
+ ;; (address) <- HL
+ ;; No flags
+OPCODE(22,`
+ HOLD_INTS
+ FETCHWI d1
+ CONTINUE_INTS
+ PUTW ehl,d1
+ ') ;nok
+
+ ;; INC HL
+ ;; No flags
+OPCODE(23,`
+ addq.w #1,ehl
+ ') ;nok
+
+ ;; INC H
+ ;; Flags: S,Z,H aff.; P=overflow, N=0
+OPCODE(24,`
+ LOHI ehl
+ F_INC_B ehl
+ HILO ehl
+ ') ;nok
+
+ ;; DEC H
+ ;; Flags: S,Z,H aff.; P=overflow, N=1
+OPCODE(25,`
+ LOHI ehl
+ F_DEC_B ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,immed.b
+ ;; No flags
+OPCODE(26,`
+ HOLD_INTS
+ LOHI ehl
+ FETCHBI ehl
+ CONTINUE_INTS
+ HILO ehl
+ ') ;nok
+
+ ;; DAA
+ ;; Decrement, adjust accum
+ ;; http://www.z80.info/z80syntx.htm#DAA
+ ;; Flags: oh lord they're fucked up
+ ;; XXX DO THIS
+OPCODE(27,`
+
+ F_PAR eaf
+ ') ;nok
+
+ ;; JR Z,immed.b
+ ;; If zero
+ ;; PC <- PC+immed.b
+ ;; SPEED can be made faster
+ ;; No flags
+OPCODE(28,`
+ HOLD_INTS
+ bsr f_norm_z
+ bne emu_op_18
+ add.l #1,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; ADD HL,HL
+ ;; No flags
+OPCODE(29,`
+ F_ADD_W ehl,ehl
+ ') ;nok
+
+ ;; LD HL,(immed.w)
+ ;; address is absolute
+OPCODE(2a,`
+ HOLD_INTS
+ FETCHWI d1
+ CONTINUE_INTS
+ FETCHW d1,ehl
+ ') ;nok
+
+ ;; XXX TOO LONG
+
+ ;; DEC HL
+OPCODE(2b,`
+ F_DEC_W ehl
+ ') ;nok
+
+ ;; INC L
+OPCODE(2c,`
+ F_INC_B ehl
+ ') ;nok
+
+ ;; DEC L
+OPCODE(2d,`
+ F_DEC_B ehl
+ ') ;nok
+
+ ;; LD L,immed.b
+OPCODE(2e,`
+ HOLD_INTS
+ FETCHBI ehl
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; CPL
+ ;; A <- NOT A
+ ;; XXX flags
+OPCODE(2f,`
+ not.b eaf
+ ') ;nok
+
+ ;; JR NC,immed.b
+ ;; If carry clear
+ ;; PC <- PC+immed.b
+OPCODE(30,`
+ bsr f_norm_c
+ beq emu_op_18 ; branch taken: carry clear
+ add.l #1,epc
+ ')
+
+ ;; LD SP,immed.w
+OPCODE(31,`
+ HOLD_INTS
+ FETCHWI d1
+ bsr deref
+ movea.l a0,esp
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; LD (immed.w),A
+ ;; store indirect
+OPCODE(32,`
+ HOLD_INTS
+ FETCHWI d1
+ CONTINUE_INTS
+ rol.w #8,d1
+ PUTB eaf,d1
+ ') ;nok
+
+ ;; INC SP
+ ;; No flags
+ ;;
+ ;; FYI: Do not have to deref because this will never cross a
+ ;; page boundary. So sayeth BrandonW.
+OPCODE(33,`
+ HOLD_INTS
+ addq.w #1,esp
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; INC (HL)
+ ;; Increment byte
+ ;; SPEED can be made faster
+OPCODE(34,`
+ FETCHB ehl,d1
+ F_INC_B d1
+ PUTB d1,ehl
+ ') ;nok
+
+ ;; DEC (HL)
+ ;; Decrement byte
+ ;; SPEED can be made faster
+OPCODE(35,`
+ FETCHB ehl,d1
+ F_DEC_B d1
+ PUTB d1,ehl
+ ') ;nok
+
+ ;; LD (HL),immed.b
+OPCODE(36,`
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ PUTB ehl,d1
+ ') ;nok
+
+ ;; SCF
+ ;; Set Carry Flag
+ ;; XXX flags are more complicated than this :(
+OPCODE(37,`
+ ori.b #%00111011,flag_valid-flag_storage(a3)
+ move.b eaf,d1
+ ori.b #%00000001,d1
+ andi.b #%11101101,d1
+ or.b d1,flag_byte-flag_storage(a3)
+ ') ;nok
+
+ ;; JR C,immed.b
+ ;; If carry set
+ ;; PC <- PC+immed.b
+OPCODE(38,`
+ HOLD_INTS
+ bsr f_norm_c
+ bne emu_op_18
+ add.l #1,epc
+ CONTINUE_INTS
+ ')
+
+ ;; ADD HL,SP
+ ;; HL <- HL+SP
+OPCODE(39,`
+ HOLD_INTS
+ move.l esp,a0
+ bsr underef
+ F_ADD_W ehl,d0 ; ??? Can I avoid underef/deref cycle?
+ bsr deref
+ move.l a0,esp
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; LD A,(immed.w)
+OPCODE(3a,`
+ HOLD_INTS
+ FETCHWI d1
+ CONTINUE_INTS
+ FETCHB d1,eaf
+ ') ;nok
+
+ ;; DEC SP
+ ;; No flags
+OPCODE(3b,`
+ subq.l #1,esp
+ ') ;nok
+
+ ;; INC A
+OPCODE(3c,`
+ F_INC_B eaf
+ ')
+
+ ;; DEC A
+OPCODE(3d,`
+ F_DEC_B eaf
+ ') ;nok
+
+ ;; LD A,immed.b
+OPCODE(3e,`
+ HOLD_INTS
+ FETCHBI eaf
+ CONTINUE_INTS
+ ')
+
+ ;; CCF
+ ;; Clear carry flag
+ ;; XXX fuck flags
+OPCODE(3f,`
+ bsr flags_normalize
+ ;; SZ5H3PNC
+ ori.b #%00000001,flag_valid-flag_storage(a3)
+ andi.b #%11111110,flag_byte-flag_storage(a3)
+ ') ;nok
+
+ ;; LD B,B
+ ;; SPEED
+OPCODE(40,`
+ LOHI ebc
+ move.b ebc,ebc
+ HILO ebc
+ ') ;nok
+
+ ;; LD B,C
+OPCODE(41,`
+ move.w ebc,d1
+ LOHI d1
+ move.b d1,ebc
+ ') ;nok
+
+ ;; LD B,D
+ ;; B <- D
+ ;; SPEED
+OPCODE(42,`
+ LOHI ebc
+ LOHI ede
+ move.b ede,ebc
+ HILO ebc
+ HILO ede
+ ') ;nok
+
+ ;; LD B,E
+ ;; B <- E
+OPCODE(43,`
+ LOHI ebc
+ move.b ebc,ede ; 4
+ HILO ebc
+ ') ;nok
+
+ ;; LD B,H
+ ;; B <- H
+ ;; SPEED
+OPCODE(44,`
+ LOHI ebc
+ LOHI ehl
+ move.b ehl,ebc
+ HILO ebc
+ HILO ehl
+ ') ;nok
+
+ ;; LD B,L
+ ;; B <- L
+OPCODE(45,`
+ LOHI ebc
+ move.b ehl,ebc
+ HILO ebc
+ ') ;nok
+
+ ;; LD B,(HL)
+ ;; B <- (HL)
+OPCODE(46,`
+ LOHI ebc
+ FETCHB ehl,ebc
+ HILO ebc
+ ') ;nok
+
+ ;; LD B,A
+ ;; B <- A
+OPCODE(47,`
+ LOHI ebc
+ move.b eaf,ebc
+ HILO ebc
+ ') ;nok
+
+ ;; LD C,B
+ ;; C <- B
+OPCODE(48,`
+ move.w ebc,-(sp)
+ move.b (sp),ebc
+ ;; XXX emfasten?
+ addq.l #2,sp
+ ') ;nok
+ ;14 cycles
+ ;; LD C,C
+OPCODE(49,`
+ move.b ebc,ebc
+ ') ;nok
+
+ ;; LD C,D
+OPCODE(4a,`
+ move.w ede,-(sp)
+ move.b (sp),ebc
+ ;; XXX emfasten?
+ addq.l #2,sp
+ ') ;nok
+
+ ;; LD C,E
+OPCODE(4b,`
+ move.b ebc,ede
+ ') ;nok
+
+ ;; LD C,H
+OPCODE(4c,`
+ LOHI ehl
+ move.b ebc,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD C,L
+OPCODE(4d,`
+ move.b ebc,ehl
+ ') ;nok
+
+ ;; LD C,(HL)
+ ;; C <- (HL)
+OPCODE(4e,`
+ FETCHB ehl,ebc
+ ') ;nok
+
+ ;; LD C,A
+OPCODE(4f,`
+ move.b eaf,ebc
+ ') ;nok
+
+; faster (slightly bigger) if we abuse sp again, something along the lines of (UNTESTED)
+; move.w ebc,-(sp) ; 8, 2
+; move.w ede,-(sp) ; 8, 2
+; move.b 2(sp),(sp) ; 16, 4
+; move.w (sp)+,ede ; 8, 2
+; addq.l #2,sp ; 8, 2
+ ;; LD D,B
+OPCODE(50,`
+ LOHI ebc
+ LOHI ede
+ move.b ebc,ede
+ HILO ebc
+ HILO ede
+ ') ;nok
+
+ ;; LD D,C
+OPCODE(51,`
+ LOHI ede
+ move.b ebc,ede
+ HILO ede
+ ') ;nok
+
+ ;; LD D,D
+OPCODE(52,`
+ ') ;nok
+
+ ;; LD D,E
+OPCODE(53,`
+ andi.w #$00ff,ede
+ move.b ede,d1
+ lsl #8,d1
+ or.w d1,ede
+ ') ;nok
+
+ ;; LD D,H
+OPCODE(54,`
+ LOHI ede ; 4
+ LOHI ehl ; 4
+ move.b ehl,ede ; 4
+ HILO ede ; 4
+ HILO ehl ; 4
+ ') ;nok
+ ;20 cycles
+
+ ;; LD D,L
+OPCODE(55,`
+ LOHI ede
+ move.b ehl,ede
+ HILO ede
+ ') ;nok
+
+ ;; LD D,(HL)
+ ;; D <- (HL)
+OPCODE(56,`
+ LOHI ede
+ FETCHB ehl,ede
+ HILO ede
+ ') ;nok
+
+ ;; LD D,A
+OPCODE(57,`
+ LOHI ede
+ move.b eaf,ede
+ HILO ede
+ ') ;nok
+
+ ;; LD E,B
+OPCODE(58,`
+ LOHI ebc
+ move.b ebc,ede
+ HILO ebc
+ ') ;nok
+
+ ;; LD E,C
+OPCODE(59,`
+ move.b ebc,ede
+ ') ;nok
+
+ ;; LD E,D
+OPCODE(5a,`
+ andi.w #$ff00,ede ; 8/4
+ move.b ede,d1 ; 4/2
+ lsr.w #8,d1 ;22/2
+ or.w d1,ede ; 4/2
+ ') ;nok
+ ;38/2
+
+ ;; LD E,E
+OPCODE(5b,`
+ move.b ede,ede
+ ') ;nok
+
+ ;; LD E,H
+OPCODE(5c,`
+ LOHI ehl
+ move.b ede,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD E,L
+OPCODE(5d,`
+ move.b ede,ehl
+ ') ;nok
+
+ ;; LD E,(HL)
+OPCODE(5e,`
+ FETCHB ehl,d1
+ ') ;nok
+
+ ;; LD E,A
+OPCODE(5f,`
+ move.b ede,eaf
+ ') ;nok
+
+ ;; LD H,B
+OPCODE(60,`
+ LOHI ebc
+ LOHI ehl
+ move.b ehl,ebc
+ HILO ebc
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,C
+OPCODE(61,`
+ LOHI ehl
+ move.b ebc,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,D
+OPCODE(62,`
+ LOHI ede
+ LOHI ehl
+ move.b ede,ehl
+ HILO ede
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,E
+OPCODE(63,`
+ LOHI ehl
+ move.b ede,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,H
+OPCODE(64,`
+ LOHI ehl
+ move.b ehl,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,L
+ ;; H <- L
+OPCODE(65,`
+ move.b ehl,d1
+ LOHI ehl
+ move.b d1,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,(HL)
+OPCODE(66,`
+ FETCHB ehl,d1
+ LOHI ehl
+ move.b d1,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD H,A
+OPCODE(67,`
+ LOHI ehl
+ move.b eaf,ehl
+ HILO ehl
+ ') ;nok
+
+ ;; LD L,B
+OPCODE(68,`
+ LOHI ebc
+ move.b ebc,ehl
+ HILO ebc
+ ') ;nok
+
+ ;; LD L,C
+OPCODE(69,`
+ move.b ebc,ehl
+ ') ;nok
+
+ ;; LD L,D
+OPCODE(6a,`
+ LOHI ede
+ move.b ede,ehl
+ HILO ede
+ ') ;nok
+
+ ;; LD L,E
+OPCODE(6b,`
+ move.b ede,ehl
+ ') ;nok
+
+ ;; LD L,H
+OPCODE(6c,`
+ move.b ehl,d1
+ LOHI d1
+ move.b d1,ehl
+ ') ;nok
+
+ ;; LD L,L
+OPCODE(6d,`
+ move.b ehl,ehl
+ ') ;nok
+
+ ;; LD L,(HL)
+ ;; L <- (HL)
+OPCODE(6e,`
+ FETCHB ehl,ehl
+ ') ;nok
+
+ ;; LD L,A
+OPCODE(6f,`
+ move.b eaf,ehl
+ ') ;nok
+
+ ;; LD (HL),B
+OPCODE(70,`
+ LOHI ebc
+ PUTB ehl,ebc
+ HILO ebc
+ ') ;nok
+
+ ;; LD (HL),C
+OPCODE(71,`
+ PUTB ehl,ebc
+ ') ;nok
+
+ ;; LD (HL),D
+OPCODE(72,`
+ LOHI ede
+ PUTB ehl,ede
+ HILO ede
+ ') ;nok
+
+ ;; LD (HL),E
+OPCODE(73,`
+ PUTB ehl,ede
+ ') ;nok
+
+ ;; LD (HL),H
+OPCODE(74,`
+ move.w ehl,d1
+ HILO d1
+ PUTB d1,ehl
+ ') ;nok
+
+ ;; LD (HL),L
+OPCODE(75,`
+ move.b ehl,d1
+ PUTB d1,ehl
+ ') ;nok
+
+ ;; HALT
+ ;; XXX do this
+OPCODE(76,`
+ bra emu_op_76
+ ') ;nok
+
+ ;; LD (HL),A
+OPCODE(77,`
+ PUTB eaf,ehl
+ ') ;nok
+
+ ;; LD A,B
+OPCODE(78,`
+ move.w ebc,d1
+ LOHI d1
+ move.b d1,eaf
+ ') ;nok
+
+ ;; LD A,C
+OPCODE(79,`
+ move.b ebc,eaf
+ ') ;nok
+
+ ;; LD A,D
+OPCODE(7a,`
+ move.w ede,d1
+ LOHI d1
+ move.b d1,eaf
+ ') ;nok
+
+ ;; LD A,E
+OPCODE(7b,`
+ move.b ede,eaf
+ ') ;nok
+
+ ;; LD A,H
+OPCODE(7c,`
+ move.w ehl,d1
+ LOHI d1
+ move.b d1,eaf
+ ') ;nok
+
+ ;; LD A,L
+OPCODE(7d,`
+ move.b ehl,eaf
+ ') ;nok
+
+ ;; LD A,(HL)
+ ;; A <- (HL)
+OPCODE(7e,`
+ FETCHB ehl,eaf
+ ') ;nok
+
+ ;; LD A,A
+OPCODE(7f,`
+ ') ;nok
+
+
+
+ ;; Do an ADD \2,\1
+F_ADD_B MACRO ; 14 bytes?
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_add
+ move.b d1,\2
+ ENDM
+
+ ;; ADD A,B
+OPCODE(80,`
+ LOHI ebc
+ F_ADD_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; ADD A,C
+OPCODE(81,`
+ F_ADD_B ebc,eaf
+ ') ;nok
+
+ ;; ADD A,D
+OPCODE(82,`
+ LOHI ede
+ F_ADD_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; ADD A,E
+OPCODE(83,`
+ F_ADD_B ede,eaf
+ ') ;nok
+
+ ;; ADD A,H
+OPCODE(84,`
+ LOHI ehl
+ F_ADD_B ehl,eaf
+ HILO ehl
+ ') ;nok
+
+ ;; ADD A,L
+OPCODE(85,`
+ F_ADD_B ehl,eaf
+ ') ;nok
+
+ ;; ADD A,(HL)
+ ;; XXX size?
+OPCODE(86,`
+ FETCHB ehl,d2
+ F_ADD_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+ ;; ADD A,A
+OPCODE(87,`
+ F_ADD_B eaf,eaf
+ ') ;nok
+
+
+
+ ;; Do an ADC \2,\1
+F_ADC_B MACRO ; S34
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_adc
+ move.b d1,\2
+ ENDM
+
+ ;; ADC A,B
+ ;; A <- A + B + (carry)
+OPCODE(88,`
+ LOHI ebc
+ F_ADC_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; ADC A,C
+ ;; A <- A + C + (carry)
+OPCODE(89,`
+ F_ADC_B ebc,eaf
+ ') ;nok
+
+ ;; ADC A,D
+OPCODE(8a,`
+ LOHI ede
+ F_ADC_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; ADC A,E
+ ;; A <- A + E + carry
+OPCODE(8b,`
+ F_ADC_B ede,eaf
+ ') ;nok
+
+ ;; ADC A,H
+OPCODE(8c,`
+ LOHI eaf
+ F_ADC_B ehl,eaf
+ HILO eaf
+ ') ;nok
+
+ ;; ADC A,L
+OPCODE(8d,`
+ F_ADC_B ehl,eaf
+ ') ;nok
+
+ ;; ADC A,(HL)
+OPCODE(8e,`
+ FETCHB ehl,d2
+ F_ADC_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+ ;; ADC A,A
+OPCODE(8f,`
+ F_ADC_B eaf,eaf
+ ') ;nok
+
+
+
+
+
+ ;; Do a SUB \2,\1
+F_SUB_B MACRO
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_sub
+ move.b d1,\2
+ ENDM
+
+ ;; SUB A,B
+OPCODE(90,`
+ LOHI ebc
+ F_SUB_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; SUB A,C
+OPCODE(91,`
+ F_SUB_B ebc,eaf
+ ') ;nok
+
+ ;; SUB A,D
+OPCODE(92,`
+ LOHI ede
+ F_SUB_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; SUB A,E
+OPCODE(93,`
+ F_SUB_B ede,eaf
+ ') ;nok
+
+ ;; SUB A,H
+OPCODE(94,`
+ LOHI ehl
+ F_SUB_B ehl,eaf
+ HILO ehl
+ ') ;nok
+
+ ;; SUB A,L
+OPCODE(95,`
+ F_SUB_B ehl,eaf
+ ')
+
+ ;; SUB A,(HL)
+OPCODE(96,`
+ FETCHB ehl,d2
+ F_SUB_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+ ;; SUB A,A
+OPCODE(97,`
+ F_SUB_B eaf,eaf
+ ') ;nok
+
+
+
+
+ ;; Do a SBC \2,\1
+F_SBC_B MACRO
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_sbc
+ move.b d1,\2
+ ENDM
+
+ ;; SBC A,B
+OPCODE(98,`
+ LOHI ebc
+ F_SBC_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; SBC A,C
+OPCODE(99,`
+ F_SBC_B ebc,eaf
+ ') ;nok
+
+ ;; SBC A,D
+OPCODE(9a,`
+ LOHI ede
+ F_SBC_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; SBC A,E
+OPCODE(9b,`
+ F_SBC_B ede,eaf
+ ') ;nok
+
+ ;; SBC A,H
+OPCODE(9c,`
+ LOHI ehl
+ F_SBC_B ehl,eaf
+ HILO ehl
+ ') ;nok
+
+ ;; SBC A,L
+OPCODE(9d,`
+ F_SBC_B ehl,eaf
+ ') ;nok
+
+ ;; SBC A,(HL)
+OPCODE(9e,`
+ FETCHB ehl,d2
+ F_SBC_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+ ;; SBC A,A
+OPCODE(9f,`
+ F_SBC_B eaf,eaf
+ ') ;nok
+
+
+
+
+
+F_AND_B MACRO
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_and
+ move.b d1,\2
+ ENDM
+
+ ;; AND B
+OPCODE(a0,`
+ LOHI ebc
+ F_AND_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; AND C
+OPCODE(a1,`
+ F_AND_B ebc,eaf
+ ')
+
+ ;; AND D
+OPCODE(a2,`
+ LOHI ede
+ F_AND_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; AND E
+OPCODE(a3,`
+ F_AND_B ede,eaf
+ ') ;nok
+
+ ;; AND H
+OPCODE(a4,`
+ LOHI ehl
+ F_AND_B ehl,eaf
+ HILO ehl
+ ') ;nok
+
+ ;; AND L
+OPCODE(a5,`
+ F_AND_B ehl,eaf
+ ') ;nok
+
+ ;; AND (HL)
+OPCODE(a6,`
+ FETCHB ehl,d2
+ F_AND_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+ ;; AND A
+ ;; SPEED ... It's probably not necessary to run this faster.
+OPCODE(a7,`
+ F_AND_B eaf,eaf
+ ') ;nok
+
+
+
+
+
+F_XOR_B MACRO
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_xor
+ move.b d1,\2
+ ENDM
+
+ ;; XOR B
+OPCODE(a8,`
+ LOHI ebc
+ F_XOR_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; XOR C
+OPCODE(a9,`
+ F_XOR_B ebc,eaf
+ ') ;nok
+
+ ;; XOR D
+OPCODE(aa,`
+ LOHI ede
+ F_XOR_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; XOR E
+OPCODE(ab,`
+ F_XOR_B ede,eaf
+ ') ;nok
+
+ ;; XOR H
+OPCODE(ac,`
+ LOHI ehl
+ F_XOR_B ehl,eaf
+ HILO ehl
+ ') ;nok
+
+ ;; XOR L
+OPCODE(ad,`
+ F_XOR_B ehl,eaf
+ ') ;nok
+
+ ;; XOR (HL)
+OPCODE(ae,`
+ FETCHB ehl,d2
+ F_XOR_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+ ;; XOR A
+OPCODE(af,`
+ F_XOR_B eaf,eaf
+ ;; XXX
+ ') ;nok
+
+
+
+
+
+F_OR_B MACRO
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_or
+ move.b d1,\2
+ ENDM
+
+ ;; OR B
+OPCODE(b0,`
+ LOHI ebc
+ F_OR_B ebc,eaf
+ HILO ebc
+ ') ;nok
+
+ ;; OR C
+OPCODE(b1,`
+ F_OR_B ebc,eaf
+ ') ;nok
+
+ ;; OR D
+OPCODE(b2,`
+ LOHI ede
+ F_OR_B ede,eaf
+ HILO ede
+ ') ;nok
+
+ ;; OR E
+OPCODE(b3,`
+ F_OR_B ede,eaf
+ ') ;nok
+
+ ;; OR H
+OPCODE(b4,`
+ LOHI ehl
+ F_OR_B ehl,eaf
+ HILO ehl
+ ') ;nok
+
+ ;; OR L
+OPCODE(b5,`
+ F_OR_B ehl,eaf
+ ') ;nok
+
+ ;; OR (HL)
+OPCODE(b6,`
+ FETCHB ehl,d2
+ F_OR_B d2,eaf
+ PUTB d2,ehl
+ ') ;nok
+
+OPCODE(b7,`
+ ;; OR A
+ F_OR_B eaf,eaf
+ ') ;nok
+
+
+
+
+
+ ;; COMPARE instruction
+F_CP_B MACRO
+ ;; XXX deal with \2 or \1 being d1 or d0
+ move.b \2,d1
+ move.b \1,d0
+ bsr alu_cp
+ ;; no result to save
+ ENDM
+
+ ;; CP B
+OPCODE(b8,`
+ move.w ebc,d2
+ LOHI d2
+ F_CP_B d2,eaf
+ ') ;nok
+
+ ;; CP C
+OPCODE(b9,`
+ F_CP_B ebc,eaf
+ ') ;nok
+
+ ;; CP D
+OPCODE(ba,`
+ move.w ede,d2
+ LOHI d2
+ F_CP_B d2,eaf
+ ') ;nok
+
+ ;; CP E
+OPCODE(bb,`
+ F_CP_B ede,eaf
+ ') ;nok
+
+ ;; CP H
+OPCODE(bc,`
+ move.w ehl,d2
+ LOHI d2
+ F_CP_B d2,eaf
+ ') ;nok
+
+ ;; CP L
+OPCODE(bd,`
+ F_CP_B ehl,eaf
+ ') ;nok
+
+ ;; CP (HL)
+OPCODE(be,`
+ FETCHB ehl,d2
+ F_CP_B d2,eaf
+ ;; no result to store
+ ') ;nok
+
+ ;; CP A
+OPCODE(bf,`
+ F_CP_B eaf,eaf
+ ')
+
+ ;; RET NZ
+ ;; if ~Z
+ ;; PCl <- (SP)
+ ;; PCh <- (SP+1)
+ ;; SP <- (SP+2)
+OPCODE(c0,`
+ HOLD_INTS
+ bsr f_norm_z
+ ;; SPEED inline RET
+ beq emu_op_c9 ; RET
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; POP BC
+ ;; Pops a word into BC
+OPCODE(c1,` ; S10 T
+ HOLD_INTS
+ POPW ebc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; JP NZ,immed.w
+ ;; if ~Z
+ ;; PC <- immed.w
+OPCODE(c2,`
+ HOLD_INTS
+ bsr f_norm_z
+ bne.s emu_op_c3
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ; S12 T36
+ ;; JP immed.w
+ ;; PC <- immed.w
+OPCODE(c3,`
+ HOLD_INTS
+ FETCHWI d1
+ bsr deref
+ movea.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; CALL NZ,immed.w
+ ;; If ~Z, CALL immed.w
+OPCODE(c4,`
+ HOLD_INTS
+ bsr f_norm_z
+ ;; CALL (emu_op_cd) will run HOLD_INTS again. This doesn't
+ ;; matter with the current implementation because HOLD_INTS
+ ;; simply sets a bit.
+ bne emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; PUSH BC
+OPCODE(c5,`
+ HOLD_INTS
+ PUSHW ebc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; ADD A,immed.b
+OPCODE(c6,`
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ F_ADD_B d1,eaf
+ ') ;nok
+
+ ;; RST &0
+ ;; == CALL 0
+ ;; XXX check
+OPCODE(c7,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$00,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET Z
+OPCODE(c8,`
+ HOLD_INTS
+ bsr f_norm_z
+ beq.s emu_op_c9
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET
+ ;; PCl <- (SP)
+ ;; PCh <- (SP+1) POPW
+ ;; SP <- (SP+2)
+OPCODE(c9,`
+ HOLD_INTS
+ POPW d1
+ bsr deref
+ movea.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; JP Z,immed.w
+ ;; If Z, jump
+OPCODE(ca,`
+ HOLD_INTS
+ bsr f_norm_z
+ beq emu_op_c3
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+OPCODE(cb,` ; prefix
+ movea.w emu_op_undo_cb(pc),a2
+ ')
+ ;; nok
+
+ ;; CALL Z,immed.w
+OPCODE(cc,`
+ HOLD_INTS
+ bsr f_norm_z
+ beq.s emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; CALL immed.w
+ ;; (Like JSR on 68k)
+ ;; (SP-1) <- PCh
+ ;; (SP-2) <- PCl
+ ;; SP <- SP - 2
+ ;; PC <- address
+OPCODE(cd,`
+ HOLD_INTS ; released in JP routine
+ move.l epc,a0
+ bsr underef ; d0 has PC
+ add.w #2,d0
+ PUSHW d0
+ bra emu_op_c3 ; JP
+ ')
+
+ ;; ADC A,immed.b
+OPCODE(ce,`
+ HOLD_INTS
+ FETCHWI d1
+ CONTINUE_INTS
+ F_ADC_B d1,eaf
+ ') ;nok
+
+ ;; RST &08
+ ;; == CALL 8
+OPCODE(cf,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef ; d0 has PC
+ PUSHW d0
+ move.w #$08,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET NC
+OPCODE(d0,`
+ HOLD_INTS
+ bsr f_norm_c
+ beq emu_op_c9
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; POP DE
+OPCODE(d1,`
+ HOLD_INTS
+ POPW ede
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; JP NC,immed.w
+OPCODE(d2,`
+ HOLD_INTS
+ bsr f_norm_c
+ beq emu_op_c3
+ add.l #2,epc
+ CONTINUE_INTS
+ ')
+
+ ;; OUT immed.b,A
+OPCODE(d3,`
+ HOLD_INTS
+ move.b eaf,d1
+ FETCHBI d0
+ bsr port_out
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; CALL NC,immed.w
+OPCODE(d4,`
+ HOLD_INTS
+ bsr f_norm_c
+ beq emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; PUSH DE
+OPCODE(d5,`
+ HOLD_INTS
+ PUSHW ede
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; SUB A,immed.b
+OPCODE(d6,`
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ F_SUB_B eaf,d1
+ ') ;nok
+
+ ;; RST &10
+ ;; == CALL 10
+OPCODE(d7,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$10,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET C
+OPCODE(d8,`
+ HOLD_INTS
+ bsr f_norm_c
+ bne emu_op_c9
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; EXX
+OPCODE(d9,`
+ swap ebc
+ swap ede
+ swap ehl
+ ') ;nok
+
+ ;; JP C,immed.w
+OPCODE(da,`
+ HOLD_INTS
+ bsr f_norm_c
+ bne emu_op_c3
+ CONTINUE_INTS
+ ') ;nok
+
+OPCODE(db,`
+ ;; IN A,immed.b
+ HOLD_INTS
+ move.b eaf,d1
+ FETCHBI d0
+ CONTINUE_INTS
+ bsr port_in
+ ') ;nok
+
+ ;; CALL C,immed.w
+OPCODE(dc,`
+ HOLD_INTS
+ bsr f_norm_c
+ bne emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+OPCODE(dd,` ; prefix
+ movea.w emu_op_undo_dd(pc),a2
+ ')
+
+ ;; SBC A,immed.b
+OPCODE(de,`
+ HOLD_INTS
+ FETCHWI d1
+ CONTINUE_INTS
+ F_SBC_B d1,eaf
+ ') ;nok
+
+ ;; RST &18
+ ;; == CALL 18
+OPCODE(df,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$18,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET PO
+ ;; If parity odd (P zero), return
+OPCODE(e0,`
+ HOLD_INTS
+ bsr f_norm_pv
+ beq emu_op_c9
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; POP HL
+OPCODE(e1,`
+ POPW ehl
+ ') ;nok
+
+ ;; JP PO,immed.w
+OPCODE(e2,`
+ HOLD_INTS
+ bsr f_norm_pv
+ beq emu_op_c3
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; EX (SP),HL
+ ;; Exchange
+OPCODE(e3,`
+ HOLD_INTS
+ POPW d1
+ PUSHW ehl
+ CONTINUE_INTS
+ move.w d1,ehl
+ ') ;nok
+
+ ;; CALL PO,immed.w
+ ;; if parity odd (P=0), call
+OPCODE(e4,`
+ HOLD_INTS
+ bsr f_norm_pv
+ beq emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; PUSH HL
+OPCODE(e5,`
+ HOLD_INTS
+ PUSHW ehl
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; AND immed.b
+OPCODE(e6,`
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ F_AND_B d1,eaf
+ ') ;nok
+
+ ;; RST &20
+ ;; == CALL 20
+OPCODE(e7,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$20,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET PE
+ ;; If parity odd (P zero), return
+OPCODE(e8,`
+ HOLD_INTS
+ bsr f_norm_pv
+ bne emu_op_c9
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; JP (HL)
+OPCODE(e9,`
+ HOLD_INTS
+ FETCHB ehl,d1
+ bsr deref
+ movea.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; JP PE,immed.w
+OPCODE(ea,`
+ HOLD_INTS
+ bsr f_norm_pv
+ bne emu_op_c3
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; EX DE,HL
+OPCODE(eb,`
+ exg.w ede,ehl
+ ') ;nok
+
+ ;; CALL PE,immed.w
+ ;; If parity even (P=1), call
+OPCODE(ec,`
+ HOLD_INTS
+ bsr f_norm_c
+ bne emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; XXX this probably ought to hold interrupts too
+OPCODE(ed,` ; prefix
+ movea.w emu_op_undo_ed(pc),a2
+ ') ;nok
+
+ ;; XOR immed.b
+OPCODE(ee,`
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ F_XOR_B d1,eaf
+ ') ;nok
+
+ ;; RST &28
+ ;; == CALL 28
+OPCODE(ef,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$28,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET P
+ ;; Return if Positive
+OPCODE(f0,`
+ HOLD_INTS
+ bsr f_norm_sign
+ beq emu_op_c9 ; RET
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; POP AF
+ ;; SPEED this can be made faster ...
+ ;; XXX AF
+OPCODE(f1,`
+ POPW eaf
+ move.w eaf,(flag_byte-flag_storage)(a3)
+ move.b #$ff,(flag_valid-flag_storage)(a3)
+ ') ;nok
+
+ ;; JP P,immed.w
+OPCODE(f2,`
+ HOLD_INTS
+ bsr f_norm_sign
+ beq emu_op_c3 ; JP
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+OPCODE(f3,`
+ ;; DI
+ bsr ints_stop
+ ')
+
+ ;; CALL P,&0000
+ ;; Call if positive (S=0)
+OPCODE(f4,`
+ HOLD_INTS
+ bsr f_norm_sign
+ beq emu_op_cd
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; PUSH AF
+OPCODE(f5,`
+ HOLD_INTS
+ bsr flags_normalize
+ LOHI eaf
+ move.b flag_byte(pc),eaf
+ ;; XXX wrong, af is not normalized by flags_normalize?
+ CONTINUE_INTS
+ HILO eaf
+ PUSHW eaf
+ ') ;nok
+
+OPCODE(f6,`
+ ;; OR immed.b
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ F_OR_B d1,eaf
+ ') ;nok
+
+ ;; RST &30
+ ;; == CALL 30
+OPCODE(f7,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$08,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; RET M
+ ;; Return if Sign == 1, minus
+OPCODE(f8,`
+ HOLD_INTS
+ bsr f_norm_sign
+ bne emu_op_c9 ; RET
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; LD SP,HL
+ ;; SP <- HL
+OPCODE(f9,`
+ HOLD_INTS
+ move.w ehl,d1
+ bsr deref
+ movea.l a0,esp
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; JP M,immed.w
+OPCODE(fa,`
+ HOLD_INTS
+ bsr f_norm_sign
+ bne emu_op_c3 ; JP
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; EI
+OPCODE(fb,`
+ bsr ints_start
+ ') ;nok
+
+ ;; CALL M,immed.w
+ ;; Call if minus (S=1)
+OPCODE(fc,`
+ HOLD_INTS
+ bsr f_norm_sign
+ bne emu_op_cd
+ add.l #2,epc
+ CONTINUE_INTS
+ ') ;nok
+
+ ;; swap IY, HL
+OPCODE(fd,` ; prefix
+ movea.w emu_op_undo_fd(pc),a2
+ ')
+
+ ;; CP immed.b
+OPCODE(fe,`
+ HOLD_INTS
+ FETCHBI d1
+ CONTINUE_INTS
+ F_CP_B d1,eaf
+ ') ;nok
+
+ ;; RST &38
+ ;; == CALL 38
+OPCODE(ff,`
+ HOLD_INTS
+ move.l epc,a0
+ bsr underef
+ PUSHW d0
+ move.w #$08,d0
+ bsr deref
+ move.l a0,epc
+ CONTINUE_INTS
+ ') ;nok