#include "common.h" #ifdef FCEUDEF_DEBUGGER #include "../../x6502.h" #include "../../debug.h" #include "debug.h" void UpdateDebugger(void); static int discallb(uint16 a, char *s); static void crs(HWND hParent); static void Disyou(uint16 a); static void UpdateDMem(uint16 a); static HWND mwin=0; static int32 cmsi; static int instep=-1; static X6502 *Xsave; HWND dwin; static uint16 StrToU16(char *s) { unsigned int ret=0; sscanf(s,"%4x",&ret); return ret; } static uint8 StrToU8(char *s) { unsigned int ret=0; sscanf(s,"%2x",&ret); return ret; } /* Need to be careful where these functions are used. */ static char *U16ToStr(uint16 a) { static char TempArray[16]; sprintf(TempArray,"%04X",a); return TempArray; } static char *U8ToStr(uint8 a) { static char TempArray[16]; sprintf(TempArray,"%02X",a); return TempArray; } static uint16 asavers[27]; static void crs(HWND hParent) { // SetDlgItemText(hParent,320,(LPTSTR)(instep>=0)?"Stopped.":"Running..."); EnableWindow( GetDlgItem(hParent,301),(instep>=0)?1:0); } static void Disyou(uint16 a) { int discount; SendDlgItemMessage(dwin,100,LB_RESETCONTENT,0,0); discount = 0; while(discount < 25) { char buffer[256]; uint16 prea = a; asavers[discount]=a; sprintf(buffer,"%04x: ",a); a = FCEUI_Disassemble(Xsave,a,buffer + strlen(buffer)); if(prea==Xsave->PC) SendDlgItemMessage(dwin,100,LB_SETCURSEL,discount,0); SendDlgItemMessage(dwin,100,LB_ADDSTRING,0,(LPARAM)(LPSTR)buffer); discount++; } //FCEUI_Disassemble(Xsave,a,discallb); } static void SSI(X6502 *X) { SCROLLINFO si; memset(&si,0,sizeof(si)); si.cbSize=sizeof(si); si.fMask=SIF_ALL; si.nMin=-32768; si.nMax=32767; si.nPage=27; si.nPos=X->PC-32768; SetScrollInfo(GetDlgItem(dwin,101),SB_CTL,&si,1); } static void RFlags(X6502 *X) { int x; SetDlgItemText(dwin,202,(LPTSTR)U8ToStr(X->P&~0x30)); for(x=0;x<8;x++) { if(x!=4 && x!=5) CheckDlgButton(dwin,400+x,((X->P>>x)&1)?BST_CHECKED:BST_UNCHECKED); } } static void RRegs(X6502 *X) { SetDlgItemText(dwin,200,(LPTSTR)U16ToStr(X->PC)); SetDlgItemText(dwin,201,(LPTSTR)U8ToStr(X->S)); SetDlgItemText(dwin,210,(LPTSTR)U8ToStr(X->A)); SetDlgItemText(dwin,211,(LPTSTR)U8ToStr(X->X)); SetDlgItemText(dwin,212,(LPTSTR)U8ToStr(X->Y)); } static void DoVecties(HWND hParent) { uint16 m[3]; int x; FCEUI_GetIVectors(&m[2],&m[0],&m[1]); for(x=0;x<3;x++) SetDlgItemText(hParent,220+x,(LPTSTR)U16ToStr(m[x])); } static void Redrawsy(X6502 *X) { SSI(X); RFlags(X); RRegs(X); Disyou(X->PC); DoVecties(dwin); } static void MultiCB(X6502 *X) { Xsave=X; if(instep>=0) { Redrawsy(X); if(mwin) UpdateDMem(cmsi); } while(instep>=0) { if(instep>=1) { instep--; return; } StopSound(); if(!BlockingCheck()) /* Whoops, need to exit for some reason. */ { instep=-1; FCEUI_SetCPUCallback(0); return; } Sleep(50); } } static int multistep=0; static void cpucb(X6502 *X) { multistep=0; MultiCB(X); } static void BPointHandler(X6502 *X, int type, unsigned int A) { if(multistep) return; /* To handle instructions that can cause multiple breakpoints per instruction. */ if(!dwin) return; /* Window is closed, don't do breakpoints. */ multistep=1; instep=0; crs(dwin); MultiCB(X); } static HWND hWndCallB; static int RBPCallBack(int type, unsigned int A1, unsigned int A2, void (*Handler)(X6502 *, int type, unsigned int A) ) { char buf[128]; sprintf(buf,"%s%s%s $%04x - $%04x",(type&BPOINT_READ)?"R":" ", (type&BPOINT_WRITE)?"W":" ",(type&BPOINT_PC)?"P":" ",A1,A2); SendDlgItemMessage(hWndCallB,510,LB_ADDSTRING,0,(LPARAM)(LPSTR)buf); return(1); } static void RebuildBPointList(HWND hwndDlg) { SendDlgItemMessage(hwndDlg,510,LB_RESETCONTENT,0,0); hWndCallB=hwndDlg; FCEUI_ListBreakPoints(RBPCallBack); } static void FetchBPDef(HWND hwndDlg, uint16 *A1, uint16 *A2, int *type) { char tmp[256]; GetDlgItemText(hwndDlg,520,tmp,256); *A1=StrToU16(tmp); GetDlgItemText(hwndDlg,521,tmp,256); if(tmp[0]==0) *A2=*A1; else *A2=StrToU16(tmp); *type=0; *type|=(IsDlgButtonChecked(hwndDlg,530)==BST_CHECKED)?BPOINT_READ:0; *type|=(IsDlgButtonChecked(hwndDlg,531)==BST_CHECKED)?BPOINT_WRITE:0; *type|=(IsDlgButtonChecked(hwndDlg,532)==BST_CHECKED)?BPOINT_PC:0; } static void SetBPDef(HWND hwndDlg, int32 A1, int32 A2, int type) { if(A1>=0) SetDlgItemText(hwndDlg,520,(LPTSTR)U16ToStr(A1)); if(A2>=0) SetDlgItemText(hwndDlg,521,(LPTSTR)U16ToStr(A2)); if(type>=0) { // CheckDlgButton(hwndDlg,123,(soundoptions&SO_SECONDARY)?BST_CHECKED:BST_UNCHECKED); } } static BOOL CALLBACK DebugCon(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { int32 scrollindex=0,ced=0; DSMFix(uMsg); switch(uMsg) { case WM_INITDIALOG: crs(hwndDlg); DoVecties(hwndDlg); FCEUI_SetCPUCallback(cpucb); RebuildBPointList(hwndDlg); break; case WM_VSCROLL: if(0!=instep) break; switch((int)LOWORD(wParam)) { case SB_TOP: scrollindex=-32768; ced=1; break; case SB_BOTTOM: scrollindex=32767; ced=1; break; case SB_LINEUP: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,101),SB_CTL); if(scrollindex>-32768) { scrollindex--; ced=1; } break; case SB_PAGEUP: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,101),SB_CTL); scrollindex-=27; if(scrollindex<-32768) scrollindex=-32768; ced=1; break; case SB_LINEDOWN: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,101),SB_CTL); if(scrollindex<32767) { scrollindex++; ced=1; } break; case SB_PAGEDOWN: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,101),SB_CTL); scrollindex+=27; if(scrollindex>32767) { scrollindex=32767; } ced=1; break; case SB_THUMBPOSITION: case SB_THUMBTRACK: scrollindex=(int16)(wParam>>16); ced=1; break; } if(ced) { SendDlgItemMessage(hwndDlg,101,SBM_SETPOS,scrollindex,1); Disyou(scrollindex+32768); } break; case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: switch(HIWORD(wParam)) { case LBN_DBLCLK: if(0==instep) { Xsave->PC=asavers[SendDlgItemMessage(hwndDlg,100,LB_GETCURSEL,0,0)]; RRegs(Xsave); Disyou(Xsave->PC); } break; case EN_KILLFOCUS: { char TempArray[64]; int id=LOWORD(wParam); GetDlgItemText(hwndDlg,id,TempArray,64); if(0==instep) { int tscroll=32768+SendDlgItemMessage(hwndDlg,101,SBM_GETPOS,0,0); switch(id) { case 200: if(Xsave->PC!=StrToU16(TempArray)) { Xsave->PC=StrToU16(TempArray); Disyou(Xsave->PC); RRegs(Xsave); } break; case 201:Xsave->S=StrToU8(TempArray); RRegs(Xsave); Disyou(tscroll); break; case 202:Xsave->P&=0x30; Xsave->P|=StrToU8(TempArray)&~0x30; RFlags(Xsave); Disyou(tscroll); break; case 210:Xsave->A=StrToU8(TempArray); RRegs(Xsave); Disyou(tscroll); break; case 211:Xsave->X=StrToU8(TempArray); RRegs(Xsave); Disyou(tscroll); break; case 212:Xsave->Y=StrToU8(TempArray); RRegs(Xsave); Disyou(tscroll); break; } } } break; case BN_CLICKED: if(LOWORD(wParam)>=400 && LOWORD(wParam)<=407) { if(0==instep) { Xsave->P^=1<<(LOWORD(wParam)&7); RFlags(Xsave); } } else switch(LOWORD(wParam)) { case 300: instep=1; crs(hwndDlg); break; case 301: instep=-1; crs(hwndDlg); break; case 302:FCEUI_NMI();break; case 303:FCEUI_IRQ();break; case 310:FCEUI_ResetNES(); if(instep>=0) instep=1; crs(hwndDlg); break; case 311:DoMemmo(hwndDlg);break; case 540: { LONG t; t=SendDlgItemMessage(hwndDlg,510,LB_GETCURSEL,0,0); if(t!=LB_ERR) { FCEUI_DeleteBreakPoint(t); SendDlgItemMessage(hWndCallB,510,LB_DELETESTRING,t,(LPARAM)(LPSTR)0); } } break; case 541: { uint16 A1,A2; int type; FetchBPDef(hwndDlg, &A1, &A2, &type); FCEUI_AddBreakPoint(type, A1,A2,BPointHandler); hWndCallB=hwndDlg; /* Hacky hacky. */ RBPCallBack(type, A1,A2,0); } break; } break; } if(!(wParam>>16)) switch(wParam&0xFFFF) { case 1: gornk: instep=-1; FCEUI_SetCPUCallback(0); DestroyWindow(dwin); dwin=0; break; } } return 0; } void BeginDSeq(HWND hParent) { if(dwin) { SetFocus(dwin); return; } if(!GI) { FCEUD_PrintError("You must have a game loaded before you can screw up a game."); return; } dwin=CreateDialog(fceu_hInstance,"DEBUGGER",0,DebugCon); } /* 16 numbers per line times 3 then minus one(no space at end) and plus 6 for "8000: "-like string and plus 2 for crlf. *16 for 16 lines, and +1 for a null. */ static uint8 kbuf[(16*3-1+6+2)*16+1]; static void sexycallb(uint16 a, uint8 v) { if((a&15)==15) sprintf(kbuf+strlen(kbuf),"%02X\r\n",v); else if((a&15)==0) sprintf(kbuf+strlen(kbuf),"%03xx: %02X ",a>>4,v); else sprintf(kbuf+strlen(kbuf),"%02X ",v); } static void MDSSI(void) { SCROLLINFO si; memset(&si,0,sizeof(si)); si.cbSize=sizeof(si); si.fMask=SIF_ALL; si.nMin=0; si.nMax=0xFFFF>>4; si.nPage=16; cmsi=si.nPos=0; SetScrollInfo(GetDlgItem(mwin,103),SB_CTL,&si,1); } static void UpdateDMem(uint16 a) { kbuf[0]=0; FCEUI_MemDump(a<<4,256,sexycallb); SetDlgItemText(mwin,100,kbuf); } int CreateDumpSave(uint32 a1, uint32 a2) { const char filter[]="Raw dump(*.dmp)\0*.dmp\0"; char nameo[2048]; OPENFILENAME ofn; memset(&ofn,0,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); ofn.hInstance=fceu_hInstance; ofn.lpstrTitle="Dump Memory As..."; ofn.lpstrFilter=filter; nameo[0]=0; ofn.lpstrFile=nameo; ofn.nMaxFile=256; ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; if(GetSaveFileName(&ofn)) { FCEUI_DumpMem(nameo,a1,a2); return(1); } return 0; } int LoadSave(uint32 a) { const char filter[]="Raw dump(*.dmp)\0*.dmp\0"; char nameo[2048]; OPENFILENAME ofn; memset(&ofn,0,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); ofn.hInstance=fceu_hInstance; ofn.lpstrTitle="Load Memory..."; ofn.lpstrFilter=filter; nameo[0]=0; ofn.lpstrFile=nameo; ofn.nMaxFile=256; ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; if(GetOpenFileName(&ofn)) { FCEUI_LoadMem(nameo,a,0); /* LL Load */ return(1); } return 0; } static BOOL CALLBACK MemCon(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { int32 scrollindex=0,ced=0; char TempArray[64]; DSMFix(uMsg); switch(uMsg) { case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: switch(HIWORD(wParam)) { case BN_CLICKED: switch(LOWORD(wParam)) { case 203: case 202: { uint16 a; uint8 v; GetDlgItemText(hwndDlg,200,TempArray,64); a=StrToU16(TempArray); GetDlgItemText(hwndDlg,201,TempArray,64); v=StrToU8(TempArray); FCEUI_MemPoke(a,v,LOWORD(wParam)&1); UpdateDMem(cmsi); if(dwin && 0==instep) { int tscroll=32768+SendDlgItemMessage(dwin,101,SBM_GETPOS,0,0); Disyou(tscroll); } } break; case 212: { uint16 a1; uint16 a2; GetDlgItemText(hwndDlg,210,TempArray,64); a1=StrToU16(TempArray); GetDlgItemText(hwndDlg,211,TempArray,64); a2=StrToU16(TempArray); CreateDumpSave(a1,a2); } break; case 222: { uint16 a; GetDlgItemText(hwndDlg,220,TempArray,64); a=StrToU16(TempArray); LoadSave(a); UpdateDMem(cmsi); if(dwin && 0==instep) { int tscroll=32768+SendDlgItemMessage(dwin,101,SBM_GETPOS,0,0); Disyou(tscroll); } } break; } break; } if(!(wParam>>16)) switch(wParam&0xFFFF) { case 1: gornk: DestroyWindow(mwin); mwin=0; break; } break; case WM_INITDIALOG: return(1); case WM_VSCROLL: switch((int)LOWORD(wParam)) { case SB_TOP: scrollindex=0; ced=1; break; case SB_BOTTOM: scrollindex=0xffff>>4; ced=1; break; case SB_LINEUP: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,103),SB_CTL); if(scrollindex>0) { scrollindex--; ced=1; } break; case SB_PAGEUP: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,103),SB_CTL); scrollindex-=16; if(scrollindex<0) scrollindex=0; ced=1; break; case SB_LINEDOWN: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,103),SB_CTL); if(scrollindex<(0xFFFF>>4)) { scrollindex++; ced=1; } break; case SB_PAGEDOWN: scrollindex=GetScrollPos(GetDlgItem(hwndDlg,103),SB_CTL); scrollindex+=16; if(scrollindex>(0xFFFF>>4)) { scrollindex=(65535>>4); } ced=1; break; case SB_THUMBPOSITION: case SB_THUMBTRACK: scrollindex=HIWORD(wParam); ced=1; break; } if(ced) { SendDlgItemMessage(hwndDlg,103,SBM_SETPOS,scrollindex,1); UpdateDMem(scrollindex); cmsi=scrollindex; } break; } return 0; } void DoMemmo(HWND hParent) { if(mwin) { SetFocus(mwin); return; } mwin=CreateDialog(fceu_hInstance,"MEMVIEW",0,MemCon); MDSSI(); UpdateDMem(0); } void UpdateDebugger(void) { if(mwin) UpdateDMem(cmsi); } void KillDebugger(void) { if(mwin) DestroyWindow(mwin); if(dwin) DestroyWindow(dwin); dwin=mwin=0; } #endif