Merge branch 'master' into translations

This commit is contained in:
Vicki Pfau 2022-07-17 22:53:02 -07:00
commit f941d27b0a
102 changed files with 50722 additions and 47712 deletions

View File

@ -50,6 +50,8 @@ Emulation fixes:
- GBA Video: Fix sprite layer priority updating in GL
Other fixes:
- ARM: Disassemble Thumb mov pseudo-instruction properly
- ARM: Disassemble ARM asr/lsr #32 properly
- ARM: Disassemble ARM movs properly
- Core: Don't attempt to restore rewind diffs past start of rewind
- Core: Fix the runloop resuming after a game has crashed (fixes mgba.io/i/2451)
- Core: Fix crash if library can't be opened
@ -64,6 +66,7 @@ Other fixes:
- Qt: Fix crash when clicking past last tile in viewer
- Qt: Fix preloading for ROM replacing
- Qt: Fix screen not displaying on Wayland (fixes mgba.io/i/2190)
- Qt: Fix crash when selecting 256-color sprite in sprite view
- VFS: Failed file mapping should return NULL on POSIX
Misc:
- Core: Suspend runloop when a core crashes

View File

@ -754,6 +754,7 @@ if(ENABLE_SCRIPTING)
include_directories(AFTER ${LUA_INCLUDE_DIR})
list(APPEND FEATURE_DEFINES LUA_VERSION_ONLY=\"${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}\")
list(APPEND DEPENDENCY_LIB ${LUA_LIBRARY})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},liblua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}-0")
endif()
if(BUILD_PYTHON)

View File

