diff options
Diffstat (limited to 'src/z80_decode.c')
-rw-r--r-- | src/z80_decode.c | 2533 |
1 files changed, 2533 insertions, 0 deletions
diff --git a/src/z80_decode.c b/src/z80_decode.c new file mode 100644 index 0000000..992e1d1 --- /dev/null +++ b/src/z80_decode.c @@ -0,0 +1,2533 @@ +/* + + 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: z80_decode.c 4 2006-10-04 23:05:43Z ianc $ + +*/ +#include <stdlib.h> +#include <limits.h> + +#include "z80.h" +#include "z80_private.h" + +static const char ident[]="$Id: z80_decode.c 4 2006-10-04 23:05:43Z ianc $"; + +/* ---------------------------------------- TABLES AND INIT +*/ +static Z80Byte PSZtable[512]; +static Z80Byte SZtable[512]; +static Z80Byte Ptable[512]; +static Z80Byte Stable[512]; +static Z80Byte Ztable[512]; + + +int Z80_HI_WORD; +int Z80_LO_WORD; + +#define HI Z80_HI_WORD +#define LO Z80_LO_WORD + +/* ---------------------------------------- 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; + } +} + +#ifndef ENABLE_ARRAY_MEMORY +static Z80Word FPEEKW(Z80 *cpu, Z80Word addr) +{ + return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); +} + + +static void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val) +{ + PRIV->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; \ + 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=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]=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=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(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 (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 */ + 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 (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) */ + 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 (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 */ + 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 (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) */ + 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 (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 */ + 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 (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) */ + 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 (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,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 (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]]; + 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]); + 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 (PRIV->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 (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]); + 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); + 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) */ + TSTATE(13); + cpu->AF.b[HI]=PEEK(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); + POKE(*HL+off,cpu->BC.b[HI]); + break; + + case 0x71: /* LD (HL),C */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->BC.b[LO]); + break; + + case 0x72: /* LD (HL),D */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->DE.b[HI]); + break; + + case 0x73: /* LD (HL),E */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->DE.b[LO]); + break; + + case 0x74: /* LD (HL),H */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->HL.b[HI]); + break; + + case 0x75: /* LD (HL),L */ + TSTATE(7); + OFFSET(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(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->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); + } + 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; + } + 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 */ |