/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * * 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 */ #include #include "types.h" #include "x6502.h" #include "fceu.h" #include "sound.h" //mbg merge 6/29/06 #include "debugger.h" //bbit edited: line added #include "tracer.h" //bbit edited: line added #include "memview.h" //bbit edited: line added #include "cdlogger.h" X6502 X; //mbg merge 7/19/06 //#ifdef FCEUDEF_DEBUGGER //void (*X6502_Run)(int32 cycles); //#endif uint32 timestamp; void FP_FASTAPASS(1) (*MapIRQHook)(int a); #define _PC X.PC #define _A X.A #define _X X.X #define _Y X.Y #define _S X.S #define _P X.P #define _PI X.mooPI #define _DB X.DB #define _count X.count #define _tcount X.tcount #define _IRQlow X.IRQlow #define _jammed X.jammed //------- //mbg merge 6/29/06 //bbit edited: a large portion of code was inserted from here on down extern uint8 *XBuf; //extern void FCEUD_BlitScreen(uint8 *XBuf); void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count); //mbg merge 6/30/06 - do this instead static int indirectnext; static INLINE void BreakHit() { DoDebug(1); FCEUI_SetEmulationPaused(1); //mbg merge 7/19/06 changed to use EmulationPaused() //if((!logtofile) && (logging))PauseLoggingSequence(); UpdateLogWindow(); if(hMemView)UpdateMemoryView(0); //mbg merge 6/30/06 - this architecture has changed FCEUD_Update(0,0,0); //FCEUD_BlitScreen(XBuf+8); //this looks odd, I know. but the pause routine is in here!! //if(logging)LogInstruction(); //logging might have been started while we were paused } static INLINE void LogCDVectors(int which){ int i = 0xFFFA+(which*2); int j; j = GetPRGAddress(i); if(j == -1){ return; } if(cdloggerdata[j] == 0){ cdloggerdata[j] |= 0x0E; // we're in the last bank and recording it as data so 0x1110 or 0xE should be what we need datacount++; undefinedcount--; } j++; if(cdloggerdata[j] == 0){ cdloggerdata[j] |= 0x0E; // we're in the last bank and recording it as data so 0x1110 or 0xE should be what we need datacount++; undefinedcount--; } return; } /* //very ineffecient, but this shouldn't get executed THAT much if(!(cdloggerdata[GetPRGAddress(0xFFFA)] & 2)){ cdloggerdata[GetPRGAddress(0xFFFA)]|=2; codecount++; undefinedcount--; } if(!(cdloggerdata[GetPRGAddress(0xFFFB)] & 2)){ cdloggerdata[GetPRGAddress(0xFFFB)]|=2; codecount++; undefinedcount--; } if(!(cdloggerdata[GetPRGAddress(0xFFFC)] & 2)){ cdloggerdata[GetPRGAddress(0xFFFC)]|=2; codecount++; undefinedcount--; } if(!(cdloggerdata[GetPRGAddress(0xFFFD)] & 2)){ cdloggerdata[GetPRGAddress(0xFFFD)]|=2; codecount++; undefinedcount--; } if(!(cdloggerdata[GetPRGAddress(0xFFFE)] & 2)){ cdloggerdata[GetPRGAddress(0xFFFE)]|=2; codecount++; undefinedcount--; } if(!(cdloggerdata[GetPRGAddress(0xFFFF)] & 2)){ cdloggerdata[GetPRGAddress(0xFFFF)]|=2; codecount++; undefinedcount--; } return; } */ static INLINE void LogCDData(){ int i, j; uint16 A=0; uint8 opcode[3] = {0}; j = GetPRGAddress(_PC); opcode[0] = GetMem(_PC); for (i = 1; i < opsize[opcode[0]]; i++) opcode[i] = GetMem(_PC+i); if(j != -1){ for (i = 0; i < opsize[opcode[0]]; i++){ if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip cdloggerdata[j+i] |= 1; cdloggerdata[j+i] |=((_PC+i)>>11)&12; if(indirectnext)cdloggerdata[j+i] |= 0x10; codecount++; if(!(cdloggerdata[j+i] & 0x42))undefinedcount--; } } indirectnext = 0; //log instruction jumped to in an indirect jump if(opcode[0] == 0x6c){ indirectnext = 1; } switch (optype[opcode[0]]) { case 0: break; case 1: A = (opcode[1]+_X) & 0xFF; A = GetMem(A) | (GetMem(A+1))<<8; break; case 2: A = opcode[1]; break; case 3: A = opcode[1] | opcode[2]<<8; break; case 4: A = (GetMem(opcode[1]) | (GetMem(opcode[1]+1))<<8)+_Y; break; case 5: A = opcode[1]+_X; break; case 6: A = (opcode[1] | opcode[2]<<8)+_Y; break; case 7: A = (opcode[1] | opcode[2]<<8)+_X; break; case 8: A = opcode[1]+_Y; break; } //if(opbrktype[opcode[0]] != WP_R)return; //we only want reads if((j = GetPRGAddress(A)) == -1)return; //if(j == 0)BreakHit(); if(cdloggerdata[j] & 2)return; cdloggerdata[j] |= 2; cdloggerdata[j] |=((A/*+i*/)>>11)&12; if((optype[opcode[0]] == 1) || (optype[opcode[0]] == 4))cdloggerdata[j] |= 0x20; datacount++; if(!(cdloggerdata[j+i] & 1))undefinedcount--; return; } // ################################## Start of SP CODE ########################### // Returns the value of a given type or register int getValue(int type) { switch (type) { case 'A': return _A; case 'X': return _X; case 'Y': return _Y; case 'N': return _P & N_FLAG ? 1 : 0; case 'V': return _P & V_FLAG ? 1 : 0; case 'U': return _P & U_FLAG ? 1 : 0; case 'B': return _P & B_FLAG ? 1 : 0; case 'D': return _P & D_FLAG ? 1 : 0; case 'I': return _P & I_FLAG ? 1 : 0; case 'Z': return _P & Z_FLAG ? 1 : 0; case 'C': return _P & C_FLAG ? 1 : 0; case 'P': return _PC; } return 0; } // Evaluates a condition int evaluate(Condition* c) { int f = 0; int value1, value2; if (c->lhs) { value1 = evaluate(c->lhs); } else { switch(c->type1) { case TYPE_ADDR: case TYPE_NUM: value1 = c->value1; break; default: value1 = getValue(c->value1); } } if (c->type1 == TYPE_ADDR) { value1 = GetMem(value1); } f = value1; if (c->op) { if (c->rhs) { value2 = evaluate(c->rhs); } else { switch(c->type2) { case TYPE_ADDR: case TYPE_NUM: value2 = c->value2; break; default: value2 = getValue(c->type2); } } if (c->type2 == TYPE_ADDR) { value2 = GetMem(value2); } switch (c->op) { case OP_EQ: f = value1 == value2; break; case OP_NE: f = value1 != value2; break; case OP_GE: f = value1 >= value2; break; case OP_LE: f = value1 <= value2; break; case OP_G: f = value1 > value2; break; case OP_L: f = value1 < value2; break; case OP_MULT: f = value1 * value2; break; case OP_DIV: f = value1 / value2; break; case OP_PLUS: f = value1 + value2; break; case OP_MINUS: f = value1 - value2; break; case OP_OR: f = value1 || value2; break; case OP_AND: f = value1 && value2; break; } } return f; } int condition(watchpointinfo* wp) { return wp->cond == 0 || evaluate(wp->cond); } // ################################## End of SP CODE ########################### //extern int step; //extern int stepout; //extern int jsrcount; void breakpoint() { int i; uint16 A=0; uint8 brk_type,opcode[3] = {0}; opcode[0] = GetMem(_PC); if(badopbreak && (opsize[opcode[0]] == 0))BreakHit(); if (stepout) { if (opcode[0] == 0x20) jsrcount++; else if (opcode[0] == 0x60) { if (jsrcount) jsrcount--; else { stepout = 0; step = 1; return; } } } if (step) { step = 0; BreakHit(); return; } if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) { watchpoint[64].address = 0; watchpoint[64].flags = 0; BreakHit(); return; } for (i = 1; i < opsize[opcode[0]]; i++) opcode[i] = GetMem(_PC+i); brk_type = opbrktype[opcode[0]] | WP_X; switch (optype[opcode[0]]) { case 0: /*A = _PC;*/ break; case 1: A = (opcode[1]+_X) & 0xFF; A = GetMem(A) | (GetMem(A+1))<<8; break; case 2: A = opcode[1]; break; case 3: A = opcode[1] | opcode[2]<<8; break; case 4: A = (GetMem(opcode[1]) | (GetMem(opcode[1]+1))<<8)+_Y; break; case 5: A = opcode[1]+_X; break; case 6: A = (opcode[1] | opcode[2]<<8)+_Y; break; case 7: A = (opcode[1] | opcode[2]<<8)+_X; break; case 8: A = opcode[1]+_Y; break; } for (i = 0; i < numWPs; i++) { // ################################## Start of SP CODE ########################### if (condition(&watchpoint[i])) { // ################################## End of SP CODE ########################### if (watchpoint[i].flags & BT_P) { //PPU Mem breaks if ((watchpoint[i].flags & WP_E) && (watchpoint[i].flags & brk_type) && ((A >= 0x2000) && (A < 0x4000)) && ((A&7) == 7)) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= RefreshAddr) && (watchpoint[i].endaddress >= RefreshAddr)) BreakHit(); } else if (watchpoint[i].address == RefreshAddr) BreakHit(); } } else if (watchpoint[i].flags & BT_S) { //Sprite Mem breaks if ((watchpoint[i].flags & WP_E) && (watchpoint[i].flags & brk_type) && ((A >= 0x2000) && (A < 0x4000)) && ((A&7) == 4)) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= PPU[3]) && (watchpoint[i].endaddress >= PPU[3])) BreakHit(); } else if (watchpoint[i].address == PPU[3]) BreakHit(); } else if ((watchpoint[i].flags & WP_E) && (watchpoint[i].flags & WP_W) && (A == 0x4014)) BreakHit(); //Sprite DMA! :P } else { //CPU mem breaks if ((watchpoint[i].flags & WP_E) && (watchpoint[i].flags & brk_type)) { if (watchpoint[i].endaddress) { if (((!(watchpoint[i].flags & WP_X)) && (watchpoint[i].address <= A) && (watchpoint[i].endaddress >= A)) || ((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC))) BreakHit(); } else if (((!(watchpoint[i].flags & WP_X)) && (watchpoint[i].address == A)) || ((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC))) BreakHit(); } } // ################################## Start of SP CODE ########################### } // ################################## End of SP CODE ########################### } } //bbit edited: this is the end of the inserted code #define ADDCYC(x) \ { \ int __x=x; \ _tcount+=__x; \ _count-=__x*48; \ timestamp+=__x; \ } //mbg 6/30/06 - hooked functions arent being used right now ////hooked memory read //static INLINE uint8 RdMemHook(unsigned int A) //{ // if(X.ReadHook) // return(_DB = X.ReadHook(&X,A) ); // else // return(_DB=ARead[A](A)); //} // ////hooked memory write //static INLINE void WrMemHook(unsigned int A, uint8 V) //{ // if(X.WriteHook) // X.WriteHook(&X,A,V); // else // BWrite[A](A,V); //} //#define RdRAMFast(A) (_DB=RAM[(A)]) //#define WrRAMFast(A,V) RAM[(A)]=(V) //normal memory read static INLINE uint8 RdMemNorm(unsigned int A) { return(_DB=ARead[A](A)); } //normal memory write static INLINE void WrMemNorm(unsigned int A, uint8 V) { BWrite[A](A,V); } static INLINE uint8 RdRAMNorm(unsigned int A) { //bbit edited: this was changed so cheat substituion would work return(_DB=ARead[A](A)); // return(_DB=RAM[A]); } static INLINE void WrRAMNorm(unsigned int A, uint8 V) { RAM[A]=V; } uint8 FASTAPASS(1) X6502_DMR(uint32 A) { ADDCYC(1); return(X.DB=ARead[A](A)); } void FASTAPASS(2) X6502_DMW(uint32 A, uint8 V) { ADDCYC(1); BWrite[A](A,V); } #define PUSH(V) \ { \ uint8 VTMP=V; \ WrRAM(0x100+_S,VTMP); \ _S--; \ } #define POP() RdRAM(0x100+(++_S)) static uint8 ZNTable[256]; /* Some of these operations will only make sense if you know what the flag constants are. */ #define X_ZN(zort) _P&=~(Z_FLAG|N_FLAG);_P|=ZNTable[zort] #define X_ZNT(zort) _P|=ZNTable[zort] #define JR(cond); \ { \ if(cond) \ { \ uint32 tmp; \ int32 disp; \ disp=(int8)RdMem(_PC); \ _PC++; \ ADDCYC(1); \ tmp=_PC; \ _PC+=disp; \ if((tmp^_PC)&0x100) \ ADDCYC(1); \ } \ else _PC++; \ } #define LDA _A=x;X_ZN(_A) #define LDX _X=x;X_ZN(_X) #define LDY _Y=x;X_ZN(_Y) /* All of the freaky arithmetic operations. */ #define AND _A&=x;X_ZN(_A) #define BIT _P&=~(Z_FLAG|V_FLAG|N_FLAG);_P|=ZNTable[x&_A]&Z_FLAG;_P|=x&(V_FLAG|N_FLAG) #define EOR _A^=x;X_ZN(_A) #define ORA _A|=x;X_ZN(_A) #define ADC { \ uint32 l=_A+x+(_P&1); \ _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \ _P|=((((_A^x)&0x80)^0x80) & ((_A^l)&0x80))>>1; \ _P|=(l>>8)&C_FLAG; \ _A=l; \ X_ZNT(_A); \ } #define SBC { \ uint32 l=_A-x-((_P&1)^1); \ _P&=~(Z_FLAG|C_FLAG|N_FLAG|V_FLAG); \ _P|=((_A^l)&(_A^x)&0x80)>>1; \ _P|=((l>>8)&C_FLAG)^C_FLAG; \ _A=l; \ X_ZNT(_A); \ } #define CMPL(a1,a2) { \ uint32 t=a1-a2; \ X_ZN(t&0xFF); \ _P&=~C_FLAG; \ _P|=((t>>8)&C_FLAG)^C_FLAG; \ } /* Special undocumented operation. Very similar to CMP. */ #define AXS { \ uint32 t=(_A&_X)-x; \ X_ZN(t&0xFF); \ _P&=~C_FLAG; \ _P|=((t>>8)&C_FLAG)^C_FLAG; \ _X=t; \ } #define CMP CMPL(_A,x) #define CPX CMPL(_X,x) #define CPY CMPL(_Y,x) /* The following operations modify the byte being worked on. */ #define DEC x--;X_ZN(x) #define INC x++;X_ZN(x) #define ASL _P&=~C_FLAG;_P|=x>>7;x<<=1;X_ZN(x) #define LSR _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=x&1;x>>=1;X_ZNT(x) /* For undocumented instructions, maybe for other things later... */ #define LSRA _P&=~(C_FLAG|N_FLAG|Z_FLAG);_P|=_A&1;_A>>=1;X_ZNT(_A) #define ROL { \ uint8 l=x>>7; \ x<<=1; \ x|=_P&C_FLAG; \ _P&=~(Z_FLAG|N_FLAG|C_FLAG); \ _P|=l; \ X_ZNT(x); \ } #define ROR { \ uint8 l=x&1; \ x>>=1; \ x|=(_P&C_FLAG)<<7; \ _P&=~(Z_FLAG|N_FLAG|C_FLAG); \ _P|=l; \ X_ZNT(x); \ } /* Icky icky thing for some undocumented instructions. Can easily be broken if names of local variables are changed. */ /* Absolute */ #define GetAB(target) \ { \ target=RdMem(_PC); \ _PC++; \ target|=RdMem(_PC)<<8; \ _PC++; \ } /* Absolute Indexed(for reads) */ #define GetABIRD(target, i) \ { \ unsigned int tmp; \ GetAB(tmp); \ target=tmp; \ target+=i; \ if((target^tmp)&0x100) \ { \ target&=0xFFFF; \ RdMem(target^0x100); \ ADDCYC(1); \ } \ } /* Absolute Indexed(for writes and rmws) */ #define GetABIWR(target, i) \ { \ unsigned int rt; \ GetAB(rt); \ target=rt; \ target+=i; \ target&=0xFFFF; \ RdMem((target&0x00FF)|(rt&0xFF00)); \ } /* Zero Page */ #define GetZP(target) \ { \ target=RdMem(_PC); \ _PC++; \ } /* Zero Page Indexed */ #define GetZPI(target,i) \ { \ target=i+RdMem(_PC); \ _PC++; \ } /* Indexed Indirect */ #define GetIX(target) \ { \ uint8 tmp; \ tmp=RdMem(_PC); \ _PC++; \ tmp+=_X; \ target=RdRAM(tmp); \ tmp++; \ target|=RdRAM(tmp)<<8; \ } /* Indirect Indexed(for reads) */ #define GetIYRD(target) \ { \ unsigned int rt; \ uint8 tmp; \ tmp=RdMem(_PC); \ _PC++; \ rt=RdRAM(tmp); \ tmp++; \ rt|=RdRAM(tmp)<<8; \ target=rt; \ target+=_Y; \ if((target^rt)&0x100) \ { \ target&=0xFFFF; \ RdMem(target^0x100); \ ADDCYC(1); \ } \ } /* Indirect Indexed(for writes and rmws) */ #define GetIYWR(target) \ { \ unsigned int rt; \ uint8 tmp; \ tmp=RdMem(_PC); \ _PC++; \ rt=RdRAM(tmp); \ tmp++; \ rt|=RdRAM(tmp)<<8; \ target=rt; \ target+=_Y; \ target&=0xFFFF; \ RdMem((target&0x00FF)|(rt&0xFF00)); \ } /* Now come the macros to wrap up all of the above stuff addressing mode functions and operation macros. Note that operation macros will always operate(redundant redundant) on the variable "x". */ #define RMW_A(op) {uint8 x=_A; op; _A=x; break; } /* Meh... */ #define RMW_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; } #define RMW_ABI(reg,op) {unsigned int A; uint8 x; GetABIWR(A,reg); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; } #define RMW_ABX(op) RMW_ABI(_X,op) #define RMW_ABY(op) RMW_ABI(_Y,op) #define RMW_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; } #define RMW_IY(op) {unsigned int A; uint8 x; GetIYWR(A); x=RdMem(A); WrMem(A,x); op; WrMem(A,x); break; } #define RMW_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; WrRAM(A,x); break; } #define RMW_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; WrRAM(A,x); break;} #define LD_IM(op) {uint8 x; x=RdMem(_PC); _PC++; op; break;} #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;} #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;} #define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;} #define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; } #define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;} #define LD_ABX(op) LD_ABI(_X,op) #define LD_ABY(op) LD_ABI(_Y,op) #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;} #define LD_IY(op) {unsigned int A; uint8 x; GetIYRD(A); x=RdMem(A); op; break;} #define ST_ZP(r) {uint8 A; GetZP(A); WrRAM(A,r); break;} #define ST_ZPX(r) {uint8 A; GetZPI(A,_X); WrRAM(A,r); break;} #define ST_ZPY(r) {uint8 A; GetZPI(A,_Y); WrRAM(A,r); break;} #define ST_AB(r) {unsigned int A; GetAB(A); WrMem(A,r); break;} #define ST_ABI(reg,r) {unsigned int A; GetABIWR(A,reg); WrMem(A,r); break; } #define ST_ABX(r) ST_ABI(_X,r) #define ST_ABY(r) ST_ABI(_Y,r) #define ST_IX(r) {unsigned int A; GetIX(A); WrMem(A,r); break; } #define ST_IY(r) {unsigned int A; GetIYWR(A); WrMem(A,r); break; } static uint8 CycTable[256] = { /*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6, /*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, /*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6, /*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, /*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6, /*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, /*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6, /*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, /*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, /*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5, /*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, /*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4, /*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, /*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, /*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6, /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, }; void FASTAPASS(1) X6502_IRQBegin(int w) { _IRQlow|=w; } void FASTAPASS(1) X6502_IRQEnd(int w) { _IRQlow&=~w; } void TriggerNMI(void) { _IRQlow|=FCEU_IQNMI; } void TriggerNMI2(void) { _IRQlow|=FCEU_IQNMI2; } #ifdef FCEUDEF_DEBUGGER /* Called from debugger. */ void FCEUI_NMI(void) { _IRQlow|=FCEU_IQNMI; } void FCEUI_IRQ(void) { _IRQlow|=FCEU_IQTEMP; } void FCEUI_GetIVectors(uint16 *reset, uint16 *irq, uint16 *nmi) { fceuindbg=1; *reset=RdMemNorm(0xFFFC); *reset|=RdMemNorm(0xFFFD)<<8; *nmi=RdMemNorm(0xFFFA); *nmi|=RdMemNorm(0xFFFB)<<8; *irq=RdMemNorm(0xFFFE); *irq|=RdMemNorm(0xFFFF)<<8; fceuindbg=0; } static int debugmode; #endif void X6502_Reset(void) { _IRQlow=FCEU_IQRESET; } void X6502_Init(void) { int x; memset((void *)&X,0,sizeof(X)); for(x=0;x<256;x++) if(!x) ZNTable[x]=Z_FLAG; else if(x&0x80) ZNTable[x]=N_FLAG; else ZNTable[x]=0; #ifdef FCEUDEF_DEBUGGER X6502_Debug(0,0,0); #endif } void X6502_Power(void) { _count=_tcount=_IRQlow=_PC=_A=_X=_Y=_S=_P=_PI=_DB=_jammed=0; timestamp=0; X6502_Reset(); } //mbg 6/30/06 merge - this function reworked significantly for merge void X6502_Run(int32 cycles) { #define RdRAM RdRAMNorm #define WrRAM WrRAMNorm #define RdMem RdMemNorm #define WrMem WrMemNorm if(PAL) cycles*=15; // 15*4=60 else cycles*=16; // 16*4=64 _count+=cycles; while(_count>0) { int32 temp; uint8 b1; if(_IRQlow) { if(_IRQlow&FCEU_IQRESET) { if(loggingcodedata)LogCDVectors(0); _PC=RdMem(0xFFFC); _PC|=RdMem(0xFFFD)<<8; _jammed=0; _PI=_P=I_FLAG; _IRQlow&=~FCEU_IQRESET; } else if(_IRQlow&FCEU_IQNMI2) { _IRQlow&=~FCEU_IQNMI2; _IRQlow|=FCEU_IQNMI; } else if(_IRQlow&FCEU_IQNMI) { if(!_jammed) { ADDCYC(7); PUSH(_PC>>8); PUSH(_PC); PUSH((_P&~B_FLAG)|(U_FLAG)); _P|=I_FLAG; if(loggingcodedata)LogCDVectors(1); _PC=RdMem(0xFFFA); _PC|=RdMem(0xFFFB)<<8; _IRQlow&=~FCEU_IQNMI; } } else { if(!(_PI&I_FLAG) && !_jammed) { ADDCYC(7); PUSH(_PC>>8); PUSH(_PC); PUSH((_P&~B_FLAG)|(U_FLAG)); _P|=I_FLAG; if(loggingcodedata)LogCDVectors(1); _PC=RdMem(0xFFFE); _PC|=RdMem(0xFFFF)<<8; } } _IRQlow&=~(FCEU_IQTEMP); if(_count<=0) { _PI=_P; return; } //Should increase accuracy without a //major speed hit. } //will probably cause a major speed decrease on low-end systems //bbit edited: this line added if (numWPs | step | stepout | watchpoint[64].flags | badopbreak) breakpoint(); if(loggingcodedata)LogCDData(); //mbg 6/30/06 - this was commented out when i got here. i dont understand it anyway //if(logging || (hMemView && (EditingMode == 2))) LogInstruction(); if(logging) LogInstruction(); //--- _PI=_P; b1=RdMem(_PC); ADDCYC(CycTable[b1]); temp=_tcount; _tcount=0; if(MapIRQHook) MapIRQHook(temp); FCEU_SoundCPUHook(temp); _PC++; switch(b1) { #include "ops.h" } } #undef RdRAM #undef WrRAM #undef RdMem #undef WrMem } void X6502_Debug(void (*CPUHook)(X6502 *), uint8 (*ReadHook)(X6502 *, unsigned int), void (*WriteHook)(X6502 *, unsigned int, uint8)) { //mbg 6/30/06 - stubbed out because we don't support the hooked cpu //debugmode=(ReadHook || WriteHook || CPUHook)?1:0; //X.ReadHook=ReadHook; //X.WriteHook=WriteHook; //X.CPUHook=CPUHook; } //mbg 6/30/06 - the non-hooked cpu core and core switching has been removed to mimic XD. //this could be put back in later /* //#ifdef FCEUDEF_DEBUGGER //X6502 XSave; // This is getting ugly. //#define RdMemHook(A) ( X.ReadHook?(_DB=X.ReadHook(&X,A)):(_DB=ARead[A](A)) ) //#define WrMemHook(A,V) { if(X.WriteHook) X.WriteHook(&X,A,V); else BWrite[A](A,V); } #ifdef FCEUDEF_DEBUGGER void (*X6502_Run)(int32 cycles); #endif #ifdef FCEUDEF_DEBUGGER static void X6502_RunDebug(int32 cycles) { #define RdRAM RdMemHook #define WrRAM WrMemHook #define RdMem RdMemHook #define WrMem WrMemHook if(PAL) cycles*=15; // 15*4=60 else cycles*=16; // 16*4=64 _count+=cycles; while(_count>0) { int32 temp; uint8 b1; if(_IRQlow) { if(_IRQlow&FCEU_IQRESET) { _PC=RdMem(0xFFFC); _PC|=RdMem(0xFFFD)<<8; _jammed=0; _PI=_P=I_FLAG; _IRQlow&=~FCEU_IQRESET; } else if(_IRQlow&FCEU_IQNMI2) { _IRQlow&=~FCEU_IQNMI2; _IRQlow|=FCEU_IQNMI; } else if(_IRQlow&FCEU_IQNMI) { if(!_jammed) { ADDCYC(7); PUSH(_PC>>8); PUSH(_PC); PUSH((_P&~B_FLAG)|(U_FLAG)); _P|=I_FLAG; if(loggingcodedata)LogCDVectors(1); //mbg 6/29/06 _PC=RdMem(0xFFFA); _PC|=RdMem(0xFFFB)<<8; _IRQlow&=~FCEU_IQNMI; } } else { if(!(_PI&I_FLAG) && !_jammed) { ADDCYC(7); PUSH(_PC>>8); PUSH(_PC); PUSH((_P&~B_FLAG)|(U_FLAG)); _P|=I_FLAG; if(loggingcodedata)LogCDVectors(1); //mbg 6/29/06 _PC=RdMem(0xFFFE); _PC|=RdMem(0xFFFF)<<8; } } _IRQlow&=~(FCEU_IQTEMP); if(_count<=0) { _PI=_P; return; } //Should increase accuracy without a //major speed hit. } //--- //mbg merge 6/29/06 //will probably cause a major speed decrease on low-end systems if (numWPs | step | stepout | watchpoint[64].flags | badopbreak) breakpoint(); //bbit edited: this line added if(loggingcodedata)LogCDData(); if(logging //|| (hMemView && (EditingMode == 2)) )LogInstruction(); //--- if(X.CPUHook) X.CPUHook(&X); //Ok, now the real fun starts. //Do the pre-exec voodoo. if(X.ReadHook || X.WriteHook) { uint32 tsave=timestamp; XSave=X; fceuindbg=1; X.preexec=1; b1=RdMem(_PC); _PC++; switch(b1) { #include "ops.h" } timestamp=tsave; //In case an NMI/IRQ/RESET was triggered by the debugger. //Should we also copy over the other hook variables? XSave.IRQlow=X.IRQlow; XSave.ReadHook=X.ReadHook; XSave.WriteHook=X.WriteHook; XSave.CPUHook=X.CPUHook; X=XSave; fceuindbg=0; } _PI=_P; b1=RdMem(_PC); ADDCYC(CycTable[b1]); temp=_tcount; _tcount=0; if(MapIRQHook) MapIRQHook(temp); FCEU_SoundCPUHook(temp); _PC++; switch(b1) { #include "ops.h" } } #undef RdRAM #undef WrRAM #undef RdMem #undef WrMem } static void X6502_RunNormal(int32 cycles) #else void X6502_Run(int32 cycles) #endif { #define RdRAM RdRAMFast #define WrRAM WrRAMFast #define RdMem RdMemNorm #define WrMem WrMemNorm //#if(defined(C80x86) && defined(__GNUC__)) //// Gives a nice little speed boost. //register uint16 pbackus asm ("edi"); //#else //uint16 pbackus; //#endif //pbackus=_PC; //#undef _PC //#define _PC pbackus if(PAL) cycles*=15; // 15*4=60 else cycles*=16; // 16*4=64 _count+=cycles; while(_count>0) { int32 temp; uint8 b1; // XI.PC=pbackus; if(_IRQlow) { if(_IRQlow&FCEU_IQRESET) { _PC=RdMem(0xFFFC); _PC|=RdMem(0xFFFD)<<8; _jammed=0; _PI=_P=I_FLAG; _IRQlow&=~FCEU_IQRESET; } else if(_IRQlow&FCEU_IQNMI2) { _IRQlow&=~FCEU_IQNMI2; _IRQlow|=FCEU_IQNMI; } else if(_IRQlow&FCEU_IQNMI) { if(!_jammed) { ADDCYC(7); PUSH(_PC>>8); PUSH(_PC); PUSH((_P&~B_FLAG)|(U_FLAG)); _P|=I_FLAG; if(loggingcodedata)LogCDVectors(1); //mbg 6/29/06 _PC=RdMem(0xFFFA); _PC|=RdMem(0xFFFB)<<8; _IRQlow&=~FCEU_IQNMI; } } else { if(!(_PI&I_FLAG) && !_jammed) { ADDCYC(7); PUSH(_PC>>8); PUSH(_PC); PUSH((_P&~B_FLAG)|(U_FLAG)); _P|=I_FLAG; if(loggingcodedata)LogCDVectors(1); //mbg 6/29/06 _PC=RdMem(0xFFFE); _PC|=RdMem(0xFFFF)<<8; } } _IRQlow&=~(FCEU_IQTEMP); if(_count<=0) { _PI=_P; //X.PC=pbackus; return; } //Should increase accuracy without a //major speed hit. } //--- //mbg merge 6/29/06 //will probably cause a major speed decrease on low-end systems if (numWPs | step | stepout | watchpoint[64].flags | badopbreak) breakpoint(); //bbit edited: this line added if(loggingcodedata)LogCDData(); if(logging // || (hMemView && (EditingMode == 2)) ) LogInstruction(); //--- _PI=_P; b1=RdMem(_PC); ADDCYC(CycTable[b1]); temp=_tcount; _tcount=0; if(MapIRQHook) MapIRQHook(temp); FCEU_SoundCPUHook(temp); //X.PC=pbackus; _PC++; switch(b1) { #include "ops.h" } } //#undef _PC //#define _PC X.PC //_PC=pbackus; //#undef RdRAM #undef WrRAM } #ifdef FCEUDEF_DEBUGGER void X6502_Debug(void (*CPUHook)(X6502 *), uint8 (*ReadHook)(X6502 *, unsigned int), void (*WriteHook)(X6502 *, unsigned int, uint8)) { debugmode=(ReadHook || WriteHook || CPUHook)?1:0; X.ReadHook=ReadHook; X.WriteHook=WriteHook; X.CPUHook=CPUHook; if(!debugmode) X6502_Run=X6502_RunNormal; else X6502_Run=X6502_RunDebug; } #endif*/