www.pudn.com > virtual_gameboy-0.8.8.zip > Z80.C
/** VGB: portable GameBoy emulator ***************************/ /** **/ /** Z80.c **/ /** **/ /** This file contains implementation for the GameBoy CPU. **/ /** See Z80.h for the relevant definitions. Please, note **/ /** that this code can not be used to emulate a generic Z80 **/ /** because the GameBoy version of it differs from Z80 in **/ /** many ways. **/ /** **/ /** Copyright (C) Marat Fayzullin 1994,1995,1996 **/ /** Marcel de Kogel 1996 **/ /** You are not allowed to distribute this software **/ /** commercially. Please, notify me, if you make any **/ /** changes to this file. **/ /*************************************************************/ #include#include #include "GB.h" #include "Tables.h" /*** Registers ***********************************************/ /*** Z80 registers and running flag. ***/ /*************************************************************/ reg R; byte CPURunning; /*** Interrupts **********************************************/ /*** Interrupt-related variables. ***/ /*************************************************************/ int IPeriod = 69905; /* Number of cycles between int. int-s */ int ICount; /* Variable used to count CPU cycles */ /*** Trace and Trap ******************************************/ /*** Switches to turn tracing on and off in DEBUG mode. ***/ /*************************************************************/ #ifdef DEBUG byte Trace=0; /* Tracing is on if Trace==1 */ word Trap=0xFFFF; /* When PC==Trap, set Trace=1 */ #endif /*** TrapBadOps **********************************************/ /*** When 1, print warnings of illegal Z80 instructions. ***/ /*************************************************************/ byte TrapBadOps=0; /* Tables to convert Z80 flags to GB flags and vise versa */ byte Z80toGB[256]; byte GBtoZ80[256]; #define S(Fl) R.AF.B.l|=Fl #define R(Fl) R.AF.B.l&=~(Fl) #define FLAGS(Rg,Fl) R.AF.B.l=Fl|ZTable[Rg]; #define M_RLC(Rg) \ R.AF.B.l=Rg>>7;Rg=(Rg<<1)|R.AF.B.l;R.AF.B.l|=ZTable[Rg] #define M_RRC(Rg) \ R.AF.B.l=Rg&0x01;Rg=(Rg>>1)|(R.AF.B.l<<7);R.AF.B.l|=ZTable[Rg] #define M_RL(Rg) \ if(Rg&0x80) \ { \ Rg=(Rg<<1)|(R.AF.B.l&C_FLAG); \ R.AF.B.l=ZTable[Rg]|C_FLAG; \ } \ else \ { \ Rg=(Rg<<1)|(R.AF.B.l&C_FLAG); \ R.AF.B.l=ZTable[Rg]; \ } #define M_RR(Rg) \ if(Rg&0x01) \ { \ Rg=(Rg>>1)|(R.AF.B.l<<7); \ R.AF.B.l=ZTable[Rg]|C_FLAG; \ } \ else \ { \ Rg=(Rg>>1)|(R.AF.B.l<<7); \ R.AF.B.l=ZTable[Rg]; \ } #define M_SLA(Rg) \ R.AF.B.l=Rg>>7;Rg<<=1;R.AF.B.l|=ZTable[Rg] #define M_SRA(Rg) \ R.AF.B.l=Rg&C_FLAG;Rg=(Rg>>1)|(Rg&0x80);R.AF.B.l|=ZTable[Rg] #define M_SLL(Rg) \ R.AF.B.l=Rg>>7;Rg=(Rg<<1)|0x01;R.AF.B.l|=ZTable[Rg] #define M_SRL(Rg) \ R.AF.B.l=Rg&0x01;Rg>>=1;R.AF.B.l|=ZTable[Rg] #define M_BIT(Bit,Rg) \ R.AF.B.l=(R.AF.B.l&~(N_FLAG|Z_FLAG))|H_FLAG|(Rg&(1< PC.W=0x0100;Regs->SP.W=0xF000; Regs->AF.W=Regs->BC.W=Regs->DE.W=Regs->HL.W=0x0000; Regs->I=0x00;Regs->IFF=0x00; } /*** Interpret Z80 code: **********************************/ /*** Registers have initial values from Regs. PC value ***/ /*** at which emulation stopped is returned by this ***/ /*** function. ***/ /**********************************************************/ word Z80(reg Regs) { byte I; pair J; static int Z80_virgin=1; if (Z80_virgin) { int i,j; for (i=0;i<256;++i) { Cycles[i]<<=8; CyclesCB[i]<<=8; j=(i&0xA0)>>1; /* Z and H flags */ j|=(i&0x40)>>5; /* N flag */ j|=(i&0x10)>>4; /* C flag */ GBtoZ80[i]=j; j=(i&0x50)<<1; /* Z and H flags */ j|=(i&0x02)<<5; /* N flag */ j|=(i&0x01)<<4; /* C flag */ Z80toGB[i]=j; } Z80_virgin=0; } R=Regs;ICount=IPeriod;CPURunning=1; for(;;) { #ifdef DEBUG if(R.PC.W==Trap) Trace=1; /*** Turn tracing on if trapped ***/ if(Trace) Debug(&R); /*** Call single-step debugger ***/ #endif I=M_RDMEM_OPCODE(); ICount-=Cycles[I]; switch(I) { #include "Codes.h" case PFX_CB: CodesCB();break; case 0x10: case HALT: R.PC.W--;R.IFF|=0x80;if (ICount>0) ICount=0; break; default: ICount-=(4<<8); if(TrapBadOps) printf ( "Unrecognized instruction: %X at PC=%hX\n", M_RDMEM(R.PC.W-1),R.PC.W-1 ); } if(ICount<=0) { ICount+=IPeriod; if(!CPURunning) break; J.W=Interrupt(); if((J.W!=0xFFFF)&&(R.IFF&0x81)) { if(R.IFF&0x80) R.PC.W++; IFLAGS&=~IMask;IMask=0x00; R.IFF&=0x7E; M_PUSH(PC);R.PC.W=J.W; } } } return(R.PC.W); }