void IntZ80(Z80 *R,word Vector) { /* If HALTed, take CPU off HALT instruction */ if(R->IFF&IFF_HALT) { R->PC.W++;R->IFF&=~IFF_HALT; } if((R->IFF&IFF_1)||(Vector==INT_NMI)) { /* Save PC on stack */ M_PUSH(PC); /* Automatically reset IRequest if needed */ if(R->IAutoReset&&(Vector==R->IRequest)) R->IRequest=INT_NONE; /* If it is NMI... */ if(Vector==INT_NMI) { /* Clear IFF1 */ R->IFF&=~(IFF_1|IFF_EI); /* Jump to hardwired NMI vector */ R->PC.W=0x0066; JumpZ80(0x0066); /* Done */ return; } /* Further interrupts off */ R->IFF&=~(IFF_1|IFF_2|IFF_EI); /* If in IM2 mode... */ if(R->IFF&IFF_IM2) { /* Make up the vector address */ Vector=(Vector&0xFF)|((word)(R->I)<<8); /* Read the vector */ R->PC.B.l=RdZ80(Vector++); R->PC.B.h=RdZ80(Vector); JumpZ80(R->PC.W); /* Done */ return; } /* If in IM1 mode, just jump to hardwired IRQ vector */ if(R->IFF&IFF_IM1) { R->PC.W=0x0038;JumpZ80(0x0038);return; } /* If in IM0 mode... */ /* Jump to a vector */ switch(Vector) { case INT_RST00: R->PC.W=0x0000;JumpZ80(0x0000);break; case INT_RST08: R->PC.W=0x0008;JumpZ80(0x0008);break; case INT_RST10: R->PC.W=0x0010;JumpZ80(0x0010);break; case INT_RST18: R->PC.W=0x0018;JumpZ80(0x0018);break; case INT_RST20: R->PC.W=0x0020;JumpZ80(0x0020);break; case INT_RST28: R->PC.W=0x0028;JumpZ80(0x0028);break; case INT_RST30: R->PC.W=0x0030;JumpZ80(0x0030);break; case INT_RST38: R->PC.W=0x0038;JumpZ80(0x0038);break; } } }
static void CodesDD(register Z80 *R) { register byte I; register pair J; #define XX IX I=RdZ80(R->PC.W++); R->ICount-=CyclesXX[I]; switch(I) { #include "CodesXX.h" case PFX_FD: case PFX_DD: R->PC.W--;break; case PFX_CB: CodesDDCB(R);break; default: if(R->TrapBadOps) printf ( "[Z80 %lX] Unrecognized instruction: DD %02X at PC=%04X\n", (long)R->User,RdZ80(R->PC.W-1),R->PC.W-2 ); } #undef XX }
static void CodesFD(register Z80 *R) { register byte I; register pair J; #define XX IY I=RdZ80(R->PC.W++); R->ICount-=CyclesXX[I]; switch(I) { #include "CodesXX.h" case PFX_FD: case PFX_DD: R->PC.W--;break; case PFX_CB: CodesFDCB(R);break; default: printf ( "Unrecognized instruction: FD %02X at PC=%04X\n", RdZ80(R->PC.W-1),R->PC.W-2 ); } #undef XX }
word RunZ80(Z80 *R) { register byte I; register pair J; for(;;) { #ifdef DEBUG /* Turn tracing on when reached trap address */ if(R->PC.W==R->Trap) R->Trace=1; /* Call single-step debugger, exit if requested */ if(R->Trace) if(!DebugZ80(R)) return(R->PC.W); #endif I=RdZ80(R->PC.W++); R->ICount-=Cycles[I]; switch(I) { #include "Codes.h" case PFX_CB: CodesCB(R);break; case PFX_ED: CodesED(R);break; case PFX_FD: CodesFD(R);break; case PFX_DD: CodesDD(R);break; } /* If cycle counter expired... */ if(R->ICount<=0) { /* If we have come after EI, get address from IRequest */ /* Otherwise, get it from the loop handler */ if(R->IFF&IFF_EI) { R->IFF=(R->IFF&~IFF_EI)|IFF_1; /* Done with AfterEI state */ R->ICount+=R->IBackup-1; /* Restore the ICount */ /* Call periodic handler or set pending IRQ */ if(R->ICount>0) J.W=R->IRequest; else { J.W=LoopZ80(R); /* Call periodic handler */ R->ICount+=R->IPeriod; /* Reset the cycle counter */ if(J.W==INT_NONE) J.W=R->IRequest; /* Pending IRQ */ } } else { J.W=LoopZ80(R); /* Call periodic handler */ R->ICount+=R->IPeriod; /* Reset the cycle counter */ if(J.W==INT_NONE) J.W=R->IRequest; /* Pending IRQ */ } if(J.W==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */ if(J.W!=INT_NONE) IntZ80(R,J.W); /* Int-pt if needed */ } } /* Execution stopped */ return(R->PC.W); }
static void CodesCB(register Z80 *R) { register byte I; I=RdZ80(R->PC.W++); R->ICount-=CyclesCB[I]; switch(I) { #include "CodesCB.h" default: if(R->TrapBadOps) printf ( "[Z80 %lX] Unrecognized instruction: CB %02X at PC=%04X\n", (long)(R->User),RdZ80(R->PC.W-1),R->PC.W-2 ); } }
static void CodesED(register Z80 *R) { register byte I; register pair J; I=RdZ80(R->PC.W++); R->ICount-=CyclesED[I]; switch(I) { #include "CodesED.h" case PFX_ED: R->PC.W--;break; default: if(R->TrapBadOps) printf ( "[Z80 %lX] Unrecognized instruction: ED %02X at PC=%04X\n", (long)R->User,RdZ80(R->PC.W-1),R->PC.W-2 ); } }
static void CodesFDCB(register Z80 *R) { register pair J; register byte I; #define XX IY J.W=R->XX.W+(offset)RdZ80(R->PC.W++); I=RdZ80(R->PC.W++); R->ICount-=CyclesXXCB[I]; switch(I) { #include "CodesXCB.h" default: if(R->TrapBadOps) printf ( "[Z80 %lX] Unrecognized instruction: FD CB %02X %02X at PC=%04X\n", (long)R->User,RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4 ); } #undef XX }
void IntZ80(Z80 *R,word Vector) { if((R->IFF&0x01)||(Vector==INT_NMI)) { /* Experimental V Shouldn't disable all interrupts? */ R->IFF=(R->IFF&0x9E)|((R->IFF&0x01)<<6); if(R->IFF&0x80) { R->PC.W++;R->IFF&=0x7F; } M_PUSH(PC); if(Vector==INT_NMI) R->PC.W=INT_NMI; else if(R->IFF&0x04) { Vector=(Vector&0xFF)|((word)(R->I)<<8); R->PC.B.l=RdZ80(Vector++); R->PC.B.h=RdZ80(Vector); } else if(R->IFF&0x02) R->PC.W=INT_IRQ; else R->PC.W=Vector; } mz80_cache_ip(R); }
void IntZ80(Z80 *R,word Vector) { if((R->IFF&0x01)||(Vector==INT_NMI)) { /* Experimental V Shouldn't disable all interrupts? */ R->IFF=(R->IFF&0x9E)|((R->IFF&0x01)<<6); if(R->IFF&0x80) { R->PC.W++;R->IFF&=0x7F; } M_PUSH(PC); /* Automatically reset IRequest if needed */ if(R->IAutoReset&&(Vector==R->IRequest)) R->IRequest=INT_NONE; if(Vector==INT_NMI) R->PC.W=0x0066; else if(R->IFF&0x04) { Vector=(Vector&0xFF)|((word)(R->I)<<8); R->PC.B.l=RdZ80(Vector++); R->PC.B.h=RdZ80(Vector); } else if(R->IFF&0x02) R->PC.W=0x0038; else switch(Vector) { case INT_RST00: R->PC.W=0x0000;break; case INT_RST08: R->PC.W=0x0008;break; case INT_RST10: R->PC.W=0x0010;break; case INT_RST18: R->PC.W=0x0018;break; case INT_RST20: R->PC.W=0x0020;break; case INT_RST28: R->PC.W=0x0028;break; case INT_RST30: R->PC.W=0x0030;break; case INT_RST38: R->PC.W=0x0038;break; } } }
word ExecZ80(Z80 *R) { register byte I; register pair J; I=RdZ80(R->PC.W++); R->ICount-=Cycles[I]; switch(I) { #include "Codes.h" case PFX_CB: CodesCB(R);break; case PFX_ED: CodesED(R);break; case PFX_FD: CodesFD(R);break; case PFX_DD: CodesDD(R);break; } /* We are done */ return(R->PC.W); }
byte DebugZ80(Z80 *R) { static char Flags[9] = "SZ.H.PNC"; char S[128],T[10]; byte J,I; DAsm(S,R->PC.W); for(J=0,I=R->AF.B.l;J<8;J++,I<<=1) T[J]=I&0x80? Flags[J]:'.'; T[8]='\0'; printf ( "AF:%04X HL:%04X DE:%04X BC:%04X PC:%04X SP:%04X IX:%04X IY:%04X I:%02X\n", R->AF.W,R->HL.W,R->DE.W,R->BC.W,R->PC.W,R->SP.W,R->IX.W,R->IY.W,R->I ); printf ( "AT PC: [%02X - %s] AT SP: [%04X] FLAGS: [%s] %s: %s\n\n", RdZ80(R->PC.W),S,RdZ80(R->SP.W)+RdZ80(R->SP.W+1)*256,T, R->IFF&0x04? "IM2":R->IFF&0x02? "IM1":"IM0", R->IFF&0x01? "EI":"DI" ); while(1) { printf("\n[Command,'?']-> "); fflush(stdout);fflush(stdin); fgets(S,50,stdin); for(J=0;S[J]>=' ';J++) S[J]=toupper(S[J]); S[J]='\0'; switch(S[0]) { case 'H': case '?': puts("\n***** Built-in Z80 Debugger Commands *****"); puts("<CR> : Break at next instruction"); puts("= <addr> : Break at addr"); puts("+ <offset> : Break at PC + offset"); puts("c : Continue without break"); puts("j <addr> : Continue from addr"); puts("m <addr> : Memory dump at addr"); puts("d <addr> : Disassembly at addr"); puts("?,h : Show this help text"); puts("q : Exit Z80 emulation"); break; case '\0': return(1); case '=': if(strlen(S)>=2) { sscanf(S+1,"%hX",&(R->Trap));R->Trace=0;return(1); } break; case '+': if(strlen(S)>=2) { sscanf(S+1,"%hX",&(R->Trap)); R->Trap+=R->PC.W;R->Trace=0; return(1); } break; case 'J': if(strlen(S)>=2) { sscanf(S+1,"%hX",&(R->PC.W));R->Trace=0;return(1); } break; case 'C': R->Trap=0xFFFF;R->Trace=0;return(1); case 'Q': return(0); case 'M': { word Addr; if(strlen(S)>1) sscanf(S+1,"%hX",&Addr); else Addr=R->PC.W; puts(""); for(J=0;J<16;J++) { printf("%04X: ",Addr); for(I=0;I<16;I++,Addr++) printf("%02X ",RdZ80(Addr)); printf(" | ");Addr-=16; for(I=0;I<16;I++,Addr++) putchar(isprint(RdZ80(Addr))? RdZ80(Addr):'.'); puts(""); } } break; case 'D': { word Addr; if(strlen(S)>1) sscanf(S+1,"%hX",&Addr); else Addr=R->PC.W; puts(""); for(J=0;J<16;J++) { printf("%04X: ",Addr); Addr+=DAsm(S,Addr); puts(S); } } break; } } /* Continue emulation */ return(1); }
static int DAsm(char *S,word A) { char R[128],H[10],C,*T,*P; byte J,Offset; word B; Offset=0; B=A; C='\0'; J=0; switch(RdZ80(B)) { case 0xCB: B++;T=MnemonicsCB[RdZ80(B++)];break; case 0xED: B++;T=MnemonicsED[RdZ80(B++)];break; case 0xDD: B++;C='X'; if(RdZ80(B)!=0xCB) T=MnemonicsXX[RdZ80(B++)]; else { B++;Offset=RdZ80(B++);J=1;T=MnemonicsXCB[RdZ80(B++)]; } break; case 0xFD: B++;C='Y'; if(RdZ80(B)!=0xCB) T=MnemonicsXX[RdZ80(B++)]; else { B++;Offset=RdZ80(B++);J=1;T=MnemonicsXCB[RdZ80(B++)]; } break; default: T=Mnemonics[RdZ80(B++)]; } if(P=strchr(T,'^')) { strncpy(R,T,P-T);R[P-T]='\0'; sprintf(H,"%02X",RdZ80(B++)); strcat(R,H);strcat(R,P+1); } else strcpy(R,T); if(P=strchr(R,'%')) *P=C; if(P=strchr(R,'*')) { strncpy(S,R,P-R);S[P-R]='\0'; sprintf(H,"%02X",RdZ80(B++)); strcat(S,H);strcat(S,P+1); } else if(P=strchr(R,'@')) { strncpy(S,R,P-R);S[P-R]='\0'; if(!J) Offset=RdZ80(B++); strcat(S,Offset&0x80? "-":"+"); J=Offset&0x80? 256-Offset:Offset; sprintf(H,"%02X",J); strcat(S,H);strcat(S,P+1); } else if(P=strchr(R,'#')) { strncpy(S,R,P-R);S[P-R]='\0'; sprintf(H,"%04X",RdZ80(B)+256*RdZ80(B+1)); strcat(S,H);strcat(S,P+1); B+=2; } else strcpy(S,R); return(B-A); }
int Z80ReadMem(word where) { return RdZ80(where); }
INLINE unsigned char OpZ80(Z80 *R) { return RdZ80(R->PC.W++); }