/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2003 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 #include #include "types.h" #include "x6502.h" #include "fceu.h" #include "debug.h" #include "cart.h" void FCEUI_DumpVid(const char *fname, uint32 start, uint32 end) { FILE *fp=FCEUD_UTF8fopen(fname,"wb"); fceuindbg=1; start&=0x1FFF; end&=0x1FFF; for(;start<=end;start++) fputc(VPage[start>>10][start],fp); fclose(fp); fceuindbg=0; } void FCEUI_DumpMem(const char *fname, uint32 start, uint32 end) { FILE *fp=FCEUD_UTF8fopen(fname,"wb"); fceuindbg=1; for(;start<=end;start++) fputc(ARead[start](start),fp); fclose(fp); fceuindbg=0; } void FCEUI_LoadMem(const char *fname, uint32 start, int hl) { int t; FILE *fp=FCEUD_UTF8fopen(fname,"rb"); while((t=fgetc(fp))>=0) { if(start>0xFFFF) break; if(hl) { extern uint8 *Page[32]; if(Page[start/2048]) Page[start/2048][start]=t; } else BWrite[start](start,t); start++; } fclose(fp); } #ifdef FCEUDEF_DEBUGGER static char *fstrings[12]= { "#$%02X", // immediate "$%04X", // RELATIVE(jump) "$%02X", // Z "$%02X,X", // Z,x "$%02X,Y", // Z,y "$%04X", //ABS "$%04X,X", // ABS,x "$%04X,Y", // ABS,y "($%04X)", // IND "($%02X,X)", // INX "($%02X),Y", // INY "" }; static int flengths[12]={1,1,1,1,1,2,2,2,2,1,1,0}; #define IMD(x) ((0<<16)|x) #define REL(x) ((1<<16)|x) #define ZP(x) ((2<<16)|x) #define ZPX(x) ((3<<16)|x) #define ZPY(x) ((4<<16)|x) #define ABS(x) ((5<<16)|x) #define ABX(x) ((6<<16)|x) #define ABY(x) ((7<<16)|x) #define IND(x) ((8<<16)|x) #define INX(x) ((9<<16)|x) #define INY(x) ((10<<16)|x) #define IMP(x) ((11<<16)|x) typedef struct { char *name; int type; /* 1 for read, 2 for write, 3 for r then write. */ int32 modes[10]; } OPS; #define NUMOPS 56 static OPS optable[NUMOPS]= { {"BRK",0,{IMP(0x00),-1}}, {"RTI",0,{IMP(0x40),-1}}, {"RTS",0,{IMP(0x60),-1}}, {"PHA",2,{IMP(0x48),-1}}, {"PHP",2,{IMP(0x08),-1}}, {"PLA",1,{IMP(0x68),-1}}, {"PLP",1,{IMP(0x28),-1}}, {"JMP",0,{ABS(0x4C),IND(0x6C),-1}}, {"JSR",0,{ABS(0x20),-1}}, {"TAX",0,{IMP(0xAA),-1}}, {"TXA",0,{IMP(0x8A),-1}}, {"TAY",0,{IMP(0xA8),-1}}, {"TYA",0,{IMP(0x98),-1}}, {"TSX",0,{IMP(0xBA),-1}}, {"TXS",0,{IMP(0x9A),-1}}, {"DEX",0,{IMP(0xCA),-1}}, {"DEY",0,{IMP(0x88),-1}}, {"INX",0,{IMP(0xE8),-1}}, {"INY",0,{IMP(0xC8),-1}}, {"CLC",0,{IMP(0x18),-1}}, {"CLD",0,{IMP(0xD8),-1}}, {"CLI",0,{IMP(0x58),-1}}, {"CLV",0,{IMP(0xB8),-1}}, {"SEC",0,{IMP(0x38),-1}}, {"SED",0,{IMP(0xF8),-1}}, {"SEI",0,{IMP(0x78),-1}}, {"NOP",0,{IMP(0xEA),-1}}, {"ASL",1,{IMP(0x0a),ZP(0x06),ZPX(0x16),ABS(0x0E),ABX(0x1E),-1}}, {"DEC",3,{ZP(0xc6),ZPX(0xd6),ABS(0xcE),ABX(0xdE),-1}}, {"INC",3,{ZP(0xe6),ZPX(0xf6),ABS(0xeE),ABX(0xfE),-1}}, {"LSR",3,{IMP(0x4a),ZP(0x46),ZPX(0x56),ABS(0x4E),ABX(0x5E),-1}}, {"ROL",3,{IMP(0x2a),ZP(0x26),ZPX(0x36),ABS(0x2E),ABX(0x3E),-1}}, {"ROR",3,{IMP(0x6a),ZP(0x66),ZPX(0x76),ABS(0x6E),ABX(0x7E),-1}}, {"ADC",1,{IMD(0x69),ZP(0x65),ZPX(0x75),ABS(0x6D),ABX(0x7d),ABY(0x79), INX(0x61),INY(0x71),-1}}, {"AND",1,{IMD(0x29),ZP(0x25),ZPX(0x35),ABS(0x2D),ABX(0x3d),ABY(0x39), INX(0x21),INY(0x31),-1}}, {"BIT",1,{ZP(0x24),ABS(0x2c),-1}}, {"CMP",1,{IMD(0xc9),ZP(0xc5),ZPX(0xd5),ABS(0xcD),ABX(0xdd),ABY(0xd9), INX(0xc1),INY(0xd1),-1}}, {"CPX",1,{IMD(0xe0),ZP(0xe4),ABS(0xec),-1}}, {"CPY",1,{IMD(0xc0),ZP(0xc4),ABS(0xcc),-1}}, {"EOR",1,{IMD(0x49),ZP(0x45),ZPX(0x55),ABS(0x4D),ABX(0x5d),ABY(0x59), INX(0x41),INY(0x51),-1}}, {"LDA",1,{IMD(0xa9),ZP(0xa5),ZPX(0xb5),ABS(0xaD),ABX(0xbd),ABY(0xb9), INX(0xa1),INY(0xb1),-1}}, {"LDX",1,{IMD(0xa2),ZP(0xa6),ZPY(0xB6),ABS(0xae),ABY(0xbe),-1}}, {"LDY",1,{IMD(0xa0),ZP(0xa4),ZPX(0xB4),ABS(0xac),ABX(0xbc),-1}}, {"ORA",1,{IMD(0x09),ZP(0x05),ZPX(0x15),ABS(0x0D),ABX(0x1d),ABY(0x19), INX(0x01),INY(0x11),-1}}, {"SBC",1,{IMD(0xEB),IMD(0xe9),ZP(0xe5),ZPX(0xf5),ABS(0xeD),ABX(0xfd),ABY(0xf9), INX(0xe1),INY(0xf1),-1}}, {"STA",2,{ZP(0x85),ZPX(0x95),ABS(0x8D),ABX(0x9d),ABY(0x99), INX(0x81),INY(0x91),-1}}, {"STX",2,{ZP(0x86),ZPY(0x96),ABS(0x8E),-1}}, {"STY",2,{ZP(0x84),ZPX(0x94),ABS(0x8C),-1}}, {"BCC",1,{REL(0x90),-1}}, {"BCS",1,{REL(0xb0),-1}}, {"BEQ",1,{REL(0xf0),-1}}, {"BNE",1,{REL(0xd0),-1}}, {"BMI",1,{REL(0x30),-1}}, {"BPL",1,{REL(0x10),-1}}, {"BVC",1,{REL(0x50),-1}}, {"BVS",1,{REL(0x70),-1}}, }; uint16 FCEUI_Disassemble(void *XA, uint16 a, char *stringo) { X6502 *X=(X6502*)XA; uint8 buf; unsigned int arg; int32 info; int x; int y; info=-1; fceuindbg=1; buf=ARead[a](a); a++; for(x=0;x=0) { if((optable[x].modes[y]&0xFF)==buf) { info=optable[x].modes[y]; goto endy; } y++; } } endy: sprintf(stringo,"%02X ",buf); if(info>=0) { int z=flengths[(info>>16)]; if(z) { arg=ARead[a](a); sprintf(stringo+strlen(stringo),"%02X ",arg); a++; if(z==2) {arg|=ARead[a](a)<<8;sprintf(stringo+strlen(stringo),"%02X ",arg>>8);a++;} else strcat(stringo," "); if((info>>16)==1) /* Relative branch */ arg=a+(char)arg; sprintf(stringo+strlen(stringo),"%s ",optable[x].name); sprintf(stringo+strlen(stringo),fstrings[info>>16],arg); /* 0 "#$%02X", // immediate 1 "$%04X", // RELATIVE(jump) 2 "$%02X", // Z 3 "$%02X,X", // Z,x 4 "$%02X,Y", // Z,y 5 "$%04X", //ABS 6 "$%04X,X", // ABS,x 7 "$%04X,Y", // ABS,y 8 "($%04X)", // IND 9 "($%02X,X)", // INX 10 "($%02X),Y", // INY 11 #define IMP(x) ((11<<16)|x) */ { unsigned int tmp; switch(info>>16) { case 2:tmp=arg; if(optable[x].type&1) { sprintf(stringo+strlen(stringo)," @ $%04X",tmp); sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); } break; case 3:tmp=(arg+X->X)&0xff; sprintf(stringo+strlen(stringo)," @ $%04X",tmp); if(optable[x].type&1) sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); break; case 4:tmp=(arg+X->Y)&0xff; sprintf(stringo+strlen(stringo)," @ $%04X",tmp); if(optable[x].type&1) sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); break; case 5:tmp=arg; if(optable[x].type&1) { sprintf(stringo+strlen(stringo)," @ $%04X",tmp); sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); } break; case 6:tmp=(arg+X->X)&0xffff; sprintf(stringo+strlen(stringo)," @ $%04X",tmp); if(optable[x].type&1) sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); break; case 7:tmp=(arg+X->Y)&0xffff; sprintf(stringo+strlen(stringo)," @ $%04X",tmp); if(optable[x].type&1) sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); break; case 8:tmp=ARead[arg](arg)|(ARead[(arg+1)&0xffff]((arg+1)&0xffff)<<8); sprintf(stringo+strlen(stringo)," $%04X",tmp); break; case 9:tmp=(arg+X->X)&0xFF; tmp=ARead[tmp](tmp) | (ARead[(tmp+1)&0xFF]((tmp+1)&0xFF)<<8); sprintf(stringo+strlen(stringo)," @ $%04X",tmp); if(optable[x].type&1) sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); break; case 10:tmp=ARead[arg](arg) | (ARead[(arg+1)&0xFF]((arg+1)&0xFF)<<8); tmp=(tmp+X->Y)&0xFFFF; sprintf(stringo+strlen(stringo)," @ $%04X",tmp); if(optable[x].type&1) sprintf(stringo+strlen(stringo)," = $%02X",ARead[tmp](tmp)); break; } } } else { strcat(stringo," "); strcat(stringo,optable[x].name); } } else sprintf(stringo+strlen(stringo)," .db $%02X",buf); fceuindbg=0; return(a); } void FCEUI_MemDump(uint16 a, int32 len, void (*callb)(uint16 a, uint8 v)) { fceuindbg=1; while(len) { callb(a,ARead[a](a)); a++; len--; } fceuindbg=0; } uint8 FCEUI_MemSafePeek(uint16 A) { uint8 ret; fceuindbg=1; ret=ARead[A](A); fceuindbg=0; return(ret); } void FCEUI_MemPoke(uint16 a, uint8 v, int hl) { extern uint8 *Page[32]; if(hl) { if(Page[a/2048]) Page[a/2048][a]=v; } else BWrite[a](a,v); } typedef struct __BPOINT { struct __BPOINT *next; void (*Handler)(X6502 *X, int type, unsigned int A); unsigned int A[2]; int type; } BPOINT; static BPOINT *BreakPoints=NULL; static BPOINT *LastBP=NULL; static void (*CPUHook)(X6502 *)=NULL; static int FindBPoint(X6502 *X, int who, unsigned int A) { BPOINT *tmp; tmp=BreakPoints; while(tmp) { if(tmp->type&who) { if(tmp->type&BPOINT_PC) if(X->PC!=A) goto don; /* Doesn't match, so go on. */ if((A>=tmp->A[0]) && (A<=tmp->A[1])) /* Whee, match. */ { tmp->Handler(X,tmp->type,A); return(1); } } don: tmp=tmp->next; } return(0); } static uint8 ReadHandler(X6502 *X, unsigned int A) { extern X6502 XSave; if(X->preexec) FindBPoint(&XSave,BPOINT_READ,A); return(ARead[A](A)); } static void WriteHandler(X6502 *X, unsigned int A, uint8 V) { extern X6502 XSave; if(X->preexec) FindBPoint(&XSave,BPOINT_WRITE,A); else BWrite[A](A,V); } int FCEUI_AddBreakPoint(int type, unsigned int A1, unsigned int A2, void (*Handler)(X6502 *, int type, unsigned int A)) { BPOINT *tmp; tmp=(BPOINT *)malloc(sizeof(BPOINT)); tmp->A[0]=A1; tmp->A[1]=A2; tmp->Handler=Handler; tmp->type=type; tmp->next=0; if(BreakPoints==NULL) BreakPoints=tmp; else LastBP->next=tmp; LastBP=tmp; X6502_Debug(CPUHook,ReadHandler,WriteHandler); return(1); } int FCEUI_SetBreakPoint(uint32 w, int type, unsigned int A1, unsigned int A2, void (*Handler)(X6502 *, int type, unsigned int A)) { uint32 x=0; BPOINT *tmp; tmp=BreakPoints; while(tmp) { if(w==x) { tmp->type=type; tmp->A[0]=A1; tmp->A[1]=A2; tmp->Handler=Handler; return(1); } x++; tmp=tmp->next; } return(0); } int FCEUI_GetBreakPoint(uint32 w, int *type, unsigned int *A1, unsigned int *A2, void (**Handler)(X6502 *, int type, unsigned int A)) { uint32 x=0; BPOINT *tmp; tmp=BreakPoints; while(tmp) { if(w==x) { *type=tmp->type; *A1=tmp->A[0]; *A2=tmp->A[1]; *Handler=tmp->Handler; return(1); } x++; tmp=tmp->next; } return(0); } int FCEUI_ListBreakPoints(int (*callb)(int type, unsigned int A1, unsigned int A2, void (*Handler)(X6502 *, int type, unsigned int A) )) { BPOINT *tmp; tmp=BreakPoints; while(tmp) { callb(tmp->type,tmp->A[0],tmp->A[1],tmp->Handler); tmp=tmp->next; } return(1); } int FCEUI_DeleteBreakPoint(uint32 w) { BPOINT *tmp,*prev=NULL; uint32 x=0; tmp=BreakPoints; while(tmp) { if(w==x) { if(prev) /* Not the first breakpoint. */ { if(tmp->next) /* More breakpoints. */ prev->next=tmp->next; else /* This is the last breakpoint. */ { prev->next=0; LastBP=prev; } } else /* The first breakpoint. */ { if(tmp->next) /* More breakpoints. */ BreakPoints=tmp->next; else { BreakPoints=LastBP=0; /* No more breakpoints. */ /* Update the CPU hooks. */ X6502_Debug(CPUHook,BreakPoints?ReadHandler:0,BreakPoints?WriteHandler:0); } } free(tmp); return(1); } prev=tmp; tmp=tmp->next; x++; } return(0); } void FCEUI_SetCPUCallback(void (*callb)(X6502 *X)) { CPUHook=callb; X6502_Debug(CPUHook,BreakPoints?ReadHandler:0,BreakPoints?WriteHandler:0); } #endif