summaryrefslogtreecommitdiff
path: root/source/z80_decode.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2006-09-13 23:49:18 +0000
committerIan C <ianc@noddybox.co.uk>2006-09-13 23:49:18 +0000
commite007fe3daeff4bcd64bd41894d5606fe43948672 (patch)
tree489ae3bf888f235321423b41269bfae463b18c18 /source/z80_decode.c
parentf7c8435b666daac5a30c88e462727a6c3dbf584d (diff)
Initail version with Spectrum booting
Diffstat (limited to 'source/z80_decode.c')
-rw-r--r--source/z80_decode.c2522
1 files changed, 2522 insertions, 0 deletions
diff --git a/source/z80_decode.c b/source/z80_decode.c
new file mode 100644
index 0000000..ced7fbd
--- /dev/null
+++ b/source/z80_decode.c
@@ -0,0 +1,2522 @@
+/*
+
+ z80 - Z80 Emulator
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ $Id$
+
+*/
+#include <stdlib.h>
+#include <limits.h>
+
+#include "z80.h"
+#include "z80_private.h"
+
+static const char ident[]="$Id$";
+
+/* ---------------------------------------- TABLES AND INIT
+*/
+static Z80Byte PSZtable[512];
+static Z80Byte SZtable[512];
+static Z80Byte Ptable[512];
+static Z80Byte Stable[512];
+static Z80Byte Ztable[512];
+
+
+static int HI;
+static int LO;
+
+/* ---------------------------------------- MISC FUNCTIONS
+*/
+void Z80_InitialiseInternals(void)
+{
+ Z80Word f;
+ Z80Reg r;
+
+ /* Check endianness
+ */
+ r.w=0x1234;
+
+ if (r.b[0] == 0x12)
+ {
+ HI=0;
+ LO=1;
+ }
+ else if (r.b[1] == 0x12)
+ {
+ HI=1;
+ LO=0;
+ }
+ else
+ {
+ exit(1);
+ }
+
+ /* Check variable sizes
+ */
+ if (CHAR_BIT!=8 || sizeof(Z80Word)!=2)
+ {
+ exit(2);
+ }
+
+ /* Initialise flag tables
+ */
+ for(f=0;f<256;f++)
+ {
+ Z80Byte p,z,s;
+ int b;
+
+ p=0;
+
+ for(b=0;b<8;b++)
+ if (f&(1<<b))
+ p++;
+
+ if (p&1)
+ p=0;
+ else
+ p=P_Z80;
+
+ if (f)
+ z=0;
+ else
+ z=Z_Z80;
+
+ if (f&0x80)
+ s=S_Z80;
+ else
+ s=0;
+
+ Ptable[f]=p;
+ Stable[f]=s;
+ Ztable[f]=z;
+ SZtable[f]=z|s;
+ PSZtable[f]=z|s|p;
+
+ Ptable[f+256]=Ptable[f]|C_Z80;
+ Stable[f+256]=Stable[f]|C_Z80;
+ Ztable[f+256]=Ztable[f]|C_Z80;
+ SZtable[f+256]=SZtable[f]|C_Z80;
+ PSZtable[f+256]=PSZtable[f]|C_Z80;
+ }
+}
+
+static Z80Word FPEEKW(Z80 *cpu, Z80Word addr)
+{
+ return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8);
+}
+
+
+static void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val)
+{
+ cpu->mwrite(cpu,addr,val);
+ cpu->mwrite(cpu,addr+1,val>>8);
+}
+
+
+/* ---------------------------------------- GENERAL MACROS
+*/
+#define SWAP(A,B) \
+do { \
+ unsigned swap_tmp; \
+ swap_tmp=A; \
+ A=B; \
+ B=swap_tmp; \
+} while(0)
+
+
+/* ---------------------------------------- ARITHMETIC OPS
+*/
+#define ADD8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=cpu->AF.b[HI]+(unsigned)VAL; \
+ cpu->AF.b[LO]=SZtable[w]; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define ADC8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]+(unsigned)VAL+CARRY)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define SUB8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]|N_Z80; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define CMP8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]|N_Z80; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(VAL); \
+} while(0)
+
+
+#define SBC8(ONCE) \
+do { \
+ Z80Byte VAL=ONCE; \
+ unsigned w; \
+ w=(cpu->AF.b[HI]-(unsigned)VAL-CARRY)&0x1ff; \
+ cpu->AF.b[LO]=SZtable[w]|N_Z80; \
+ if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \
+ if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \
+ SETHIDDEN(w); \
+ cpu->AF.b[HI]=w; \
+} while(0)
+
+
+#define ADD16(REG,ONCE) \
+do { \
+ Z80Word VAL=ONCE; \
+ Z80Val w; \
+ w=(REG)+(Z80Val)VAL; \
+ cpu->AF.b[LO]&=(S_Z80|Z_Z80|V_Z80); \
+ if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \
+ if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \
+ SETHIDDEN(w>>8); \
+ (REG)=w; \
+} while(0)
+
+
+#define ADC16(REG, ONCE) \
+do { \
+ Z80Word VAL=ONCE; \
+ Z80Val w; \
+ w=(REG)+(Z80Val)VAL+CARRY; \
+ cpu->AF.b[LO]=0; \
+ if ((w&0xffff)==0) cpu->AF.b[LO]=Z_Z80; \
+ if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \
+ if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \
+ if ((VAL^(REG)^0x8000)&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \
+ SETHIDDEN(w>>8); \
+ (REG)=w; \
+} while(0)
+
+
+#define SBC16(REG, ONCE) \
+do { \
+ Z80Word VAL=ONCE; \
+ Z80Val w; \
+ w=(REG)-(Z80Val)VAL-CARRY; \
+ cpu->AF.b[LO]=N_Z80; \
+ if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \
+ if ((w&0xffff)==0) cpu->AF.b[LO]|=Z_Z80; \
+ if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \
+ if ((VAL^(REG))&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \
+ SETHIDDEN(w>>8); \
+ (REG)=w; \
+} while(0)
+
+
+#define INC8(REG) \
+do { \
+ (REG)++; \
+ cpu->AF.b[LO]=CARRY|SZtable[(REG)]; \
+ if ((REG)==0x80) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)&0x0f)==0) cpu->AF.b[LO]|=H_Z80; \
+} while(0)
+
+
+#define DEC8(REG) \
+do { \
+ (REG)--; \
+ cpu->AF.b[LO]=N_Z80|CARRY; \
+ if ((REG)==0x7f) cpu->AF.b[LO]|=P_Z80; \
+ if (((REG)&0x0f)==0x0f) cpu->AF.b[LO]|=H_Z80; \
+ cpu->AF.b[LO]|=SZtable[(REG)]; \
+} while(0)
+
+
+#define OP_ON_MEM(OP,addr) \
+do { \
+ Z80Byte memop=cpu->mread(cpu,addr); \
+ OP(memop); \
+ cpu->mwrite(cpu,addr,memop); \
+} while(0)
+
+
+#define OP_ON_MEM_WITH_ARG(OP,addr,arg) \
+do { \
+ Z80Byte memop=cpu->mread(cpu,addr); \
+ OP(memop,arg); \
+ cpu->mwrite(cpu,addr,memop); \
+} while(0)
+
+
+#define OP_ON_MEM_WITH_COPY(OP,addr,copy) \
+do { \
+ Z80Byte memop=cpu->mread(cpu,addr); \
+ OP(memop); \
+ copy=memop; \
+ cpu->mwrite(cpu,addr,memop); \
+} while(0)
+
+
+#define OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,arg,copy) \
+do { \
+ Z80Byte memop=cpu->mread(cpu,addr); \
+ OP(memop,arg); \
+ copy=memop; \
+ cpu->mwrite(cpu,addr,memop); \
+} while(0)
+
+
+/* ---------------------------------------- ROTATE AND SHIFT OPS
+*/
+#define RRCA \
+do { \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(cpu->AF.b[HI]<<7); \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RRA \
+do { \
+ Z80Byte c; \
+ c=CARRY; \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(c<<7); \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RRC(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)=((REG)>>1)|((REG)<<7); \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define RR(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)=((REG)>>1)|(CARRY<<7); \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define RLCA \
+do { \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|(cpu->AF.b[HI]>>7); \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RLA \
+do { \
+ Z80Byte c; \
+ c=CARRY; \
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \
+ cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|c; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define RLC(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=((REG)<<1)|c; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define RL(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=((REG)<<1)|CARRY; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SRL(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)>>=1; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SRA(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)&C_Z80; \
+ (REG)=((REG)>>1)|((REG)&0x80); \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SLL(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=((REG)<<1)|1; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+#define SLA(REG) \
+do { \
+ Z80Byte c; \
+ c=(REG)>>7; \
+ (REG)=(REG)<<1; \
+ cpu->AF.b[LO]=PSZtable[(REG)]|c; \
+ SETHIDDEN(REG); \
+} while(0)
+
+
+/* ---------------------------------------- BOOLEAN OPS
+*/
+#define AND(VAL) \
+do { \
+ cpu->AF.b[HI]&=VAL; \
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]|H_Z80; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define OR(VAL) \
+do { \
+ cpu->AF.b[HI]|=VAL; \
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define XOR(VAL) \
+do { \
+ cpu->AF.b[HI]^=VAL; \
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \
+ SETHIDDEN(cpu->AF.b[HI]); \
+} while(0)
+
+
+#define BIT(REG,B) \
+do { \
+ cpu->AF.b[LO]=CARRY|H_Z80; \
+ if ((REG)&(1<<B)) \
+ { \
+ if (B==7 && (REG&S_Z80)) cpu->AF.b[LO]|=S_Z80; \
+ if (B==5 && (REG&B5_Z80)) cpu->AF.b[LO]|=B5_Z80; \
+ if (B==3 && (REG&B3_Z80)) cpu->AF.b[LO]|=B3_Z80; \
+ } \
+ else \
+ { \
+ cpu->AF.b[LO]|=Z_Z80; \
+ cpu->AF.b[LO]|=P_Z80; \
+ } \
+} while(0)
+
+#define BIT_SET(REG,B) (REG)|=(1<<B)
+#define BIT_RES(REG,B) (REG)&=~(1<<B)
+
+
+/* ---------------------------------------- JUMP OPERATIONS
+*/
+#define JR_COND(COND) \
+do { \
+ if (COND) \
+ { \
+ TSTATE(12); \
+ JR; \
+ } \
+ else \
+ { \
+ TSTATE(7); \
+ NOJR; \
+ } \
+} while(0)
+
+
+#define JP_COND(COND) \
+do { \
+ TSTATE(10); \
+ if (COND) \
+ { \
+ JP; \
+ } \
+ else \
+ { \
+ NOJP; \
+ } \
+} while(0)
+
+
+#define CALL_COND(COND) \
+do { \
+ if (COND) \
+ { \
+ TSTATE(17); \
+ CALL; \
+ } \
+ else \
+ { \
+ TSTATE(10); \
+ NOCALL; \
+ } \
+} while(0)
+
+
+#define RET_COND(COND) \
+do { \
+ if (COND) \
+ { \
+ TSTATE(11); \
+ POP(cpu->PC); \
+ } \
+ else \
+ { \
+ TSTATE(5); \
+ } \
+} while(0)
+
+
+#define RST(ADDR) \
+ TSTATE(11); \
+ PUSH(cpu->PC); \
+ cpu->PC=ADDR
+
+/* ---------------------------------------- BLOCK OPERATIONS
+*/
+#define LDI \
+do { \
+ Z80Byte b; \
+ \
+ b=PEEK(cpu->HL.w); \
+ POKE(cpu->DE.w,b); \
+ cpu->DE.w++; \
+ cpu->HL.w++; \
+ cpu->BC.w--; \
+ \
+ CLRFLAG(H_Z80); \
+ CLRFLAG(N_Z80); \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+ \
+ SETHIDDEN(cpu->AF.b[HI]+b); \
+} while(0)
+
+#define LDD \
+do { \
+ Z80Byte b; \
+ \
+ b=PEEK(cpu->HL.w); \
+ POKE(cpu->DE.w,b); \
+ cpu->DE.w--; \
+ cpu->HL.w--; \
+ cpu->BC.w--; \
+ \
+ CLRFLAG(H_Z80); \
+ CLRFLAG(N_Z80); \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+ \
+ SETHIDDEN(cpu->AF.b[HI]+b); \
+} while(0)
+
+#define CPI \
+do { \
+ Z80Byte c,b; \
+ \
+ c=CARRY; \
+ b=PEEK(cpu->HL.w); \
+ \
+ CMP8(b); \
+ \
+ if (c) \
+ SETFLAG(C_Z80); \
+ else \
+ CLRFLAG(C_Z80); \
+ \
+ cpu->HL.w++; \
+ cpu->BC.w--; \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+} while(0)
+
+#define CPD \
+do { \
+ Z80Byte c,b; \
+ \
+ c=CARRY; \
+ b=PEEK(cpu->HL.w); \
+ \
+ CMP8(b); \
+ \
+ if (c) \
+ SETFLAG(C_Z80); \
+ else \
+ CLRFLAG(C_Z80); \
+ \
+ cpu->HL.w--; \
+ cpu->BC.w--; \
+ \
+ if (cpu->BC.w) \
+ SETFLAG(P_Z80); \
+ else \
+ CLRFLAG(P_Z80); \
+} while(0)
+
+#define INI \
+do { \
+ Z80Word w; \
+ Z80Byte b; \
+ \
+ b=IN(cpu->BC.w); \
+ POKE(cpu->HL.w,b); \
+ \
+ cpu->BC.b[HI]--; \
+ cpu->HL.w++; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETHIDDEN(cpu->BC.b[HI]); \
+ \
+ w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \
+ \
+ if (b&0x80) \
+ SETFLAG(N_Z80); \
+ \
+ if (w&0x100) \
+ { \
+ SETFLAG(C_Z80); \
+ SETFLAG(H_Z80); \
+ } \
+ else \
+ { \
+ CLRFLAG(C_Z80); \
+ CLRFLAG(H_Z80); \
+ } \
+} while(0)
+
+#define IND \
+do { \
+ Z80Word w; \
+ Z80Byte b; \
+ \
+ b=IN(cpu->BC.w); \
+ POKE(cpu->HL.w,b); \
+ \
+ cpu->BC.b[HI]--; \
+ cpu->HL.w--; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETHIDDEN(cpu->BC.b[HI]); \
+ \
+ w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \
+ \
+ if (b&0x80) \
+ SETFLAG(N_Z80); \
+ \
+ if (w&0x100) \
+ { \
+ SETFLAG(C_Z80); \
+ SETFLAG(H_Z80); \
+ } \
+ else \
+ { \
+ CLRFLAG(C_Z80); \
+ CLRFLAG(H_Z80); \
+ } \
+} while(0) \
+
+#define OUTI \
+do { \
+ OUT(cpu->BC.w,PEEK(cpu->HL.w)); \
+ \
+ cpu->HL.w++; \
+ cpu->BC.b[HI]--; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETHIDDEN(cpu->BC.b[HI]); \
+} while(0)
+
+#define OUTD \
+do { \
+ OUT(cpu->BC.w,PEEK(cpu->HL.w)); \
+ \
+ cpu->HL.w--; \
+ cpu->BC.b[HI]--; \
+ \
+ cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \
+ SETFLAG(N_Z80); \
+ SETHIDDEN(cpu->BC.b[HI]); \
+} while(0)
+
+
+/* ---------------------------------------- BASE OPCODE SHORT-HAND BLOCKS
+*/
+
+#define LD_BLOCK(BASE,DEST,DEST2) \
+ case BASE: /* LD DEST,B */ \
+ TSTATE(4); \
+ DEST=cpu->BC.b[HI]; \
+ break; \
+ \
+ case BASE+1: /* LD DEST,C */ \
+ TSTATE(4); \
+ DEST=cpu->BC.b[LO]; \
+ break; \
+ \
+ case BASE+2: /* LD DEST,D */ \
+ TSTATE(4); \
+ DEST=cpu->DE.b[HI]; \
+ break; \
+ \
+ case BASE+3: /* LD DEST,E */ \
+ TSTATE(4); \
+ DEST=cpu->DE.b[LO]; \
+ break; \
+ \
+ case BASE+4: /* LD DEST,H */ \
+ TSTATE(4); \
+ DEST=*H; \
+ break; \
+ \
+ case BASE+5: /* LD DEST,L */ \
+ TSTATE(4); \
+ DEST=*L; \
+ break; \
+ \
+ case BASE+6: /* LD DEST,(HL) */ \
+ TSTATE(7); \
+ OFFSET(off); \
+ DEST2=cpu->mread(cpu,*HL+off); \
+ break; \
+ \
+ case BASE+7: /* LD DEST,A */ \
+ TSTATE(4); \
+ DEST=cpu->AF.b[HI]; \
+ break;
+
+#define ALU_BLOCK(BASE,OP) \
+ case BASE: /* OP A,B */ \
+ TSTATE(4); \
+ OP(cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP A,C */ \
+ TSTATE(4); \
+ OP(cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP A,D */ \
+ TSTATE(4); \
+ OP(cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP A,E */ \
+ TSTATE(4); \
+ OP(cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP A,H */ \
+ TSTATE(4); \
+ OP(*H); \
+ break; \
+ \
+ case BASE+5: /* OP A,L */ \
+ TSTATE(4); \
+ OP(*L); \
+ break; \
+ \
+ case BASE+6: /* OP A,(HL) */ \
+ TSTATE(7); \
+ OFFSET(off); \
+ OP_ON_MEM(OP,*HL+off); \
+ break; \
+ \
+ case BASE+7: /* OP A,A */ \
+ TSTATE(4); \
+ OP(cpu->AF.b[HI]); \
+ break;
+
+
+/* ---------------------------------------- CB OPCODE SHORT-HAND BLOCKS
+*/
+
+#define CB_ALU_BLOCK(BASE,OP) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[HI]); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[LO]); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(15); \
+ OP_ON_MEM(OP,cpu->HL.w); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP(cpu->AF.b[HI]); \
+ break;
+
+#define CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[HI],BIT_NO); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP(cpu->BC.b[LO],BIT_NO); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[HI],BIT_NO); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP(cpu->DE.b[LO],BIT_NO); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[HI],BIT_NO); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP(cpu->HL.b[LO],BIT_NO); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(12); \
+ OP_ON_MEM_WITH_ARG(OP,cpu->HL.w,BIT_NO); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP(cpu->AF.b[HI],BIT_NO); \
+ break;
+
+/* ---------------------------------------- SHIFTED CB OPCODE SHORT-HAND BLOCKS
+*/
+
+#define SHIFTED_CB_ALU_BLOCK(BASE,OP) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[HI]); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[LO]); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(15); \
+ OP_ON_MEM(OP,addr); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_COPY(OP,addr,cpu->AF.b[HI]); \
+ break;
+
+#define SHIFTED_CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \
+ case BASE: /* OP B */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[HI]); \
+ break; \
+ \
+ case BASE+1: /* OP C */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[LO]); \
+ break; \
+ \
+ case BASE+2: /* OP D */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[HI]); \
+ break; \
+ \
+ case BASE+3: /* OP E */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[LO]); \
+ break; \
+ \
+ case BASE+4: /* OP H */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[HI]); \
+ break; \
+ \
+ case BASE+5: /* OP L */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[LO]); \
+ break; \
+ \
+ case BASE+6: /* OP (HL) */ \
+ TSTATE(12); \
+ OP_ON_MEM_WITH_ARG(OP,addr,BIT_NO); \
+ break; \
+ \
+ case BASE+7: /* OP A */ \
+ TSTATE(8); \
+ OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->AF.b[HI]); \
+ break;
+
+/* ---------------------------------------- DAA
+*/
+
+/* This alogrithm is based on info from
+ http://www.worldofspectrum.org/faq/reference/z80reference.htm
+*/
+static void DAA (Z80 *cpu)
+{
+ Z80Byte add=0;
+ Z80Byte carry=0;
+ Z80Byte nf=cpu->AF.b[LO]&N_Z80;
+ Z80Byte acc=cpu->AF.b[HI];
+
+ if (acc>0x99 || IS_C)
+ {
+ add|=0x60;
+ carry=C_Z80;
+ }
+
+ if ((acc&0xf)>0x9 || IS_H)
+ {
+ add|=0x06;
+ }
+
+ if (nf)
+ {
+ cpu->AF.b[HI]-=add;
+ }
+ else
+ {
+ cpu->AF.b[HI]+=add;
+ }
+
+ cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]
+ | carry
+ | nf
+ | ((acc^cpu->AF.b[HI])&H_Z80)
+ | (cpu->AF.b[HI]&(B3_Z80|B5_Z80));
+}
+
+/* ---------------------------------------- HANDLERS FOR ED OPCODES
+*/
+static void DecodeED(Z80 *cpu, Z80Byte opcode)
+{
+ switch(opcode)
+ {
+ case 0x40: /* IN B,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->BC.b[HI]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->BC.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[HI]];
+ SETHIDDEN(cpu->BC.b[HI]);
+ break;
+
+ case 0x41: /* OUT (C),B */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->BC.b[HI]);
+ break;
+
+ case 0x42: /* SBC HL,BC */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->BC.w);
+ break;
+
+ case 0x43: /* LD (nnnn),BC */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->BC.w);
+ break;
+
+ case 0x44: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x45: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x46: /* IM 0 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x47: /* LD I,A */
+ TSTATE(9);
+ cpu->I=cpu->AF.b[HI];
+ break;
+
+ case 0x48: /* IN C,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->BC.b[LO]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->BC.b[LO]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[LO]];
+ SETHIDDEN(cpu->BC.b[LO]);
+ break;
+
+ case 0x49: /* OUT (C),C */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->BC.b[LO]);
+ break;
+
+ case 0x4a: /* ADC HL,BC */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->BC.w);
+ break;
+
+ case 0x4b: /* LD BC,(nnnn) */
+ TSTATE(20);
+ cpu->BC.w=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x4c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x4d: /* RETI */
+ TSTATE(14);
+ CALLBACK(eZ80_RETI,0);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x4e: /* IM 0/1 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x4f: /* LD R,A */
+ TSTATE(9);
+ cpu->R=cpu->AF.b[HI];
+ break;
+
+ case 0x50: /* IN D,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->DE.b[HI]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->DE.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[HI]];
+ SETHIDDEN(cpu->BC.b[HI]);
+ break;
+
+ case 0x51: /* OUT (C),D */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->DE.b[HI]);
+ break;
+
+ case 0x52: /* SBC HL,DE */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->DE.w);
+ break;
+
+ case 0x53: /* LD (nnnn),DE */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->DE.w);
+ break;
+
+ case 0x54: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x55: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x56: /* IM 1 */
+ TSTATE(8);
+ cpu->IM=1;
+ break;
+
+ case 0x57: /* LD A,I */
+ TSTATE(9);
+ cpu->AF.b[HI]=cpu->I;
+ break;
+
+ case 0x58: /* IN E,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->DE.b[LO]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->BC.b[LO]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[LO]];
+ SETHIDDEN(cpu->DE.b[LO]);
+ break;
+
+ case 0x59: /* OUT (C),E */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->DE.b[LO]);
+ break;
+
+ case 0x5a: /* ADC HL,DE */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->DE.w);
+ break;
+
+ case 0x5b: /* LD DE,(nnnn) */
+ TSTATE(20);
+ cpu->DE.w=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x5c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x5d: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x5e: /* IM 2 */
+ TSTATE(8);
+ cpu->IM=2;
+ break;
+
+ case 0x5f: /* LD A,R */
+ TSTATE(9);
+ cpu->AF.b[HI]=cpu->R;
+ break;
+
+ case 0x60: /* IN H,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->HL.b[HI]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->HL.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[HI]];
+ SETHIDDEN(cpu->HL.b[HI]);
+ break;
+
+ case 0x61: /* OUT (C),H */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->HL.b[HI]);
+ break;
+
+ case 0x62: /* SBC HL,HL */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->HL.w);
+ break;
+
+ case 0x63: /* LD (nnnn),HL */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->HL.w);
+ break;
+
+ case 0x64: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x65: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x66: /* IM 0 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x67: /* RRD */
+ {
+ Z80Byte b;
+
+ TSTATE(18);
+
+ b=PEEK(cpu->HL.w);
+
+ POKE(cpu->HL.w,(b>>4)|(cpu->AF.b[HI]<<4));
+ cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b&0x0f);
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]];
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+ }
+
+ case 0x68: /* IN L,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->HL.b[LO]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->HL.b[LO]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[LO]];
+ SETHIDDEN(cpu->HL.b[LO]);
+ break;
+
+ case 0x69: /* OUT (C),L */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->HL.b[LO]);
+ break;
+
+ case 0x6a: /* ADC HL,HL */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->HL.w);
+ break;
+
+ case 0x6b: /* LD HL,(nnnn) */
+ TSTATE(20);
+ cpu->HL.w=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x6c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x6d: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x6e: /* IM 0/1 */
+ TSTATE(8);
+ cpu->IM=0;
+ break;
+
+ case 0x6f: /* RLD */
+ {
+ Z80Byte b;
+
+ TSTATE(18);
+
+ b=PEEK(cpu->HL.w);
+
+ POKE(cpu->HL.w,(b<<4)|(cpu->AF.b[HI]&0x0f));
+ cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b>>4);
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]];
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+ }
+
+ case 0x70: /* IN (C) */
+ {
+ Z80Byte b;
+
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ b=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ b=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[b];
+ SETHIDDEN(b);
+ break;
+ }
+
+ case 0x71: /* OUT (C) */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,0);
+ break;
+
+ case 0x72: /* SBC HL,SP */
+ TSTATE(15);
+ SBC16(cpu->HL.w,cpu->SP);
+ break;
+
+ case 0x73: /* LD (nnnn),SP */
+ TSTATE(20);
+ POKEW(FETCH_WORD,cpu->SP);
+ break;
+
+ case 0x74: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x75: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x76: /* IM 1 */
+ TSTATE(8);
+ cpu->IM=1;
+ break;
+
+ case 0x77: /* NOP */
+ TSTATE(8);
+ CALLBACK(eZ80_EDHook,opcode);
+ break;
+
+ case 0x78: /* IN A,(C) */
+ TSTATE(12);
+
+ if (cpu->pread)
+ {
+ cpu->AF.b[HI]=cpu->pread(cpu,cpu->BC.w);
+ }
+ else
+ {
+ cpu->AF.b[HI]=0;
+ }
+
+ cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]];
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+
+ case 0x79: /* OUT (C),A */
+ TSTATE(12);
+ if (cpu->pwrite) cpu->pwrite(cpu,cpu->BC.w,cpu->AF.b[HI]);
+ break;
+
+ case 0x7a: /* ADC HL,SP */
+ TSTATE(15);
+ ADC16(cpu->HL.w,cpu->SP);
+ break;
+
+ case 0x7b: /* LD SP,(nnnn) */
+ TSTATE(20);
+ cpu->SP=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x7c: /* NEG */
+ {
+ Z80Byte b;
+
+ TSTATE(8);
+
+ b=cpu->AF.b[HI];
+ cpu->AF.b[HI]=0;
+ SUB8(b);
+ break;
+ }
+
+ case 0x7d: /* RETN */
+ TSTATE(14);
+ cpu->IFF1=cpu->IFF2;
+ POP(cpu->PC);
+ break;
+
+ case 0x7e: /* IM 2 */
+ TSTATE(8);
+ cpu->IM=2;
+ break;
+
+ case 0x7f: /* NOP */
+ TSTATE(8);
+ CALLBACK(eZ80_EDHook,opcode);
+ break;
+
+ case 0xa0: /* LDI */
+ TSTATE(16);
+ LDI;
+ break;
+
+ case 0xa1: /* CPI */
+ TSTATE(16);
+ CPI;
+ break;
+
+ case 0xa2: /* INI */
+ TSTATE(16);
+ INI;
+ break;
+
+ case 0xa3: /* OUTI */
+ TSTATE(16);
+ OUTI;
+ break;
+
+ case 0xa8: /* LDD */
+ TSTATE(16);
+ LDD;
+ break;
+
+ case 0xa9: /* CPD */
+ TSTATE(16);
+ CPD;
+ break;
+
+ case 0xaa: /* IND */
+ TSTATE(16);
+ IND;
+ break;
+
+ case 0xab: /* OUTD */
+ TSTATE(16);
+ OUTD;
+ break;
+
+ case 0xb0: /* LDIR */
+ TSTATE(16);
+ LDI;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb1: /* CPIR */
+ TSTATE(16);
+ CPI;
+ if (cpu->BC.w && !IS_Z)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb2: /* INIR */
+ TSTATE(16);
+ INI;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb3: /* OTIR */
+ TSTATE(16);
+ OUTI;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb8: /* LDDR */
+ TSTATE(16);
+ LDD;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xb9: /* CPDR */
+ TSTATE(16);
+ CPD;
+ if (cpu->BC.w && !IS_Z)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xba: /* INDR */
+ TSTATE(16);
+ IND;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ case 0xbb: /* OTDR */
+ TSTATE(16);
+ OUTD;
+ if (cpu->BC.w)
+ {
+ TSTATE(5);
+ cpu->PC-=2;
+ }
+ break;
+
+ /* All the rest are NOP/invalid
+ */
+ default:
+ TSTATE(8);
+ CALLBACK(eZ80_EDHook,opcode);
+ break;
+ }
+}
+
+
+/* ---------------------------------------- HANDLERS FOR CB OPCODES
+*/
+static void DecodeCB(Z80 *cpu, Z80Byte opcode)
+{
+ switch(opcode)
+ {
+ CB_ALU_BLOCK(0x00,RLC)
+ CB_ALU_BLOCK(0x08,RRC)
+ CB_ALU_BLOCK(0x10,RL)
+ CB_ALU_BLOCK(0x18,RR)
+ CB_ALU_BLOCK(0x20,SLA)
+ CB_ALU_BLOCK(0x28,SRA)
+ CB_ALU_BLOCK(0x30,SLL)
+ CB_ALU_BLOCK(0x38,SRL)
+
+ CB_BITMANIP_BLOCK(0x40,BIT,0)
+ CB_BITMANIP_BLOCK(0x48,BIT,1)
+ CB_BITMANIP_BLOCK(0x50,BIT,2)
+ CB_BITMANIP_BLOCK(0x58,BIT,3)
+ CB_BITMANIP_BLOCK(0x60,BIT,4)
+ CB_BITMANIP_BLOCK(0x68,BIT,5)
+ CB_BITMANIP_BLOCK(0x70,BIT,6)
+ CB_BITMANIP_BLOCK(0x78,BIT,7)
+
+ CB_BITMANIP_BLOCK(0x80,BIT_RES,0)
+ CB_BITMANIP_BLOCK(0x88,BIT_RES,1)
+ CB_BITMANIP_BLOCK(0x90,BIT_RES,2)
+ CB_BITMANIP_BLOCK(0x98,BIT_RES,3)
+ CB_BITMANIP_BLOCK(0xa0,BIT_RES,4)
+ CB_BITMANIP_BLOCK(0xa8,BIT_RES,5)
+ CB_BITMANIP_BLOCK(0xb0,BIT_RES,6)
+ CB_BITMANIP_BLOCK(0xb8,BIT_RES,7)
+
+ CB_BITMANIP_BLOCK(0xc0,BIT_SET,0)
+ CB_BITMANIP_BLOCK(0xc8,BIT_SET,1)
+ CB_BITMANIP_BLOCK(0xd0,BIT_SET,2)
+ CB_BITMANIP_BLOCK(0xd8,BIT_SET,3)
+ CB_BITMANIP_BLOCK(0xe0,BIT_SET,4)
+ CB_BITMANIP_BLOCK(0xe8,BIT_SET,5)
+ CB_BITMANIP_BLOCK(0xf0,BIT_SET,6)
+ CB_BITMANIP_BLOCK(0xf8,BIT_SET,7)
+ }
+}
+
+
+static void ShiftedDecodeCB(Z80 *cpu, Z80Byte opcode, Z80Relative offset)
+{
+ Z80Word addr;
+
+ /* See if we've come here from a IX/IY shift.
+ */
+ switch (cpu->shift)
+ {
+ case 0xdd:
+ addr=cpu->IX.w+offset;
+ break;
+ case 0xfd:
+ addr=cpu->IY.w+offset;
+ break;
+ default:
+ addr=cpu->HL.w; /* Play safe... */
+ break;
+ }
+
+ switch(opcode)
+ {
+ SHIFTED_CB_ALU_BLOCK(0x00,RLC)
+ SHIFTED_CB_ALU_BLOCK(0x08,RRC)
+ SHIFTED_CB_ALU_BLOCK(0x10,RL)
+ SHIFTED_CB_ALU_BLOCK(0x18,RR)
+ SHIFTED_CB_ALU_BLOCK(0x20,SLA)
+ SHIFTED_CB_ALU_BLOCK(0x28,SRA)
+ SHIFTED_CB_ALU_BLOCK(0x30,SLL)
+ SHIFTED_CB_ALU_BLOCK(0x38,SRL)
+
+ SHIFTED_CB_BITMANIP_BLOCK(0x40,BIT,0)
+ SHIFTED_CB_BITMANIP_BLOCK(0x48,BIT,1)
+ SHIFTED_CB_BITMANIP_BLOCK(0x50,BIT,2)
+ SHIFTED_CB_BITMANIP_BLOCK(0x58,BIT,3)
+ SHIFTED_CB_BITMANIP_BLOCK(0x60,BIT,4)
+ SHIFTED_CB_BITMANIP_BLOCK(0x68,BIT,5)
+ SHIFTED_CB_BITMANIP_BLOCK(0x70,BIT,6)
+ SHIFTED_CB_BITMANIP_BLOCK(0x78,BIT,7)
+
+ SHIFTED_CB_BITMANIP_BLOCK(0x80,BIT_RES,0)
+ SHIFTED_CB_BITMANIP_BLOCK(0x88,BIT_RES,1)
+ SHIFTED_CB_BITMANIP_BLOCK(0x90,BIT_RES,2)
+ SHIFTED_CB_BITMANIP_BLOCK(0x98,BIT_RES,3)
+ SHIFTED_CB_BITMANIP_BLOCK(0xa0,BIT_RES,4)
+ SHIFTED_CB_BITMANIP_BLOCK(0xa8,BIT_RES,5)
+ SHIFTED_CB_BITMANIP_BLOCK(0xb0,BIT_RES,6)
+ SHIFTED_CB_BITMANIP_BLOCK(0xb8,BIT_RES,7)
+
+ SHIFTED_CB_BITMANIP_BLOCK(0xc0,BIT_SET,0)
+ SHIFTED_CB_BITMANIP_BLOCK(0xc8,BIT_SET,1)
+ SHIFTED_CB_BITMANIP_BLOCK(0xd0,BIT_SET,2)
+ SHIFTED_CB_BITMANIP_BLOCK(0xd8,BIT_SET,3)
+ SHIFTED_CB_BITMANIP_BLOCK(0xe0,BIT_SET,4)
+ SHIFTED_CB_BITMANIP_BLOCK(0xe8,BIT_SET,5)
+ SHIFTED_CB_BITMANIP_BLOCK(0xf0,BIT_SET,6)
+ SHIFTED_CB_BITMANIP_BLOCK(0xf8,BIT_SET,7)
+ }
+}
+
+
+/* ---------------------------------------- NORMAL OPCODE DECODER
+*/
+void Z80_Decode(Z80 *cpu, Z80Byte opcode)
+{
+ Z80Word *HL;
+ Z80Byte *H;
+ Z80Byte *L;
+ Z80Relative off;
+
+ /* See if we've come here from a IX/IY shift
+ */
+ switch (cpu->shift)
+ {
+ case 0xdd:
+ HL=&(cpu->IX.w);
+ L=cpu->IX.b+LO;
+ H=cpu->IX.b+HI;
+ break;
+ case 0xfd:
+ HL=&(cpu->IY.w);
+ L=cpu->IY.b+LO;
+ H=cpu->IY.b+HI;
+ break;
+ default:
+ HL=&(cpu->HL.w);
+ L=cpu->HL.b+LO;
+ H=cpu->HL.b+HI;
+ break;
+ }
+
+ switch(opcode)
+ {
+ case 0x00: /* NOP */
+ TSTATE(4);
+ break;
+
+ case 0x01: /* LD BC,nnnn */
+ TSTATE(10);
+ cpu->BC.w=FETCH_WORD;
+ break;
+
+ case 0x02: /* LD (BC),A */
+ TSTATE(7);
+ POKE(cpu->BC.w,cpu->AF.b[HI]);
+ break;
+
+ case 0x03: /* INC BC */
+ TSTATE(6);
+ cpu->BC.w++;
+ break;
+
+ case 0x04: /* INC B */
+ TSTATE(4);
+ INC8(cpu->BC.b[HI]);
+ break;
+
+ case 0x05: /* DEC B */
+ TSTATE(4);
+ DEC8(cpu->BC.b[HI]);
+ break;
+
+ case 0x06: /* LD B,n */
+ TSTATE(7);
+ cpu->BC.b[HI]=FETCH_BYTE;
+ break;
+
+ case 0x07: /* RLCA */
+ TSTATE(4);
+ RLCA;
+ break;
+
+ case 0x08: /* EX AF,AF' */
+ TSTATE(4);
+ SWAP(cpu->AF.w,cpu->AF_);
+ break;
+
+ case 0x09: /* ADD HL,BC */
+ TSTATE(11);
+ ADD16(*HL,cpu->BC.w);
+ break;
+
+ case 0x0a: /* LD A,(BC) */
+ TSTATE(7);
+ cpu->AF.b[HI]=PEEK(cpu->BC.w);
+ break;
+
+ case 0x0b: /* DEC BC */
+ TSTATE(6);
+ cpu->BC.w--;
+ break;
+
+ case 0x0c: /* INC C */
+ TSTATE(4);
+ INC8(cpu->BC.b[LO]);
+ break;
+
+ case 0x0d: /* DEC C */
+ TSTATE(4);
+ DEC8(cpu->BC.b[LO]);
+ break;
+
+ case 0x0e: /* LD C,n */
+ TSTATE(7);
+ cpu->BC.b[LO]=FETCH_BYTE;
+ break;
+
+ case 0x0f: /* RRCA */
+ TSTATE(4);
+ RRCA;
+ break;
+
+ case 0x10: /* DJNZ */
+ if (--(cpu->BC.b[HI]))
+ {
+ TSTATE(13);
+ JR;
+ }
+ else
+ {
+ TSTATE(8);
+ NOJR;
+ }
+ break;
+
+ case 0x11: /* LD DE,nnnn */
+ TSTATE(10);
+ cpu->DE.w=FETCH_WORD;
+ break;
+
+ case 0x12: /* LD (DE),A */
+ TSTATE(7);
+ POKE(cpu->DE.w,cpu->AF.b[HI]);
+ break;
+
+ case 0x13: /* INC DE */
+ TSTATE(6);
+ cpu->DE.w++;
+ break;
+
+ case 0x14: /* INC D */
+ TSTATE(4);
+ INC8(cpu->DE.b[HI]);
+ break;
+
+ case 0x15: /* DEC D */
+ TSTATE(4);
+ DEC8(cpu->DE.b[HI]);
+ break;
+
+ case 0x16: /* LD D,n */
+ TSTATE(7);
+ cpu->DE.b[HI]=FETCH_BYTE;
+ break;
+
+ case 0x17: /* RLA */
+ TSTATE(4);
+ RLA;
+ break;
+
+ case 0x18: /* JR d */
+ TSTATE(12);
+ JR;
+ break;
+
+ case 0x19: /* ADD HL,DE */
+ TSTATE(11);
+ ADD16(*HL,cpu->DE.w);
+ break;
+
+ case 0x1a: /* LD A,(DE) */
+ TSTATE(7);
+ cpu->AF.b[HI]=PEEK(cpu->DE.w);
+ break;
+
+ case 0x1b: /* DEC DE */
+ TSTATE(6);
+ cpu->DE.w--;
+ break;
+
+ case 0x1c: /* INC E */
+ TSTATE(4);
+ INC8(cpu->DE.b[LO]);
+ break;
+
+ case 0x1d: /* DEC E */
+ TSTATE(4);
+ DEC8(cpu->DE.b[LO]);
+ break;
+
+ case 0x1e: /* LD E,n */
+ TSTATE(7);
+ cpu->DE.b[LO]=FETCH_BYTE;
+ break;
+
+ case 0x1f: /* RRA */
+ TSTATE(4);
+ RRA;
+ break;
+
+ case 0x20: /* JR NZ,e */
+ JR_COND(!IS_Z);
+ break;
+
+ case 0x21: /* LD HL,nnnn */
+ TSTATE(10);
+ *HL=FETCH_WORD;
+ break;
+
+ case 0x22: /* LD (nnnn),HL */
+ TSTATE(16);
+ POKEW(FETCH_WORD,*HL);
+ break;
+
+ case 0x23: /* INC HL */
+ TSTATE(6);
+ (*HL)++;
+ break;
+
+ case 0x24: /* INC H */
+ TSTATE(4);
+ INC8(*H);
+ break;
+
+ case 0x25: /* DEC H */
+ TSTATE(4);
+ DEC8(*H);
+ break;
+
+ case 0x26: /* LD H,n */
+ TSTATE(7);
+ *H=FETCH_BYTE;
+ break;
+
+ case 0x27: /* DAA */
+ TSTATE(4);
+ DAA(cpu);
+ break;
+
+ case 0x28: /* JR Z,d */
+ JR_COND(IS_Z);
+ break;
+
+ case 0x29: /* ADD HL,HL */
+ TSTATE(11);
+ ADD16(*HL,*HL);
+ break;
+
+ case 0x2a: /* LD HL,(nnnn) */
+ TSTATE(7);
+ *HL=PEEKW(FETCH_WORD);
+ break;
+
+ case 0x2b: /* DEC HL */
+ TSTATE(6);
+ (*HL)--;
+ break;
+
+ case 0x2c: /* INC L */
+ TSTATE(4);
+ INC8(*L);
+ break;
+
+ case 0x2d: /* DEC L */
+ TSTATE(4);
+ DEC8(*L);
+ break;
+
+ case 0x2e: /* LD L,n */
+ TSTATE(7);
+ *L=FETCH_BYTE;
+ break;
+
+ case 0x2f: /* CPL */
+ TSTATE(4);
+ cpu->AF.b[HI]^=0xff;
+ SETFLAG(H_Z80);
+ SETFLAG(N_Z80);
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+
+ case 0x30: /* JR NC,d */
+ JR_COND(!IS_C);
+ break;
+
+ case 0x31: /* LD SP,nnnn */
+ TSTATE(10);
+ cpu->SP=FETCH_WORD;
+ break;
+
+ case 0x32: /* LD (nnnn),A */
+ TSTATE(13);
+ POKE(FETCH_WORD,cpu->AF.b[HI]);
+ break;
+
+ case 0x33: /* INC SP */
+ TSTATE(6);
+ cpu->SP++;
+ break;
+
+ case 0x34: /* INC (HL) */
+ TSTATE(11);
+ OFFSET(off);
+ OP_ON_MEM(INC8,*HL+off);
+ break;
+
+ case 0x35: /* DEC (HL) */
+ TSTATE(11);
+ OFFSET(off);
+ OP_ON_MEM(DEC8,*HL+off);
+ break;
+
+ case 0x36: /* LD (HL),n */
+ TSTATE(10);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,FETCH_BYTE);
+ break;
+
+ case 0x37: /* SCF */
+ TSTATE(4);
+ cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))
+ | C_Z80
+ | (cpu->AF.b[HI]&(B3_Z80|B5_Z80));
+ break;
+
+ case 0x38: /* JR C,d */
+ JR_COND(IS_C);
+ break;
+
+ case 0x39: /* ADD HL,SP */
+ TSTATE(11);
+ ADD16(*HL,cpu->SP);
+ break;
+
+ case 0x3a: /* LD A,(nnnn) */
+ TSTATE(13);
+ cpu->AF.b[HI]=cpu->mread(cpu,FETCH_WORD);
+ break;
+
+ case 0x3b: /* DEC SP */
+ TSTATE(6);
+ cpu->SP--;
+ break;
+
+ case 0x3c: /* INC A */
+ TSTATE(4);
+ INC8(cpu->AF.b[HI]);
+ break;
+
+ case 0x3d: /* DEC A */
+ TSTATE(4);
+ DEC8(cpu->AF.b[HI]);
+ break;
+
+ case 0x3e: /* LD A,n */
+ TSTATE(7);
+ cpu->AF.b[HI]=FETCH_BYTE;
+ break;
+
+ case 0x3f: /* CCF */
+ TSTATE(4);
+
+ if (CARRY)
+ SETFLAG(H_Z80);
+ else
+ CLRFLAG(H_Z80);
+
+ cpu->AF.b[LO]^=C_Z80;
+ SETHIDDEN(cpu->AF.b[HI]);
+ break;
+
+ LD_BLOCK(0x40,cpu->BC.b[HI],cpu->BC.b[HI])
+ LD_BLOCK(0x48,cpu->BC.b[LO],cpu->BC.b[LO])
+ LD_BLOCK(0x50,cpu->DE.b[HI],cpu->DE.b[HI])
+ LD_BLOCK(0x58,cpu->DE.b[LO],cpu->DE.b[LO])
+ LD_BLOCK(0x60,*H,cpu->HL.b[HI])
+ LD_BLOCK(0x68,*L,cpu->HL.b[LO])
+
+ case 0x70: /* LD (HL),B */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->BC.b[HI]);
+ break;
+
+ case 0x71: /* LD (HL),C */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->BC.b[LO]);
+ break;
+
+ case 0x72: /* LD (HL),D */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->DE.b[HI]);
+ break;
+
+ case 0x73: /* LD (HL),E */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->DE.b[LO]);
+ break;
+
+ case 0x74: /* LD (HL),H */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->HL.b[HI]);
+ break;
+
+ case 0x75: /* LD (HL),L */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->HL.b[LO]);
+ break;
+
+ case 0x76: /* HALT */
+ TSTATE(4);
+ cpu->PC--;
+
+ if (!cpu->halt)
+ CALLBACK(eZ80_Halt,1);
+
+ cpu->halt=TRUE;
+ break;
+
+ case 0x77: /* LD (HL),A */
+ TSTATE(7);
+ OFFSET(off);
+ cpu->mwrite(cpu,*HL+off,cpu->AF.b[HI]);
+ break;
+
+ LD_BLOCK(0x78,cpu->AF.b[HI],cpu->AF.b[HI])
+
+ ALU_BLOCK(0x80,ADD8)
+ ALU_BLOCK(0x88,ADC8)
+ ALU_BLOCK(0x90,SUB8)
+ ALU_BLOCK(0x98,SBC8)
+ ALU_BLOCK(0xa0,AND)
+ ALU_BLOCK(0xa8,XOR)
+ ALU_BLOCK(0xb0,OR)
+ ALU_BLOCK(0xb8,CMP8)
+
+ case 0xc0: /* RET NZ */
+ RET_COND(!IS_Z);
+ break;
+
+ case 0xc1: /* POP BC */
+ TSTATE(10);
+ POP(cpu->BC.w);
+ break;
+
+ case 0xc2: /* JP NZ,nnnn */
+ JP_COND(!IS_Z);
+ break;
+
+ case 0xc3: /* JP nnnn */
+ JP_COND(1);
+ break;
+
+ case 0xc4: /* CALL NZ,nnnn */
+ CALL_COND(!IS_Z);
+ break;
+
+ case 0xc5: /* PUSH BC */
+ TSTATE(10);
+ PUSH(cpu->BC.w);
+ break;
+
+ case 0xc6: /* ADD A,n */
+ TSTATE(7);
+ ADD8(FETCH_BYTE);
+ break;
+
+ case 0xc7: /* RST 0 */
+ RST(0);
+ break;
+
+ case 0xc8: /* RET Z */
+ RET_COND(IS_Z);
+ break;
+
+ case 0xc9: /* RET */
+ TSTATE(10);
+ POP(cpu->PC);
+ break;
+
+ case 0xca: /* JP Z,nnnn */
+ JP_COND(IS_Z);
+ break;
+
+ case 0xcb: /* CB PREFIX */
+ INC_R;
+
+ /* Check for previous IX/IY shift.
+ */
+ if (cpu->shift!=0)
+ {
+ Z80Relative cb_offset;
+
+ TSTATE(4); /* Wild stab in the dark! */
+ cb_offset=FETCH_BYTE;
+ ShiftedDecodeCB(cpu,FETCH_BYTE,cb_offset);
+ }
+ else
+ {
+ DecodeCB(cpu,FETCH_BYTE);
+ }
+ break;
+
+ case 0xcc: /* CALL Z,nnnn */
+ CALL_COND(IS_Z);
+ break;
+
+ case 0xcd: /* CALL nnnn */
+ CALL_COND(1);
+ break;
+
+ case 0xce: /* ADC A,n */
+ ADC8(FETCH_BYTE);
+ break;
+
+ case 0xcf: /* RST 8 */
+ RST(8);
+ break;
+
+ case 0xd0: /* RET NC */
+ RET_COND(!IS_C);
+ break;
+
+ case 0xd1: /* POP DE */
+ TSTATE(10);
+ POP(cpu->DE.w);
+ break;
+
+ case 0xd2: /* JP NC,nnnn */
+ JP_COND(!IS_C);
+ break;
+
+ case 0xd3: /* OUT (n),A */
+ TSTATE(11);
+ if (cpu->pwrite)
+ cpu->pwrite(cpu,FETCH_BYTE,cpu->AF.b[HI]);
+ else
+ cpu->PC++;
+ break;
+
+ case 0xd4: /* CALL NC,nnnn */
+ CALL_COND(!IS_C);
+ break;
+
+ case 0xd5: /* PUSH DE */
+ TSTATE(11);
+ PUSH(cpu->DE.w);
+ break;
+
+ case 0xd6: /* SUB A,n */
+ TSTATE(7);
+ SUB8(FETCH_BYTE);
+ break;
+
+ case 0xd7: /* RST 10 */
+ RST(0x10);
+ break;
+
+ case 0xd8: /* RET C */
+ RET_COND(IS_C);
+ break;
+
+ case 0xd9: /* EXX */
+ TSTATE(4);
+ SWAP(cpu->BC.w,cpu->BC_);
+ SWAP(cpu->DE.w,cpu->DE_);
+ SWAP(cpu->HL.w,cpu->HL_);
+ break;
+
+ case 0xda: /* JP C,nnnn */
+ JP_COND(IS_C);
+ break;
+
+ case 0xdb: /* IN A,(n) */
+ TSTATE(11);
+ if (cpu->pread)
+ {
+ Z80Word port;
+
+ port=FETCH_BYTE;
+ port|=(Z80Word)cpu->AF.b[HI]<<8;
+ cpu->AF.b[HI]=cpu->pread(cpu,port);
+ }
+ else
+ cpu->PC++;
+ break;
+
+ case 0xdc: /* CALL C,nnnn */
+ CALL_COND(IS_C);
+ break;
+
+ case 0xdd: /* DD PREFIX */
+ TSTATE(4);
+ INC_R;
+
+ cpu->shift=opcode;
+ Z80_Decode(cpu,FETCH_BYTE);
+ break;
+
+ case 0xde: /* SBC A,n */
+ TSTATE(7);
+ SBC8(FETCH_BYTE);
+ break;
+
+ case 0xdf: /* RST 18 */
+ RST(0x18);
+ break;
+
+ case 0xe0: /* RET PO */
+ RET_COND(!IS_P);
+ break;
+
+ case 0xe1: /* POP HL */
+ TSTATE(10);
+ POP(*HL);
+ break;
+
+ case 0xe2: /* JP PO,nnnn */
+ JP_COND(!IS_P);
+ break;
+
+ case 0xe3: /* EX (SP),HL */
+ {
+ Z80Word tmp;
+ TSTATE(19);
+ POP(tmp);
+ PUSH(*HL);
+ *HL=tmp;
+ }
+ break;
+
+ case 0xe4: /* CALL PO,nnnn */
+ CALL_COND(!IS_P);
+ break;
+
+ case 0xe5: /* PUSH HL */
+ TSTATE(10);
+ PUSH(*HL);
+ break;
+
+ case 0xe6: /* AND A,n */
+ TSTATE(7);
+ AND(FETCH_BYTE);
+ break;
+
+ case 0xe7: /* RST 20 */
+ RST(0x20);
+ break;
+
+ case 0xe8: /* RET PE */
+ RET_COND(IS_P);
+ break;
+
+ case 0xe9: /* JP (HL) */
+ TSTATE(4);
+ cpu->PC=*HL;
+ break;
+
+ case 0xea: /* JP PE,nnnn */
+ JP_COND(IS_P);
+ break;
+
+ case 0xeb: /* EX DE,HL */
+ TSTATE(4);
+ SWAP(cpu->DE.w,*HL);
+ break;
+
+ case 0xec: /* CALL PE,nnnn */
+ CALL_COND(IS_P);
+ break;
+
+ case 0xed: /* ED PREFIX */
+ INC_R;
+ DecodeED(cpu,FETCH_BYTE);
+ break;
+
+ case 0xee: /* XOR A,n */
+ TSTATE(7);
+ XOR(FETCH_BYTE);
+ break;
+
+ case 0xef: /* RST 28 */
+ RST(0x28);
+ break;
+
+ case 0xf0: /* RET P */
+ RET_COND(!IS_S);
+ break;
+
+ case 0xf1: /* POP AF */
+ TSTATE(10);
+ POP(cpu->AF.w);
+ break;
+
+ case 0xf2: /* JP P,nnnn */
+ JP_COND(!IS_S);
+ break;
+
+ case 0xf3: /* DI */
+ TSTATE(4);
+ cpu->IFF1=0;
+ cpu->IFF2=0;
+ break;
+
+ case 0xf4: /* CALL P,nnnn */
+ CALL_COND(!IS_S);
+ break;
+
+ case 0xf5: /* PUSH AF */
+ TSTATE(10);
+ PUSH(cpu->AF.w);
+ break;
+
+ case 0xf6: /* OR A,n */
+ TSTATE(7);
+ OR(FETCH_BYTE);
+ break;
+
+ case 0xf7: /* RST 30 */
+ RST(0x30);
+ break;
+
+ case 0xf8: /* RET M */
+ RET_COND(IS_S);
+ break;
+
+ case 0xf9: /* LD SP,HL */
+ TSTATE(6);
+ cpu->SP=*HL;
+ break;
+
+ case 0xfa: /* JP M,nnnn */
+ JP_COND(IS_S);
+ break;
+
+ case 0xfb: /* EI */
+ TSTATE(4);
+ cpu->IFF1=1;
+ cpu->IFF2=1;
+ break;
+
+ case 0xfc: /* CALL M,nnnn */
+ CALL_COND(IS_S);
+ break;
+
+ case 0xfd: /* FD PREFIX */
+ TSTATE(4);
+ INC_R;
+
+ cpu->shift=opcode;
+ Z80_Decode(cpu,FETCH_BYTE);
+ break;
+
+ case 0xfe: /* CP A,n */
+ TSTATE(7);
+ CMP8(FETCH_BYTE);
+ break;
+
+ case 0xff: /* RST 38 */
+ RST(0x38);
+ break;
+
+ }
+}
+
+
+/* END OF FILE */