1. added new 'R' and 'W' conditions for breakpoints which evaluate to the value read by read instructions, or the value about to be written by write instructions.
2. added illegal opcode support for breakpoints (filled in missing fields of optype matrix)
This commit is contained in:
parent
f947ef06e7
commit
6e5cfae6f7
|
@ -35,9 +35,10 @@
|
|||
* Number -> '#' [1-9A-F]*
|
||||
* Address -> '$' [1-9A-F]* | '$' '[' Connect ']'
|
||||
* Register -> 'A' | 'X' | 'Y' | 'P' | 'S'
|
||||
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V'
|
||||
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' | 'U' | 'D'
|
||||
* PC Bank -> 'K'
|
||||
* Data Bank -> 'T'
|
||||
* Data Bank -> 'T'
|
||||
* Value -> 'R' | 'W'
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
@ -50,8 +51,9 @@
|
|||
#include <cassert>
|
||||
#include <cctype>
|
||||
|
||||
// hack: this address is used by 'T' condition
|
||||
uint16 addressOfTheLastAccessedData = 0;
|
||||
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
|
||||
uint8 debugLastOpcode; // used to evaluate 'W' condition
|
||||
|
||||
// Next non-whitespace character in string
|
||||
char next;
|
||||
|
||||
|
@ -152,6 +154,18 @@ int isDataBank(char c)
|
|||
return c == 'T';
|
||||
}
|
||||
|
||||
// Determines if a character is for value read
|
||||
int isValueRead(char c)
|
||||
{
|
||||
return c == 'R';
|
||||
}
|
||||
|
||||
// Determines if a character is for value write
|
||||
int isValueWrite(char c)
|
||||
{
|
||||
return c == 'W';
|
||||
}
|
||||
|
||||
// Reads a hexadecimal number from str
|
||||
int getNumber(unsigned int* number, const char** str)
|
||||
{
|
||||
|
@ -272,6 +286,40 @@ Condition* Primitive(const char** str, Condition* c)
|
|||
|
||||
return c;
|
||||
}
|
||||
else if (isValueRead(next))
|
||||
{
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_VALUE_READ;
|
||||
c->value1 = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_VALUE_READ;
|
||||
c->value2 = next;
|
||||
}
|
||||
|
||||
scan(str);
|
||||
|
||||
return c;
|
||||
}
|
||||
else if (isValueWrite(next))
|
||||
{
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_VALUE_WRITE;
|
||||
c->value1 = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_VALUE_WRITE;
|
||||
c->value2 = next;
|
||||
}
|
||||
|
||||
scan(str);
|
||||
|
||||
return c;
|
||||
}
|
||||
else if (next == '#') /* Numbers */
|
||||
{
|
||||
unsigned int number = 0;
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#define TYPE_ADDR 4
|
||||
#define TYPE_PC_BANK 5
|
||||
#define TYPE_DATA_BANK 6
|
||||
#define TYPE_VALUE_READ 7
|
||||
#define TYPE_VALUE_WRITE 8
|
||||
|
||||
#define OP_NO 0
|
||||
#define OP_EQ 1
|
||||
|
@ -43,7 +45,9 @@
|
|||
#define OP_OR 11
|
||||
#define OP_AND 12
|
||||
|
||||
extern uint16 addressOfTheLastAccessedData;
|
||||
extern uint16 debugLastAddress;
|
||||
extern uint8 debugLastOpcode;
|
||||
|
||||
//mbg merge 7/18/06 turned into sane c++
|
||||
struct Condition
|
||||
{
|
||||
|
|
|
@ -310,6 +310,32 @@ uint8 GetPPUMem(uint8 A) {
|
|||
|
||||
//---------------------
|
||||
|
||||
uint8 evaluateWrite(uint8 opcode, uint16 address)
|
||||
{
|
||||
// predicts value written by this opcode
|
||||
switch (opwrite[opcode])
|
||||
{
|
||||
default:
|
||||
case 0: return 0; // no write
|
||||
case 1: return _A; // STA, PHA
|
||||
case 2: return _X; // STX
|
||||
case 3: return _Y; // STY
|
||||
case 4: return _P; // PHP
|
||||
case 5: return GetMem(address) << 1; // ASL (SLO)
|
||||
case 6: return GetMem(address) >> 1; // LSR (SRE)
|
||||
case 7: return (GetMem(address) << 1) | (_P & 1); // ROL (RLA)
|
||||
case 8: return (GetMem(address) >> 1) | ((_P & 1) << 7); // ROL (RRA)
|
||||
case 9: return GetMem(address) + 1; // INC (ISC)
|
||||
case 10: return GetMem(address) - 1; // DEC (DCP)
|
||||
case 11: return _A & _X; // (SAX)
|
||||
case 12: return _A&_X&(((address-_Y)>>8)+1); // (AHX)
|
||||
case 13: return _Y&(((address-_X)>>8)+1); // (SHY)
|
||||
case 14: return _X&(((address-_Y)>>8)+1); // (SHX)
|
||||
case 15: return _S& (((address-_Y)>>8)+1); // (TAS)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Evaluates a condition
|
||||
int evaluate(Condition* c)
|
||||
{
|
||||
|
@ -335,7 +361,9 @@ int evaluate(Condition* c)
|
|||
{
|
||||
case TYPE_ADDR: value1 = GetMem(value1); break;
|
||||
case TYPE_PC_BANK: value1 = getBank(_PC); break;
|
||||
case TYPE_DATA_BANK: value1 = getBank(addressOfTheLastAccessedData); break;
|
||||
case TYPE_DATA_BANK: value1 = getBank(debugLastAddress); break;
|
||||
case TYPE_VALUE_READ: value1 = GetMem(debugLastAddress); break;
|
||||
case TYPE_VALUE_WRITE: value1 = evaluateWrite(debugLastOpcode, debugLastAddress); break;
|
||||
}
|
||||
|
||||
f = value1;
|
||||
|
@ -360,7 +388,9 @@ int evaluate(Condition* c)
|
|||
{
|
||||
case TYPE_ADDR: value2 = GetMem(value2); break;
|
||||
case TYPE_PC_BANK: value2 = getBank(_PC); break;
|
||||
case TYPE_DATA_BANK: value2 = getBank(addressOfTheLastAccessedData); break;
|
||||
case TYPE_DATA_BANK: value2 = getBank(debugLastAddress); break;
|
||||
case TYPE_VALUE_READ: value2 = GetMem(debugLastAddress); break;
|
||||
case TYPE_VALUE_WRITE: value2 = evaluateWrite(debugLastOpcode, debugLastAddress); break;
|
||||
}
|
||||
|
||||
switch (c->op)
|
||||
|
@ -507,6 +537,11 @@ void BreakHit(int bp_num, bool force)
|
|||
{
|
||||
if(!force)
|
||||
{
|
||||
if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
|
||||
{
|
||||
return; // condition rejected
|
||||
}
|
||||
|
||||
//check to see whether we fall in any forbid zone
|
||||
for (int i = 0; i < numWPs; i++)
|
||||
{
|
||||
|
@ -544,6 +579,9 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
|||
uint8 stackop=0;
|
||||
uint8 stackopstartaddr,stackopendaddr;
|
||||
|
||||
debugLastAddress = A;
|
||||
debugLastOpcode = opcode[0];
|
||||
|
||||
if (break_asap)
|
||||
{
|
||||
break_asap = false;
|
||||
|
@ -606,24 +644,23 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
|||
switch (opcode[0]) {
|
||||
//Push Ops
|
||||
case 0x08: //Fall to next
|
||||
case 0x48: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
|
||||
case 0x48: debugLastAddress=stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
|
||||
//Pull Ops
|
||||
case 0x28: //Fall to next
|
||||
case 0x68: stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
|
||||
case 0x68: debugLastAddress=stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break;
|
||||
//JSR (Includes return address - 1)
|
||||
case 0x20: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=(opcode[1]|opcode[2]<<8); break;
|
||||
//RTI (Includes processor status, and exact return address)
|
||||
case 0x40: stackopstartaddr=X.S+1; stackopendaddr=X.S+3; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(X.S+2|0x0100)|GetMem(X.S+3|0x0100)<<8); break;
|
||||
//RTS (Includes return address - 1)
|
||||
case 0x60: stackopstartaddr=X.S+1; stackopendaddr=X.S+2; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(stackopstartaddr|0x0100)|GetMem(stackopendaddr|0x0100)<<8)+1; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
for (i = 0; i < numWPs; i++)
|
||||
{
|
||||
// ################################## Start of SP CODE ###########################
|
||||
if ((watchpoint[i].flags & WP_E) && condition(&watchpoint[i]))
|
||||
if ((watchpoint[i].flags & WP_E))
|
||||
{
|
||||
// ################################## End of SP CODE ###########################
|
||||
if (watchpoint[i].flags & BT_P)
|
||||
{
|
||||
// PPU Mem breaks
|
||||
|
@ -747,9 +784,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
|||
|
||||
}
|
||||
}
|
||||
// ################################## Start of SP CODE ###########################
|
||||
}
|
||||
// ################################## End of SP CODE ###########################
|
||||
}
|
||||
|
||||
//Update the stack address with the current one, now that changes have registered.
|
||||
|
@ -761,6 +796,7 @@ void DebugCycle()
|
|||
{
|
||||
uint8 opcode[3] = {0};
|
||||
uint16 A = 0, tmp;
|
||||
uint8 V = 0;
|
||||
int size;
|
||||
|
||||
if (scanline == 240)
|
||||
|
@ -782,9 +818,12 @@ void DebugCycle()
|
|||
size = opsize[opcode[0]];
|
||||
switch (size)
|
||||
{
|
||||
default:
|
||||
case 1: break;
|
||||
case 2:
|
||||
opcode[1] = GetMem(_PC + 1);
|
||||
break;
|
||||
case 0: // illegal instructions may have operands
|
||||
case 3:
|
||||
opcode[1] = GetMem(_PC + 1);
|
||||
opcode[2] = GetMem(_PC + 2);
|
||||
|
@ -808,7 +847,6 @@ void DebugCycle()
|
|||
case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break;
|
||||
case 8: A = opcode[1] + _Y; break;
|
||||
}
|
||||
addressOfTheLastAccessedData = A;
|
||||
|
||||
if (numWPs || dbgstate.step || dbgstate.runline || dbgstate.stepout || watchpoint[64].flags || dbgstate.badopbreak || break_on_cycles || break_on_instructions || break_asap)
|
||||
breakpoint(opcode, A, size);
|
||||
|
|
|
@ -49,13 +49,11 @@ typedef struct {
|
|||
uint16 address;
|
||||
uint16 endaddress;
|
||||
uint8 flags;
|
||||
// ################################## Start of SP CODE ###########################
|
||||
|
||||
Condition* cond;
|
||||
char* condText;
|
||||
char* desc;
|
||||
|
||||
// ################################## End of SP CODE ###########################
|
||||
} watchpointinfo;
|
||||
|
||||
//mbg merge 7/18/06 had to make this extern
|
||||
|
|
|
@ -541,7 +541,7 @@ const uint8 opsize[256] = {
|
|||
#else
|
||||
/*0x00*/ 1, //BRK
|
||||
#endif
|
||||
/*0x01*/ 2,0,0,0,2,2,0,1,2,1,0,0,3,3,0,
|
||||
/*0x01*/ 2,0,0,0,2,2,0,1,2,1,0,0,3,3,0,
|
||||
/*0x10*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
/*0x20*/ 3,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0x30*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
|
@ -573,20 +573,58 @@ const uint8 opsize[256] = {
|
|||
// 8 = Zero Page,Y
|
||||
//
|
||||
const uint8 optype[256] = {
|
||||
/*0x00*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0,
|
||||
/*0x10*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x20*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0x30*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x40*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0,
|
||||
/*0x50*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x60*/ 0,1,0,0,0,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0x70*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x80*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0x90*/ 0,4,0,0,5,5,8,0,0,6,0,0,0,7,0,0,
|
||||
/*0xA0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xB0*/ 0,4,0,0,5,5,8,0,0,6,0,0,7,7,6,0,
|
||||
/*0xC0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xD0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0xE0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xF0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0
|
||||
/*0x00*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0x10*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
|
||||
/*0x20*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0x30*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
|
||||
/*0x40*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0x50*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
|
||||
/*0x60*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0x70*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
|
||||
/*0x80*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0x90*/ 0,4,0,3,5,5,8,8,0,6,0,6,7,7,6,6,
|
||||
/*0xA0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0xB0*/ 0,4,0,3,5,5,8,8,0,6,0,6,7,7,6,6,
|
||||
/*0xC0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0xD0*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
|
||||
/*0xE0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
|
||||
/*0xF0*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
|
||||
};
|
||||
|
||||
// the opwrite table aids in predicting the value written for any 6502 opcode
|
||||
//
|
||||
// 0 = No value written
|
||||
// 1 = Write from A
|
||||
// 2 = Write from X
|
||||
// 3 = Write from Y
|
||||
// 4 = Write from P
|
||||
// 5 = ASL (SLO)
|
||||
// 6 = LSR (SRE)
|
||||
// 7 = ROL (RLA)
|
||||
// 8 = ROR (RRA)
|
||||
// 9 = INC (ISC)
|
||||
// 10 = DEC (DCP)
|
||||
// 11 = (SAX)
|
||||
// 12 = (AHX)
|
||||
// 13 = (SHY)
|
||||
// 14 = (SHX)
|
||||
// 15 = (TAS)
|
||||
|
||||
const uint8 opwrite[256] = {
|
||||
/*0x00*/ 0, 0, 0, 5, 0, 0, 5, 5, 4, 0, 0, 0, 0, 0, 5, 5,
|
||||
/*0x10*/ 0, 0, 0, 5, 0, 0, 5, 5, 0, 0, 0, 5, 0, 0, 5, 5,
|
||||
/*0x20*/ 0, 0, 0, 7, 0, 0, 7, 7, 0, 0, 7, 0, 0, 0, 7, 7,
|
||||
/*0x30*/ 0, 0, 0, 7, 0, 0, 7, 7, 0, 0, 0, 7, 0, 0, 7, 7,
|
||||
/*0x40*/ 0, 0, 0, 6, 0, 0, 6, 6, 1, 0, 6, 0, 0, 0, 6, 6,
|
||||
/*0x50*/ 0, 0, 0, 6, 0, 0, 6, 6, 0, 0, 0, 6, 0, 0, 6, 6,
|
||||
/*0x60*/ 0, 0, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 0, 0, 8, 8,
|
||||
/*0x70*/ 0, 0, 0, 8, 0, 0, 8, 8, 0, 0, 0, 8, 0, 0, 8, 8,
|
||||
/*0x80*/ 0, 1, 0,11, 3, 1, 2,11, 0, 0, 0, 0, 3, 1, 2,11,
|
||||
/*0x90*/ 0, 1, 0,12, 3, 1, 2,11, 0, 1, 0,15,13, 1,14,12,
|
||||
/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/*0xC0*/ 0, 0, 0,10, 0, 0,10,10, 0, 0, 0, 0, 0, 0,10,10,
|
||||
/*0xD0*/ 0, 0, 0,10, 0, 0,10,10, 0, 0, 0,10, 0, 0,10,10,
|
||||
/*0xE0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9,
|
||||
/*0xF0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 9, 0, 0, 9, 9,
|
||||
};
|
|
@ -31,6 +31,9 @@ extern const uint8 opsize[256];
|
|||
//the optype table is a quick way to grab the addressing mode for any 6502 opcode
|
||||
extern const uint8 optype[256];
|
||||
|
||||
// the opwrite table aids in predicting the value written for any 6502 opcode
|
||||
extern const uint8 opwrite[256];
|
||||
|
||||
//-----------
|
||||
//mbg 6/30/06 - some of this was removed to mimic XD
|
||||
//#ifdef FCEUDEF_DEBUGGER
|
||||
|
|
Loading…
Reference in New Issue