src/gb/debugger/cli.c (view raw)
1/* Copyright (c) 2013-2016 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/gb/extra/cli.h>
7
8#include <mgba/core/core.h>
9#include <mgba/core/serialize.h>
10#include <mgba/internal/gb/gb.h>
11#include <mgba/internal/gb/io.h>
12#include <mgba/internal/gb/video.h>
13#include <mgba/internal/lr35902/debugger/cli-debugger.h>
14
15static void _GBCLIDebuggerInit(struct CLIDebuggerSystem*);
16static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem*);
17static uint32_t _GBCLIDebuggerLookupIdentifier(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 _GBCLIDebuggerCommands[] = {
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 CLIDebuggerSystem* GBCLIDebuggerCreate(struct mCore* core) {
31 UNUSED(core);
32 struct GBCLIDebugger* debugger = malloc(sizeof(struct GBCLIDebugger));
33 LR35902CLIDebuggerCreate(&debugger->d);
34 debugger->d.init = _GBCLIDebuggerInit;
35 debugger->d.deinit = NULL;
36 debugger->d.custom = _GBCLIDebuggerCustom;
37 debugger->d.lookupIdentifier = _GBCLIDebuggerLookupIdentifier;
38
39 debugger->d.name = "Game Boy";
40 debugger->d.commands = _GBCLIDebuggerCommands;
41
42 debugger->core = core;
43
44 return &debugger->d;
45}
46
47static void _GBCLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
48 struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger;
49
50 gbDebugger->frameAdvance = false;
51}
52
53static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) {
54 struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger;
55
56 if (gbDebugger->frameAdvance) {
57 if (!gbDebugger->inVblank && GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1) {
58 mDebuggerEnter(&gbDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0);
59 gbDebugger->frameAdvance = false;
60 return false;
61 }
62 gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1;
63 return true;
64 }
65 return false;
66}
67
68static uint32_t _GBCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) {
69 UNUSED(debugger);
70 int i;
71 for (i = 0; i < REG_MAX; ++i) {
72 const char* reg = GBIORegisterNames[i];
73 if (reg && strcasecmp(reg, name) == 0) {
74 return GB_BASE_IO | i;
75 }
76 }
77 dv->type = CLIDV_ERROR_TYPE;
78 return 0;
79}
80
81static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
82 UNUSED(dv);
83 debugger->d.state = DEBUGGER_CUSTOM;
84
85 struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system;
86 gbDebugger->frameAdvance = true;
87 gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1;
88}
89
90static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
91 struct CLIDebuggerBackend* be = debugger->backend;
92 if (!dv || dv->type != CLIDV_INT_TYPE) {
93 be->printf(be, "%s\n", ERROR_MISSING_ARGS);
94 return;
95 }
96
97 int state = dv->intValue;
98 if (state < 1 || state > 9) {
99 be->printf(be, "State %u out of range", state);
100 }
101
102 struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system;
103
104 mCoreLoadState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
105}
106
107static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
108 struct CLIDebuggerBackend* be = debugger->backend;
109 if (!dv || dv->type != CLIDV_INT_TYPE) {
110 be->printf(be, "%s\n", ERROR_MISSING_ARGS);
111 return;
112 }
113
114 int state = dv->intValue;
115 if (state < 1 || state > 9) {
116 be->printf(be, "State %u out of range", state);
117 }
118
119 struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system;
120
121 mCoreSaveState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC | SAVESTATE_METADATA);
122}