all repos — mgba @ 338486338215add02c7aba0e2ddcdb2094417c78

mGBA Game Boy Advance Emulator

src/gba/gba-cli.c (view raw)

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "gba-cli.h"
  7
  8#include "gba-io.h"
  9#include "gba-serialize.h"
 10#include "gba-thread.h"
 11
 12#ifdef USE_CLI_DEBUGGER
 13
 14static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
 15
 16static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
 17static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem*);
 18static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
 19static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
 20
 21static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
 22static void _load(struct CLIDebugger*, struct CLIDebugVector*);
 23static void _save(struct CLIDebugger*, struct CLIDebugVector*);
 24
 25struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
 26	{ "frame", _frame, 0, "Frame advance" },
 27	{ "load", _load, CLIDVParse, "Load a savestate" },
 28	{ "save", _save, CLIDVParse, "Save a savestate" },
 29	{ 0, 0, 0, 0 }
 30};
 31#endif
 32
 33struct GBACLIDebugger* GBACLIDebuggerCreate(struct GBAThread* context) {
 34	struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
 35#ifdef USE_CLI_DEBUGGER
 36	debugger->d.init = _GBACLIDebuggerInit;
 37	debugger->d.deinit = _GBACLIDebuggerDeinit;
 38	debugger->d.custom = _GBACLIDebuggerCustom;
 39	debugger->d.lookupIdentifier = _GBACLIDebuggerLookupIdentifier;
 40
 41	debugger->d.name = "Game Boy Advance";
 42	debugger->d.commands = _GBACLIDebuggerCommands;
 43
 44	debugger->context = context;
 45#else
 46	UNUSED(context);
 47#endif
 48
 49	return debugger;
 50}
 51
 52#ifdef USE_CLI_DEBUGGER
 53static void _GBACLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
 54	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 55
 56	gbaDebugger->frameAdvance = false;
 57}
 58
 59static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem* debugger) {
 60	UNUSED(debugger);
 61}
 62
 63static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
 64	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 65
 66	if (gbaDebugger->frameAdvance) {
 67		if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(gbaDebugger->context->gba->video.dispstat)) {
 68			ARMDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_BREAKPOINT);
 69			gbaDebugger->frameAdvance = false;
 70			return false;
 71		}
 72		gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->video.dispstat);
 73		return true;
 74	}
 75	return false;
 76}
 77
 78static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
 79	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 80	int i;
 81	for (i = 0; i < REG_MAX; i += 2) {
 82		const char* reg = GBAIORegisterNames[i >> 1];
 83		if (reg && strcasecmp(reg, name) == 0) {
 84			return GBALoad16(gbaDebugger->context->gba->cpu, BASE_IO | i, 0);
 85		}
 86	}
 87	dv->type = CLIDV_ERROR_TYPE;
 88	return 0;
 89}
 90
 91static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 92	UNUSED(dv);
 93	debugger->d.state = DEBUGGER_CUSTOM;
 94
 95	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
 96	gbaDebugger->frameAdvance = true;
 97	gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->video.dispstat);
 98}
 99
100static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
101	if (!dv || dv->type != CLIDV_INT_TYPE) {
102		printf("%s\n", ERROR_MISSING_ARGS);
103		return;
104	}
105
106	int state = dv->intValue;
107	if (state < 1 || state > 9) {
108		printf("State %u out of range", state);
109	}
110
111	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
112
113	GBALoadState(gbaDebugger->context->gba, gbaDebugger->context->stateDir, dv->intValue);
114}
115
116static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
117	if (!dv || dv->type != CLIDV_INT_TYPE) {
118		printf("%s\n", ERROR_MISSING_ARGS);
119		return;
120	}
121
122	int state = dv->intValue;
123	if (state < 1 || state > 9) {
124		printf("State %u out of range", state);
125	}
126
127	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
128
129	GBASaveState(gbaDebugger->context->gba, gbaDebugger->context->stateDir, dv->intValue, true);
130}
131#endif