/* z80 - Z80 Emulator Copyright (C) 2021 Ian Cowburn 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 3 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, see ------------------------------------------------------------------------- $Id$ */ #include #include #include "z80.h" #include "z80_private.h" /* ---------------------------------------- TABLES AND INIT */ static Z80Byte PSZtable[512]; static Z80Byte SZtable[512]; static Z80Byte Ptable[512]; static Z80Byte Stable[512]; static Z80Byte Ztable[512]; /* ---------------------------------------- MISC FUNCTIONS */ void Z80_InitialiseInternals(void) { Z80Word f; Z80Reg r; /* Check endianness */ r.w=0x1234; if (r.b.hi != 0x12 || r.b.lo != 0x34) { 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<mwrite(cpu,addr,val); PRIV->mwrite(cpu,addr+1,val>>8); } #endif /* ---------------------------------------- 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; \ cpu->priv->memptr.w=REG+1; \ 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; \ cpu->priv->memptr.w=REG+1; \ 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; \ cpu->priv->memptr.w=REG+1; \ 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)]|((REG)&(B3_Z80|B5_Z80)); \ 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|((REG)&(B3_Z80|B5_Z80)); \ 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=PEEK(addr); \ OP(memop); \ POKE(addr,memop); \ } while(0) #define OP_ON_MEM_WITH_ARG(OP,addr,arg) \ do { \ Z80Byte memop=PEEK(addr); \ OP(memop,arg); \ POKE(addr,memop); \ } while(0) #define OP_ON_MEM_WITH_COPY(OP,addr,copy) \ do { \ Z80Byte memop=PEEK(addr); \ OP(memop); \ copy=memop; \ POKE(addr,memop); \ } while(0) #define OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,arg,copy) \ do { \ Z80Byte memop=PEEK(addr); \ OP(memop,arg); \ copy=memop; \ POKE(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&=C_Z80; \ cpu->AF.b.lo|=H_Z80; \ if ((REG)&(1<AF.b.lo|=S_Z80® \ } \ else \ { \ cpu->AF.b.lo|=Z_Z80|P_Z80; \ } \ SETHIDDEN(REG); \ } while(0) #define BIT_MEMPTR(REG,B) \ do { \ cpu->AF.b.lo&=C_Z80; \ cpu->AF.b.lo|=H_Z80; \ if ((REG)&(1<AF.b.lo|=S_Z80® \ } \ else \ { \ cpu->AF.b.lo|=Z_Z80|P_Z80; \ } \ SETHIDDEN(PRIV->memptr.b.hi); \ } while(0) #define BIT_SET(REG,B) (REG)|=(1<PC); \ PRIV->memptr.w=cpu->PC; \ } \ else \ { \ TSTATE(5); \ } \ } while(0) #define RST(ADDR) \ TSTATE(11); \ PUSH(cpu->PC); \ cpu->PC=ADDR; \ PRIV->memptr.w=ADDR /* ---------------------------------------- BLOCK OPERATIONS */ #define LDI \ do { \ Z80Byte b,a1; \ \ 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); \ \ a1=cpu->AF.b.hi+b; \ if (a1&2) SETFLAG(B5_Z80); else CLRFLAG(B5_Z80); \ if (a1&B3_Z80) SETFLAG(B3_Z80); else CLRFLAG(B3_Z80); \ } while(0) #define LDD \ do { \ Z80Byte b,a1; \ \ 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); \ \ a1=cpu->AF.b.hi+b; \ if (a1&2) SETFLAG(B5_Z80); else CLRFLAG(B5_Z80); \ if (a1&B3_Z80) SETFLAG(B3_Z80); else CLRFLAG(B3_Z80); \ } while(0) #define CPI \ do { \ Z80Byte c,b,a1; \ \ c=CARRY; \ b=PEEK(cpu->HL.w); \ \ CMP8(b); \ a1=cpu->AF.b.hi-b-(IS_H?1:0); \ \ if (a1&2) SETFLAG(B5_Z80); else CLRFLAG(B5_Z80); \ if (a1&B3_Z80) SETFLAG(B3_Z80); else CLRFLAG(B3_Z80); \ \ 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,a1; \ \ c=CARRY; \ b=PEEK(cpu->HL.w); \ \ CMP8(b); \ a1=cpu->AF.b.hi-b-(IS_H?1:0); \ \ if (a1&2) SETFLAG(B5_Z80); else CLRFLAG(B5_Z80); \ if (a1&B3_Z80) SETFLAG(B3_Z80); else CLRFLAG(B3_Z80); \ \ 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(*HL,off); \ DEST2=PEEK(*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(*HL,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,OP2,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: /* OP2 (HL) */ \ TSTATE(12); \ OP_ON_MEM_WITH_ARG(OP2,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,OP2,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: /* OP2 (HL) */ \ TSTATE(12); \ OP_ON_MEM_WITH_ARG(OP2,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=cpu->AF.b.lo&C_Z80; Z80Byte nf=cpu->AF.b.lo&N_Z80; Z80Byte acc=cpu->AF.b.hi; if (acc > 0x99 || IS_C) { add|=0x60; if (acc > 0x99) { carry=C_Z80; } } if ((acc&0xf) > 0x9 || IS_H) { add|=0x06; } if (nf) { SUB8(add); } else { ADD8(add); } cpu->AF.b.lo = (cpu->AF.b.lo & ~(C_Z80|P_Z80)) | carry | Ptable[cpu->AF.b.hi]; } /* ---------------------------------------- HANDLERS FOR ED OPCODES */ static void DecodeED(Z80 *cpu, Z80Byte opcode) { switch(opcode) { case 0x40: /* IN B,(C) */ TSTATE(12); if (PRIV->pread) { cpu->BC.b.hi=PRIV->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 (PRIV->pwrite) PRIV->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 */ { Z80Word addr=FETCH_WORD; TSTATE(20); POKEW(addr,cpu->BC.w); cpu->priv->memptr.w=addr+1; 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 (PRIV->pread) { cpu->BC.b.lo=PRIV->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 (PRIV->pwrite) PRIV->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) */ { Z80Word addr=FETCH_WORD; TSTATE(20); cpu->BC.w=PEEKW(addr); cpu->priv->memptr.w=addr+1; 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); cpu->priv->memptr.w=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 (PRIV->pread) { cpu->DE.b.hi=PRIV->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 (PRIV->pwrite) PRIV->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 */ { Z80Word addr=FETCH_WORD; TSTATE(20); POKEW(addr,cpu->DE.w); cpu->priv->memptr.w=addr+1; 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 (PRIV->pread) { cpu->DE.b.lo=PRIV->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 (PRIV->pwrite) PRIV->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) */ { Z80Word addr=FETCH_WORD; TSTATE(20); cpu->DE.w=PEEKW(addr); cpu->priv->memptr.w=addr+1; 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 (PRIV->pread) { cpu->HL.b.hi=PRIV->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 (PRIV->pwrite) PRIV->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 */ { Z80Word addr=FETCH_WORD; TSTATE(20); POKEW(addr,cpu->HL.w); cpu->priv->memptr.w=addr+1; 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); cpu->priv->memptr.w=cpu->HL.w+1; 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 (PRIV->pread) { cpu->HL.b.lo=PRIV->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 (PRIV->pwrite) PRIV->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) */ { Z80Word addr=FETCH_WORD; TSTATE(20); cpu->HL.w=PEEKW(addr); cpu->priv->memptr.w=addr+1; 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); cpu->priv->memptr.w=cpu->HL.w+1; 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 (PRIV->pread) { b=PRIV->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 (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,255); 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 (PRIV->pread) { cpu->AF.b.hi=PRIV->pread(cpu,cpu->BC.w); } else { cpu->AF.b.hi=0; } cpu->AF.b.lo=CARRY|PSZtable[cpu->AF.b.hi]; PRIV->memptr.w=cpu->BC.w+1; SETHIDDEN(cpu->AF.b.hi); break; case 0x79: /* OUT (C),A */ TSTATE(12); if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->AF.b.hi); PRIV->memptr.w=cpu->BC.w+1; 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; PRIV->memptr.w++; break; case 0xa2: /* INI */ TSTATE(16); PRIV->memptr.w = cpu->BC.w + 1; INI; break; case 0xa3: /* OUTI */ TSTATE(16); OUTI; PRIV->memptr.w=cpu->BC.w+1; break; case 0xa8: /* LDD */ TSTATE(16); LDD; break; case 0xa9: /* CPD */ TSTATE(16); CPD; PRIV->memptr.w--; break; case 0xaa: /* IND */ TSTATE(16); PRIV->memptr.w = cpu->BC.w - 1; IND; break; case 0xab: /* OUTD */ TSTATE(16); OUTD; PRIV->memptr.w=cpu->BC.w-1; break; case 0xb0: /* LDIR */ TSTATE(16); LDI; if (cpu->BC.w) { TSTATE(5); cpu->PC-=2; SETHIDDEN((cpu->PC)>>8); PRIV->memptr.w=cpu->PC+1; } break; case 0xb1: /* CPIR */ TSTATE(16); CPI; if (cpu->BC.w && !IS_Z) { TSTATE(5); cpu->PC-=2; PRIV->memptr.w++; } else { PRIV->memptr.w=cpu->PC-1; } break; case 0xb2: /* INIR */ TSTATE(16); PRIV->memptr.w = cpu->BC.w + 1; INI; if (cpu->BC.w) { TSTATE(5); cpu->PC-=2; } break; case 0xb3: /* OTIR */ TSTATE(16); OUTI; PRIV->memptr.w=cpu->BC.w+1; 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; SETHIDDEN((cpu->PC)>>8); PRIV->memptr.w=cpu->PC+1; } break; case 0xb9: /* CPDR */ TSTATE(16); CPD; if (cpu->BC.w && !IS_Z) { TSTATE(5); cpu->PC-=2; PRIV->memptr.w++; } else { PRIV->memptr.w=cpu->PC-1; } break; case 0xba: /* INDR */ TSTATE(16); PRIV->memptr.w = cpu->BC.w-1; IND; if (cpu->BC.w) { TSTATE(5); cpu->PC-=2; } break; case 0xbb: /* OTDR */ TSTATE(16); OUTD; PRIV->memptr.w=cpu->BC.w-1; 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,BIT_MEMPTR,0) CB_BITMANIP_BLOCK(0x48,BIT,BIT_MEMPTR,1) CB_BITMANIP_BLOCK(0x50,BIT,BIT_MEMPTR,2) CB_BITMANIP_BLOCK(0x58,BIT,BIT_MEMPTR,3) CB_BITMANIP_BLOCK(0x60,BIT,BIT_MEMPTR,4) CB_BITMANIP_BLOCK(0x68,BIT,BIT_MEMPTR,5) CB_BITMANIP_BLOCK(0x70,BIT,BIT_MEMPTR,6) CB_BITMANIP_BLOCK(0x78,BIT,BIT_MEMPTR,7) CB_BITMANIP_BLOCK(0x80,BIT_RES,BIT_RES,0) CB_BITMANIP_BLOCK(0x88,BIT_RES,BIT_RES,1) CB_BITMANIP_BLOCK(0x90,BIT_RES,BIT_RES,2) CB_BITMANIP_BLOCK(0x98,BIT_RES,BIT_RES,3) CB_BITMANIP_BLOCK(0xa0,BIT_RES,BIT_RES,4) CB_BITMANIP_BLOCK(0xa8,BIT_RES,BIT_RES,5) CB_BITMANIP_BLOCK(0xb0,BIT_RES,BIT_RES,6) CB_BITMANIP_BLOCK(0xb8,BIT_RES,BIT_RES,7) CB_BITMANIP_BLOCK(0xc0,BIT_SET,BIT_SET,0) CB_BITMANIP_BLOCK(0xc8,BIT_SET,BIT_SET,1) CB_BITMANIP_BLOCK(0xd0,BIT_SET,BIT_SET,2) CB_BITMANIP_BLOCK(0xd8,BIT_SET,BIT_SET,3) CB_BITMANIP_BLOCK(0xe0,BIT_SET,BIT_SET,4) CB_BITMANIP_BLOCK(0xe8,BIT_SET,BIT_SET,5) CB_BITMANIP_BLOCK(0xf0,BIT_SET,BIT_SET,6) CB_BITMANIP_BLOCK(0xf8,BIT_SET,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 (PRIV->shift) { case 0xdd: addr=cpu->IX.w+offset; PRIV->memptr.w=addr; break; case 0xfd: addr=cpu->IY.w+offset; PRIV->memptr.w=addr; 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_MEMPTR,BIT_MEMPTR,0) SHIFTED_CB_BITMANIP_BLOCK(0x48,BIT_MEMPTR,BIT_MEMPTR,1) SHIFTED_CB_BITMANIP_BLOCK(0x50,BIT_MEMPTR,BIT_MEMPTR,2) SHIFTED_CB_BITMANIP_BLOCK(0x58,BIT_MEMPTR,BIT_MEMPTR,3) SHIFTED_CB_BITMANIP_BLOCK(0x60,BIT_MEMPTR,BIT_MEMPTR,4) SHIFTED_CB_BITMANIP_BLOCK(0x68,BIT_MEMPTR,BIT_MEMPTR,5) SHIFTED_CB_BITMANIP_BLOCK(0x70,BIT_MEMPTR,BIT_MEMPTR,6) SHIFTED_CB_BITMANIP_BLOCK(0x78,BIT_MEMPTR,BIT_MEMPTR,7) SHIFTED_CB_BITMANIP_BLOCK(0x80,BIT_RES,BIT_RES,0) SHIFTED_CB_BITMANIP_BLOCK(0x88,BIT_RES,BIT_RES,1) SHIFTED_CB_BITMANIP_BLOCK(0x90,BIT_RES,BIT_RES,2) SHIFTED_CB_BITMANIP_BLOCK(0x98,BIT_RES,BIT_RES,3) SHIFTED_CB_BITMANIP_BLOCK(0xa0,BIT_RES,BIT_RES,4) SHIFTED_CB_BITMANIP_BLOCK(0xa8,BIT_RES,BIT_RES,5) SHIFTED_CB_BITMANIP_BLOCK(0xb0,BIT_RES,BIT_RES,6) SHIFTED_CB_BITMANIP_BLOCK(0xb8,BIT_RES,BIT_RES,7) SHIFTED_CB_BITMANIP_BLOCK(0xc0,BIT_SET,BIT_SET,0) SHIFTED_CB_BITMANIP_BLOCK(0xc8,BIT_SET,BIT_SET,1) SHIFTED_CB_BITMANIP_BLOCK(0xd0,BIT_SET,BIT_SET,2) SHIFTED_CB_BITMANIP_BLOCK(0xd8,BIT_SET,BIT_SET,3) SHIFTED_CB_BITMANIP_BLOCK(0xe0,BIT_SET,BIT_SET,4) SHIFTED_CB_BITMANIP_BLOCK(0xe8,BIT_SET,BIT_SET,5) SHIFTED_CB_BITMANIP_BLOCK(0xf0,BIT_SET,BIT_SET,6) SHIFTED_CB_BITMANIP_BLOCK(0xf8,BIT_SET,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 (PRIV->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); cpu->priv->memptr.b.lo=(cpu->BC.w+1)&0xff; cpu->priv->memptr.b.hi=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); cpu->priv->memptr.w=cpu->BC.w+1; 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); cpu->priv->memptr.b.lo=(cpu->DE.w+1)&0xff; cpu->priv->memptr.b.hi=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); cpu->priv->memptr.w=cpu->DE.w+1; 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 */ { Z80Word addr=FETCH_WORD; TSTATE(13); POKE(addr,cpu->AF.b.hi); cpu->priv->memptr.b.lo=(addr + 1) & 0xff; cpu->priv->memptr.b.hi=cpu->AF.b.hi; break; } case 0x33: /* INC SP */ TSTATE(6); cpu->SP++; break; case 0x34: /* INC (HL) */ TSTATE(11); OFFSET(*HL,off); OP_ON_MEM(INC8,*HL+off); break; case 0x35: /* DEC (HL) */ TSTATE(11); OFFSET(*HL,off); OP_ON_MEM(DEC8,*HL+off); break; case 0x36: /* LD (HL),n */ TSTATE(10); OFFSET(*HL,off); POKE(*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) */ { Z80Word addr=FETCH_WORD; TSTATE(13); cpu->AF.b.hi=PEEK(addr); cpu->priv->memptr.w=addr + 1; 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); CLRFLAG(N_Z80); 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(*HL,off); POKE(*HL+off,cpu->BC.b.hi); break; case 0x71: /* LD (HL),C */ TSTATE(7); OFFSET(*HL,off); POKE(*HL+off,cpu->BC.b.lo); break; case 0x72: /* LD (HL),D */ TSTATE(7); OFFSET(*HL,off); POKE(*HL+off,cpu->DE.b.hi); break; case 0x73: /* LD (HL),E */ TSTATE(7); OFFSET(*HL,off); POKE(*HL+off,cpu->DE.b.lo); break; case 0x74: /* LD (HL),H */ TSTATE(7); OFFSET(*HL,off); POKE(*HL+off,cpu->HL.b.hi); break; case 0x75: /* LD (HL),L */ TSTATE(7); OFFSET(*HL,off); POKE(*HL+off,cpu->HL.b.lo); break; case 0x76: /* HALT */ TSTATE(4); cpu->PC--; if (!PRIV->halt) CALLBACK(eZ80_Halt,1); PRIV->halt=TRUE; break; case 0x77: /* LD (HL),A */ TSTATE(7); OFFSET(*HL,off); POKE(*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 (PRIV->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 (PRIV->pwrite) { Z80Word port; port=FETCH_BYTE; port|=(Z80Word)cpu->AF.b.hi<<8; PRIV->memptr.w=port+1; PRIV->pwrite(cpu,port,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 (PRIV->pread) { Z80Word port; port=FETCH_BYTE; port|=(Z80Word)cpu->AF.b.hi<<8; cpu->AF.b.hi=PRIV->pread(cpu,port); PRIV->memptr.w=port+1; } else cpu->PC++; break; case 0xdc: /* CALL C,nnnn */ CALL_COND(IS_C); break; case 0xdd: /* DD PREFIX */ TSTATE(4); INC_R; PRIV->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; cpu->priv->memptr.w=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; PRIV->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 */