View
@@ -21,6 +21,10 @@
#include <mgba-util/memory.h>
#include <mgba-util/vfs.h>
+#ifdef USE_ELF
+#include <mgba-util/elf-read.h>
+#endif
+
mLOG_DEFINE_CATEGORY(GBA, "GBA", "gba");
mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug");
@@ -203,6 +207,10 @@ void GBAReset(struct ARMCore* cpu) {
gba->debug = false;
memset(gba->debugString, 0, sizeof(gba->debugString));
+
+ if (!gba->romVf) {
+ GBASkipBIOS(gba);
+ }
}
void GBASkipBIOS(struct GBA* gba) {
@@ -288,6 +296,25 @@ void GBADetachDebugger(struct GBA* gba) {
}
#endif
+bool GBALoadNull(struct GBA* gba) {
+ GBAUnloadROM(gba);
+ gba->romVf = NULL;
+ gba->pristineRomSize = 0;
+ gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM);
+#ifndef FIXED_ROM_BUFFER
+ gba->memory.rom = anonymousMemoryMap(SIZE_CART0);
+#else
+ gba->memory.rom = romBuffer;
+#endif
+ gba->isPristine = false;
+ gba->yankedRomSize = 0;
+ gba->memory.romSize = SIZE_CART0;
+ gba->memory.romMask = SIZE_CART0 - 1;
+ gba->memory.mirroring = false;
+ gba->romCrc32 = 0;
+ return true;
+}
+
bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
GBAUnloadROM(gba);
gba->romVf = vf;
@@ -478,6 +505,17 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
}
bool GBAIsROM(struct VFile* vf) {
+#ifdef USE_ELF
+ struct ELF* elf = ELFOpen(vf);
+ if (elf) {
+ uint32_t entry = ELFEntry(elf);
+ bool isGBA = true;
+ isGBA = isGBA && ELFMachine(elf) == EM_ARM;
+ isGBA = isGBA && (entry == BASE_CART0 || entry == BASE_WORKING_RAM);
+ ELFClose(elf);
+ return isGBA;
+ }
+#endif
if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
return false;
}
@@ -495,6 +533,14 @@ bool GBAIsMB(struct VFile* vf) {
if (!GBAIsROM(vf)) {
return false;
}
+#ifdef USE_ELF
+ struct ELF* elf = ELFOpen(vf);
+ if (elf) {
+ bool isMB = ELFEntry(elf) == BASE_WORKING_RAM;
+ ELFClose(elf);
+ return isMB;
+ }
+#endif
if (vf->size(vf) > SIZE_WORKING_RAM) {
return false;
}
View
@@ -80,6 +80,8 @@ void GBAMemoryInit(struct GBA* gba) {
gba->memory.biosPrefetch = 0;
gba->memory.mirroring = false;
+ gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
+
GBADMAInit(gba);
GBAVFameInit(&gba->memory.vfame);
}
@@ -107,9 +109,8 @@ void GBAMemoryReset(struct GBA* gba) {
}
if (gba->memory.iwram) {
- mappedMemoryFree(gba->memory.iwram, SIZE_WORKING_IRAM);
+ memset(gba->memory.iwram, 0, SIZE_WORKING_IRAM);
}
- gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
memset(gba->memory.io, 0, sizeof(gba->memory.io));
View
@@ -58,4 +58,5 @@ void free(void*);
#endif
#ifdef USE_DEBUGGERS
#include <mgba/debugger/debugger.h>
+#include <mgba/internal/debugger/cli-debugger.h>
#endif
View
@@ -28,6 +28,7 @@
#include <mgba/core/version.h>
#include <mgba/debugger/debugger.h>
#include <mgba/internal/arm/arm.h>
+#include <mgba/internal/debugger/cli-debugger.h>
#include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/input.h>
#include <mgba/internal/gba/renderers/tile-cache.h>
@@ -70,17 +71,27 @@
ffi.embedding_api('\n'.join(lines))
ffi.embedding_init_code("""
- from mgba._pylib import ffi
- debugger = None
+ from mgba._pylib import ffi, lib
+ symbols = {}
+ globalSyms = {
+ 'symbols': symbols
+ }
pendingCode = []
@ffi.def_extern()
- def mPythonSetDebugger(_debugger):
- from mgba.debugger import NativeDebugger
- global debugger
- if debugger and debugger._native == _debugger:
+ def mPythonSetDebugger(debugger):
+ from mgba.debugger import NativeDebugger, CLIDebugger
+ oldDebugger = globalSyms.get('debugger')
+ if oldDebugger and oldDebugger._native == debugger:
return
- debugger = _debugger and NativeDebugger(_debugger)
+ if oldDebugger and not debugger:
+ del globalSyms['debugger']
+ return
+ if debugger.type == lib.DEBUGGER_CLI:
+ debugger = CLIDebugger(debugger)
+ else:
+ debugger = NativeDebugger(debugger)
+ globalSyms['debugger'] = debugger
@ffi.def_extern()
def mPythonLoadScript(name, vf):
@@ -99,18 +110,40 @@ def mPythonLoadScript(name, vf):
def mPythonRunPending():
global pendingCode
for code in pendingCode:
- exec(code)
+ exec(code, globalSyms, {})
pendingCode = []
@ffi.def_extern()
def mPythonDebuggerEntered(reason, info):
- global debugger
+ debugger = globalSyms['debugger']
if not debugger:
return
if info == ffi.NULL:
info = None
for cb in debugger._cbs:
cb(reason, info)
+
+ @ffi.def_extern()
+ def mPythonLookupSymbol(name, outptr):
+ name = ffi.string(name).decode('utf-8')
+ if name not in symbols:
+ return False
+ sym = symbols[name]
+ val = None
+ try:
+ val = int(sym)
+ except:
+ try:
+ val = sym()
+ except:
+ pass
+ if val is None:
+ return False
+ try:
+ outptr[0] = ffi.cast('int32_t', val)
+ return True
+ except:
+ return False
""")
if __name__ == "__main__":
View
@@ -21,6 +21,7 @@ static void mPythonScriptEngineDeinit(struct mScriptEngine*);
static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf);
static bool mPythonScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf);
static void mPythonScriptEngineRun(struct mScriptEngine*);
+static bool mPythonScriptEngineLookupSymbol(struct mScriptEngine*, const char* name, int32_t* out);
#ifdef USE_DEBUGGERS
static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
@@ -39,6 +40,7 @@ struct mPythonScriptEngine* mPythonCreateScriptEngine(void) {
engine->d.isScript = mPythonScriptEngineIsScript;
engine->d.loadScript = mPythonScriptEngineLoadScript;
engine->d.run = mPythonScriptEngineRun;
+ engine->d.lookupSymbol = mPythonScriptEngineLookupSymbol;
#ifdef USE_DEBUGGERS
engine->d.debuggerEntered = mPythonScriptDebuggerEntered;
#endif
@@ -89,6 +91,11 @@ void mPythonScriptEngineRun(struct mScriptEngine* se) {
mPythonRunPending();
}
+bool mPythonScriptEngineLookupSymbol(struct mScriptEngine* se, const char* name, int32_t* out) {
+ struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
+ return mPythonLookupSymbol(name, out);
+}
+
#ifdef USE_DEBUGGERS
void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
View
@@ -4,6 +4,7 @@ struct VFile;
extern bool mPythonLoadScript(const char*, struct VFile*);
extern void mPythonRunPending();
+extern bool mPythonLookupSymbol(const char* name, int32_t* out);
#ifdef USE_DEBUGGERS
extern void mPythonSetDebugger(struct mDebugger*);
View
@@ -5,6 +5,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from ._pylib import ffi, lib
from .core import IRunner, ICoreOwner, Core
+import io
+import sys
class DebuggerCoreOwner(ICoreOwner):
def __init__(self, debugger):
@@ -78,3 +80,22 @@ def clearWatchpoint(self, address):
def addCallback(self, cb):
self._cbs.append(cb)
+
+class CLIBackend(object):
+ def __init__(self, backend):
+ self.backend = backend
+
+ def write(self, string):
+ self.backend.printf(string)
+
+class CLIDebugger(NativeDebugger):
+ def __init__(self, native):
+ super(CLIDebugger, self).__init__(native)
+ self._cli = ffi.cast("struct CLIDebugger*", native)
+
+ def printf(self, message, *args, **kwargs):
+ message = message.format(*args, **kwargs)
+ self._cli.backend.printf(ffi.new("char []", b"%s"), ffi.new("char []", message.encode('utf-8')))
+
+ def installPrint(self):
+ sys.stdout = CLIBackend(self)
View
@@ -155,7 +155,9 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
#endif
m_screenWidget->setPixmap(m_logo);
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
+ m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
m_screenWidget->setLockIntegerScaling(false);
+ m_screenWidget->setLockAspectRatio(true);
setCentralWidget(m_screenWidget);
connect(m_controller, &GameController::gameStarted, this, &Window::gameStarted);
@@ -173,7 +175,6 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
QPixmap pixmap;
pixmap.convertFromImage(currentImage);
m_screenWidget->setPixmap(pixmap);
- m_screenWidget->setLockAspectRatio(width, height);
});
connect(m_controller, &GameController::gamePaused, m_display, &Display::pauseDrawing);
#ifndef Q_OS_MAC
@@ -803,7 +804,9 @@ void Window::gameStarted(mCoreThread* context, const QString& fname) {
context->core->desiredVideoDimensions(context->core, &width, &height);
m_display->setMinimumSize(width, height);
m_screenWidget->setMinimumSize(m_display->minimumSize());
+ m_screenWidget->setDimensions(width, height);
m_config->updateOption("lockIntegerScaling");
+ m_config->updateOption("lockAspectRatio");
if (m_savedScale > 0) {
resizeFrame(QSize(width, height) * m_savedScale);
}
@@ -867,7 +870,9 @@ void Window::gameStopped() {
updateTitle();
detachWidget(m_display);
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
+ m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
m_screenWidget->setLockIntegerScaling(false);
+ m_screenWidget->setLockAspectRatio(true);
m_screenWidget->setPixmap(m_logo);
m_screenWidget->unsetCursor();
#ifdef M_CORE_GB
@@ -1341,6 +1346,9 @@ void Window::setupMenu(QMenuBar* menubar) {
lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu);
lockAspectRatio->connect([this](const QVariant& value) {
m_display->lockAspectRatio(value.toBool());
+ if (m_controller->isLoaded()) {
+ m_screenWidget->setLockAspectRatio(value.toBool());
+ }
}, this);
m_config->updateOption("lockAspectRatio");
@@ -1670,14 +1678,13 @@ QSize WindowBackground::sizeHint() const {
return m_sizeHint;
}
-void WindowBackground::setLockAspectRatio(int width, int height) {
- m_centered = false;
- m_aspectWidth = width;
- m_aspectHeight = height;
-}
-
void WindowBackground::setCenteredAspectRatio(int width, int height) {
m_centered = true;
+ m_lockAspectRatio = true;
+ setDimensions(width, height);
+}
+
+void WindowBackground::setDimensions(int width, int height) {
m_aspectWidth = width;
m_aspectHeight = height;
}
@@ -1686,6 +1693,11 @@ void WindowBackground::setLockIntegerScaling(bool lock) {
m_lockIntegerScaling = lock;
}
+void WindowBackground::setLockAspectRatio(bool lock) {
+ m_centered = false;
+ m_lockAspectRatio = lock;
+}
+
void WindowBackground::paintEvent(QPaintEvent*) {
const QPixmap* logo = pixmap();
if (!logo) {
@@ -1702,7 +1714,7 @@ void WindowBackground::paintEvent(QPaintEvent*) {
} else if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth);
}
- } else {
+ } else if (m_lockAspectRatio) {
if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight);
} else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) {
View
@@ -210,9 +210,10 @@ Q_OBJECT
void setSizeHint(const QSize& size);
virtual QSize sizeHint() const override;
- void setLockAspectRatio(int width, int height);
+ void setDimensions(int width, int height);
void setCenteredAspectRatio(int width, int height);
void setLockIntegerScaling(bool lock);
+ void setLockAspectRatio(bool lock);
protected:
virtual void paintEvent(QPaintEvent*) override;
@@ -222,6 +223,7 @@ Q_OBJECT
bool m_centered;
int m_aspectWidth;
int m_aspectHeight;
+ bool m_lockAspectRatio;
bool m_lockIntegerScaling;
};
View
@@ -21,6 +21,7 @@
#endif
#endif
+#include <mgba/core/cheats.h>
#include <mgba/core/core.h>
#include <mgba/core/config.h>
#include <mgba/core/input.h>
@@ -104,6 +105,16 @@ int main(int argc, char** argv) {
return 1;
}
+ struct mCheatDevice* device = NULL;
+ if (args.cheatsFile && (device = renderer.core->cheatDevice(renderer.core))) {
+ struct VFile* vf = VFileOpen(args.cheatsFile, O_RDONLY);
+ if (vf) {
+ mCheatDeviceClear(device);
+ mCheatParseFile(device, vf);
+ vf->close(vf);
+ }
+ }
+
mInputMapInit(&renderer.core->inputMap, renderer.core->inputInfo);
mCoreInitConfig(renderer.core, PORT);
applyArguments(&args, &subparser, &renderer.core->config);
@@ -148,6 +159,10 @@ int main(int argc, char** argv) {
mSDLDetachPlayer(&renderer.events, &renderer.player);
mInputMapDeinit(&renderer.core->inputMap);
+ if (device) {
+ mCheatDeviceDestroy(device);
+ }
+
mSDLDeinit(&renderer);
freeArguments(&args);
@@ -184,10 +199,10 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
#endif
mDebuggerAttach(debugger, renderer->core);
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
- }
-#ifdef ENABLE_SCRIPTING
- mScriptBridgeSetDebugger(bridge, debugger);
+ #ifdef ENABLE_SCRIPTING
+ mScriptBridgeSetDebugger(bridge, debugger);
#endif
+ }
#endif
if (args->patch) {
View
@@ -0,0 +1,125 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <mgba-util/elf-read.h>
+
+#ifdef USE_ELF
+
+#include <mgba-util/vfs.h>
+
+DEFINE_VECTOR(ELFProgramHeaders, Elf32_Phdr);
+DEFINE_VECTOR(ELFSectionHeaders, Elf32_Shdr);
+
+static bool _elfInit = false;
+
+struct ELF {
+ Elf* e;
+ struct VFile* vf;
+ size_t size;
+ char* memory;
+};
+
+struct ELF* ELFOpen(struct VFile* vf) {
+ if (!_elfInit) {
+ _elfInit = elf_version(EV_CURRENT) != EV_NONE;
+ if (!_elfInit) {
+ return NULL;
+ }
+ }
+ if (!vf) {
+ return NULL;
+ }
+ size_t size = vf->size(vf);
+ char* memory = vf->map(vf, size, MAP_READ);
+ if (!memory) {
+ return NULL;
+ }
+
+ Elf* e = elf_memory(memory, size);
+ if (!e || elf_kind(e) != ELF_K_ELF) {
+ elf_end(e);
+ vf->unmap(vf, memory, size);
+ return false;
+ }
+ struct ELF* elf = malloc(sizeof(*elf));
+ elf->e = e;
+ elf->vf = vf;
+ elf->size = size;
+ elf->memory = memory;
+ return elf;
+}
+
+void ELFClose(struct ELF* elf) {
+ elf_end(elf->e);
+ elf->vf->unmap(elf->vf, elf->memory, elf->size);
+ free(elf);
+}
+
+void* ELFBytes(struct ELF* elf, size_t* size) {
+ if (size) {
+ *size = elf->size;
+ }
+ return elf->memory;
+}
+
+uint16_t ELFMachine(struct ELF* elf) {
+ Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
+ if (!hdr) {
+ return 0;
+ }
+ return hdr->e_machine;
+}
+
+uint32_t ELFEntry(struct ELF* elf) {
+ Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
+ if (!hdr) {
+ return 0;
+ }
+ return hdr->e_entry;
+}
+
+void ELFGetProgramHeaders(struct ELF* elf, struct ELFProgramHeaders* ph) {
+ ELFProgramHeadersClear(ph);
+ Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
+ Elf32_Phdr* phdr = elf32_getphdr(elf->e);
+ ELFProgramHeadersResize(ph, hdr->e_phnum);
+ memcpy(ELFProgramHeadersGetPointer(ph, 0), phdr, sizeof(*phdr) * hdr->e_phnum);
+}
+
+void ELFGetSectionHeaders(struct ELF* elf, struct ELFSectionHeaders* sh) {
+ ELFSectionHeadersClear(sh);
+ Elf_Scn* section = elf_getscn(elf->e, 0);
+ do {
+ *ELFSectionHeadersAppend(sh) = *elf32_getshdr(section);
+ } while ((section = elf_nextscn(elf->e, section)));
+}
+
+Elf32_Shdr* ELFGetSectionHeader(struct ELF* elf, size_t index) {
+ Elf_Scn* section = elf_getscn(elf->e, index);
+ return elf32_getshdr(section);
+}
+
+size_t ELFFindSection(struct ELF* elf, const char* name) {
+ Elf32_Ehdr* hdr = elf32_getehdr(elf->e);
+ size_t shstrtab = hdr->e_shstrndx;
+ if (strcmp(name, ".shstrtab") == 0) {
+ return shstrtab;
+ }
+ Elf_Scn* section = NULL;
+ while ((section = elf_nextscn(elf->e, section))) {
+ Elf32_Shdr* shdr = elf32_getshdr(section);
+ const char* sname = elf_strptr(elf->e, shstrtab, shdr->sh_name);
+ if (strcmp(sname, name) == 0) {
+ return elf_ndxscn(section);
+ }
+ }
+ return 0;
+}
+
+const char* ELFGetString(struct ELF* elf, size_t section, size_t string) {
+ return elf_strptr(elf->e, section, string);
+}
+
+#endif