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 GBAThread* context) {
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->context = context;
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(gbaDebugger->context->gba->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(gbaDebugger->context->gba->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(gbaDebugger->context->gba->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 GBALoadState(gbaDebugger->context, gbaDebugger->context->dirs.state, 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 GBARewindAll(gbaDebugger->context);
116 } else if (dv->type != CLIDV_INT_TYPE) {
117 printf("%s\n", ERROR_MISSING_ARGS);
118 } else {
119 GBARewind(gbaDebugger->context, dv->intValue);
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 GBASaveState(gbaDebugger->context, gbaDebugger->context->dirs.state, dv->intValue, SAVESTATE_SCREENSHOT);
137}
138#endif