mirror of https://github.com/stella-emu/stella.git
Added register names to argument processing. This means you can set e.g.
location 80 to the contents of the X register by saying "ram 80 x". This also means that there's a small conflict: if you're inputting the value 0x0a (decimal 10), you need to either say "0a" or "A". Otherwise the parser thinks you're talking about the "a" register instead of the hex number "a". Added dereference operator to arg processing. This works the same way as in C: you prefix a "*" to an argument. So "80" means a literal hex 80, as before, but you can say "*80" to mean "the memory location pointed to by location 80"... this also works with the registers. Example: if the X register holds the value ff, you can say "*x" and it will be treated as the value ff. Unlike C, multiple levels of dereference are not supported. Also, the result of a dereference is always a byte for now. Added "eval" command to debugger prompt. This evaluates one or more arguments (which may hex values or a labels, and may have a * in front) and prints the results in hex, binary, and decimal, along with the label that has that value, if any. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@527 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
a92a6b0ab8
commit
5378b2c971
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: Debugger.cxx,v 1.16 2005-06-18 15:45:05 urchlay Exp $
|
// $Id: Debugger.cxx,v 1.17 2005-06-18 17:28:18 urchlay Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
@ -397,6 +397,31 @@ int Debugger::getPC() {
|
||||||
return myDebugger->pc();
|
return myDebugger->pc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int Debugger::getA() {
|
||||||
|
return myDebugger->a();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int Debugger::getX() {
|
||||||
|
return myDebugger->x();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int Debugger::getY() {
|
||||||
|
return myDebugger->y();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int Debugger::getS() {
|
||||||
|
return myDebugger->sp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int Debugger::getP() {
|
||||||
|
return myDebugger->ps();
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string Debugger::disassemble(int start, int lines) {
|
string Debugger::disassemble(int start, int lines) {
|
||||||
char buf[255], bbuf[255];
|
char buf[255], bbuf[255];
|
||||||
|
@ -438,3 +463,8 @@ void Debugger::clearAllBreakPoints() {
|
||||||
breakPoints = new PackedBitArray(0x10000);
|
breakPoints = new PackedBitArray(0x10000);
|
||||||
mySystem->m6502().setBreakPoints(NULL);
|
mySystem->m6502().setBreakPoints(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int Debugger::peek(int addr) {
|
||||||
|
return mySystem->peek(addr);
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: Debugger.hxx,v 1.14 2005-06-18 15:45:05 urchlay Exp $
|
// $Id: Debugger.hxx,v 1.15 2005-06-18 17:28:18 urchlay Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#ifndef DEBUGGER_HXX
|
#ifndef DEBUGGER_HXX
|
||||||
|
@ -49,7 +49,7 @@ enum {
|
||||||
for all debugging operations in Stella (parser, 6502 debugger, etc).
|
for all debugging operations in Stella (parser, 6502 debugger, etc).
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
@version $Id: Debugger.hxx,v 1.14 2005-06-18 15:45:05 urchlay Exp $
|
@version $Id: Debugger.hxx,v 1.15 2005-06-18 17:28:18 urchlay Exp $
|
||||||
*/
|
*/
|
||||||
class Debugger : public DialogContainer
|
class Debugger : public DialogContainer
|
||||||
{
|
{
|
||||||
|
@ -105,6 +105,27 @@ class Debugger : public DialogContainer
|
||||||
{
|
{
|
||||||
return (int) strtoimax(h, NULL, 16);
|
return (int) strtoimax(h, NULL, 16);
|
||||||
}
|
}
|
||||||
|
static char *to_bin(int dec, int places, char *buf) {
|
||||||
|
int bit = 1;
|
||||||
|
buf[places] = '\0';
|
||||||
|
while(--places >= 0) {
|
||||||
|
if(dec & bit)
|
||||||
|
buf[places] = '1';
|
||||||
|
else
|
||||||
|
buf[places] = '0';
|
||||||
|
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
static char *to_bin_8(int dec) {
|
||||||
|
static char buf[9];
|
||||||
|
return to_bin(dec, 8, buf);
|
||||||
|
}
|
||||||
|
static char *to_bin_16(int dec) {
|
||||||
|
static char buf[17];
|
||||||
|
return to_bin(dec, 16, buf);
|
||||||
|
}
|
||||||
|
|
||||||
void toggleBreakPoint(int bp);
|
void toggleBreakPoint(int bp);
|
||||||
bool breakPoint(int bp);
|
bool breakPoint(int bp);
|
||||||
|
@ -146,6 +167,12 @@ class Debugger : public DialogContainer
|
||||||
void setS(int sp);
|
void setS(int sp);
|
||||||
void setPC(int pc);
|
void setPC(int pc);
|
||||||
int getPC();
|
int getPC();
|
||||||
|
int getA();
|
||||||
|
int getX();
|
||||||
|
int getY();
|
||||||
|
int getP();
|
||||||
|
int getS();
|
||||||
|
int peek(int addr);
|
||||||
void toggleC();
|
void toggleC();
|
||||||
void toggleZ();
|
void toggleZ();
|
||||||
void toggleN();
|
void toggleN();
|
||||||
|
|
|
@ -13,12 +13,13 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: DebuggerParser.cxx,v 1.12 2005-06-18 15:45:05 urchlay Exp $
|
// $Id: DebuggerParser.cxx,v 1.13 2005-06-18 17:28:18 urchlay Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "Debugger.hxx"
|
#include "Debugger.hxx"
|
||||||
#include "DebuggerParser.hxx"
|
#include "DebuggerParser.hxx"
|
||||||
|
#include "D6502.hxx"
|
||||||
#include "EquateList.hxx"
|
#include "EquateList.hxx"
|
||||||
|
|
||||||
// Constants for argument processing
|
// Constants for argument processing
|
||||||
|
@ -57,31 +58,45 @@ int DebuggerParser::conv_hex_digit(char d) {
|
||||||
else return -1;
|
else return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a string argument that's either a label or a
|
// Given a string argument that's either a label,
|
||||||
// hex value, either dereference the label or convert
|
// hex value, or a register, either dereference the label or convert
|
||||||
// the hex to an int. Returns -1 on error.
|
// the hex to an int. Returns -1 on error.
|
||||||
int DebuggerParser::decipher_arg(string &arg) {
|
int DebuggerParser::decipher_arg(string &arg, bool deref) {
|
||||||
const char *a = arg.c_str();
|
const char *a = arg.c_str();
|
||||||
int address = debugger->equateList->getAddress(a);
|
int address;
|
||||||
// cerr << "decipher_arg: equateList->getAddress(" << a << ") == " << address << endl;
|
|
||||||
if(address >= 0)
|
|
||||||
return address;
|
|
||||||
|
|
||||||
address = 0;
|
// Special cases (registers):
|
||||||
while(*a != '\0') {
|
if(arg == "a") address = debugger->getA();
|
||||||
int hex = conv_hex_digit(*a++);
|
else if(arg == "x") address = debugger->getX();
|
||||||
if(hex < 0)
|
else if(arg == "y") address = debugger->getY();
|
||||||
return -1;
|
else if(arg == "p") address = debugger->getP();
|
||||||
|
else if(arg == "s") address = debugger->getS();
|
||||||
|
else if(arg == "pc") address = debugger->getPC();
|
||||||
|
else { // normal addresses: check for label first
|
||||||
|
address = debugger->equateList->getAddress(a);
|
||||||
|
|
||||||
address = (address << 4) + hex;
|
// if not label, must be hex.
|
||||||
|
if(address < 0) {
|
||||||
|
address = 0;
|
||||||
|
while(*a != '\0') {
|
||||||
|
int hex = conv_hex_digit(*a++);
|
||||||
|
if(hex < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
address = (address << 4) + hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dereference if we're supposed to:
|
||||||
|
if(deref) address = debugger->peek(address);
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggerParser::getArgs(const string& command) {
|
bool DebuggerParser::getArgs(const string& command) {
|
||||||
int state = kIN_COMMAND;
|
int state = kIN_COMMAND;
|
||||||
int deref = 0;
|
bool deref = false;
|
||||||
string curArg = "";
|
string curArg = "";
|
||||||
argCount = 0;
|
argCount = 0;
|
||||||
verb = "";
|
verb = "";
|
||||||
|
@ -112,30 +127,21 @@ bool DebuggerParser::getArgs(const string& command) {
|
||||||
state = kIN_ARG_CONT;
|
state = kIN_ARG_CONT;
|
||||||
// FIXME: actually use this.
|
// FIXME: actually use this.
|
||||||
if(*c == '*') {
|
if(*c == '*') {
|
||||||
deref = 1;
|
deref = true;
|
||||||
c++;
|
c++;
|
||||||
} else {
|
} else {
|
||||||
deref = 0;
|
deref = false;
|
||||||
} // FALL THROUGH!
|
} // FALL THROUGH!
|
||||||
|
|
||||||
case kIN_ARG_CONT:
|
case kIN_ARG_CONT:
|
||||||
/*if(isxdigit(*c)) {
|
|
||||||
int dig = conv_hex_digit(*c);
|
|
||||||
curArg = (curArg << 4) + dig;
|
|
||||||
*c++;
|
|
||||||
} else {
|
|
||||||
args[argCount++] = curArg;
|
|
||||||
state = kIN_SPACE;
|
|
||||||
}
|
|
||||||
break;*/
|
|
||||||
if(isalpha(*c) || isdigit(*c) || *c == '_') {
|
if(isalpha(*c) || isdigit(*c) || *c == '_') {
|
||||||
curArg += *c++;
|
curArg += *c++;
|
||||||
// cerr << "curArg: " << curArg << endl;
|
// cerr << "curArg: " << curArg << endl;
|
||||||
} else {
|
} else {
|
||||||
args[argCount] = decipher_arg(curArg);
|
int a = decipher_arg(curArg, deref);
|
||||||
if(args[argCount] < 0)
|
if(a < 0)
|
||||||
return false;
|
return false;
|
||||||
argCount++;
|
args[argCount++] = a;
|
||||||
curArg = "";
|
curArg = "";
|
||||||
state = kIN_SPACE;
|
state = kIN_SPACE;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +156,7 @@ bool DebuggerParser::getArgs(const string& command) {
|
||||||
|
|
||||||
// pick up last arg, if any:
|
// pick up last arg, if any:
|
||||||
if(state == kIN_ARG_CONT || state == kIN_ARG_START)
|
if(state == kIN_ARG_CONT || state == kIN_ARG_START)
|
||||||
if( (args[argCount++] = decipher_arg(curArg)) < 0)
|
if( (args[argCount++] = decipher_arg(curArg, deref)) < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// for(int i=0; i<argCount; i++)
|
// for(int i=0; i<argCount; i++)
|
||||||
|
@ -205,6 +211,31 @@ string DebuggerParser::disasm() {
|
||||||
return debugger->disassemble(start, lines);
|
return debugger->disassemble(start, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string DebuggerParser::eval() {
|
||||||
|
char buf[10];
|
||||||
|
string ret;
|
||||||
|
for(int i=0; i<argCount; i++) {
|
||||||
|
char *label = debugger->equates()->getLabel(args[i]);
|
||||||
|
if(label != NULL) {
|
||||||
|
ret += label;
|
||||||
|
ret += ": ";
|
||||||
|
}
|
||||||
|
if(args[i] < 0x100) {
|
||||||
|
ret += Debugger::to_hex_8(args[i]);
|
||||||
|
ret += " ";
|
||||||
|
ret += Debugger::to_bin_8(args[i]);
|
||||||
|
} else {
|
||||||
|
ret += Debugger::to_hex_16(args[i]);
|
||||||
|
ret += " ";
|
||||||
|
ret += Debugger::to_bin_16(args[i]);
|
||||||
|
}
|
||||||
|
sprintf(buf, " %d", args[i]);
|
||||||
|
ret += buf;
|
||||||
|
if(i != argCount - 1) ret += "\n";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
string DebuggerParser::run(const string& command) {
|
string DebuggerParser::run(const string& command) {
|
||||||
string result;
|
string result;
|
||||||
|
|
||||||
|
@ -319,15 +350,23 @@ string DebuggerParser::run(const string& command) {
|
||||||
} else if(subStringMatch(verb, "disasm")) {
|
} else if(subStringMatch(verb, "disasm")) {
|
||||||
return disasm();
|
return disasm();
|
||||||
} else if(subStringMatch(verb, "frame")) {
|
} else if(subStringMatch(verb, "frame")) {
|
||||||
|
/*
|
||||||
|
// FIXME: make multiple frames work!
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if(argCount != 0) count = args[0];
|
if(argCount != 0) count = args[0];
|
||||||
// FIXME: make multiple frames work!
|
|
||||||
for(int i=0; i<count; i++)
|
for(int i=0; i<count; i++)
|
||||||
debugger->nextFrame();
|
debugger->nextFrame();
|
||||||
|
*/
|
||||||
|
debugger->nextFrame();
|
||||||
return "OK";
|
return "OK";
|
||||||
} else if(subStringMatch(verb, "clearbreaks")) {
|
} else if(subStringMatch(verb, "clearbreaks")) {
|
||||||
debugger->clearAllBreakPoints();
|
debugger->clearAllBreakPoints();
|
||||||
return "cleared all breakpoints";
|
return "cleared all breakpoints";
|
||||||
|
} else if(subStringMatch(verb, "eval")) {
|
||||||
|
if(argCount < 1)
|
||||||
|
return "one or more arguments required";
|
||||||
|
else
|
||||||
|
return eval();
|
||||||
} else if(subStringMatch(verb, "quit") || subStringMatch(verb, "run")) {
|
} else if(subStringMatch(verb, "quit") || subStringMatch(verb, "run")) {
|
||||||
debugger->quit();
|
debugger->quit();
|
||||||
return "";
|
return "";
|
||||||
|
@ -336,6 +375,8 @@ string DebuggerParser::run(const string& command) {
|
||||||
// easy to sort - bkw
|
// easy to sort - bkw
|
||||||
return
|
return
|
||||||
"Commands are case-insensitive and may be abbreviated.\n"
|
"Commands are case-insensitive and may be abbreviated.\n"
|
||||||
|
"Arguments are either labels or hex constants, and may be\n"
|
||||||
|
"prefixed with a * to dereference.\n"
|
||||||
"a xx - Set Accumulator to xx\n"
|
"a xx - Set Accumulator to xx\n"
|
||||||
"break - Set/clear breakpoint at current PC\n"
|
"break - Set/clear breakpoint at current PC\n"
|
||||||
"break xx - Set/clear breakpoint at address xx\n"
|
"break xx - Set/clear breakpoint at address xx\n"
|
||||||
|
@ -344,19 +385,20 @@ string DebuggerParser::run(const string& command) {
|
||||||
"d - Toggle Decimal Flag\n"
|
"d - Toggle Decimal Flag\n"
|
||||||
"disasm - Disassemble (from current PC)\n"
|
"disasm - Disassemble (from current PC)\n"
|
||||||
"disasm xx - Disassemble (from address xx)\n"
|
"disasm xx - Disassemble (from address xx)\n"
|
||||||
|
"eval xx - Evaluate expression xx\n"
|
||||||
"frame - Advance to next TIA frame, then break\n"
|
"frame - Advance to next TIA frame, then break\n"
|
||||||
"listbreaks - List all breakpoints\n"
|
"listbreaks - List all breakpoints\n"
|
||||||
"loadsym f - Load DASM symbols from file f\n"
|
"loadsym f - Load DASM symbols from file f\n"
|
||||||
"n - Toggle Negative Flag\n"
|
"n - Toggle Negative Flag\n"
|
||||||
"pc xx - Set Program Counter to xx\n"
|
"pc xx - Set Program Counter to xx\n"
|
||||||
"ram - Show RIOT RAM contents\n"
|
"ram - Show RIOT RAM contents\n"
|
||||||
"ram xx yy - Set RAM location xx to value yy (multiple values may be given)\n"
|
"ram xx yy - Set RAM location xx to value yy (multiple values allowed)\n"
|
||||||
"reset - Jump to 6502 init vector (does not reset TIA/RIOT)\n"
|
"reset - Jump to 6502 init vector (does not reset TIA/RIOT)\n"
|
||||||
"run - Exit debugger (back to emulator)\n"
|
"run - Exit debugger (back to emulator)\n"
|
||||||
"s xx - Set Stack Pointer to xx\n"
|
"s xx - Set Stack Pointer to xx\n"
|
||||||
"step - Single-step\n"
|
"step - Single-step\n"
|
||||||
"tia - Show TIA register contents\n"
|
"tia - Show TIA register contents\n"
|
||||||
"trace - Single-step treating subroutine calls as one instruction\n"
|
"trace - Single-step treating subroutine calls as 1 instruction\n"
|
||||||
"v - Toggle Overflow Flag\n"
|
"v - Toggle Overflow Flag\n"
|
||||||
"x xx - Set X register to xx\n"
|
"x xx - Set X register to xx\n"
|
||||||
"y xx - Set Y register to xx\n"
|
"y xx - Set Y register to xx\n"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: DebuggerParser.hxx,v 1.6 2005-06-17 21:59:53 urchlay Exp $
|
// $Id: DebuggerParser.hxx,v 1.7 2005-06-18 17:28:18 urchlay Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#ifndef DEBUGGER_PARSER_HXX
|
#ifndef DEBUGGER_PARSER_HXX
|
||||||
|
@ -38,12 +38,12 @@ class DebuggerParser
|
||||||
private:
|
private:
|
||||||
int DebuggerParser::conv_hex_digit(char d);
|
int DebuggerParser::conv_hex_digit(char d);
|
||||||
bool DebuggerParser::subStringMatch(const string& needle, const string& haystack);
|
bool DebuggerParser::subStringMatch(const string& needle, const string& haystack);
|
||||||
int decipher_arg(string &arg);
|
int decipher_arg(string &arg, bool deref);
|
||||||
string disasm();
|
string disasm();
|
||||||
string listBreaks();
|
string listBreaks();
|
||||||
|
string eval();
|
||||||
|
|
||||||
Debugger* debugger;
|
Debugger* debugger;
|
||||||
EquateList *equateList;
|
|
||||||
|
|
||||||
bool done;
|
bool done;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: EquateList.cxx,v 1.7 2005-06-16 02:16:26 urchlay Exp $
|
// $Id: EquateList.cxx,v 1.8 2005-06-18 17:28:18 urchlay Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -120,7 +120,7 @@ int EquateList::calcSize() {
|
||||||
char *EquateList::getLabel(int addr) {
|
char *EquateList::getLabel(int addr) {
|
||||||
// cerr << "getLabel(" << addr << ")" << endl;
|
// cerr << "getLabel(" << addr << ")" << endl;
|
||||||
for(int i=0; ourVcsEquates[i].label != NULL; i++) {
|
for(int i=0; ourVcsEquates[i].label != NULL; i++) {
|
||||||
// cerr << "Checking ourVcsEquates[" << i << "] (" << ourVcsEquates[i].label << endl;
|
// cerr << "Checking ourVcsEquates[" << i << "] (" << ourVcsEquates[i].label << ")" << endl;
|
||||||
if(ourVcsEquates[i].address == addr) {
|
if(ourVcsEquates[i].address == addr) {
|
||||||
// cerr << "Found label " << ourVcsEquates[i].label << endl;
|
// cerr << "Found label " << ourVcsEquates[i].label << endl;
|
||||||
return ourVcsEquates[i].label;
|
return ourVcsEquates[i].label;
|
||||||
|
|
Loading…
Reference in New Issue