src/gba/gba-cli.c (view raw)
1/* Copyright (c) 2013-2014 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 "gba-cli.h"
7
8#include "gba-io.h"
9#include "gba-serialize.h"
10#include "gba-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 _save(struct CLIDebugger*, struct CLIDebugVector*);
24
25struct CLIDebuggerCommandSummary _GBACLIDebuggerCommands[] = {
26 { "frame", _frame, 0, "Frame advance" },
27 { "load", _load, CLIDVParse, "Load a savestate" },
28 { "save", _save, CLIDVParse, "Save a savestate" },
29 { 0, 0, 0, 0 }
30};
31#endif
32
33struct GBACLIDebugger* GBACLIDebuggerCreate(struct GBAThread* context) {
34 struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger));
35#ifdef USE_CLI_DEBUGGER
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#else
46 UNUSED(context);
47#endif
48
49 return debugger;
50}
51
52#ifdef USE_CLI_DEBUGGER
53static void _GBACLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
54 struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
55
56 gbaDebugger->frameAdvance = false;
57}
58
59static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem* debugger) {
60 UNUSED(debugger);
61}
62
63static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
64 struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
65
66 if (gbaDebugger->frameAdvance) {
67 if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(gbaDebugger->context->gba->video.dispstat)) {
68 ARMDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_BREAKPOINT);
69 gbaDebugger->frameAdvance = false;
70 return false;
71 }
72 gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->video.dispstat);
73 return true;
74 }
75 return false;
76}
77
78static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
79 struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger;
80 int i;
81 for (i = 0; i < REG_MAX; i += 2) {
82 const char* reg = GBAIORegisterNames[i >> 1];
83 if (reg && strcasecmp(reg, name) == 0) {
84 return GBALoad16(gbaDebugger->context->gba->cpu, BASE_IO | i, 0);
85 }
86 }
87 dv->type = CLIDV_ERROR_TYPE;
88 return 0;
89}
90
91static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
92 UNUSED(dv);
93 debugger->d.state = DEBUGGER_CUSTOM;
94
95 struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
96 gbaDebugger->frameAdvance = true;
97 gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->video.dispstat);
98}
99
100static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
101 if (!dv || dv->type != CLIDV_INT_TYPE) {
102 printf("%s\n", ERROR_MISSING_ARGS);
103 return;
104 }
105
106 int state = dv->intValue;
107 if (state < 1 || state > 9) {
108 printf("State %u out of range", state);
109 }
110
111 struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
112
113 GBALoadState(gbaDebugger->context->gba, gbaDebugger->context->stateDir, dv->intValue);
114}
115
116static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
117 if (!dv || dv->type != CLIDV_INT_TYPE) {
118 printf("%s\n", ERROR_MISSING_ARGS);
119 return;
120 }
121
122 int state = dv->intValue;
123 if (state < 1 || state > 9) {
124 printf("State %u out of range", state);
125 }
126
127 struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
128
129 GBASaveState(gbaDebugger->context->gba, gbaDebugger->context->stateDir, dv->intValue, true);
130}
131#endif