@ -122,13 +122,15 @@ Compiling requires using CMake 3.1 or newer. GCC and Clang are both known to wor
#### Docker building
The recommended way to build for most platforms is to use Docker. Several Docker images are provided that contain the requisite toolchain and dependencies for building mGBA across several platforms.
The recommended way to build for most platforms is to use Docker. Several Docker images are provided that contain the requisite toolchain and dependencies for building mGBA across several platforms.
Note: If you are on an older Windows system before Windows 10, you may need to configure your Docker to use VirtualBox shared folders to correctly map your current `mgba` checkout directory to the Docker image's working directory. (See issue [#1985](https://mgba.io/i/1985) for details.)
To use a Docker image to build mGBA, simply run the following command while in the root of an mGBA checkout:
docker run --rm -t -v ${PWD}:/home/mgba/src mgba/windows:w32
docker run --rm -it -v ${PWD}:/home/mgba/src mgba/windows:w32
This will produce a `build-win32` directory with the build products. Replace `mgba/windows:w32` with another Docker image for other platforms, which will produce a corresponding other directory. The following Docker images available on Docker Hub:
After starting the Docker container, it will produce a `build-win32` directory with the build products. Replace `mgba/windows:w32` with another Docker image for other platforms, which will produce a corresponding other directory. The following Docker images available on Docker Hub:
- mgba/3ds
- mgba/switch
@ -141,6 +143,8 @@ This will produce a `build-win32` directory with the build products. Replace `mg
- mgba/windows:w32
- mgba/windows:w64
If you want to speed up the build process, consider adding the flag `-e MAKEFLAGS=-jN` to do a parallel build for mGBA with `N` number of CPU cores.
#### *nix building
To use CMake to build on a Unix-based system, the recommended commands are as follows:

View File

@ -86,6 +86,7 @@ struct mCore {
bool (*loadSave)(struct mCore*, struct VFile* vf);
bool (*loadTemporarySave)(struct mCore*, struct VFile* vf);
void (*unloadROM)(struct mCore*);
size_t (*romSize)(const struct mCore*);
void (*checksum)(const struct mCore*, void* data, enum mCoreChecksumType type);
bool (*loadBIOS)(struct mCore*, struct VFile* vf, int biosID);

View File

@ -36,6 +36,12 @@ struct mLogger {
struct mLogFilter* filter;
};
struct mStandardLogger {
struct mLogger d;
bool logToStdout;
struct VFile* logFile;
};
struct mLogger* mLogGetContext(void);
void mLogSetDefaultLogger(struct mLogger*);
int mLogGenerateCategory(const char*, const char*);
@ -44,6 +50,10 @@ const char* mLogCategoryId(int);
int mLogCategoryById(const char*);
struct mCoreConfig;
void mStandardLoggerInit(struct mStandardLogger*);
void mStandardLoggerDeinit(struct mStandardLogger*);
void mStandardLoggerConfig(struct mStandardLogger*, struct mCoreConfig* config);
void mLogFilterInit(struct mLogFilter*);
void mLogFilterDeinit(struct mLogFilter*);
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);

View File

@ -21,6 +21,7 @@ struct mCoreThread;
struct mThreadLogger {
struct mLogger d;
struct mCoreThread* p;
struct mLogger* logger;
};
#ifdef ENABLE_SCRIPTING

View File

@ -67,10 +67,11 @@ struct ParseTree {
};
size_t lexExpression(struct LexVector* lv, const char* string, size_t length, const char* eol);
void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv);
void lexFree(struct LexVector* lv);
struct ParseTree* parseTreeCreate(void);
void parseFree(struct ParseTree* tree);
bool parseLexedExpression(struct ParseTree* tree, struct LexVector* lv);
struct mDebugger;
bool mDebuggerEvaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, int32_t* value, int* segment);

View File

@ -155,6 +155,7 @@ struct GBAVideoGLRenderer {
GLuint vbo;
GLuint outputTex;
bool outputTexDirty;
GLuint paletteTex;
uint16_t shadowPalette[GBA_VIDEO_VERTICAL_PIXELS][512];

BIN
res/gb-icon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

BIN
res/gb-icon-24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

BIN
res/gb-icon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
res/gba-icon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

BIN
res/gba-icon-24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

BIN
res/gba-icon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
res/gbc-icon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

BIN
res/gbc-icon-24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

BIN
res/gbc-icon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

View File

@ -19,6 +19,9 @@
info->operandFormat |= ARM_OPERAND_SHIFT_REGISTER_3; \
} else { \
info->op3.shifterImm = (opcode >> 7) & 0x1F; \
if (!info->op3.shifterImm && (ARM_SHIFT_ ## OP == ARM_SHIFT_LSR || ARM_SHIFT_ ## OP == ARM_SHIFT_ASR)) { \
info->op3.shifterImm = 32; \
} \
info->operandFormat |= ARM_OPERAND_SHIFT_IMMEDIATE_3; \
}

View File

@ -416,6 +416,7 @@ int ARMDisassemble(const struct ARMInstructionInfo* info, struct ARMCore* cpu, c
case ARM_MN_LSR:
case ARM_MN_MLA:
case ARM_MN_MUL:
case ARM_MN_MOV:
case ARM_MN_MVN:
case ARM_MN_ORR:
case ARM_MN_ROR:

View File

@ -7,8 +7,10 @@
#include <mgba/core/config.h>
#include <mgba/core/thread.h>
#include <mgba-util/vfs.h>
#define MAX_CATEGORY 64
#define MAX_LOG_BUF 1024
static struct mLogger* _defaultLogger = NULL;
@ -183,4 +185,63 @@ int mLogFilterLevels(const struct mLogFilter* filter , int category) {
return value;
}
void _mCoreStandardLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
struct mStandardLogger* stdlog = (struct mStandardLogger*) logger;
if (!mLogFilterTest(logger->filter, category, level)) {
return;
}
char buffer[MAX_LOG_BUF];
// Prepare the string
size_t length = snprintf(buffer, sizeof(buffer), "%s: ", mLogCategoryName(category));
if (length < sizeof(buffer)) {
length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
}
if (length < sizeof(buffer)) {
length += snprintf(buffer + length, sizeof(buffer) - length, "\n");
}
// Make sure the length doesn't exceed the size of the buffer when actually writing
if (length > sizeof(buffer)) {
length = sizeof(buffer);
}
if (stdlog->logToStdout) {
printf("%s", buffer);
}
if (stdlog->logFile) {
stdlog->logFile->write(stdlog->logFile, buffer, length);
}
}
void mStandardLoggerInit(struct mStandardLogger* logger) {
logger->d.log = _mCoreStandardLog;
logger->d.filter = malloc(sizeof(struct mLogFilter));
mLogFilterInit(logger->d.filter);
}
void mStandardLoggerDeinit(struct mStandardLogger* logger) {
if (logger->d.filter) {
mLogFilterDeinit(logger->d.filter);
free(logger->d.filter);
logger->d.filter = NULL;
}
}
void mStandardLoggerConfig(struct mStandardLogger* logger, struct mCoreConfig* config) {
bool logToFile = false;
const char* logFile = mCoreConfigGetValue(config, "logFile");
mCoreConfigGetBoolValue(config, "logToStdout", &logger->logToStdout);
mCoreConfigGetBoolValue(config, "logToFile", &logToFile);
if (logToFile && logFile) {
logger->logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
}
mLogFilterLoad(logger->d.filter, config);
}
mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")

View File

@ -215,19 +215,19 @@ static struct mScriptValue* mScriptMemoryDomainReadRange(struct mScriptMemoryDom
static void mScriptMemoryDomainWrite8(struct mScriptMemoryDomain* adapter, uint32_t address, uint8_t value) {
CALCULATE_SEGMENT_INFO;
CALCULATE_SEGMENT_ADDRESS;
adapter->core->rawWrite8(adapter->core, address, segmentAddress, value);
adapter->core->rawWrite8(adapter->core, segmentAddress, segment, value);
}
static void mScriptMemoryDomainWrite16(struct mScriptMemoryDomain* adapter, uint32_t address, uint16_t value) {
CALCULATE_SEGMENT_INFO;
CALCULATE_SEGMENT_ADDRESS;
adapter->core->rawWrite16(adapter->core, address, segmentAddress, value);
adapter->core->rawWrite16(adapter->core, segmentAddress, segment, value);
}
static void mScriptMemoryDomainWrite32(struct mScriptMemoryDomain* adapter, uint32_t address, uint32_t value) {
CALCULATE_SEGMENT_INFO;
CALCULATE_SEGMENT_ADDRESS;
adapter->core->rawWrite32(adapter->core, address, segmentAddress, value);
adapter->core->rawWrite32(adapter->core, segmentAddress, segment, value);
}
static uint32_t mScriptMemoryDomainBase(struct mScriptMemoryDomain* adapter) {
@ -424,6 +424,7 @@ mSCRIPT_DECLARE_STRUCT_CD_METHOD(mCore, S32, frameCycles, 0);
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mCore, S32, frequency, 0);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mCore, WSTR, getGameTitle, _mScriptCoreGetGameTitle, 0);
mSCRIPT_DECLARE_STRUCT_C_METHOD(mCore, WSTR, getGameCode, _mScriptCoreGetGameCode, 0);
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mCore, S64, romSize, 0);
mSCRIPT_DECLARE_STRUCT_C_METHOD_WITH_DEFAULTS(mCore, WSTR, checksum, _mScriptCoreChecksum, 1, S32, type);
// Run functions
@ -483,6 +484,8 @@ mSCRIPT_DEFINE_STRUCT(mCore)
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, frameCycles)
mSCRIPT_DEFINE_DOCSTRING("Get the number of cycles per second")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, frequency)
mSCRIPT_DEFINE_DOCSTRING("Get the size of the loaded ROM")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, romSize)
mSCRIPT_DEFINE_DOCSTRING("Get the checksum of the loaded ROM")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, checksum)

View File

@ -253,10 +253,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
core->setSync(core, &threadContext->impl->sync);
struct mLogFilter filter;
if (!threadContext->logger.d.filter) {
threadContext->logger.d.filter = &filter;
mLogFilterInit(threadContext->logger.d.filter);
mLogFilterLoad(threadContext->logger.d.filter, &core->config);
struct mLogger* logger = &threadContext->logger.d;
if (threadContext->logger.logger) {
logger->filter = threadContext->logger.logger->filter;
} else {
logger->filter = &filter;
mLogFilterInit(logger->filter);
mLogFilterLoad(logger->filter, &core->config);
}
#ifdef ENABLE_SCRIPTING
@ -431,10 +434,10 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
#endif
core->clearCoreCallbacks(core);
if (threadContext->logger.d.filter == &filter) {
if (logger->filter == &filter) {
mLogFilterDeinit(&filter);
}
threadContext->logger.d.filter = NULL;
logger->filter = NULL;
return 0;
}
@ -444,10 +447,8 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
threadContext->impl->state = mTHREAD_INITIALIZED;
threadContext->impl->requested = 0;
threadContext->logger.p = threadContext;
if (!threadContext->logger.d.log) {
threadContext->logger.d.log = _mCoreLog;
threadContext->logger.d.filter = NULL;
}
threadContext->logger.d.log = _mCoreLog;
threadContext->logger.d.filter = NULL;
if (!threadContext->impl->sync.fpsTarget) {
threadContext->impl->sync.fpsTarget = _defaultFPSTarget;
@ -718,14 +719,17 @@ struct mCoreThread* mCoreThreadGet(void) {
}
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
UNUSED(logger);
UNUSED(level);
printf("%s: ", mLogCategoryName(category));
vprintf(format, args);
printf("\n");
struct mCoreThread* thread = mCoreThreadGet();
if (thread && level == mLOG_FATAL) {
mCoreThreadMarkCrashed(thread);
struct mThreadLogger* threadLogger = (struct mThreadLogger*) logger;
if (level == mLOG_FATAL) {
mCoreThreadMarkCrashed(threadLogger->p);
}
if (!threadLogger->p->logger.logger) {
printf("%s: ", mLogCategoryName(category));
vprintf(format, args);
printf("\n");
} else {
logger = threadLogger->p->logger.logger;
logger->log(logger, category, level, format, args);
}
}
#else

View File

@ -588,7 +588,7 @@ static struct ParseTree* _parseTree(const char** string) {
}
struct ParseTree* tree = NULL;
if (!error) {
tree = malloc(sizeof(*tree));
tree = parseTreeCreate();
parseLexedExpression(tree, &lv);
}
lexFree(&lv);
@ -796,17 +796,16 @@ struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* stri
dvTemp.type = CLIDV_ERROR_TYPE;
}
struct ParseTree tree;
parseLexedExpression(&tree, &lv);
if (tree.token.type == TOKEN_ERROR_TYPE) {
struct ParseTree* tree = parseTreeCreate();
if (!parseLexedExpression(tree, &lv)) {
dvTemp.type = CLIDV_ERROR_TYPE;
} else {
if (!mDebuggerEvaluateParseTree(&debugger->d, &tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
if (!mDebuggerEvaluateParseTree(&debugger->d, tree, &dvTemp.intValue, &dvTemp.segmentValue)) {
dvTemp.type = CLIDV_ERROR_TYPE;
}
}
parseFree(&tree);
parseFree(tree);
lexFree(&lv);
LexVectorDeinit(&lv);

View File

@ -495,7 +495,7 @@ static const int _operatorPrecedence[] = {
[OP_DEREFERENCE] = 2,
};
static struct ParseTree* _parseTreeCreate(void) {
struct ParseTree* parseTreeCreate(void) {
struct ParseTree* tree = malloc(sizeof(struct ParseTree));
tree->token.type = TOKEN_ERROR_TYPE;
tree->p = NULL;
@ -529,12 +529,12 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, int
}
break;
case TOKEN_SEGMENT_TYPE:
tree->lhs = _parseTreeCreate();
tree->lhs = parseTreeCreate();
tree->lhs->token.type = TOKEN_UINT_TYPE;
tree->lhs->token.uintValue = token->uintValue;
tree->lhs->p = tree;
tree->lhs->precedence = precedence;
tree->rhs = _parseTreeCreate();
tree->rhs = parseTreeCreate();
tree->rhs->p = tree;
tree->rhs->precedence = precedence;
tree->token.type = TOKEN_SEGMENT_TYPE;
@ -572,7 +572,7 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, int
}
newPrecedence = _operatorPrecedence[token->operatorValue];
if (newPrecedence < precedence) {
newTree = _parseTreeCreate();
newTree = parseTreeCreate();
memcpy(newTree, tree, sizeof(*tree));
if (newTree->lhs) {
newTree->lhs->p = newTree;
@ -582,7 +582,7 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, int
}
newTree->p = tree;
tree->lhs = newTree;
tree->rhs = _parseTreeCreate();
tree->rhs = parseTreeCreate();
tree->rhs->p = tree;
tree->rhs->precedence = newPrecedence;
precedence = newPrecedence;
@ -617,9 +617,9 @@ static size_t _parseExpression(struct ParseTree* tree, struct LexVector* lv, int
return i;
}
void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv) {
bool parseLexedExpression(struct ParseTree* tree, struct LexVector* lv) {
if (!tree) {
return;
return false;
}
tree->token.type = TOKEN_ERROR_TYPE;
@ -636,6 +636,7 @@ void parseLexedExpression(struct ParseTree* tree, struct LexVector* lv) {
}
tree->token.type = TOKEN_ERROR_TYPE;
}
return tree->token.type != TOKEN_ERROR_TYPE;
}
void lexFree(struct LexVector* lv) {

View File

@ -260,8 +260,16 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
free((void*) buffer.name);
free((void*) buffer.romName);
free((void*) dbType);
free((void*) dbVersion);
if (dbType) {
free(dbType);
}
if (dbVersion) {
free(dbVersion);
}
if (fieldName) {
free(fieldName);
}
sqlite3_finalize(gamedbTable);
sqlite3_finalize(gamedbDrop);

View File

@ -92,7 +92,7 @@ bool mUpdaterInit(struct mUpdaterContext* context, const char* manifest) {
ConfigurationInit(&context->manifest);
struct VFile* vf = VFileFromConstMemory(manifest, strlen(manifest) + 1);
bool success = vf && ConfigurationReadVFile(&context->manifest, vf);
bool success = ConfigurationReadVFile(&context->manifest, vf);
vf->close(vf);
if (!success) {
ConfigurationDeinit(&context->manifest);

View File

@ -473,8 +473,16 @@ static void _GBCoreUnloadROM(struct mCore* core) {
GBUnloadROM(core->board);
}
static size_t _GBCoreROMSize(const struct mCore* core) {
const struct GB* gb = (const struct GB*) core->board;
if (gb->romVf) {
return gb->romVf->size(gb->romVf);
}
return gb->pristineRomSize;
}
static void _GBCoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
struct GB* gb = (struct GB*) core->board;
const struct GB* gb = (const struct GB*) core->board;
switch (type) {
case mCHECKSUM_CRC32:
memcpy(data, &gb->romCrc32, sizeof(gb->romCrc32));
@ -865,59 +873,59 @@ static bool _GBCoreReadRegister(const struct mCore* core, const char* name, void
uint16_t* value16 = out;
uint8_t* value8 = out;
if (strcmp(name, "b") == 0) {
if (strcasecmp(name, "b") == 0) {
*value8 = cpu->b;
return true;
}
if (strcmp(name, "c") == 0) {
if (strcasecmp(name, "c") == 0) {
*value8 = cpu->c;
return true;
}
if (strcmp(name, "d") == 0) {
if (strcasecmp(name, "d") == 0) {
*value8 = cpu->d;
return true;
}
if (strcmp(name, "e") == 0) {
if (strcasecmp(name, "e") == 0) {
*value8 = cpu->e;
return true;
}
if (strcmp(name, "a") == 0) {
if (strcasecmp(name, "a") == 0) {
*value8 = cpu->a;
return true;
}
if (strcmp(name, "f") == 0) {
if (strcasecmp(name, "f") == 0) {
*value8 = cpu->f.packed;
return true;
}
if (strcmp(name, "h") == 0) {
if (strcasecmp(name, "h") == 0) {
*value8 = cpu->h;
return true;
}
if (strcmp(name, "l") == 0) {
if (strcasecmp(name, "l") == 0) {
*value8 = cpu->l;
return true;
}
if (strcmp(name, "bc") == 0) {
if (strcasecmp(name, "bc") == 0) {
*value16 = cpu->bc;
return true;
}
if (strcmp(name, "de") == 0) {
if (strcasecmp(name, "de") == 0) {
*value16 = cpu->de;
return true;
}
if (strcmp(name, "hl") == 0) {
if (strcasecmp(name, "hl") == 0) {
*value16 = cpu->hl;
return true;
}
if (strcmp(name, "af") == 0) {
if (strcasecmp(name, "af") == 0) {
*value16 = cpu->af;
return true;
}
if (strcmp(name, "pc") == 0) {
if (strcasecmp(name, "pc") == 0) {
*value16 = cpu->pc;
return true;
}
if (strcmp(name, "sp") == 0) {
if (strcasecmp(name, "sp") == 0) {
*value16 = cpu->sp;
return true;
}
@ -1237,6 +1245,7 @@ struct mCore* GBCoreCreate(void) {
core->loadTemporarySave = _GBCoreLoadTemporarySave;
core->loadPatch = _GBCoreLoadPatch;
core->unloadROM = _GBCoreUnloadROM;
core->romSize = _GBCoreROMSize;
core->checksum = _GBCoreChecksum;
core->reset = _GBCoreReset;
core->runFrame = _GBCoreRunFrame;

View File

@ -446,6 +446,7 @@ static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) {
#ifdef BUILD_GLES3
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->glRenderer.outputTex = texid;
gbacore->glRenderer.outputTexDirty = true;
#else
UNUSED(core);
UNUSED(texid);
@ -568,8 +569,16 @@ static void _GBACoreUnloadROM(struct mCore* core) {
GBAUnloadROM(core->board);
}
static size_t _GBACoreROMSize(const struct mCore* core) {
const struct GBA* gba = (const struct GBA*) core->board;
if (gba->romVf) {
return gba->romVf->size(gba->romVf);
}
return gba->pristineRomSize;
}
static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChecksumType type) {
struct GBA* gba = (struct GBA*) core->board;
const struct GBA* gba = (const struct GBA*) core->board;
switch (type) {
case mCHECKSUM_CRC32:
memcpy(data, &gba->romCrc32, sizeof(gba->romCrc32));
@ -1362,6 +1371,7 @@ struct mCore* GBACoreCreate(void) {
core->loadTemporarySave = _GBACoreLoadTemporarySave;
core->loadPatch = _GBACoreLoadPatch;
core->unloadROM = _GBACoreUnloadROM;
core->romSize = _GBACoreROMSize;
core->checksum = _GBACoreChecksum;
core->reset = _GBACoreReset;
core->runFrame = _GBACoreRunFrame;

View File

@ -257,7 +257,7 @@ void GBAReset(struct ARMCore* cpu) {
memset(gba->debugString, 0, sizeof(gba->debugString));
if (gba->romVf && gba->pristineRomSize > SIZE_CART0) {
if (gba->romVf && gba->romVf->size(gba->romVf) > SIZE_CART0) {
char ident;
gba->romVf->seek(gba->romVf, 0xAC, SEEK_SET);
gba->romVf->read(gba->romVf, &ident, 1);

View File

@ -779,6 +779,7 @@ static void _initFramebuffers(struct GBAVideoGLRenderer* glRenderer) {
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]);
_initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale);
glRenderer->outputTexDirty = false;
int i;
for (i = 0; i < 4; ++i) {
@ -1678,6 +1679,10 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u
void _finalizeLayers(struct GBAVideoGLRenderer* renderer) {
const GLuint* uniforms = renderer->finalizeShader.uniforms;
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OUTPUT]);
if (renderer->outputTexDirty) {
_initFramebufferTexture(renderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, renderer->scale);
renderer->outputTexDirty = false;
}
glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
glScissor(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
if (GBARegisterDISPCNTIsForcedBlank(renderer->dispcnt)) {

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutScreen</class>
<widget class="QWidget" name="AboutScreen">
<class>QGBA::AboutScreen</class>
<widget class="QWidget" name="QGBA::AboutScreen">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ApplicationUpdatePrompt</class>
<widget class="QDialog" name="ApplicationUpdatePrompt">
<class>QGBA::ApplicationUpdatePrompt</class>
<widget class="QDialog" name="QGBA::ApplicationUpdatePrompt">
<property name="geometry">
<rect>
<x>0</x>
@ -58,7 +58,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ApplicationUpdatePrompt</receiver>
<receiver>QGBA::ApplicationUpdatePrompt</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ArchiveInspector</class>
<widget class="QDialog" name="ArchiveInspector">
<class>QGBA::ArchiveInspector</class>
<widget class="QDialog" name="QGBA::ArchiveInspector">
<property name="geometry">
<rect>
<x>0</x>
@ -46,7 +46,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ArchiveInspector</receiver>
<receiver>QGBA::ArchiveInspector</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
@ -62,7 +62,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ArchiveInspector</receiver>
<receiver>QGBA::ArchiveInspector</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -82,6 +82,9 @@ void AssetTile::setBoundary(int boundary, int set0, int set1) {
}
void AssetTile::selectIndex(int index) {
if (index > m_maxTile) {
return;
}
m_index = index;
const color_t* data;
mTileCache* tileCache = m_tileCaches[index >= m_boundary];
@ -141,3 +144,7 @@ void AssetTile::selectColor(int index) {
m_ui.g->setText(tr("0x%0 (%1)").arg(g, 2, 16, QChar('0')).arg(g, 2, 10, QChar('0')));
m_ui.b->setText(tr("0x%0 (%1)").arg(b, 2, 16, QChar('0')).arg(b, 2, 10, QChar('0')));
}
void AssetTile::setMaxTile(int tile) {
m_maxTile = tile;
}

View File

@ -29,6 +29,7 @@ public slots:
void selectIndex(int);
void setFlip(bool h, bool v);
void selectColor(int);
void setMaxTile(int);
protected:
int customLocation(const QString& id = {}) override;
@ -45,6 +46,7 @@ private:
int m_addressBase;
int m_boundary;
int m_boundaryBase;
int m_maxTile;
bool m_flipH = false;
bool m_flipV = false;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AssetTile</class>
<widget class="QGBA::AssetInfo" name="AssetTile">
<class>QGBA::AssetTile</class>
<widget class="QGBA::AssetInfo" name="QGBA::AssetTile">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BattleChipView</class>
<widget class="QDialog" name="BattleChipView">
<class>QGBA::BattleChipView</class>
<widget class="QDialog" name="QGBA::BattleChipView">
<property name="geometry">
<rect>
<x>0</x>
@ -238,7 +238,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BattleChipView</receiver>
<receiver>QGBA::BattleChipView</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -330,17 +330,17 @@ if(${QT}LinguistTools_FOUND)
file(GLOB TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ts/${BINARY_NAME}-*.ts")
if(UPDATE_TRANSLATIONS)
if(TARGET Qt6::Core)
qt_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} OPTIONS -locations absolute -no-obsolete)
qt_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} ${CMAKE_CURRENT_SOURCE_DIR} OPTIONS -locations absolute -no-obsolete)
else()
qt5_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} OPTIONS -locations absolute -no-obsolete)
qt5_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} ${CMAKE_CURRENT_SOURCE_DIR} OPTIONS -locations absolute -no-obsolete)
endif()
list(REMOVE_ITEM TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ts/${BINARY_NAME}-template.ts")
else()
list(REMOVE_ITEM TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/ts/${BINARY_NAME}-template.ts")
if(TARGET Qt6::Core)
qt_add_translation(TRANSLATION_FILES ${TS_FILES})
qt_add_translation(TRANSLATION_FILES ${TS_FILES} ${CMAKE_CURRENT_SOURCE_DIR})
else()
qt5_add_translation(TRANSLATION_FILES ${TS_FILES})
qt5_add_translation(TRANSLATION_FILES ${TS_FILES} ${CMAKE_CURRENT_SOURCE_DIR})
endif()
endif()
set(QT_QM_FILES)
@ -358,9 +358,14 @@ if(${QT}LinguistTools_FOUND)
endforeach()
list(APPEND TRANSLATION_FILES ${QT_QM_FILES})
endif()
add_custom_command(OUTPUT ${TRANSLATION_QRC}
COMMAND ${CMAKE_COMMAND} -DTRANSLATION_QRC:FILEPATH="${TRANSLATION_QRC}" -DQM_BASE="${CMAKE_CURRENT_BINARY_DIR}" "-DTRANSLATION_FILES='${TRANSLATION_FILES}'" -P "${CMAKE_CURRENT_SOURCE_DIR}/ts.cmake"
DEPENDS ${TRANSLATION_FILES})
file(WRITE ${TRANSLATION_QRC} "<RCC>\n\t<qresource prefix=\"/translations/\">\n")
foreach(TS ${TRANSLATION_FILES})
get_filename_component(TS_BASE "${TS}" NAME)
file(APPEND ${TRANSLATION_QRC} "\t\t<file alias=\"${TS_BASE}\">${TS}</file>\n")
endforeach()
file(APPEND ${TRANSLATION_QRC} "\t</qresource>\n</RCC>")
if(TARGET Qt6::Core)
qt_add_resources(TRANSLATION_RESOURCES ${TRANSLATION_QRC})
else()

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CheatsView</class>
<widget class="QWidget" name="CheatsView">
<class>QGBA::CheatsView</class>
<widget class="QWidget" name="QGBA::CheatsView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -144,19 +144,19 @@ CoreController::CoreController(mCore* core, QObject* parent)
QMetaObject::invokeMethod(controller, "unpaused");
};
m_threadContext.logger.d.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
mThreadLogger* logContext = reinterpret_cast<mThreadLogger*>(logger);
mCoreThread* context = logContext->p;
m_logger.self = this;
m_logger.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
CoreLogger* logContext = static_cast<CoreLogger*>(logger);
static const char* savestateMessage = "State %i saved";
static const char* loadstateMessage = "State %i loaded";
static const char* savestateFailedMessage = "State %i failed to load";
static int biosCat = -1;
static int statusCat = -1;
if (!context) {
if (!logContext) {
return;
}
CoreController* controller = static_cast<CoreController*>(context->userData);
CoreController* controller = logContext->self;
QString message;
if (biosCat < 0) {
biosCat = mLogCategoryById("gba.bios");
@ -201,10 +201,10 @@ CoreController::CoreController(mCore* core, QObject* parent)
message = QString::vasprintf(format, args);
QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message));
if (level == mLOG_FATAL) {
mCoreThreadMarkCrashed(controller->thread());
QMetaObject::invokeMethod(controller, "crashed", Q_ARG(const QString&, message));
}
};
m_threadContext.logger.logger = &m_logger;
}
CoreController::~CoreController() {
@ -424,7 +424,7 @@ void CoreController::setInputController(InputController* inputController) {
void CoreController::setLogger(LogController* logger) {
disconnect(m_log);
m_log = logger;
m_threadContext.logger.d.filter = logger->filter();
m_logger.filter = logger->filter();
connect(this, &CoreController::logPosted, m_log, &LogController::postLog);
}
@ -1238,24 +1238,21 @@ void CoreController::updateFastForward() {
if (m_fastForwardMute >= 0) {
m_threadContext.core->opts.mute = m_fastForwardMute || m_mute;
}
setSync(false);
// If we aren't holding the fast forward button
// then use the non "(held)" ratio
if(!m_fastForward) {
if (m_fastForwardRatio > 0) {
m_threadContext.impl->sync.fpsTarget = m_fpsTarget * m_fastForwardRatio;
setSync(true);
} else {
setSync(false);
m_threadContext.impl->sync.audioWait = true;
}
} else {
// If we are holding the fast forward button,
// then use the held ratio
if (m_fastForwardHeldRatio > 0) {
m_threadContext.impl->sync.fpsTarget = m_fpsTarget * m_fastForwardHeldRatio;
setSync(true);
} else {
setSync(false);
m_threadContext.impl->sync.audioWait = true;
}
}
} else {
@ -1358,3 +1355,7 @@ void CoreController::Interrupter::resume(CoreController* controller) {
mCoreThreadContinue(controller->thread());
}
bool CoreController::Interrupter::held() const {
return m_parent && m_parent->thread()->impl;
}

View File

@ -68,6 +68,8 @@ public:
void interrupt(std::shared_ptr<CoreController>);
void resume();
bool held() const;
private:
void interrupt();
void resume(CoreController*);
@ -239,6 +241,9 @@ private:
void updateROMInfo();
mCoreThread m_threadContext{};
struct CoreLogger : public mLogger {
CoreController* self;
} m_logger{};
bool m_patched = false;
bool m_preload = false;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DebuggerConsole</class>
<widget class="QWidget" name="DebuggerConsole">
<class>QGBA::DebuggerConsole</class>
<widget class="QWidget" name="QGBA::DebuggerConsole">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -285,7 +285,7 @@ void DisplayGL::stopDrawing() {
m_isDrawing = false;
m_hasStarted = false;
CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter.get(), "stop", Qt::BlockingQueuedConnection);
m_painter->stop();
if (m_gl) {
hide();
}
@ -457,8 +457,7 @@ void PainterGL::create() {
m_paintDev = std::make_unique<QOpenGLPaintDevice>();
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
auto version = m_format.version();
if (version >= qMakePair(2, 0)) {
if (m_supportsShaders) {
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
mGLES2ContextCreate(gl2Backend);
m_backend = &gl2Backend->d;
@ -626,6 +625,15 @@ void PainterGL::draw() {
if (!m_started || m_queue.isEmpty()) {
return;
}
if (m_interrupter.held()) {
// A resize event is pending; that needs to happen first
if (!m_drawTimer.isActive()) {
m_drawTimer.start(0);
}
return;
}
mCoreSync* sync = &m_context->thread()->impl->sync;
if (!mCoreSyncWaitFrameStart(sync)) {
mCoreSyncWaitFrameEnd(sync);
@ -676,6 +684,11 @@ void PainterGL::forceDraw() {
}
void PainterGL::stop() {
m_started = false;
QMetaObject::invokeMethod(this, "doStop", Qt::BlockingQueuedConnection);
}
void PainterGL::doStop() {
m_drawTimer.stop();
m_active = false;
m_started = false;

View File

@ -135,6 +135,8 @@ public:
void setMessagePainter(MessagePainter*);
void enqueue(const uint32_t* backing);
void stop();
bool supportsShaders() const { return m_supportsShaders; }
int glTex();
@ -148,7 +150,6 @@ public slots:
void forceDraw();
void draw();
void start();
void stop();
void pause();
void unpause();
void resize(const QSize& size);
@ -167,6 +168,9 @@ public slots:
signals:
void started();
private slots:
void doStop();
private:
void makeCurrent();
void performDraw();

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DolphinConnector</class>
<widget class="QDialog" name="DolphinConnector">
<class>QGBA::DolphinConnector</class>
<widget class="QDialog" name="QGBA::DolphinConnector">
<property name="geometry">
<rect>
<x>0</x>
@ -98,7 +98,7 @@
<connection>
<sender>close</sender>
<signal>clicked()</signal>
<receiver>DolphinConnector</receiver>
<receiver>QGBA::DolphinConnector</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FrameView</class>
<widget class="QWidget" name="FrameView">
<class>QGBA::FrameView</class>
<widget class="QWidget" name="QGBA::FrameView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GIFView</class>
<widget class="QWidget" name="GIFView">
<class>QGBA::GIFView</class>
<widget class="QWidget" name="QGBA::GIFView">
<property name="geometry">
<rect>
<x>0</x>
@ -180,7 +180,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GIFView</receiver>
<receiver>QGBA::GIFView</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -44,9 +44,7 @@ static const QList<GBMemoryBankControllerType> s_mbcList{
static QMap<GBModel, QString> s_gbModelNames;
static QMap<GBMemoryBankControllerType, QString> s_mbcNames;
static QString tr(const char* str) {
return QCoreApplication::translate("Game Boy", str);
}
#define tr(STR) QCoreApplication::translate("QGBA::GameBoy", STR)
QList<GBModel> GameBoy::modelList() {
return s_gbModelList;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>IOViewer</class>
<widget class="QWidget" name="IOViewer">
<class>QGBA::IOViewer</class>
<widget class="QWidget" name="QGBA::IOViewer">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoadSaveState</class>
<widget class="QWidget" name="LoadSaveState">
<class>QGBA::LoadSaveState</class>
<widget class="QWidget" name="QGBA::LoadSaveState">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LogView</class>
<widget class="QWidget" name="LogView">
<class>QGBA::LogView</class>
<widget class="QWidget" name="QGBA::LogView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -42,6 +42,7 @@ MapView::MapView(std::shared_ptr<CoreController> controller, QWidget* parent)
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
m_boundary = 2048;
m_ui.tile->setMaxTile(3096);
m_addressBase = BASE_VRAM;
m_addressWidth = 8;
m_ui.bgInfo->addCustomProperty("priority", tr("Priority"));
@ -55,6 +56,7 @@ MapView::MapView(std::shared_ptr<CoreController> controller, QWidget* parent)
#ifdef M_CORE_GB
case mPLATFORM_GB:
m_boundary = 1024;
m_ui.tile->setMaxTile(512);
m_addressBase = GB_BASE_VRAM;
m_addressWidth = 4;
m_ui.bgInfo->addCustomProperty("screenBase", tr("Map base"));

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MapView</class>
<widget class="QWidget" name="MapView">
<class>QGBA::MapView</class>
<widget class="QWidget" name="QGBA::MapView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MemoryDump</class>
<widget class="QDialog" name="MemoryDump">
<class>QGBA::MemoryDump</class>
<widget class="QDialog" name="QGBA::MemoryDump">
<property name="geometry">
<rect>
<x>0</x>
@ -126,7 +126,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MemoryDump</receiver>
<receiver>QGBA::MemoryDump</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@ -142,7 +142,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MemoryDump</receiver>
<receiver>QGBA::MemoryDump</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MemorySearch</class>
<widget class="QWidget" name="MemorySearch">
<class>QGBA::MemorySearch</class>
<widget class="QWidget" name="QGBA::MemorySearch">
<property name="geometry">
<rect>
<x>0</x>
@ -367,7 +367,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MemorySearch</receiver>
<receiver>QGBA::MemorySearch</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MemoryView</class>
<widget class="QWidget" name="MemoryView">
<class>QGBA::MemoryView</class>
<widget class="QWidget" name="QGBA::MemoryView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -116,14 +116,16 @@ void ObjView::updateTilesGBA(bool force) {
if (GBAObjAttributesAIs256Color(obj->a)) {
m_ui.palette->setText("256-color");
m_ui.tile->setBoundary(1024, 1, 3);
m_ui.tile->setPalette(0);
m_boundary = 1024;
tileBase *= 2;
m_ui.tile->setMaxTile(1536);
m_ui.tile->setPalette(0);
} else {
m_ui.palette->setText(QString::number(newInfo.paletteId));
m_ui.tile->setBoundary(2048, 0, 2);
m_ui.tile->setPalette(newInfo.paletteId);
m_boundary = 2048;
m_ui.tile->setMaxTile(3072);
m_ui.tile->setPalette(newInfo.paletteId);
}
if (newInfo != m_objInfo) {
force = true;
@ -225,6 +227,7 @@ void ObjView::updateTilesGB(bool force) {
m_objInfo = newInfo;
m_tileOffset = tile;
m_boundary = 1024;
m_ui.tile->setMaxTile(512);
int i = 0;
m_ui.tile->setPalette(newInfo.paletteId);

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ObjView</class>
<widget class="QWidget" name="ObjView">
<class>QGBA::ObjView</class>
<widget class="QWidget" name="QGBA::ObjView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OverrideView</class>
<widget class="QWidget" name="OverrideView">
<class>QGBA::OverrideView</class>
<widget class="QWidget" name="QGBA::OverrideView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PaletteView</class>
<widget class="QWidget" name="PaletteView">
<class>QGBA::PaletteView</class>
<widget class="QWidget" name="QGBA::PaletteView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PlacementControl</class>
<widget class="QDialog" name="PlacementControl">
<class>QGBA::PlacementControl</class>
<widget class="QDialog" name="QGBA::PlacementControl">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PrinterView</class>
<widget class="QWidget" name="PrinterView">
<class>QGBA::PrinterView</class>
<widget class="QWidget" name="QGBA::PrinterView">
<property name="geometry">
<rect>
<x>0</x>
@ -250,7 +250,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PrinterView</receiver>
<receiver>QGBA::PrinterView</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -9,12 +9,6 @@
#include "CoreController.h"
#include <mgba/core/core.h>
#ifdef M_CORE_GB
#include <mgba/internal/gb/gb.h>
#endif
#ifdef M_CORE_GBA
#include <mgba/internal/gba/gba.h>
#endif
#ifdef USE_SQLITE3
#include "feature/sqlite3/no-intro.h"
#endif
@ -46,25 +40,8 @@ ROMInfo::ROMInfo(std::shared_ptr<CoreController> controller, QWidget* parent)
core->checksum(core, &crc32, mCHECKSUM_CRC32);
switch (controller->thread()->core->platform(controller->thread()->core)) {
#ifdef M_CORE_GBA
case mPLATFORM_GBA: {
GBA* gba = static_cast<GBA*>(core->board);
m_ui.size->setText(QString::number(gba->pristineRomSize) + tr(" bytes"));
break;
}
#endif
#ifdef M_CORE_GB
case mPLATFORM_GB: {
GB* gb = static_cast<GB*>(core->board);
m_ui.size->setText(QString::number(gb->pristineRomSize) + tr(" bytes"));
break;
}
#endif
default:
m_ui.size->setText(tr("(unknown)"));
break;
}
m_ui.size->setText(QString::number(core->romSize(core)) + tr(" bytes"));
if (crc32) {
m_ui.crc->setText(QString::number(crc32, 16));
#ifdef USE_SQLITE3

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ROMInfo</class>
<widget class="QDialog" name="ROMInfo">
<class>QGBA::ROMInfo</class>
<widget class="QDialog" name="QGBA::ROMInfo">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ReportView</class>
<widget class="QDialog" name="ReportView">
<class>QGBA::ReportView</class>
<widget class="QDialog" name="QGBA::ReportView">
<property name="geometry">
<rect>
<x>0</x>
@ -163,7 +163,7 @@
<connection>
<sender>openList</sender>
<signal>clicked()</signal>
<receiver>ReportView</receiver>
<receiver>QGBA::ReportView</receiver>
<slot>openBugReportPage()</slot>
<hints>
<hint type="sourcelabel">
@ -179,7 +179,7 @@
<connection>
<sender>generate</sender>
<signal>clicked()</signal>
<receiver>ReportView</receiver>
<receiver>QGBA::ReportView</receiver>
<slot>generateReport()</slot>
<hints>
<hint type="sourcelabel">
@ -195,7 +195,7 @@
<connection>
<sender>save</sender>
<signal>clicked()</signal>
<receiver>ReportView</receiver>
<receiver>QGBA::ReportView</receiver>
<slot>save()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -447,14 +447,14 @@ SaveConverter::AnnotatedSave::operator QString() const {
QString typeFormat("%1");
QString endianStr;
QString saveType;
QString format = QCoreApplication::translate("SaveConverter", "%1 %2 save game");
QString format = QCoreApplication::translate("QGBA::SaveConverter", "%1 %2 save game");
switch (endianness) {
case Endian::LITTLE:
endianStr = QCoreApplication::translate("SaveConverter", "little endian");
endianStr = QCoreApplication::translate("QGBA::SaveConverter", "little endian");
break;
case Endian::BIG:
endianStr = QCoreApplication::translate("SaveConverter", "big endian");
endianStr = QCoreApplication::translate("QGBA::SaveConverter", "big endian");
break;
default:
break;
@ -465,15 +465,15 @@ SaveConverter::AnnotatedSave::operator QString() const {
case mPLATFORM_GBA:
switch (gba.type) {
case SAVEDATA_SRAM:
typeFormat = QCoreApplication::translate("SaveConverter", "SRAM");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "SRAM");
break;
case SAVEDATA_FLASH512:
case SAVEDATA_FLASH1M:
typeFormat = QCoreApplication::translate("SaveConverter", "%1 flash");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "%1 flash");
break;
case SAVEDATA_EEPROM:
case SAVEDATA_EEPROM512:
typeFormat = QCoreApplication::translate("SaveConverter", "%1 EEPROM");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "%1 EEPROM");
break;
default:
break;
@ -485,29 +485,29 @@ SaveConverter::AnnotatedSave::operator QString() const {
switch (gb.type) {
case GB_MBC_AUTODETECT:
if (size & 0xFF) {
typeFormat = QCoreApplication::translate("SaveConverter", "%1 SRAM + RTC");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "%1 SRAM + RTC");
} else {
typeFormat = QCoreApplication::translate("SaveConverter", "%1 SRAM");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "%1 SRAM");
}
break;
case GB_MBC2:
if (size == 0x100) {
typeFormat = QCoreApplication::translate("SaveConverter", "packed MBC2");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "packed MBC2");
} else {
typeFormat = QCoreApplication::translate("SaveConverter", "unpacked MBC2");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "unpacked MBC2");
}
break;
case GB_MBC6:
if (size == GB_SIZE_MBC6_FLASH) {
typeFormat = QCoreApplication::translate("SaveConverter", "MBC6 flash");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "MBC6 flash");
} else if (size > GB_SIZE_MBC6_FLASH) {
typeFormat = QCoreApplication::translate("SaveConverter", "MBC6 combined SRAM + flash");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "MBC6 combined SRAM + flash");
} else {
typeFormat = QCoreApplication::translate("SaveConverter", "MBC6 SRAM");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "MBC6 SRAM");
}
break;
case GB_TAMA5:
typeFormat = QCoreApplication::translate("SaveConverter", "TAMA5");
typeFormat = QCoreApplication::translate("QGBA::SaveConverter", "TAMA5");
break;
default:
break;
@ -519,17 +519,17 @@ SaveConverter::AnnotatedSave::operator QString() const {
}
saveType = typeFormat.arg(sizeStr);
if (!endianStr.isEmpty()) {
saveType = QCoreApplication::translate("SaveConverter", "%1 (%2)").arg(saveType).arg(endianStr);
saveType = QCoreApplication::translate("QGBA::SaveConverter", "%1 (%2)").arg(saveType).arg(endianStr);
}
switch (container) {
case Container::SAVESTATE:
format = QCoreApplication::translate("SaveConverter", "%1 save state with embedded %2 save game");
format = QCoreApplication::translate("QGBA::SaveConverter", "%1 save state with embedded %2 save game");
break;
case Container::SHARKPORT:
format = QCoreApplication::translate("SaveConverter", "%1 SharkPort %2 save game");
format = QCoreApplication::translate("QGBA::SaveConverter", "%1 SharkPort %2 save game");
break;
case Container::GSV:
format = QCoreApplication::translate("SaveConverter", "%1 GameShark Advance SP %2 save game");
format = QCoreApplication::translate("QGBA::SaveConverter", "%1 GameShark Advance SP %2 save game");
break;
case Container::NONE:
break;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SaveConverter</class>
<widget class="QDialog" name="SaveConverter">
<class>QGBA::SaveConverter</class>
<widget class="QDialog" name="QGBA::SaveConverter">
<property name="geometry">
<rect>
<x>0</x>
@ -91,7 +91,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SaveConverter</receiver>
<receiver>QGBA::SaveConverter</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@ -107,7 +107,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SaveConverter</receiver>
<receiver>QGBA::SaveConverter</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SensorView</class>
<widget class="QWidget" name="SensorView">
<class>QGBA::SensorView</class>
<widget class="QWidget" name="QGBA::SensorView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -35,16 +35,17 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
m_ui.setupUi(this);
m_pageIndex[Page::AV] = 0;
m_pageIndex[Page::INTERFACE] = 1;
m_pageIndex[Page::UPDATE] = 2;
m_pageIndex[Page::EMULATION] = 3;
m_pageIndex[Page::ENHANCEMENTS] = 4;
m_pageIndex[Page::BIOS] = 5;
m_pageIndex[Page::PATHS] = 6;
m_pageIndex[Page::LOGGING] = 7;
m_pageIndex[Page::GAMEPLAY] = 1;
m_pageIndex[Page::INTERFACE] = 2;
m_pageIndex[Page::UPDATE] = 3;
m_pageIndex[Page::EMULATION] = 4;
m_pageIndex[Page::ENHANCEMENTS] = 5;
m_pageIndex[Page::BIOS] = 6;
m_pageIndex[Page::PATHS] = 7;
m_pageIndex[Page::LOGGING] = 8;
#ifdef M_CORE_GB
m_pageIndex[Page::GB] = 8;
m_pageIndex[Page::GB] = 9;
for (auto model : GameBoy::modelList()) {
m_ui.gbModel->addItem(GameBoy::modelName(model), model);

View File

@ -34,6 +34,7 @@ public:
enum class Page {
AV,
INTERFACE,
GAMEPLAY,
UPDATE,
EMULATION,
ENHANCEMENTS,

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ShaderSelector</class>
<widget class="QDialog" name="ShaderSelector">
<class>QGBA::ShaderSelector</class>
<widget class="QDialog" name="QGBA::ShaderSelector">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ShortcutView</class>
<widget class="QWidget" name="ShortcutView">
<class>QGBA::ShortcutView</class>
<widget class="QWidget" name="QGBA::ShortcutView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -51,6 +51,7 @@ TileView::TileView(std::shared_ptr<CoreController> controller, QWidget* parent)
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
m_ui.tile->setBoundary(2048, 0, 2);
m_ui.tile->setMaxTile(3096);
break;
#endif
#ifdef M_CORE_GB
@ -60,6 +61,7 @@ TileView::TileView(std::shared_ptr<CoreController> controller, QWidget* parent)
m_ui.tilesBoth->setEnabled(false);
m_ui.palette256->setEnabled(false);
m_ui.tile->setBoundary(1024, 0, 0);
m_ui.tile->setMaxTile(512);
break;
#endif
default:
@ -74,6 +76,7 @@ TileView::TileView(std::shared_ptr<CoreController> controller, QWidget* parent)
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
m_ui.tile->setBoundary(2048 >> selected, selected, selected + 2);
m_ui.tile->setMaxTile(3096 >> selected);
break;
#endif
#ifdef M_CORE_GB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TileView</class>
<widget class="QWidget" name="TileView">
<class>QGBA::TileView</class>
<widget class="QWidget" name="QGBA::TileView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VideoView</class>
<widget class="QWidget" name="VideoView">
<class>QGBA::VideoView</class>
<widget class="QWidget" name="QGBA::VideoView">
<property name="geometry">
<rect>
<x>0</x>

View File

@ -48,11 +48,11 @@ LibraryTree::LibraryTree(LibraryController* parent)
m_widget->setAlternatingRowColors(true);
QTreeWidgetItem* header = new QTreeWidgetItem({
QApplication::translate("LibraryTree", "Name", nullptr),
QApplication::translate("LibraryTree", "Location", nullptr),
QApplication::translate("LibraryTree", "Platform", nullptr),
QApplication::translate("LibraryTree", "Size", nullptr),
QApplication::translate("LibraryTree", "CRC32", nullptr),
QApplication::translate("QGBA::LibraryTree", "Name", nullptr),
QApplication::translate("QGBA::LibraryTree", "Location", nullptr),
QApplication::translate("QGBA::LibraryTree", "Platform", nullptr),
QApplication::translate("QGBA::LibraryTree", "Size", nullptr),
QApplication::translate("QGBA::LibraryTree", "CRC32", nullptr),
});
header->setTextAlignment(3, Qt::AlignTrailing | Qt::AlignVCenter);
m_widget->setHeaderItem(header);

View File

@ -61,6 +61,9 @@ void ScriptingController::setController(std::shared_ptr<CoreController> controll
bool ScriptingController::loadFile(const QString& path) {
VFileDevice vf(path, QIODevice::ReadOnly);
if (!vf.isOpen()) {
return false;
}
return load(vf, path);
}

View File

@ -1,67 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScriptingView</class>
<widget class="QMainWindow" name="ScriptingView">
<class>QGBA::ScriptingView</class>
<widget class="QMainWindow" name="QGBA::ScriptingView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
<width>843</width>
<height>637</height>
</rect>
</property>
<property name="windowTitle">
<string>Scripting</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" rowspan="3">
<widget class="QListView" name="buffers">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>180</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QPlainTextEdit" name="buffer">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QGBA::LogWidget" name="log">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="prompt"/>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="runButton">
<property name="text">
<string>Run</string>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QListView" name="buffers">
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLineEdit" name="prompt"/>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="runButton">
<property name="text">
<string>Run</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QSplitter" name="splitter_1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QPlainTextEdit" name="buffer">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<widget class="QGBA::LogWidget" name="log">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@ -1,6 +0,0 @@
file(WRITE ${TRANSLATION_QRC} "<RCC>\n\t<qresource prefix=\"/translations/\">\n")
foreach(TS ${TRANSLATION_FILES})
get_filename_component(TS_BASE "${TS}" NAME)
file(APPEND ${TRANSLATION_QRC} "\t\t<file alias=\"${TS_BASE}\">${TS}</file>\n")
endforeach()
file(APPEND ${TRANSLATION_QRC} "\t</qresource>\n</RCC>")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -38,19 +38,12 @@
#include <signal.h>
#define PORT "sdl"
#define MAX_LOG_BUF 1024
static void mSDLDeinit(struct mSDLRenderer* renderer);
static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args);
static void _setLogger(struct mCore* core);
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args);
static bool _logToStdout = true;
static struct VFile* _logFile = NULL;
static struct mLogFilter _filter;
static struct mLogger _logger;
static struct mStandardLogger _logger;
static struct VFile* _state = NULL;
@ -136,6 +129,7 @@ int main(int argc, char** argv) {
mCoreInitConfig(renderer.core, PORT);
mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
mCoreConfigSetDefaultIntValue(&renderer.core->config, "logToStdout", true);
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
mCoreLoadConfig(renderer.core);
@ -188,7 +182,8 @@ int main(int argc, char** argv) {
int ret;
// TODO: Use opts and config
_setLogger(renderer.core);
mStandardLoggerInit(&_logger);
mStandardLoggerConfig(&_logger, &renderer.core->config);
ret = mSDLRun(&renderer, &args);
mSDLDetachPlayer(&renderer.events, &renderer.player);
mInputMapDeinit(&renderer.core->inputMap);
@ -198,6 +193,7 @@ int main(int argc, char** argv) {
}
mSDLDeinit(&renderer);
mStandardLoggerDeinit(&_logger);
mArgumentsDeinit(&args);
mCoreConfigFreeOpts(&opts);
@ -273,12 +269,8 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
renderer->audio.samples = renderer->core->opts.audioBuffers;
renderer->audio.sampleRate = 44100;
struct mThreadLogger threadLogger;
threadLogger.d = _logger;
threadLogger.p = &thread;
thread.logger = threadLogger;
thread.logger.logger = &_logger.d;
bool didFail = !mCoreThreadStart(&thread);
if (!didFail) {
@ -308,6 +300,7 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
if (mCoreThreadHasCrashed(&thread)) {
didFail = true;
printf("The game crashed!\n");
mCoreThreadEnd(&thread);
}
} else {
didFail = true;
@ -342,63 +335,3 @@ static void mSDLDeinit(struct mSDLRenderer* renderer) {
SDL_Quit();
}
static void _setLogger(struct mCore* core) {
int fakeBool = 0;
bool logToFile = false;
if (mCoreConfigGetIntValue(&core->config, "logToStdout", &fakeBool)) {
_logToStdout = fakeBool;
}
if (mCoreConfigGetIntValue(&core->config, "logToFile", &fakeBool)) {
logToFile = fakeBool;
}
const char* logFile = mCoreConfigGetValue(&core->config, "logFile");
if (logToFile && logFile) {
_logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
}
// Create the filter
mLogFilterInit(&_filter);
mLogFilterLoad(&_filter, &core->config);
// Fill the logger
_logger.log = _mCoreLog;
_logger.filter = &_filter;
}
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
struct mCoreThread* thread = mCoreThreadGet();
if (thread && level == mLOG_FATAL) {
mCoreThreadMarkCrashed(thread);
}
if (!mLogFilterTest(logger->filter, category, level)) {
return;
}
char buffer[MAX_LOG_BUF];
// Prepare the string
size_t length = snprintf(buffer, sizeof(buffer), "%s: ", mLogCategoryName(category));
if (length < sizeof(buffer)) {
length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
}
if (length < sizeof(buffer)) {
length += snprintf(buffer + length, sizeof(buffer) - length, "\n");
}
// Make sure the length doesn't exceed the size of the buffer when actually writing
if (length > sizeof(buffer)) {
length = sizeof(buffer);
}
if (_logToStdout) {
printf("%s", buffer);
}
if (_logFile) {
_logFile->write(_logFile, buffer, length);
}
}

View File

@ -8,6 +8,7 @@
#include <mgba/core/cheats.h>
#include <mgba/core/config.h>
#include <mgba/core/core.h>
#include <mgba/core/log.h>
#include <mgba/core/serialize.h>
#ifdef M_CORE_GBA
#include <mgba/internal/gba/gba.h>
@ -30,49 +31,37 @@
struct RomTestOpts {
int exitSwiImmediate;
unsigned int returnCodeRegister;
char* returnCodeRegister;
};
static void _romTestShutdown(int signal);
static bool _parseRomTestOpts(struct mSubParser* parser, int option, const char* arg);
static bool _parseSwi(const char* regStr, int* oSwi);
static bool _parseNamedRegister(const char* regStr, unsigned int* oRegister);
static bool _romTestCheckResiger(void);
static struct mCore* core;
static bool _dispatchExiting = false;
static int _exitCode = 0;
static struct mStandardLogger _logger;
static void _romTestCallback(void* context);
#ifdef M_CORE_GBA
static void _romTestSwi3Callback(void* context);
static void _romTestSwi16(struct ARMCore* cpu, int immediate);
static void _romTestSwi32(struct ARMCore* cpu, int immediate);
static int _exitSwiImmediate;
static unsigned int _returnCodeRegister;
static char* _returnCodeRegister;
void (*_armSwi16)(struct ARMCore* cpu, int immediate);
void (*_armSwi32)(struct ARMCore* cpu, int immediate);
#endif
#ifdef M_CORE_GB
enum GBReg {
GB_REG_A = 16,
GB_REG_F,
GB_REG_B,
GB_REG_C,
GB_REG_D,
GB_REG_E,
GB_REG_H,
GB_REG_L
};
static void _romTestGBCallback(void* context);
#endif
int main(int argc, char * argv[]) {
signal(SIGINT, _romTestShutdown);
struct RomTestOpts romTestOpts = { 3, 0 };
struct RomTestOpts romTestOpts = { 3, NULL };
struct mSubParser subparser = {
.usage = ROM_TEST_USAGE,
.parse = _parseRomTestOpts,
@ -93,7 +82,7 @@ int main(int argc, char * argv[]) {
version(argv[0]);
return 0;
}
struct mCore* core = mCoreFind(args.fname);
core = mCoreFind(args.fname);
if (!core) {
return 1;
}
@ -102,24 +91,29 @@ int main(int argc, char * argv[]) {
mArgumentsApply(&args, NULL, 0, &core->config);
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
mCoreConfigSetDefaultIntValue(&core->config, "logToStdout", true);
mStandardLoggerInit(&_logger);
mStandardLoggerConfig(&_logger, &core->config);
mLogSetDefaultLogger(&_logger.d);
bool cleanExit = false;
struct mCoreCallbacks callbacks = {0};
callbacks.context = core;
_returnCodeRegister = romTestOpts.returnCodeRegister;
if (!_romTestCheckResiger()) {
goto loadError;
}
switch (core->platform(core)) {
#ifdef M_CORE_GBA
case mPLATFORM_GBA:
((struct GBA*) core->board)->hardCrash = false;
if (romTestOpts.returnCodeRegister >= 16) {
goto loadError;
}
_exitSwiImmediate = romTestOpts.exitSwiImmediate;
_returnCodeRegister = romTestOpts.returnCodeRegister;
if (_exitSwiImmediate == 3) {
// Hook into SWI 3 (shutdown)
callbacks.shutdown = _romTestSwi3Callback;
callbacks.shutdown = _romTestCallback;
core->addCoreCallbacks(core, &callbacks);
} else {
// Custom SWI hooks
@ -132,13 +126,7 @@ int main(int argc, char * argv[]) {
#endif
#ifdef M_CORE_GB
case mPLATFORM_GB:
if (romTestOpts.returnCodeRegister < GB_REG_A) {
goto loadError;
}
_returnCodeRegister = romTestOpts.returnCodeRegister;
callbacks.shutdown = _romTestGBCallback;
callbacks.shutdown = _romTestCallback;
core->addCoreCallbacks(core, &callbacks);
break;
#endif
@ -185,8 +173,12 @@ int main(int argc, char * argv[]) {
loadError:
mArgumentsDeinit(&args);
mStandardLoggerDeinit(&_logger);
mCoreConfigDeinit(&core->config);
core->deinit(core);
if (_returnCodeRegister) {
free(_returnCodeRegister);
}
return cleanExit ? _exitCode : 1;
}
@ -196,16 +188,66 @@ static void _romTestShutdown(int signal) {
_dispatchExiting = true;
}
#ifdef M_CORE_GBA
static void _romTestSwi3Callback(void* context) {
struct mCore* core = context;
_exitCode = ((struct GBA*) core->board)->cpu->regs.gprs[_returnCodeRegister];
static bool _romTestCheckResiger(void) {
if (!_returnCodeRegister) {
return true;
}
const struct mCoreRegisterInfo* registers;
const struct mCoreRegisterInfo* reg = NULL;
size_t regCount = core->listRegisters(core, &registers);
size_t i;
for (i = 0; i < regCount; ++i) {
if (strcasecmp(_returnCodeRegister, registers[i].name) == 0) {
reg = &registers[i];
break;
}
if (registers[i].aliases) {
size_t j;
for (j = 0; registers[i].aliases[j]; ++j) {
if (strcasecmp(_returnCodeRegister, registers[i].aliases[j]) == 0) {
reg = &registers[i];
break;
}
}
if (reg) {
break;
}
}
}
if (!reg) {
return false;
}
if (reg->width > 4) {
return false;
}
if (reg->type != mCORE_REGISTER_GPR) {
return false;
}
if (reg->mask != 0xFFFFFFFFU >> (4 - reg->width) * 8) {
return false;
}
return true;
}
static void _romTestCallback(void* context) {
UNUSED(context);
if (_returnCodeRegister) {
core->readRegister(core, _returnCodeRegister, &_exitCode);
}
_dispatchExiting = true;
}
#ifdef M_CORE_GBA
static void _romTestSwi16(struct ARMCore* cpu, int immediate) {
if (immediate == _exitSwiImmediate) {
_exitCode = cpu->regs.gprs[_returnCodeRegister];
if (_returnCodeRegister) {
core->readRegister(core, _returnCodeRegister, &_exitCode);
}
_dispatchExiting = true;
return;
}
@ -214,7 +256,9 @@ static void _romTestSwi16(struct ARMCore* cpu, int immediate) {
static void _romTestSwi32(struct ARMCore* cpu, int immediate) {
if (immediate == _exitSwiImmediate) {
_exitCode = cpu->regs.gprs[_returnCodeRegister];
if (_returnCodeRegister) {
core->readRegister(core, _returnCodeRegister, &_exitCode);
}
_dispatchExiting = true;
return;
}
@ -222,41 +266,6 @@ static void _romTestSwi32(struct ARMCore* cpu, int immediate) {
}
#endif
#ifdef M_CORE_GB
static void _romTestGBCallback(void* context) {
struct mCore* core = context;
struct SM83Core* cpu = core->cpu;
switch (_returnCodeRegister) {
case GB_REG_A:
_exitCode = cpu->a;
break;
case GB_REG_B:
_exitCode = cpu->b;
break;
case GB_REG_C:
_exitCode = cpu->c;
break;
case GB_REG_D:
_exitCode = cpu->d;
break;
case GB_REG_E:
_exitCode = cpu->e;
break;
case GB_REG_F:
_exitCode = cpu->f.packed;
break;
case GB_REG_H:
_exitCode = cpu->h;
break;
case GB_REG_L:
_exitCode = cpu->l;
break;
}
_dispatchExiting = true;
}
#endif
static bool _parseRomTestOpts(struct mSubParser* parser, int option, const char* arg) {
struct RomTestOpts* opts = parser->opts;
errno = 0;
@ -264,7 +273,8 @@ static bool _parseRomTestOpts(struct mSubParser* parser, int option, const char*
case 'S':
return _parseSwi(arg, &opts->exitSwiImmediate);
case 'R':
return _parseNamedRegister(arg, &opts->returnCodeRegister);
opts->returnCodeRegister = strdup(arg);
return true;
default:
return false;
}
@ -279,72 +289,3 @@ static bool _parseSwi(const char* swiStr, int* oSwi) {
*oSwi = swi;
return true;
}
static bool _parseNamedRegister(const char* regStr, unsigned int* oRegister) {
#ifdef M_CORE_GB
static const enum GBReg gbMapping[] = {
['a' - 'a'] = GB_REG_A,
['b' - 'a'] = GB_REG_B,
['c' - 'a'] = GB_REG_C,
['d' - 'a'] = GB_REG_D,
['e' - 'a'] = GB_REG_E,
['f' - 'a'] = GB_REG_F,
['h' - 'a'] = GB_REG_H,
['l' - 'a'] = GB_REG_L,
};
#endif
switch (regStr[0]) {
case 'r':
case 'R':
++regStr;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
#ifdef M_CORE_GB
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'h':
case 'l':
if (regStr[1] != '\0') {
return false;
}
*oRegister = gbMapping[regStr[0] - 'a'];
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'H':
case 'L':
if (regStr[1] != '\0') {
return false;
}
*oRegister = gbMapping[regStr[0] - 'A'];
return true;
#endif
}
char* parseEnd;
unsigned long regId = strtoul(regStr, &parseEnd, 10);
if (errno || regId > 15 || *parseEnd) {
return false;
}
*oRegister = regId;
return true;
}

Some files were not shown because too many files have changed in this diff Show More