all repos — mgba @ 3021996a49cf72be55d15a1be4b24a13a8b751b9

mGBA Game Boy Advance Emulator

src/gba/debugger/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 <mgba/internal/gba/extra/cli.h>
  7
  8#include <mgba/core/core.h>
  9#include <mgba/core/serialize.h>
 10#include <mgba/internal/gba/gba.h>
 11#include <mgba/internal/gba/io.h>
 12#include <mgba/internal/gba/video.h>
 13#include <mgba/internal/arm/debugger/cli-debugger.h>
 14
 15static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*);
 16static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*);
 17static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);
 18
 19static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
 20static void _load(struct CLIDebugger*, struct CLIDebugVector*);
 21static void _save(struct CLIDebugger*, struct CLIDebugVector*);
 22
 23struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
 24	{ "frame", _frame, 0, "Frame advance" },
 25	{ "load", _load, CLIDVParse, "Load a savestate" },
 26	{ "save", _save, CLIDVParse, "Save a savestate" },
 27	{ 0, 0, 0, 0 }
 28};
 29
 30struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) {
 31	struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
 32	ARMCLIDebuggerCreate(&debugger->d);
 33	debugger->d.init = _GBACLIDebuggerInit;
 34	debugger->d.deinit = NULL;
 35	debugger->d.custom = _GBACLIDebuggerCustom;
 36	debugger->d.lookupIdentifier = _GBACLIDebuggerLookupIdentifier;
 37
 38	debugger->d.name = "Game Boy Advance";
 39	debugger->d.commands = _GBACLIDebuggerCommands;
 40
 41	debugger->core = core;
 42
 43	return debugger;
 44}
 45
 46static void _GBACLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
 47	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 48
 49	gbaDebugger->frameAdvance = false;
 50}
 51
 52static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
 53	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
 54
 55	if (gbaDebugger->frameAdvance) {
 56		if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) {
 57			mDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
 58			gbaDebugger->frameAdvance = false;
 59			return false;
 60		}
 61		gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
 62		return true;
 63	}
 64	return false;
 65}
 66
 67static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
 68	UNUSED(debugger);
 69	int i;
 70	for (i = 0; i < REG_MAX; i += 2) {
 71		const char* reg = GBAIORegisterNames[i >> 1];
 72		if (reg && strcasecmp(reg, name) == 0) {
 73			return BASE_IO | i;
 74		}
 75	}
 76	dv->type = CLIDV_ERROR_TYPE;
 77	return 0;
 78}
 79
 80static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 81	UNUSED(dv);
 82	debugger->d.state = DEBUGGER_CUSTOM;
 83
 84	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
 85	gbaDebugger->frameAdvance = true;
 86	gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]);
 87}
 88
 89static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
 90	struct CLIDebuggerBackend* be = debugger->backend;
 91	if (!dv || dv->type != CLIDV_INT_TYPE) {
 92		be->printf(be, "%s\n", ERROR_MISSING_ARGS);
 93		return;
 94	}
 95
 96	int state = dv->intValue;
 97	if (state < 1 || state > 9) {
 98		be->printf(be, "State %u out of range", state);
 99	}
100
101	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
102
103	mCoreLoadState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
104}
105
106// TODO: Put back rewind
107
108static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
109	struct CLIDebuggerBackend* be = debugger->backend;
110	if (!dv || dv->type != CLIDV_INT_TYPE) {
111		be->printf(be, "%s\n", ERROR_MISSING_ARGS);
112		return;
113	}
114
115	int state = dv->intValue;
116	if (state < 1 || state > 9) {
117		be->printf(be, "State %u out of range", state);
118	}
119
120	struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
121
122	mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
123}