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:
rainwarrior 2016-08-24 05:35:51 +00:00
parent f947ef06e7
commit 6e5cfae6f7
6 changed files with 163 additions and 34 deletions

View File

@ -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;

View File

@ -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
{

View File

@ -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);

View File

@ -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

View File

@ -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,
};

View File

@ -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