1
//============================================================================
5
// SS tttttt eeee ll ll aaaa
6
// SSSS tt ee ee ll ll aa
7
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8
// SS SS tt ee ll ll aa aa
9
// SSSS ttt eeeee llll llll aaaaa
11
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
13
// See the file "license" for information on usage and redistribution of
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16
// $Id: DebuggerParser.cxx,v 1.89 2005/12/19 02:19:48 stephena Exp $
17
//============================================================================
24
#include "Debugger.hxx"
25
#include "CpuDebug.hxx"
26
#include "DebuggerParser.hxx"
27
#include "YaccParser.hxx"
29
#include "Expression.hxx"
30
#include "RomWidget.hxx"
32
#ifdef CHEATCODE_SUPPORT
33
#include "CheatManager.hxx"
36
#include "DebuggerParser.hxx"
38
Command DebuggerParser::commands[] = {
41
"Set Accumulator to value xx",
44
{ kARG_WORD, kARG_END_ARGS },
45
&DebuggerParser::executeA
50
"Show # of banks (with no args), Switch to bank (with 1 arg)",
53
{ kARG_WORD, kARG_END_ARGS },
54
&DebuggerParser::executeBank
59
"Set default base (hex, dec, or bin)",
62
{ kARG_BASE_SPCL, kARG_END_ARGS },
63
&DebuggerParser::executeBase
68
"Set/clear breakpoint at address (default: current pc)",
71
{ kARG_WORD, kARG_END_ARGS },
72
&DebuggerParser::executeBreak
77
"Set breakpoint on condition",
80
{ kARG_WORD, kARG_END_ARGS },
81
&DebuggerParser::executeBreakif
86
"Carry Flag: set (to 0 or 1), or toggle (no arg)",
89
{ kARG_BOOL, kARG_END_ARGS },
90
&DebuggerParser::executeC
93
#ifdef CHEATCODE_SUPPORT
96
"Use a cheat code (see Stella manual for cheat types)",
99
{ kARG_LABEL, kARG_END_ARGS },
100
&DebuggerParser::executeCheat
106
"Clear all breakpoints",
110
&DebuggerParser::executeClearbreaks
119
&DebuggerParser::executeCleartraps
128
&DebuggerParser::executeClearwatches
136
{ kARG_WORD, kARG_END_ARGS },
137
&DebuggerParser::executeColortest
142
"Decimal Flag: set (to 0 or 1), or toggle (no arg)",
145
{ kARG_BOOL, kARG_END_ARGS },
146
&DebuggerParser::executeD
154
{ kARG_LABEL, kARG_WORD, kARG_END_ARGS },
155
&DebuggerParser::executeDefine
160
"Delete conditional break created with breakif",
163
{ kARG_WORD, kARG_END_ARGS },
164
&DebuggerParser::executeDelbreakif
172
{ kARG_WORD, kARG_END_ARGS },
173
&DebuggerParser::executeDelwatch
178
"Disassemble from address (default=pc)",
181
{ kARG_WORD, kARG_END_ARGS },
182
&DebuggerParser::executeDisasm
187
"Dump 128 bytes of memory at address",
190
{ kARG_WORD, kARG_END_ARGS },
191
&DebuggerParser::executeDump
196
"Execute script file",
199
{ kARG_FILE, kARG_END_ARGS },
200
&DebuggerParser::executeExec
205
"Advance emulation by xx frames (default=1)",
208
{ kARG_WORD, kARG_END_ARGS },
209
&DebuggerParser::executeFrame
214
"Define expression as a function for later use",
217
{ kARG_LABEL, kARG_WORD, kARG_END_ARGS },
218
&DebuggerParser::executeFunction
223
"Change height of debugger window",
226
{ kARG_WORD, kARG_END_ARGS },
227
&DebuggerParser::executeHeight
236
&DebuggerParser::executeHelp
241
"List source (if loaded with loadlst)",
244
{ kARG_WORD, kARG_END_ARGS },
245
&DebuggerParser::executeList
254
&DebuggerParser::executeListbreaks
263
&DebuggerParser::executeListtraps
272
&DebuggerParser::executeListwatches
277
"Load emulator state (0-9)",
280
{ kARG_WORD, kARG_END_ARGS },
281
&DebuggerParser::executeLoadstate
286
"Load DASM listing file",
289
{ kARG_FILE, kARG_END_ARGS },
290
&DebuggerParser::executeLoadlist
298
{ kARG_FILE, kARG_END_ARGS },
299
&DebuggerParser::executeLoadsym
304
"Negative Flag: set (to 0 or 1), or toggle (no arg)",
307
{ kARG_BOOL, kARG_END_ARGS },
308
&DebuggerParser::executeN
313
"Set Program Counter to address",
316
{ kARG_WORD, kARG_END_ARGS },
317
&DebuggerParser::executePc
322
"Set address to value. Can give multiple values (for address+1, etc)",
325
{ kARG_WORD, kARG_MULTI_BYTE },
326
&DebuggerParser::executeRam
331
"Evaluate and print expression in hex/dec/binary",
334
{ kARG_WORD, kARG_END_ARGS },
335
&DebuggerParser::executePrint
340
"Show RAM contents (no args), or set address xx to value yy",
343
{ kARG_WORD, kARG_MULTI_BYTE },
344
&DebuggerParser::executeRam
349
"Reload ROM and symbol file",
353
&DebuggerParser::executeReload
358
"Reset 6507 to init vector (does not reset TIA, RIOT)",
362
&DebuggerParser::executeReset
367
"Show RIOT timer/input status",
371
&DebuggerParser::executeRiot
376
"Change ROM contents",
379
{ kARG_WORD, kARG_MULTI_BYTE },
380
&DebuggerParser::executeRom
385
"Exit debugger, return to emulator",
389
&DebuggerParser::executeRun
394
"Run until first occurrence of string in disassembly",
397
{ kARG_LABEL, kARG_END_ARGS },
398
&DebuggerParser::executeRunTo
403
"Set Stack Pointer to value xx",
406
{ kARG_WORD, kARG_END_ARGS },
407
&DebuggerParser::executeS
412
"Save breaks, watches, traps as a .stella script file",
415
{ kARG_FILE, kARG_END_ARGS },
416
&DebuggerParser::executeSave
421
"Save (possibly patched) ROM to file",
424
{ kARG_FILE, kARG_END_ARGS },
425
&DebuggerParser::executeSaverom
430
"Save console session to file",
433
{ kARG_FILE, kARG_END_ARGS },
434
&DebuggerParser::executeSaveses
439
"Save emulator state (valid args 0-9)",
442
{ kARG_WORD, kARG_END_ARGS },
443
&DebuggerParser::executeSavestate
448
"Save symbols to file",
451
{ kARG_FILE, kARG_END_ARGS },
452
&DebuggerParser::executeSavesym
457
"Advance emulation by xx scanlines (default=1)",
460
{ kARG_WORD, kARG_END_ARGS },
461
&DebuggerParser::executeScanline
466
"Single step CPU (optionally, with count)",
469
{ kARG_WORD, kARG_END_ARGS },
470
&DebuggerParser::executeStep
475
"Show TIA state (NOT FINISHED YET)",
479
&DebuggerParser::executeTia
484
"Single step CPU (optionally, with count), subroutines count as one instruction",
487
{ kARG_WORD, kARG_END_ARGS },
488
&DebuggerParser::executeTrace
493
"Trap read and write accesses to address",
496
{ kARG_WORD, kARG_END_ARGS },
497
&DebuggerParser::executeTrap
502
"Trap read accesses to address",
505
{ kARG_WORD, kARG_END_ARGS },
506
&DebuggerParser::executeTrapread
511
"Trap write accesses to address",
514
{ kARG_WORD, kARG_END_ARGS },
515
&DebuggerParser::executeTrapwrite
520
"Undefine label (if defined)",
523
{ kARG_LABEL, kARG_END_ARGS },
524
&DebuggerParser::executeUndef
529
"Overflow Flag: set (to 0 or 1), or toggle (no arg)",
532
{ kARG_BOOL, kARG_END_ARGS },
533
&DebuggerParser::executeV
538
"Print contents of address before every prompt",
541
{ kARG_WORD, kARG_END_ARGS },
542
&DebuggerParser::executeWatch
547
"Set X Register to value xx",
550
{ kARG_WORD, kARG_END_ARGS },
551
&DebuggerParser::executeX
556
"Set Y Register to value xx",
559
{ kARG_WORD, kARG_END_ARGS },
560
&DebuggerParser::executeY
565
"Zero Flag: set (to 0 or 1), or toggle (no arg)",
568
{ kARG_BOOL, kARG_END_ARGS },
569
&DebuggerParser::executeZ
583
// Constants for argument processing
591
DebuggerParser::DebuggerParser(Debugger* d)
595
defaultBase = kBASE_16;
598
DebuggerParser::~DebuggerParser() {
604
int DebuggerParser::conv_hex_digit(char d) {
605
if(d >= '0' && d <= '9')
607
else if(d >= 'a' && d <= 'f')
609
else if(d >= 'A' && d <= 'F')
614
// Evaluate expression. Expressions always evaluate to a 16-bit value if
615
// they're valid, or -1 if they're not.
617
// decipher_arg may be called by the GUI as needed. It is also called
618
// internally by DebuggerParser::run()
619
int DebuggerParser::decipher_arg(const string &str) {
620
bool derefByte=false, derefWord=false, lobyte=false, hibyte=false, bin=false, dec=false;
624
if(defaultBase == kBASE_2) {
626
} else if(defaultBase == kBASE_10) {
629
bin=false; dec=false;
632
if(arg.substr(0, 1) == "*") {
635
} else if(arg.substr(0, 1) == "@") {
640
if(arg.substr(0, 1) == "<") {
643
} else if(arg.substr(0, 1) == ">") {
648
if(arg.substr(0, 1) == "%") {
652
} else if(arg.substr(0, 1) == "#") {
656
} else if(arg.substr(0, 1) == "$") {
662
// sanity check mutually exclusive options:
663
if(derefByte && derefWord) return -1;
664
if(lobyte && hibyte) return -1;
665
if(bin && dec) return -1;
667
// Special cases (registers):
668
CpuState& state = (CpuState&) debugger->cpuDebug().getState();
669
if(arg == "a") result = state.A;
670
else if(arg == "x") result = state.X;
671
else if(arg == "y") result = state.Y;
672
else if(arg == "p") result = state.PS;
673
else if(arg == "s") result = state.SP;
674
else if(arg == "pc" || arg == ".") result = state.PC;
675
else { // Not a special, must be a regular arg: check for label first
676
const char *a = arg.c_str();
677
result = debugger->equateList->getAddress(arg);
679
if(result < 0) { // if not label, must be a number
680
if(bin) { // treat as binary
699
int digit = (*a++) - '0';
700
if(digit < 0 || digit > 9)
703
result = (result * 10) + digit;
705
} else { // must be hex.
708
int hex = conv_hex_digit(*a++);
712
result = (result << 4) + hex;
718
if(lobyte) result &= 0xff;
719
else if(hibyte) result = (result >> 8) & 0xff;
721
// dereference if we're supposed to:
722
if(derefByte) result = debugger->peek(result);
723
if(derefWord) result = debugger->dpeek(result);
728
bool DebuggerParser::getArgs(const string& command) {
729
int state = kIN_COMMAND;
732
const char *c = command.c_str();
737
// cerr << "Parsing \"" << command << "\"" << endl;
739
// First, pick apart string into space-separated tokens.
740
// The first token is the command verb, the rest go in an array
742
// cerr << "State " << state << ", *c '" << *c << "'" << endl;
761
if(*c == '}' || *c == '\0') {
763
argStrings.push_back(curArg);
764
// cerr << "{" << curArg << "}" << endl;
772
if(*c == ' ' || *c == '\0') {
774
argStrings.push_back(curArg);
781
} while(*c++ != '\0');
783
argCount = argStrings.size();
786
// Now decipher each argument, in turn.
787
for(int i=0; i<argCount; i++) {
788
int temp = decipher_arg(argStrings[i]);
789
args.push_back(temp); // value maybe -1, if not expression argument
790
// (validate_args will decide whether that's OK, not us.)
794
for(int i=0; i<argCount; i++) {
795
int err = YaccParser::parse(argStrings[i].c_str());
799
Expression *e = YaccParser::getResult();
800
args.push_back( e->evaluate() );
808
bool DebuggerParser::subStringMatch(const string& needle, const string& haystack) {
809
const char *hs = haystack.c_str();
810
const char *n = needle.c_str();
812
if(STR_N_CASE_CMP(n, hs, strlen(n)) == 0)
818
string DebuggerParser::listBreaks() {
823
for(unsigned int i=0; i<0x10000; i++) {
824
if(debugger->breakPoints->isSet(i)) {
825
sprintf(buf, "%s ", debugger->equateList->getFormatted(i, 4));
827
if(! (++count % 8) ) ret += "\n";
834
return "no breakpoints set";
837
ret = "breaks:\n" + ret;
839
StringList conds = debugger->cpuDebug().m6502().getCondBreakNames();
840
if(conds.size() > 0) {
841
ret += "\nbreakifs:\n";
842
for(unsigned int i=0; i<conds.size(); i++) {
843
ret += debugger->valueToString(i);
846
if(i != (conds.size() - 1)) ret += "\n";
851
return "no breakpoints set";
856
string DebuggerParser::listTraps() {
860
for(unsigned int i=0; i<0x10000; i++) {
861
if(debugger->readTrap(i) || debugger->writeTrap(i)) {
862
ret += trapStatus(i);
871
return "no traps set";
874
string DebuggerParser::disasm() {
875
int start, lines = 20;
878
start = debugger->cpuDebug().pc();
879
} else if(argCount == 1) {
881
} else if(argCount == 2) {
885
return "wrong number of arguments";
888
return debugger->disassemble(start, lines);
891
string DebuggerParser::dump() {
893
for(int i=0; i<8; i++) {
894
int start = args[0] + i*16;
895
ret += debugger->valueToString(start);
897
for(int j=0; j<16; j++) {
898
ret += debugger->valueToString( debugger->peek(start+j) );
900
if(j == 7) ret += "- ";
902
if(i != 7) ret += "\n";
907
string DebuggerParser::eval() {
910
for(int i=0; i<argCount; i++) {
911
string label = debugger->equates()->getLabel(args[i]);
917
if(args[i] < 0x100) {
918
ret += Debugger::to_hex_8(args[i]);
920
ret += Debugger::to_bin_8(args[i]);
922
ret += Debugger::to_hex_16(args[i]);
924
ret += Debugger::to_bin_16(args[i]);
926
sprintf(buf, " #%d", args[i]);
928
if(i != argCount - 1) ret += "\n";
933
string DebuggerParser::showWatches() {
937
for(unsigned int i=0; i<watches.size(); i++) {
938
if(watches[i] != "") {
939
// Clear the args, since we're going to pass them to eval()
943
sprintf(buf, "%d", i+1);
945
argStrings.push_back(watches[i]);
946
args.push_back(decipher_arg(argStrings[0]));
950
ret += ": " + argStrings[0] + "\n";
954
ret += " (" + argStrings[0] + ") -> " + eval() + "\n";
961
string DebuggerParser::addWatch(string watch) {
962
watches.push_back(watch);
963
return "Added watch";
966
void DebuggerParser::delAllWatches() {
970
string DebuggerParser::delWatch(int which) {
972
if(which < 0 || which >= (int)watches.size())
973
return "no such watch";
975
watches.remove_at(which);
977
return "removed watch";
980
string DebuggerParser::trapStatus(int addr) {
982
result += debugger->valueToString(addr);
984
bool r = debugger->readTrap(addr);
985
bool w = debugger->writeTrap(addr);
987
result += "read|write";
995
string l = debugger->equateList->getLabel(addr);
1005
bool DebuggerParser::validateArgs(int cmd)
1007
// cerr << "entering validateArgs(" << cmd << ")" << endl;
1008
bool required = commands[cmd].parmsRequired;
1009
parameters *p = commands[cmd].parms;
1015
commandResult = red("missing required argument(s)");
1016
return false; // needed args. didn't get 'em.
1019
return true; // no args needed, no args got
1022
// Figure out how many arguments are required by the command
1023
int count = 0, argRequiredCount = 0;
1024
while(*p != kARG_END_ARGS && *p != kARG_MULTI_BYTE)
1030
// Evil hack: some commands intentionally take multiple arguments
1031
// In this case, the required number of arguments is unbounded
1032
argRequiredCount = (*p == kARG_END_ARGS) ? count : argCount;
1034
p = commands[cmd].parms;
1038
if(curCount >= argCount)
1041
int curArgInt = args[curCount];
1042
string& curArgStr = argStrings[curCount];
1047
if(curArgInt < 0 || curArgInt > 0xffff)
1049
commandResult = red("invalid word argument (must be 0-$ffff)");
1055
if(curArgInt < 0 || curArgInt > 0xff)
1057
commandResult = red("invalid byte argument (must be 0-$ff)");
1063
if(curArgInt != 0 && curArgInt != 1)
1065
commandResult = red("invalid boolean argument (must be 0 or 1)");
1070
case kARG_BASE_SPCL:
1071
if(curArgInt != 2 && curArgInt != 10 && curArgInt != 16
1072
&& curArgStr != "hex" && curArgStr != "dec" && curArgStr != "bin")
1074
commandResult = red("invalid base (must be #2, #10, #16, \"bin\", \"dec\", or \"hex\")");
1081
break; // TODO: validate these (for now any string's allowed)
1083
case kARG_MULTI_BYTE:
1084
case kARG_MULTI_WORD:
1085
break; // FIXME: validate these (for now, any number's allowed)
1093
} while(*p != kARG_END_ARGS && curCount < argRequiredCount);
1096
cerr << "curCount = " << curCount << endl
1097
<< "argRequiredCount = " << argRequiredCount << endl
1098
<< "*p = " << *p << endl << endl;
1101
if(curCount < argRequiredCount)
1103
commandResult = red("missing required argument(s)");
1106
else if(argCount > curCount)
1108
commandResult = red("too many arguments");
1115
// main entry point: PromptWidget calls this method.
1116
string DebuggerParser::run(const string& command) {
1119
// this was our parser test code. Left for reference.
1120
static Expression *lastExpression;
1122
// special case: parser testing
1123
if(strncmp(command.c_str(), "expr ", 5) == 0) {
1124
delete lastExpression;
1125
commandResult = "parser test: status==";
1126
int status = YaccParser::parse(command.c_str() + 5);
1127
commandResult += debugger->valueToString(status);
1128
commandResult += ", result==";
1130
lastExpression = YaccParser::getResult();
1131
commandResult += debugger->valueToString(lastExpression->evaluate());
1133
// delete lastExpression; // NO! lastExpression isn't valid (not 0 either)
1134
// It's the result of casting the last token
1135
// to Expression* (because of yacc's union).
1136
// As such, we can't and don't need to delete it
1137
// (However, it means yacc leaks memory on error)
1138
commandResult += "ERROR - ";
1139
commandResult += YaccParser::errorMessage();
1141
return commandResult;
1144
if(command == "expr") {
1146
commandResult = "result==" + debugger->valueToString(lastExpression->evaluate());
1148
commandResult = "no valid expr";
1149
return commandResult;
1154
#ifdef EXPR_REF_COUNT
1155
extern int refCount;
1156
cerr << "Expression count: " << refCount << endl;
1162
if( subStringMatch(verb, commands[i].cmdString.c_str()) ) {
1163
if( validateArgs(i) )
1164
CALL_METHOD(commands[i].executor);
1166
if( commands[i].refreshRequired )
1167
debugger->myBaseDialog->loadConfig();
1169
return commandResult;
1172
} while(commands[++i].cmdString != "");
1174
commandResult = "No such command (try \"help\")";
1175
return commandResult;
1178
// completion-related stuff:
1179
int DebuggerParser::countCompletions(const char *in) {
1180
int count = 0, i = 0;
1181
completions = compPrefix = "";
1183
// cerr << "Attempting to complete \"" << in << "\"" << endl;
1185
const char *l = commands[i].cmdString.c_str();
1187
if(STR_N_CASE_CMP(l, in, strlen(in)) == 0) {
1188
if(compPrefix == "")
1192
const char *c = compPrefix.c_str();
1193
while(*c != '\0' && tolower(*c) == tolower(l[nonMatch])) {
1197
compPrefix.erase(nonMatch, compPrefix.length());
1198
// cerr << "compPrefix==" << compPrefix << endl;
1201
if(count++) completions += " ";
1204
} while(commands[++i].cmdString != "");
1206
// cerr << "Found " << count << " label(s):" << endl << completions << endl;
1210
const char *DebuggerParser::getCompletions() {
1211
return completions.c_str();
1214
const char *DebuggerParser::getCompletionPrefix() {
1215
return compPrefix.c_str();
1218
string DebuggerParser::exec(const string& cmd, bool verbose) {
1222
char buffer[256]; // FIXME: static buffers suck
1224
if( file.find_last_of('.') == string::npos ) {
1228
ifstream in(file.c_str());
1230
return red("file \"" + file + "\" not found.");
1232
while( !in.eof() ) {
1233
if(!in.getline(buffer, 255))
1246
ret += debugger->valueToString(count);
1247
ret += " commands from \"";
1253
bool DebuggerParser::saveScriptFile(string file) {
1254
if( file.find_last_of('.') == string::npos ) {
1258
ofstream out(file.c_str());
1260
FunctionDefMap funcs = debugger->getFunctionDefMap();
1261
for(FunctionDefMap::const_iterator i = funcs.begin(); i != funcs.end(); ++i)
1262
out << "function " << i->first << " { " << i->second << " }" << endl;
1264
for(unsigned int i=0; i<watches.size(); i++)
1265
out << "watch " << watches[i] << endl;
1267
for(unsigned int i=0; i<0x10000; i++)
1268
if(debugger->breakPoint(i))
1269
out << "break #" << i << endl;
1271
for(unsigned int i=0; i<0x10000; i++) {
1272
bool r = debugger->readTrap(i);
1273
bool w = debugger->writeTrap(i);
1276
out << "trap #" << i << endl;
1278
out << "trapread #" << i << endl;
1280
out << "trapwrite #" << i << endl;
1283
StringList conds = debugger->cpuDebug().m6502().getCondBreakNames();
1284
for(unsigned int i=0; i<conds.size(); i++)
1285
out << "breakif {" << conds[i] << "}" << endl;
1287
bool ok = out.good();
1292
////// executor methods for commands[] array. All are void, no args.
1295
void DebuggerParser::executeA() {
1296
debugger->cpuDebug().setA((uInt8)args[0]);
1300
void DebuggerParser::executeBank() {
1301
int banks = debugger->bankCount();
1303
commandResult += debugger->getCartType();
1304
commandResult += ": ";
1306
commandResult += red("bankswitching not supported by this cartridge");
1308
commandResult += debugger->valueToString(debugger->getBank());
1309
commandResult += "/";
1310
commandResult += debugger->valueToString(banks);
1313
if(args[0] >= banks) {
1314
commandResult += red("invalid bank number (must be 0 to ");
1315
commandResult += debugger->valueToString(banks - 1);
1316
commandResult += ")";
1317
} else if(debugger->setBank(args[0])) {
1318
commandResult += "switched bank OK";
1320
commandResult += red("unknown error switching banks");
1326
void DebuggerParser::executeBase() {
1327
if(args[0] == 2 || argStrings[0] == "bin")
1329
else if(args[0] == 10 || argStrings[0] == "dec")
1331
else if(args[0] == 16 || argStrings[0] == "hex")
1334
commandResult = "default base set to ";
1335
switch(defaultBase) {
1337
commandResult += "#2/bin";
1341
commandResult += "#10/dec";
1345
commandResult += "#16/hex";
1349
commandResult += red("UNKNOWN");
1355
void DebuggerParser::executeBreak() {
1358
bp = debugger->cpuDebug().pc();
1361
debugger->toggleBreakPoint(bp);
1362
debugger->myRom->invalidate();
1364
if(debugger->breakPoint(bp))
1365
commandResult = "Set";
1367
commandResult = "Cleared";
1369
commandResult += " breakpoint at ";
1370
commandResult += debugger->valueToString(bp);
1374
void DebuggerParser::executeBreakif() {
1375
int res = YaccParser::parse(argStrings[0].c_str());
1377
// I hate this().method().chaining().crap()
1378
unsigned int ret = debugger->cpuDebug().m6502().addCondBreak(
1379
YaccParser::getResult(), argStrings[0] );
1380
commandResult = "Added breakif ";
1381
commandResult += debugger->valueToString(ret);
1383
commandResult = red("invalid expression");
1388
void DebuggerParser::executeC() {
1390
debugger->cpuDebug().toggleC();
1391
else if(argCount == 1)
1392
debugger->cpuDebug().setC(args[0]);
1395
#ifdef CHEATCODE_SUPPORT
1397
// (see Stella manual for different cheat types)
1398
void DebuggerParser::executeCheat() {
1400
commandResult = red("Missing cheat code");
1404
for(int arg = 0; arg < argCount; arg++) {
1405
string& cheat = argStrings[arg];
1406
const Cheat* c = debugger->getOSystem()->cheat().add("DBG", cheat);
1407
if(c && c->enabled()) {
1408
commandResult = "Cheat code " + cheat + " enabled\n";
1410
commandResult = red("Invalid cheat code " + cheat + "\n");
1417
void DebuggerParser::executeClearbreaks() {
1418
debugger->clearAllBreakPoints();
1419
debugger->cpuDebug().m6502().clearCondBreaks();
1420
commandResult = "all breakpoints cleared";
1424
void DebuggerParser::executeCleartraps() {
1425
debugger->clearAllTraps();
1426
commandResult = "all traps cleared";
1430
void DebuggerParser::executeClearwatches() {
1432
commandResult = "all watches cleared";
1436
void DebuggerParser::executeColortest() {
1437
commandResult = "test color: ";
1438
commandResult += char((args[0]>>1) | 0x80);
1439
commandResult += inverse(" ");
1443
void DebuggerParser::executeD() {
1445
debugger->cpuDebug().toggleD();
1446
else if(argCount == 1)
1447
debugger->cpuDebug().setD(args[0]);
1451
void DebuggerParser::executeDefine() {
1452
// TODO: check if label already defined?
1453
debugger->addLabel(argStrings[0], args[1]);
1454
debugger->myRom->invalidate();
1455
commandResult = "label " + argStrings[0] + " defined as " + debugger->valueToString(args[1]);
1459
void DebuggerParser::executeDelbreakif() {
1460
debugger->cpuDebug().m6502().delCondBreak(args[0]);
1464
void DebuggerParser::executeDelwatch() {
1465
commandResult = delWatch(args[0]);
1469
void DebuggerParser::executeDisasm() {
1470
commandResult = disasm();
1474
void DebuggerParser::executeDump() {
1475
commandResult = dump();
1479
void DebuggerParser::executeExec() {
1480
commandResult = exec(argStrings[0]);
1484
void DebuggerParser::executeHeight() {
1485
int height = debugger->setHeight(args[0]);
1486
commandResult = "height set to " + debugger->valueToString(height, kBASE_10) +
1487
"\nExit debugger and reload ROM to take effect";
1491
void DebuggerParser::executeHelp() {
1492
static char buf[256];
1495
sprintf(buf, "%13s - %s\n",
1496
commands[i].cmdString.c_str(),
1497
commands[i].description.c_str());
1499
commandResult += buf;
1500
} while(commands[++i].cmdString != "");
1502
commandResult += "\nBuilt-in functions:\n";
1503
commandResult += debugger->builtinHelp();
1507
void DebuggerParser::executeFrame() {
1509
if(argCount != 0) count = args[0];
1510
debugger->nextFrame(count);
1511
commandResult = "advanced ";
1512
commandResult += debugger->valueToString(count);
1513
commandResult += " frame";
1514
if(count != 1) commandResult += "s";
1518
void DebuggerParser::executeFunction() {
1520
commandResult = red("name already in use");
1524
int res = YaccParser::parse(argStrings[1].c_str());
1526
debugger->addFunction(argStrings[0], argStrings[1], YaccParser::getResult());
1527
commandResult = "Added function " + argStrings[0];
1529
commandResult = red("invalid expression");
1534
void DebuggerParser::executeList() {
1535
for(int i=args[0] - 2; i<args[0] + 3; i++)
1536
commandResult += debugger->getSourceLines(i);
1540
void DebuggerParser::executeListbreaks() {
1541
commandResult = listBreaks();
1545
void DebuggerParser::executeListtraps() {
1546
commandResult = listTraps();
1550
void DebuggerParser::executeListwatches() {
1551
// commandResult = listWatches();
1552
commandResult = red("command not yet implemented (sorry)");
1556
void DebuggerParser::executeLoadstate() {
1557
if(args[0] >= 0 && args[0] <= 9) {
1558
debugger->loadState(args[0]);
1559
commandResult = "state loaded";
1561
commandResult = red("invalid slot (must be 0-9)");
1566
void DebuggerParser::executeLoadlist() {
1567
commandResult = debugger->loadListFile(argStrings[0]);
1571
void DebuggerParser::executeLoadsym() {
1572
commandResult = debugger->equateList->loadFile(argStrings[0]);
1573
debugger->myRom->invalidate();
1577
void DebuggerParser::executeN() {
1579
debugger->cpuDebug().toggleN();
1580
else if(argCount == 1)
1581
debugger->cpuDebug().setN(args[0]);
1585
void DebuggerParser::executePc() {
1586
debugger->cpuDebug().setPC(args[0]);
1590
void DebuggerParser::executePrint() {
1591
commandResult = eval();
1595
void DebuggerParser::executeRam() {
1597
commandResult = debugger->dumpRAM();
1599
commandResult = debugger->setRAM(args);
1603
void DebuggerParser::executeReload() {
1604
debugger->reloadROM();
1606
commandResult = "reloaded";
1610
void DebuggerParser::executeReset() {
1612
commandResult = "reset CPU";
1616
void DebuggerParser::executeRiot() {
1617
commandResult = debugger->riotState();
1621
void DebuggerParser::executeRom() {
1623
for(int i=1; i<argCount; i++) {
1624
if( !(debugger->patchROM(addr++, args[i])) ) {
1625
commandResult = red("patching ROM unsupported for this cart type");
1630
// Normally the run() method calls loadConfig() on the debugger,
1631
// which results in all child widgets being redrawn.
1632
// The RomWidget is a special case, since we don't want to re-disassemble
1633
// any more than necessary. So we only do it by calling the following
1635
debugger->myRom->invalidate();
1637
commandResult = "changed ";
1638
commandResult += debugger->valueToString( args.size() - 1 );
1639
commandResult += " location(s)";
1643
void DebuggerParser::executeRun() {
1644
debugger->saveOldState();
1646
commandResult = "exiting debugger";
1650
void DebuggerParser::executeRunTo() {
1652
int cycles = 0, count = 0;
1655
cycles += debugger->step();
1656
if(++count % 100 == 0)
1657
debugger->prompt()->putchar('.');
1658
string next = debugger->disassemble(debugger->cpuDebug().pc(), 1);
1659
done = (next.find(argStrings[0]) != string::npos);
1662
commandResult = "executed ";
1663
commandResult += debugger->valueToString(cycles);
1664
commandResult += " cycles";
1668
void DebuggerParser::executeS() {
1669
debugger->cpuDebug().setSP((uInt8)args[0]);
1673
void DebuggerParser::executeSave() {
1674
if(saveScriptFile(argStrings[0]))
1675
commandResult = "saved script to file " + argStrings[0];
1677
commandResult = red("I/O error");
1681
void DebuggerParser::executeSaverom() {
1682
if(debugger->saveROM(argStrings[0]))
1683
commandResult = "saved ROM as " + argStrings[0];
1685
commandResult = red("failed to save ROM");
1689
void DebuggerParser::executeSaveses() {
1690
if(debugger->prompt()->saveBuffer(argStrings[0]))
1691
commandResult = "saved session to file " + argStrings[0];
1693
commandResult = red("I/O error");
1697
void DebuggerParser::executeSavestate() {
1698
if(args[0] >= 0 && args[0] <= 9) {
1699
debugger->saveState(args[0]);
1700
commandResult = "state saved";
1702
commandResult = red("invalid slot (must be 0-9)");
1707
void DebuggerParser::executeSavesym() {
1708
if(debugger->equateList->saveFile(argStrings[0]))
1709
commandResult = "saved symbols to file " + argStrings[0];
1711
commandResult = red("I/O error");
1715
void DebuggerParser::executeScanline() {
1717
if(argCount != 0) count = args[0];
1718
debugger->nextScanline(count);
1719
commandResult = "advanced ";
1720
commandResult += debugger->valueToString(count);
1721
commandResult += " scanline";
1722
if(count != 1) commandResult += "s";
1726
void DebuggerParser::executeStep() {
1727
int cycles = debugger->step();
1728
commandResult = "executed ";
1729
commandResult += debugger->valueToString(cycles);
1730
commandResult += " cycles";
1734
void DebuggerParser::executeTia() {
1735
commandResult = debugger->dumpTIA();
1739
void DebuggerParser::executeTrace() {
1740
int cycles = debugger->trace();
1741
commandResult = "executed ";
1742
commandResult += debugger->valueToString(cycles);
1743
commandResult += " cycles";
1747
void DebuggerParser::executeTrap() {
1748
debugger->toggleReadTrap(args[0]);
1749
debugger->toggleWriteTrap(args[0]);
1750
commandResult = trapStatus(args[0]);
1754
void DebuggerParser::executeTrapread() {
1755
debugger->toggleReadTrap(args[0]);
1756
commandResult = trapStatus(args[0]);
1760
void DebuggerParser::executeTrapwrite() {
1761
debugger->toggleWriteTrap(args[0]);
1762
commandResult = trapStatus(args[0]);
1766
void DebuggerParser::executeUndef() {
1767
if(debugger->equateList->undefine(argStrings[0]))
1769
debugger->myRom->invalidate();
1770
commandResult = argStrings[0] + " now undefined";
1773
commandResult = red("no such label");
1777
void DebuggerParser::executeV() {
1779
debugger->cpuDebug().toggleV();
1780
else if(argCount == 1)
1781
debugger->cpuDebug().setV(args[0]);
1785
void DebuggerParser::executeWatch() {
1786
addWatch(argStrings[0]);
1787
commandResult = "added watch \"" + argStrings[0] + "\"";
1791
void DebuggerParser::executeX() {
1792
debugger->cpuDebug().setX((uInt8)args[0]);
1796
void DebuggerParser::executeY() {
1797
debugger->cpuDebug().setY((uInt8)args[0]);
1801
void DebuggerParser::executeZ() {
1803
debugger->cpuDebug().toggleZ();
1804
else if(argCount == 1)
1805
debugger->cpuDebug().setZ(args[0]);