all repos — mgba @ a75c019fab24f045069cb9a923d02795f4d6f564

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
 11#ifdef USE_CLI_DEBUGGER
 12
 13static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share
 14
 15static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
 16static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem*);
 17static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
 18static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
 19
 20static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
 21static void _load(struct CLIDebugger*, struct CLIDebugVector*);
 22static void _rewind(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	{ "rewind", _rewind, CLIDVParse, "Rewind the emulation a number of recorded intervals" },
 29	{ "save", _save, CLIDVParse, "Save a savestate" },
 30	{ 0, 0, 0, 0 }
 31};
 32
 33struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) {
 34	struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
 35	debugger->d.init = _GBACLIDebuggerInit;
 36	debugger->d.deinit = _GBACLIDebuggerDeinit;
 37	debugger->d.custom = _GBACLIDebuggerCustom;
 38	debugger->d.lookupIdentifier = _GBACLIDebuggerLookupIdentifier;
 39
 40	debugger->d.name = "Game Boy Advance";
 41	debugger->d.commands = _GBACLIDebuggerCommands;
 42
 43	debugger->core = core;
 44
 45	return debugger;
 46}
 47
 48static void _GBACLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
 49	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 50
 51	gbaDebugger->frameAdvance = false;
 52}
 53
 54static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem* debugger) {
 55	UNUSED(debugger);
 56}
 57
 58static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
 59	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 60
 61	if (gbaDebugger->frameAdvance) {
 62		if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) {
 63			DebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
 64			gbaDebugger->frameAdvance = false;
 65			return false;
 66		}
 67		gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
 68		return true;
 69	}
 70	return false;
 71}
 72
 73static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
 74	UNUSED(debugger);
 75	int i;
 76	for (i = 0; i < REG_MAX; i += 2) {
 77		const char* reg = GBAIORegisterNames[i >> 1];
 78		if (reg && strcasecmp(reg, name) == 0) {
 79			return BASE_IO | i;
 80		}
 81	}
 82	dv->type = CLIDV_ERROR_TYPE;
 83	return 0;
 84}
 85
 86static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 87	UNUSED(dv);
 88	debugger->d.state = DEBUGGER_CUSTOM;
 89
 90	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
 91	gbaDebugger->frameAdvance = true;
 92	gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
 93}
 94
 95static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 96	if (!dv || dv->type != CLIDV_INT_TYPE) {
 97		printf("%s\n", ERROR_MISSING_ARGS);
 98		return;
 99	}
100
101	int state = dv->intValue;
102	if (state < 1 || state > 9) {
103		printf("State %u out of range", state);
104	}
105
106	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
107
108	mCoreLoadState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT);
109}
110
111static void _rewind(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
112	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
113	if (!dv) {
114		// TODO: Put back rewind
115	} else if (dv->type != CLIDV_INT_TYPE) {
116		printf("%s\n", ERROR_MISSING_ARGS);
117	} else {
118		// TODO: Put back rewind
119	}
120}
121
122static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
123	if (!dv || dv->type != CLIDV_INT_TYPE) {
124		printf("%s\n", ERROR_MISSING_ARGS);
125		return;
126	}
127
128	int state = dv->intValue;
129	if (state < 1 || state > 9) {
130		printf("State %u out of range", state);
131	}
132
133	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
134
135	mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT);
136}
137#endif