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