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