all repos — mgba @ eccddde2834544da2ce62dfb3abe2c596207bd5f

mGBA Game Boy Advance Emulator

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

  1/* Copyright (c) 2013-2015 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 "cli.h"
  7
  8#include "gba/io.h"
  9#include "gba/serialize.h"
 10#include "gba/supervisor/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 _rewind(struct CLIDebugger*, struct CLIDebugVector*);
 24static void _save(struct CLIDebugger*, struct CLIDebugVector*);
 25
 26struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
 27	{ "frame", _frame, 0, "Frame advance" },
 28	{ "load", _load, CLIDVParse, "Load a savestate" },
 29	{ "rewind", _rewind, CLIDVParse, "Rewind the emulation a number of recorded intervals" },
 30	{ "save", _save, CLIDVParse, "Save a savestate" },
 31	{ 0, 0, 0, 0 }
 32};
 33
 34struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) {
 35	struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
 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->core = core;
 45
 46	return debugger;
 47}
 48
 49static void _GBACLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
 50	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 51
 52	gbaDebugger->frameAdvance = false;
 53}
 54
 55static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem* debugger) {
 56	UNUSED(debugger);
 57}
 58
 59static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
 60	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 61
 62	if (gbaDebugger->frameAdvance) {
 63		if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) {
 64			ARMDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
 65			gbaDebugger->frameAdvance = false;
 66			return false;
 67		}
 68		gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
 69		return true;
 70	}
 71	return false;
 72}
 73
 74static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
 75	UNUSED(debugger);
 76	int i;
 77	for (i = 0; i < REG_MAX; i += 2) {
 78		const char* reg = GBAIORegisterNames[i >> 1];
 79		if (reg && strcasecmp(reg, name) == 0) {
 80			return BASE_IO | i;
 81		}
 82	}
 83	dv->type = CLIDV_ERROR_TYPE;
 84	return 0;
 85}
 86
 87static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 88	UNUSED(dv);
 89	debugger->d.state = DEBUGGER_CUSTOM;
 90
 91	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
 92	gbaDebugger->frameAdvance = true;
 93	gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
 94}
 95
 96static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 97	if (!dv || dv->type != CLIDV_INT_TYPE) {
 98		printf("%s\n", ERROR_MISSING_ARGS);
 99		return;
100	}
101
102	int state = dv->intValue;
103	if (state < 1 || state > 9) {
104		printf("State %u out of range", state);
105	}
106
107	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
108
109	mCoreLoadState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT);
110}
111
112static void _rewind(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
113	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
114	if (!dv) {
115		// TODO: Put back rewind
116	} else if (dv->type != CLIDV_INT_TYPE) {
117		printf("%s\n", ERROR_MISSING_ARGS);
118	} else {
119		// TODO: Put back rewind
120	}
121}
122
123static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
124	if (!dv || dv->type != CLIDV_INT_TYPE) {
125		printf("%s\n", ERROR_MISSING_ARGS);
126		return;
127	}
128
129	int state = dv->intValue;
130	if (state < 1 || state > 9) {
131		printf("State %u out of range", state);
132	}
133
134	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
135
136	mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT);
137}
138#endif