mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into medusa
This commit is contained in:
commit
45169bc0f2
6
CHANGES
6
CHANGES
|
@ -8,6 +8,8 @@ Misc:
|
||||||
- DS GX: Clean up and unify texture mapping
|
- DS GX: Clean up and unify texture mapping
|
||||||
|
|
||||||
0.7.0: (Future)
|
0.7.0: (Future)
|
||||||
|
Features:
|
||||||
|
- ELF support
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
|
- GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749)
|
||||||
Misc:
|
Misc:
|
||||||
|
@ -15,7 +17,7 @@ Misc:
|
||||||
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
|
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
|
||||||
- All: Make FIXED_ROM_BUFFER an option instead of 3DS-only
|
- All: Make FIXED_ROM_BUFFER an option instead of 3DS-only
|
||||||
|
|
||||||
0.6.0: (Future)
|
0.6.0: (2017-07-16)
|
||||||
Features:
|
Features:
|
||||||
- Library view
|
- Library view
|
||||||
- Sprite viewer
|
- Sprite viewer
|
||||||
|
@ -190,6 +192,8 @@ Bugfixes:
|
||||||
- Core: Fix rewinding getting out of sync (fixes mgba.io/i/791)
|
- Core: Fix rewinding getting out of sync (fixes mgba.io/i/791)
|
||||||
- Qt: Fix GL-less build
|
- Qt: Fix GL-less build
|
||||||
- Qt: Fix Software renderer not handling alpha bits properly
|
- Qt: Fix Software renderer not handling alpha bits properly
|
||||||
|
- Qt: Fix screen background improperly stretching
|
||||||
|
- SDL: Fix cheats not loading
|
||||||
Misc:
|
Misc:
|
||||||
- GB Serialize: Add MBC state serialization
|
- GB Serialize: Add MBC state serialization
|
||||||
- GBA Memory: Call crash callbacks regardless of if hard crash is enabled
|
- GBA Memory: Call crash callbacks regardless of if hard crash is enabled
|
||||||
|
|
|
@ -16,6 +16,7 @@ set(USE_PNG ON CACHE BOOL "Whether or not to enable PNG support")
|
||||||
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")
|
set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support")
|
||||||
set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support")
|
set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support")
|
||||||
set(USE_SQLITE3 ON CACHE BOOL "Whether or not to enable SQLite3 support")
|
set(USE_SQLITE3 ON CACHE BOOL "Whether or not to enable SQLite3 support")
|
||||||
|
set(USE_ELF ON CACHE BOOL "Whether or not to enable ELF support")
|
||||||
set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core")
|
set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core")
|
||||||
set(M_CORE_GB ON CACHE BOOL "Build Game Boy core")
|
set(M_CORE_GB ON CACHE BOOL "Build Game Boy core")
|
||||||
set(M_CORE_DS ON CACHE BOOL "Build DS core")
|
set(M_CORE_DS ON CACHE BOOL "Build DS core")
|
||||||
|
@ -402,6 +403,7 @@ find_feature(USE_MAGICK "MagickWand")
|
||||||
find_feature(USE_EPOXY "epoxy")
|
find_feature(USE_EPOXY "epoxy")
|
||||||
find_feature(USE_CMOCKA "cmocka")
|
find_feature(USE_CMOCKA "cmocka")
|
||||||
find_feature(USE_SQLITE3 "sqlite3")
|
find_feature(USE_SQLITE3 "sqlite3")
|
||||||
|
find_feature(USE_ELF "libelf")
|
||||||
find_feature(ENABLE_PYTHON "PythonLibs")
|
find_feature(ENABLE_PYTHON "PythonLibs")
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
|
@ -620,6 +622,17 @@ if(USE_SQLITE3)
|
||||||
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/sqlite3/no-intro.c")
|
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/sqlite3/no-intro.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(USE_ELF)
|
||||||
|
list(APPEND FEATURES ELF)
|
||||||
|
include_directories(AFTER ${LIBELF_INCLUDE_DIRS})
|
||||||
|
find_file(ELF_REPL_H elf_repl.h PATHS ${LIBELF_INCLUDE_DIRS})
|
||||||
|
if (ELF_REPL_H)
|
||||||
|
add_definitions(-DUSE_ELF_REPL)
|
||||||
|
endif()
|
||||||
|
list(APPEND DEPENDENCY_LIB ${LIBELF_LIBRARIES})
|
||||||
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libelfg0")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_SCRIPTING)
|
if(ENABLE_SCRIPTING)
|
||||||
list(APPEND ENABLES SCRIPTING)
|
list(APPEND ENABLES SCRIPTING)
|
||||||
|
|
||||||
|
@ -967,6 +980,7 @@ if(NOT QUIET)
|
||||||
message(STATUS " ZIP support: ${SUMMARY_ZIP}")
|
message(STATUS " ZIP support: ${SUMMARY_ZIP}")
|
||||||
message(STATUS " 7-Zip support: ${USE_LZMA}")
|
message(STATUS " 7-Zip support: ${USE_LZMA}")
|
||||||
message(STATUS " SQLite3 game database: ${USE_SQLITE3}")
|
message(STATUS " SQLite3 game database: ${USE_SQLITE3}")
|
||||||
|
message(STATUS " ELF loading support: ${USE_ELF}")
|
||||||
message(STATUS " OpenGL support: ${SUMMARY_GL}")
|
message(STATUS " OpenGL support: ${SUMMARY_GL}")
|
||||||
message(STATUS "Frontends:")
|
message(STATUS "Frontends:")
|
||||||
message(STATUS " Qt: ${BUILD_QT}")
|
message(STATUS " Qt: ${BUILD_QT}")
|
||||||
|
|
|
@ -160,6 +160,7 @@ medusa has no hard dependencies, however, the following optional dependencies ar
|
||||||
- libzip or zlib: for loading ROMs stored in zip files.
|
- libzip or zlib: for loading ROMs stored in zip files.
|
||||||
- ImageMagick: for GIF recording.
|
- ImageMagick: for GIF recording.
|
||||||
- SQLite3: for game databases.
|
- SQLite3: for game databases.
|
||||||
|
- libelf: for ELF loading.
|
||||||
|
|
||||||
SQLite3, libpng, and zlib are included with the emulator, so they do not need to be externally compiled first.
|
SQLite3, libpng, and zlib are included with the emulator, so they do not need to be externally compiled first.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* 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/. */
|
||||||
|
#ifndef ELF_READ_H
|
||||||
|
#define ELF_READ_H
|
||||||
|
|
||||||
|
#include <mgba-util/common.h>
|
||||||
|
|
||||||
|
CXX_GUARD_START
|
||||||
|
|
||||||
|
#ifdef USE_ELF
|
||||||
|
|
||||||
|
#include <libelf.h>
|
||||||
|
|
||||||
|
#if USE_ELF_REPL
|
||||||
|
#include <elf_repl.h>
|
||||||
|
#else
|
||||||
|
#include <elf.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mgba-util/vector.h>
|
||||||
|
|
||||||
|
struct ELF;
|
||||||
|
struct VFile;
|
||||||
|
|
||||||
|
DECLARE_VECTOR(ELFProgramHeaders, Elf32_Phdr);
|
||||||
|
DECLARE_VECTOR(ELFSectionHeaders, Elf32_Shdr);
|
||||||
|
|
||||||
|
struct ELF* ELFOpen(struct VFile*);
|
||||||
|
void ELFClose(struct ELF*);
|
||||||
|
|
||||||
|
void* ELFBytes(struct ELF*, size_t* size);
|
||||||
|
|
||||||
|
uint16_t ELFMachine(struct ELF*);
|
||||||
|
uint32_t ELFEntry(struct ELF*);
|
||||||
|
|
||||||
|
void ELFGetProgramHeaders(struct ELF*, struct ELFProgramHeaders*);
|
||||||
|
|
||||||
|
size_t ELFFindSection(struct ELF*, const char* name);
|
||||||
|
void ELFGetSectionHeaders(struct ELF*, struct ELFSectionHeaders*);
|
||||||
|
Elf32_Shdr* ELFGetSectionHeader(struct ELF*, size_t index);
|
||||||
|
|
||||||
|
const char* ELFGetString(struct ELF*, size_t section, size_t string);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
#endif
|
|
@ -196,6 +196,14 @@ void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config
|
||||||
|
|
||||||
void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc);
|
void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc);
|
||||||
|
|
||||||
|
void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size);
|
||||||
|
|
||||||
|
#ifdef USE_ELF
|
||||||
|
struct ELF;
|
||||||
|
bool mCoreLoadELF(struct mCore* core, struct ELF* elf);
|
||||||
|
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF*);
|
||||||
|
#endif
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct mScriptEngine {
|
||||||
bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
||||||
bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf);
|
||||||
void (*run)(struct mScriptEngine*);
|
void (*run)(struct mScriptEngine*);
|
||||||
|
bool (*lookupSymbol)(struct mScriptEngine*, const char* name, int32_t* out);
|
||||||
|
|
||||||
#ifdef USE_DEBUGGERS
|
#ifdef USE_DEBUGGERS
|
||||||
void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||||
|
@ -44,6 +45,8 @@ void mScriptBridgeDebuggerEntered(struct mScriptBridge*, enum mDebuggerEntryReas
|
||||||
void mScriptBridgeRun(struct mScriptBridge*);
|
void mScriptBridgeRun(struct mScriptBridge*);
|
||||||
bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
|
bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
|
||||||
|
|
||||||
|
bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -91,6 +91,7 @@ struct mDebugger {
|
||||||
struct mCPUComponent d;
|
struct mCPUComponent d;
|
||||||
struct mDebuggerPlatform* platform;
|
struct mDebuggerPlatform* platform;
|
||||||
enum mDebuggerState state;
|
enum mDebuggerState state;
|
||||||
|
enum mDebuggerType type;
|
||||||
struct mCore* core;
|
struct mCore* core;
|
||||||
struct mScriptBridge* bridge;
|
struct mScriptBridge* bridge;
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,7 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf);
|
||||||
void GBAApplyPatch(struct GBA* gba, struct Patch* patch);
|
void GBAApplyPatch(struct GBA* gba, struct Patch* patch);
|
||||||
|
|
||||||
bool GBALoadMB(struct GBA* gba, struct VFile* vf);
|
bool GBALoadMB(struct GBA* gba, struct VFile* vf);
|
||||||
|
bool GBALoadNull(struct GBA* gba);
|
||||||
|
|
||||||
bool GBAIsROM(struct VFile* vf);
|
bool GBAIsROM(struct VFile* vf);
|
||||||
bool GBAIsMB(struct VFile* vf);
|
bool GBAIsMB(struct VFile* vf);
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
#include <mgba/core/log.h>
|
#include <mgba/core/log.h>
|
||||||
#include <mgba/core/serialize.h>
|
#include <mgba/core/serialize.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
#include <mgba/internal/debugger/symbols.h>
|
||||||
|
|
||||||
|
#ifdef USE_ELF
|
||||||
|
#include <mgba-util/elf-read.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
#include <mgba/gb/core.h>
|
#include <mgba/gb/core.h>
|
||||||
|
@ -280,3 +285,67 @@ void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) {
|
||||||
core->rtc.custom = rtc;
|
core->rtc.custom = rtc;
|
||||||
core->rtc.override = RTC_CUSTOM_START;
|
core->rtc.override = RTC_CUSTOM_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size) {
|
||||||
|
const struct mCoreMemoryBlock* blocks;
|
||||||
|
size_t nBlocks = core->listMemoryBlocks(core, &blocks);
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < nBlocks; ++i) {
|
||||||
|
if (!(blocks[i].flags & mCORE_MEMORY_MAPPED)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (start < blocks[i].start) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (start >= blocks[i].start + blocks[i].size) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint8_t* out = core->getMemoryBlock(core, blocks[i].id, size);
|
||||||
|
out += start - blocks[i].start;
|
||||||
|
*size -= start - blocks[i].start;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ELF
|
||||||
|
bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
|
||||||
|
struct ELFProgramHeaders ph;
|
||||||
|
ELFProgramHeadersInit(&ph, 0);
|
||||||
|
ELFGetProgramHeaders(elf, &ph);
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < ELFProgramHeadersSize(&ph); ++i) {
|
||||||
|
size_t bsize, esize;
|
||||||
|
Elf32_Phdr* phdr = ELFProgramHeadersGetPointer(&ph, i);
|
||||||
|
void* block = mCoreGetMemoryBlock(core, phdr->p_paddr, &bsize);
|
||||||
|
char* bytes = ELFBytes(elf, &esize);
|
||||||
|
if (block && bsize >= phdr->p_filesz && esize >= phdr->p_filesz + phdr->p_offset) {
|
||||||
|
memcpy(block, &bytes[phdr->p_offset], phdr->p_filesz);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF* elf) {
|
||||||
|
size_t symIndex = ELFFindSection(elf, ".symtab");
|
||||||
|
size_t names = ELFFindSection(elf, ".strtab");
|
||||||
|
Elf32_Shdr* symHeader = ELFGetSectionHeader(elf, symIndex);
|
||||||
|
char* bytes = ELFBytes(elf, NULL);
|
||||||
|
|
||||||
|
Elf32_Sym* syms = (Elf32_Sym*) &bytes[symHeader->sh_offset];
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i * sizeof(*syms) < symHeader->sh_size; ++i) {
|
||||||
|
if (!syms[i].st_name || ELF32_ST_TYPE(syms[i].st_info) == STT_FILE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char* name = ELFGetString(elf, names, syms[i].st_name);
|
||||||
|
if (name[0] == '$') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mDebuggerSymbolAdd(symbols, name, syms[i].st_value, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -19,6 +19,12 @@ struct mScriptInfo {
|
||||||
bool success;
|
bool success;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mScriptSymbol {
|
||||||
|
const char* name;
|
||||||
|
int32_t* out;
|
||||||
|
bool success;
|
||||||
|
};
|
||||||
|
|
||||||
static void _seDeinit(void* value) {
|
static void _seDeinit(void* value) {
|
||||||
struct mScriptEngine* se = value;
|
struct mScriptEngine* se = value;
|
||||||
se->deinit(se);
|
se->deinit(se);
|
||||||
|
@ -33,6 +39,15 @@ static void _seTryLoad(const char* key, void* value, void* user) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _seLookupSymbol(const char* key, void* value, void* user) {
|
||||||
|
UNUSED(key);
|
||||||
|
struct mScriptEngine* se = value;
|
||||||
|
struct mScriptSymbol* si = user;
|
||||||
|
if (!si->success) {
|
||||||
|
si->success = se->lookupSymbol(se, si->name, si->out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void _seRun(const char* key, void* value, void* user) {
|
static void _seRun(const char* key, void* value, void* user) {
|
||||||
UNUSED(key);
|
UNUSED(key);
|
||||||
UNUSED(user);
|
UNUSED(user);
|
||||||
|
@ -111,3 +126,13 @@ bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) {
|
||||||
vf->close(vf);
|
vf->close(vf);
|
||||||
return info.success;
|
return info.success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mScriptBridgeLookupSymbol(struct mScriptBridge* sb, const char* name, int32_t* out) {
|
||||||
|
struct mScriptSymbol info = {
|
||||||
|
.name = name,
|
||||||
|
.out = out,
|
||||||
|
.success = false
|
||||||
|
};
|
||||||
|
HashTableEnumerate(&sb->engines, _seLookupSymbol, &info);
|
||||||
|
return info.success;
|
||||||
|
}
|
||||||
|
|
|
@ -551,6 +551,11 @@ static void _lookupIdentifier(struct mDebugger* debugger, const char* name, stru
|
||||||
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
|
||||||
if (cliDebugger->system) {
|
if (cliDebugger->system) {
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
|
#ifdef ENABLE_SCRIPTING
|
||||||
|
if (debugger->bridge && mScriptBridgeLookupSymbol(debugger->bridge, name, &dv->intValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, &dv->intValue, &dv->segmentValue)) {
|
if (debugger->core->symbolTable && mDebuggerSymbolLookup(debugger->core->symbolTable, name, &dv->intValue, &dv->segmentValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -832,6 +837,7 @@ void CLIDebuggerCreate(struct CLIDebugger* debugger) {
|
||||||
debugger->d.custom = _cliDebuggerCustom;
|
debugger->d.custom = _cliDebuggerCustom;
|
||||||
debugger->d.paused = _commandLine;
|
debugger->d.paused = _commandLine;
|
||||||
debugger->d.entered = _reportEntry;
|
debugger->d.entered = _reportEntry;
|
||||||
|
debugger->d.type = DEBUGGER_CLI;
|
||||||
|
|
||||||
debugger->system = NULL;
|
debugger->system = NULL;
|
||||||
debugger->backend = NULL;
|
debugger->backend = NULL;
|
||||||
|
|
|
@ -658,6 +658,7 @@ void GDBStubCreate(struct GDBStub* stub) {
|
||||||
stub->d.paused = _gdbStubWait;
|
stub->d.paused = _gdbStubWait;
|
||||||
stub->d.entered = _gdbStubEntered;
|
stub->d.entered = _gdbStubEntered;
|
||||||
stub->d.custom = _gdbStubPoll;
|
stub->d.custom = _gdbStubPoll;
|
||||||
|
stub->d.type = DEBUGGER_GDB;
|
||||||
stub->untilPoll = GDB_STUB_INTERVAL;
|
stub->untilPoll = GDB_STUB_INTERVAL;
|
||||||
stub->lineAck = GDB_ACK_PENDING;
|
stub->lineAck = GDB_ACK_PENDING;
|
||||||
stub->shouldBlock = false;
|
stub->shouldBlock = false;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
#include <mgba/core/log.h>
|
#include <mgba/core/log.h>
|
||||||
#include <mgba/internal/arm/debugger/debugger.h>
|
#include <mgba/internal/arm/debugger/debugger.h>
|
||||||
|
#include <mgba/internal/debugger/symbols.h>
|
||||||
#include <mgba/internal/gba/cheats.h>
|
#include <mgba/internal/gba/cheats.h>
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
#include <mgba/internal/gba/io.h>
|
#include <mgba/internal/gba/io.h>
|
||||||
|
@ -20,6 +21,9 @@
|
||||||
#include <mgba/internal/gba/renderers/video-software.h>
|
#include <mgba/internal/gba/renderers/video-software.h>
|
||||||
#include <mgba/internal/gba/savedata.h>
|
#include <mgba/internal/gba/savedata.h>
|
||||||
#include <mgba/internal/gba/serialize.h>
|
#include <mgba/internal/gba/serialize.h>
|
||||||
|
#ifdef USE_ELF
|
||||||
|
#include <mgba-util/elf-read.h>
|
||||||
|
#endif
|
||||||
#include <mgba-util/memory.h>
|
#include <mgba-util/memory.h>
|
||||||
#include <mgba-util/patch.h>
|
#include <mgba-util/patch.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
@ -318,6 +322,15 @@ static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
|
static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
|
||||||
|
#ifdef USE_ELF
|
||||||
|
struct ELF* elf = ELFOpen(vf);
|
||||||
|
if (elf) {
|
||||||
|
GBALoadNull(core->board);
|
||||||
|
bool success = mCoreLoadELF(core, elf);
|
||||||
|
ELFClose(elf);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (GBAIsMB(vf)) {
|
if (GBAIsMB(vf)) {
|
||||||
return GBALoadMB(core->board, vf);
|
return GBALoadMB(core->board, vf);
|
||||||
}
|
}
|
||||||
|
@ -718,7 +731,27 @@ static void _GBACoreDetachDebugger(struct mCore* core) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) {
|
static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) {
|
||||||
// TODO
|
#ifdef USE_ELF
|
||||||
|
bool closeAfter = false;
|
||||||
|
core->symbolTable = mDebuggerSymbolTableCreate();
|
||||||
|
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||||
|
if (!vf) {
|
||||||
|
closeAfter = true;
|
||||||
|
vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".elf", O_RDONLY);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!vf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct ELF* elf = ELFOpen(vf);
|
||||||
|
if (elf) {
|
||||||
|
mCoreLoadELFSymbols(core->symbolTable, elf);
|
||||||
|
ELFClose(elf);
|
||||||
|
}
|
||||||
|
if (closeAfter) {
|
||||||
|
vf->close(vf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
#include <mgba-util/memory.h>
|
#include <mgba-util/memory.h>
|
||||||
#include <mgba-util/vfs.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, "GBA", "gba");
|
||||||
mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug");
|
mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug");
|
||||||
|
|
||||||
|
@ -203,6 +207,10 @@ void GBAReset(struct ARMCore* cpu) {
|
||||||
|
|
||||||
gba->debug = false;
|
gba->debug = false;
|
||||||
memset(gba->debugString, 0, sizeof(gba->debugString));
|
memset(gba->debugString, 0, sizeof(gba->debugString));
|
||||||
|
|
||||||
|
if (!gba->romVf) {
|
||||||
|
GBASkipBIOS(gba);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASkipBIOS(struct GBA* gba) {
|
void GBASkipBIOS(struct GBA* gba) {
|
||||||
|
@ -288,6 +296,25 @@ void GBADetachDebugger(struct GBA* gba) {
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
|
||||||
GBAUnloadROM(gba);
|
GBAUnloadROM(gba);
|
||||||
gba->romVf = vf;
|
gba->romVf = vf;
|
||||||
|
@ -478,6 +505,17 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GBAIsROM(struct VFile* vf) {
|
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) {
|
if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -495,6 +533,14 @@ bool GBAIsMB(struct VFile* vf) {
|
||||||
if (!GBAIsROM(vf)) {
|
if (!GBAIsROM(vf)) {
|
||||||
return false;
|
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) {
|
if (vf->size(vf) > SIZE_WORKING_RAM) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,8 @@ void GBAMemoryInit(struct GBA* gba) {
|
||||||
gba->memory.biosPrefetch = 0;
|
gba->memory.biosPrefetch = 0;
|
||||||
gba->memory.mirroring = false;
|
gba->memory.mirroring = false;
|
||||||
|
|
||||||
|
gba->memory.iwram = anonymousMemoryMap(SIZE_WORKING_IRAM);
|
||||||
|
|
||||||
GBADMAInit(gba);
|
GBADMAInit(gba);
|
||||||
GBAVFameInit(&gba->memory.vfame);
|
GBAVFameInit(&gba->memory.vfame);
|
||||||
}
|
}
|
||||||
|
@ -107,9 +109,8 @@ void GBAMemoryReset(struct GBA* gba) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gba->memory.iwram) {
|
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));
|
memset(gba->memory.io, 0, sizeof(gba->memory.io));
|
||||||
|
|
||||||
|
|
|
@ -58,4 +58,5 @@ void free(void*);
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_DEBUGGERS
|
#ifdef USE_DEBUGGERS
|
||||||
#include <mgba/debugger/debugger.h>
|
#include <mgba/debugger/debugger.h>
|
||||||
|
#include <mgba/internal/debugger/cli-debugger.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,6 +28,7 @@ ffi.set_source("mgba._pylib", """
|
||||||
#include <mgba/core/version.h>
|
#include <mgba/core/version.h>
|
||||||
#include <mgba/debugger/debugger.h>
|
#include <mgba/debugger/debugger.h>
|
||||||
#include <mgba/internal/arm/arm.h>
|
#include <mgba/internal/arm/arm.h>
|
||||||
|
#include <mgba/internal/debugger/cli-debugger.h>
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
#include <mgba/internal/gba/input.h>
|
#include <mgba/internal/gba/input.h>
|
||||||
#include <mgba/internal/gba/renderers/tile-cache.h>
|
#include <mgba/internal/gba/renderers/tile-cache.h>
|
||||||
|
@ -70,17 +71,27 @@ for line in preprocessed.splitlines():
|
||||||
ffi.embedding_api('\n'.join(lines))
|
ffi.embedding_api('\n'.join(lines))
|
||||||
|
|
||||||
ffi.embedding_init_code("""
|
ffi.embedding_init_code("""
|
||||||
from mgba._pylib import ffi
|
from mgba._pylib import ffi, lib
|
||||||
debugger = None
|
symbols = {}
|
||||||
|
globalSyms = {
|
||||||
|
'symbols': symbols
|
||||||
|
}
|
||||||
pendingCode = []
|
pendingCode = []
|
||||||
|
|
||||||
@ffi.def_extern()
|
@ffi.def_extern()
|
||||||
def mPythonSetDebugger(_debugger):
|
def mPythonSetDebugger(debugger):
|
||||||
from mgba.debugger import NativeDebugger
|
from mgba.debugger import NativeDebugger, CLIDebugger
|
||||||
global debugger
|
oldDebugger = globalSyms.get('debugger')
|
||||||
if debugger and debugger._native == _debugger:
|
if oldDebugger and oldDebugger._native == debugger:
|
||||||
return
|
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()
|
@ffi.def_extern()
|
||||||
def mPythonLoadScript(name, vf):
|
def mPythonLoadScript(name, vf):
|
||||||
|
@ -99,18 +110,40 @@ ffi.embedding_init_code("""
|
||||||
def mPythonRunPending():
|
def mPythonRunPending():
|
||||||
global pendingCode
|
global pendingCode
|
||||||
for code in pendingCode:
|
for code in pendingCode:
|
||||||
exec(code)
|
exec(code, globalSyms, {})
|
||||||
pendingCode = []
|
pendingCode = []
|
||||||
|
|
||||||
@ffi.def_extern()
|
@ffi.def_extern()
|
||||||
def mPythonDebuggerEntered(reason, info):
|
def mPythonDebuggerEntered(reason, info):
|
||||||
global debugger
|
debugger = globalSyms['debugger']
|
||||||
if not debugger:
|
if not debugger:
|
||||||
return
|
return
|
||||||
if info == ffi.NULL:
|
if info == ffi.NULL:
|
||||||
info = None
|
info = None
|
||||||
for cb in debugger._cbs:
|
for cb in debugger._cbs:
|
||||||
cb(reason, info)
|
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__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -21,6 +21,7 @@ static void mPythonScriptEngineDeinit(struct mScriptEngine*);
|
||||||
static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf);
|
static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf);
|
||||||
static bool mPythonScriptEngineLoadScript(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 void mPythonScriptEngineRun(struct mScriptEngine*);
|
||||||
|
static bool mPythonScriptEngineLookupSymbol(struct mScriptEngine*, const char* name, int32_t* out);
|
||||||
|
|
||||||
#ifdef USE_DEBUGGERS
|
#ifdef USE_DEBUGGERS
|
||||||
static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
|
||||||
|
@ -39,6 +40,7 @@ struct mPythonScriptEngine* mPythonCreateScriptEngine(void) {
|
||||||
engine->d.isScript = mPythonScriptEngineIsScript;
|
engine->d.isScript = mPythonScriptEngineIsScript;
|
||||||
engine->d.loadScript = mPythonScriptEngineLoadScript;
|
engine->d.loadScript = mPythonScriptEngineLoadScript;
|
||||||
engine->d.run = mPythonScriptEngineRun;
|
engine->d.run = mPythonScriptEngineRun;
|
||||||
|
engine->d.lookupSymbol = mPythonScriptEngineLookupSymbol;
|
||||||
#ifdef USE_DEBUGGERS
|
#ifdef USE_DEBUGGERS
|
||||||
engine->d.debuggerEntered = mPythonScriptDebuggerEntered;
|
engine->d.debuggerEntered = mPythonScriptDebuggerEntered;
|
||||||
#endif
|
#endif
|
||||||
|
@ -89,6 +91,11 @@ void mPythonScriptEngineRun(struct mScriptEngine* se) {
|
||||||
mPythonRunPending();
|
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
|
#ifdef USE_DEBUGGERS
|
||||||
void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
|
||||||
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
|
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
|
||||||
|
|
|
@ -4,6 +4,7 @@ struct VFile;
|
||||||
|
|
||||||
extern bool mPythonLoadScript(const char*, struct VFile*);
|
extern bool mPythonLoadScript(const char*, struct VFile*);
|
||||||
extern void mPythonRunPending();
|
extern void mPythonRunPending();
|
||||||
|
extern bool mPythonLookupSymbol(const char* name, int32_t* out);
|
||||||
|
|
||||||
#ifdef USE_DEBUGGERS
|
#ifdef USE_DEBUGGERS
|
||||||
extern void mPythonSetDebugger(struct mDebugger*);
|
extern void mPythonSetDebugger(struct mDebugger*);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
from ._pylib import ffi, lib
|
from ._pylib import ffi, lib
|
||||||
from .core import IRunner, ICoreOwner, Core
|
from .core import IRunner, ICoreOwner, Core
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
|
||||||
class DebuggerCoreOwner(ICoreOwner):
|
class DebuggerCoreOwner(ICoreOwner):
|
||||||
def __init__(self, debugger):
|
def __init__(self, debugger):
|
||||||
|
@ -78,3 +80,22 @@ class NativeDebugger(IRunner):
|
||||||
|
|
||||||
def addCallback(self, cb):
|
def addCallback(self, cb):
|
||||||
self._cbs.append(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)
|
||||||
|
|
|
@ -155,7 +155,9 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
|
||||||
#endif
|
#endif
|
||||||
m_screenWidget->setPixmap(m_logo);
|
m_screenWidget->setPixmap(m_logo);
|
||||||
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
|
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
|
||||||
|
m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
|
||||||
m_screenWidget->setLockIntegerScaling(false);
|
m_screenWidget->setLockIntegerScaling(false);
|
||||||
|
m_screenWidget->setLockAspectRatio(true);
|
||||||
setCentralWidget(m_screenWidget);
|
setCentralWidget(m_screenWidget);
|
||||||
|
|
||||||
connect(m_controller, &GameController::gameStarted, this, &Window::gameStarted);
|
connect(m_controller, &GameController::gameStarted, this, &Window::gameStarted);
|
||||||
|
@ -173,7 +175,6 @@ Window::Window(ConfigController* config, int playerId, QWidget* parent)
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
pixmap.convertFromImage(currentImage);
|
pixmap.convertFromImage(currentImage);
|
||||||
m_screenWidget->setPixmap(pixmap);
|
m_screenWidget->setPixmap(pixmap);
|
||||||
m_screenWidget->setLockAspectRatio(width, height);
|
|
||||||
});
|
});
|
||||||
connect(m_controller, &GameController::gamePaused, m_display, &Display::pauseDrawing);
|
connect(m_controller, &GameController::gamePaused, m_display, &Display::pauseDrawing);
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
|
@ -803,7 +804,9 @@ void Window::gameStarted(mCoreThread* context, const QString& fname) {
|
||||||
context->core->desiredVideoDimensions(context->core, &width, &height);
|
context->core->desiredVideoDimensions(context->core, &width, &height);
|
||||||
m_display->setMinimumSize(width, height);
|
m_display->setMinimumSize(width, height);
|
||||||
m_screenWidget->setMinimumSize(m_display->minimumSize());
|
m_screenWidget->setMinimumSize(m_display->minimumSize());
|
||||||
|
m_screenWidget->setDimensions(width, height);
|
||||||
m_config->updateOption("lockIntegerScaling");
|
m_config->updateOption("lockIntegerScaling");
|
||||||
|
m_config->updateOption("lockAspectRatio");
|
||||||
if (m_savedScale > 0) {
|
if (m_savedScale > 0) {
|
||||||
resizeFrame(QSize(width, height) * m_savedScale);
|
resizeFrame(QSize(width, height) * m_savedScale);
|
||||||
}
|
}
|
||||||
|
@ -867,7 +870,9 @@ void Window::gameStopped() {
|
||||||
updateTitle();
|
updateTitle();
|
||||||
detachWidget(m_display);
|
detachWidget(m_display);
|
||||||
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
|
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
|
||||||
|
m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
|
||||||
m_screenWidget->setLockIntegerScaling(false);
|
m_screenWidget->setLockIntegerScaling(false);
|
||||||
|
m_screenWidget->setLockAspectRatio(true);
|
||||||
m_screenWidget->setPixmap(m_logo);
|
m_screenWidget->setPixmap(m_logo);
|
||||||
m_screenWidget->unsetCursor();
|
m_screenWidget->unsetCursor();
|
||||||
#ifdef M_CORE_GB
|
#ifdef M_CORE_GB
|
||||||
|
@ -1341,6 +1346,9 @@ void Window::setupMenu(QMenuBar* menubar) {
|
||||||
lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu);
|
lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu);
|
||||||
lockAspectRatio->connect([this](const QVariant& value) {
|
lockAspectRatio->connect([this](const QVariant& value) {
|
||||||
m_display->lockAspectRatio(value.toBool());
|
m_display->lockAspectRatio(value.toBool());
|
||||||
|
if (m_controller->isLoaded()) {
|
||||||
|
m_screenWidget->setLockAspectRatio(value.toBool());
|
||||||
|
}
|
||||||
}, this);
|
}, this);
|
||||||
m_config->updateOption("lockAspectRatio");
|
m_config->updateOption("lockAspectRatio");
|
||||||
|
|
||||||
|
@ -1670,14 +1678,13 @@ QSize WindowBackground::sizeHint() const {
|
||||||
return m_sizeHint;
|
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) {
|
void WindowBackground::setCenteredAspectRatio(int width, int height) {
|
||||||
m_centered = true;
|
m_centered = true;
|
||||||
|
m_lockAspectRatio = true;
|
||||||
|
setDimensions(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowBackground::setDimensions(int width, int height) {
|
||||||
m_aspectWidth = width;
|
m_aspectWidth = width;
|
||||||
m_aspectHeight = height;
|
m_aspectHeight = height;
|
||||||
}
|
}
|
||||||
|
@ -1686,6 +1693,11 @@ void WindowBackground::setLockIntegerScaling(bool lock) {
|
||||||
m_lockIntegerScaling = lock;
|
m_lockIntegerScaling = lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowBackground::setLockAspectRatio(bool lock) {
|
||||||
|
m_centered = false;
|
||||||
|
m_lockAspectRatio = lock;
|
||||||
|
}
|
||||||
|
|
||||||
void WindowBackground::paintEvent(QPaintEvent*) {
|
void WindowBackground::paintEvent(QPaintEvent*) {
|
||||||
const QPixmap* logo = pixmap();
|
const QPixmap* logo = pixmap();
|
||||||
if (!logo) {
|
if (!logo) {
|
||||||
|
@ -1702,7 +1714,7 @@ void WindowBackground::paintEvent(QPaintEvent*) {
|
||||||
} else if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
|
} else if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
|
||||||
ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth);
|
ds.setHeight(ds.width() * m_aspectHeight / m_aspectWidth);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (m_lockAspectRatio) {
|
||||||
if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
|
if (ds.width() * m_aspectHeight > ds.height() * m_aspectWidth) {
|
||||||
ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight);
|
ds.setWidth(ds.height() * m_aspectWidth / m_aspectHeight);
|
||||||
} else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) {
|
} else if (ds.width() * m_aspectHeight < ds.height() * m_aspectWidth) {
|
||||||
|
|
|
@ -210,9 +210,10 @@ public:
|
||||||
|
|
||||||
void setSizeHint(const QSize& size);
|
void setSizeHint(const QSize& size);
|
||||||
virtual QSize sizeHint() const override;
|
virtual QSize sizeHint() const override;
|
||||||
void setLockAspectRatio(int width, int height);
|
void setDimensions(int width, int height);
|
||||||
void setCenteredAspectRatio(int width, int height);
|
void setCenteredAspectRatio(int width, int height);
|
||||||
void setLockIntegerScaling(bool lock);
|
void setLockIntegerScaling(bool lock);
|
||||||
|
void setLockAspectRatio(bool lock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void paintEvent(QPaintEvent*) override;
|
virtual void paintEvent(QPaintEvent*) override;
|
||||||
|
@ -222,6 +223,7 @@ private:
|
||||||
bool m_centered;
|
bool m_centered;
|
||||||
int m_aspectWidth;
|
int m_aspectWidth;
|
||||||
int m_aspectHeight;
|
int m_aspectHeight;
|
||||||
|
bool m_lockAspectRatio;
|
||||||
bool m_lockIntegerScaling;
|
bool m_lockIntegerScaling;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <mgba/core/cheats.h>
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
#include <mgba/core/config.h>
|
#include <mgba/core/config.h>
|
||||||
#include <mgba/core/input.h>
|
#include <mgba/core/input.h>
|
||||||
|
@ -104,6 +105,16 @@ int main(int argc, char** argv) {
|
||||||
return 1;
|
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);
|
mInputMapInit(&renderer.core->inputMap, renderer.core->inputInfo);
|
||||||
mCoreInitConfig(renderer.core, PORT);
|
mCoreInitConfig(renderer.core, PORT);
|
||||||
applyArguments(&args, &subparser, &renderer.core->config);
|
applyArguments(&args, &subparser, &renderer.core->config);
|
||||||
|
@ -148,6 +159,10 @@ int main(int argc, char** argv) {
|
||||||
mSDLDetachPlayer(&renderer.events, &renderer.player);
|
mSDLDetachPlayer(&renderer.events, &renderer.player);
|
||||||
mInputMapDeinit(&renderer.core->inputMap);
|
mInputMapDeinit(&renderer.core->inputMap);
|
||||||
|
|
||||||
|
if (device) {
|
||||||
|
mCheatDeviceDestroy(device);
|
||||||
|
}
|
||||||
|
|
||||||
mSDLDeinit(&renderer);
|
mSDLDeinit(&renderer);
|
||||||
|
|
||||||
freeArguments(&args);
|
freeArguments(&args);
|
||||||
|
@ -184,10 +199,10 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
|
||||||
#endif
|
#endif
|
||||||
mDebuggerAttach(debugger, renderer->core);
|
mDebuggerAttach(debugger, renderer->core);
|
||||||
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
|
mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
|
||||||
}
|
#ifdef ENABLE_SCRIPTING
|
||||||
#ifdef ENABLE_SCRIPTING
|
|
||||||
mScriptBridgeSetDebugger(bridge, debugger);
|
mScriptBridgeSetDebugger(bridge, debugger);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (args->patch) {
|
if (args->patch) {
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue