/*==================================================================== void Z80Interrupt( Z80 *regs, word ivec ) ===================================================================*/ void Z80Interrupt (Z80 * regs, word ivec) { word intaddress; /* unhalt the computer */ if (regs->halted == 1) regs->halted = 0; if (regs->IFF1) { PUSH (PC); regs->IFF1 = 0; switch (regs->IM) { case 0: r_PC = 0x0038; AddCycles (12); break; case 1: r_PC = 0x0038; AddCycles (13); break; case 2: intaddress = (((regs->I & 0xFF) << 8) | 0xFF); regs->PC.B.l = Z80ReadMem (intaddress); regs->PC.B.h = Z80ReadMem (intaddress + 1); AddCycles (19); break; } } }
void CDead6800::Step() { u8 Opcode; //current opcode u8 tmp,ntmp,otmp; //temp variables used by opcodes u32 tmp2,tmp3; CHECK_INTERRUPTS; if(WaitInterrupt) { AddCycles(1); return; } SavePC = PC; Opcode = OpRead(PC++); switch(Opcode) { #include "Dead6800switch.cpp" } AddCycles(c6800Cycles[Opcode]); //debug crap if(Debug == 3) { char dis[128]; Disassemble(dis,SavePC); message("$%04X: %s D=$%04X X=$%04X S=$%04X CC=$%02X\n",SavePC,dis,D,X,S,CC); } }
void CDead63701::Step() { u8 Opcode; //current opcode u8 tmp,ntmp,otmp; //temp variables used by opcodes u32 tmp2,tmp3; CHECK_INTERRUPTS; if(WaitInterrupt) { AddCycles(1); return; } SavePC = PC; Opcode = OpRead(PC++); switch(Opcode) { #include "Dead63701switch.cpp" #include "../dead6800/Dead6800switch.cpp" } AddCycles(c63701Cycles[Opcode]); }
virtual void AddMapCycles(unsigned int num) { AddCycles(num); }
bool CCpu::SingleStep() { ServiceInterruptRequest(); //Save incoming PC to compare with the outgoing one. If they are identical //this indicates a "halt" instruction. TUint16 incommingPc = iRegMap.iPC; //Read the instruction, and decode the op code. TUint16 inst = iMemMap[iRegMap.iPC++]; TUint op = Decode::BasicOpCode(inst); //All opcodes need to read and/or write operand A. TUint16& a = Decode::OperandA(iRegMap, iMemMap, Decode::A(inst)); if(op != Decode::EOpCodeSPECIAL) { //All basic instructions need to read A and read and/or write B. TUint16& b = Decode::OperandB(iRegMap, iMemMap, Decode::B(inst)); switch(op) { case Decode::EOpCodeSET: { b = a; AddCycles(1); break; } case Decode::EOpCodeADD: { TUint32 u32 = TUint32(b) + TUint32(a); b = TUint16(u32 & 0xffff); iRegMap.iEX = TUint16(u32 >> 16); AddCycles(2); break; } case Decode::EOpCodeSUB: { TUint32 u32 = TUint32(b) - TUint32(a); b = TUint16(u32 & 0xffff); iRegMap.iEX = TUint16(u32 >> 16); AddCycles(2); break; } case Decode::EOpCodeMUL: { TUint32 u32 = TUint32(b) * TUint32(a); b = TUint16(u32 & 0xffff); iRegMap.iEX = TUint16(u32 >> 16); AddCycles(2); break; } case Decode::EOpCodeMLI: { TInt32 i32 = TInt32(b) * TInt32(a); b = TUint16(i32 & 0x7fff); iRegMap.iEX = TUint16(i32 >> 16); AddCycles(2); break; } case Decode::EOpCodeDIV: { if(a == 0) { b = 0; iRegMap.iEX = 0; } else { b /= a; iRegMap.iEX = TUint16(((TUint32(b) << 16) / TUint32(a))); } AddCycles(3); break; } case Decode::EOpCodeDVI: { if(a == 0) { b = 0; iRegMap.iEX = 0; } else { TInt32 sa = TInt32(a); TInt32 sb = TInt32(b); b = TUint16(sb / sa); iRegMap.iEX = TUint16((sb << 16) / sa); } AddCycles(3); break; } case Decode::EOpCodeMOD: { if(a == 0) { b = 0; } else { b = TUint16(TInt32(b) % TInt32(a)); } AddCycles(3); break; } case Decode::EOpCodeMDI: { if(a == 0) { b = 0; } else { b = TUint16(TInt32(b) % TInt32(a)); } AddCycles(3); break; } case Decode::EOpCodeAND: { b &= a; AddCycles(1); break; } case Decode::EOpCodeBOR: { b |= a; AddCycles(1); break; } case Decode::EOpCodeXOR: { b ^= a; AddCycles(1); break; } case Decode::EOpCodeSHR: { b >>= a; iRegMap.iEX = TUint16(((TUint32(b) << 16) >> TUint32(a))); AddCycles(1); break; } case Decode::EOpCodeASR: { TInt32 sb = TInt32(b); b = TUint16(sb >> a); iRegMap.iEX = TUint16((TInt32(sb) << 16) >> TUint32(a)); AddCycles(1); break; } case Decode::EOpCodeSHL: { TUint32 u32 = TUint32(b) << TUint32(a); b = TUint16(u32 & 0xffff); iRegMap.iEX = TUint16(u32 >> 16); AddCycles(1); break; } case Decode::EOpCodeIFB: { if((b & a) == 0) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFC: { if((b & a) != 0) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFE: { if(b != a) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFN: { if(b == a) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFG: { if(b <= a) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFA: { if(TInt32(b) <= TInt32(a)) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFL: { if(b >= a) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeIFU: { if(TInt32(b) >= TInt32(a)) { SkipInstructions(); } AddCycles(2); break; } case Decode::EOpCodeADX: { TUint32 u32 = TUint32(b) + TUint32(a) + TUint32(iRegMap.iEX); b = TUint16(u32 & 0xffff); iRegMap.iEX = TUint16(u32 >> 16); AddCycles(3); break; } case Decode::EOpCodeSBX: { TUint32 u32 = TUint32(b) - TUint32(a) + TUint32(iRegMap.iEX); b = TUint16(u32 & 0xffff); iRegMap.iEX = TUint16(u32 >> 16); AddCycles(3); break; } case Decode::EOpCodeSTI: { b = a; iRegMap.iI++; iRegMap.iJ++; AddCycles(2); break; } case Decode::EOpCodeSTD: { b = a; iRegMap.iI--; iRegMap.iJ--; AddCycles(2); break; } default: assert("Unknown basic op code" && false); } }
/*==================================================================== word Z80Run( Z80 *regs, int numopcodes ) This function does the whole Z80 simulation. It consists on a for(;;) loop (as stated on Marat's Fayzullin HOWTO -How to Write a Computer Emulator-) which fetchs the next opcode, interprets it (using a switch statement) and then it's executed in the right CASE: of that switch. I've put the different case statements into C files included here with #include to make this more readable (and programming easier! :). This function will change regs->ICount register and will execute an interrupt when it reaches 0 (or <0). You can then do anything related to your machine emulation here, using the Z80Hardware() function. This function must be filled by yourself: put there the code related to the emulated machine hardware, such as screen redrawing, sound playing and so on. This functions can return an special value to make Z80Run stop the emulation (and return to the caller): that's INT_QUIT. If there is time to execute an interrupt, please return INT_IRQ or INT_NMI. Return INT_NOINT if there is no time for an interrupt :) . Z80Execute() will change PC and all the z80 registers acording to the executed opcode, and those values will be returned when a INT_QUIT is received. Pass as numcycles the number of clock cycle you want to execute z80 opcodes for or < 0 (negative) to execute "infinite" opcodes. ===================================================================*/ word ExecZ80 (Z80 * regs, int numcycles) { /* opcode and temp variables */ register byte opcode; eword tmpreg, ops, mread, tmpreg2; unsigned long tempdword; register int loop; unsigned short tempword; /* emulate <numcycles> cycles */ loop = (regs->ICount - numcycles); /* this is the emulation main loop */ while (regs->ICount > loop) { #ifdef DEBUG /* test if we have reached the trap address */ if (regs->PC.W == regs->TrapAddress && regs->dobreak != 0) return (regs->PC.W); #endif if (regs->halted == 1) { r_PC--; AddCycles (4); } /* read the opcode from memory (pointed by PC) */ opcode = Z80ReadMem (regs->PC.W); regs->PC.W++; /* increment the R register and decode the instruction */ AddR (1); switch (opcode) { #include "opcodes.h" case PREFIX_CB: AddR (1); #include "op_cb.h" break; case PREFIX_ED: AddR (1); #include "op_ed.h" break; case PREFIX_DD: case PREFIX_FD: AddR (1); if (opcode == PREFIX_DD) { #define REGISTER regs->IX regs->we_are_on_ddfd = WE_ARE_ON_DD; #include "op_dd_fd.h" #undef REGISTER } else { #define REGISTER regs->IY regs->we_are_on_ddfd = WE_ARE_ON_FD; #include "op_dd_fd.h" #undef REGISTER } regs->we_are_on_ddfd = 0; break; } /* patch ROM loading routine */ // address contributed by Ignacio Burgue�o :) // if( r_PC == 0x0569 ) if (r_PC >= 0x0556 && r_PC <= 0x056c) Z80Patch (regs); /* check if it's time to do other hardware emulation */ if (regs->ICount <= 0) { // if (regs->petint==1) { regs->petint=0; /* tmpreg.W = Z80Hardware (regs); */ //Z80Hardware alwais return INT_NOINT regs->ICount += regs->IPeriod; loop = regs->ICount + loop; /* check if we must exit the emulation or there is an INT */ /* if (tmpreg.W == INT_QUIT) return (regs->PC.W); if (tmpreg.W != INT_NOINT) */ Z80Interrupt (regs, tmpreg.W); } } return (regs->PC.W); }