mirror of https://github.com/mgba-emu/mgba.git
Debugger: Add unary operators and memory dereferencing
This commit is contained in:
parent
f5ddeb3611
commit
c3ec7311e8
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -38,6 +38,7 @@ enum Operation {
|
|||
OP_NOT,
|
||||
OP_SHIFT_L,
|
||||
OP_SHIFT_R,
|
||||
OP_DEREFERENCE,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
|
|
@ -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:
|
||||
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;
|
||||
}
|
||||
return _performOperation(tree->token.operatorValue, lhs, rhs, value);
|
||||
break;
|
||||
}
|
||||
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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue