diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | emma.c | 156 | ||||
-rw-r--r-- | runall | 4 | ||||
-rw-r--r-- | rundoc | 4 | ||||
-rw-r--r-- | runprelim | 4 | ||||
-rw-r--r-- | z80.c | 190 | ||||
-rw-r--r-- | z80.h | 9 | ||||
-rw-r--r-- | z80_decode.c | 2981 | ||||
-rw-r--r-- | z80_private.h | 71 |
9 files changed, 1952 insertions, 1477 deletions
@@ -18,7 +18,7 @@ # # ------------------------------------------------------------------------- # -# $Id: Makefile,v 1.1.1.1 2006-08-20 17:39:42 ianc Exp $ +# $Id: Makefile,v 1.2 2006-08-20 22:31:42 ianc Exp $ # # This CFLAGS assumes that gcc is being used. @@ -29,16 +29,18 @@ CFLAGS = -Wall -Werror -pedantic -ansi -O2 -finline-functions TARGET = emma -SOURCE = z80.c \ +SOURCE = z80.c \ + z80_decode \ emma.c -OBJECTS = z80.o \ +OBJECTS = z80.o \ + z80_decode.o \ emma.o all: $(TARGET) emucpm.hex $(TARGET): $(OBJECTS) - ld -o $(TARGET) $(OBJECTS) + cc -o $(TARGET) $(OBJECTS) emucpm.hex: emucpm.z80 tpasm -P Z80 -o intel emucpm.hex emucpm.z80 @@ -31,7 +31,6 @@ static const char id[]="$Id$"; #include <stdarg.h> #include "z80.h" -#include "expr.h" #define TRUE 1 @@ -41,10 +40,17 @@ static const char id[]="$Id$"; #define LO(w) ((w)&0xff) #define MK(h,l) (((Z80Word)(h))<<8|(l)) +typedef struct +{ + Z80Word address; + const char *label; +} Z80Label; + /* ---------------------------------------- GLOBALS */ static Z80 *z80; static Z80Byte mem[0x10000]; +static int memctl[256]; static sig_atomic_t stop=FALSE; static int quit=FALSE; @@ -68,6 +74,7 @@ static void Log(const char *format, ...); static void Run(char *p); static Z80Word Address(const char *p); static const char *GetLabel(Z80 *z80, Z80Word addr); +static const char *Disassemble(Z80Word *addr); /* ---------------------------------------- SIGNALS @@ -176,7 +183,7 @@ static void DisplayState(void) Log("I=%2.2x IM=%2.2x R=%2.2x ",s.I,s.IM,s.R); Log("IFF1=%2.2x IFF2=%2.2x\n",s.IFF1,s.IFF2); Log("%4.4x: ",s.PC); - Log("%s\n",Z80Disassemble(z80,&s.PC)); + Log("%s\n",Disassemble(&s.PC)); } @@ -195,12 +202,12 @@ static int StrEq(const char *a, const char *b) } -static int Expand(void *client, const char *p, long *res) +static int Expand(const char *p, long *res) { Z80State s; int ok=TRUE; - Z80GetState((Z80 *)client,&s); + Z80GetState(z80,&s); if (StrEq(p,"AF")) *res=s.AF; @@ -280,21 +287,21 @@ static int Expand(void *client, const char *p, long *res) n=Address(p+1); *res=MK(mem[n+1],mem[n]); } - else /* Check for labels */ + else /* Check for labels */ { - int f; - - ok=FALSE; - - for(f=0;label && label[f].label;f++) - { - if (StrEq(p,label[f].label)) - { - *res=label[f].address; - ok=TRUE; - break; - } - } + int f; + + ok=FALSE; + + for(f=0;label && label[f].label;f++) + { + if (StrEq(p,label[f].label)) + { + *res=label[f].address; + ok=TRUE; + break; + } + } } return ok; @@ -305,19 +312,29 @@ static Z80Word Address(const char *p) { long e=0; - if (!ExprEval(p,&e,Expand,z80)) - Log("%s\n",ExprError()); + if (!Expand(p,&e)) + { + e=strtol(p,NULL,0); + } return (Z80Word)e; } +static const char *Disassemble(Z80Word *addr) +{ + return Z80Disassemble(z80,addr); +} + + static Z80Val Val(const char *p) { long e=0; - if (!ExprEval(p,&e,Expand,z80)) - Log("%s\n",ExprError()); + if (!Expand(p,&e)) + { + e=strtol(p,NULL,0); + } return (Z80Val)e; } @@ -527,7 +544,7 @@ static void DoDis(int no, const char *arg[]) if ((l=GetLabel(z80,orig))) Log("*** %s ***\n",l); - Log("%4.4x: %s\n",orig,Z80Disassemble(z80,&addr)); + Log("%4.4x: %s\n",orig,Disassemble(&addr)); prev=len; len-=(addr-orig); } @@ -707,6 +724,8 @@ static void DoRun(int no, const char *arg[]) static void DoUntil(int no, const char *arg[]) { + Log("No supported\n"); +#if 0 if (no<2) { Log("Missing arguments\n"); @@ -744,6 +763,7 @@ static void DoUntil(int no, const char *arg[]) } stop=FALSE; +#endif } @@ -766,16 +786,23 @@ static void DoSilent(int no, const char *arg[]) static void DoRange(int no, const char *arg[]) { + int f; + if (no<3) { Log("Missing arguments\n"); return; } - bottom=Address(arg[1]); - top=Address(arg[2]); + bottom=(Address(arg[1]))/256; + top=Address(arg[2])/256; + + for(f=0;f<256;f++) + { + memctl[f]=(f>=bottom && f<=top); + } - Log("Writable memory between 0x%4.4x and 0x%4.4x\n",bottom,top); + Log("Writable memory between 0x%4.4x and 0x%4.4x\n",bottom*256,top*256); } @@ -921,77 +948,6 @@ static void Run(char *cmd) /* ---------------------------------------- MEMORY */ -static Z80Byte ReadMem(Z80 *z80, Z80Word addr) -{ - if (mem_trace) - Log("PEEK(0x%4.4x)=0x%2.2x\n",addr,mem[addr]); - - return mem[addr]; -} - - -static Z80Word ReadMemWord(Z80 *z80, Z80Word addr) -{ - Z80Word w; - - w=MK(mem[addr+1],mem[addr]); - - if (mem_trace) - Log("PEEKW(0x%4.4x)=0x%4.4x\n",addr,w); - - return w; -} - - -static Z80Byte ReadMemDis(Z80 *z80, Z80Word addr) -{ - return mem[addr]; -} - - -static void WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) -{ - if (addr>=bottom && addr<=top) - { - mem[addr]=val; - - if (mem_trace) - Log("POKE(0x%4.4x)=0x%2.2x\n",addr,mem[addr]); - } - else - { - if (mem_trace) - Log("POKE(0x%4.4x)=0x%2.2x [BLOCKED]\n",addr,mem[addr]); - } -} - - -static void WriteMemWord(Z80 *z80, Z80Word addr, Z80Word val) -{ - static const char *block_str[3]={""," [ONE BYTE BLOCKED]"," [BLOCKED]"}; - Z80Byte lo,hi; - int block=0; - - lo=LO(val); - hi=HI(val); - - if (addr>=bottom && addr<=top) - mem[addr]=lo; - else - block++; - - addr++; - - if (addr>=bottom && addr<=top) - mem[addr]=hi; - else - block++; - - if (mem_trace) - Log("POKEW(0x%4.4x)=0x%4.4x%s\n",addr,val,block_str[block]); -} - - static Z80Byte ReadPort(Z80 *z80, Z80Word addr) { Z80Byte b=0xff; @@ -1131,9 +1087,11 @@ int main(int argc, char *argv[]) { const char *autoarg[2]={".","auto"}; char buff[1024]; + int f; + + for(f=0;f<256;f++) memctl[f]=1; - z80=Z80Init(WriteMem,ReadMem,WriteMemWord,ReadMemWord, - WritePort,ReadPort,ReadMemDis); + z80=Z80Init(mem,memctl,WritePort,ReadPort); if (!z80) { @@ -0,0 +1,4 @@ +i emucpm.hex +l zexall.com 0x100 +s +r 0x100 @@ -0,0 +1,4 @@ +i emucpm.hex +l zexdoc.com 0x100 +s +r 0x100 diff --git a/runprelim b/runprelim new file mode 100644 index 0000000..609efd3 --- /dev/null +++ b/runprelim @@ -0,0 +1,4 @@ +i emucpm.hex +l prelim.com 0x100 +s +r 0x100 @@ -28,19 +28,14 @@ Z80 */ +#include <stdlib.h> + #include "z80.h" #include "z80_private.h" static const char ident[]="$Id$"; - - -/* ---------------------------------------- LIBRARY VARIABLES -*/ -static Z80Byte PSZtable[512]; -static Z80Byte SZtable[512]; -static Z80Byte Ptable[512]; -static Z80Byte Stable[512]; -static Z80Byte Ztable[512]; +static const char ident_z80_header[]=Z80_H; +static const char ident_z80_private_header[]=Z80_PRIVATE_H; /* ---------------------------------------- PRIVATE FUNCTIONS @@ -48,54 +43,13 @@ static Z80Byte Ztable[512]; static void InitTables() { static int init=FALSE; - Z80Reg r; - Z80Word f; if (init) return; init=TRUE; - /* 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; - } + Z80_InitialiseInternals(); } static void Z80_CheckInterrupt(Z80 *cpu) @@ -116,7 +70,7 @@ static void Z80_CheckInterrupt(Z80 *cpu) TSTATE(2); cpu->IFF1=0; cpu->nmi=FALSE; - PUSH(PC); + PUSH(cpu->PC); cpu->PC=0x66; } else if (cpu->IFF1) @@ -140,12 +94,12 @@ static void Z80_CheckInterrupt(Z80 *cpu) break; case 1: - PUSH(PC); + PUSH(cpu->PC); cpu->PC=0x38; break; case 2: - PUSH(PC); + PUSH(cpu->PC); cpu->PC=(Z80Word)cpu->I*256+cpu->devbyte; break; } @@ -170,7 +124,7 @@ Z80 *Z80Init(Z80Memory memory, InitTables(); - if (!write_byte || !read_byte || !write_word || !read_word) + if (!memory || !memcontrol) return NULL; cpu=malloc(sizeof *cpu); @@ -198,18 +152,17 @@ void Z80Reset(Z80 *cpu) cpu->cycle=0; cpu->PC=0; - cpu->A=0xff; - cpu->F=0xff; - cpu->BC=0xffff; - cpu->DE=0xffff; - cpu->HL=0xffff; - cpu->AF_=0xffff; - cpu->BC_=0xffff; - cpu->DE_=0xffff; - cpu->HL_=0xffff; + cpu->AF.w=0xffff; + cpu->BC.w=0xffff; + cpu->DE.w=0xffff; + cpu->HL.w=0xffff; + cpu->AF_.w=0xffff; + cpu->BC_.w=0xffff; + cpu->DE_.w=0xffff; + cpu->HL_.w=0xffff; - cpu->IX=0xffff; - cpu->IY=0xffff; + cpu->IX.w=0xffff; + cpu->IY.w=0xffff; cpu->SP=0xffff; cpu->IFF1=0; @@ -297,66 +250,57 @@ void Z80Exec(Z80 *cpu) void Z80GetState(Z80 *cpu, Z80State *state) { -#define COPY(a) state->a=cpu->a - COPY(cycle); + state->cycle= cpu->cycle; - SET_HI(state->AF,cpu->A); - SET_LO(state->AF,cpu->F); + state->AF = cpu->AF.w; + state->BC = cpu->BC.w; + state->DE = cpu->DE.w; + state->HL = cpu->HL.w; - COPY(BC); - COPY(DE); - COPY(HL); + state->AF_ = cpu->AF_.w; + state->BC_ = cpu->BC_.w; + state->DE_ = cpu->DE_.w; + state->HL_ = cpu->HL_.w; - COPY(AF_); - COPY(BC_); - COPY(DE_); - COPY(HL_); + state->IX = cpu->IX.w; + state->IY = cpu->IY.w; - COPY(IX); - COPY(IY); + state->SP = cpu->SP; + state->PC = cpu->PC; - COPY(SP); - COPY(PC); - - COPY(IFF1); - COPY(IFF2); - COPY(IM); - COPY(I); - COPY(R); -#undef COPY + state->IFF1 = cpu->IFF1; + state->IFF2 = cpu->IFF2; + state->IM = cpu->IM; + state->I = cpu->I; + state->R = cpu->R; } -void Z80SetState(Z80 *cpu, Z80State *state) +void Z80SetState(Z80 *cpu, const Z80State *state) { -#define COPY(a) cpu->a=state->a - COPY(cycle); - - cpu->A=GET_HI(state->AF); - cpu->F=GET_LO(state->AF); - - COPY(AF); - COPY(BC); - COPY(DE); - COPY(HL); - - COPY(AF_); - COPY(BC_); - COPY(DE_); - COPY(HL_); - - COPY(IX); - COPY(IY); - - COPY(SP); - COPY(PC); - - COPY(IFF1); - COPY(IFF2); - COPY(IM); - COPY(I); - COPY(R); -#undef COPY + cpu->cycle = state->cycle; + + cpu->AF.w = state->AF; + cpu->BC.w = state->BC; + cpu->DE.w = state->DE; + cpu->HL.w = state->HL; + + cpu->AF_.w = state->AF_; + cpu->BC_.w = state->BC_; + cpu->DE_.w = state->DE_; + cpu->HL_.w = state->HL_; + + cpu->IX.w = state->IX; + cpu->IY.w = state->IY; + + cpu->SP = state->SP; + cpu->PC = state->PC; + + cpu->IFF1 = state->IFF1; + cpu->IFF2 = state->IFF2; + cpu->IM = state->IM; + cpu->I = state->I; + cpu->R = state->R; } @@ -365,4 +309,16 @@ Z80Val Z80Cycles(Z80 *cpu) return cpu->cycle; } + +const char *Z80Disassemble(Z80 *cpu, Z80Word *addr) +{ +#ifdef Z80_DISASSEMBLER_ENABLED + (*addr)+=4; + return "NO DISASSEMBLER"; +#else + (*addr)+=4; + return "NO DISASSEMBLER"; +#endif +} + /* END OF FILE */ @@ -33,6 +33,10 @@ /* ---------------------------------------- TYPES */ +/* Remove this to disable the disassembler (saving some memory) +*/ +#define Z80_DISASSEMBLER_ENABLED + /* The processor */ struct Z80; @@ -213,6 +217,11 @@ Z80Val Z80Cycles(Z80 *cpu); void Z80GetState(Z80 *cpu, Z80State *state); void Z80SetState(Z80 *cpu, const Z80State *state); + +/* Simple disassembly. addr is updated on exit. +*/ +const char *Z80Disassemble(Z80 *cpu, Z80Word *addr); + #endif /* END OF FILE */ diff --git a/z80_decode.c b/z80_decode.c index c323d1f..6bb34f5 100644 --- a/z80_decode.c +++ b/z80_decode.c @@ -28,1549 +28,2064 @@ Z80 */ -#include "z80_private.h" +#include <stdlib.h> -/* ---------------------------------------- ARITHMETIC OPS -*/ -#define ADD_8_BIT(REG,VAL) \ -do \ -{ \ - Z80Word w; \ - w=REG+(Z80Word)VAL; \ - cpu->F=SZtable[w]; \ - if ((REG^w^VAL)&H_Z80) cpu->F|=H_Z80; \ - if ((VAL^REG^0x80)&(REG^w)&0x80) cpu->F|=P_Z80; \ - SETHIDDEN(w); \ - REG=w; \ -} while(0) - - -#define ADC_8_BIT(REG,VAL) \ -do \ -{ \ - Z80Word w; \ - w=(REG+(Z80Word)VAL+CARRY)&0x1ff; \ - cpu->F=SZtable[w]; \ - if ((REG^w^VAL)&H_Z80) cpu->F|=H_Z80; \ - if ((VAL^REG^0x80)&(REG^w)&0x80) cpu->F|=P_Z80; \ - SETHIDDEN(w); \ - REG=w; \ -} while(0) - - -#define SUB_8_BIT(REG,VAL) \ -do \ -{ \ - Z80Word w; \ - w=(REG-(Z80Word)VAL)&0x1ff; \ - cpu->F=SZtable[w]|N_Z80; \ - if ((REG^w^VAL)&H_Z80) cpu->F|=H_Z80; \ - if ((VAL^REG^0x80)&(REG^w)&0x80) cpu->F|=P_Z80; \ - SETHIDDEN(w); \ - REG=w; \ -} while(0) - - -#define CMP_8_BIT(REG,VAL) \ -do \ -{ \ - Z80Word w; \ - w=(REG-(Z80Word)VAL)&0x1ff; \ - cpu->F=SZtable[w]|N_Z80; \ - if ((REG^w^VAL)&H_Z80) cpu->F|=H_Z80; \ - if ((VAL^REG^0x80)&(REG^w)&0x80) cpu->F|=P_Z80; \ - SETHIDDEN(VAL); \ -} while(0) - - -#define SBC_8_BIT(REG,VAL) \ -do \ -{ \ - Z80Word w; \ - w=(REG-(Z80Word)VAL-CARRY)&0x1ff; \ - cpu->F=SZtable[w]|N_Z80; \ - if ((REG^w^VAL)&H_Z80) cpu->F|=H_Z80; \ - if ((VAL^REG^0x80)&(REG^w)&0x80) cpu->F|=P_Z80; \ - SETHIDDEN(w); \ - REG=w; \ -} while(0) - - -#define ADD_16_BIT(REG,VAL) \ -do \ -{ \ - Z80Val w; \ - w=REG+(Z80Val)VAL; \ - cpu->F&=(S_Z80|Z_Z80|V_Z80); \ - if (w>0xffff) cpu->F|=C_Z80; \ - if ((REG^w^VAL)&0x1000) cpu->F|=H_Z80; \ - SETHIDDEN(w>>8); \ - REG=w; \ -} while(0) - - -#define ADC_16_BIT(REG,VAL) \ -do \ -{ \ - Z80Val w; \ - w=REG+(Z80Val)VAL+CARRY; \ - cpu->F&=(S_Z80|Z_Z80|V_Z80); \ - if (w>0xffff) cpu->F|=C_Z80; \ - if ((REG^w^VAL)&0x1000) cpu->F|=H_Z80; \ - SETHIDDEN(w>>8); \ - REG=w; \ -} while(0) - - -#define SBC_16_BIT(REG,VAL) \ -do \ -{ \ - Z80Val w; \ - w=REG-(Z80Val)VAL-CARRY; \ - cpu->F=N_Z80; \ - if (w&0x8000) cpu->F|=S_Z80; \ - if ((w&0xffff)==0) cpu->F|=Z_Z80; \ - if (w>0xffff) cpu->F|=C_Z80; \ - if ((REG^w^VAL)&0x1000) cpu->F|=H_Z80; \ - if ((VAL^REG)&(VAL^w)&0x8000) cpu->F|=P_Z80; \ - SETHIDDEN(w>>8); \ - REG=w; \ -} while(0) - - -#define INC8(REG) \ -do \ -{ \ - REG++; \ - cpu->F=CARRY|SZtable[REG]; \ - if (w&0x80) cpu->F|=P_Z80; \ - if (w&0x0f) cpu->F|=H_Z80; \ -} while(0) - - -#define DEC8(REG) \ -do \ -{ \ - cpu->F=N_Z80|CARRY; \ - if (w&0x80) cpu->F|=P_Z80; \ - if (w&0x0f) cpu->F|=H_Z80; \ - REG--; \ - cpu->F|=SZtable[REG]; \ -} while(0) +#include "z80.h" +#include "z80_private.h" +static const char ident[]="$Id$"; -/* ---------------------------------------- ROTATE AND SHIFT OPS +/* ---------------------------------------- TABLES AND INIT */ -#define RRCA \ -do \ -{ \ - cpu->F=(cpu->F&0xec)|cpu->A&C_Z80; \ - cpu->A=(cpu->A>>1)|(cpu->A<<7); \ - SETHIDDEN(cpu->A); \ -} while(0) - - -#define RRA \ -do \ -{ \ - Z80Byte c; \ - c=CARRY; \ - cpu->F=(cpu->F&0xec)|cpu->A&C_Z80; \ - cpu->A=(cpu->A>>1)|(c<<7); \ - SETHIDDEN(cpu->A); \ -} while(0) - - -#define RRC(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG&C_Z80; \ - REG=(REG>>1)|(REG<<7); \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define RR(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG&C_Z80; \ - REG=(REG>>1)|(CARRY<<7); \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define RLCA \ -do \ -{ \ - cpu->F=(cpu->F&0xec)|(cpu->A>>7); \ - cpu->A=(cpu->A<<1)|(cpu->A>>7); \ - SETHIDDEN(cpu->A); \ -} while(0) - - -#define RLA \ -do \ -{ \ - Z80Byte c; \ - c=CARRY; \ - cpu->F=(cpu->F&0xec)|(cpu->A>>7); \ - cpu->A=(cpu->A<<1)|c; \ - SETHIDDEN(cpu->A); \ -} while(0) - - -#define RLC(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG>>7; \ - REG=(REG<<1)|c; \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define RL(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG>>7; \ - REG=(REG<<1)|CARRY; \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define SRL(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG&Z80_C; \ - REG>>=1; \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define SRA(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG&Z80_C; \ - REG=(REG>>1)|(REG&0x80); \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define SLL(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG>>7; \ - REG=(REG<<1)|1; \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -#define SLA(REG) \ -do \ -{ \ - Z80Byte c; \ - c=REG>>7; \ - REG=REG<<1; \ - cpu->F=PSZtable[REG]|c; \ - SETHIDDEN(REG); \ -} while(0) - - -/* ---------------------------------------- FLOW OPS +static const unsigned char partab[256] = { + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, +}; + +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; + +/* ---------------------------------------- PRIVATE FUNCTIONS */ -#define CALL(COND) \ -do \ -{ \ - if (COND) \ - { \ - PUSH(cpu->PC+2); \ - cpu->PC=PEEKW(cpu->PC); \ - } \ - else \ - { \ - cpu->PC+=2; \ - } \ -} \ -while(0) - - -#define JP(COND) \ -do \ -{ \ - if (COND) \ - { \ - cpu->PC=PEEKW(cpu->PC); \ - } \ - else \ - { \ - cpu->PC+=2; \ - } \ -} \ -while(0) - - -#define JR(COND) \ -do \ -{ \ - if (COND) \ - { \ - cpu->PC+=(Z80Relative)PEEK(cpu->PC)+1; \ - } \ - else \ - { \ - cpu->PC++; \ - } \ -} \ -while(0) +void Z80_InitialiseInternals(void) +{ + Z80Word f; + Z80Reg r; + r.w=0x1234; -/* ---------------------------------------- BOOLEAN OPS -*/ -#define AND(REG,VAL) \ -do \ -{ \ - REG&=VAL; \ - cpu->F=PSZtable[REG]|H_Z80; \ - SETHIDDEN(REG); \ -} while(0) - - -#define OR(REG,VAL) \ -do \ -{ \ - REG|=VAL; \ - cpu->F=PSZtable[REG]; \ - SETHIDDEN(REG); \ -} while(0) - - -#define XOR(REG,VAL) \ -do \ -{ \ - REG^=VAL; \ - cpu->F=PSZtable[REG]; \ - SETHIDDEN(REG); \ -} while(0) - - -#define BIT(REG,B) \ -do \ -{ \ - cpu->F=CARRY|H_Z80; \ - if (REG&&(1<<B)) \ - { \ - if (B==7) cpu->F|=S_Z80; \ - if (B==5) cpu->F|=B5_Z80; \ - if (B==3) cpu->F|=B3_Z80; \ - } \ - else \ - { \ - cpu->F|=Z_Z80; \ - } \ -} while(0) + if (r.b[0] == 0x12) + { + HI=0; + LO=1; + } + else if (r.b[1] == 0x12) + { + HI=1; + LO=0; + } + else + { + exit(1); + } + /* 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; + } +} -/* ---------------------------------------- GENERAL MACROS -*/ -/* Decides whether the offset for IX/IY should be fetched, or used - from the store for a CB instruction +/* ---------------------------------------- ARITHMETIC OPS */ -#define GETREL (cpu->use_cb_off ? cpu->cb_off : (Z80Relative)FETCH_BYTE) +static void ADD8(Z80 *cpu, Z80Byte VAL) +{ + Z80Word w; + w=cpu->AF.b[HI]+(Z80Word)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)&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; + SETHIDDEN(w); + cpu->AF.b[HI]=w; +} -/* ---------------------------------------- GENERAL UTILS -*/ +static void ADC8(Z80 *cpu, Z80Byte VAL) +{ + Z80Word w; + w=(cpu->AF.b[HI]+(Z80Word)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)&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; + SETHIDDEN(w); + cpu->AF.b[HI]=w; +} -/* This code based on the DAA opcode from YAZE, (c) Frank D. Cringle -*/ -static void DAA (Z80 *cpu) + +static void SUB8(Z80 *cpu, Z80Byte VAL) { - Z80Word AF; - Z80Word acu,temp,cbits; + Z80Word w; + w=(cpu->AF.b[HI]-(Z80Word)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]^0x80)&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; + SETHIDDEN(w); + cpu->AF.b[HI]=w; +} - AF=(Z80Word)cpu->A<<8|cpu->F; - acu=cpu->A; - temp=acu&0xf; - cbits=CARRY; - if (IS_N) /* last operation was a subtract */ - { - int hd = cbits || acu > 0x99; - if (IS_H || (temp > 9)) /* adjust low digit */ - { - if (temp > 5) - { - CLR(AF,H_Z80); - } +static void CMP8(Z80 *cpu, Z80Byte VAL) +{ + Z80Word w; + w=(cpu->AF.b[HI]-(Z80Word)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]^0x80)&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; + SETHIDDEN(VAL); +} - acu -= 6; - acu &= 0xff; - } - if (hd) /* adjust high digit */ - acu -= 0x160; - } - else /* last operation was an add */ - { - if (IS_H || (temp > 9)) /* adjust low digit */ - { - if (temp>9) - { - SET(AF,H_Z80); - } - else - { - CLR(AF,H_Z80); - } - acu += 6; - } - if (cbits || ((acu & 0x1f0) > 0x90)) /* adjust high digit */ - acu += 0x60; - } - cbits |= (acu >> 8) & 1; - acu &= 0xff; - AF = (acu << 8) | (acu & 0xa8) | ((acu == 0) << 6) | - (AF & 0x12) | partab[acu] | cbits; +static void SBC8(Z80 *cpu, Z80Byte VAL) +{ + Z80Word w; + w=(cpu->AF.b[HI]-(Z80Word)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]^0x80)&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; + SETHIDDEN(w); + cpu->AF.b[HI]=w; +} + + +static Z80Word ADD16(Z80 *cpu, Z80Word REG, Z80Word VAL) +{ + 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); + return w; +} + - cpu->A=(AF>>8); - cpu->F=(AF&0xff); - SETHIDDEN(cpu->A); +static Z80Word ADC16(Z80 *cpu, Z80Word REG, Z80Word VAL) +{ + Z80Val w; + w=REG+(Z80Val)VAL+CARRY; + 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); + return w; +} + + +static Z80Word SBC16(Z80 *cpu, Z80Word REG, Z80Word VAL) +{ + 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 ((REG^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; + if ((VAL^REG)&(VAL^w)&0x8000) cpu->AF.b[LO]|=P_Z80; + SETHIDDEN(w>>8); + return w; } +static Z80Byte INC8(Z80 *cpu, Z80Byte REG) +{ + REG++; + cpu->AF.b[LO]=CARRY|SZtable[REG]; + if (REG&0x80) cpu->AF.b[LO]|=P_Z80; + if (REG&0x0f) cpu->AF.b[LO]|=H_Z80; + return REG; +} -/* ---------------------------------------- HANDLERS FOR CB OPCODES + +static Z80Byte DEC8(Z80 *cpu, Z80Byte REG) +{ + cpu->AF.b[LO]=N_Z80|CARRY; + if (REG&0x80) cpu->AF.b[LO]|=P_Z80; + if (REG&0x0f) cpu->AF.b[LO]|=H_Z80; + REG--; + cpu->AF.b[LO]|=SZtable[REG]; + return REG; +} + + +/* ---------------------------------------- ROTATE AND SHIFT OPS */ -static void DecodeCB(Z80 *cpu, Z80Byte opcode) +static void RRCA(Z80 *cpu) { - switch(opcode) - { - } + cpu->AF.b[LO]=(cpu->AF.b[LO]&0xec)|(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]); +} - Z80Byte bmh,bmm,bml; - /* Split up the opcode into it's bitmasks - */ - bmh=(opcode>>6)&3; - bmm=(opcode>>3)&7; - bml=opcode&7; +static void RRA(Z80 *cpu) +{ + Z80Byte c; + c=CARRY; + cpu->AF.b[LO]=(cpu->AF.b[LO]&0xec)|(cpu->AF.b[HI]&C_Z80); + cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(c<<7); + SETHIDDEN(cpu->AF.b[HI]); +} - /* Instruction set 00 - */ - if (bmh==0x00) - { - CBOp_00(cpu,opcode,bmh,bmm,bml); - return; - } - /* Instruction set 01 (BIT) - */ - if (bmh==0x01) - { - CBOp_01(cpu,opcode,bmh,bmm,bml); - return; - } +static Z80Byte RRC(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG&C_Z80; + REG=(REG>>1)|(REG<<7); + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} - /* Instruction set 10 (RES) and 11 (SET) - */ - CBOp_ResSet(cpu,opcode,bmh,bmm,bml); + +static Z80Byte RR(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG&C_Z80; + REG=(REG>>1)|(CARRY<<7); + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; } +static void RLCA(Z80 *cpu) +{ + cpu->AF.b[LO]=(cpu->AF.b[LO]&0xec)|(cpu->AF.b[HI]>>7); + cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|(cpu->AF.b[HI]>>7); + SETHIDDEN(cpu->AF.b[HI]); +} + + +static void RLA(Z80 *cpu) +{ + Z80Byte c; + c=CARRY; + cpu->AF.b[LO]=(cpu->AF.b[LO]&0xec)|(cpu->AF.b[HI]>>7); + cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|c; + SETHIDDEN(cpu->AF.b[HI]); +} -/* ---------------------------------------- OPCODE DECODER +static Z80Byte RLC(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG>>7; + REG=(REG<<1)|c; + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} + + +static Z80Byte RL(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG>>7; + REG=(REG<<1)|CARRY; + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} + + +static Z80Byte SRL(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG&C_Z80; + REG>>=1; + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} + + +static Z80Byte SRA(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG&C_Z80; + REG=(REG>>1)|(REG&0x80); + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} + + +static Z80Byte SLL(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG>>7; + REG=(REG<<1)|1; + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} + + +static Z80Byte SLA(Z80 *cpu, Z80Byte REG) +{ + Z80Byte c; + c=REG>>7; + REG=REG<<1; + cpu->AF.b[LO]=PSZtable[REG]|c; + SETHIDDEN(REG); + return REG; +} + + +/* ---------------------------------------- BOOLEAN OPS */ -void Z80_Decode(Z80 *cpu, Z80Byte opcode) +static void AND(Z80 *cpu, Z80Byte VAL) { - Z80Byte bmh,bmm,bml; + cpu->AF.b[HI]&=VAL; + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]|H_Z80; + SETHIDDEN(cpu->AF.b[HI]); +} - /* IX/IY shifts - */ - if (opcode==0xdd || opcode==0xfd) - { - TSTATE(4); - INC_R; - cpu->shift=opcode; - Z80_Decode(cpu,FETCH_BYTE); - return; - } +static void OR(Z80 *cpu, Z80Byte VAL) +{ + cpu->AF.b[HI]|=VAL; + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); +} - /* CB shifts - */ - if (opcode==0xcb) - { - INC_R; - /* Check for previous IX/IY shift. - */ - if (cpu->shift!=0) - { - cpu->use_cb_off=TRUE; - cpu->cb_off=(Z80Relative)FETCH_BYTE; - } +static void XOR(Z80* cpu, Z80Byte VAL) +{ + cpu->AF.b[HI]^=VAL; + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); +} - DecodeCB(cpu,FETCH_BYTE); - return; - } - /* DE shifts - */ - if (opcode==0xed) +static void BIT(Z80 *cpu, Z80Byte REG, Z80Byte B) +{ + cpu->AF.b[LO]=CARRY|H_Z80; + if (REG&&(1<<B)) { - INC_R; - DecodeED(cpu,FETCH_BYTE); - return; + if (B==7) cpu->AF.b[LO]|=S_Z80; + if (B==5) cpu->AF.b[LO]|=B5_Z80; + if (B==3) cpu->AF.b[LO]|=B3_Z80; } + else + { + cpu->AF.b[LO]|=Z_Z80; + } +} - *** NEW *** - INC_R; +/* ---------------------------------------- BLOCK OPERATIONS +*/ +static void LDI(Z80 *cpu) +{ + Z80Byte b; - switch(opcode) - { - case 0x00: /* NOP */ - TSTATE(4); - break; + b=PEEK(cpu->HL.w); + POKE(cpu->DE.w,b); + cpu->DE.w++; + cpu->HL.w++; + cpu->BC.w--; - case 0x01: /* LD BC, nnnn */ - TSTATE(10); - cpu->BC=FETCH_WORD; - break; + CLRFLAG(H_Z80); + CLRFLAG(N_Z80); - case 0x02: - TSTATE(7); - break; + if (cpu->BC.w) + SETFLAG(P_Z80); + else + CLRFLAG(P_Z80); - case 0x03: - TSTATE(4); - break; + SETHIDDEN(cpu->AF.b[HI]+b); +} - case 0x04: - TSTATE(4); - break; +static void LDD(Z80 *cpu) +{ + Z80Byte b; - case 0x05: - TSTATE(4); - break; + b=PEEK(cpu->HL.w); + POKE(cpu->DE.w,b); + cpu->DE.w--; + cpu->HL.w--; + cpu->BC.w--; - case 0x06: - TSTATE(4); - break; + CLRFLAG(H_Z80); + CLRFLAG(N_Z80); - case 0x07: - TSTATE(4); - break; + if (cpu->BC.w) + SETFLAG(P_Z80); + else + CLRFLAG(P_Z80); - case 0x08: - TSTATE(4); - break; + SETHIDDEN(cpu->AF.b[HI]+b); +} - case 0x09: - TSTATE(4); - break; +static void CPI(Z80 *cpu) +{ + Z80Byte c,b; - case 0x0a: - TSTATE(4); - break; + c=CARRY; + b=PEEK(cpu->HL.w); - case 0x0b: - TSTATE(4); - break; + CMP8(cpu,b); - case 0x0c: - TSTATE(4); - break; + if (c) + SETFLAG(C_Z80); + else + CLRFLAG(C_Z80); - case 0x0d: - TSTATE(4); - break; + cpu->HL.w++; + cpu->BC.w--; - case 0x0e: - TSTATE(4); - break; + if (cpu->BC.w) + SETFLAG(P_Z80); + else + CLRFLAG(P_Z80); +} - case 0x0f: - TSTATE(4); - break; +static void CPD(Z80 *cpu) +{ + Z80Byte c,b; - case 0x10: - TSTATE(4); - break; + c=CARRY; + b=PEEK(cpu->HL.w); - case 0x11: - TSTATE(4); - break; + CMP8(cpu,b); - case 0x12: - TSTATE(4); - break; + if (c) + SETFLAG(C_Z80); + else + CLRFLAG(C_Z80); - case 0x13: - TSTATE(4); - break; + cpu->HL.w--; + cpu->BC.w--; - case 0x14: - TSTATE(4); - break; + if (cpu->BC.w) + SETFLAG(P_Z80); + else + CLRFLAG(P_Z80); +} - case 0x15: - TSTATE(4); - break; +static void INI(Z80 *cpu) +{ + Z80Word w; + Z80Byte b; - case 0x16: - TSTATE(4); - break; + b=IN(cpu->BC.w); + POKE(cpu->HL.w,b); - case 0x17: - TSTATE(4); - break; + cpu->BC.b[HI]--; + cpu->HL.w++; - case 0x18: - TSTATE(4); - break; + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; + SETHIDDEN(cpu->BC.b[HI]); - case 0x19: - TSTATE(4); - break; + w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; - case 0x1a: - TSTATE(4); - break; + if (b&0x80) + SETFLAG(N_Z80); - case 0x1b: - TSTATE(4); - break; + if (w&0x100) + { + SETFLAG(C_Z80); + SETFLAG(H_Z80); + } + else + { + CLRFLAG(C_Z80); + CLRFLAG(H_Z80); + } +} - case 0x1c: - TSTATE(4); - break; +static void IND(Z80 *cpu) +{ + Z80Word w; + Z80Byte b; - case 0x1d: - TSTATE(4); - break; + b=IN(cpu->BC.w); + POKE(cpu->HL.w,b); - case 0x1e: - TSTATE(4); - break; + cpu->BC.b[HI]--; + cpu->HL.w--; - case 0x1f: - TSTATE(4); - break; + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; + SETHIDDEN(cpu->BC.b[HI]); - case 0x20: - TSTATE(4); - break; + w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; - case 0x21: - TSTATE(4); - break; + if (b&0x80) + SETFLAG(N_Z80); - case 0x22: - TSTATE(4); - break; + if (w&0x100) + { + SETFLAG(C_Z80); + SETFLAG(H_Z80); + } + else + { + CLRFLAG(C_Z80); + CLRFLAG(H_Z80); + } +} - case 0x23: - TSTATE(4); - break; +static void OUTI(Z80 *cpu) +{ + OUT(cpu->BC.w,PEEK(cpu->HL.w)); - case 0x24: - TSTATE(4); - break; + cpu->HL.w++; + cpu->BC.b[HI]--; - case 0x25: - TSTATE(4); - break; + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; + SETHIDDEN(cpu->BC.b[HI]); +} - case 0x26: - TSTATE(4); - break; +static void OUTD(Z80 *cpu) +{ + OUT(cpu->BC.w,PEEK(cpu->HL.w)); - case 0x27: - TSTATE(4); - break; + cpu->HL.w--; + cpu->BC.b[HI]--; - case 0x28: - TSTATE(4); - break; + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; + SETFLAG(N_Z80); + SETHIDDEN(cpu->BC.b[HI]); +} - case 0x29: - TSTATE(4); - break; - case 0x2a: - TSTATE(4); - break; - case 0x2b: - TSTATE(4); - break; +/* ---------------------------------------- GENERAL MACROS +*/ - case 0x2c: - TSTATE(4); - break; +/* Decides whether the offset for IX/IY should be fetched, or used + from the store for a CB instruction +*/ +#define GETREL (cpu->use_cb_off ? cpu->cb_off : (Z80Relative)FETCH_BYTE) - case 0x2d: - TSTATE(4); - break; - case 0x2e: - TSTATE(4); - break; +/* ---------------------------------------- DAA +*/ - case 0x2f: - TSTATE(4); - break; +/* This code based on the DAA opcode from YAZE, (c) Frank D. Cringle +*/ +static void DAA (Z80 *cpu) +{ + Z80Word AF,acu,temp,cbits; - case 0x30: - TSTATE(4); - break; + AF=cpu->AF.w; + acu=cpu->AF.b[HI]; + temp=acu&0xf; + cbits=CARRY; - case 0x31: - TSTATE(4); - break; + if (IS_N) /* last operation was a subtract */ + { + int hd = cbits || acu > 0x99; + if (IS_H || (temp > 9)) /* adjust low digit */ + { + if (temp > 5) + { + CLR(AF,H_Z80); + } - case 0x32: - TSTATE(4); - break; + acu -= 6; + acu &= 0xff; + } + if (hd) /* adjust high digit */ + acu -= 0x160; + } + else /* last operation was an add */ + { + if (IS_H || (temp > 9)) /* adjust low digit */ + { + if (temp>9) + { + SET(AF,H_Z80); + } + else + { + CLR(AF,H_Z80); + } + acu += 6; + } + if (cbits || ((acu & 0x1f0) > 0x90)) /* adjust high digit */ + acu += 0x60; + } - case 0x33: - TSTATE(4); - break; + cbits |= (acu >> 8) & 1; + acu &= 0xff; + AF = (acu << 8) | (acu & 0xa8) | ((acu == 0) << 6) | + (AF & 0x12) | partab[acu] | cbits; - case 0x34: - TSTATE(4); - break; + cpu->AF.w=AF; + SETHIDDEN(cpu->AF.b[HI]); +} - case 0x35: - TSTATE(4); - break; - case 0x36: - TSTATE(4); - break; +/* ---------------------------------------- DECODE AND REGISTER SELECTION +*/ - case 0x37: - TSTATE(4); - break; +/* Get the 16 bit register to use according to the bitmask +*/ +static Z80Word *Get16(Z80 *cpu, Z80Byte bm) +{ + if (bm==0x00) + return &cpu->BC.w; - case 0x38: - TSTATE(4); - break; + if (bm==0x01) + return &cpu->DE.w; - case 0x39: - TSTATE(4); - break; + if (bm==0x02) + { + if (cpu->shift==0xdd) + return &cpu->IX.w; - case 0x3a: - TSTATE(4); - break; + if (cpu->shift==0xfd) + return &cpu->IY.w; - case 0x3b: - TSTATE(4); - break; + return &cpu->HL.w; + } - case 0x3c: - TSTATE(4); - break; + return &cpu->SP; +} - case 0x3d: - TSTATE(4); - break; - case 0x3e: - TSTATE(4); - break; +/* Get the 16 bit register to use according to the bitmask, ignoring the shift +*/ +static Z80Word *Get16_HL(Z80 *cpu, Z80Byte bm) +{ + if (bm==0x00) + return &cpu->BC.w; - case 0x3f: - TSTATE(4); - break; + if (bm==0x01) + return &cpu->DE.w; - case 0x40: - TSTATE(4); - break; + if (bm==0x02) + return &cpu->HL.w; - case 0x41: - TSTATE(4); - break; + return &cpu->SP; +} - case 0x42: - TSTATE(4); - break; - case 0x43: - TSTATE(4); - break; +/* Get the 16 bit register to use according to the bitmask, + with AF instead of SP +*/ +static Z80Word *Get16_AF(Z80 *cpu, Z80Byte bm) +{ + if (bm==0x00) + return &cpu->BC.w; - case 0x44: - TSTATE(4); - break; + if (bm==0x01) + return &cpu->DE.w; - case 0x45: - TSTATE(4); - break; + if (bm==0x02) + { + if (cpu->shift==0xdd) + return &cpu->IX.w; - case 0x46: - TSTATE(4); - break; + if (cpu->shift==0xfd) + return &cpu->IY.w; - case 0x47: - TSTATE(4); - break; + return &cpu->HL.w; + } - case 0x48: - TSTATE(4); - break; + return &cpu->AF.w; +} - case 0x49: - TSTATE(4); - break; - case 0x4a: - TSTATE(4); - break; +/* Get the 8 bit register to use according to the bitmask . + Returns NULL for (HL), (I[XY]+d) +*/ +static Z80Byte *Get8(Z80 *cpu, Z80Byte bm) +{ + if (bm==0x07) + return &cpu->AF.b[HI]; - case 0x4b: - TSTATE(4); - break; + if (bm==0x00) + return &cpu->BC.b[HI]; - case 0x4c: - TSTATE(4); - break; + if (bm==0x01) + return &cpu->BC.b[LO]; - case 0x4d: - TSTATE(4); - break; + if (bm==0x02) + return &cpu->DE.b[HI]; - case 0x4e: - TSTATE(4); - break; + if (bm==0x03) + return &cpu->DE.b[LO]; - case 0x4f: - TSTATE(4); - break; + if (bm==0x04) + { + if (cpu->shift==0xdd) + return &cpu->IX.b[HI]; - case 0x50: - TSTATE(4); - break; + if (cpu->shift==0xfd) + return &cpu->IY.b[HI]; - case 0x51: - TSTATE(4); - break; + return &cpu->HL.b[HI]; + } - case 0x52: - TSTATE(4); - break; + if (bm==0x05) + { + if (cpu->shift==0xdd) + return &cpu->IX.b[LO]; - case 0x53: - TSTATE(4); - break; + if (cpu->shift==0xfd) + return &cpu->IY.b[LO]; - case 0x54: - TSTATE(4); - break; + return &cpu->HL.b[LO]; + } - case 0x55: - TSTATE(4); - break; + return NULL; +} - case 0x56: - TSTATE(4); - break; - case 0x57: - TSTATE(4); - break; +/* Get the 8 bit register to use according to the bitmask, ignoring the shift. + Returns NULL for (HL) +*/ +static Z80Byte *Get8_HL(Z80 *cpu, Z80Byte bm) +{ + if (bm==0x07) + return &cpu->AF.b[HI]; - case 0x58: - TSTATE(4); - break; + if (bm==0x00) + return &cpu->BC.b[HI]; - case 0x59: - TSTATE(4); - break; + if (bm==0x01) + return &cpu->BC.b[LO]; - case 0x5a: - TSTATE(4); - break; + if (bm==0x02) + return &cpu->DE.b[HI]; - case 0x5b: - TSTATE(4); - break; + if (bm==0x03) + return &cpu->DE.b[LO]; - case 0x5c: - TSTATE(4); - break; + if (bm==0x04) + return &cpu->HL.b[HI]; - case 0x5d: - TSTATE(4); - break; + if (bm==0x05) + return &cpu->HL.b[LO]; - case 0x5e: - TSTATE(4); - break; + return NULL; +} - case 0x5f: - TSTATE(4); - break; - case 0x60: - TSTATE(4); - break; +/* Get the address pointed to by HL, or the relative one depending on the shift +*/ +static Z80Word GetHL(Z80 *cpu) +{ + if (cpu->shift==0) + return cpu->HL.w; - case 0x61: - TSTATE(4); - break; + if (cpu->shift==0xdd) + { + TSTATE(8); + return cpu->IX.w+GETREL; + } - case 0x62: - TSTATE(4); - break; + if (cpu->shift==0xfd) + { + TSTATE(8); + return cpu->IY.w+GETREL; + } - case 0x63: - TSTATE(4); - break; + return 0; +} - case 0x64: - TSTATE(4); - break; - case 0x65: - TSTATE(4); - break; +/* Get the value of HL, IX, IY depending on the shift +*/ +static Z80Word GetHLVal(Z80 *cpu) +{ + if (cpu->shift==0) + return cpu->HL.w; - case 0x66: - TSTATE(4); - break; + if (cpu->shift==0xdd) + return cpu->IX.w; - case 0x67: - TSTATE(4); - break; + if (cpu->shift==0xfd) + return cpu->IY.w; - case 0x68: - TSTATE(4); - break; + return 0; +} - case 0x69: - TSTATE(4); - break; - case 0x6a: - TSTATE(4); - break; +/* Get the register (HL, IX, IY) depending on the shift +*/ +static Z80Word* GetHLReg(Z80 *cpu) +{ + if (cpu->shift==0) + return &cpu->HL.w; - case 0x6b: - TSTATE(4); - break; + if (cpu->shift==0xdd) + return &cpu->IX.w; - case 0x6c: - TSTATE(4); - break; + if (cpu->shift==0xfd) + return &cpu->IY.w; - case 0x6d: - TSTATE(4); - break; + return 0; +} - case 0x6e: - TSTATE(4); - break; - case 0x6f: - TSTATE(4); - break; +/* Get a condition depending on the bitmask +*/ +static Z80Byte GetCond(Z80 *cpu, Z80Byte bm) +{ + if (bm==0x00) /* NZ */ + return !IS_Z; - case 0x70: - TSTATE(4); - break; + if (bm==0x01) /* Z */ + return IS_Z; - case 0x71: - TSTATE(4); - break; + if (bm==0x02) /* NC */ + return !IS_C; - case 0x72: - TSTATE(4); - break; + if (bm==0x03) /* C */ + return IS_C; - case 0x73: - TSTATE(4); - break; + if (bm==0x04) /* PO */ + return !IS_P; - case 0x74: - TSTATE(4); - break; + if (bm==0x05) /* PE */ + return IS_P; - case 0x75: - TSTATE(4); - break; + if (bm==0x06) /* P */ + return !IS_S; - case 0x76: - TSTATE(4); - break; + if (bm==0x07) /* M */ + return IS_S; - case 0x77: - TSTATE(4); - break; + return 0; +} - case 0x78: - TSTATE(4); - break; - case 0x79: - TSTATE(4); - break; +/* ---------------------------------------- HANDLERS FOR ED OPCODES +*/ - case 0x7a: - TSTATE(4); - break; - case 0x7b: - TSTATE(4); - break; +static void EDOp_01(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + if (bml==0x00) /* IN r,(C) */ + { + Z80Byte *reg; + Z80Byte v; - case 0x7c: - TSTATE(4); - break; + TSTATE(12); - case 0x7d: - TSTATE(4); - break; + reg=Get8_HL(cpu,bmm); + v=IN(cpu->BC.w); - case 0x7e: - TSTATE(4); - break; + cpu->AF.b[LO]=(cpu->AF.b[LO]&C_Z80)|PSZtable[v]; + SETHIDDEN(v); - case 0x7f: - TSTATE(4); - break; + if (reg) + *reg=v; - case 0x80: - TSTATE(4); - break; + return; + } - case 0x81: - TSTATE(4); - break; + if (bml==0x01) /* OUT r,(C) */ + { + Z80Byte *reg; - case 0x82: - TSTATE(4); - break; + TSTATE(12); - case 0x83: - TSTATE(4); - break; + reg=Get8_HL(cpu,bmm); + OUT(cpu->BC.w,reg ? *reg:0); - case 0x84: - TSTATE(4); - break; + return; + } - case 0x85: - TSTATE(4); - break; + if (bml==0x02) + { + Z80Word *reg; - case 0x86: - TSTATE(4); - break; + TSTATE(15); - case 0x87: - TSTATE(4); - break; + reg=Get16_HL(cpu,bmm>>1); - case 0x88: - TSTATE(4); - break; + if (bmm&1) /* ADC HL,rr */ + { + cpu->HL.w=ADC16(cpu,cpu->HL.w,*reg); + } + else /* SBC HL,rr */ + { + cpu->HL.w=SBC16(cpu,cpu->HL.w,*reg); + } - case 0x89: - TSTATE(4); - break; + return; + } - case 0x8a: - TSTATE(4); - break; + if (bml==0x03) + { + Z80Word a; + Z80Word *reg; - case 0x8b: - TSTATE(4); - break; + TSTATE(20); - case 0x8c: - TSTATE(4); - break; + a=FETCH_WORD; + reg=Get16_HL(cpu,bmm>>1); - case 0x8d: - TSTATE(4); - break; + if (bmm&1) /* LD rr,(nn) */ + { + *reg=PEEKW(a); + } + else /* LD (nn),rr */ + { + POKEW(a,*reg); + } - case 0x8e: - TSTATE(4); - break; + return; + } - case 0x8f: - TSTATE(4); - break; + if (bml==0x04) /* NEG */ + { + Z80Byte v; - case 0x90: - TSTATE(4); - break; + TSTATE(8); - case 0x91: - TSTATE(4); - break; + v=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; - case 0x92: - TSTATE(4); - break; + SUB8(cpu,v); - case 0x93: - TSTATE(4); - break; + return; + } - case 0x94: - TSTATE(4); - break; + if (bml==0x05) + { + TSTATE(14); - case 0x95: - TSTATE(4); - break; + if (bmm&1) /* RETI */ + { + POP(cpu->PC); + CALLBACK(eZ80_RETI,0); + } + else /* RETN */ + { + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + } - case 0x96: - TSTATE(4); - break; + return; + } - case 0x97: - TSTATE(4); - break; + if (bml==0x06) /* IM n */ + { + TSTATE(8); - case 0x98: - TSTATE(4); - break; + switch(bmm&0x3) + { + case 0x00: + case 0x01: + cpu->IM=0; + break; + + case 0x02: + cpu->IM=1; + break; + + case 0x03: + cpu->IM=2; + break; + } - case 0x99: - TSTATE(4); - break; + return; + } - case 0x9a: - TSTATE(4); - break; + if (bml==0x07) + { + Z80Byte b; - case 0x9b: - TSTATE(4); - break; + switch(bmm) + { + case 0x00: /* LD I,A */ + TSTATE(9); + cpu->I=cpu->AF.b[HI]; + break; + case 0x01: /* LD R,A */ + TSTATE(9); + cpu->R=cpu->AF.b[HI]; + break; + case 0x02: /* LD A,I */ + TSTATE(9); + cpu->AF.b[HI]=cpu->I; + break; + case 0x03: /* LD A,R */ + TSTATE(9); + cpu->AF.b[HI]=cpu->R; + break; + case 0x04: /* RRD */ + 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]=(cpu->AF.b[LO]&C_Z80)|PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); + break; + case 0x05: /* RLD */ + 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]=(cpu->AF.b[LO]&C_Z80)|PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); + break; + case 0x06: /* NOP */ + case 0x07: + TSTATE(8); + break; + } - case 0x9c: - TSTATE(4); - break; + return; + } +} - case 0x9d: - TSTATE(4); - break; - case 0x9e: - TSTATE(4); - break; +static void EDOp_10(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + if (bml==0x00) + { + switch(bmm) + { + case 0x00: /* NOP */ + case 0x01: + case 0x02: + case 0x03: + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + case 0x04: /* LDI */ + TSTATE(16); + LDI(cpu); + break; + case 0x05: /* LDD */ + TSTATE(16); + LDD(cpu); + break; + case 0x06: /* LDIR */ + TSTATE(16); + LDI(cpu); + + if(cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + case 0x07: /* LDDR */ + TSTATE(16); + LDD(cpu); + + if(cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + } + } - case 0x9f: - TSTATE(4); - break; + if (bml==0x01) + { + switch(bmm) + { + case 0x00: /* NOP */ + case 0x01: + case 0x02: + case 0x03: + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + case 0x04: /* CPI */ + TSTATE(16); + CPI(cpu); + break; + case 0x05: /* CPD */ + TSTATE(16); + CPD(cpu); + break; + case 0x06: /* CPIR */ + TSTATE(16); + CPI(cpu); + + if(cpu->BC.w && !IS_Z) + { + TSTATE(5); + cpu->PC-=2; + } + break; + case 0x07: /* CPDR */ + TSTATE(16); + CPD(cpu); + + if(cpu->BC.w && !IS_Z) + { + TSTATE(5); + cpu->PC-=2; + } + break; + } + } - case 0xa0: - TSTATE(4); - break; + if (bml==0x02) + { + switch(bmm) + { + case 0x00: /* NOP */ + case 0x01: + case 0x02: + case 0x03: + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + case 0x04: /* INI */ + TSTATE(16); + INI(cpu); + break; + case 0x05: /* IND */ + TSTATE(16); + IND(cpu); + break; + case 0x06: /* INIR */ + TSTATE(16); + INI(cpu); + + if(cpu->BC.b[HI]) + { + TSTATE(5); + cpu->PC-=2; + } + break; + case 0x07: /* INDR */ + TSTATE(16); + IND(cpu); + + if(cpu->BC.b[HI]) + { + TSTATE(5); + cpu->PC-=2; + } + break; + } + } - case 0xa1: - TSTATE(4); - break; + if (bml==0x03) + { + switch(bmm) + { + case 0x00: /* NOP */ + case 0x01: + case 0x02: + case 0x03: + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + case 0x04: /* OUTI */ + TSTATE(16); + OUTI(cpu); + break; + case 0x05: /* OUTD */ + TSTATE(16); + OUTD(cpu); + break; + case 0x06: /* OTIR */ + TSTATE(16); + OUTI(cpu); + + if(cpu->BC.b[HI]) + { + TSTATE(5); + cpu->PC-=2; + } + break; + case 0x07: /* OTDR */ + TSTATE(16); + OUTD(cpu); + + if(cpu->BC.b[HI]) + { + TSTATE(5); + cpu->PC-=2; + } + break; + } + } - case 0xa2: - TSTATE(4); - break; + /* Everything else is a NOP + */ + CALLBACK(eZ80_EDHook,opcode); +} - case 0xa3: - TSTATE(4); - break; - case 0xa4: - TSTATE(4); - break; +static void DecodeED(Z80 *cpu, Z80Byte opcode) +{ + Z80Byte bmh,bmm,bml; - case 0xa5: - TSTATE(4); - break; + /* Split up the opcode into it's bitmasks + */ + bmh=(opcode>>6)&3; + bmm=(opcode>>3)&7; + bml=opcode&7; - case 0xa6: - TSTATE(4); - break; + /* Instruction set 01 + */ + if (bmh==0x01) + { + EDOp_01(cpu,opcode,bmh,bmm,bml); + return; + } - case 0xa7: - TSTATE(4); - break; + /* Instruction set 10 + */ + if (bmh==0x02) + { + EDOp_10(cpu,opcode,bmh,bmm,bml); + return; + } - case 0xa8: - TSTATE(4); - break; + /* All the rest are NOP/invalid + */ + CALLBACK(eZ80_EDHook,opcode); +} - case 0xa9: - TSTATE(4); - break; - case 0xaa: - TSTATE(4); - break; +/* ---------------------------------------- HANDLERS FOR CB OPCODES +*/ - case 0xab: - TSTATE(4); - break; - case 0xac: - TSTATE(4); - break; +static void CBOp_00(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + static Z80Byte (*op[8])(Z80 *cpu, Z80Byte val)= + { + RLC, + RRC, + RL, + RR, + SLA, + SRA, + SLL, + SRL + }; + Z80Byte *reg; + + reg=Get8(cpu,bml); + + /* If the reg is NULL, this is an (HL) type arg. Also, if this is a + shifted op then the argument is taken from (HL) and also copied to the + register. + */ + if (cpu->shift || !reg) + { + Z80Word a; - case 0xad: - TSTATE(4); - break; + TSTATE(15); + a=GetHL(cpu); - case 0xae: - TSTATE(4); - break; + if (cpu->shift && reg) + { + *reg=op[bmm](cpu,PEEK(a)); + POKE(a,*reg); + } + else + POKE(a,op[bmm](cpu,PEEK(a))); + } + else + { + TSTATE(8); + *reg=op[bmm](cpu,*reg); + } +} - case 0xaf: - TSTATE(4); - break; - case 0xb0: - TSTATE(4); - break; +static void CBOp_01(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + Z80Byte *reg; - case 0xb1: - TSTATE(4); - break; + reg=Get8(cpu,bml); - case 0xb2: - TSTATE(4); - break; + /* If the reg is NULL, this is an (HL) type arg. Also, if this is a + shifted op. + */ + if (cpu->shift || !reg) + { + Z80Word a; - case 0xb3: - TSTATE(4); - break; + TSTATE(12); + a=GetHL(cpu); + BIT(cpu,PEEK(a),bmm); + } + else + { + TSTATE(8); + BIT(cpu,*reg,bmm); + } +} - case 0xb4: - TSTATE(4); - break; - case 0xb5: - TSTATE(4); - break; +static void CBOp_ResSet(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + Z80Byte *reg; + int reset; - case 0xb6: - TSTATE(4); - break; + reg=Get8(cpu,bml); - case 0xb7: - TSTATE(4); - break; + reset=(bmh==0x02); - case 0xb8: - TSTATE(4); - break; + /* If the reg is NULL, this is an (HL) type arg. Also, if this is a + shifted op then the argument is taken from (HL) and also copied to the + register. + */ + if (cpu->shift || !reg) + { + Z80Word a; - case 0xb9: - TSTATE(4); - break; + TSTATE(15); + a=GetHL(cpu); - case 0xba: - TSTATE(4); - break; + if (reset) + { + CLR(cpu->memory[a],bmm); + } + else + { + SET(cpu->memory[a],bmm); + } - case 0xbb: - TSTATE(4); - break; + if (cpu->shift && reg) + { + *reg=cpu->memory[a]; + } + } + else + { + TSTATE(8); + if (reset) + { + CLR(*reg,bmm); + } + else + { + SET(*reg,bmm); + } + } +} - case 0xbc: - TSTATE(4); - break; - case 0xbd: - TSTATE(4); - break; +static void DecodeCB(Z80 *cpu, Z80Byte opcode) +{ + Z80Byte bmh,bmm,bml; - case 0xbe: - TSTATE(4); - break; + /* Split up the opcode into it's bitmasks + */ + bmh=(opcode>>6)&3; + bmm=(opcode>>3)&7; + bml=opcode&7; - case 0xbf: - TSTATE(4); - break; + /* Instruction set 00 + */ + if (bmh==0x00) + { + CBOp_00(cpu,opcode,bmh,bmm,bml); + return; + } - case 0xc0: - TSTATE(4); - break; + /* Instruction set 01 (BIT) + */ + if (bmh==0x01) + { + CBOp_01(cpu,opcode,bmh,bmm,bml); + return; + } - case 0xc1: - TSTATE(4); - break; + /* Instruction set 10 (RES) and 11 (SET) + */ + CBOp_ResSet(cpu,opcode,bmh,bmm,bml); +} - case 0xc2: - TSTATE(4); - break; - case 0xc3: - TSTATE(4); - break; +/* ---------------------------------------- HANDLERS FOR NORMAL OPCODES +*/ +static void Normal_00(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + Z80Reg tmp; + Z80Byte *bp=NULL; + Z80Word w; - case 0xc4: - TSTATE(4); - break; + if (bml==0x00) + { + switch(bmm) + { + case 0x00: /* NOP */ + TSTATE(4); + break; + case 0x01: /* EX AF,AF' */ + TSTATE(4); + tmp=cpu->AF; + cpu->AF=cpu->AF_; + cpu->AF_=tmp; + break; + case 0x02: /* DJNZ */ + if (--cpu->BC.b[HI]) + { + TSTATE(13); + JR; + } + else + { + TSTATE(8); + NOJR; + } + break; + case 0x03: /* JR */ + TSTATE(12); + JR; + break; + + case 0x04: /* JR cc */ + case 0x05: + case 0x06: + case 0x07: + if (GetCond(cpu,bmm&3)) + { + TSTATE(12); + JR; + } + else + { + TSTATE(7); + NOJR; + } + break; + } - case 0xc5: - TSTATE(4); - break; + return; + } - case 0xc6: - TSTATE(4); - break; + if (bml==0x01) + { + if(bmm&1) /* ADD HL,rr */ + { + TSTATE(11); + *GetHLReg(cpu)=ADD16(cpu,*GetHLReg(cpu),*Get16(cpu,bmm>>1)); + } + else /* LD rr,nn */ + { + TSTATE(10); + *Get16(cpu,bmm>>1)=FETCH_WORD; + } - case 0xc7: - TSTATE(4); - break; + return; + } - case 0xc8: - TSTATE(4); - break; + if (bml==0x02) + { + switch(bmm) + { + case 0x00: /* LD (rr),A */ + case 0x02: + TSTATE(7); + POKE(*Get16(cpu,(bmm&2)>>1),cpu->AF.b[HI]); + break; + case 0x01: /* LD A,(rr) */ + case 0x03: + TSTATE(7); + cpu->AF.b[HI]=PEEK(*Get16(cpu,(bmm&2)>>1)); + break; + case 0x04: /* LD (nn),HL */ + TSTATE(16); + w=FETCH_WORD; + POKEW(w,*GetHLReg(cpu)); + break; + case 0x05: /* LD (nn),HL */ + TSTATE(16); + w=FETCH_WORD; + *GetHLReg(cpu)=PEEKW(w); + break; + case 0x06: /* LD (nn),A */ + TSTATE(13); + w=FETCH_WORD; + POKE(w,cpu->AF.b[HI]); + break; + case 0x07: /* LD A,(nn) */ + TSTATE(13); + w=FETCH_WORD; + cpu->AF.b[HI]=PEEK(w); + break; + } - case 0xc9: - TSTATE(4); - break; + return; + } - case 0xca: - TSTATE(4); - break; + if (bml==0x03) + { + if(bmm&1) /* DEC rr */ + { + TSTATE(6); + (*Get16(cpu,bmm>>1))--; + } + else /* INC rr */ + { + TSTATE(6); + (*Get16(cpu,bmm>>1))++; + } - case 0xcb: - TSTATE(4); - break; + return; + } - case 0xcc: - TSTATE(4); - break; + if (bml==0x04) + { + bp=Get8(cpu,bmm); - case 0xcd: - TSTATE(4); - break; + if(!bp) /* INC (HL) */ + { + Z80Word a; - case 0xce: + TSTATE(11); + a=GetHL(cpu); + POKE(a,INC8(cpu,PEEK(a))); + } + else /* INC r */ + { TSTATE(4); - break; + *bp=INC8(cpu,*bp); + } - case 0xcf: - TSTATE(4); - break; + return; + } - case 0xd0: - TSTATE(4); - break; + if (bml==0x05) + { + bp=Get8(cpu,bmm); - case 0xd1: - TSTATE(4); - break; + if(!bp) /* INC (HL) */ + { + Z80Word a; - case 0xd2: + TSTATE(11); + a=GetHL(cpu); + POKE(a,DEC8(cpu,PEEK(a))); + } + else /* INC r */ + { TSTATE(4); - break; + *bp=DEC8(cpu,*bp); + } - case 0xd3: - TSTATE(4); - break; + return; + } - case 0xd4: - TSTATE(4); - break; + if (bml==0x06) + { + bp=Get8(cpu,bmm); - case 0xd5: - TSTATE(4); - break; + if(!bp) /* LD (HL),n */ + { + Z80Word a; - case 0xd6: - TSTATE(4); - break; + TSTATE(10); + a=GetHL(cpu); + POKE(a,FETCH_BYTE); + } + else /* LD r,n */ + { + TSTATE(7); + *bp=FETCH_BYTE; + } - case 0xd7: - TSTATE(4); - break; + return; + } - case 0xd8: - TSTATE(4); - break; + if (bml==0x07) + { + switch(bmm) + { + case 0x00: /* RLCA */ + TSTATE(4); + RLCA(cpu); + break; + case 0x01: /* RRCA */ + TSTATE(4); + RRCA(cpu); + break; + case 0x02: /* RLA */ + TSTATE(4); + RLA(cpu); + break; + case 0x03: /* RRA */ + TSTATE(4); + RRA(cpu); + break; + case 0x04: /* DAA */ + TSTATE(4); + DAA(cpu); + break; + case 0x05: /* CPL */ + TSTATE(4); + cpu->AF.b[HI]=cpu->AF.b[HI]^0xff; + SETFLAG(H_Z80); + SETFLAG(N_Z80); + break; + case 0x06: /* SCF */ + TSTATE(4); + SETFLAG(C_Z80); + break; + case 0x07: /* CCF */ + TSTATE(4); + if (IS_C) + SETFLAG(H_Z80); + else + CLRFLAG(H_Z80); + + cpu->AF.b[LO]^=C_Z80; + break; + } - case 0xd9: - TSTATE(4); - break; + return; + } +} - case 0xda: - TSTATE(4); - break; - case 0xdb: - TSTATE(4); - break; +static void Normal_01(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + Z80Byte *dest; + Z80Byte *src; - case 0xdc: - TSTATE(4); - break; + dest=Get8(cpu,bmm); + src=Get8(cpu,bml); - case 0xdd: - TSTATE(4); - break; + /* Handle HALT + */ + if (!dest && !src) + { + TSTATE(4); + cpu->PC--; - case 0xde: - TSTATE(4); - break; + /* Inform user of HALT going high + */ + if (!cpu->halt) + CALLBACK(eZ80_Halt,1); - case 0xdf: - TSTATE(4); - break; + cpu->halt=TRUE; - case 0xe0: - TSTATE(4); - break; + return; + } - case 0xe1: - TSTATE(4); - break; + /* If the src is NULL, then it is an (HL), (IX...) type instruction + */ + if (src) + { + /* If the dest is NULL then it is an (HL) type store + */ + if (!dest) + { + Z80Word a; - case 0xe2: - TSTATE(4); - break; + TSTATE(7); - case 0xe3: - TSTATE(4); - break; + /* Reget the source in case we're shifted. HL is the source when + doing an (HL) style store. + */ + src=Get8_HL(cpu,bml); - case 0xe4: - TSTATE(4); - break; + a=GetHL(cpu); - case 0xe5: + POKE(a,*src); + } + else + { TSTATE(4); - break; + *dest=*src; + } + } + else + { + Z80Word a; - case 0xe6: - TSTATE(4); - break; + TSTATE(7); - case 0xe7: - TSTATE(4); - break; + /* Reget the destination in case we're shifted. HL is the dest when + doing an (HL) style read. + */ + dest=Get8_HL(cpu,bmm); - case 0xe8: - TSTATE(4); - break; + a=GetHL(cpu); + *dest=PEEK(a); + } +} - case 0xe9: - TSTATE(4); - break; - case 0xea: - TSTATE(4); - break; +static void Normal_10(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + static void (*op[8])(Z80 *cpu, Z80Byte val)= + { + ADD8, + ADC8, + SUB8, + SBC8, + AND, + XOR, + OR, + CMP8 + }; + + Z80Byte *reg; + + reg=Get8(cpu,bml); + + if (!reg) /* op A,(HL) */ + { + Z80Word a; - case 0xeb: - TSTATE(4); - break; + TSTATE(7); + a=GetHL(cpu); + op[bmm](cpu,PEEK(a)); + } + else /* op A,r */ + { + TSTATE(4); + op[bmm](cpu,*reg); + } +} - case 0xec: - TSTATE(4); - break; - case 0xed: - TSTATE(4); - break; +static void Normal_11(Z80 *cpu, Z80Byte opcode, + Z80Byte bmh, Z80Byte bmm, Z80Byte bml) +{ + Z80Reg tmp; - case 0xee: - TSTATE(4); - break; + if (bml==0x00) /* RET cc */ + { + if (GetCond(cpu,bmm)) + { + TSTATE(11); + POP(cpu->PC); + } + else + { + TSTATE(5); + } - case 0xef: - TSTATE(4); - break; + return; + } - case 0xf0: - TSTATE(4); - break; + if (bml==0x01) + { + switch(bmm) + { + case 0x00: /* POP rr */ + case 0x02: + case 0x04: + case 0x06: + TSTATE(10); + POP(*Get16_AF(cpu,bmm>>1)); + break; + case 0x01: /* RET */ + TSTATE(10); + POP(cpu->PC); + break; + case 0x03: /* EXX */ + TSTATE(4); + tmp=cpu->BC; + cpu->BC=cpu->BC_; + cpu->BC_=tmp; + tmp=cpu->DE; + cpu->DE=cpu->DE_; + cpu->DE_=tmp; + tmp=cpu->HL; + cpu->HL=cpu->HL_; + cpu->HL_=tmp; + break; + case 0x05: /* JP (HL) */ + TSTATE(4); + cpu->PC=GetHLVal(cpu); + break; + case 0x07: /* LD SP,HL */ + TSTATE(6); + cpu->SP=GetHLVal(cpu); + break; + } - case 0xf1: - TSTATE(4); - break; + return; + } - case 0xf2: - TSTATE(4); - break; + if (bml==0x02) /* JP cc */ + { + TSTATE(10); - case 0xf3: - TSTATE(4); - break; + if (GetCond(cpu,bmm)) + { + JP; + } + else + { + NOJP; + } - case 0xf4: - TSTATE(4); - break; + return; + } - case 0xf5: - TSTATE(4); - break; + if (bml==0x03) + { + Z80Word tmp; + Z80Word *reg; - case 0xf6: - TSTATE(4); - break; + switch(bmm) + { + case 0x00: /* JP nn */ + TSTATE(10); + cpu->PC=FETCH_WORD; + break; + case 0x01: /* shift */ + break; + case 0x02: /* OUT (n),a */ + TSTATE(11); + OUT(FETCH_BYTE,cpu->AF.b[HI]); + break; + case 0x03: /* IN A,(n) */ + TSTATE(11); + cpu->AF.b[HI]=IN(FETCH_BYTE); + break; + case 0x04: /* EX (SP),HL */ + TSTATE(19); + reg=GetHLReg(cpu); + tmp=*reg; + *reg=PEEKW(cpu->SP); + POKEW(cpu->SP,tmp); + break; + case 0x05: /* EX DE,HL */ + TSTATE(4); + tmp=cpu->HL.w; + cpu->HL.w=cpu->DE.w; + cpu->DE.w=tmp; + break; + case 0x06: /* DI */ + TSTATE(4); + cpu->IFF1=0; + cpu->IFF2=0; + break; + case 0x07: /* EI */ + TSTATE(4); + cpu->IFF1=1; + cpu->IFF2=1; + break; + } - case 0xf7: - TSTATE(4); - break; + return; + } - case 0xf8: - TSTATE(4); - break; + if (bml==0x04) /* CALL cc */ + { + if (GetCond(cpu,bmm)) + { + TSTATE(12); + CALL; + } + else + { + TSTATE(7); + NOCALL; + } - case 0xf9: - TSTATE(4); - break; + return; + } - case 0xfa: - TSTATE(4); - break; + if (bml==0x05) + { + if (bmm==01) /* CALL nn */ + { + TSTATE(17); + CALL; + } + else + { + if (!(bmm&1)) /* PUSH rr */ + { + TSTATE(11); + PUSH(*Get16_AF(cpu,bmm>>1)); + } - case 0xfb: - TSTATE(4); - break; + /* Everything else is a shift */ + } - case 0xfc: - TSTATE(4); - break; + return; + } - case 0xfd: - TSTATE(4); - break; + if (bml==0x06) + { + TSTATE(8); - case 0xfe: - TSTATE(4); - break; + switch(bmm) + { + case 0x00: /* ADD A,n */ + ADD8(cpu,FETCH_BYTE); + break; + case 0x01: /* ADC A,n */ + ADC8(cpu,FETCH_BYTE); + break; + case 0x02: /* SUB A,n */ + SUB8(cpu,FETCH_BYTE); + break; + case 0x03: /* SBC A,n */ + SBC8(cpu,FETCH_BYTE); + break; + case 0x04: /* AND n */ + AND(cpu,FETCH_BYTE); + break; + case 0x05: /* XOR n */ + XOR(cpu,FETCH_BYTE); + break; + case 0x06: /* OR n */ + OR(cpu,FETCH_BYTE); + break; + case 0x07: /* CP n */ + CMP8(cpu,FETCH_BYTE); + break; + } - case 0xff: - TSTATE(4); - break; + return; + } + if (bml==0x07) /* RST nn */ + { + TSTATE(11); + PUSH(cpu->PC); + cpu->PC=bmm*8; + return; } } +/* ---------------------------------------- NORMAL OPCODE DECODER +*/ +void Z80_Decode(Z80 *cpu, Z80Byte opcode) +{ + Z80Byte bmh,bmm,bml; + + /* IX/IY shifts + */ + if (opcode==0xdd || opcode==0xfd) + { + TSTATE(4); + INC_R; + + cpu->shift=opcode; + Z80_Decode(cpu,FETCH_BYTE); + return; + } + + /* CB shifts + */ + if (opcode==0xcb) + { + INC_R; + + /* Check for previous IX/IY shift. + */ + if (cpu->shift!=0) + { + cpu->use_cb_off=TRUE; + cpu->cb_off=(Z80Relative)FETCH_BYTE; + } + + DecodeCB(cpu,FETCH_BYTE); + return; + } + + /* DE shifts + */ + if (opcode==0xed) + { + INC_R; + DecodeED(cpu,FETCH_BYTE); + return; + } + + /* Split up the opcode into it's bitmasks + */ + bmh=(opcode>>6)&3; + bmm=(opcode>>3)&7; + bml=opcode&7; + + /* Instruction set 00 + */ + if (bmh==0x00) + { + Normal_00(cpu,opcode,bmh,bmm,bml); + return; + } + + /* Instruction set 01 + */ + if (bmh==0x01) + { + Normal_01(cpu,opcode,bmh,bmm,bml); + return; + } + + /* Instruction set 10 + */ + if (bmh==0x02) + { + Normal_10(cpu,opcode,bmh,bmm,bml); + return; + } + + /* Instruction set 11 + */ + Normal_11(cpu,opcode,bmh,bmm,bml); +} + + /* END OF FILE */ diff --git a/z80_private.h b/z80_private.h index 08dc543..32ce91f 100644 --- a/z80_private.h +++ b/z80_private.h @@ -43,25 +43,30 @@ /* ---------------------------------------- TYPES */ +typedef union +{ + Z80Word w; + Z80Byte b[2]; +} Z80Reg; + struct Z80 { Z80Val cycle; Z80Word PC; - Z80Byte A; - Z80Byte F; - Z80Word BC; - Z80Word DE; - Z80Word HL; + Z80Reg AF; + Z80Reg BC; + Z80Reg DE; + Z80Reg HL; - Z80Word AF_; - Z80Word BC_; - Z80Word DE_; - Z80Word HL_; + Z80Reg AF_; + Z80Reg BC_; + Z80Reg DE_; + Z80Reg HL_; - Z80Word IX; - Z80Word IY; + Z80Reg IX; + Z80Reg IY; Z80Word SP; @@ -136,8 +141,8 @@ struct Z80 #define SET(v,b) v|=b #define CLR(v,b) v&=~(b) -#define SETFLAG(f) SET(cpu->F,f) -#define CLRFLAG(f) CLR(cpu->F,f) +#define SETFLAG(f) SET(cpu->AF.b[LO],f) +#define CLRFLAG(f) CLR(cpu->AF.b[LO],f) #define PEEK(addr) (cpu->memory[addr]) #define PEEKW(addr) (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8) @@ -148,11 +153,12 @@ struct Z80 { \ cpu->memory[addr]=val; \ } \ - while (0)(cpu->write(cpu,addr,val)) + } while (0) #define POKEW(addr,val) do \ { \ - POKE(addr,val); \ - POKE(addr+1,val>>8); \ + Z80Word once=val; \ + POKE(addr,once); \ + POKE(addr+1,once>>8); \ } while(0) #define FETCH_BYTE (cpu->memory[cpu->PC++]) @@ -160,12 +166,12 @@ struct Z80 cpu->memory[cpu->PC-2]| \ ((Z80Word)cpu->memory[cpu->PC-1]<<8)) -#define IS_C (cpu->F&C_Z80) -#define IS_N (cpu->F&N_Z80) -#define IS_P (cpu->F&P_Z80) -#define IS_H (cpu->F&H_Z80) -#define IS_Z (cpu->F&Z_Z80) -#define IS_S (cpu->F&S_Z80) +#define IS_C (cpu->AF.b[LO]&C_Z80) +#define IS_N (cpu->AF.b[LO]&N_Z80) +#define IS_P (cpu->AF.b[LO]&P_Z80) +#define IS_H (cpu->AF.b[LO]&H_Z80) +#define IS_Z (cpu->AF.b[LO]&Z_Z80) +#define IS_S (cpu->AF.b[LO]&S_Z80) #define CARRY IS_C @@ -185,9 +191,25 @@ struct Z80 cpu->SP+=2; \ } while(0) -#define SETHIDDEN(res) cpu->F=(cpu->F&~(B3_Z80|B5_Z80))|\ +#define SETHIDDEN(res) cpu->AF.b[LO]=(cpu->AF.b[LO]&~(B3_Z80|B5_Z80))|\ ((res)&(B3_Z80|B5_Z80)) +#define CALL do \ + { \ + PUSH(cpu->PC+2); \ + cpu->PC=PEEKW(cpu->PC); \ + } while(0) +#define NOCALL cpu->PC+=2 +#define JP cpu->PC=PEEKW(cpu->PC) +#define NOJP cpu->PC+=2 +#define JR cpu->PC+=(Z80Relative)PEEK(cpu->PC)+1 +#define NOJR cpu->PC++ + +#define IN(PORT) (cpu->pread ? cpu->pread(cpu,PORT) : 0) +#define OUT(PORT,VAL) if (cpu->pwrite) \ + { \ + cpu->pwrite(cpu,PORT,VAL); \ + } /* ---------------------------------------- FLAG TABLES @@ -201,7 +223,8 @@ extern Z80Byte Ztable[512]; /* ---------------------------------------- GLOBAL GENERAL OPCODES/ROUTINES */ -void Z80_Decode(Z80 *cpu); +void Z80_Decode(Z80 *cpu, Z80Byte opcode); +void Z80_InitialiseInternals(void); #endif |