Debugger: Add unary operators and memory dereferencing

This commit is contained in:
Vicki Pfau 2019-03-04 18:27:13 -08:00
parent f5ddeb3611
commit c3ec7311e8
5 changed files with 83 additions and 9 deletions

View File

@ -3,6 +3,7 @@ Features:
- Improved logging configuration
- One-Player BattleChip/Progress/Beast Link Gate support
- Add Game Boy Color palettes for original Game Boy games
- Debugger: Add unary operators and memory dereferencing
Emulation fixes:
- GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208)
- GBA: Reset now reloads multiboot ROMs

View File

@ -38,6 +38,7 @@ enum Operation {
OP_NOT,
OP_SHIFT_L,
OP_SHIFT_R,
OP_DEREFERENCE,
};
struct Token {

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/debugger/parser.h>
#include <mgba/core/core.h>
#include <mgba/debugger/debugger.h>
#include <mgba-util/string.h>
@ -89,6 +90,29 @@ static void _lexOperator(struct LexVector* lv, char operator, enum LexState* sta
break;
}
*state = LEX_ERROR;
}
if (*state == LEX_ROOT || *state == LEX_ERROR) {
struct Token* lvNext = LexVectorAppend(lv);
lvNext->type = TOKEN_OPERATOR_TYPE;
*state = LEX_ROOT;
switch (operator) {
case '-':
lvNext->operatorValue = OP_NEGATE;
break;
case '~':
lvNext->operatorValue = OP_FLIP;
break;
case '!':
lvNext->operatorValue = OP_NOT;
break;
case '*':
lvNext->operatorValue = OP_DEREFERENCE;
break;
default:
lvNext->type = TOKEN_ERROR_TYPE;
*state = LEX_ERROR;
break;
}
return;
}
struct Token* lvNext = LexVectorAppend(lv);
@ -247,6 +271,12 @@ size_t lexExpression(struct LexVector* lv, const char* string, size_t length, co
lvNext = LexVectorAppend(lv);
lvNext->type = TOKEN_OPEN_PAREN_TYPE;
break;
case '!':
case '-':
case '~':
case '*':
_lexOperator(lv, token, &state);
break;
case ' ':
case '\t':
break;
@ -499,6 +529,7 @@ static const int _operatorPrecedence[] = {
[OP_NOT] = 2,
[OP_SHIFT_L] = 5,
[OP_SHIFT_R] = 5,
[OP_DEREFERENCE] = 2,
};
static struct ParseTree* _parseTreeCreate() {
@ -622,7 +653,7 @@ void parseFree(struct ParseTree* tree) {
}
}
static bool _performOperation(enum Operation operation, int32_t current, int32_t next, int32_t* value) {
static bool _performOperation(struct mDebugger* debugger, enum Operation operation, int32_t current, int32_t next, int32_t* value, int* segment) {
switch (operation) {
case OP_ASSIGN:
current = next;
@ -683,12 +714,29 @@ static bool _performOperation(enum Operation operation, int32_t current, int32_t
case OP_GE:
current = current >= next;
break;
case OP_NEGATE:
current = -next;
break;
case OP_FLIP:
current = ~next;
break;
case OP_NOT:
current = !next;
break;
case OP_SHIFT_L:
current <<= next;
break;
case OP_SHIFT_R:
current >>= next;
break;
case OP_DEREFERENCE:
if (*segment < 0) {
current = debugger->core->busRead8(debugger->core, next);
} else {
current = debugger->core->rawRead8(debugger->core, next, *segment);
}
*segment = -1;
break;
default:
return false;
}
@ -714,13 +762,37 @@ bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tr
}
return mDebuggerEvaluateParseTree(debugger, tree->lhs, segment, NULL);
case TOKEN_OPERATOR_TYPE:
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) {
return false;
switch (tree->token.operatorValue) {
case OP_ASSIGN:
case OP_ADD:
case OP_SUBTRACT:
case OP_MULTIPLY:
case OP_DIVIDE:
case OP_MODULO:
case OP_AND:
case OP_OR:
case OP_XOR:
case OP_LESS:
case OP_GREATER:
case OP_EQUAL:
case OP_NOT_EQUAL:
case OP_LOGICAL_AND:
case OP_LOGICAL_OR:
case OP_LE:
case OP_GE:
case OP_SHIFT_L:
case OP_SHIFT_R:
if (!mDebuggerEvaluateParseTree(debugger, tree->lhs, &lhs, segment)) {
return false;
}
// Fall through
default:
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
return false;
}
break;
}
if (!mDebuggerEvaluateParseTree(debugger, tree->rhs, &rhs, segment)) {
return false;
}
return _performOperation(tree->token.operatorValue, lhs, rhs, value);
return _performOperation(debugger, tree->token.operatorValue, lhs, rhs, value, segment);
case TOKEN_IDENTIFIER_TYPE:
return mDebuggerLookupIdentifier(debugger, tree->token.identifierValue, value, segment);
case TOKEN_ERROR_TYPE:

View File

@ -74,7 +74,7 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address
};
disPtr[0] = '\t';
++disPtr;
LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
be->printf(be, "%s\n", disassembly);
return address;
}

View File

@ -215,7 +215,7 @@ static void LR35902DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t*
disPtr[0] = ':';
disPtr[1] = ' ';
disPtr += 2;
LR35902Disassemble(&info, disPtr, sizeof(disassembly) - (disPtr - disassembly));
LR35902Disassemble(&info, address, disPtr, sizeof(disassembly) - (disPtr - disassembly));
*length = snprintf(out, *length, "A: %02X F: %02X B: %02X C: %02X D: %02X E: %02X H: %02X L: %02X SP: %04X PC: %02X:%04X | %s",
cpu->a, cpu->f.packed, cpu->b, cpu->c,