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}