#include "types.h" #include "x6502.h" #include "fceu.h" #include "cart.h" #include "ines.h" #include "debug.h" #include "driver.h" #include "ppu.h" #include int GetPRGAddress(int A){ unsigned int result; if((A < 0x8000) || (A > 0xFFFF))return -1; result = &Page[A>>11][A]-PRGptr[0]; if((result > PRGsize[0]) || (result < 0))return -1; else return result; } int GetNesFileAddress(int A){ unsigned int result; if((A < 0x8000) || (A > 0xFFFF))return -1; result = &Page[A>>11][A]-PRGptr[0]; if((result > PRGsize[0]) || (result < 0))return -1; else return result+16; //16 bytes for the header remember } int GetRomAddress(int A){ int i; uint8 *p = GetNesPRGPointer(A-=16); for(i = 16;i < 32;i++){ if((&Page[i][i<<11] <= p) && (&Page[i][(i+1)<<11] > p))break; } if(i == 32)return -1; //not found return (i<<11) + (p-&Page[i][i<<11]); } uint8 *GetNesPRGPointer(int A){ return PRGptr[0]+A; } uint8 *GetNesCHRPointer(int A){ return CHRptr[0]+A; } uint8 GetMem(uint16 A) { if ((A >= 0x2000) && (A < 0x4000)) { switch (A&7) { case 0: return PPU[0]; case 1: return PPU[1]; case 2: return PPU[2]|(PPUGenLatch&0x1F); case 3: return PPU[3]; case 4: return SPRAM[PPU[3]]; case 5: return XOffset; case 6: return RefreshAddr&0xFF; case 7: return VRAMBuffer; } } else if ((A >= 0x4000) && (A < 0x6000)) return 0xFF; //fix me return ARead[A](A); } uint8 GetPPUMem(uint8 A) { uint16 tmp=RefreshAddr&0x3FFF; if (tmp<0x2000) return VPage[tmp>>10][tmp]; if (tmp>=0x3F00) return PALRAM[tmp&0x1F]; return vnapage[(tmp>>10)&0x3][tmp&0x3FF]; } //--------------------- volatile int codecount, datacount, undefinedcount; //HWND hCDLogger=0; unsigned char *cdloggerdata; char *cdlogfilename; //char loadedcdfile[MAX_PATH]; static int indirectnext; //records whether loggingCD is enabled int debug_loggingCD; //called by the cpu to perform logging if CDLogging is enabled 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; } 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; } //-----------debugger stuff watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over int badopbreak; int iaPC; uint32 iapoffset; //mbg merge 7/18/06 changed from int int step,stepout,jsrcount; int u; //deleteme int skipdebug; //deleteme int numWPs; void BreakHit() { FCEUI_SetEmulationPaused(1); //mbg merge 7/19/06 changed to use EmulationPaused() //MBG TODO - was this commented out before the gnu refactoring? //if((!logtofile) && (logging))PauseLoggingSequence(); FCEUD_DebugBreakpoint(); } /* //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; } */ // ################################## 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 int debug_tracing; void DebugCycle() { if (numWPs | step | stepout | watchpoint[64].flags | badopbreak) breakpoint(); if(debug_loggingCD) LogCDData(); //mbg 6/30/06 - this was commented out when i got here. i dont understand it anyway //if(logging || (hMemView && (EditingMode == 2))) LogInstruction(); FCEUD_TraceInstruction(); }