diff --git a/changelog.txt b/changelog.txt index deadb27d..41dfd3fa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,6 @@ ---version 2.0.2 released--- + +13-aug-2008 - zeromus - add FORBID breakpoints - regions which block breakpoints from happening if they contain the PC 13-aug-2008 - punkrockguy318 - SDL: fixed --input(1-4) options. input1 and 2 are regular inputs, input3 and 4 are famicom expansion inputs 12-aug-2008 - zeromus - fix SDL configfile woes. configfile now goes to ~/.fceux/fceux.cfg 12-aug-2008 - zeromus - SF [ 2047986 ] palflag 1 in .fm2 files crashes fceux diff --git a/src/debug.cpp b/src/debug.cpp index ee7c900c..f82c926c 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -24,15 +24,15 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) return -1; } - if (type & PPU_BREAKPOINT) + if (type & BT_P) { return offset & 0x3FFF; } - else if (type & SPRITE_BREAKPOINT) + else if (type & BT_S) { return offset & 0x00FF; } - else // CPU_BREAKPOINTS + else // BT_C { if (GameInfo->type == GIT_NSF) { //NSF Breakpoint keywords if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8)); @@ -56,6 +56,30 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) return offset; } +// Returns the value of a given type or register + +int getValue(int type) +{ + switch (type) + { + case 'A': return _A; + case 'X': return _X; + case 'Y': return _Y; + case 'N': return _P & N_FLAG ? 1 : 0; + case 'V': return _P & V_FLAG ? 1 : 0; + case 'U': return _P & U_FLAG ? 1 : 0; + case 'B': return _P & B_FLAG ? 1 : 0; + case 'D': return _P & D_FLAG ? 1 : 0; + case 'I': return _P & I_FLAG ? 1 : 0; + case 'Z': return _P & Z_FLAG ? 1 : 0; + case 'C': return _P & C_FLAG ? 1 : 0; + case 'P': return _PC; + } + + return 0; +} + + /** * Checks whether a breakpoint condition is syntactically valid * and creates a breakpoint condition object if everything's OK. @@ -146,14 +170,15 @@ unsigned int NewBreak(const char* name, int start, int end, unsigned int type, c // Get the breakpoint flags watchpoint[num].flags = 0; if (enable) watchpoint[num].flags|=WP_E; - if (type & READ_BREAKPOINT) watchpoint[num].flags|=WP_R; - if (type & WRITE_BREAKPOINT) watchpoint[num].flags|=WP_W; - if (type & EXECUTE_BREAKPOINT) watchpoint[num].flags|=WP_X; - if (type & PPU_BREAKPOINT) { + if (type & WP_R) watchpoint[num].flags|=WP_R; + if (type & WP_F) watchpoint[num].flags|=WP_F; + if (type & WP_W) watchpoint[num].flags|=WP_W; + if (type & WP_X) watchpoint[num].flags|=WP_X; + if (type & BT_P) { watchpoint[num].flags|=BT_P; watchpoint[num].flags&=~WP_X; //disable execute flag! } - if (type & SPRITE_BREAKPOINT) { + if (type & BT_S) { watchpoint[num].flags|=BT_S; watchpoint[num].flags&=~WP_X; //disable execute flag! } @@ -227,6 +252,82 @@ uint8 GetPPUMem(uint8 A) { return vnapage[(tmp>>10)&0x3][tmp&0x3FF]; } +//--------------------- + +// Evaluates a condition +int evaluate(Condition* c) +{ + int f = 0; + + int value1, value2; + + if (c->lhs) + { + value1 = evaluate(c->lhs); + } + else + { + switch(c->type1) + { + case TYPE_ADDR: + case TYPE_NUM: value1 = c->value1; break; + default: value1 = getValue(c->value1); + } + } + + if (c->type1 == TYPE_ADDR) + { + value1 = GetMem(value1); + } + + f = value1; + + if (c->op) + { + if (c->rhs) + { + value2 = evaluate(c->rhs); + } + else + { + switch(c->type2) + { + case TYPE_ADDR: + case TYPE_NUM: value2 = c->value2; break; + default: value2 = getValue(c->type2); + } + } + + if (c->type2 == TYPE_ADDR) + { + value2 = GetMem(value2); + } + + switch (c->op) + { + case OP_EQ: f = value1 == value2; break; + case OP_NE: f = value1 != value2; break; + case OP_GE: f = value1 >= value2; break; + case OP_LE: f = value1 <= value2; break; + case OP_G: f = value1 > value2; break; + case OP_L: f = value1 < value2; break; + case OP_MULT: f = value1 * value2; break; + case OP_DIV: f = value1 / value2; break; + case OP_PLUS: f = value1 + value2; break; + case OP_MINUS: f = value1 - value2; break; + case OP_OR: f = value1 || value2; break; + case OP_AND: f = value1 && value2; break; + } + } + + return f; +} + +int condition(watchpointinfo* wp) +{ + return wp->cond == 0 || evaluate(wp->cond); +} + //--------------------- @@ -333,7 +434,29 @@ static DebuggerState dbgstate; DebuggerState &FCEUI_Debugger() { return dbgstate; } -void BreakHit() { +void BreakHit(bool force = false) { + + if(!force) { + + //check to see whether we fall in any forbid zone + for (int i = 0; i < numWPs; i++) { + watchpointinfo& wp = watchpoint[i]; + if(!(wp.flags & WP_F)) + continue; + + if (condition(&wp)) + { + if (wp.endaddress) { + if( (wp.address <= _PC) && (wp.endaddress >= _PC) ) + return; //forbid + } else { + if(wp.address == _PC) + return; //forbid + } + } + } + } + FCEUI_SetEmulationPaused(1); //mbg merge 7/19/06 changed to use EmulationPaused() //MBG TODO - was this commented out before the gnu refactoring? @@ -377,108 +500,6 @@ void BreakHit() { } */ -// ################################## Start of SP CODE ########################### - -// Returns the value of a given type or register - -int getValue(int type) -{ - switch (type) - { - case 'A': return _A; - case 'X': return _X; - case 'Y': return _Y; - case 'N': return _P & N_FLAG ? 1 : 0; - case 'V': return _P & V_FLAG ? 1 : 0; - case 'U': return _P & U_FLAG ? 1 : 0; - case 'B': return _P & B_FLAG ? 1 : 0; - case 'D': return _P & D_FLAG ? 1 : 0; - case 'I': return _P & I_FLAG ? 1 : 0; - case 'Z': return _P & Z_FLAG ? 1 : 0; - case 'C': return _P & C_FLAG ? 1 : 0; - case 'P': return _PC; - } - - return 0; -} - -// Evaluates a condition -int evaluate(Condition* c) -{ - int f = 0; - - int value1, value2; - - if (c->lhs) - { - value1 = evaluate(c->lhs); - } - else - { - switch(c->type1) - { - case TYPE_ADDR: - case TYPE_NUM: value1 = c->value1; break; - default: value1 = getValue(c->value1); - } - } - - if (c->type1 == TYPE_ADDR) - { - value1 = GetMem(value1); - } - - f = value1; - - if (c->op) - { - if (c->rhs) - { - value2 = evaluate(c->rhs); - } - else - { - switch(c->type2) - { - case TYPE_ADDR: - case TYPE_NUM: value2 = c->value2; break; - default: value2 = getValue(c->type2); - } - } - - if (c->type2 == TYPE_ADDR) - { - value2 = GetMem(value2); - } - - switch (c->op) - { - case OP_EQ: f = value1 == value2; break; - case OP_NE: f = value1 != value2; break; - case OP_GE: f = value1 >= value2; break; - case OP_LE: f = value1 <= value2; break; - case OP_G: f = value1 > value2; break; - case OP_L: f = value1 < value2; break; - case OP_MULT: f = value1 * value2; break; - case OP_DIV: f = value1 / value2; break; - case OP_PLUS: f = value1 + value2; break; - case OP_MINUS: f = value1 - value2; break; - case OP_OR: f = value1 || value2; break; - case OP_AND: f = value1 && value2; break; - } - } - - return f; -} - -int condition(watchpointinfo* wp) -{ - return wp->cond == 0 || evaluate(wp->cond); -} - -// ################################## End of SP CODE ########################### - - ///fires a breakpoint void breakpoint() { int i; @@ -489,7 +510,7 @@ void breakpoint() { opcode[0] = GetMem(_PC); //if the current instruction is bad, and we are breaking on bad opcodes, then hit the breakpoint - if(dbgstate.badopbreak && (opsize[opcode[0]] == 0)) BreakHit(); + if(dbgstate.badopbreak && (opsize[opcode[0]] == 0)) BreakHit(true); //if we're stepping out, track the nest level if (dbgstate.stepout) { @@ -507,7 +528,7 @@ void breakpoint() { //if we're stepping, then we'll always want to break if (dbgstate.step) { dbgstate.step = false; - BreakHit(); + BreakHit(true); return; } @@ -515,7 +536,7 @@ void breakpoint() { if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) { watchpoint[64].address = 0; watchpoint[64].flags = 0; - BreakHit(); + BreakHit(true); return; } diff --git a/src/debug.h b/src/debug.h index eece10e5..95cb4586 100644 --- a/src/debug.h +++ b/src/debug.h @@ -10,10 +10,11 @@ #define WP_W 0x02 //watchpoint, write #define WP_R 0x04 //watchpoint, read #define WP_X 0x08 //watchpoint, execute +#define WP_F 0x10 //watchpoint, forbid #define BT_C 0x00 //break type, cpu mem -#define BT_P 0x10 //break type, ppu mem -#define BT_S 0x20 //break type, sprite mem +#define BT_P 0x20 //break type, ppu mem +#define BT_S 0x40 //break type, sprite mem //opbrktype is used to grab the breakpoint type that each instruction will cause. //WP_X is not used because ALL opcodes will have the execute bit set. @@ -46,7 +47,7 @@ typedef struct { Condition* cond; char* condText; char* desc; - + // ################################## End of SP CODE ########################### } watchpointinfo; @@ -121,12 +122,12 @@ extern NSF_HEADER NSFHeader; ///retrieves the core's DebuggerState DebuggerState &FCEUI_Debugger(); -#define CPU_BREAKPOINT 1 -#define PPU_BREAKPOINT 2 -#define SPRITE_BREAKPOINT 4 -#define READ_BREAKPOINT 8 -#define WRITE_BREAKPOINT 16 -#define EXECUTE_BREAKPOINT 32 +//#define CPU_BREAKPOINT 1 +//#define PPU_BREAKPOINT 2 +//#define SPRITE_BREAKPOINT 4 +//#define READ_BREAKPOINT 8 +//#define WRITE_BREAKPOINT 16 +//#define EXECUTE_BREAKPOINT 32 int offsetStringToInt(unsigned int type, const char* offsetBuffer); unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable); diff --git a/src/drivers/win/debugger.cpp b/src/drivers/win/debugger.cpp index 9f527a40..37c2e47f 100644 --- a/src/drivers/win/debugger.cpp +++ b/src/drivers/win/debugger.cpp @@ -75,32 +75,24 @@ unsigned int NewBreakWindows(HWND hwndDlg, unsigned int num, bool enable) GetDlgItemText(hwndDlg, IDC_ADDBP_ADDR_END, endOffsetBuffer, sizeof(endOffsetBuffer)); if (IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MEM_CPU)) - { - type |= CPU_BREAKPOINT; - } + type |= BT_C; else if (IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MEM_PPU)) - { - type |= PPU_BREAKPOINT; - } + type |= BT_P; else - { - type |= SPRITE_BREAKPOINT; - } + type |= BT_S; if (IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MODE_R)) - { - type |= READ_BREAKPOINT; - } + type |= WP_R; if (IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MODE_W)) - { - type |= WRITE_BREAKPOINT; - } + type |= WP_W; if (IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MODE_X)) - { - type |= EXECUTE_BREAKPOINT; - } + type |= WP_X; + + //this overrides all + if (IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MODE_F)) + type = WP_F; int start = offsetStringToInt(type, startOffsetBuffer); @@ -155,6 +147,24 @@ unsigned int AddBreak(HWND hwndDlg) return 0; } +static void UpdateDialog(HWND hwndDlg) { + BOOL forbid = IsDlgButtonChecked(hwndDlg, IDC_ADDBP_MODE_F); + BOOL enable = !forbid; + EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MODE_R),enable); + EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MODE_W),enable); + EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MODE_X),enable); + 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); +} + BOOL CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { char str[8]={0}; @@ -175,6 +185,7 @@ BOOL CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) if (watchpoint[WP_edit].flags&WP_R) CheckDlgButton(hwndDlg, IDC_ADDBP_MODE_R, BST_CHECKED); if (watchpoint[WP_edit].flags&WP_W) CheckDlgButton(hwndDlg, IDC_ADDBP_MODE_W, BST_CHECKED); if (watchpoint[WP_edit].flags&WP_X) CheckDlgButton(hwndDlg, IDC_ADDBP_MODE_X, BST_CHECKED); + if (watchpoint[WP_edit].flags&WP_F) CheckDlgButton(hwndDlg, IDC_ADDBP_MODE_F, BST_CHECKED); if (watchpoint[WP_edit].flags&BT_P) { CheckDlgButton(hwndDlg, IDC_ADDBP_MEM_PPU, BST_CHECKED); @@ -185,6 +196,8 @@ BOOL CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) EnableWindow(GetDlgItem(hwndDlg,IDC_ADDBP_MODE_X),FALSE); } else CheckDlgButton(hwndDlg, IDC_ADDBP_MEM_CPU, BST_CHECKED); + + UpdateDialog(hwndDlg); // ################################## Start of SP CODE ########################### @@ -220,6 +233,11 @@ BOOL CALLBACK AddbpCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) switch(HIWORD(wParam)) { case BN_CLICKED: switch(LOWORD(wParam)) { + case IDC_ADDBP_MODE_F: { + UpdateDialog(hwndDlg); + break; + } + case IDOK: if (WP_edit >= 0) { int tmp = NewBreakWindows(hwndDlg,WP_edit,(BOOL)(watchpoint[WP_edit].flags&WP_E)); @@ -562,11 +580,12 @@ char *BreakToText(unsigned int num) { if (watchpoint[num].flags&WP_R) strcat(str,"R"); else strcat(str,"-"); if (watchpoint[num].flags&WP_W) strcat(str,"W"); else strcat(str,"-"); if (watchpoint[num].flags&WP_X) strcat(str,"X"); else strcat(str,"-"); + if (watchpoint[num].flags&WP_F) strcat(str,"F"); else strcat(str,"-"); // ################################## Start of SP CODE ########################### if (watchpoint[num].desc) { - strcat(str, " - "); + strcat(str, " : "); strcat(str, watchpoint[num].desc); } // ################################## End of SP CODE ########################### diff --git a/src/drivers/win/res.rc b/src/drivers/win/res.rc index a6571c9c..77aa7a29 100644 --- a/src/drivers/win/res.rc +++ b/src/drivers/win/res.rc @@ -924,7 +924,7 @@ BEGIN "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,181,196,158,10 END -ADDBP DIALOGEX 66, 83, 185, 121 +ADDBP DIALOGEX 66, 83, 196, 130 STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Add Breakpoint..." FONT 8, "MS Sans Serif", 0, 0, 0x0 @@ -933,19 +933,21 @@ BEGIN CTEXT "-",65534,78,5,8,8 EDITTEXT IDC_ADDBP_ADDR_START,48,4,30,12,ES_UPPERCASE | ES_WANTRETURN EDITTEXT IDC_ADDBP_ADDR_END,83,4,30,12,ES_UPPERCASE | ES_WANTRETURN - CONTROL "Read",IDC_ADDBP_MODE_R,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,20,35,12 - CONTROL "Write",IDC_ADDBP_MODE_W,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,45,20,35,12 - CONTROL "Execute",IDC_ADDBP_MODE_X,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,20,40,12 - DEFPUSHBUTTON "&OK",IDOK,47,104,42,13 - PUSHBUTTON "&Cancel",IDCANCEL,95,105,42,13 - GROUPBOX "Memory",108,6,34,174,24,WS_TABSTOP - CONTROL "CPU Mem",IDC_ADDBP_MEM_CPU,"Button",BS_AUTORADIOBUTTON | WS_GROUP,10,44,50,10 - CONTROL "PPU Mem",IDC_ADDBP_MEM_PPU,"Button",BS_AUTORADIOBUTTON,65,44,50,10 - CONTROL "Sprite Mem",IDC_ADDBP_MEM_SPR,"Button",BS_AUTORADIOBUTTON,121,44,50,10 - EDITTEXT IDC_ADDBP_CONDITION,43,64,136,14,ES_AUTOHSCROLL - LTEXT "Condition",65533,7,66,30,8 - LTEXT "Name",65532,8,84,20,8 - EDITTEXT IDC_ADDBP_NAME,43,81,136,14,ES_AUTOHSCROLL + CONTROL "Read",IDC_ADDBP_MODE_R,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,25,35,12 + CONTROL "Write",IDC_ADDBP_MODE_W,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,49,25,35,12 + CONTROL "Execute",IDC_ADDBP_MODE_X,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,86,25,40,12 + DEFPUSHBUTTON "&OK",IDOK,99,113,42,13 + PUSHBUTTON "&Cancel",IDCANCEL,147,114,42,13 + GROUPBOX "Memory",108,9,39,174,24,WS_TABSTOP + CONTROL "CPU Mem",IDC_ADDBP_MEM_CPU,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,49,50,10 + CONTROL "PPU Mem",IDC_ADDBP_MEM_PPU,"Button",BS_AUTORADIOBUTTON,68,49,50,10 + CONTROL "Sprite Mem",IDC_ADDBP_MEM_SPR,"Button",BS_AUTORADIOBUTTON,124,49,50,10 + EDITTEXT IDC_ADDBP_CONDITION,43,72,136,14,ES_AUTOHSCROLL + LTEXT "Condition",65533,7,74,30,8 + LTEXT "Name",65532,8,92,20,8 + EDITTEXT IDC_ADDBP_NAME,43,89,136,14,ES_AUTOHSCROLL + CONTROL "Forbid",IDC_ADDBP_MODE_F,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,145,6,40,12 + GROUPBOX "",112,3,18,185,50,WS_TABSTOP END NTVIEW DIALOGEX 44, 38, 355, 402 @@ -1403,6 +1405,12 @@ BEGIN RIGHTMARGIN, 547 END + "ADDBP", DIALOG + BEGIN + RIGHTMARGIN, 185 + BOTTOMMARGIN, 121 + END + "MONITOR", DIALOG BEGIN LEFTMARGIN, 7 diff --git a/src/drivers/win/resource.h b/src/drivers/win/resource.h index e55545fd..b91996af 100644 --- a/src/drivers/win/resource.h +++ b/src/drivers/win/resource.h @@ -102,6 +102,8 @@ #define IDC_CHEAT_VAL_GT_BY 109 #define IDC_DEBUGGER_SEEK_TO 109 #define IDC_ROMPATCHER_PATCH_DATA 109 +#define IDC_ADDBP_MODE_X2 109 +#define IDC_ADDBP_MODE_F 109 #define IDC_CHEAT_VAL_LT_BY 110 #define MENU_SAVE_STATE 110 #define CB_ASK_EXIT 110