diff --git a/src/asm.cpp b/src/asm.cpp index 0aa2a61ee..ae20c2516 100644 --- a/src/asm.cpp +++ b/src/asm.cpp @@ -254,8 +254,8 @@ int Assemble(unsigned char *output, int addr, char *str) { return 0; } -///disassembles the opcodes in the buffer assuming the provided address. Uses GetMem() and 6502 current registers to query referenced values. returns a static string buffer. -char *Disassemble(int addr, uint8 *opcode) { +///Disassembles the instruction bytes in the buffer using the provided address for trace info. Uses GetMem() and 6502 current registers to query referenced values. Returns a static string buffer. +char *Disassemble(int addr, uint8 *opcode, bool showTrace) { static char str[64]={0},chr[5]={0}; uint16 tmp,tmp2; @@ -333,7 +333,9 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xE1: strcpy(chr,"SBC"); goto _indirectx; _indirectx: indirectX(tmp); - sprintf(str,"%s ($%02X,X) @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); + showTrace + ? sprintf(str,"%s ($%02X,X) @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)) + : sprintf(str,"%s ($%02X,X)", chr,opcode[1]); break; //Zero Page @@ -359,10 +361,10 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xE5: strcpy(chr,"SBC"); goto _zeropage; case 0xE6: strcpy(chr,"INC"); goto _zeropage; _zeropage: - // ################################## Start of SP CODE ########################### // Change width to %04X // don't! - sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1])); - // ################################## End of SP CODE ########################### + showTrace + ? sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1])) + : sprintf(str,"%s $%02X", chr,opcode[1]); break; //#Immediate @@ -406,7 +408,9 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xEE: strcpy(chr,"INC"); goto _absolute; _absolute: absolute(tmp); - sprintf(str,"%s $%04X = #$%02X", chr,tmp,GetMem(tmp)); + showTrace + ? sprintf(str,"%s $%04X = #$%02X", chr,tmp,GetMem(tmp)) + : sprintf(str,"%s $%04X", chr,tmp); break; //branches @@ -434,7 +438,9 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xF1: strcpy(chr,"SBC"); goto _indirecty; _indirecty: indirectY(tmp); - sprintf(str,"%s ($%02X),Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); + showTrace + ? sprintf(str,"%s ($%02X),Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)) + : sprintf(str,"%s ($%02X),Y", chr,opcode[1]); break; //Zero Page,X @@ -456,10 +462,10 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xF6: strcpy(chr,"INC"); goto _zeropagex; _zeropagex: zpIndex(tmp,RX); - // ################################## Start of SP CODE ########################### // Change width to %04X // don't! - sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); - // ################################## End of SP CODE ########################### + showTrace + ? sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)) + : sprintf(str,"%s $%02X,X", chr,opcode[1]); break; //Absolute,Y @@ -475,7 +481,9 @@ char *Disassemble(int addr, uint8 *opcode) { _absolutey: absolute(tmp); tmp2=(tmp+RY); - sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2)); + showTrace + ? sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2)) + : sprintf(str,"%s $%04X,Y", chr,tmp); break; //Absolute,X @@ -497,7 +505,9 @@ char *Disassemble(int addr, uint8 *opcode) { _absolutex: absolute(tmp); tmp2=(tmp+RX); - sprintf(str,"%s $%04X,X @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2)); + showTrace + ? sprintf(str,"%s $%04X,X @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2)) + : sprintf(str,"%s $%04X,X", chr,tmp); break; //jumps @@ -514,10 +524,10 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xB6: strcpy(chr,"LDX"); goto _zeropagey; _zeropagey: zpIndex(tmp,RY); - // ################################## Start of SP CODE ########################### // Change width to %04X // don't! - sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); - // ################################## End of SP CODE ########################### + showTrace + ? sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)) + : sprintf(str,"%s $%02X,Y", chr,opcode[1]); break; //UNDEFINED @@ -527,3 +537,83 @@ char *Disassemble(int addr, uint8 *opcode) { return str; } + +char *DisassembleLine(int addr, bool showTrace, bool showRomOffsets) { + uint8 instruction[] = {GetMem(addr), GetMem(addr + 1), GetMem(addr + 2)}; + return DisassembleData(addr, instruction, showTrace, showRomOffsets); +} + +int formatAddress(char *str, int addr, bool showRomOffsets) { + if (addr >= 0x8000) + { + if (showRomOffsets && GetNesFileAddress(addr) != -1) + { + return sprintf(str, " %06X: ", GetNesFileAddress(addr)); + } + else + { + return sprintf(str, "%02X:%04X: ", getBank(addr), addr); + } + } + else + { + return sprintf(str, " :%04X: ", addr); + } +} + +char *DisassembleData(int addr, uint8 *opcode, bool showTrace, bool showRomOffsets) { + static char str[64] = { 0 }, chr[25] = { 0 }; + char *c; + int size, j; + + formatAddress(str, addr, showRomOffsets); + + size = opsize[opcode[0]]; + if (size == 0) + { + sprintf(chr, "%02X UNDEFINED", opcode[0]); + strcat(str, chr); + } + else + { + if ((addr + size) > 0x10000) + { + sprintf(chr, "%02X OVERFLOW", opcode[0]); + strcat(str, chr); + } + else + { + for (j = 0; j < size; j++) + { + sprintf(chr, "%02X ", opcode[j]); + addr++; + strcat(str, chr); + } + while (size < 3) + { + strcat(str, " "); //pad output to align ASM + size++; + } + strcat(strcat(str, " "), Disassemble(addr, opcode, showTrace)); + } + } + return str; +} + +/// Disassembles a data block of the given length, regardless of any cdlogger info. +char *DisassembleDataBlock(int addr, int length, bool showTrace, bool showRomOffsets) { + static char str[64] = { 0 }, chr[25] = { 0 }; + int size; + + formatAddress(str, addr, showRomOffsets); + + sprintf(chr, ".db $%02X", GetMem(addr)); + strcat(str, chr); + + for (int i = addr + 1; i < addr + length && i < 0x10000; i++) { + sprintf(chr, ", $%02X", GetMem(i)); + strcat(str, chr); + } + + return str; +} diff --git a/src/asm.h b/src/asm.h index 5dff9f326..232dcc767 100644 --- a/src/asm.h +++ b/src/asm.h @@ -1,2 +1,7 @@ +#pragma once + int Assemble(unsigned char *output, int addr, char *str); -char *Disassemble(int addr, uint8 *opcode); +char *Disassemble(int addr, uint8 *opcode, bool showTrace = false); +char *DisassembleLine(int addr, bool showTrace = false, bool showRomOffsets = false); +char *DisassembleData(int addr, uint8 *opcode, bool showTrace = false, bool showRomOffsets = false); +char *DisassembleDataBlock(int addr, int length, bool showTrace = false, bool showRomOffsets = false); diff --git a/src/drivers/win/assembler.cpp b/src/drivers/win/assembler.cpp new file mode 100644 index 000000000..8be768f72 --- /dev/null +++ b/src/drivers/win/assembler.cpp @@ -0,0 +1,159 @@ +#include + +#include "types.h" +#include "gui.h" +#include "resource.h" +#include "debugger.h" +#include "../../debug.h" +#include "asm.h" +#include "../../x6502.h" +#include "../../fceu.h" +#include "../../debug.h" +#include "../../nsf.h" +#include "../../ppu.h" +#include "../../cart.h" +#include "../../ines.h" +#include "../../asm.h" + +int AddAsmHistory(HWND hwndDlg, int id, char *str) { + int index; + index = SendDlgItemMessage(hwndDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)(LPSTR)str); + if (index == CB_ERR) { + SendDlgItemMessage(hwndDlg, id, CB_INSERTSTRING, -1, (LPARAM)(LPSTR)str); + return 0; + } + return 1; +} + +INT_PTR CALLBACK AssemblerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + int romaddr, count, i, j; + char str[128], *dasm; + static int patchlen, applied, saved, lastundo; + static uint8 patchdata[64][3], undodata[64 * 3]; + uint8 *ptr; + + switch (uMsg) { + case WM_INITDIALOG: + CenterWindow(hwndDlg); + + //set font + SendDlgItemMessage(hwndDlg, IDC_ASSEMBLER_DISASSEMBLY, WM_SETFONT, (WPARAM)debugSystem->hFixedFont, FALSE); + SendDlgItemMessage(hwndDlg, IDC_ASSEMBLER_PATCH_DISASM, WM_SETFONT, (WPARAM)debugSystem->hFixedFont, FALSE); + + //set limits + SendDlgItemMessage(hwndDlg, IDC_ASSEMBLER_HISTORY, CB_LIMITTEXT, 20, 0); + + SetDlgItemText(hwndDlg, IDC_ASSEMBLER_DISASSEMBLY, DisassembleLine(iaPC)); + SetFocus(GetDlgItem(hwndDlg, IDC_ASSEMBLER_HISTORY)); + + patchlen = 0; + applied = 0; + saved = 0; + lastundo = 0; + break; + case WM_CLOSE: + case WM_QUIT: + EndDialog(hwndDlg, 0); + break; + case WM_COMMAND: + { + switch (HIWORD(wParam)) + { + case BN_CLICKED: + { + switch (LOWORD(wParam)) + { + case IDC_ASSEMBLER_APPLY: + if (patchlen) { + ptr = GetNesPRGPointer(GetNesFileAddress(iaPC) - 16); + count = 0; + for (i = 0; i < patchlen; i++) { + for (j = 0; j < opsize[patchdata[i][0]]; j++) { + if (count == lastundo) undodata[lastundo++] = ptr[count]; + ptr[count++] = patchdata[i][j]; + } + } + SetWindowText(hwndDlg, "Inline Assembler *Patches Applied*"); + applied = 1; + } + break; + case IDC_ASSEMBLER_SAVE: + if (applied) { + count = romaddr = GetNesFileAddress(iaPC); + for (i = 0; i < patchlen; i++) + { + count += opsize[patchdata[i][0]]; + } + if (patchlen) sprintf(str, "Write patch data to file at addresses 0x%06X - 0x%06X?", romaddr, count - 1); + else sprintf(str, "Undo all previously applied patches?"); + if (MessageBox(hwndDlg, str, "Save changes to file?", MB_YESNO | MB_ICONINFORMATION) == IDYES) { + if (iNesSave()) { + saved = 1; + applied = 0; + } + else MessageBox(hwndDlg, "Unable to save changes to file", "Error saving to file", MB_OK | MB_ICONERROR); + } + } + break; + case IDC_ASSEMBLER_UNDO: + if ((count = SendDlgItemMessage(hwndDlg, IDC_ASSEMBLER_PATCH_DISASM, LB_GETCOUNT, 0, 0))) { + SendDlgItemMessage(hwndDlg, IDC_ASSEMBLER_PATCH_DISASM, LB_DELETESTRING, count - 1, 0); + patchlen--; + count = 0; + for (i = 0; i < patchlen; i++) + { + count += opsize[patchdata[i][0]]; + } + if (count < lastundo) { + ptr = GetNesPRGPointer(GetNesFileAddress(iaPC) - 16); + j = opsize[patchdata[patchlen][0]]; + for (i = count; i < (count + j); i++) { + ptr[i] = undodata[i]; + } + lastundo -= j; + applied = 1; + } + SetDlgItemText(hwndDlg, IDC_ASSEMBLER_DISASSEMBLY, DisassembleLine(iaPC + count)); + } + break; + case IDC_ASSEMBLER_DEFPUSHBUTTON: + count = 0; + for (i = 0; i < patchlen; i++) + { + count += opsize[patchdata[i][0]]; + } + GetDlgItemText(hwndDlg, IDC_ASSEMBLER_HISTORY, str, 21); + if (!Assemble(patchdata[patchlen], (iaPC + count), str)) { + count = iaPC; + for (i = 0; i <= patchlen; i++) + { + count += opsize[patchdata[i][0]]; + } + if (count > 0x10000) { //note: don't use 0xFFFF! + MessageBox(hwndDlg, "Patch data cannot exceed address 0xFFFF", "Address error", MB_OK | MB_ICONERROR); + break; + } + SetDlgItemText(hwndDlg, IDC_ASSEMBLER_HISTORY, ""); + if (count < 0x10000) SetDlgItemText(hwndDlg, IDC_ASSEMBLER_DISASSEMBLY, DisassembleLine(count)); + else SetDlgItemText(hwndDlg, IDC_ASSEMBLER_DISASSEMBLY, "OVERFLOW"); + dasm = DisassembleData((count - opsize[patchdata[patchlen][0]]), patchdata[patchlen]); + SendDlgItemMessage(hwndDlg, IDC_ASSEMBLER_PATCH_DISASM, LB_INSERTSTRING, -1, (LPARAM)(LPSTR)dasm); + AddAsmHistory(hwndDlg, IDC_ASSEMBLER_HISTORY, dasm + 16); + SetWindowText(hwndDlg, "Inline Assembler"); + patchlen++; + } + else { //ERROR! + SetWindowText(hwndDlg, "Inline Assembler *Syntax Error*"); + MessageBeep(MB_ICONEXCLAMATION); + } + break; + } + SetFocus(GetDlgItem(hwndDlg, IDC_ASSEMBLER_HISTORY)); //set focus to combo box after anything is pressed! + break; + } + } + break; + } + } + return FALSE; +} diff --git a/src/drivers/win/assembler.h b/src/drivers/win/assembler.h new file mode 100644 index 000000000..a08bccf5e --- /dev/null +++ b/src/drivers/win/assembler.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +INT_PTR CALLBACK AssemblerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/src/drivers/win/debugger.cpp b/src/drivers/win/debugger.cpp index 2fba0cfe9..f47a9d67f 100644 --- a/src/drivers/win/debugger.cpp +++ b/src/drivers/win/debugger.cpp @@ -38,9 +38,9 @@ #include "cdlogger.h" #include "ppuview.h" #include "richedit.h" - -// ################################## Start of SP CODE ########################### - +#include "assembler.h" +#include "patcher.h" +#include "dumper.h" #include "debuggersp.h" extern Name* pageNames[32]; @@ -49,8 +49,6 @@ extern bool ramBankNamesLoaded; extern int pageNumbersLoaded[32]; extern int myNumWPs; -// ################################## End of SP CODE ########################### - extern int vblankScanLines; extern int vblankPixel; extern bool DebuggerWasUpdated; @@ -70,7 +68,6 @@ static HMENU hDisasmcontext; //Handle to context menu static HMENU hDisasmcontextsub; //Handle to context sub menu WNDPROC IDC_DEBUGGER_DISASSEMBLY_oldWndProc = 0; -// static HFONT hFont; static SCROLLINFO si; bool debuggerAutoload = false; @@ -78,12 +75,15 @@ bool debuggerSaveLoadDEBFiles = true; bool debuggerIDAFont = false; unsigned int IDAFontSize = 16; bool debuggerDisplayROMoffsets = false; +bool debuggerShowTraceInfo = true; +bool debuggerUnloggedBytesAsData = false; +bool debuggerFollowPc = true; -wchar_t* debug_wstr; -char* debug_cdl_str; -char* debug_str_decoration_comment; -char* debug_decoration_comment; -char* debug_decoration_comment_end_pos; +static wchar_t* debug_wstr; +static char* debug_cdl_str; +static char* debug_str_decoration_comment; +static char* debug_decoration_comment; +static char* debug_decoration_comment_end_pos; FINDTEXT newline; FINDTEXT num; @@ -99,17 +99,16 @@ struct DBGCOLORMENU { { NULL }, { "Mnemonic", PPCCF(DbgMnem) }, { NULL }, - { "Symbolic name", PPCCF(DbgSym) }, + { "Symbolic Name", PPCCF(DbgSym) }, { "Comment" , PPCCF(DbgComm) }, { NULL }, { "Operand" , PPCCF(DbgOper) }, - { "Operand note" , PPCCF(DbgOpNt) }, - { "Effective address", PPCCF(DbgEff) }, + { "Operand Note" , PPCCF(DbgOpNt) }, + { "Effective Address", PPCCF(DbgEff) }, { NULL }, - { "RTS Line", PPCCF(DbgRts) } + { "RTS/RTI Line", PPCCF(DbgRts) } }; -#define IDC_DEBUGGER_RESTORESIZE 1000 #define ID_COLOR_DEBUGGER 2000 bool ChangeColor(HWND hwnd, DBGCOLORMENU* item) @@ -127,13 +126,14 @@ std::vector disassembly_addresses; // this is used to keep track of addresses in operands of each printed instruction std::vector> disassembly_operands; // this is used to autoscroll the Disassembly window while keeping relative position of the ">" pointer inside this window -unsigned int PC_pointerOffset = 0; -int PCLine = -1; -// this is used for dirty, but unavoidable hack, which is necessary to ensure the ">" pointer is visible when stepping/seeking to PC -bool PCPointerWasDrawn = false; -// and another hack... +unsigned int PCLine = -1; +// hack to help syntax highlighting find the PC int beginningOfPCPointerLine = -1; // index of the first char within debug_str[] string, where the ">" line starts +static int scrollAddress; +static int commentOffset = 0; // rename to commentOffset +static int linesPerComment; // Update in ScrollUp and ScrollDown when the address changes? How does that work with a hard jump? + #define INVALID_START_OFFSET 1 #define INVALID_END_OFFSET 2 @@ -142,7 +142,7 @@ int beginningOfPCPointerLine = -1; // index of the first char within debug_str[] void UpdateOtherDebuggingDialogs() { - //adelikat: This updates all the other dialogs such as ppu, nametable, logger, etc in one function, should be applied to all the step type buttons + //This updates all the other dialogs such as ppu, nametable, logger, etc in one function, should be applied to all the step type buttons NTViewDoBlit(0); //Nametable Viewer UpdateLogWindow(); //Trace Logger UpdateCDLogger(); //Code/Data Logger @@ -156,7 +156,7 @@ void UpdateOtherDebuggingDialogs() #define DEBUGGER_MIN_WIDTH 360 // Minimum width for debugger #define DEBUGGER_DEFAULT_HEIGHT 594 // default height for debugger -// owomomo: default width of the debugger is depend on the default width of disasm view, so it's not defined here. +// Default width of the debugger depends on the default width of disasm view, so it's not defined here. void RestoreSize(HWND hwndDlg) { @@ -255,10 +255,70 @@ unsigned int AddBreak(HWND hwndDlg) return 0; } -// This function is for "smart" scrolling... -// it attempts to scroll up one line by a whole instruction +#define MAX_DB_LEN 8 + +typedef struct +{ + int address; + int commentOffset; +} AddrScrollInfo; + +bool IsData(unsigned int addr) +{ + if (cdloggerdataSize) + { + unsigned int romAddr = GetNesFileAddress(addr) - 16; // minus iNES header + if (romAddr >= 0 && romAddr < cdloggerdataSize) + { + uint8 cdlData = cdloggerdata[romAddr] & 3; + return cdlData == 0 + ? debuggerUnloggedBytesAsData + : cdlData == 2; // Only data, not code + } + } + return false; +} + +// Tells you how many lines the comments and label name take for a given address. +// Used for smoothly scrolling through comments. +static int NumAnnotationLines(int addr) +{ + if (symbDebugEnabled) + { + Name* node = findNode(getNamesPointerForAddress(addr), addr); + if (node) + { + int count = 0; + + if (node->name) + count++; + + char* str = node->comment; + for (; str; count++) + str = strstr(str + 1, "\n"); + + return count; + } + } + + return 0; +} + +// This function is for "smart" scrolling. +// It attempts to scroll up by a whole instruction heuristically. +// Should we add the label-respecting logic from dumper.cpp? +// Always attempting the full data block size can lead to weird results. Maybe cut it when address is a multiple of 8? int InstructionUp(int from) { + if (IsData(from - 1)) + { + // Scroll past the beginning of the data block, up to MAX_DB_LEN bytes. + int i = from - 2; + for (; i >= from - MAX_DB_LEN && IsData(i); i--); + + return i + 1; + } + int i = std::min(16, from), j; while (i > 0) @@ -280,19 +340,61 @@ int InstructionUp(int from) } // if we get here, no suitable instruction was found - if ((from >= 2) && (GetMem(from - 2) == 0x00)) - return (from - 2); // if a BRK instruction is possible, use that if (from) - return (from - 1); // else, scroll up one byte + return (from - 1); // scroll up one byte return 0; // of course, if we can't scroll up, just return 0! } + int InstructionDown(int from) { + if (IsData(from)) + { + // Scroll past the end of the data block, up to MAX_DB_LEN bytes. + int i = from + 1; + for (; i < from + MAX_DB_LEN && IsData(i); i++); + + return i; + } + int tmp = opsize[GetMem(si.nPos)]; if ((tmp)) return from + tmp; else - return from + 1; // this is data or undefined instruction + return from + 1; // this is an undefined instruction +} + +// Updates the scroll address and comment offset, and sends that info to the debugger window. +// TODO: Make this extern? DebuggerSetScroll or similar. +inline void SetScroll(int addr, int offset) +{ + scrollAddress = addr; + commentOffset = offset; + si.nPos = addr; + SetScrollInfo(GetDlgItem(hDebug, IDC_DEBUGGER_DISASSEMBLY_VSCR), SB_CTL, &si, TRUE); +} + +// Scroll up one visible line, respecting comments and labels. +// commentOffset will eventually tell the DisassembleToWindow function how many comment lines to skip. +AddrScrollInfo ScrollUp() +{ + if (commentOffset) + SetScroll(scrollAddress, --commentOffset); + else + SetScroll(scrollAddress = InstructionUp(scrollAddress), NumAnnotationLines(scrollAddress)); + + return {scrollAddress, commentOffset}; +} + + +AddrScrollInfo ScrollDown() +{ + // TODO: Store this annotationLines info so we can stop recomputing it! + if (commentOffset >= NumAnnotationLines(scrollAddress)) + SetScroll(InstructionDown(scrollAddress), 0); + else + SetScroll(scrollAddress, ++commentOffset); + + return {scrollAddress, commentOffset}; } static void UpdateDialog(HWND hwndDlg) { @@ -304,13 +406,6 @@ static void UpdateDialog(HWND hwndDlg) { EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MEM_CPU),enable); EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MEM_PPU),enable); EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MEM_SPR),enable); - //nah.. lets leave these checked - //CheckDlgButton(hwndDlg,IDC_ADDBP_MODE_R,BST_UNCHECKED); - //CheckDlgButton(hwndDlg,IDC_ADDBP_MODE_W,BST_UNCHECKED); - //CheckDlgButton(hwndDlg,IDC_ADDBP_MODE_X,BST_UNCHECKED); - //CheckDlgButton(hwndDlg,IDC_ADDBP_MEM_CPU,BST_UNCHECKED); - //CheckDlgButton(hwndDlg,IDC_ADDBP_MEM_PPU,BST_UNCHECKED); - //CheckDlgButton(hwndDlg,IDC_ADDBP_MEM_SPR,BST_UNCHECKED); } INT_PTR CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -353,8 +448,6 @@ INT_PTR CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara else CheckDlgButton(hwndDlg, IDC_ADDBP_MEM_CPU, BST_CHECKED); UpdateDialog(hwndDlg); - -// ################################## Start of SP CODE ########################### SendDlgItemMessage(hwndDlg,IDC_ADDBP_CONDITION,EM_SETLIMITTEXT,200,0); SendDlgItemMessage(hwndDlg,IDC_ADDBP_NAME,EM_SETLIMITTEXT,200,0); @@ -376,8 +469,6 @@ INT_PTR CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara { SetDlgItemText(hwndDlg, IDC_ADDBP_NAME, ""); } - -// ################################## End of SP CODE ########################### } else { CheckDlgButton(hwndDlg, IDC_ADDBP_MEM_CPU, BST_CHECKED); @@ -445,7 +536,7 @@ INT_PTR CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara } break; } - return FALSE; //TRUE; + return FALSE; } void HighlightPC(HWND hWnd) @@ -454,12 +545,22 @@ void HighlightPC(HWND hWnd) return; FINDTEXT ft; - ft.lpstrText = ">"; + ft.lpstrText = "\r"; ft.chrg.cpMin = 0; ft.chrg.cpMax = -1; - int start = SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_FINDTEXT, (WPARAM)FR_DOWN, (LPARAM)&ft); + + int start = 0; + + for (int i = 0; i < PCLine; i++) + { + // Scroll down to PCLine by looking for newlines + start = SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_FINDTEXT, (WPARAM)FR_DOWN, (LPARAM)&ft) + 1; + ft.chrg.cpMin = start; + } + if (start >= 0) { + // Highlight PC int old_start, old_end; SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_GETSEL, (WPARAM)&old_start, (LPARAM)&old_end); SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETSEL, (WPARAM)start, (LPARAM)start+20); @@ -483,6 +584,7 @@ void HighlightSyntax(HWND hWnd, int lines) wordbreak = SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_FINDWORDBREAK, (WPARAM)WB_RIGHT, (LPARAM)newline.chrg.cpMin + 21); for (int ch = newline.chrg.cpMin; ; ch++) { + // Lots of highlighting glitches for labels like @loop or table-1. Need to forbid these characters in labels or interlace this with the disassembly process. if (debug_wstr[ch] == L'=' || debug_wstr[ch] == L'@' || debug_wstr[ch] == L'\n' || debug_wstr[ch] == L'-' || debug_wstr[ch] == L';') { opbreak = ch; @@ -495,23 +597,29 @@ void HighlightSyntax(HWND hWnd, int lines) int oldline = newline.chrg.cpMin; newline.chrg.cpMin = SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_FINDTEXT, (WPARAM)FR_DOWN, (LPARAM)&newline) + 1; if(newline.chrg.cpMin == 0) break; - // symbolic address - if (debug_wstr[newline.chrg.cpMin - 2] == L':') - { - SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETSEL, (WPARAM)oldline, (LPARAM)newline.chrg.cpMin); - SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)PPCF(DbgSym)); - continue; - } - if (!commentline) - SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)PPCF(DbgMnem)); - // comment + if (!commentline) + { + // We checked for semicolons first because otherwise this would detect comments ending in a colon. + if (debug_wstr[newline.chrg.cpMin - 2] == L':') + { + // Named label line. + SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETSEL, (WPARAM)oldline, (LPARAM)newline.chrg.cpMin); + SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)PPCF(DbgSym)); + continue; + } + SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)PPCF(DbgMnem)); + } + // Comment or code. NOT label. if (opbreak < newline.chrg.cpMin) { SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETSEL, (WPARAM)opbreak, (LPARAM)newline.chrg.cpMin); if (commentline) + { SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)PPCF(DbgComm)); - else + continue; + } else { + // RTS/RTI dash. Gets confused by dashes in label names! if (debug_wstr[opbreak] == L'-') SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_SETCHARFORMAT, (WPARAM)SCF_SELECTION, (LPARAM)PPCF(DbgRts)); @@ -528,17 +636,13 @@ void HighlightSyntax(HWND hWnd, int lines) } } } - if (commentline) - continue; // operand num.chrg.cpMin = wordbreak; num.chrg.cpMax = wordbreak + 6; numpos = SendDlgItemMessage(hWnd, IDC_DEBUGGER_DISASSEMBLY, EM_FINDTEXT, (WPARAM)FR_DOWN, (LPARAM)&num); if (numpos != 0) { - if (debug_wstr[numpos + 3] == L',' || debug_wstr[numpos + 3] == L')' || debug_wstr[numpos + 3] == L'\n' - || debug_wstr[numpos + 3] == L' ' //zero 30-nov-2017 - in support of combined label/offset disassembly. not sure this is a good idea - ) + if (debug_wstr[numpos + 3] == L',' || debug_wstr[numpos + 3] == L')' || debug_wstr[numpos + 3] == L'\n' || debug_wstr[numpos + 3] == L' ') wordbreak = numpos + 2; else wordbreak = numpos + 4; @@ -568,16 +672,21 @@ void UpdateDisassembleView(HWND hWnd, UINT id, int lines, bool text = false) SendDlgItemMessage(hWnd, id, EM_SETEVENTMASK, 0, eventMask); } -void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) +/** +* Disassembles to the debugger window using the existing address scroll info. +* Assumes that either SetScroll or the overload that takes address and offset was called. +*/ +void DisassembleToWindow(HWND hWnd, int id, int scrollid) { - wchar_t chr[40] = { 0 }; + // Why is this getting called twice per scroll? wchar_t debug_wbuf[2048] = { 0 }; int size; uint8 opcode[3]; unsigned int instruction_addr; + unsigned int addr = scrollAddress; + int skiplines = commentOffset; disassembly_addresses.resize(0); - PCPointerWasDrawn = false; beginningOfPCPointerLine = -1; if (symbDebugEnabled) @@ -586,9 +695,6 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) disassembly_operands.resize(0); } - si.nPos = addr; - SetScrollInfo(GetDlgItem(hWnd,scrollid),SB_CTL,&si,TRUE); - //figure out how many lines we can draw RECT rect; GetClientRect(GetDlgItem(hWnd, id), &rect); @@ -596,7 +702,7 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) debug_wstr[0] = 0; PCLine = -1; - unsigned int instructions_count = 0; + unsigned int line_count = 0; for (int i = 0; i < lines; i++) { // PC pointer @@ -612,12 +718,20 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) { if (node->name) { - swprintf(debug_wbuf, L"%S:\n", node->name); - wcscat(debug_wstr, debug_wbuf); - // we added one line to the disassembly window - disassembly_addresses.push_back(addr); - disassembly_operands.resize(i + 1); - i++; + if (skiplines == 0) + { + swprintf(debug_wbuf, L"%S:\n", node->name); + wcscat(debug_wstr, debug_wbuf); + // we added one line to the disassembly window + disassembly_addresses.push_back(addr); + disassembly_operands.resize(i + 1); + line_count++; + i++; + } + else + { + skiplines--; + } } if (node->comment) { @@ -631,12 +745,20 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) { debug_decoration_comment_end_pos[0] = 0; // set \0 instead of \r debug_decoration_comment_end_pos[1] = 0; // set \0 instead of \n - swprintf(debug_wbuf, L"; %S\n", debug_decoration_comment); - wcscat(debug_wstr, debug_wbuf); - // we added one line to the disassembly window - disassembly_addresses.push_back(addr); - disassembly_operands.resize(i + 1); - i++; + if (skiplines == 0) + { + swprintf(debug_wbuf, L"; %S\n", debug_decoration_comment); + wcscat(debug_wstr, debug_wbuf); + // we added one line to the disassembly window + disassembly_addresses.push_back(addr); + disassembly_operands.resize(i + 1); + i++; + line_count++; + } + else + { + skiplines--; + } debug_decoration_comment_end_pos += 2; debug_decoration_comment = debug_decoration_comment_end_pos; @@ -644,81 +766,59 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) } } } + if (skiplines) + { + // We were told to skip more comment/name lines than exist. + commentOffset -= skiplines; + skiplines = 0; + } } if (addr == X.PC) { - PC_pointerOffset = instructions_count; - PCPointerWasDrawn = true; + PCLine = line_count; beginningOfPCPointerLine = wcslen(debug_wstr); wcscat(debug_wstr, L">"); - PCLine = instructions_count; } else { wcscat(debug_wstr, L" "); } - - if (addr >= 0x8000) - { - if (debuggerDisplayROMoffsets && GetNesFileAddress(addr) != -1) - { - swprintf(chr, L" %06X: ", GetNesFileAddress(addr)); - } else - { - swprintf(chr, L"%02X:%04X: ", getBank(addr), addr); - } - } else - { - swprintf(chr, L" :%04X: ", addr); - } // Add address - wcscat(debug_wstr, chr); disassembly_addresses.push_back(addr); if (symbDebugEnabled) disassembly_operands.resize(i + 1); - size = opsize[GetMem(addr)]; - if (size == 0) + static char bufferForDisassemblyWithPlentyOfStuff[64 + NL_MAX_NAME_LEN * 10]; //"plenty" + + if (IsData(addr)) { - swprintf(chr, L"%02X UNDEFINED", GetMem(addr++)); - wcscat(debug_wstr, chr); + // TOOD: Label-respecting logic. But then the whole "array" naming convetion gets obnoxious. + + // Determine data block length + for (size = 1; size < MAX_DB_LEN && IsData(addr + size); size++); + + char *_a = DisassembleDataBlock(addr, size, debuggerShowTraceInfo, debuggerDisplayROMoffsets); + strcpy(bufferForDisassemblyWithPlentyOfStuff, _a); } else { - if ((addr + size) > 0xFFFF) - { - while (addr < 0xFFFF) - { - swprintf(chr, L"%02X OVERFLOW\n", GetMem(addr++)); - wcscat(debug_wstr, chr); - } - break; - } - for (int j = 0; j < size; j++) - { - swprintf(chr, L"%02X ", opcode[j] = GetMem(addr++)); - wcscat(debug_wstr, chr); - } - while (size < 3) - { - wcscat(debug_wstr, L" "); //pad output to align ASM - size++; - } - - static char bufferForDisassemblyWithPlentyOfStuff[64+NL_MAX_NAME_LEN*10]; //"plenty" - char* _a = Disassemble(addr, opcode); + char* _a = DisassembleLine(addr, debuggerShowTraceInfo, debuggerDisplayROMoffsets); strcpy(bufferForDisassemblyWithPlentyOfStuff, _a); - + if (symbDebugEnabled) - { + { // TODO: This will add in both the default name and custom name if you have inlineAddresses enabled. + if (symbRegNames) + replaceRegNames(bufferForDisassemblyWithPlentyOfStuff); replaceNames(ramBankNames, bufferForDisassemblyWithPlentyOfStuff, &disassembly_operands[i]); - for(int p=0;p 0xFFFF) + break; } UpdateDisassembleView(hWnd, id, lines, true); @@ -764,6 +873,26 @@ void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr) } SetDlgItemText(hWnd, IDC_DEBUGGER_DISASSEMBLY_LEFT_PANEL, debug_cdl_str); } + +/** +* Starting at addr, disassembles code to the debugger window. The number of lines is automatically determined +* by the window size. id and scrollid tell the function which dialog items to modify, although a hardcoded ID +* is mixed in, so, eh. +* skiplines is used so that large comments can appear/disappear line by line, as you would expect in a text file, +* rather than jumping in all at once. +* +* @param hWnd Handle to the debugger window +* @param id id of the disassembly textbox +* @param scrollid id of the scrollbar +* @param addr starting address for disassembly +* @param skiplines how many comment/label lines to skip, used for smooth scrolling (default 0) +*/ +void DisassembleToWindow(HWND hWnd, int id, int scrollid, unsigned int addr, int skiplines) +{ + SetScroll(addr, skiplines); + DisassembleToWindow(hWnd, id, scrollid); +} + void PrintOffsetToSeekAndBookmarkFields(int offset) { if (offset >= 0 && hDebug) @@ -777,80 +906,6 @@ void PrintOffsetToSeekAndBookmarkFields(int offset) } } -char *DisassembleLine(int addr) { - static char str[64]={0},chr[25]={0}; - char *c; - int size,j; - uint8 opcode[3]; - - sprintf(str, "%02X:%04X: ", getBank(addr),addr); - size = opsize[GetMem(addr)]; - if (size == 0) - { - sprintf(chr, "%02X UNDEFINED", GetMem(addr++)); - strcat(str,chr); - } - else { - if ((addr+size) > 0x10000) { - sprintf(chr, "%02X OVERFLOW", GetMem(addr)); - strcat(str,chr); - } - else { - for (j = 0; j < size; j++) { - sprintf(chr, "%02X ", opcode[j] = GetMem(addr++)); - strcat(str,chr); - } - while (size < 3) { - strcat(str," "); //pad output to align ASM - size++; - } - strcat(strcat(str," "),Disassemble(addr,opcode)); - } - } - if ((c=strchr(str,'='))) *(c-1) = 0; - if ((c=strchr(str,'@'))) *(c-1) = 0; - return str; -} - -char *DisassembleData(int addr, uint8 *opcode) { - static char str[64]={0},chr[25]={0}; - char *c; - int size,j; - - sprintf(str, "%02X:%04X: ", getBank(addr), addr); - size = opsize[opcode[0]]; - if (size == 0) - { - sprintf(chr, "%02X UNDEFINED", opcode[0]); - strcat(str,chr); - } else - { - if ((addr+size) > 0x10000) - { - sprintf(chr, "%02X OVERFLOW", opcode[0]); - strcat(str,chr); - } else - { - for (j = 0; j < size; j++) - { - sprintf(chr, "%02X ", opcode[j]); - addr++; - strcat(str,chr); - } - while (size < 3) - { - strcat(str," "); //pad output to align ASM - size++; - } - strcat(strcat(str," "),Disassemble(addr,opcode)); - } - } - if ((c=strchr(str,'='))) *(c-1) = 0; - if ((c=strchr(str,'@'))) *(c-1) = 0; - return str; -} - - int GetEditHex(HWND hwndDlg, int id) { char str[9]; int tmp; @@ -859,38 +914,6 @@ int GetEditHex(HWND hwndDlg, int id) { return tmp; } -int *GetEditHexData(HWND hwndDlg, int id){ - static int data[31]; - char str[60]; - int i,j, k; - - GetDlgItemText(hwndDlg,id,str,60); - memset(data,0,31*sizeof(int)); - j=0; - for(i = 0;i < 60;i++){ - if(str[i] == 0)break; - if((str[i] >= '0') && (str[i] <= '9'))j++; - if((str[i] >= 'A') && (str[i] <= 'F'))j++; - if((str[i] >= 'a') && (str[i] <= 'f'))j++; - } - - j=j&1; - for(i = 0;i < 60;i++){ - if(str[i] == 0)break; - k = -1; - if((str[i] >= '0') && (str[i] <= '9'))k=str[i]-'0'; - if((str[i] >= 'A') && (str[i] <= 'F'))k=(str[i]-'A')+10; - if((str[i] >= 'a') && (str[i] <= 'f'))k=(str[i]-'a')+10; - if(k != -1){ - if(j&1)data[j>>1] |= k; - else data[j>>1] |= k<<4; - j++; - } - } - data[j>>1]=-1; - return data; -} - void UpdateRegs(HWND hwndDlg) { if (DebuggerWasUpdated) { X.A = GetEditHex(hwndDlg,IDC_DEBUGGER_VAL_A); @@ -918,7 +941,6 @@ void FCEUD_DebugBreakpoint(int bp_num) // normal breakpoint sprintf(str_temp, "Breakpoint %u Hit at $%04X: ", bp_num, X.PC); strcat(str_temp, BreakToText(bp_num)); - //watchpoint[num].condText OutputLogLine(str_temp); } else if (bp_num == BREAK_TYPE_BADOP) { @@ -967,7 +989,7 @@ void FCEUD_DebugBreakpoint(int bp_num) void win_debuggerLoop(); // HACK to let user interact with the Debugger while emulator isn't updating win_debuggerLoop(); - // since we unfreezed emulation, reset delta_cycles counter + // since we unfroze emulation, reset delta_cycles counter ResetDebugStatisticsDeltaCounters(); } @@ -993,49 +1015,40 @@ void UpdateDebugger(bool jump_to_pc) ShowWindow(hDebug, SW_SHOWNORMAL); SetForegroundWindow(hDebug); + if (!GameInfo) + { + SetDlgItemText(hDebug, IDC_DEBUGGER_DISASSEMBLY, ""); + return; + } + char str[512] = {0}, str2[512] = {0}, chr[8]; - int tmp, ret, i, starting_address; + int tmp, ret, i; if (jump_to_pc || disassembly_addresses.size() == 0) { - starting_address = X.PC; + // For relative positioning, we want start pos to be PC address with the comments scrolled offscreen. + SetScroll(X.PC, NumAnnotationLines(X.PC)); // ensure that PC pointer will be visible even after the window was resized RECT rect; GetClientRect(GetDlgItem(hDebug, IDC_DEBUGGER_DISASSEMBLY), &rect); unsigned int lines = (rect.bottom-rect.top) / debugSystem->disasmFontHeight; - if (PC_pointerOffset >= lines) - PC_pointerOffset = 0; + if (PCLine >= lines) + PCLine = 0; // keep the relative position of the ">" pointer inside the Disassembly window - for (int i = PC_pointerOffset; i > 0; i--) - { - starting_address = InstructionUp(starting_address); - } - Disassemble(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, starting_address); - - // HACK, but I don't see any other way to ensure the ">" pointer is visible when "Symbolic debug" is enabled - if (!PCPointerWasDrawn && PC_pointerOffset) + for (int i = PCLine; i > 0; i--) { - // we've got a problem, probably due to Symbolic info taking so much space that PC pointer couldn't be seen with (PC_pointerOffset > 0) - PC_pointerOffset = 0; - starting_address = X.PC; - // retry with (PC_pointerOffset = 0) now - Disassemble(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, starting_address); + ScrollUp(); } - - starting_address = X.PC; - } else - { - starting_address = disassembly_addresses[0]; - Disassemble(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, starting_address); } + + DisassembleToWindow(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR); - // "Address Bookmark Add" follows the address - //sprintf(str, "%04X", starting_address); - //SetDlgItemText(hDebug, IDC_DEBUGGER_BOOKMARK, str); + // The address in the Add Bookmark textbox follows the scroll pos. + // Update register values sprintf(str, "%02X", X.A); SetDlgItemText(hDebug, IDC_DEBUGGER_VAL_A, str); sprintf(str, "%02X", X.X); @@ -1115,6 +1128,7 @@ void UpdateDebugger(bool jump_to_pc) UpdateBreakpointsCaption(); + // Draw the stack tmp = X.S|0x0100; sprintf(str, "Stack $%04X", tmp); SetDlgItemText(hDebug, IDC_DEBUGGER_VAL_S, str); @@ -1125,7 +1139,6 @@ void UpdateDebugger(bool jump_to_pc) sprintf(str, "%02X", GetMem(tmp)); for (i = 1; i < 128; i++) { - //tmp = ((tmp+1)|0x0100)&0x01FF; //increment and fix pointer to $0100-$01FF range tmp++; if (tmp > 0x1FF) break; @@ -1245,11 +1258,9 @@ void DeleteBreak(int sel) watchpoint[i].address = watchpoint[i+1].address; watchpoint[i].endaddress = watchpoint[i+1].endaddress; watchpoint[i].flags = watchpoint[i+1].flags; -// ################################## Start of SP CODE ########################### watchpoint[i].cond = watchpoint[i+1].cond; watchpoint[i].condText = watchpoint[i+1].condText; watchpoint[i].desc = watchpoint[i+1].desc; -// ################################## End of SP CODE ########################### } // erase last BP item watchpoint[numWPs].address = 0; @@ -1259,9 +1270,7 @@ void DeleteBreak(int sel) watchpoint[numWPs].condText = 0; watchpoint[numWPs].desc = 0; numWPs--; -// ################################## Start of SP CODE ########################### myNumWPs--; -// ################################## End of SP CODE ########################### SendDlgItemMessage(hDebug,IDC_DEBUGGER_BP_LIST,LB_DELETESTRING,sel,0); // select next item in the list if (numWPs) @@ -1286,280 +1295,67 @@ void KillDebugger() { DebuggerExit(); } FCEUI_Debugger().reset(); - FCEUI_SetEmulationPaused(0); //mbg merge 7/18/06 changed from userpause + FCEUI_SetEmulationPaused(0); } +extern char *iNesShortFName(); -int AddAsmHistory(HWND hwndDlg, int id, char *str) { - int index; - index = SendDlgItemMessage(hwndDlg,id,CB_FINDSTRINGEXACT,-1,(LPARAM)(LPSTR)str); - if (index == CB_ERR) { - SendDlgItemMessage(hwndDlg,id,CB_INSERTSTRING,-1,(LPARAM)(LPSTR)str); - return 0; +void DebuggerExit() +{ + debugger_open = 0; + inDebugger = false; + // in case someone calls it multiple times + if (hDebug) + { + // release bitmap icons + for (int i = 0; i < sizeof(dbgcolormenu) / sizeof(DBGCOLORMENU); ++i) + { + DeleteObject(dbgcolormenu[i].menu.bitmap); + dbgcolormenu[i].menu.bitmap = NULL; + } + // Destroy menu + DestroyMenu(hDebugcontext); + DestroyMenu(hDisasmcontext); + // Destroy debug window + DestroyWindow(hDebug); + hDebug = NULL; + free(debug_wstr); + free(debug_cdl_str); + free(debug_str_decoration_comment); } - return 1; } -INT_PTR CALLBACK AssemblerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - int romaddr,count,i,j; - char str[128],*dasm; - static int patchlen,applied,saved,lastundo; - static uint8 patchdata[64][3],undodata[64*3]; - uint8 *ptr; - - switch(uMsg) { - case WM_INITDIALOG: - CenterWindow(hwndDlg); - - //set font - SendDlgItemMessage(hwndDlg,IDC_ASSEMBLER_DISASSEMBLY,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - SendDlgItemMessage(hwndDlg,IDC_ASSEMBLER_PATCH_DISASM,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); +static RECT currDebuggerRect; +static RECT newDebuggerRect; - //set limits - SendDlgItemMessage(hwndDlg,IDC_ASSEMBLER_HISTORY,CB_LIMITTEXT,20,0); +//moves all child items in the dialog when you resize (except for the dock fill controls which are resized) +BOOL CALLBACK DebuggerEnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + POINT* p = (POINT*)lParam; + int dx = p[0].x; + int dy_l = p[0].y; + int dy_r = p[1].y; - SetDlgItemText(hwndDlg,IDC_ASSEMBLER_DISASSEMBLY,DisassembleLine(iaPC)); - SetFocus(GetDlgItem(hwndDlg,IDC_ASSEMBLER_HISTORY)); + RECT crect; + HWND parent = GetParent(hwnd); + GetWindowRect(hwnd, &crect); //Get rect of current child to be resized + ScreenToClient(parent, (LPPOINT)&crect); //Convert rect coordinates to client area coordinates + ScreenToClient(parent, ((LPPOINT)&crect) + 1); - patchlen = 0; - applied = 0; - saved = 0; - lastundo = 0; + switch (GetDlgCtrlID(hwnd)) + { + case IDC_DEBUGGER_DISASSEMBLY: + // horizontal and vertical stretch + crect.right += dx; + crect.bottom += dy_l; + SetWindowPos(hwnd, 0, 0, 0, crect.right - crect.left, crect.bottom - crect.top, SWP_NOZORDER | SWP_NOMOVE); + GetScrollInfo(GetDlgItem(parent, IDC_DEBUGGER_DISASSEMBLY_VSCR), SB_CTL, &si); + DisassembleToWindow(parent, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, si.nPos); break; - case WM_CLOSE: - case WM_QUIT: - EndDialog(hwndDlg,0); - break; - case WM_COMMAND: - { - switch (HIWORD(wParam)) - { - case BN_CLICKED: - { - switch (LOWORD(wParam)) - { - case IDC_ASSEMBLER_APPLY: - if (patchlen) { - ptr = GetNesPRGPointer(GetNesFileAddress(iaPC)-16); - count = 0; - for (i = 0; i < patchlen; i++) { - for (j = 0; j < opsize[patchdata[i][0]]; j++) { - if (count == lastundo) undodata[lastundo++] = ptr[count]; - ptr[count++] = patchdata[i][j]; - } - } - SetWindowText(hwndDlg, "Inline Assembler *Patches Applied*"); - //MessageBeep(MB_OK); - applied = 1; - } - break; - case IDC_ASSEMBLER_SAVE: - if (applied) { - count = romaddr = GetNesFileAddress(iaPC); - for (i = 0; i < patchlen; i++) - { - count += opsize[patchdata[i][0]]; - } - if (patchlen) sprintf(str,"Write patch data to file at addresses 0x%06X - 0x%06X?",romaddr,count-1); - else sprintf(str,"Undo all previously applied patches?"); - if (MessageBox(hwndDlg, str, "Save changes to file?", MB_YESNO|MB_ICONINFORMATION) == IDYES) { - if (iNesSave()) { - saved = 1; - applied = 0; - } - else MessageBox(hwndDlg, "Unable to save changes to file", "Error saving to file", MB_OK | MB_ICONERROR); - } - } - break; - case IDC_ASSEMBLER_UNDO: - if ((count = SendDlgItemMessage(hwndDlg,IDC_ASSEMBLER_PATCH_DISASM,LB_GETCOUNT,0,0))) { - SendDlgItemMessage(hwndDlg,IDC_ASSEMBLER_PATCH_DISASM,LB_DELETESTRING,count-1,0); - patchlen--; - count = 0; - for (i = 0; i < patchlen; i++) - { - count += opsize[patchdata[i][0]]; - } - if (count < lastundo) { - ptr = GetNesPRGPointer(GetNesFileAddress(iaPC)-16); - j = opsize[patchdata[patchlen][0]]; - for (i = count; i < (count+j); i++) { - ptr[i] = undodata[i]; - } - lastundo -= j; - applied = 1; - } - SetDlgItemText(hwndDlg,IDC_ASSEMBLER_DISASSEMBLY,DisassembleLine(iaPC+count)); - } - break; - case IDC_ASSEMBLER_DEFPUSHBUTTON: - count = 0; - for (i = 0; i < patchlen; i++) - { - count += opsize[patchdata[i][0]]; - } - GetDlgItemText(hwndDlg,IDC_ASSEMBLER_HISTORY,str,21); - if (!Assemble(patchdata[patchlen],(iaPC+count),str)) { - count = iaPC; - for (i = 0; i <= patchlen; i++) - { - count += opsize[patchdata[i][0]]; - } - if (count > 0x10000) { //note: don't use 0xFFFF! - MessageBox(hwndDlg, "Patch data cannot exceed address 0xFFFF", "Address error", MB_OK | MB_ICONERROR); - break; - } - SetDlgItemText(hwndDlg,IDC_ASSEMBLER_HISTORY,""); - if (count < 0x10000) SetDlgItemText(hwndDlg,IDC_ASSEMBLER_DISASSEMBLY,DisassembleLine(count)); - else SetDlgItemText(hwndDlg,IDC_ASSEMBLER_DISASSEMBLY,"OVERFLOW"); - dasm = DisassembleData((count-opsize[patchdata[patchlen][0]]),patchdata[patchlen]); - SendDlgItemMessage(hwndDlg,IDC_ASSEMBLER_PATCH_DISASM,LB_INSERTSTRING,-1,(LPARAM)(LPSTR)dasm); - AddAsmHistory(hwndDlg,IDC_ASSEMBLER_HISTORY,dasm+16); - SetWindowText(hwndDlg, "Inline Assembler"); - patchlen++; - } - else { //ERROR! - SetWindowText(hwndDlg, "Inline Assembler *Syntax Error*"); - MessageBeep(MB_ICONEXCLAMATION); - } - break; - } - SetFocus(GetDlgItem(hwndDlg,IDC_ASSEMBLER_HISTORY)); //set focus to combo box after anything is pressed! - break; - } - } - break; - } - } - return FALSE; -} - -INT_PTR CALLBACK PatcherCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - char str[64]; //mbg merge 7/18/06 changed from unsigned char - uint8 *c; - int i; - int *p; - - switch(uMsg) { - case WM_INITDIALOG: - CenterWindow(hwndDlg); - - //set limits - SendDlgItemMessage(hwndDlg,IDC_ROMPATCHER_OFFSET,EM_SETLIMITTEXT,6,0); - SendDlgItemMessage(hwndDlg,IDC_ROMPATCHER_PATCH_DATA,EM_SETLIMITTEXT,30,0); - UpdatePatcher(hwndDlg); - - if(iapoffset != -1){ - CheckDlgButton(hwndDlg, IDC_ROMPATCHER_DOTNES_OFFSET, BST_CHECKED); - sprintf((char*)str,"%X",iapoffset); //mbg merge 7/18/06 added cast - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_OFFSET,str); - } - - SetFocus(GetDlgItem(hwndDlg,IDC_ROMPATCHER_OFFSET_BOX)); - break; - case WM_CLOSE: - case WM_QUIT: - EndDialog(hwndDlg,0); - break; - case WM_COMMAND: - switch(HIWORD(wParam)) { - case BN_CLICKED: - switch(LOWORD(wParam)) { - case IDC_ROMPATCHER_BTN_EDIT: //todo: maybe get rid of this button and cause iapoffset to update every time you change the text - if(IsDlgButtonChecked(hwndDlg,IDC_ROMPATCHER_DOTNES_OFFSET) == BST_CHECKED) - iapoffset = GetEditHex(hwndDlg,IDC_ROMPATCHER_OFFSET); - else - iapoffset = GetNesFileAddress(GetEditHex(hwndDlg,IDC_ROMPATCHER_OFFSET)); - if((iapoffset < 16) && (iapoffset != -1)){ - MessageBox(hDebug, "Sorry, iNES Header editing isn't supported by this tool. If you want to edit the header, please use iNES Header Editor", "Error", MB_OK | MB_ICONASTERISK); - iapoffset = -1; - } - if((iapoffset > PRGsize[0]) && (iapoffset != -1)){ - MessageBox(hDebug, "Error: .Nes offset outside of PRG rom", "Error", MB_OK | MB_ICONERROR); - iapoffset = -1; - } - UpdatePatcher(hwndDlg); - break; - case IDC_ROMPATCHER_BTN_APPLY: - p = GetEditHexData(hwndDlg,IDC_ROMPATCHER_PATCH_DATA); - i=0; - c = GetNesPRGPointer(iapoffset-16); - while(p[i] != -1){ - c[i] = p[i]; - i++; - } - UpdatePatcher(hwndDlg); - break; - case IDC_ROMPATCHER_BTN_SAVE: - if (!iNesSave()) - MessageBox(NULL, "Error Saving", "Error", MB_OK | MB_ICONERROR); - break; - } - break; - } - break; - } - return FALSE; -} - -extern char *iNesShortFName(); - -void DebuggerExit() -{ - debugger_open = 0; - inDebugger = false; - // in case someone call it multiple times - if (hDebug) - { - // release bitmap icons - for (int i = 0; i < sizeof(dbgcolormenu) / sizeof(DBGCOLORMENU); ++i) - { - DeleteObject(dbgcolormenu[i].menu.bitmap); - dbgcolormenu[i].menu.bitmap = NULL; - } - // Destroy menu - DestroyMenu(hDebugcontext); - DestroyMenu(hDisasmcontext); - // Destroy debug window - DestroyWindow(hDebug); - hDebug = NULL; - free(debug_wstr); - free(debug_cdl_str); - free(debug_str_decoration_comment); - } -} - -static RECT currDebuggerRect; -static RECT newDebuggerRect; - -//used to move all child items in the dialog when you resize (except for the dock fill controls which are resized) -BOOL CALLBACK DebuggerEnumWindowsProc(HWND hwnd, LPARAM lParam) -{ - POINT* p = (POINT*)lParam; - int dx = p[0].x; - int dy_l = p[0].y; - int dy_r = p[1].y; - - RECT crect; - HWND parent = GetParent(hwnd); - GetWindowRect(hwnd, &crect); //Get rect of current child to be resized - ScreenToClient(parent, (LPPOINT)&crect); //Convert rect coordinates to client area coordinates - ScreenToClient(parent, ((LPPOINT)&crect) + 1); - - switch (GetDlgCtrlID(hwnd)) - { - case IDC_DEBUGGER_DISASSEMBLY: - // horizontal and vertical stretch - crect.right += dx; - crect.bottom += dy_l; - SetWindowPos(hwnd, 0, 0, 0, crect.right - crect.left, crect.bottom - crect.top, SWP_NOZORDER | SWP_NOMOVE); - GetScrollInfo(GetDlgItem(parent, IDC_DEBUGGER_DISASSEMBLY_VSCR), SB_CTL, &si); - Disassemble(parent, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, si.nPos); - break; - case IDC_DEBUGGER_DISASSEMBLY_LEFT_PANEL: - // vertical stretch, no movement - crect.bottom += dy_l; - SetWindowPos(hwnd, 0, 0, 0, crect.right - crect.left, crect.bottom - crect.top, SWP_NOZORDER | SWP_NOMOVE); + case IDC_DEBUGGER_DISASSEMBLY_LEFT_PANEL: + // vertical stretch, no movement + crect.bottom += dy_l; + SetWindowPos(hwnd, 0, 0, 0, crect.right - crect.left, crect.bottom - crect.top, SWP_NOZORDER | SWP_NOMOVE); break; case IDC_DEBUGGER_VAL_S: case IDC_DEBUGGER_STACK_CONTENTS: @@ -1604,7 +1400,6 @@ BOOL CALLBACK DebuggerEnumWindowsProc(HWND hwnd, LPARAM lParam) case IDC_DEBUGGER_BP_ADD: case IDC_DEBUGGER_BP_DEL: case IDC_DEBUGGER_BP_EDIT: - case IDC_DEBUGGER_BREAK_ON_BAD_OP: case IDC_DEBUGGER_STATUSFLAGS: case IDC_DEBUGGER_FLAG_N: case IDC_DEBUGGER_FLAG_V: @@ -1643,20 +1438,6 @@ BOOL CALLBACK DebuggerEnumWindowsProc(HWND hwnd, LPARAM lParam) crect.left += dx; SetWindowPos(hwnd, 0, crect.left, crect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); break; - case IDC_DEBUGGER_VAL_S3: - case IDC_DEBUGGER_ROM_OFFSETS: - case IDC_DEBUGGER_ENABLE_SYMBOLIC: - case IDC_DEBUGGER_PREDEFINED_REGS: - case IDC_DEBUGGER_RELOAD_SYMS: - case IDC_DEBUGGER_ROM_PATCHER: - case DEBUGAUTOLOAD: - case DEBUGLOADDEB: - case DEBUGIDAFONT: - // no stretch, move up and down full length, move left and right full length - crect.top += dy_r; - crect.left += dx; - SetWindowPos(hwnd, 0, crect.left, crect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); - break; case IDC_DEBUGGER_ADDR_LINE: // horizontal stretch, move up and down full length crect.top += dy_l; @@ -1846,7 +1627,6 @@ BOOL CALLBACK IDC_DEBUGGER_DISASSEMBLY_WndProc(HWND hwndDlg, UINT uMsg, WPARAM w if (!symbDebugEnabled) { symbDebugEnabled = true; - CheckDlgButton(hDebug, IDC_DEBUGGER_ENABLE_SYMBOLIC, BST_CHECKED); } UpdateDebugger(false); } else @@ -1946,749 +1726,949 @@ BOOL CALLBACK IDC_DEBUGGER_DISASSEMBLY_WndProc(HWND hwndDlg, UINT uMsg, WPARAM w return CallWindowProc(IDC_DEBUGGER_DISASSEMBLY_oldWndProc, hwndDlg, uMsg, wParam, lParam); } -INT_PTR CALLBACK DebuggerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +// Need to coordinate these with res.rc +#define MENU_OPTIONS_POS 0 +#define MENU_SYMBOLS_POS 1 +#define MENU_TOOLS_POS 2 + +#define MENU_OPTIONS_COLORS_POS 2 + +HMENU toolsPopup, symbolsPopup, optionsPopup; + +INT_PTR CALLBACK DebuggerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +inline int CheckedFlag(bool b) { - //these messages get handled at any time - switch(uMsg) - { - case WM_INITDIALOG: - { - char str[256] = { 0 }; - CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_CYCLES, break_on_cycles ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_INSTRUCTIONS, break_on_instructions ? BST_CHECKED : BST_UNCHECKED); - sprintf(str, "%u", (unsigned)break_cycles_limit); - SetDlgItemText(hwndDlg, IDC_DEBUGGER_CYCLES_EXCEED, str); - sprintf(str, "%u", (unsigned)break_instructions_limit); - SetDlgItemText(hwndDlg, IDC_DEBUGGER_INSTRUCTIONS_EXCEED, str); - - CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_BAD_OP, FCEUI_Debugger().badopbreak ? BST_CHECKED : BST_UNCHECKED); - - CheckDlgButton(hwndDlg, DEBUGLOADDEB, debuggerSaveLoadDEBFiles ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, DEBUGIDAFONT, debuggerIDAFont ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, DEBUGAUTOLOAD, debuggerAutoload ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_DEBUGGER_ROM_OFFSETS, debuggerDisplayROMoffsets ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_DEBUGGER_ENABLE_SYMBOLIC, symbDebugEnabled ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_DEBUGGER_PREDEFINED_REGS, symbRegNames ? BST_CHECKED : BST_UNCHECKED); - - if (DbgPosX==-32000) DbgPosX=0; //Just in case - if (DbgPosY==-32000) DbgPosY=0; - SetWindowPos(hwndDlg,0,DbgPosX,DbgPosY,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER); - - GetWindowRect(hwndDlg,&currDebuggerRect); - - si.cbSize = sizeof(SCROLLINFO); - si.fMask = SIF_ALL; - si.nMin = 0; - si.nMax = 0x10000; - si.nPos = 0; - si.nPage = 8; - SetScrollInfo(GetDlgItem(hwndDlg,IDC_DEBUGGER_DISASSEMBLY_VSCR),SB_CTL,&si,TRUE); - - //setup font - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_DISASSEMBLY,WM_SETFONT,(WPARAM)debugSystem->hDisasmFont,FALSE); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_DISASSEMBLY_LEFT_PANEL,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - //SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_A,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - //SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_X,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - //SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_Y,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - //SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PC,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_STACK_CONTENTS,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - //SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); - - //text limits - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_A,EM_SETLIMITTEXT,2,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_X,EM_SETLIMITTEXT,2,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_Y,EM_SETLIMITTEXT,2,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PC,EM_SETLIMITTEXT,4,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_STACK_CONTENTS,EM_SETLIMITTEXT,383,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,EM_SETLIMITTEXT,4,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PPU,EM_SETLIMITTEXT,4,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_SPR,EM_SETLIMITTEXT,2,0); - - // limit input - // Don't limit address entry. See: debugcpp offsetStringToInt - //DefaultEditCtrlProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_PCSEEK), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); - DefaultEditCtrlProc = (WNDPROC) - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_PC), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_A), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_X), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); - SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_Y), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); - //SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_BOOKMARK), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); - - //I'm lazy, disable the controls which I can't mess with right now - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PPU,EM_SETREADONLY,TRUE,0); - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_SPR,EM_SETREADONLY,TRUE,0); + return b ? MF_CHECKED : MF_UNCHECKED; +} -// ################################## Start of SP CODE ########################### +inline int EnabledFlag(bool b) +{ + return b ? MF_ENABLED : MF_GRAYED; +} - SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BOOKMARK,EM_SETLIMITTEXT,4,0); - - LoadGameDebuggerData(hwndDlg); +inline void UpdateOptionsPopup(HMENU optionsPopup) +{ + CheckMenuItem(optionsPopup, ID_DEBUGGER_AUTO_OPEN, CheckedFlag(debuggerAutoload)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_IDA_FONT, CheckedFlag(debuggerIDAFont)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_SHOW_ROM_OFFSETS, CheckedFlag(debuggerDisplayROMoffsets)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_SHOW_TRACE_INFO, CheckedFlag(debuggerShowTraceInfo)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_UNLOGGED_AS_DATA, CheckedFlag(debuggerUnloggedBytesAsData)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_BREAK_BAD_OPCODES, CheckedFlag(FCEUI_Debugger().badopbreak)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_BREAK_UNLOGGED_CODE, CheckedFlag(break_on_unlogged_code)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_BREAK_UNLOGGED_DATA, CheckedFlag(break_on_unlogged_data)); + CheckMenuItem(optionsPopup, ID_DEBUGGER_FOLLOW_PC, CheckedFlag(debuggerFollowPc)); + + // Gray out potentially irrelavant options + EnableMenuItem(optionsPopup, ID_DEBUGGER_UNLOGGED_AS_DATA, EnabledFlag(cdloggerdataSize)); + EnableMenuItem(optionsPopup, ID_DEBUGGER_BREAK_UNLOGGED_CODE, EnabledFlag(cdloggerdataSize)); + EnableMenuItem(optionsPopup, ID_DEBUGGER_BREAK_UNLOGGED_DATA, EnabledFlag(cdloggerdataSize)); +} - debuggerWasActive = 1; - -// ################################## End of SP CODE ########################### +inline void UpdateSymbolsPopup(HMENU symbolsPopup) +{ + CheckMenuItem(symbolsPopup, ID_DEBUGGER_LOAD_DEB_FILE, CheckedFlag(debuggerSaveLoadDEBFiles)); + CheckMenuItem(symbolsPopup, ID_DEBUGGER_SYMBOLIC_DEBUG, CheckedFlag(symbDebugEnabled)); + CheckMenuItem(symbolsPopup, ID_DEBUGGER_INLINE_ADDRESS, CheckedFlag(inlineAddressEnabled)); + CheckMenuItem(symbolsPopup, ID_DEBUGGER_DEFAULT_REG_NAMES, CheckedFlag(symbRegNames)); + + // Gray out potentially irrelavant options + EnableMenuItem(symbolsPopup, ID_DEBUGGER_DEFAULT_REG_NAMES, EnabledFlag(symbDebugEnabled)); + EnableMenuItem(symbolsPopup, ID_DEBUGGER_INLINE_ADDRESS, EnabledFlag(symbDebugEnabled)); + EnableMenuItem(symbolsPopup, ID_DEBUGGER_RELOAD_SYMBOLS, EnabledFlag(GameInfo)); +} + +inline void UpdateToolsPopup(HMENU toolsPopup) +{ + EnableMenuItem(toolsPopup, ID_DEBUGGER_ROM_PATCHER, EnabledFlag(GameInfo)); + EnableMenuItem(toolsPopup, ID_DEBUGGER_CODE_DUMPER, EnabledFlag(GameInfo)); +} - // Enable Context Sub-Menus - hDebugcontext = LoadMenu(fceu_hInstance,"DEBUGCONTEXTMENUS"); - hDisasmcontext = LoadMenu(fceu_hInstance,"DISASMCONTEXTMENUS"); +void DebuggerInitDialog(HWND hwndDlg) +{ + char str[256] = { 0 }; + CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_CYCLES, break_on_cycles ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_INSTRUCTIONS, break_on_instructions ? BST_CHECKED : BST_UNCHECKED); + sprintf(str, "%u", (unsigned)break_cycles_limit); + SetDlgItemText(hwndDlg, IDC_DEBUGGER_CYCLES_EXCEED, str); + sprintf(str, "%u", (unsigned)break_instructions_limit); + SetDlgItemText(hwndDlg, IDC_DEBUGGER_INSTRUCTIONS_EXCEED, str); + + if (DbgPosX==-32000) DbgPosX=0; //Just in case + if (DbgPosY==-32000) DbgPosY=0; + SetWindowPos(hwndDlg,0,DbgPosX,DbgPosY,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER); + + GetWindowRect(hwndDlg,&currDebuggerRect); + + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_ALL; + si.nMin = 0; + si.nMax = 0x10000; + si.nPos = 0; + si.nPage = 8; + SetScrollInfo(GetDlgItem(hwndDlg,IDC_DEBUGGER_DISASSEMBLY_VSCR),SB_CTL,&si,TRUE); + + //setup font + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_DISASSEMBLY,WM_SETFONT,(WPARAM)debugSystem->hDisasmFont,FALSE); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_DISASSEMBLY_LEFT_PANEL,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_STACK_CONTENTS,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,WM_SETFONT,(WPARAM)debugSystem->hFixedFont,FALSE); + + //text limits + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_A,EM_SETLIMITTEXT,2,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_X,EM_SETLIMITTEXT,2,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_Y,EM_SETLIMITTEXT,2,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PC,EM_SETLIMITTEXT,4,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_STACK_CONTENTS,EM_SETLIMITTEXT,383,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,EM_SETLIMITTEXT,4,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PPU,EM_SETLIMITTEXT,4,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_SPR,EM_SETLIMITTEXT,2,0); + + // limit input + // Don't limit address entry. See: debugcpp offsetStringToInt + DefaultEditCtrlProc = (WNDPROC) + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_PC), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_A), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_X), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_Y), GWLP_WNDPROC, (LONG_PTR)FilterEditCtrlProc); + + //I'm lazy, disable the controls which I can't mess with right now + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_PPU,EM_SETREADONLY,TRUE,0); + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_VAL_SPR,EM_SETREADONLY,TRUE,0); + + SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BOOKMARK,EM_SETLIMITTEXT,4,0); + + LoadGameDebuggerData(hwndDlg); - // prevent the font of the edit control from screwing up when it contains MBC or characters not contained the current font. - SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, EM_SETLANGOPTIONS, 0, SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOFONT); + debuggerWasActive = 1; - // subclass editfield - IDC_DEBUGGER_DISASSEMBLY_oldWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_DISASSEMBLY), GWLP_WNDPROC, (LONG_PTR)IDC_DEBUGGER_DISASSEMBLY_WndProc); + // Enable Context Sub-Menus + hDebugcontext = LoadMenu(fceu_hInstance,"DEBUGCONTEXTMENUS"); + hDisasmcontext = LoadMenu(fceu_hInstance,"DISASMCONTEXTMENUS"); - // prepare menu - HMENU hdbgmenu = GetMenu(hwndDlg); - InsertMenu(hdbgmenu, 0, MF_STRING | MF_BYPOSITION, IDC_DEBUGGER_RESTORESIZE, "Default window size"); - HMENU hcolorpopupmenu = GetSubMenu(hdbgmenu, 1); - for (int i = 0; i < sizeof(dbgcolormenu) / sizeof(DBGCOLORMENU); ++i) - InsertColorMenu(hwndDlg, hcolorpopupmenu, &dbgcolormenu[i].menu, i, ID_COLOR_DEBUGGER + i); + // prevent the font of the edit control from screwing up when it contains MBC or characters not contained the current font. + SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, EM_SETLANGOPTIONS, 0, SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOFONT); - debugger_open = 1; - inDebugger = true; - break; + // subclass editfield + IDC_DEBUGGER_DISASSEMBLY_oldWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DEBUGGER_DISASSEMBLY), GWLP_WNDPROC, (LONG_PTR)IDC_DEBUGGER_DISASSEMBLY_WndProc); + + // prepare menu + HMENU hdbgmenu = GetMenu(hwndDlg); + + UpdateOptionsPopup(optionsPopup = GetSubMenu(hdbgmenu, MENU_OPTIONS_POS)); + UpdateSymbolsPopup(symbolsPopup = GetSubMenu(hdbgmenu, MENU_SYMBOLS_POS)); + UpdateToolsPopup(toolsPopup = GetSubMenu(hdbgmenu, MENU_TOOLS_POS)); + + // Preprocessor nonsense to dynamically generate the colors menu + HMENU hcolorpopupmenu = GetSubMenu(optionsPopup, MENU_OPTIONS_COLORS_POS); + for (int i = 0; i < sizeof(dbgcolormenu) / sizeof(DBGCOLORMENU); ++i) + InsertColorMenu(hwndDlg, hcolorpopupmenu, &dbgcolormenu[i].menu, i, ID_COLOR_DEBUGGER + i); + + debugger_open = 1; + inDebugger = true; +} + +void DebuggerResizeWindow(HWND hwndDlg, UINT resizeType) +{ + if(resizeType == SIZE_RESTORED) //If dialog was resized + { + GetWindowRect(hwndDlg,&newDebuggerRect); //Get new size + + //Force a minimum Dialog size------------------------------- + DbgSizeX = newDebuggerRect.right - newDebuggerRect.left; //Store new size (this will be stored in the .cfg file) + DbgSizeY = newDebuggerRect.bottom - newDebuggerRect.top; + + // convert minimum size to actual screen size. + // the minimum height is different between left and right part, + // but width is the same, similarly hereinafter + HDC hdc = GetDC(hwndDlg); + int min_w = MulDiv(DEBUGGER_MIN_WIDTH, GetDeviceCaps(hdc, LOGPIXELSX), 96); + int min_h_l = MulDiv(DEBUGGER_MIN_HEIGHT_LEFT, GetDeviceCaps(hdc, LOGPIXELSY), 96); + int min_h_r = MulDiv(DEBUGGER_MIN_HEIGHT_RIGHT, GetDeviceCaps(hdc, LOGPIXELSY), 96); + ReleaseDC(hwndDlg, hdc); + + // calculate current width and height + int curr_w = currDebuggerRect.right - currDebuggerRect.left; + int curr_h_l = currDebuggerRect.bottom - currDebuggerRect.top; + int curr_h_r = curr_h_l; + // calculate new width and height + int new_w = newDebuggerRect.right - newDebuggerRect.left; + int new_h_l = newDebuggerRect.bottom - newDebuggerRect.top; + int new_h_r = new_h_l; + + // when the size is smaller than the minimum, calculate it as the minimum size + if (curr_w < min_w) curr_w = min_w; + if (curr_h_l < min_h_l) curr_h_l = min_h_l; + if (curr_h_r < min_h_r) curr_h_r = min_h_r; + + if (new_w < min_w) new_w = min_w; + if (new_h_l < min_h_l) new_h_l = min_h_l; + if (new_h_r < min_h_r) new_h_r = min_h_r; + + POINT p[2]; + // Calculate ditto with size + p[0].x = p[1].x = new_w - curr_w; + p[0].y = new_h_l - curr_h_l; + p[1].y = new_h_r - curr_h_r; + EnumChildWindows(hwndDlg, DebuggerEnumWindowsProc, (LPARAM)p); //Initiate callback for resizing child windows + InvalidateRect(hwndDlg, 0, TRUE); + UpdateWindow(hwndDlg); + currDebuggerRect = newDebuggerRect; //Store current debugger window size (for future calculations in EnumChildWindows) + } +} + +void DebuggerLbnDblClk(HWND hwndDlg, uint16 itemId, HWND hwndBtn) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + switch (itemId) + { + case IDC_DEBUGGER_BP_LIST: + EnableBreak(SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_BP_LIST, LB_GETCURSEL, 0, 0)); + break; + case LIST_DEBUGGER_BOOKMARKS: + GoToDebuggerBookmark(hwndDlg); + break; + } +} + +void DebuggerLbnSelCancel(HWND hwndDlg, uint16 listBoxId, HWND hwndList) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + switch (listBoxId) + { + case IDC_DEBUGGER_BP_LIST: + // Disable the delete and edit buttons + EnableWindow(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_DEL), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_EDIT), FALSE); + break; + } +} + +void DebuggerLbnSelChange(HWND hwndDlg, uint16 listBoxId, HWND hwndList) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + switch (listBoxId) + { + case IDC_DEBUGGER_BP_LIST: + { + // If something is selected, enabled the delete and edit buttons. + if (SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_BP_LIST, LB_GETCURSEL, 0, 0) >= 0) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_DEL), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_EDIT), TRUE); } - case WM_SIZE: + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_DEL), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_EDIT), FALSE); + } + break; + } + } +} + +void DebuggerBnClicked(HWND hwndDlg, uint16 btnId, HWND hwndBtn) +{ + // Buttons that don't need a rom loaded to do something, such as autoload + switch (btnId) + { + case ID_DEBUGGER_DEFCOLOR: { - if(wParam == SIZE_RESTORED) //If dialog was resized + if (!IsDebugColorDefault() && MessageBox(hwndDlg, "Do you want to restore all the colors to default?", "Restore default colors", MB_YESNO | MB_ICONINFORMATION) == IDYES) { - GetWindowRect(hwndDlg,&newDebuggerRect); //Get new size - - //Force a minimum Dialog size------------------------------- - DbgSizeX = newDebuggerRect.right - newDebuggerRect.left; //Store new size (this will be used to store in the .cfg file) - DbgSizeY = newDebuggerRect.bottom - newDebuggerRect.top; - - // convert minimum size to actural screen size - // owomomo: the minimum height is different between left and right part, - // but width is the same, similarly hereinafter - HDC hdc = GetDC(hwndDlg); - int min_w = MulDiv(DEBUGGER_MIN_WIDTH, GetDeviceCaps(hdc, LOGPIXELSX), 96); - int min_h_l = MulDiv(DEBUGGER_MIN_HEIGHT_LEFT, GetDeviceCaps(hdc, LOGPIXELSY), 96); - int min_h_r = MulDiv(DEBUGGER_MIN_HEIGHT_RIGHT, GetDeviceCaps(hdc, LOGPIXELSY), 96); - ReleaseDC(hwndDlg, hdc); - - // calculate current width and height - int curr_w = currDebuggerRect.right - currDebuggerRect.left; - int curr_h_l = currDebuggerRect.bottom - currDebuggerRect.top; - int curr_h_r = curr_h_l; - // calculate new width and height - int new_w = newDebuggerRect.right - newDebuggerRect.left; - int new_h_l = newDebuggerRect.bottom - newDebuggerRect.top; - int new_h_r = new_h_l; - - // when the size is smaller than the minimum, calculate it as the minimum size - if (curr_w < min_w) curr_w = min_w; - if (curr_h_l < min_h_l) curr_h_l = min_h_l; - if (curr_h_r < min_h_r) curr_h_r = min_h_r; - - if (new_w < min_w) new_w = min_w; - if (new_h_l < min_h_l) new_h_l = min_h_l; - if (new_h_r < min_h_r) new_h_r = min_h_r; - - POINT p[2]; - // Calculate ditto with size - p[0].x = p[1].x = new_w - curr_w; - p[0].y = new_h_l - curr_h_l; - p[1].y = new_h_r - curr_h_r; - EnumChildWindows(hwndDlg, DebuggerEnumWindowsProc, (LPARAM)p); //Initiate callback for resizing child windows - InvalidateRect(hwndDlg, 0, TRUE); - UpdateWindow(hwndDlg); - currDebuggerRect = newDebuggerRect; //Store current debugger window size (for future calculations in EnumChildWindows + RestoreDefaultDebugColor(); + RECT rect; + GetClientRect(GetDlgItem(hwndDlg, IDC_DEBUGGER_DISASSEMBLY), &rect); + UpdateDisassembleView(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, (rect.bottom - rect.top) / debugSystem->disasmFontHeight); + HMENU hcolorpopupmenu = GetSubMenu(optionsPopup, MENU_OPTIONS_COLORS_POS); + for (int i = 0; i < sizeof(dbgcolormenu) / sizeof(DBGCOLORMENU); ++i) + ModifyColorMenu(hwndDlg, hcolorpopupmenu, &dbgcolormenu[i].menu, i, ID_COLOR_DEBUGGER + i); } - break; } - - - case WM_CLOSE: - case WM_QUIT: - //exitdebug: - DebuggerExit(); + break; + case ID_COLOR_DEBUGGER: + case ID_COLOR_DEBUGGER + 1: + case ID_COLOR_DEBUGGER + 2: + case ID_COLOR_DEBUGGER + 3: + case ID_COLOR_DEBUGGER + 4: + case ID_COLOR_DEBUGGER + 5: + case ID_COLOR_DEBUGGER + 6: + case ID_COLOR_DEBUGGER + 7: + case ID_COLOR_DEBUGGER + 8: + case ID_COLOR_DEBUGGER + 9: + case ID_COLOR_DEBUGGER + 10: + case ID_COLOR_DEBUGGER + 11: + case ID_COLOR_DEBUGGER + 12: + { + int index = btnId - ID_COLOR_DEBUGGER; + if (ChangeColor(hwndDlg, &dbgcolormenu[index])) + { + RECT rect; + GetClientRect(GetDlgItem(hwndDlg, IDC_DEBUGGER_DISASSEMBLY), &rect); + UpdateDisassembleView(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, (rect.bottom - rect.top) / debugSystem->disasmFontHeight); + ModifyColorMenu(hwndDlg, GetSubMenu(GetMenu(hwndDlg), 1), &dbgcolormenu[index].menu, index, btnId); + } + } + break; + // Options menu + case ID_DEBUGGER_AUTO_OPEN: + debuggerAutoload ^= 1; break; - case WM_MOVING: + case ID_DEBUGGER_IDA_FONT: + debuggerIDAFont ^= 1; + debugSystem->hDisasmFont = debuggerIDAFont ? debugSystem->hIDAFont : debugSystem->hFixedFont; + debugSystem->disasmFontHeight = debuggerIDAFont ? IDAFontSize : debugSystem->fixedFontHeight; + SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, WM_SETFONT, (WPARAM)debugSystem->hDisasmFont, FALSE); + UpdateDebugger(false); break; - case WM_MOVE: - if (!IsIconic(hwndDlg)) { - RECT wrect; - GetWindowRect(hwndDlg,&wrect); - DbgPosX = wrect.left; - DbgPosY = wrect.top; - - #ifdef WIN32 - WindowBoundsCheckResize(DbgPosX,DbgPosY,DbgSizeX,wrect.right); - #endif - } + case ID_DEBUGGER_SHOW_TRACE_INFO: + debuggerShowTraceInfo ^= 1; + UpdateDebugger(false); break; - - //adelikat: Buttons that don't need a rom loaded to do something, such as autoload - case WM_COMMAND: - { - switch (HIWORD(wParam)) + case ID_DEBUGGER_UNLOGGED_AS_DATA: + debuggerUnloggedBytesAsData ^= 1; + UpdateDebugger(false); + break; + case ID_DEBUGGER_SHOW_ROM_OFFSETS: + debuggerDisplayROMoffsets ^= 1; + UpdateDebugger(false); + break; + case ID_DEBUGGER_BREAK_BAD_OPCODES: + FCEUI_Debugger().badopbreak ^= 1; + break; + case ID_DEBUGGER_BREAK_UNLOGGED_CODE: + break_on_unlogged_code ^= 1; + break; + case ID_DEBUGGER_BREAK_UNLOGGED_DATA: + break_on_unlogged_data ^= 1; + break; + case ID_DEBUGGER_FOLLOW_PC: + debuggerFollowPc ^= 1; + break; + case ID_DEBUGGER_RESTORE_SIZE: + RestoreSize(hwndDlg); + break; + // Symbols menu + case ID_DEBUGGER_RELOAD_SYMBOLS: + ramBankNamesLoaded = false; + for (int i = 0; i < ARRAYSIZE(pageNumbersLoaded); i++) + pageNumbersLoaded[i] = -1; + loadNameFiles(); + UpdateDebugger(false); + break; + case ID_DEBUGGER_INLINE_ADDRESS: + inlineAddressEnabled ^= 1; + UpdateDebugger(false); + break; + case ID_DEBUGGER_LOAD_DEB_FILE: + debuggerSaveLoadDEBFiles ^= 1; + break; + case ID_DEBUGGER_SYMBOLIC_DEBUG: + symbDebugEnabled ^= 1; + UpdateDebugger(false); + break; + case ID_DEBUGGER_DEFAULT_REG_NAMES: + symbRegNames ^= 1; + UpdateDebugger(false); + break; + // Tools menu + case ID_DEBUGGER_ROM_PATCHER: + DoPatcher(-1, hwndDlg); + break; + case ID_DEBUGGER_CODE_DUMPER: + DialogBox(fceu_hInstance, "CODEDUMPER", hwndDlg, DumperCallB); + break; + case IDOK: + // Make pressing Enter synonymous with the button you'd expect depending on the focus. + HWND focus = GetFocus(); + switch (GetDlgCtrlID(focus)) { - case BN_CLICKED: - { - switch (LOWORD(wParam)) - { - case DEBUGAUTOLOAD: - debuggerAutoload ^= 1; - break; - case DEBUGLOADDEB: - debuggerSaveLoadDEBFiles = !debuggerSaveLoadDEBFiles; - break; - case DEBUGIDAFONT: - debuggerIDAFont ^= 1; - debugSystem->hDisasmFont = debuggerIDAFont ? debugSystem->hIDAFont : debugSystem->hFixedFont; - debugSystem->disasmFontHeight = debuggerIDAFont ? IDAFontSize : debugSystem->fixedFontHeight; - SendDlgItemMessage(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, WM_SETFONT, (WPARAM)debugSystem->hDisasmFont, FALSE); - UpdateDebugger(false); - break; - case IDC_DEBUGGER_CYCLES_EXCEED: - { - if (HIWORD(wParam) == EN_CHANGE) - { - char str[16]; - GetDlgItemText(hwndDlg, IDC_DEBUGGER_CYCLES_EXCEED, str, 16); - break_cycles_limit = strtoul(str, NULL, 10); - } - break; - } - case IDC_DEBUGGER_INSTRUCTIONS_EXCEED: - { - if (HIWORD(wParam) == EN_CHANGE) - { - char str[16]; - GetDlgItemText(hwndDlg, IDC_DEBUGGER_INSTRUCTIONS_EXCEED, str, 16); - break_instructions_limit = strtoul(str, NULL, 10); - } - break; - } - case ID_DEBUGGER_DEFCOLOR: - { - if (!IsDebugColorDefault() && MessageBox(hwndDlg, "Do you want to restore all the colors to default?", "Restore default colors", MB_YESNO | MB_ICONINFORMATION) == IDYES) - { - RestoreDefaultDebugColor(); - RECT rect; - GetClientRect(GetDlgItem(hwndDlg, IDC_DEBUGGER_DISASSEMBLY), &rect); - UpdateDisassembleView(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, (rect.bottom - rect.top) / debugSystem->disasmFontHeight); - HMENU hcolorpopupmenu = GetSubMenu(GetMenu(hwndDlg), 1); - for (int i = 0; i < sizeof(dbgcolormenu) / sizeof(DBGCOLORMENU); ++i) - ModifyColorMenu(hwndDlg, hcolorpopupmenu, &dbgcolormenu[i].menu, i, ID_COLOR_DEBUGGER + i); - } - } - break; - case ID_COLOR_DEBUGGER: - case ID_COLOR_DEBUGGER + 1: - case ID_COLOR_DEBUGGER + 2: - case ID_COLOR_DEBUGGER + 3: - case ID_COLOR_DEBUGGER + 4: - case ID_COLOR_DEBUGGER + 5: - case ID_COLOR_DEBUGGER + 6: - case ID_COLOR_DEBUGGER + 7: - case ID_COLOR_DEBUGGER + 8: - case ID_COLOR_DEBUGGER + 9: - case ID_COLOR_DEBUGGER + 10: - case ID_COLOR_DEBUGGER + 11: - case ID_COLOR_DEBUGGER + 12: - { - int index = wParam - ID_COLOR_DEBUGGER; - if (ChangeColor(hwndDlg, &dbgcolormenu[index])) - { - RECT rect; - GetClientRect(GetDlgItem(hwndDlg, IDC_DEBUGGER_DISASSEMBLY), &rect); - UpdateDisassembleView(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, (rect.bottom - rect.top) / debugSystem->disasmFontHeight); - ModifyColorMenu(hwndDlg, GetSubMenu(GetMenu(hwndDlg), 1), &dbgcolormenu[index].menu, index, wParam); - } - } - break; - case IDC_DEBUGGER_RESTORESIZE: - RestoreSize(hwndDlg); - break; - } - } + case IDC_DEBUGGER_VAL_PCSEEK: + DebuggerBnClicked(hwndDlg, IDC_DEBUGGER_SEEK_TO, NULL); + break; + case IDC_DEBUGGER_BOOKMARK: + DebuggerBnClicked(hwndDlg, IDC_DEBUGGER_BOOKMARK_ADD, NULL); + break; + case IDC_DEBUGGER_VAL_PC: + DebuggerBnClicked(hwndDlg, IDC_DEBUGGER_SEEK_PC, NULL); + break; + case IDC_DEBUGGER_CYCLES_EXCEED: + // Sending click events in this way does not auto-check the box. + DebuggerBnClicked(hwndDlg, IDC_DEBUGGER_BREAK_ON_CYCLES, NULL); + break; + case IDC_DEBUGGER_INSTRUCTIONS_EXCEED: + DebuggerBnClicked(hwndDlg, IDC_DEBUGGER_BREAK_ON_INSTRUCTIONS, NULL); + break; } - } + break; } - //these messages only get handled when a game is loaded + // Buttons that only get handled when a game is loaded if (GameInfo) { - switch(uMsg) + switch (btnId) { - case WM_ACTIVATE: - { - //Prevents numerous situations where the debugger is out of date with the data - if (LOWORD(wParam) != WA_INACTIVE) - { - UpdateDebugger(false); - } else - { - if (FCEUI_EmulationPaused()) - UpdateRegs(hwndDlg); + case IDC_DEBUGGER_BP_ADD: + childwnd = 1; + if (DialogBoxParam(fceu_hInstance,"ADDBP",hwndDlg,AddbpCallB, 0)) AddBreakList(); + childwnd = 0; + UpdateDebugger(false); + break; + case IDC_DEBUGGER_BP_DEL: + DeleteBreak(SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0)); + break; + case IDC_DEBUGGER_BP_EDIT: + WP_edit = SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0); + if (DialogBoxParam(fceu_hInstance, "ADDBP", hwndDlg, AddbpCallB, 0)) EditBreakList(); + WP_edit = -1; + UpdateDebugger(false); + break; + case IDC_DEBUGGER_RUN: + if (FCEUI_EmulationPaused()) { + UpdateRegs(hwndDlg); + FCEUI_ToggleEmulationPause(); + //DebuggerWasUpdated = false done in above function; } break; - } - case WM_VSCROLL: - { - //mbg merge 7/18/06 changed pausing check + case IDC_DEBUGGER_STEP_IN: if (FCEUI_EmulationPaused()) UpdateRegs(hwndDlg); - if (lParam) + FCEUI_Debugger().step = true; + FCEUI_SetEmulationPaused(0); + UpdateOtherDebuggingDialogs(); + break; + case IDC_DEBUGGER_RUN_LINE: + if (FCEUI_EmulationPaused()) + UpdateRegs(hwndDlg); + FCEUI_Debugger().runline = true; { - GetScrollInfo((HWND)lParam,SB_CTL,&si); - switch(LOWORD(wParam)) - { - case SB_ENDSCROLL: - case SB_TOP: - case SB_BOTTOM: break; - case SB_LINEUP: - { - si.nPos = InstructionUp(si.nPos); - break; - } - case SB_LINEDOWN: - { - si.nPos = InstructionDown(si.nPos); - break; - } - case SB_PAGEUP: - { - for (int i = si.nPage; i > 0; i--) - { - si.nPos = InstructionUp(si.nPos); - if (si.nPos < si.nMin) - { - si.nPos = si.nMin; - break; - } - } - break; - } - case SB_PAGEDOWN: - { - for (int i = si.nPage; i > 0; i--) - { - si.nPos = InstructionDown(si.nPos); - if ((si.nPos + (int)si.nPage) > si.nMax) - { - si.nPos = si.nMax - si.nPage; - break; - } - } - break; - } - case SB_THUMBPOSITION: //break; - case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; + uint64 ts=timestampbase; + ts+=timestamp; + ts+=341/3; + FCEUI_Debugger().runline_end_time=ts; + } + FCEUI_SetEmulationPaused(0); + UpdateOtherDebuggingDialogs(); + break; + case IDC_DEBUGGER_RUN_FRAME2: + if (FCEUI_EmulationPaused()) + UpdateRegs(hwndDlg); + FCEUI_Debugger().runline = true; + { + uint64 ts=timestampbase; + ts+=timestamp; + ts+=128*341/3; + FCEUI_Debugger().runline_end_time=ts; + } + FCEUI_SetEmulationPaused(0); + UpdateOtherDebuggingDialogs(); + break; + case IDC_DEBUGGER_STEP_OUT: + if (FCEUI_EmulationPaused() > 0) { + DebuggerState &dbgstate = FCEUI_Debugger(); + UpdateRegs(hwndDlg); + if ((dbgstate.stepout) && (MessageBox(hwndDlg,"Step Out is currently in process. Cancel it and setup a new Step Out watch?","Step Out Already Active",MB_YESNO|MB_ICONINFORMATION) != IDYES)) break; + if (GetMem(X.PC) == 0x20) dbgstate.jsrcount = 1; + else dbgstate.jsrcount = 0; + dbgstate.stepout = 1; + FCEUI_SetEmulationPaused(0); + } + break; + case IDC_DEBUGGER_STEP_OVER: + if (FCEUI_EmulationPaused()) { + UpdateRegs(hwndDlg); + int tmp = X.PC; + uint8 opcode = GetMem(tmp); + bool jsr = opcode==0x20; + bool call = jsr; + #ifdef BRK_3BYTE_HACK + //with this hack, treat BRK similar to JSR + if(opcode == 0x00) + call = true; + #endif + if (call) { + if ((watchpoint[64].flags) && (MessageBox(hwndDlg,"Step Over is currently in process. Cancel it and setup a new Step Over watch?","Step Over Already Active",MB_YESNO|MB_ICONINFORMATION) != IDYES)) break; + watchpoint[64].address = (tmp+3); + watchpoint[64].flags = WP_E|WP_X; } - if (si.nPos < si.nMin) - si.nPos = si.nMin; - if ((si.nPos + (int)si.nPage) > si.nMax) - si.nPos = si.nMax - si.nPage; - SetScrollInfo((HWND)lParam,SB_CTL,&si,TRUE); - - Disassemble(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, si.nPos); - // "Address Bookmark Add" follows the address - char str[16]; + else FCEUI_Debugger().step = true; + FCEUI_SetEmulationPaused(0); + } + break; + case IDC_DEBUGGER_SEEK_PC: + if (FCEUI_EmulationPaused()) + { + UpdateRegs(hwndDlg); + UpdateDebugger(true); + } + break; + case IDC_DEBUGGER_SEEK_TO: + { + if (FCEUI_EmulationPaused()) + UpdateRegs(hwndDlg); + char str[16]; + GetDlgItemText(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,str,5); + int tmp = offsetStringToInt(BT_C, str); + if (tmp != -1) + { + sprintf(str,"%04X", tmp); + SetDlgItemText(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,str); + DisassembleToWindow(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, tmp); + // The address in the Add Bookmark textbox follows the scroll pos. sprintf(str,"%04X", si.nPos); - SetDlgItemText(hwndDlg, IDC_DEBUGGER_BOOKMARK, str); + SetDlgItemText(hDebug, IDC_DEBUGGER_BOOKMARK, str); } break; } - case WM_CONTEXTMENU: + case IDC_DEBUGGER_FLAG_N: X.P^=N_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_V: X.P^=V_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_U: X.P^=U_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_B: X.P^=B_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_D: X.P^=D_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_I: X.P^=I_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_Z: X.P^=Z_FLAG; UpdateDebugger(false); break; + case IDC_DEBUGGER_FLAG_C: X.P^=C_FLAG; UpdateDebugger(false); break; + + case IDC_DEBUGGER_RESET_COUNTERS: { - // Handle certain stubborn context menus for nearly incapable controls. - - if (wParam == (INT_PTR)GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_LIST)) { - // Only open the menu if a breakpoint is selected - if (SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0) >= 0) { - hDebugcontextsub = GetSubMenu(hDebugcontext,0); - //SetMenuDefaultItem(hDebugcontextsub, DEBUGGER_CONTEXT_TOGGLEBREAK, false); - if (lParam != -1) - TrackPopupMenu(hDebugcontextsub,TPM_RIGHTBUTTON,LOWORD(lParam),HIWORD(lParam),0,hwndDlg,0); //Create menu - else { // Handle the context menu keyboard key - RECT wrect; - GetWindowRect(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_LIST), &wrect); - TrackPopupMenu(hDebugcontextsub,TPM_RIGHTBUTTON,wrect.left + int((wrect.right - wrect.left) / 3),wrect.top + int((wrect.bottom - wrect.top) / 3),0,hwndDlg,0); //Create menu - } - } - } + ResetDebugStatisticsCounters(); + UpdateDebugger(false); break; } - case WM_MOUSEWHEEL: + case IDC_DEBUGGER_BREAK_ON_CYCLES: { - GetScrollInfo((HWND)lParam,SB_CTL,&si); - int i = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA; - if (i < 0) - { - for (i *= -(int)si.nPage; i > 0; i--) - { - si.nPos = InstructionDown(si.nPos); - if ((si.nPos + (int)si.nPage) > si.nMax) - { - si.nPos = si.nMax - si.nPage; - break; - } - } - } else if (i > 0) - { - for (i *= si.nPage; i > 0; i--) - { - si.nPos = InstructionUp(si.nPos); - if (si.nPos < si.nMin) - { - si.nPos = si.nMin; - break; - } - } - } - SetScrollInfo((HWND)lParam,SB_CTL,&si,TRUE); - - Disassemble(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, si.nPos); - // "Address Bookmark Add" follows the address - char str[16]; - sprintf(str,"%04X", si.nPos); - SetDlgItemText(hDebug, IDC_DEBUGGER_BOOKMARK, str); + break_on_cycles ^= 1; + CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_CYCLES, break_on_cycles); break; } - case WM_KEYDOWN: - MessageBox(hwndDlg,"Die!","I'm dead!",MB_YESNO|MB_ICONINFORMATION); + case IDC_DEBUGGER_BREAK_ON_INSTRUCTIONS: + { + break_on_instructions ^= 1; + CheckDlgButton(hwndDlg, IDC_DEBUGGER_BREAK_ON_INSTRUCTIONS, break_on_instructions); break; + } + case IDC_DEBUGGER_BOOKMARK_ADD: AddDebuggerBookmark(hwndDlg); break; + case IDC_DEBUGGER_BOOKMARK_DEL: DeleteDebuggerBookmark(hwndDlg); break; + case IDC_DEBUGGER_BOOKMARK_EDIT: EditDebuggerBookmark(hwndDlg); break; + // Double click the breakpoint list + case DEBUGGER_CONTEXT_TOGGLEBREAK: DebuggerLbnDblClk(hwndDlg, IDC_DEBUGGER_BP_LIST, hwndBtn); break; + } + } +} - case WM_MOUSEMOVE: - { - int mouse_x = GET_X_LPARAM(lParam); - int mouse_y = GET_Y_LPARAM(lParam); +void DebuggerInitMenuPopup(HWND hwndDlg, HMENU hmenu, uint16 pos, bool isWindowMenu) +{ + // We have position in parent menu, but we can't get a handle to the parent... + if (hmenu == toolsPopup) + { + UpdateToolsPopup(hmenu); + return; + } + if (hmenu == symbolsPopup) + { + UpdateSymbolsPopup(symbolsPopup); + return; + } + if (hmenu == optionsPopup) + { + UpdateOptionsPopup(optionsPopup); + return; + } +} - bool setString = false; - if ((mouse_x > 6) && (mouse_x < 30) && (mouse_y > 10)) - { - setString = true; - RECT rectDisassembly; - GetClientRect(GetDlgItem(hDebug,IDC_DEBUGGER_DISASSEMBLY),&rectDisassembly); - int height = rectDisassembly.bottom-rectDisassembly.top; - mouse_y -= 10; - if(mouse_y > height) - setString = false; - mouse_y /= debugSystem->disasmFontHeight; - } +void DebuggerMoveWindow(HWND hwndDlg, uint16 x, uint16 y) +{ + if (!IsIconic(hwndDlg)) + { + RECT wrect; + GetWindowRect(hwndDlg,&wrect); + DbgPosX = wrect.left; + DbgPosY = wrect.top; + + #ifdef WIN32 + WindowBoundsCheckResize(DbgPosX,DbgPosY,DbgSizeX,wrect.right); + #endif + } +} - if (setString) - SetDlgItemText(hDebug, IDC_DEBUGGER_ADDR_LINE, "Leftclick = Inline Assembler. Midclick = Game Genie. Rightclick = Hexeditor."); - else - SetDlgItemText(hDebug, IDC_DEBUGGER_ADDR_LINE, ""); +void DebuggerWindowActivate(HWND hwndDlg, uint16 eventType, HWND hwndActivated) +{ + // Prevents numerous situations where the debugger is out of sync with the data + if (eventType != WA_INACTIVE) + { + UpdateDebugger(false); + } + else + { + if (GameInfo && FCEUI_EmulationPaused()) + UpdateRegs(hwndDlg); + } +} + +void DebuggerVScroll(HWND hwndDlg, uint16 eventType, uint16 scrollPos, HWND hwndScrollBar) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + if (FCEUI_EmulationPaused()) + UpdateRegs(hwndDlg); + + if (hwndScrollBar) + { + GetScrollInfo(hwndScrollBar, SB_CTL, &si); + switch (eventType) + { + case SB_ENDSCROLL: + case SB_TOP: + case SB_BOTTOM: break; + case SB_LINEUP: + { + ScrollUp(); break; } - case WM_LBUTTONDOWN: + case SB_LINEDOWN: { - int mouse_x = GET_X_LPARAM(lParam); - int mouse_y = GET_Y_LPARAM(lParam); -// ################################## Start of SP CODE ########################### - - // mouse_y < 538 - // > 33) tmp = 33 - //mbg merge 7/18/06 changed pausing check - if (FCEUI_EmulationPaused() && (mouse_x > 6) && (mouse_x < 30) && (mouse_y > 10)) - { -// ################################## End of SP CODE ########################### - int tmp = (mouse_y - 10) / debugSystem->disasmFontHeight; - if (tmp < (int)disassembly_addresses.size()) - { - int i = disassembly_addresses[tmp]; - //DoPatcher(GetNesFileAddress(i),hwndDlg); - iaPC=i; - if (iaPC >= 0x8000) - { - DialogBox(fceu_hInstance,"ASSEMBLER",hwndDlg,AssemblerCallB); - UpdateDebugger(false); - } - } - } + ScrollDown(); break; } - case WM_RBUTTONDOWN: + case SB_PAGEUP: { - int mouse_x = GET_X_LPARAM(lParam); - int mouse_y = GET_Y_LPARAM(lParam); - //mbg merge 7/18/06 changed pausing check - if (FCEUI_EmulationPaused() && (mouse_x > 6) && (mouse_x < 30) && (mouse_y > 10)) + for (int i = si.nPage; i > 0; i--) { - int tmp = (mouse_y - 10) / debugSystem->disasmFontHeight; - if (tmp < (int)disassembly_addresses.size()) + si.nPos = ScrollUp().address; + if (si.nPos < si.nMin) { - int i = disassembly_addresses[tmp]; - if (i >= 0x8000) - // show ROM data in Hexeditor - ChangeMemViewFocus(3, GetNesFileAddress(i), -1); - else - // show RAM data in Hexeditor - ChangeMemViewFocus(0, i, -1); + si.nPos = si.nMin; + break; } } break; } - case WM_MBUTTONDOWN: + case SB_PAGEDOWN: { - int mouse_x = GET_X_LPARAM(lParam); - int mouse_y = GET_Y_LPARAM(lParam); - //mbg merge 7/18/06 changed pausing check - if (FCEUI_EmulationPaused() && (mouse_x > 6) && (mouse_x < 30) && (mouse_y > 10)) + for (int i = si.nPage; i > 0; i--) { - int tmp = (mouse_y - 10) / debugSystem->disasmFontHeight; - if (tmp < (int)disassembly_addresses.size()) + si.nPos = ScrollDown().address; + if ((si.nPos + (int)si.nPage) > si.nMax) { - int i = disassembly_addresses[tmp]; - SetGGConvFocus(i,GetMem(i)); + si.nPos = si.nMax - si.nPage; + break; } } break; } - case WM_INITMENUPOPUP: - case WM_INITMENU: + case SB_THUMBPOSITION: + case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; + } + if (si.nPos < si.nMin) + { + si.nPos = si.nMin; + commentOffset = 0; + } + if ((si.nPos + (int)si.nPage) > si.nMax) + { + si.nPos = si.nMax - si.nPage; + commentOffset = 0; + } + + DisassembleToWindow(hwndDlg, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, si.nPos, commentOffset); + + // The address in the Add Bookmark textbox follows the scroll pos. + char str[16]; + sprintf(str,"%04X", si.nPos); + SetDlgItemText(hwndDlg, IDC_DEBUGGER_BOOKMARK, str); + } +} + +void DebuggerMouseWheel(HWND hwndDlg, int16 rotAmt, uint16 cursorX, uint16 cursorY, uint16 vkeyFlags) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + // Try to scroll up or down in units of 8 lines + int i = rotAmt / WHEEL_DELTA; + if (i < 0) + { + for (i *= -(int)si.nPage; i > 0; i--) + { + si.nPos = ScrollDown().address; + if ((si.nPos + (int)si.nPage) > si.nMax) + { + si.nPos = si.nMax - si.nPage; break; - case WM_COMMAND: + } + } + } else if (i > 0) + { + for (i *= si.nPage; i > 0; i--) + { + si.nPos = ScrollUp().address; + if (si.nPos < si.nMin) { - switch(HIWORD(wParam)) - { - case BN_CLICKED: - switch(LOWORD(wParam)) { - case IDC_DEBUGGER_BP_ADD: - childwnd = 1; - if (DialogBoxParam(fceu_hInstance,"ADDBP",hwndDlg,AddbpCallB, 0)) AddBreakList(); - childwnd = 0; - UpdateDebugger(false); - break; - case IDC_DEBUGGER_BP_DEL: - DeleteBreak(SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0)); - break; - case IDC_DEBUGGER_BP_EDIT: - WP_edit = SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0); - if (DialogBoxParam(fceu_hInstance, "ADDBP", hwndDlg, AddbpCallB, 0)) EditBreakList(); - WP_edit = -1; - UpdateDebugger(false); - break; - case IDC_DEBUGGER_RUN: - //mbg merge 7/18/06 changed pausing check and set - if (FCEUI_EmulationPaused()) { - UpdateRegs(hwndDlg); - FCEUI_ToggleEmulationPause(); - //DebuggerWasUpdated = false done in above function; - } - break; - case IDC_DEBUGGER_STEP_IN: - if (FCEUI_EmulationPaused()) - UpdateRegs(hwndDlg); - FCEUI_Debugger().step = true; - FCEUI_SetEmulationPaused(0); - UpdateOtherDebuggingDialogs(); - - break; - case IDC_DEBUGGER_RUN_LINE: - if (FCEUI_EmulationPaused()) - UpdateRegs(hwndDlg); - FCEUI_Debugger().runline = true; - { - uint64 ts=timestampbase; - ts+=timestamp; - ts+=341/3; - //if (scanline == 240) vblankScanLines++; - //else vblankScanLines = 0; - FCEUI_Debugger().runline_end_time=ts; - } - FCEUI_SetEmulationPaused(0); - UpdateOtherDebuggingDialogs(); - break; - case IDC_DEBUGGER_RUN_FRAME2: - if (FCEUI_EmulationPaused()) - UpdateRegs(hwndDlg); - FCEUI_Debugger().runline = true; - { - uint64 ts=timestampbase; - ts+=timestamp; - ts+=128*341/3; - FCEUI_Debugger().runline_end_time=ts; - //if (scanline+128 >= 240 && scanline+128 <= 257) vblankScanLines = (scanline+128)-240; - //else vblankScanLines = 0; - } - FCEUI_SetEmulationPaused(0); - UpdateOtherDebuggingDialogs(); - break; - case IDC_DEBUGGER_STEP_OUT: - //mbg merge 7/18/06 changed pausing check and set - if (FCEUI_EmulationPaused() > 0) { - DebuggerState &dbgstate = FCEUI_Debugger(); - UpdateRegs(hwndDlg); - if ((dbgstate.stepout) && (MessageBox(hwndDlg,"Step Out is currently in process. Cancel it and setup a new Step Out watch?","Step Out Already Active",MB_YESNO|MB_ICONINFORMATION) != IDYES)) break; - if (GetMem(X.PC) == 0x20) dbgstate.jsrcount = 1; - else dbgstate.jsrcount = 0; - dbgstate.stepout = 1; - FCEUI_SetEmulationPaused(0); - } - break; - case IDC_DEBUGGER_STEP_OVER: - //mbg merge 7/18/06 changed pausing check and set - if (FCEUI_EmulationPaused()) { - UpdateRegs(hwndDlg); - int tmp = X.PC; - uint8 opcode = GetMem(tmp); - bool jsr = opcode==0x20; - bool call = jsr; - #ifdef BRK_3BYTE_HACK - //with this hack, treat BRK similar to JSR - if(opcode == 0x00) - call = true; - #endif - if (call) { - if ((watchpoint[64].flags) && (MessageBox(hwndDlg,"Step Over is currently in process. Cancel it and setup a new Step Over watch?","Step Over Already Active",MB_YESNO|MB_ICONINFORMATION) != IDYES)) break; - watchpoint[64].address = (tmp+3); - watchpoint[64].flags = WP_E|WP_X; - } - else FCEUI_Debugger().step = true; - FCEUI_SetEmulationPaused(0); - } - break; - case IDC_DEBUGGER_SEEK_PC: - //mbg merge 7/18/06 changed pausing check - if (FCEUI_EmulationPaused()) - { - UpdateRegs(hwndDlg); - UpdateDebugger(true); - } - break; - case IDC_DEBUGGER_SEEK_TO: - { - //mbg merge 7/18/06 changed pausing check - if (FCEUI_EmulationPaused()) - UpdateRegs(hwndDlg); - char str[16]; - GetDlgItemText(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,str,5); - int tmp = offsetStringToInt(BT_C, str); - if (tmp != -1) - { - sprintf(str,"%04X", tmp); - SetDlgItemText(hwndDlg,IDC_DEBUGGER_VAL_PCSEEK,str); - Disassemble(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, tmp); - // "Address Bookmark Add" follows the address - sprintf(str,"%04X", si.nPos); - SetDlgItemText(hDebug, IDC_DEBUGGER_BOOKMARK, str); - } - break; - } - case IDC_DEBUGGER_BREAK_ON_BAD_OP: //Break on bad opcode - FCEUI_Debugger().badopbreak ^= 1; - break; - case IDC_DEBUGGER_FLAG_N: X.P^=N_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_V: X.P^=V_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_U: X.P^=U_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_B: X.P^=B_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_D: X.P^=D_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_I: X.P^=I_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_Z: X.P^=Z_FLAG; UpdateDebugger(false); break; - case IDC_DEBUGGER_FLAG_C: X.P^=C_FLAG; UpdateDebugger(false); break; - - case IDC_DEBUGGER_RESET_COUNTERS: - { - ResetDebugStatisticsCounters(); - UpdateDebugger(false); - break; - } - case IDC_DEBUGGER_BREAK_ON_CYCLES: - { - break_on_cycles ^= 1; - break; - } - case IDC_DEBUGGER_BREAK_ON_INSTRUCTIONS: - { - break_on_instructions ^= 1; - break; - } + si.nPos = si.nMin; + break; + } + } + } -// ################################## Start of SP CODE ########################### + // This function calls UpdateScrollInfo. Don't worry! + DisassembleToWindow(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, si.nPos, commentOffset); + // The address in the Add Bookmark textbox follows the scroll pos. + char str[16]; + sprintf(str,"%04X", si.nPos); + SetDlgItemText(hDebug, IDC_DEBUGGER_BOOKMARK, str); +} - case IDC_DEBUGGER_RELOAD_SYMS: - { - ramBankNamesLoaded = false; - for(int i=0;i= 0) + { + hDebugcontextsub = GetSubMenu(hDebugcontext,0); + if (cursorX != -1) + // Create menu at cursor pos + TrackPopupMenu(hDebugcontextsub, TPM_RIGHTBUTTON, cursorX, cursorY, 0, hwndDlg, NULL); + else + { // Handle the context menu keyboard key + RECT wrect; + GetWindowRect(GetDlgItem(hwndDlg, IDC_DEBUGGER_BP_LIST), &wrect); + // Create menu over breakpoints list + TrackPopupMenu(hDebugcontextsub, TPM_RIGHTBUTTON, wrect.left + int((wrect.right - wrect.left) / 3), wrect.top + int((wrect.bottom - wrect.top) / 3), 0, hwndDlg, NULL); + } + } + } +} + +void DebuggerMouseMove(HWND hwndDlg, int cursorX, int cursorY, int vkFlags) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + bool setString = false; + if ((cursorX > 6) && (cursorX < 30) && (cursorY > 10)) + { + setString = true; + RECT rectDisassembly; + GetClientRect(GetDlgItem(hDebug, IDC_DEBUGGER_DISASSEMBLY), &rectDisassembly); + int height = rectDisassembly.bottom - rectDisassembly.top; + cursorY -= 10; + if (cursorY > height) + setString = false; + cursorY /= debugSystem->disasmFontHeight; + } + + if (setString) + SetDlgItemText(hDebug, IDC_DEBUGGER_ADDR_LINE, "Left click = Inline Assembler. Middle click = Game Genie. Right click = Hex Editor."); + else + SetDlgItemText(hDebug, IDC_DEBUGGER_ADDR_LINE, ""); +} + +void DebuggerLButtonDown(HWND hwndDlg, int cursorX, int cursorY, int vkFlags) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + if (FCEUI_EmulationPaused() && (cursorX > 6) && (cursorX < 30) && (cursorY > 10)) + { + int tmp = (cursorY - 10) / debugSystem->disasmFontHeight; + if (tmp < (int)disassembly_addresses.size()) + { + int i = disassembly_addresses[tmp]; + iaPC=i; + if (iaPC >= 0x8000) + { + DialogBox(fceu_hInstance, "ASSEMBLER", hwndDlg, AssemblerCallB); + UpdateDebugger(false); + } + } + } +} + +void DebuggerRButtonDown(HWND hwndDlg, int cursorX, int cursorY, int vkFlags) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + if (FCEUI_EmulationPaused() && (cursorX > 6) && (cursorX < 30) && (cursorY > 10)) + { + int tmp = (cursorY - 10) / debugSystem->disasmFontHeight; + if (tmp < (int)disassembly_addresses.size()) + { + int i = disassembly_addresses[tmp]; + if (i >= 0x8000) + // show ROM data in hex editor + ChangeMemViewFocus(3, GetNesFileAddress(i), -1); + else + // show RAM data in hex editor + ChangeMemViewFocus(0, i, -1); + } + } +} + +void DebuggerMButtonDown(HWND hwndDlg, int cursorX, int cursorY, int vkFlags) +{ + // None of these events can be processed without a game loaded. + if (!GameInfo) + return; + + if (FCEUI_EmulationPaused() && (cursorX > 6) && (cursorX < 30) && (cursorY > 10)) + { + int tmp = (cursorY - 10) / debugSystem->disasmFontHeight; + if (tmp < (int)disassembly_addresses.size()) + { + int i = disassembly_addresses[tmp]; + SetGGConvFocus(i, GetMem(i)); + } + } +} + +void DebuggerEnChange(HWND hwndDlg, uint16 textBoxId, HWND hwndTextbox) +{ + char str[16]; + switch (textBoxId) + { + case IDC_DEBUGGER_CYCLES_EXCEED: + GetDlgItemText(hwndDlg, IDC_DEBUGGER_CYCLES_EXCEED, str, 16); + break_cycles_limit = strtoul(str, NULL, 10); + break; + case IDC_DEBUGGER_INSTRUCTIONS_EXCEED: + GetDlgItemText(hwndDlg, IDC_DEBUGGER_INSTRUCTIONS_EXCEED, str, 16); + break_instructions_limit = strtoul(str, NULL, 10); + break; + } +} + +void DebuggerAccelerator(HWND hwndDlg, uint16 accId) +{ + switch (accId) + { + case IDC_DEBUGGER_STEP_IN: + case IDC_DEBUGGER_STEP_OUT: + case IDC_DEBUGGER_STEP_OVER: + case IDC_DEBUGGER_RUN: + case IDC_DEBUGGER_SEEK_PC: + case ID_DEBUGGER_UNLOGGED_AS_DATA: + case ID_DEBUGGER_SHOW_ROM_OFFSETS: + case ID_DEBUGGER_FOLLOW_PC: + DebuggerBnClicked(hwndDlg, accId, NULL); + break; + case IDC_DEBUGGER_VAL_PCSEEK: + SetFocus(GetDlgItem(hwndDlg, IDC_DEBUGGER_VAL_PCSEEK)); + SetDlgItemText(hDebug, IDC_DEBUGGER_VAL_PCSEEK, ""); + } +} + +INT_PTR CALLBACK DebuggerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + DebuggerInitDialog(hwndDlg); + break; + case WM_SIZE: + DebuggerResizeWindow(hwndDlg, wParam); + break; + case WM_CLOSE: + case WM_QUIT: + DebuggerExit(); + break; + case WM_MOVING: + break; + case WM_MOVE: + DebuggerMoveWindow(hwndDlg, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_COMMAND: + // I know you can cleverly ignore lParam and have all your menu messages come through as BN_CLICKED messages. + // But then your accelerators come through as LBN_SELCHANGE messages, which makes absolutely no sense. + if (lParam) + { // Normal messages + switch (HIWORD(wParam)) + { + case BN_CLICKED: + DebuggerBnClicked(hwndDlg, LOWORD(wParam), (HWND)lParam); break; case LBN_DBLCLK: - switch(LOWORD(wParam)) { - case IDC_DEBUGGER_BP_LIST: - EnableBreak(SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0)); - break; -// ################################## Start of SP CODE ########################### - - case LIST_DEBUGGER_BOOKMARKS: GoToDebuggerBookmark(hwndDlg); break; - -// ################################## End of SP CODE ########################### - } + DebuggerLbnDblClk(hwndDlg, LOWORD(wParam), (HWND)lParam); break; case LBN_SELCANCEL: - switch(LOWORD(wParam)) { - case IDC_DEBUGGER_BP_LIST: - EnableWindow(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_DEL),FALSE); - EnableWindow(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_EDIT),FALSE); - break; - } + DebuggerLbnSelCancel(hwndDlg, LOWORD(wParam), (HWND)lParam); break; case LBN_SELCHANGE: - switch(LOWORD(wParam)) - { - case IDC_DEBUGGER_BP_LIST: - { - if (SendDlgItemMessage(hwndDlg,IDC_DEBUGGER_BP_LIST,LB_GETCURSEL,0,0) >= 0) - { - EnableWindow(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_DEL),TRUE); - EnableWindow(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_EDIT),TRUE); - } else - { - EnableWindow(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_DEL),FALSE); - EnableWindow(GetDlgItem(hwndDlg,IDC_DEBUGGER_BP_EDIT),FALSE); - } - break; - } - } + DebuggerLbnSelChange(hwndDlg, LOWORD(wParam), (HWND)lParam); + break; + case EN_CHANGE: + DebuggerEnChange(hwndDlg, LOWORD(wParam), (HWND)lParam); break; } - break; } - } + else + { + switch (HIWORD(wParam)) + { + case 0: + // Menu items + DebuggerBnClicked(hwndDlg, LOWORD(wParam), (HWND)lParam); + break; + case 1: + // Accelerators + DebuggerAccelerator(hwndDlg, LOWORD(wParam)); + break; + } + } + break; + case WM_INITMENUPOPUP: + DebuggerInitMenuPopup(hwndDlg, (HMENU)wParam, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_ACTIVATE: + DebuggerWindowActivate(hwndDlg, LOWORD(wParam), (HWND)lParam); + break; + case WM_VSCROLL: + DebuggerVScroll(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); + break; + case WM_MOUSEWHEEL: + DebuggerMouseWheel(hwndDlg, HIWORD(wParam), LOWORD(lParam), HIWORD(lParam), LOWORD(wParam)); + break; + case WM_CONTEXTMENU: + DebuggerContextMenu(hwndDlg, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_MOUSEMOVE: + DebuggerMouseMove(hwndDlg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), wParam); + break; + case WM_LBUTTONDOWN: + DebuggerLButtonDown(hwndDlg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), wParam); + break; + case WM_RBUTTONDOWN: + DebuggerRButtonDown(hwndDlg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), wParam); + break; + case WM_MBUTTONDOWN: + DebuggerMButtonDown(hwndDlg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), wParam); + break; + case WM_KEYDOWN: + MessageBox(hwndDlg, "Die!", "I'm dead!", MB_YESNO | MB_ICONINFORMATION); + break; } - - - return FALSE; //TRUE; + return FALSE; } extern void iNESGI(GI h); @@ -2697,7 +2677,8 @@ void DoDebuggerStepInto() { if (!hDebug) return; - DebuggerCallB(hDebug, WM_COMMAND, IDC_DEBUGGER_STEP_IN, 0); + // Click the Step Into button + DebuggerBnClicked(hDebug, IDC_DEBUGGER_STEP_IN, NULL); } void DoPatcher(int address, HWND hParent) @@ -2710,40 +2691,6 @@ void DoPatcher(int address, HWND hParent) UpdateDebugger(false); } -void UpdatePatcher(HWND hwndDlg){ - char str[75]; //mbg merge 7/18/06 changed from unsigned - uint8 *p; - if(iapoffset != -1){ - EnableWindow(GetDlgItem(hwndDlg,IDC_ROMPATCHER_PATCH_DATA),TRUE); - EnableWindow(GetDlgItem(hwndDlg,IDC_ROMPATCHER_BTN_APPLY),TRUE); - - if(GetRomAddress(iapoffset) != -1)sprintf(str,"Current Data at NES ROM Address: %04X, .NES file Address: %04X",GetRomAddress(iapoffset),iapoffset); - else sprintf(str,"Current Data at .NES file Address: %04X",iapoffset); - - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_CURRENT_DATA_BOX,str); - - sprintf(str,"%04X",GetRomAddress(iapoffset)); - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_DISASSEMBLY,str); - - if(GetRomAddress(iapoffset) != -1)SetDlgItemText(hwndDlg,IDC_ROMPATCHER_DISASSEMBLY,DisassembleLine(GetRomAddress(iapoffset))); - else SetDlgItemText(hwndDlg,IDC_ROMPATCHER_DISASSEMBLY,"Not Currently Loaded in ROM for disassembly"); - - p = GetNesPRGPointer(iapoffset-16); - sprintf(str,"%02X %02X %02X %02X %02X %02X %02X %02X", - p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]); - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_CURRENT_DATA,str); - - } else { - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_CURRENT_DATA_BOX,"No Offset Selected"); - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_CURRENT_DATA,""); - SetDlgItemText(hwndDlg,IDC_ROMPATCHER_DISASSEMBLY,""); - EnableWindow(GetDlgItem(hwndDlg,IDC_ROMPATCHER_PATCH_DATA),FALSE); - EnableWindow(GetDlgItem(hwndDlg,IDC_ROMPATCHER_BTN_APPLY),FALSE); - } - if(GameInfo->type != GIT_CART)EnableWindow(GetDlgItem(hwndDlg,IDC_ROMPATCHER_BTN_SAVE),FALSE); - else EnableWindow(GetDlgItem(hwndDlg,IDC_ROMPATCHER_BTN_SAVE),TRUE); -} - /// Updates debugger controls that should be enabled/disabled if a game is loaded. /// @param enable Flag that indicates whether the menus should be enabled (1) or disabled (0). void updateGameDependentMenusDebugger() { @@ -2758,7 +2705,7 @@ void DoDebug(uint8 halt) if (!debugger_open) { // init buffers - // owomomo: initialize buffers even before the debugger is open, + // initialize buffers even before the debugger is open, // because some of the operations about hDebug may occur before // its WM_INITDIALOG runs. debug_wstr = (wchar_t*)malloc(16384 * sizeof(wchar_t)); @@ -2770,14 +2717,13 @@ void DoDebug(uint8 halt) } if (hDebug) { - //SetWindowPos(hDebug,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER); ShowWindow(hDebug, SW_SHOWNORMAL); SetForegroundWindow(hDebug); updateGameDependentMenusDebugger(); if (GameInfo) - UpdateDebugger(true); + UpdateDebugger(debuggerFollowPc); } } @@ -2829,8 +2775,6 @@ void DebugSystem::init() GetTextMetrics(hdc,&tm); fixedFontHeight = tm.tmHeight; fixedFontWidth = tm.tmAveCharWidth; - //printf("fixed font height: %d\n",fixedFontHeight); - //printf("fixed font width: %d\n",fixedFontWidth); SelectObject(hdc, hHexeditorFont); GetTextMetrics(hdc,&tm); HexeditorFontHeight = tm.tmHeight; @@ -2871,4 +2815,3 @@ DebugSystem::~DebugSystem() hIDAFont = 0; } } - diff --git a/src/drivers/win/debugger.h b/src/drivers/win/debugger.h index 2063229e2..84e1e0345 100644 --- a/src/drivers/win/debugger.h +++ b/src/drivers/win/debugger.h @@ -13,10 +13,9 @@ #define TOO_MANY_BREAKPOINTS 1 #define INVALID_BREAKPOINT_CONDITION 3 -//extern volatile int userpause; //mbg merge 7/18/06 removed for merging extern HWND hDebug; -extern int childwnd,numWPs; //mbg merge 7/18/06 had to make extern +extern int childwnd,numWPs; extern bool debuggerAutoload; extern bool debuggerSaveLoadDEBFiles; extern bool debuggerDisplayROMoffsets; @@ -30,7 +29,6 @@ extern char* hexeditorFontName; void CenterWindow(HWND hwndDlg); void DoPatcher(int address,HWND hParent); -void UpdatePatcher(HWND hwndDlg); int GetEditHex(HWND hwndDlg, int id); extern void AddBreakList(); @@ -39,7 +37,8 @@ extern char* BreakToText(unsigned int num); void UpdateDebugger(bool jump_to_pc = true); void DoDebug(uint8 halt); void DebuggerExit(); -void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr); +void DisassembleToWindow(HWND hWnd, int id, int scrollid, unsigned int addr, int skiplines = 0); +void DisassembleToWindow(HWND hWnd, int id, int scrollid); void PrintOffsetToSeekAndBookmarkFields(int offset); void LoadGameDebuggerData(HWND hwndDlg); diff --git a/src/drivers/win/debuggersp.cpp b/src/drivers/win/debuggersp.cpp index 1f78660ff..e7936def1 100644 --- a/src/drivers/win/debuggersp.cpp +++ b/src/drivers/win/debuggersp.cpp @@ -21,6 +21,7 @@ #include "common.h" #include "utils/xstring.h" #include "debuggersp.h" +#include "debugger.h" #include "../../fceu.h" #include "../../debug.h" #include "../../conddebug.h" @@ -33,18 +34,8 @@ int GetNesFileAddress(int A); inline int RomPageIndexForAddress(int addr) { return (addr-0x8000)>>(debuggerPageSize); } -//old -//Name* lastBankNames = 0; -//Name* loadedBankNames = 0; - -//new Name* pageNames[32] = {0}; //the maximum number of pages we could have is 32, based on 1KB debuggerPageSize -//old -//int lastBank = -1; -//int loadedBank = -1; - -//new int pageNumbersLoaded[32] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, @@ -57,6 +48,7 @@ extern char LoadedRomFName[2048]; char NLfilename[2048]; bool symbDebugEnabled = true; bool symbRegNames = true; +bool inlineAddressEnabled = false; int debuggerWasActive = 0; char temp_chr[40] = {0}; char delimiterChar[2] = "#"; @@ -506,7 +498,7 @@ void freeList(Name* n) * The caller needs to make sure that str is large enough. * * @param list NL list of address definitions -* @param str The string where replacing takes place. +* @param str The string where replacing takes place, including trace data. * @param addressesLog Vector for collecting addresses that were replaced by names **/ void replaceNames(Name* list, char* str, std::vector* addressesLog) @@ -543,7 +535,7 @@ void replaceNames(Name* list, char* str, std::vector* addressesLog) addrlen = 3; } - for(;;) + while (src) { int myAddrlen = addrlen; @@ -566,24 +558,28 @@ void replaceNames(Name* list, char* str, std::vector* addressesLog) myAddrlen = 5; } - //special hack: sometimes we have #$00, and we dont want to replace that. - //(this isn't a problem with $0000 because on the 6502 we ... dont.. have ... #$XXXX ? - //honestly, I don't know anything about this CPU. don't tell anyone. - //I'm just inferring from the fact that the algorithm previously relied on that assumption... + //we actually found an immediate value, don't replace it if(pos[-1] == '#') { src = pos + myAddrlen; continue; } - - //zero 30-nov-2017 - change how this works so we can display the address still - //append beginning part, plus addrlen for the offset - strncat(buff,src,pos-src+myAddrlen); - //append a space - strcat(buff," "); + + if (inlineAddressEnabled) + { + //append up to and including the address, + a space + strncat(buff, src, pos - src + myAddrlen); + strcat(buff, " "); + } + else + { + //append up to but not including the address + strncat(buff, src, pos - src); + } + //append the label strcat(buff, list->name); - //begin processing after that offset + //begin processing after this offset src = pos + myAddrlen; if (addressesLog) @@ -599,20 +595,43 @@ void replaceNames(Name* list, char* str, std::vector* addressesLog) } list = list->next; } +} + +/** +* Replaces all offsets in a string with the names of the corresponding NES hardware registers +* The caller needs to make sure that str is large enough. +* +* @param str The string where replacing takes place, including trace data. +**/ +void replaceRegNames(char* str) +{ + static char buff[1001]; + char* pos; + char* src; - for (int i = 0; i < RegNameCount; i++) { - if (!symbRegNames) break; + for (int i = 0; i < RegNameCount; i++) + { // copypaste, because Name* is too complex to abstract *buff = 0; src = str; - while (pos = strstr(src, RegNames[i].offset)) { - *pos = 0; - strcat(buff, src); + while (pos = strstr(src, RegNames[i].offset)) + { + if (inlineAddressEnabled) + { + strncat(buff, src, pos - src + 5); + strcat(buff, " "); + } + else + { + strncat(buff, src, pos - src); + } + strcat(buff, RegNames[i].name); src = pos + 5; } - if (*buff) { + if (*buff) + { strcat(buff, src); strcpy(str, buff); } @@ -622,6 +641,8 @@ void replaceNames(Name* list, char* str, std::vector* addressesLog) /** * Searches an address node in a list of address nodes. The found node * has the same offset as the passed parameter offs. +* +* Could speed this up with an actual data structure... * * @param node The address node list * @offs The offset to search @@ -899,7 +920,7 @@ void GoToDebuggerBookmark(HWND hwnd) // If no bookmark is selected just return if (selectedItem == LB_ERR) return; unsigned int n = getBookmarkAddress(selectedItem); - Disassemble(hwnd, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, n); + DisassembleToWindow(hwnd, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, n); } INT_PTR CALLBACK SymbolicNamingCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) diff --git a/src/drivers/win/debuggersp.h b/src/drivers/win/debuggersp.h index 01b7d9070..860ae3ffd 100644 --- a/src/drivers/win/debuggersp.h +++ b/src/drivers/win/debuggersp.h @@ -41,6 +41,7 @@ struct MemoryMappedRegister extern bool symbDebugEnabled; extern bool symbRegNames; +extern bool inlineAddressEnabled; extern std::vector> bookmarks; extern int debuggerWasActive; @@ -54,6 +55,7 @@ Name* getNamesPointerForAddress(uint16 address); void setNamesPointerForAddress(uint16 address, Name* newNode); void loadNameFiles(); void replaceNames(Name* list, char* str, std::vector* addressesLog = 0); +void replaceRegNames(char* str); void AddDebuggerBookmark(HWND hwnd); void DeleteDebuggerBookmark(HWND hwnd); void EditDebuggerBookmark(HWND hwnd); @@ -69,5 +71,4 @@ void AddNewSymbolicName(uint16 newAddress, char* newOffset, char* newName, char* void DeleteSymbolicName(uint16 address, int size); void WriteNameFileToDisk(const char* filename, Name* node); -extern void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr); extern void CenterWindow(HWND hwnd); \ No newline at end of file diff --git a/src/drivers/win/dumper.cpp b/src/drivers/win/dumper.cpp new file mode 100644 index 000000000..dccd4efca --- /dev/null +++ b/src/drivers/win/dumper.cpp @@ -0,0 +1,350 @@ +#include +#include + +#include "types.h" +#include "resource.h" +#include "debugger.h" +#include "debuggersp.h" +#include "../../debug.h" +#include "asm.h" +#include "../../x6502.h" +#include "../../fceu.h" +#include "../../debug.h" +#include "../../nsf.h" +#include "../../ppu.h" +#include "../../cart.h" +#include "../../ines.h" +#include "../../asm.h" +#include "tracer.h" +#include "window.h" + +extern Name* ramBankNames; +extern Name* pageNames[32]; + +static char* debug_str_decoration_comment; +static char* debug_decoration_comment; +static char* debug_decoration_comment_end_pos; +static char filename[MAX_PATH + 1]; +static bool showNesFileOffests; +static OPENFILENAME ofn; + +/** +* Dumps disassembled ROM code between startAddr and endAddr (inclusive) to a file. +* endAddr is the address of the last INSTRUCTION. This funcion will grab the operands if present, +* and may spill over a bit in the process. +* 0x80000 - 0xFFFF should get you the loaded banks. However, it's most reliable when you dump one subroutine at a time +* or already have a lot of labels. +* +* For example, say you have 2C A9 10 60, and the A9 byte is supposed to be the start of a subroutine. If the disassembler +* comes across that 2C first, it will interpret the code as: + +* 2C A9 10 BIT $10A9 +* 60 RTS + +* Nonsense. + +* But if you have a named label +* on that A9 byte, the 2C (BIT) instruction will be INTERRUPTED, and it will show up like this: + +* 2C INTERRUPTED +* my_subroutine: +* A9 10 LDA #$10 +* 60 RTS +* +* There is a lot of reused logic between this and DisassembleToWindow. However, they're different enough that it would +* be more trouble than it's worth to combine them. +*/ +void Dump(FILE *fout, unsigned int startAddr, unsigned int endAddr) +{ + wchar_t chr[40] = { 0 }; + wchar_t debug_wbuf[2048] = { 0 }; + int size; + uint8 opcode[3]; + unsigned int instruction_addr; + unsigned int addr = startAddr; // Keeps track of which address to get the operands, etc. from + + if (symbDebugEnabled) + loadNameFiles(); + + unsigned int instructions_count = 0; + for (int addr = startAddr; addr <= endAddr;) + { + // PC pointer + if (addr > 0xFFFF) break; + + instruction_addr = addr; + + if (symbDebugEnabled) + { + // Insert name and comment lines if present + Name* node = findNode(getNamesPointerForAddress(addr), addr); + if (node) + { + if (node->name) + { + // Could probably ditch these swprintf's and just do fwprintf. + // Need to verify exactly how the various buffers are used. + swprintf(debug_wbuf, L"%S:\n", node->name); + fprintf(fout, "%ls", debug_wbuf); + } + if (node->comment) + { + // make a copy + strcpy(debug_str_decoration_comment, node->comment); + strcat(debug_str_decoration_comment, "\r\n"); + // divide the debug_str_decoration_comment into strings (Comment1, Comment2, ...) + debug_decoration_comment = debug_str_decoration_comment; + debug_decoration_comment_end_pos = strstr(debug_decoration_comment, "\r\n"); + while (debug_decoration_comment_end_pos) + { + debug_decoration_comment_end_pos[0] = 0; // set \0 instead of \r + debug_decoration_comment_end_pos[1] = 0; // set \0 instead of \n + swprintf(debug_wbuf, L"; %S\n", debug_decoration_comment); + fprintf(fout, "%ls", debug_wbuf); + + debug_decoration_comment_end_pos += 2; + debug_decoration_comment = debug_decoration_comment_end_pos; + debug_decoration_comment_end_pos = strstr(debug_decoration_comment_end_pos, "\r\n"); + } + } + } + } + + fprintf(fout, "%ls", L" "); + + if (addr >= 0x8000) + { + if (showNesFileOffests && GetNesFileAddress(addr) != -1) + { + swprintf(chr, L" %06X: ", GetNesFileAddress(addr)); + } + else + { + swprintf(chr, L"%02X:%04X: ", getBank(addr), addr); + } + } + else + { + swprintf(chr, L" :%04X: ", addr); + } + + // Add address + fprintf(fout, "%ls", chr); + + size = opsize[GetMem(addr)]; + if (size == 0) + { + swprintf(chr, L"%02X UNDEFINED", GetMem(addr++)); + fprintf(fout, "%ls", chr); + } + else + { + if ((addr + size) > 0xFFFF) + { + while (addr < 0xFFFF) + { + swprintf(chr, L"%02X OVERFLOW\n", GetMem(addr++)); + fprintf(fout, "%ls", chr); + } + break; + } + Name* node; + for (int j = 0; j < size; j++) + { + // Write the raw bytes of this instruction + swprintf(chr, L"%02X ", opcode[j] = GetMem(addr++)); + fprintf(fout, "%ls", chr); + if (j != size - 1 && (node = findNode(getNamesPointerForAddress(addr), addr))) + { + // We were treating this as an operand, but it's named! + // Probably want an instruction to start here instead. + printf("$%04X (%s) came up as an operand for instruction @ %04X\n", addr, node->name, addr - j - 1); + size = j + 1; + break; + } + } + while (size < 3) + { + fprintf(fout, "%ls", L" "); + size++; + } + if (node) + { + // TODO: Instead of this ominous and confusing message, could print ".byte $XX $YY..." + // TODO: Work this logic into asm.cpp? + fprintf(fout, " INTERRUPTED"); + } + else + { + static char bufferForDisassemblyWithPlentyOfStuff[64 + NL_MAX_NAME_LEN * 10]; // "plenty" + char* _a = Disassemble(addr, opcode); + + strcpy(bufferForDisassemblyWithPlentyOfStuff, _a); + + if (symbDebugEnabled) + { // TODO: This will add in both the default name and custom name if you have inlineAddresses enabled. + if (symbRegNames) + replaceRegNames(bufferForDisassemblyWithPlentyOfStuff); + replaceNames(ramBankNames, bufferForDisassemblyWithPlentyOfStuff, NULL); + for (int p = 0; p 0xFFFF means you're dumb. + if (startAddr < 0 || startAddr > 0xFFFF) + { + MessageBox(hwndDlg, "Invalid start address.", "Code Dumper", MB_OK | MB_ICONINFORMATION); + break; + } + + if (endAddr < 0 || endAddr > 0xFFFF || endAddr < startAddr) + { + MessageBox(hwndDlg, "Invalid end address.", "Code Dumper", MB_OK | MB_ICONINFORMATION); + break; + } + + if (!GetDlgItemText(hwndDlg, ID_DUMPER_FILEPATH, filename, MAX_PATH)) + { + MessageBox(hwndDlg, "No file path entered.", "Code Dumper", MB_OK | MB_ICONINFORMATION); + break; + } + + FILE *fout; + if (!(fout = fopen(filename, "w"))) + { + MessageBox(hwndDlg, "Could not open file.", "Code Dumper", MB_OK | MB_ICONINFORMATION); + break; + } + + // This could take a while... + printf("Dumping $%04X - $%04X to \"%s\"...\n", startAddr, endAddr, filename); + EnableWindow(hwndDlg, false); + SetCursor(LoadCursor(NULL, IDC_WAIT)); + + Dump(fout, startAddr, endAddr); + fclose(fout); + + printf("Done.\n"); + EnableWindow(hwndDlg, true); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + MessageBeep(MB_ICONINFORMATION); + + return true; + case IDCANCEL: + return DumperExit(hwndDlg); + } + return false; +} + +INT_PTR CALLBACK DumperCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + return DumperInitDialog(hwndDlg, (HWND)wParam, (PROPSHEETPAGE*)lParam); + case WM_CLOSE: + case WM_QUIT: + return DumperExit(hwndDlg); + case WM_COMMAND: + switch (HIWORD(wParam)) + { + case BN_CLICKED: + return DumperBnClicked(hwndDlg, LOWORD(wParam), (HWND)lParam); + } + break; + } + return false; +} diff --git a/src/drivers/win/dumper.h b/src/drivers/win/dumper.h new file mode 100644 index 000000000..0eedaa7e0 --- /dev/null +++ b/src/drivers/win/dumper.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +INT_PTR CALLBACK DumperCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/src/drivers/win/main.cpp b/src/drivers/win/main.cpp index 54147dbc0..9e356f6cb 100644 --- a/src/drivers/win/main.cpp +++ b/src/drivers/win/main.cpp @@ -186,6 +186,7 @@ int ffbskip = 32; //Blit skips per blit when FF-ing HINSTANCE fceu_hInstance; HACCEL fceu_hAccel; +HACCEL debugger_hAccel; HRESULT ddrval; @@ -377,6 +378,11 @@ int BlockingCheck() if(!handled && taseditorWindow.hwndFindNote && IsChild(taseditorWindow.hwndFindNote, msg.hwnd)) handled = IsDialogMessage(taseditorWindow.hwndFindNote, &msg); + // Debugger + if(!handled && hDebug) + if(!(handled = TranslateAccelerator(hDebug, debugger_hAccel, &msg))) + handled = IsDialogMessage(hDebug, &msg); + // Sound Config extern HWND uug; if(!handled && uug && IsChild(uug, msg.hwnd)) @@ -711,6 +717,7 @@ int main(int argc,char *argv[]) fceu_hInstance = GetModuleHandle(0); fceu_hAccel = LoadAccelerators(fceu_hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1)); + debugger_hAccel = LoadAccelerators(fceu_hInstance,MAKEINTRESOURCE(IDR_DEBUGGER_ACCELERATOR)); // Get the base directory GetBaseDirectory(); diff --git a/src/drivers/win/memview.cpp b/src/drivers/win/memview.cpp index 0eb555797..54c3cdc49 100644 --- a/src/drivers/win/memview.cpp +++ b/src/drivers/win/memview.cpp @@ -2054,8 +2054,6 @@ LRESULT CALLBACK MemViewCallB(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa if (!symbDebugEnabled) { symbDebugEnabled = true; - if (hDebug) - CheckDlgButton(hDebug, IDC_DEBUGGER_ENABLE_SYMBOLIC, BST_CHECKED); } UpdateCaption(); } diff --git a/src/drivers/win/patcher.cpp b/src/drivers/win/patcher.cpp new file mode 100644 index 000000000..ee981a380 --- /dev/null +++ b/src/drivers/win/patcher.cpp @@ -0,0 +1,155 @@ +#include + +#include "types.h" +#include "gui.h" +#include "resource.h" +#include "debugger.h" +#include "../../debug.h" +#include "asm.h" +#include "../../x6502.h" +#include "../../fceu.h" +#include "../../debug.h" +#include "../../nsf.h" +#include "../../ppu.h" +#include "../../cart.h" +#include "../../ines.h" +#include "../../asm.h" + +int *GetEditHexData(HWND hwndDlg, int id) { + static int data[31]; + char str[60]; + int i, j, k; + + GetDlgItemText(hwndDlg, id, str, 60); + memset(data, 0, 31 * sizeof(int)); + j = 0; + for (i = 0; i < 60; i++) { + if (str[i] == 0)break; + if ((str[i] >= '0') && (str[i] <= '9'))j++; + if ((str[i] >= 'A') && (str[i] <= 'F'))j++; + if ((str[i] >= 'a') && (str[i] <= 'f'))j++; + } + + j = j & 1; + for (i = 0; i < 60; i++) { + if (str[i] == 0)break; + k = -1; + if ((str[i] >= '0') && (str[i] <= '9'))k = str[i] - '0'; + if ((str[i] >= 'A') && (str[i] <= 'F'))k = (str[i] - 'A') + 10; + if ((str[i] >= 'a') && (str[i] <= 'f'))k = (str[i] - 'a') + 10; + if (k != -1) { + if (j & 1)data[j >> 1] |= k; + else data[j >> 1] |= k << 4; + j++; + } + } + data[j >> 1] = -1; + return data; +} + +void UpdatePatcher(HWND hwndDlg) { + char str[75]; + uint8 *p; + if (iapoffset != -1) { + EnableWindow(GetDlgItem(hwndDlg, IDC_ROMPATCHER_PATCH_DATA), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ROMPATCHER_BTN_APPLY), TRUE); + + if (GetRomAddress(iapoffset) != -1)sprintf(str, "Current Data at NES ROM Address: %04X, .NES file Address: %04X", GetRomAddress(iapoffset), iapoffset); + else sprintf(str, "Current Data at .NES file Address: %04X", iapoffset); + + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_CURRENT_DATA_BOX, str); + + sprintf(str, "%04X", GetRomAddress(iapoffset)); + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_DISASSEMBLY, str); + + if (GetRomAddress(iapoffset) != -1)SetDlgItemText(hwndDlg, IDC_ROMPATCHER_DISASSEMBLY, DisassembleLine(GetRomAddress(iapoffset))); + else SetDlgItemText(hwndDlg, IDC_ROMPATCHER_DISASSEMBLY, "Not Currently Loaded in ROM for disassembly"); + + p = GetNesPRGPointer(iapoffset - 16); + sprintf(str, "%02X %02X %02X %02X %02X %02X %02X %02X", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_CURRENT_DATA, str); + + } + else { + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_CURRENT_DATA_BOX, "No Offset Selected"); + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_CURRENT_DATA, ""); + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_DISASSEMBLY, ""); + EnableWindow(GetDlgItem(hwndDlg, IDC_ROMPATCHER_PATCH_DATA), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ROMPATCHER_BTN_APPLY), FALSE); + } + if (GameInfo->type != GIT_CART)EnableWindow(GetDlgItem(hwndDlg, IDC_ROMPATCHER_BTN_SAVE), FALSE); + else EnableWindow(GetDlgItem(hwndDlg, IDC_ROMPATCHER_BTN_SAVE), TRUE); +} + +INT_PTR CALLBACK PatcherCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + char str[64]; + uint8 *c; + int i; + int *p; + + switch (uMsg) { + case WM_INITDIALOG: + CenterWindow(hwndDlg); + + //set limits + SendDlgItemMessage(hwndDlg, IDC_ROMPATCHER_OFFSET, EM_SETLIMITTEXT, 6, 0); + SendDlgItemMessage(hwndDlg, IDC_ROMPATCHER_PATCH_DATA, EM_SETLIMITTEXT, 30, 0); + UpdatePatcher(hwndDlg); + + if (iapoffset != -1) { + CheckDlgButton(hwndDlg, IDC_ROMPATCHER_DOTNES_OFFSET, BST_CHECKED); + sprintf((char*)str, "%X", iapoffset); + SetDlgItemText(hwndDlg, IDC_ROMPATCHER_OFFSET, str); + } + + SetFocus(GetDlgItem(hwndDlg, IDC_ROMPATCHER_OFFSET_BOX)); + break; + case WM_CLOSE: + case WM_QUIT: + EndDialog(hwndDlg, 0); + break; + case WM_COMMAND: + switch (HIWORD(wParam)) { + case BN_CLICKED: + switch (LOWORD(wParam)) { + case IDC_ROMPATCHER_BTN_EDIT: //todo: maybe get rid of this button and cause iapoffset to update every time you change the text + if (IsDlgButtonChecked(hwndDlg, IDC_ROMPATCHER_DOTNES_OFFSET) == BST_CHECKED) + iapoffset = GetEditHex(hwndDlg, IDC_ROMPATCHER_OFFSET); + else + iapoffset = GetNesFileAddress(GetEditHex(hwndDlg, IDC_ROMPATCHER_OFFSET)); + if ((iapoffset < 16) && (iapoffset != -1)) { + MessageBox(hDebug, "Sorry, iNES Header editing isn't supported by this tool. If you want to edit the header, please use iNES Header Editor", "Error", MB_OK | MB_ICONASTERISK); + iapoffset = -1; + } + if ((iapoffset > PRGsize[0]) && (iapoffset != -1)) { + MessageBox(hDebug, "Error: .Nes offset outside of PRG rom", "Error", MB_OK | MB_ICONERROR); + iapoffset = -1; + } + UpdatePatcher(hwndDlg); + break; + case IDOK: + case IDC_ROMPATCHER_BTN_APPLY: + p = GetEditHexData(hwndDlg, IDC_ROMPATCHER_PATCH_DATA); + i = 0; + c = GetNesPRGPointer(iapoffset - 16); + while (p[i] != -1) { + c[i] = p[i]; + i++; + } + UpdatePatcher(hwndDlg); + break; + case IDC_ROMPATCHER_BTN_SAVE: + if (!iNesSave()) + MessageBox(NULL, "Error Saving", "Error", MB_OK | MB_ICONERROR); + break; + case IDCANCEL: + EndDialog(hwndDlg, 0); + break; + } + break; + } + break; + } + return FALSE; +} diff --git a/src/drivers/win/patcher.h b/src/drivers/win/patcher.h new file mode 100644 index 000000000..21e666e40 --- /dev/null +++ b/src/drivers/win/patcher.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +INT_PTR CALLBACK PatcherCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/src/drivers/win/res.rc b/src/drivers/win/res.rc index 810f7343e..aad2574e4 100644 --- a/src/drivers/win/res.rc +++ b/src/drivers/win/res.rc @@ -792,24 +792,22 @@ BEGIN EDITTEXT IDC_DEBUGGER_VAL_X,387,90,15,12,ES_UPPERCASE | ES_WANTRETURN LTEXT "Y:",IDC_DEBUGGER_TEXT_Y,406,92,9,8 EDITTEXT IDC_DEBUGGER_VAL_Y,415,90,15,12,ES_UPPERCASE | ES_WANTRETURN - GROUPBOX "Breakpoints",IDC_DEBUGGER_BREAKPOINTS,434,2,116,138,WS_TABSTOP + GROUPBOX "Breakpoints",IDC_DEBUGGER_BREAKPOINTS,434,2,116,126,WS_TABSTOP LISTBOX IDC_DEBUGGER_BP_LIST,438,11,107,96,LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL PUSHBUTTON "Add",IDC_DEBUGGER_BP_ADD,438,109,31,15 PUSHBUTTON "Delete",IDC_DEBUGGER_BP_DEL,476,109,31,15,WS_DISABLED PUSHBUTTON "Edit",IDC_DEBUGGER_BP_EDIT,515,109,31,15,WS_DISABLED - CONTROL "Break on Bad Opcodes",IDC_DEBUGGER_BREAK_ON_BAD_OP, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,440,126,94,10 GROUPBOX "Stack",IDC_DEBUGGER_VAL_S,349,104,81,71,WS_TABSTOP EDITTEXT IDC_DEBUGGER_STACK_CONTENTS,353,113,73,58,ES_MULTILINE | ES_UPPERCASE | ES_NOHIDESEL | ES_READONLY | WS_VSCROLL - GROUPBOX "Status Flags",IDC_DEBUGGER_STATUSFLAGS,434,140,116,35,WS_TABSTOP - CONTROL "N",IDC_DEBUGGER_FLAG_N,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,440,149,18,12 - CONTROL "V",IDC_DEBUGGER_FLAG_V,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,471,149,18,12 - CONTROL "U",IDC_DEBUGGER_FLAG_U,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,500,149,18,12 - CONTROL "B",IDC_DEBUGGER_FLAG_B,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,528,149,18,12 - CONTROL "D",IDC_DEBUGGER_FLAG_D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,440,161,18,12 - CONTROL "I",IDC_DEBUGGER_FLAG_I,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,471,161,18,12 - CONTROL "Z",IDC_DEBUGGER_FLAG_Z,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,500,161,18,12 - CONTROL "C",IDC_DEBUGGER_FLAG_C,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,528,161,18,12 + GROUPBOX "Status Flags",IDC_DEBUGGER_STATUSFLAGS,434,128,116,35,WS_TABSTOP + CONTROL "N",IDC_DEBUGGER_FLAG_N,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,440,137,18,12 + CONTROL "V",IDC_DEBUGGER_FLAG_V,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,471,137,18,12 + CONTROL "U",IDC_DEBUGGER_FLAG_U,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,500,137,18,12 + CONTROL "B",IDC_DEBUGGER_FLAG_B,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,528,137,18,12 + CONTROL "D",IDC_DEBUGGER_FLAG_D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,440,149,18,12 + CONTROL "I",IDC_DEBUGGER_FLAG_I,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,471,149,18,12 + CONTROL "Z",IDC_DEBUGGER_FLAG_Z,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,500,149,18,12 + CONTROL "C",IDC_DEBUGGER_FLAG_C,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,528,149,18,12 GROUPBOX "",IDC_DEBUGGER_VAL_S2,349,174,55,53,WS_TABSTOP LTEXT "PPU:",IDC_DEBUGGER_TEXT_PPU,352,180,16,8 EDITTEXT IDC_DEBUGGER_VAL_PPU,371,180,28,12,ES_UPPERCASE | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER,WS_EX_TRANSPARENT @@ -837,17 +835,8 @@ BEGIN PUSHBUTTON "Delete",IDC_DEBUGGER_BOOKMARK_DEL,436,273,30,14 PUSHBUTTON "Edit",IDC_DEBUGGER_BOOKMARK_EDIT,436,290,30,14 PUSHBUTTON "Reset counters",IDC_DEBUGGER_RESET_COUNTERS,479,229,68,14 - GROUPBOX "",IDC_DEBUGGER_VAL_S3,474,241,77,75 - CONTROL "ROM offsets",IDC_DEBUGGER_ROM_OFFSETS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,479,249,62,10 - CONTROL "Symbolic debug",IDC_DEBUGGER_ENABLE_SYMBOLIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,479,261,62,10 - CONTROL "Register names",IDC_DEBUGGER_PREDEFINED_REGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,479,272,65,10 - PUSHBUTTON "Reload Symbols",IDC_DEBUGGER_RELOAD_SYMS,480,283,64,14 - PUSHBUTTON "Rom Patcher",IDC_DEBUGGER_ROM_PATCHER,480,299,64,14 CONTROL "",IDC_DEBUGGER_ADDR_LINE,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,4,319,341,11 EDITTEXT IDC_DEBUGGER_DISASSEMBLY_LEFT_PANEL,4,5,14,312,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_DISABLED - CONTROL "Auto open on ROM load",DEBUGAUTOLOAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,361,319,90,10 - CONTROL "Load .DEB file",DEBUGLOADDEB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,455,319,58,10 - CONTROL "IDA font",DEBUGIDAFONT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,514,319,42,10 END TRACER DIALOGEX 0, 0, 317, 181 @@ -962,6 +951,22 @@ BEGIN GROUPBOX "Patch Data",108,3,81,292,30 END +CODEDUMPER DIALOGEX 84, 67, 204, 66 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Code Dumper" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL ".Nes File Addresses",ID_DUMPER_NES_ADDR_TOGGLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,11,77,10 + EDITTEXT ID_DUMPER_START_ADDR,85,10,47,12,ES_AUTOHSCROLL + LTEXT "-",109,138,12,10,10 + EDITTEXT ID_DUMPER_END_ADDR,147,10,47,12,ES_AUTOHSCROLL + GROUPBOX "Offsets",107,3,1,196,25 + LTEXT "Output: ",108,3,30,26,9 + EDITTEXT ID_DUMPER_FILEPATH,29,29,114,12,ES_AUTOHSCROLL + PUSHBUTTON "Browse...",ID_DUMPER_BROWSE,146,30,45,12 + PUSHBUTTON "Dump",ID_DUMPER_GO,146,46,45,12 +END + GGCONV DIALOGEX 84, 67, 186, 146 STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Game Genie Encoder/Decoder Tool" @@ -1945,6 +1950,10 @@ BEGIN BEGIN END + "CODEDUMPER", DIALOG + BEGIN + END + "GGCONV", DIALOG BEGIN END @@ -2319,6 +2328,11 @@ BEGIN 0 END +CODEDUMPER AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -3019,10 +3033,44 @@ END DEBUGGERMENU MENU BEGIN - POPUP "Syntax highlight" + POPUP "Options" + BEGIN + MENUITEM "Auto Open on ROM Load", ID_DEBUGGER_AUTO_OPEN, CHECKED + MENUITEM SEPARATOR + POPUP "Syntax Highlighting" + BEGIN + MENUITEM SEPARATOR + MENUITEM "Restore Defaults", ID_DEBUGGER_DEFCOLOR + END + MENUITEM "IDA Font", ID_DEBUGGER_IDA_FONT, CHECKED + MENUITEM SEPARATOR + MENUITEM "&ROM Offsets\tAlt+A", ID_DEBUGGER_SHOW_ROM_OFFSETS, CHECKED + MENUITEM "Show Trace Info", ID_DEBUGGER_SHOW_TRACE_INFO, CHECKED + MENUITEM "Follow Program Counter\tAlt+F", ID_DEBUGGER_FOLLOW_PC, CHECKED + MENUITEM SEPARATOR + POPUP "Code/Data Logger" + BEGIN + MENUITEM "Show Unlogged &Bytes as Data\tAlt+D", ID_DEBUGGER_UNLOGGED_AS_DATA, CHECKED + MENUITEM "Break on Unlogged Code", ID_DEBUGGER_BREAK_UNLOGGED_CODE, CHECKED + MENUITEM "Break on Unlogged Data", ID_DEBUGGER_BREAK_UNLOGGED_DATA, CHECKED + END + MENUITEM "Break on Unofficial Opcodes", ID_DEBUGGER_BREAK_BAD_OPCODES, CHECKED + MENUITEM SEPARATOR + MENUITEM "Reset Window Size", ID_DEBUGGER_RESTORE_SIZE + END + POPUP "Symbols" BEGIN + MENUITEM "Reload", ID_DEBUGGER_RELOAD_SYMBOLS + MENUITEM "Load .DEB file", ID_DEBUGGER_LOAD_DEB_FILE, CHECKED MENUITEM SEPARATOR - MENUITEM "Restore default", ID_DEBUGGER_DEFCOLOR + MENUITEM "Symbolic Debug", ID_DEBUGGER_SYMBOLIC_DEBUG, CHECKED + MENUITEM "Show Symbol Addresses", ID_DEBUGGER_INLINE_ADDRESS, CHECKED + MENUITEM "Default Register Names", ID_DEBUGGER_DEFAULT_REG_NAMES, CHECKED + END + POPUP "Tools" + BEGIN + MENUITEM "ROM Patcher...", ID_DEBUGGER_ROM_PATCHER + MENUITEM "Code Dumper...", ID_DEBUGGER_CODE_DUMPER END END @@ -3087,6 +3135,19 @@ BEGIN "R", IDC_C_WATCH_REMOVE, VIRTKEY END +IDR_DEBUGGER_ACCELERATOR ACCELERATORS +BEGIN + VK_F11, IDC_DEBUGGER_STEP_IN, VIRTKEY + VK_F11, IDC_DEBUGGER_STEP_OUT, VIRTKEY, SHIFT + VK_F10, IDC_DEBUGGER_STEP_OVER, VIRTKEY + VK_F5, IDC_DEBUGGER_RUN, VIRTKEY + "A", IDC_DEBUGGER_VAL_PCSEEK, VIRTKEY, CONTROL + "P", IDC_DEBUGGER_SEEK_PC, VIRTKEY, CONTROL + "A", ID_DEBUGGER_SHOW_ROM_OFFSETS, VIRTKEY, ALT + "D", ID_DEBUGGER_UNLOGGED_AS_DATA, VIRTKEY, ALT + "F", ID_DEBUGGER_FOLLOW_PC, VIRTKEY, ALT +END + ///////////////////////////////////////////////////////////////////////////// // diff --git a/src/drivers/win/resource.h b/src/drivers/win/resource.h index ea863c968..8ce6e43e0 100644 --- a/src/drivers/win/resource.h +++ b/src/drivers/win/resource.h @@ -122,7 +122,6 @@ #define COMBO_FAM 110 #define IDB_TE_ARROW 110 #define IDC_CHECK_LOG_REGISTERS 110 -#define IDC_DEBUGGER_BREAK_ON_BAD_OP 110 #define IDC_ROMPATCHER_BTN_APPLY 110 #define LBL_CDLOGGER_RENDERCOUNT 110 #define IDC_VIDEOCONFIG_SQUARE_PIXELS 110 @@ -131,7 +130,6 @@ #define CB_DISABLE_SCREEN_SAVER 111 #define BTN_FAM 111 #define IDC_CHECK_LOG_PROCESSOR_STATUS 111 -#define IDC_DEBUGGER_RELOAD_SYMS 111 #define IDC_ROMPATCHER_BTN_SAVE 111 #define IDC_CHEAT_COM 111 #define IDC_VIDEOCONFIG_DIRECTDRAW_FS 111 @@ -277,11 +275,9 @@ #define BUTTON_MOVIE 206 #define IDC_DEBUGGER_FLAG_C 207 #define BUTTON_MEMWATCH 207 -#define IDC_DEBUGGER_ENABLE_SYMBOLIC 208 #define IDB_TE_GREEN_BLUE_ARROW 208 #define BUTTON_BOT 208 #define IDB_PIANO_0 209 -#define IDC_DEBUGGER_ROM_OFFSETS 209 #define BUTTON_MACRO 209 #define IDB_PIANO_1 210 #define BUTTON_PRESET 210 @@ -463,7 +459,6 @@ #define IDC_DEBUGGER_VAL_INSTRUCTIONS_COUNT 506 #define IDC_DEBUGGER_VAL_INSTRUCTIONS_COUNT2 507 #define IDC_VIDEOCONFIG_NO8LIM 600 -#define IDC_DEBUGGER_ROM_PATCHER 602 #define LIST_DEBUGGER_BOOKMARKS 701 #define BTN_CANCEL 800 #define IDC_GAME_GENIE_CODE 1000 @@ -603,7 +598,6 @@ #define MW_VAL15 1047 #define IDC_DEBUGGER_TEXT_INSTRUCTIONS_COUNT 1047 #define MW_NAME16 1048 -#define IDC_DEBUGGER_VAL_S3 1048 #define MW_ADDR16 1049 #define IDC_MAPPER_TEXT 1049 #define IDC_DEBUGGER_TEXT_A 1049 @@ -772,7 +766,6 @@ #define IDC_MOVIE_SUGGEST_READONLY 1201 #define ID_SOUND_QUALITYNOTIFY 1202 #define CB_ENABLECONTEXTMENU 1203 -#define DEBUGAUTOLOAD 1203 #define IDC_CHEAT_PAUSEWHENACTIVE 1203 #define IDC_FULLSAVESTATES 1203 #define IDC_SUPERIMPOSE 1203 @@ -792,7 +785,6 @@ #define IDC_COPY_MARKERS 1204 #define IDC_AUTOSAVECDL 1204 #define IDC_INVERT_THE_MASK 1204 -#define IDC_DEBUGGER_PREDEFINED_REGS 1204 #define IDC_RAMLIST 1205 #define IDC_CHECK_BOOKMARKS 1205 #define IDC_RUN_AUTO 1205 @@ -855,7 +847,6 @@ #define IDC_LUACONSOLE_CHOOSEFONT 1255 #define IDC_EDIT_LUAARGS 1256 #define CB_PARTIALVISUALTHEME 1257 -#define DEBUGLOADDEB 1258 #define IDC_C_SEARCHROM 1258 #define IDC_SINGLEINSTANCE 1258 #define IDC_MOVIE_CLOSEAFTERPLAYBACK 1258 @@ -899,7 +890,6 @@ #define STATIC_CONTRASTVALUE 1300 #define CTL_PALBRIGHT_TRACKBAR 1301 #define STATIC_BRIGHTVALUE 1302 -#define DEBUGIDAFONT 1305 #define IDC_AUTOSAVE_PERIOD_EVERY_TEXT 1306 #define IDC_AUTOSAVE_PERIOD_MINUTES_TEXT 1307 #define IDC_VBLANK_SCANLINES_TEXT 1308 @@ -1207,6 +1197,30 @@ #define CHEAT_CONTEXT_POSSI_ADDCHEAT 40601 #define CHEAT_CONTEXT_POSSI_ADDTORAMWATCH 40603 #define IDC_DEBUGGER_BOOKMARKS 45535 +#define ID_DEBUGGER_INLINE_ADDRESS 45536 +#define ID_DEBUGGER_RELOAD_SYMBOLS 45537 +#define ID_DEBUGGER_LOAD_DEB_FILE 45538 +#define ID_DEBUGGER_SYMBOLIC_DEBUG 45539 +#define ID_DEBUGGER_DEFAULT_REG_NAMES 45540 +#define ID_DEBUGGER_AUTO_OPEN 45541 +#define ID_DEBUGGER_IDA_FONT 45542 +#define ID_DEBUGGER_SHOW_ROM_OFFSETS 45543 +#define ID_DEBUGGER_RESTORE_SIZE 45544 +#define ID_DEBUGGER_ROM_PATCHER 45545 +#define ID_DEBUGGER_CODE_DUMPER 45546 +#define ID_DUMPER_START_ADDR 45547 +#define ID_DUMPER_END_ADDR 45548 +#define ID_DUMPER_FILEPATH 45549 +#define ID_DUMPER_BROWSE 45550 +#define ID_DUMPER_GO 45551 +#define ID_DUMPER_NES_ADDR_TOGGLE 45552 +#define ID_DEBUGGER_BREAK_BAD_OPCODES 45553 +#define ID_DEBUGGER_SHOW_TRACE_INFO 45554 +#define ID_DEBUGGER_BREAK_UNLOGGED_CODE 45555 +#define ID_DEBUGGER_BREAK_UNLOGGED_DATA 45556 +#define IDR_DEBUGGER_ACCELERATOR 45557 +#define ID_DEBUGGER_UNLOGGED_AS_DATA 45558 +#define ID_DEBUGGER_FOLLOW_PC 45559 #define MW_VALUELABEL2 65423 #define MW_VALUELABEL1 65426 #define IDC_STATIC_SLASHTEXT 65442 @@ -1225,7 +1239,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 313 -#define _APS_NEXT_COMMAND_VALUE 40012 +#define _APS_NEXT_COMMAND_VALUE 40013 #define _APS_NEXT_CONTROL_VALUE 1050 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/src/drivers/win/taseditor/history.h b/src/drivers/win/taseditor/history.h index 59d83c5ca..7cebe520d 100644 --- a/src/drivers/win/taseditor/history.h +++ b/src/drivers/win/taseditor/history.h @@ -108,7 +108,7 @@ class HISTORY int registerChanges(int mod_type, int start = 0, int end =-1, int size = 0, const char* comment = NULL, int consecutivenessTag = 0, RowsSelection* frameset = NULL); int registerAdjustLag(int start, int size); void registerMarkersChange(int modificationType, int start = 0, int end =-1, const char* comment = 0); - void registerBookmarkSet(int slot, BOOKMARK& backupÑopy, int oldCurrentBranch); + void registerBookmarkSet(int slot, BOOKMARK& backupCopy, int oldCurrentBranch); int registerBranching(int slot, bool markersWereChanged); void registerRecording(int frameOfChange, uint32 joypadDifferenceBits); int registerImport(MovieData& md, char* filename); diff --git a/src/drivers/win/tracer.cpp b/src/drivers/win/tracer.cpp index 661dac2c3..9e4a2aa2e 100644 --- a/src/drivers/win/tracer.cpp +++ b/src/drivers/win/tracer.cpp @@ -244,7 +244,7 @@ BOOL CALLBACK IDC_TRACER_LOG_WndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA DoDebug(0); if (hDebug) { - Disassemble(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, offset); + DisassembleToWindow(hDebug, IDC_DEBUGGER_DISASSEMBLY, IDC_DEBUGGER_DISASSEMBLY_VSCR, offset); PrintOffsetToSeekAndBookmarkFields(offset); } } diff --git a/src/drivers/win/window.cpp b/src/drivers/win/window.cpp index b36e74bcc..cb4c78a3e 100644 --- a/src/drivers/win/window.cpp +++ b/src/drivers/win/window.cpp @@ -3362,6 +3362,9 @@ bool inline (*GetIsLetterLegal(UINT id))(char letter) // Array Size, Init value in Symbolic Name in Debugger case IDC_EDIT_SYMBOLIC_ARRAY: case IDC_EDIT_SYMBOLIC_INIT: + // Address boxes in Debugger -> Tools menus + case ID_DUMPER_START_ADDR: case ID_DUMPER_END_ADDR: + // Address, Value, Compare, Known Value, Note equal, Greater than and Less than in Cheat case IDC_CHEAT_ADDR: case IDC_CHEAT_VAL: case IDC_CHEAT_COM: case IDC_CHEAT_VAL_KNOWN: case IDC_CHEAT_VAL_NE_BY: diff --git a/vc/vc14_fceux.vcxproj b/vc/vc14_fceux.vcxproj index 29cb00b59..3bed0b094 100644 --- a/vc/vc14_fceux.vcxproj +++ b/vc/vc14_fceux.vcxproj @@ -31,7 +31,7 @@ {6893EF44-FEA3-46DF-B236-C4C200F54294} fceux Win32Proj - 10.0 + 10.0.14393.0 @@ -71,7 +71,7 @@ - v142 + v141 v141_xp @@ -568,6 +568,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + @@ -576,6 +577,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + @@ -596,6 +598,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + @@ -1028,6 +1031,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + @@ -1035,6 +1039,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + @@ -1054,6 +1059,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + diff --git a/vc/vc14_fceux.vcxproj.filters b/vc/vc14_fceux.vcxproj.filters index c270d091d..a34827a64 100644 --- a/vc/vc14_fceux.vcxproj.filters +++ b/vc/vc14_fceux.vcxproj.filters @@ -1111,6 +1111,15 @@ boards + + drivers\win + + + drivers\win + + + drivers\win + @@ -1620,6 +1629,15 @@ drivers\win + + drivers + + + drivers\win + + + drivers\win +