From 6f09085676be07883e25c2a11ae3a505aed2562c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 16 May 2022 01:07:17 -0700 Subject: [PATCH 01/11] Qt: Poll current keys in case some external force has changed them --- src/platform/qt/CoreController.cpp | 6 +++++- src/platform/qt/CoreController.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 535bbdaf8..4491a0f33 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -859,6 +859,7 @@ void CoreController::addKey(int key) { void CoreController::clearKey(int key) { m_activeKeys &= ~(1 << key); + m_removedKeys |= 1 << key; } void CoreController::setAutofire(int key, bool enable) { @@ -1145,7 +1146,10 @@ void CoreController::setFramebufferHandle(int fb) { } void CoreController::updateKeys() { - int activeKeys = m_activeKeys | updateAutofire() | m_inputController->pollEvents(); + int polledKeys = m_inputController->pollEvents() | updateAutofire(); + int activeKeys = m_activeKeys | polledKeys; + activeKeys |= m_threadContext.core->getKeys(m_threadContext.core) & ~m_removedKeys; + m_removedKeys = polledKeys; m_threadContext.core->setKeys(m_threadContext.core, activeKeys); } diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index 1dd61fec9..03c929c48 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -265,6 +265,7 @@ private: QMutex m_bufferMutex; int m_activeKeys = 0; + int m_removedKeys = 0; bool m_autofire[32] = {}; int m_autofireStatus[32] = {}; int m_autofireThreshold = 1; From 87738ba8f383e8d79f4f4b245ce4cee38cb8472d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 16 May 2022 15:58:50 -0700 Subject: [PATCH 02/11] Core: Migrate register access API from debugger into core --- include/mgba/core/core.h | 4 + include/mgba/core/interface.h | 15 +++ include/mgba/debugger/debugger.h | 2 - src/arm/debugger/debugger.c | 80 --------------- src/debugger/cli-debugger.c | 2 +- src/debugger/debugger.c | 2 +- src/gb/core.c | 155 ++++++++++++++++++++++++++++ src/gba/core.c | 170 ++++++++++++++++++++++++++++++- src/sm83/debugger/debugger.c | 132 ------------------------ 9 files changed, 342 insertions(+), 220 deletions(-) diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 96a48ad8e..9af4ffafd 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -135,6 +135,10 @@ struct mCore { size_t (*listMemoryBlocks)(const struct mCore*, const struct mCoreMemoryBlock**); void* (*getMemoryBlock)(struct mCore*, size_t id, size_t* sizeOut); + size_t (*listRegisters)(const struct mCore*, const struct mCoreRegisterInfo**); + bool (*readRegister)(const struct mCore*, const char* name, void* out); + bool (*writeRegister)(struct mCore*, const char* name, const void* in); + #ifdef USE_DEBUGGERS bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType); struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*); diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index d75819d2c..a480db6e5 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -286,6 +286,21 @@ struct mCoreMemoryBlock { uint32_t segmentStart; }; +enum mCoreRegisterType { + mCORE_REGISTER_GPR = 0, + mCORE_REGISTER_FPR, + mCORE_REGISTER_FLAGS, + mCORE_REGISTER_SIMD, +}; + +struct mCoreRegisterInfo { + const char* name; + const char** aliases; + unsigned width; + uint32_t mask; + enum mCoreRegisterType type; +}; + CXX_GUARD_END #endif diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index 7ec09ad7e..fc9ac0f65 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -118,8 +118,6 @@ struct mDebuggerPlatform { void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length); - bool (*getRegister)(struct mDebuggerPlatform*, const char* name, int32_t* value); - bool (*setRegister)(struct mDebuggerPlatform*, const char* name, int32_t value); bool (*lookupIdentifier)(struct mDebuggerPlatform*, const char* name, int32_t* value, int* segment); uint32_t (*getStackTraceMode)(struct mDebuggerPlatform*); diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index 15f6aa181..99fd4ffb4 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -242,8 +242,6 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); static void ARMDebuggerFormatRegisters(struct ARMRegisterFile* regs, char* out, size_t* length); static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out, size_t* length); -static bool ARMDebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value); -static bool ARMDebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value); static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform*); static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform*, uint32_t); static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d); @@ -261,8 +259,6 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { platform->checkBreakpoints = ARMDebuggerCheckBreakpoints; platform->hasBreakpoints = ARMDebuggerHasBreakpoints; platform->trace = ARMDebuggerTrace; - platform->getRegister = ARMDebuggerGetRegister; - platform->setRegister = ARMDebuggerSetRegister; platform->getStackTraceMode = ARMDebuggerGetStackTraceMode; platform->setStackTraceMode = ARMDebuggerSetStackTraceMode; platform->updateStackTrace = ARMDebuggerUpdateStackTrace; @@ -511,82 +507,6 @@ static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out ARMDebuggerFormatRegisters(frame->regs, out, length); } -bool ARMDebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) { - struct ARMDebugger* debugger = (struct ARMDebugger*) d; - struct ARMCore* cpu = debugger->cpu; - - if (strcmp(name, "sp") == 0) { - *value = cpu->gprs[ARM_SP]; - return true; - } - if (strcmp(name, "lr") == 0) { - *value = cpu->gprs[ARM_LR]; - return true; - } - if (strcmp(name, "pc") == 0) { - *value = cpu->gprs[ARM_PC]; - return true; - } - if (strcmp(name, "cpsr") == 0) { - *value = cpu->cpsr.packed; - return true; - } - // TODO: test if mode has SPSR - if (strcmp(name, "spsr") == 0) { - *value = cpu->spsr.packed; - return true; - } - if (name[0] == 'r') { - char* end; - uint32_t reg = strtoul(&name[1], &end, 10); - if (reg <= ARM_PC) { - *value = cpu->gprs[reg]; - return true; - } - } - return false; -} - -bool ARMDebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) { - struct ARMDebugger* debugger = (struct ARMDebugger*) d; - struct ARMCore* cpu = debugger->cpu; - - if (strcmp(name, "sp") == 0) { - cpu->gprs[ARM_SP] = value; - return true; - } - if (strcmp(name, "lr") == 0) { - cpu->gprs[ARM_LR] = value; - return true; - } - if (strcmp(name, "pc") == 0) { - cpu->gprs[ARM_PC] = value; - if (cpu->executionMode == MODE_ARM) { - ARMWritePC(cpu); - } else { - ThumbWritePC(cpu); - } - return true; - } - if (name[0] == 'r') { - char* end; - uint32_t reg = strtoul(&name[1], &end, 10); - if (reg > ARM_PC) { - return false; - } - cpu->gprs[reg] = value; - if (reg == ARM_PC) { - if (cpu->executionMode == MODE_ARM) { - ARMWritePC(cpu); - } else { - ThumbWritePC(cpu); - } - } - return true; - } - return false; -} - static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform* d) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; return debugger->stackTraceMode; diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 2aa024bf2..a89e6db4d 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -452,7 +452,7 @@ static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); return; } - if (!debugger->d.platform->setRegister(debugger->d.platform, dv->charValue, dv->next->intValue)) { + if (!debugger->d.core->writeRegister(debugger->d.core, dv->charValue, &dv->next->intValue)) { debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); } } diff --git a/src/debugger/debugger.c b/src/debugger/debugger.c index 1c6ecd7ef..cc6beab9c 100644 --- a/src/debugger/debugger.c +++ b/src/debugger/debugger.c @@ -156,7 +156,7 @@ bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int if (debugger->core->lookupIdentifier(debugger->core, name, value, segment)) { return true; } - if (debugger->platform && debugger->platform->getRegister(debugger->platform, name, value)) { + if (debugger->platform && debugger->core->readRegister(debugger->core, name, value)) { return true; } return false; diff --git a/src/gb/core.c b/src/gb/core.c index 21cb9d79d..5d55f1b15 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -60,6 +60,23 @@ static const struct mCoreMemoryBlock _GBCMemoryBlocks[] = { { GB_BASE_HRAM, "hram", "HRAM", "High RAM", GB_BASE_HRAM, GB_BASE_HRAM + GB_SIZE_HRAM, GB_SIZE_HRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, }; +static const struct mCoreRegisterInfo _GBRegisters[] = { + { "b", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "c", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "d", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "e", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "h", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "l", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "a", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, + { "f", NULL, 1, 0xF0, mCORE_REGISTER_GPR }, + { "bc", NULL, 2, 0xFFFF, mCORE_REGISTER_GPR }, + { "de", NULL, 2, 0xFFFF, mCORE_REGISTER_GPR }, + { "hl", NULL, 2, 0xFFFF, mCORE_REGISTER_GPR }, + { "af", NULL, 2, 0xFFF0, mCORE_REGISTER_GPR }, + { "pc", NULL, 2, 0xFFFF, mCORE_REGISTER_GPR }, + { "sp", NULL, 2, 0xFFFF, mCORE_REGISTER_GPR }, +}; + struct mVideoLogContext; struct GBCore { struct mCore d; @@ -837,6 +854,141 @@ void* _GBGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) { } } +static size_t _GBCoreListRegisters(const struct mCore* core, const struct mCoreRegisterInfo** list) { + UNUSED(core); + *list = _GBRegisters; + return sizeof(_GBRegisters) / sizeof(*_GBRegisters); +} + +static bool _GBCoreReadRegister(const struct mCore* core, const char* name, void* out) { + struct SM83Core* cpu = core->cpu; + uint16_t* value16 = out; + uint8_t* value8 = out; + + if (strcmp(name, "b") == 0) { + *value8 = cpu->b; + return true; + } + if (strcmp(name, "c") == 0) { + *value8 = cpu->c; + return true; + } + if (strcmp(name, "d") == 0) { + *value8 = cpu->d; + return true; + } + if (strcmp(name, "e") == 0) { + *value8 = cpu->e; + return true; + } + if (strcmp(name, "a") == 0) { + *value8 = cpu->a; + return true; + } + if (strcmp(name, "f") == 0) { + *value8 = cpu->f.packed; + return true; + } + if (strcmp(name, "h") == 0) { + *value8 = cpu->h; + return true; + } + if (strcmp(name, "l") == 0) { + *value8 = cpu->l; + return true; + } + if (strcmp(name, "bc") == 0) { + *value16 = cpu->bc; + return true; + } + if (strcmp(name, "de") == 0) { + *value16 = cpu->de; + return true; + } + if (strcmp(name, "hl") == 0) { + *value16 = cpu->hl; + return true; + } + if (strcmp(name, "af") == 0) { + *value16 = cpu->af; + return true; + } + if (strcmp(name, "pc") == 0) { + *value16 = cpu->pc; + return true; + } + if (strcmp(name, "sp") == 0) { + *value16 = cpu->sp; + return true; + } + return false; +} + +static bool _GBCoreWriteRegister(struct mCore* core, const char* name, const void* in) { + struct SM83Core* cpu = core->cpu; + uint32_t value = *(uint32_t*) in; + + if (strcmp(name, "b") == 0) { + cpu->b = value; + return true; + } + if (strcmp(name, "c") == 0) { + cpu->c = value; + return true; + } + if (strcmp(name, "d") == 0) { + cpu->d = value; + return true; + } + if (strcmp(name, "e") == 0) { + cpu->e = value; + return true; + } + if (strcmp(name, "h") == 0) { + cpu->h = value; + return true; + } + if (strcmp(name, "l") == 0) { + cpu->l = value; + return true; + } + if (strcmp(name, "a") == 0) { + cpu->a = value; + return true; + } + if (strcmp(name, "f") == 0) { + cpu->f.packed = value & 0xF0; + return true; + } + if (strcmp(name, "bc") == 0) { + cpu->bc = value; + return true; + } + if (strcmp(name, "de") == 0) { + cpu->de = value; + return true; + } + if (strcmp(name, "hl") == 0) { + cpu->hl = value; + return true; + } + if (strcmp(name, "af") == 0) { + cpu->af = value; + cpu->f.packed &= 0xF0; + return true; + } + if (strcmp(name, "pc") == 0) { + cpu->pc = value; + cpu->memory.setActiveRegion(cpu, cpu->pc); + return true; + } + if (strcmp(name, "sp") == 0) { + cpu->sp = value; + return true; + } + return false; +} + #ifdef USE_DEBUGGERS static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) { UNUSED(core); @@ -1117,6 +1269,9 @@ struct mCore* GBCoreCreate(void) { core->rawWrite32 = _GBCoreRawWrite32; core->listMemoryBlocks = _GBListMemoryBlocks; core->getMemoryBlock = _GBGetMemoryBlock; + core->listRegisters = _GBCoreListRegisters; + core->readRegister = _GBCoreReadRegister; + core->writeRegister = _GBCoreWriteRegister; #ifdef USE_DEBUGGERS core->supportsDebuggerType = _GBCoreSupportsDebuggerType; core->debuggerPlatform = _GBCoreDebuggerPlatform; diff --git a/src/gba/core.c b/src/gba/core.c index 045eb1972..c00a0db64 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include static const struct mCoreChannelInfo _GBAVideoLayers[] = { { GBA_LAYER_BG0, "bg0", "Background 0", NULL }, @@ -127,6 +129,32 @@ static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = { { REGION_CART_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, SIZE_CART_EEPROM, SIZE_CART_EEPROM, mCORE_MEMORY_RW }, }; +static const struct mCoreRegisterInfo _GBARegisters[] = { + { "r0", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r1", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r2", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r3", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r4", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r5", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r6", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r7", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r8", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r9", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r10", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r11", NULL, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "r12", (const char*[]) { "ip", NULL }, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "sp", (const char*[]) { "r13", NULL }, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "lr", (const char*[]) { "r14", NULL }, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "pc", (const char*[]) { "r15", NULL }, 4, 0xFFFFFFFF, mCORE_REGISTER_GPR }, + { "cpsr", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, + { "spsr", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, + { "spsr_irq", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, + { "spsr_fiq", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, + { "spsr_svc", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, + { "spsr_abt", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, + { "spsr_und", NULL, 4, 0xF00000FF, mCORE_REGISTER_FLAGS }, +}; + struct mVideoLogContext; #define CPU_COMPONENT_AUDIO_MIXER CPU_COMPONENT_MISC_1 @@ -839,7 +867,7 @@ static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment GBAPatch32(cpu, address, value, NULL); } -size_t _GBAListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlock** blocks) { +size_t _GBACoreListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlock** blocks) { const struct GBA* gba = core->board; switch (gba->memory.savedata.type) { case SAVEDATA_SRAM: @@ -860,7 +888,7 @@ size_t _GBAListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBl } } -void* _GBAGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) { +void* _GBACoreGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) { struct GBA* gba = core->board; switch (id) { default: @@ -900,6 +928,137 @@ void* _GBAGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) { } } +static size_t _GBACoreListRegisters(const struct mCore* core, const struct mCoreRegisterInfo** list) { + UNUSED(core); + *list = _GBARegisters; + return sizeof(_GBARegisters) / sizeof(*_GBARegisters); +} + +static bool _GBACoreReadRegister(const struct mCore* core, const char* name, void* out) { + struct ARMCore* cpu = core->cpu; + int32_t* value = out; + switch (name[0]) { + case 'r': + case 'R': + ++name; + break; + case 'c': + case 'C': + if (strcmp(name, "cpsr") == 0 || strcmp(name, "CPSR") == 0) { + *value = cpu->cpsr.packed; + _ARMReadCPSR(cpu); + return true; + } + return false; + case 'i': + case 'I': + if (strcmp(name, "ip") == 0 || strcmp(name, "IP") == 0) { + *value = cpu->gprs[12]; + return true; + } + return false; + case 's': + case 'S': + if (strcmp(name, "sp") == 0 || strcmp(name, "SP") == 0) { + *value = cpu->gprs[ARM_SP]; + return true; + } + // TODO: SPSR + return false; + case 'l': + case 'L': + if (strcmp(name, "lr") == 0 || strcmp(name, "LR") == 0) { + *value = cpu->gprs[ARM_LR]; + return true; + } + return false; + case 'p': + case 'P': + if (strcmp(name, "pc") == 0 || strcmp(name, "PC") == 0) { + *value = cpu->gprs[ARM_PC]; + return true; + } + return false; + default: + return false; + } + + char* parseEnd; + errno = 0; + unsigned long regId = strtoul(name, &parseEnd, 10); + if (errno || regId > 15 || *parseEnd) { + return false; + } + *value = cpu->gprs[regId]; + return true; +} + +static bool _GBACoreWriteRegister(struct mCore* core, const char* name, const void* in) { + struct ARMCore* cpu = core->cpu; + int32_t value = *(const int32_t*) in; + switch (name[0]) { + case 'r': + case 'R': + ++name; + break; + case 'c': + case 'C': + if (strcmp(name, "cpsr") == 0) { + cpu->cpsr.packed = value & 0xF00000FF; + _ARMReadCPSR(cpu); + return true; + } + return false; + case 'i': + case 'I': + if (strcmp(name, "ip") == 0 || strcmp(name, "IP") == 0) { + cpu->gprs[12] = value; + return true; + } + return false; + case 's': + case 'S': + if (strcmp(name, "sp") == 0 || strcmp(name, "SP") == 0) { + cpu->gprs[ARM_SP] = value; + return true; + } + // TODO: SPSR + return false; + case 'l': + case 'L': + if (strcmp(name, "lr") == 0 || strcmp(name, "LR") == 0) { + cpu->gprs[ARM_LR] = value; + return true; + } + return false; + case 'p': + case 'P': + if (strcmp(name, "pc") == 0 || strcmp(name, "PC") == 0) { + name = "15"; + break; + } + return false; + default: + return false; + } + + char* parseEnd; + errno = 0; + unsigned long regId = strtoul(name, &parseEnd, 10); + if (errno || regId > 15 || *parseEnd) { + return false; + } + cpu->gprs[regId] = value; + if (regId == ARM_PC) { + if (cpu->cpsr.t) { + ThumbWritePC(cpu); + } else { + ARMWritePC(cpu); + } + } + return true; +} + #ifdef USE_DEBUGGERS static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) { UNUSED(core); @@ -1233,8 +1392,11 @@ struct mCore* GBACoreCreate(void) { core->rawWrite8 = _GBACoreRawWrite8; core->rawWrite16 = _GBACoreRawWrite16; core->rawWrite32 = _GBACoreRawWrite32; - core->listMemoryBlocks = _GBAListMemoryBlocks; - core->getMemoryBlock = _GBAGetMemoryBlock; + core->listMemoryBlocks = _GBACoreListMemoryBlocks; + core->getMemoryBlock = _GBACoreGetMemoryBlock; + core->listRegisters = _GBACoreListRegisters; + core->readRegister = _GBACoreReadRegister; + core->writeRegister = _GBACoreWriteRegister; #ifdef USE_DEBUGGERS core->supportsDebuggerType = _GBACoreSupportsDebuggerType; core->debuggerPlatform = _GBACoreDebuggerPlatform; diff --git a/src/sm83/debugger/debugger.c b/src/sm83/debugger/debugger.c index c964a992d..edf8afc1e 100644 --- a/src/sm83/debugger/debugger.c +++ b/src/sm83/debugger/debugger.c @@ -72,8 +72,6 @@ static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatch static void SM83DebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool SM83DebuggerHasBreakpoints(struct mDebuggerPlatform*); static void SM83DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); -static bool SM83DebuggerGetRegister(struct mDebuggerPlatform*, const char* name, int32_t* value); -static bool SM83DebuggerSetRegister(struct mDebuggerPlatform*, const char* name, int32_t value); struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void) { struct SM83Debugger* platform = malloc(sizeof(struct SM83Debugger)); @@ -88,8 +86,6 @@ struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void) { platform->d.checkBreakpoints = SM83DebuggerCheckBreakpoints; platform->d.hasBreakpoints = SM83DebuggerHasBreakpoints; platform->d.trace = SM83DebuggerTrace; - platform->d.getRegister = SM83DebuggerGetRegister; - platform->d.setRegister = SM83DebuggerSetRegister; platform->d.getStackTraceMode = NULL; platform->d.setStackTraceMode = NULL; platform->d.updateStackTrace = NULL; @@ -227,131 +223,3 @@ static void SM83DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* le cpu->d, cpu->e, cpu->h, cpu->l, cpu->sp, cpu->memory.currentSegment(cpu, cpu->pc), cpu->pc, disassembly); } - -bool SM83DebuggerGetRegister(struct mDebuggerPlatform* d, const char* name, int32_t* value) { - struct SM83Debugger* debugger = (struct SM83Debugger*) d; - struct SM83Core* cpu = debugger->cpu; - - if (strcmp(name, "a") == 0) { - *value = cpu->a; - return true; - } - if (strcmp(name, "b") == 0) { - *value = cpu->b; - return true; - } - if (strcmp(name, "c") == 0) { - *value = cpu->c; - return true; - } - if (strcmp(name, "d") == 0) { - *value = cpu->d; - return true; - } - if (strcmp(name, "e") == 0) { - *value = cpu->e; - return true; - } - if (strcmp(name, "h") == 0) { - *value = cpu->h; - return true; - } - if (strcmp(name, "l") == 0) { - *value = cpu->l; - return true; - } - if (strcmp(name, "bc") == 0) { - *value = cpu->bc; - return true; - } - if (strcmp(name, "de") == 0) { - *value = cpu->de; - return true; - } - if (strcmp(name, "hl") == 0) { - *value = cpu->hl; - return true; - } - if (strcmp(name, "af") == 0) { - *value = cpu->af; - return true; - } - if (strcmp(name, "pc") == 0) { - *value = cpu->pc; - return true; - } - if (strcmp(name, "sp") == 0) { - *value = cpu->sp; - return true; - } - if (strcmp(name, "f") == 0) { - *value = cpu->f.packed; - return true; - } - return false; -} - -bool SM83DebuggerSetRegister(struct mDebuggerPlatform* d, const char* name, int32_t value) { - struct SM83Debugger* debugger = (struct SM83Debugger*) d; - struct SM83Core* cpu = debugger->cpu; - - if (strcmp(name, "a") == 0) { - cpu->a = value; - return true; - } - if (strcmp(name, "b") == 0) { - cpu->b = value; - return true; - } - if (strcmp(name, "c") == 0) { - cpu->c = value; - return true; - } - if (strcmp(name, "d") == 0) { - cpu->d = value; - return true; - } - if (strcmp(name, "e") == 0) { - cpu->e = value; - return true; - } - if (strcmp(name, "h") == 0) { - cpu->h = value; - return true; - } - if (strcmp(name, "l") == 0) { - cpu->l = value; - return true; - } - if (strcmp(name, "bc") == 0) { - cpu->bc = value; - return true; - } - if (strcmp(name, "de") == 0) { - cpu->de = value; - return true; - } - if (strcmp(name, "hl") == 0) { - cpu->hl = value; - return true; - } - if (strcmp(name, "af") == 0) { - cpu->af = value; - cpu->f.packed &= 0xF0; - return true; - } - if (strcmp(name, "pc") == 0) { - cpu->pc = value; - cpu->memory.setActiveRegion(cpu, cpu->pc); - return true; - } - if (strcmp(name, "sp") == 0) { - cpu->sp = value; - return true; - } - if (strcmp(name, "f") == 0) { - cpu->f.packed = value & 0xF0; - return true; - } - return false; -} From 86b032dac76a0c48d1eabc294ab0c288b033534d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 21 May 2022 17:06:49 -0700 Subject: [PATCH 03/11] GBA Video: Clear window offset on reset (fixes #2471, fixes #2500) --- src/gba/renderers/gl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index b9d74b4df..e45b754ff 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -934,6 +934,11 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { bg->offsetY = 0; } + glRenderer->winN[0].offsetX = 0; + glRenderer->winN[0].offsetY = 0; + glRenderer->winN[1].offsetX = 0; + glRenderer->winN[1].offsetY = 0; + for (i = 0; i < 512; ++i) { int r = M_R5(glRenderer->d.palette[i]); int g = M_G5(glRenderer->d.palette[i]) << 1; From c6d7c40dfcad34d3a0ec0c005d6b1133a23f2f50 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 24 May 2022 19:23:39 -0700 Subject: [PATCH 04/11] GBA: Fix booting multiboot ROMs with no JOY entrypoint --- CHANGES | 1 + src/gba/hle-bios.c | 17 +++++++++++------ src/gba/hle-bios.s | 33 ++++++++++++++++++++++++--------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index 304577ecf..faaf2c15d 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,7 @@ Emulation fixes: - GB Video: Draw SGB border pieces that overlap GB graphics (fixes mgba.io/i/1339) - GBA: Improve timing when not booting from BIOS - GBA: Fix expected entry point for multiboot ELFs (fixes mgba.io/i/2450) + - GBA: Fix booting multiboot ROMs with no JOY entrypoint - GBA BIOS: Work around IRQ handling hiccup in Mario & Luigi (fixes mgba.io/i/1059) - GBA BIOS: Initial HLE timing estimation of UnLz77 functions (fixes mgba.io/i/2141) - GBA DMA: Fix DMA source direction bits being cleared (fixes mgba.io/i/2410) diff --git a/src/gba/hle-bios.c b/src/gba/hle-bios.c index 91a48711b..67424c196 100644 --- a/src/gba/hle-bios.c +++ b/src/gba/hle-bios.c @@ -3,11 +3,11 @@ #include const uint8_t hleBios[SIZE_BIOS] = { - 0x06, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea, + 0xd3, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1, - 0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x58, 0x01, 0x9f, 0xe5, - 0x00, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x02, 0x03, 0xa0, 0x03, - 0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, + 0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02, 0x00, 0x58, 0x2d, 0xe9, 0x02, 0xc0, 0x5e, 0xe5, 0xd4, 0xb0, 0xa0, 0xe3, 0x0c, 0xc1, 0x9b, 0xe7, 0xd2, 0xbf, 0xa0, 0xe3, @@ -35,7 +35,7 @@ const uint8_t hleBios[SIZE_BIOS] = { 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x02, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3, 0x00, 0xe0, 0x8f, 0xe2, 0x04, 0xf0, 0x10, 0xe5, 0x0f, 0x50, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x5e, 0xe5, 0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe0, 0xa0, 0x03, @@ -73,5 +73,10 @@ const uint8_t hleBios[SIZE_BIOS] = { 0x01, 0xa0, 0xa0, 0xe1, 0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8, 0xfa, 0x07, 0xa0, 0xe8, 0x00, 0x10, 0xa0, 0xe3, 0xf0, 0x07, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0xb0, 0x01, 0x00, 0x00, - 0x04, 0xb0, 0x5b, 0xe2, 0xfd, 0xff, 0xff, 0x8a, 0x1e, 0xff, 0x2f, 0xe1 + 0x04, 0xb0, 0x5b, 0xe2, 0xfd, 0xff, 0xff, 0x8a, 0x1e, 0xff, 0x2f, 0xe1, + 0xc2, 0x03, 0xa0, 0xe3, 0x03, 0x10, 0x50, 0xe4, 0x00, 0x00, 0x51, 0xe3, + 0x00, 0x10, 0xa0, 0x13, 0x10, 0xff, 0x2f, 0x11, 0x1c, 0x00, 0x9f, 0xe5, + 0x00, 0x10, 0x90, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x00, 0x10, 0xa0, 0xe3, + 0x10, 0xff, 0x2f, 0x11, 0xc0, 0x00, 0x40, 0xe2, 0x10, 0xff, 0x2f, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, 0xc0, 0x00, 0x00, 0x02 }; diff --git a/src/gba/hle-bios.s b/src/gba/hle-bios.s index 3f9ae905e..85c963157 100644 --- a/src/gba/hle-bios.s +++ b/src/gba/hle-bios.s @@ -16,16 +16,14 @@ nop b irqBase b fiqBase -resetBase: -ldr r0, =0x20000C0 -ldr r1, [r0] -cmp r1, #0 -moveq r0, #0x8000000 -bx r0 -.word 0 -.word 0xE129F000 - .word 0 @ Padding for back-compat +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 +.word 0 swiBase: cmp sp, #0 @@ -113,6 +111,7 @@ swiTable: .word SoundDriverGetJumpList @ 0x2A .ltorg +.word 0 @ Padding for back-compat irqBase: stmfd sp!, {r0-r3, r12, lr} @@ -313,3 +312,19 @@ StallCall: subs r11, #4 bhi StallCall bx lr + +resetBase: +mov r0, #0x8000003 +ldrb r1, [r0], #-3 +cmp r1, #0 +movne r1, #0 +bxne r0 +ldr r0, =0x20000C0 +ldr r1, [r0] +cmp r1, #0 +mov r1, #0 +bxne r0 +sub r0, #0xC0 +bx r0 +.word 0 +.word 0xE129F000 From 6b189fe24996bbb09bb5af095d964a608e8c4dac Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 26 May 2022 21:34:20 -0700 Subject: [PATCH 05/11] README: Update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a7138af7b..fcf61cae3 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ The following mappers are fully supported: - Pokémon Jade/Diamond (unlicensed) - BBD (unlicensed MBC5-like) - Hitek (unlicensed MBC5-like) +- Sachen MMC1 The following mappers are partially supported: @@ -66,6 +67,7 @@ The following mappers are partially supported: - TAMA5 (missing RTC support) - HuC-1 (missing IR support) - HuC-3 (missing IR support) +- Sachen MMC2 (missing alternate wiring support) ### Planned features From 0035b5a22be2b34319ee07162839c46212f752cd Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 23 Jul 2021 17:56:30 -0700 Subject: [PATCH 06/11] Util: Reformat hashing and let it use 64-bit regions --- include/mgba-util/hash.h | 2 +- src/util/hash.c | 113 ++++++++++++++++++++------------------- 2 files changed, 58 insertions(+), 57 deletions(-) diff --git a/include/mgba-util/hash.h b/include/mgba-util/hash.h index 7376ba425..a1f09d3c5 100644 --- a/include/mgba-util/hash.h +++ b/include/mgba-util/hash.h @@ -10,7 +10,7 @@ CXX_GUARD_START -uint32_t hash32(const void* key, int len, uint32_t seed); +uint32_t hash32(const void* key, size_t len, uint32_t seed); CXX_GUARD_END diff --git a/src/util/hash.c b/src/util/hash.c index ebf157442..ed070e86c 100644 --- a/src/util/hash.c +++ b/src/util/hash.c @@ -15,11 +15,11 @@ #define FORCE_INLINE inline __attribute__((always_inline)) -static inline uint32_t rotl32 ( uint32_t x, int8_t r ) { - return (x << r) | (x >> (32 - r)); +static inline uint32_t rotl32(uint32_t x, int8_t r) { + return (x << r) | (x >> (32 - r)); } -#define ROTL32(x,y) rotl32(x,y) +#define ROTL32(x, y) rotl32(x, y) #endif @@ -27,81 +27,82 @@ static inline uint32_t rotl32 ( uint32_t x, int8_t r ) { // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here -static FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i ) { - uint32_t ret; - LOAD_32LE(ret, i << 2, p); - return ret; +static FORCE_INLINE uint32_t getblock32(const uint32_t* p, ssize_t i) { + uint32_t ret; + LOAD_32LE(ret, i << 2, p); + return ret; } //----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche -static FORCE_INLINE uint32_t fmix32 (uint32_t h) { - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; +static FORCE_INLINE uint32_t fmix32(uint32_t h) { + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; - return h; + return h; } //----------------------------------------------------------------------------- -uint32_t hash32(const void* key, int len, uint32_t seed) { - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 4; +uint32_t hash32(const void* key, size_t len, uint32_t seed) { + const uint8_t* data = (const uint8_t*) key; + const int nblocks = len / 4; - uint32_t h1 = seed; + uint32_t h1 = seed; - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; - //---------- - // body + //---------- + // body - const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); + const uint32_t* blocks = (const uint32_t*)(data + nblocks * 4); - int i; - for(i = -nblocks; i; i++) - { - uint32_t k1 = getblock32(blocks,i); + int i; + for (i = -nblocks; i; i++) { + uint32_t k1 = getblock32(blocks, i); - k1 *= c1; - k1 = ROTL32(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = ROTL32(h1,13); - h1 = h1*5+0xe6546b64; - } + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } - //---------- - // tail + //---------- + // tail - const uint8_t * tail = (const uint8_t*)(data + nblocks*4); + const uint8_t* tail = (const uint8_t*)(data + nblocks * 4); - uint32_t k1 = 0; + uint32_t k1 = 0; - switch(len & 3) - { - case 3: - k1 ^= tail[2] << 16; - // Fall through - case 2: - k1 ^= tail[1] << 8; - // Fall through - case 1: - k1 ^= tail[0]; - k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; - }; + switch(len & 3) { + case 3: + k1 ^= tail[2] << 16; + // Fall through + case 2: + k1 ^= tail[1] << 8; + // Fall through + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; - //---------- - // finalization + //---------- + // finalization - h1 ^= len; + h1 ^= len; - h1 = fmix32(h1); + h1 = fmix32(h1); - return h1; + return h1; } From 86f7acbbb977cedaa7ea8e931029880fe10aa395 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 6 Sep 2021 15:39:20 -0700 Subject: [PATCH 07/11] CMake: Add version checking in find_feature --- src/platform/cmake/FindFeature.cmake | 47 ++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/platform/cmake/FindFeature.cmake b/src/platform/cmake/FindFeature.cmake index 50e0c57d3..4a3fa5276 100644 --- a/src/platform/cmake/FindFeature.cmake +++ b/src/platform/cmake/FindFeature.cmake @@ -7,22 +7,57 @@ function(find_feature FEATURE_NAME FEATURE_REQUIRES) set(${FEATURE_NAME} OFF PARENT_SCOPE) return() endif() + if(ARGV2) + set(VERSION "${ARGV2}") + set(FIND_VERSION "${VERSION}" EXACT) + set(PKG_CONFIG_VERSION_CHECK " >=${VERSION}") + else() + set(VERSION) + set(FIND_VERSION) + set(PKG_CONFIG_VERSION_CHECK) + endif() foreach(NAMES ${FEATURE_REQUIRES}) string(REPLACE "|" ";" NAMELIST "${NAMES}") set(FOUND OFF) foreach(REQUIRE ${NAMELIST}) if(NOT ${REQUIRE}_FOUND) - find_package(${REQUIRE} QUIET) + find_package(${REQUIRE} ${FIND_VERSION} QUIET) if(NOT ${REQUIRE}_FOUND) - pkg_search_module(${REQUIRE} ${REQUIRE}) + pkg_search_module(${REQUIRE} "${REQUIRE}${PKG_CONFIG_VERSION_CHECK}") endif() endif() if(${REQUIRE}_FOUND) string(TOUPPER ${REQUIRE} UREQUIRE) - set(${UREQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE) - set(${UREQUIRE}_FOUND ${${REQUIRE}_FOUND} PARENT_SCOPE) - set(${UREQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) - set(${UREQUIRE}_VERSION_STRING ${${REQUIRE}_VERSION_STRING} PARENT_SCOPE) + if(DEFINED ${REQUIRE}_CFLAGS_OTHER) + set(${UREQUIRE}_CFLAGS_OTHER ${${REQUIRE}_CFLAGS_OTHER} PARENT_SCOPE) + elseif(DEFINED ${UREQUIRE}_CFLAGS_OTHER) + set(${UREQUIRE}_CFLAGS_OTHER ${${UREQUIRE}_CFLAGS_OTHER} PARENT_SCOPE) + endif() + if(DEFINED ${REQUIRE}_FOUND) + set(${UREQUIRE}_FOUND ${${REQUIRE}_FOUND} PARENT_SCOPE) + elseif(DEFINED ${UREQUIRE}_FOUND) + set(${UREQUIRE}_FOUND ${${UREQUIRE}_FOUND} PARENT_SCOPE) + endif() + if(DEFINED ${REQUIRE}_INCLUDE_DIRS) + set(${UREQUIRE}_INCLUDE_DIRS ${${REQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) + elseif(DEFINED ${UREQUIRE}_INCLUDE_DIRS) + set(${UREQUIRE}_INCLUDE_DIRS ${${UREQUIRE}_INCLUDE_DIRS} PARENT_SCOPE) + endif() + if(DEFINED ${REQUIRE}_VERSION_STRING) + set(${UREQUIRE}_VERSION_STRING ${${REQUIRE}_VERSION_STRING} PARENT_SCOPE) + elseif(DEFINED ${UREQUIRE}_VERSION_STRING) + set(${UREQUIRE}_VERSION_STRING ${${UREQUIRE}_VERSION_STRING} PARENT_SCOPE) + endif() + if(DEFINED ${REQUIRE}_VERSION_MAJOR) + set(${UREQUIRE}_VERSION_MAJOR ${${REQUIRE}_VERSION_MAJOR} PARENT_SCOPE) + elseif(DEFINED ${UREQUIRE}_VERSION_MAJOR) + set(${UREQUIRE}_VERSION_MAJOR ${${UREQUIRE}_VERSION_MAJOR} PARENT_SCOPE) + endif() + if(DEFINED ${REQUIRE}_VERSION_MINOR) + set(${UREQUIRE}_VERSION_MINOR ${${REQUIRE}_VERSION_MINOR} PARENT_SCOPE) + elseif(DEFINED ${UREQUIRE}_VERSION_MINOR) + set(${UREQUIRE}_VERSION_MINOR ${${UREQUIRE}_VERSION_MINOR} PARENT_SCOPE) + endif() if (APPLE) set(IS_FRAMEWORK OFF) set(LIBS) From ab3cd84ed4ac7c1c1b056a095612bf501befc98a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 8 May 2022 22:40:29 -0700 Subject: [PATCH 08/11] Qt: Refactor out log widget --- src/platform/qt/CMakeLists.txt | 1 + src/platform/qt/DebuggerConsole.cpp | 13 +++---------- src/platform/qt/DebuggerConsole.h | 1 - src/platform/qt/DebuggerConsole.ui | 9 ++++++++- src/platform/qt/LogWidget.cpp | 24 ++++++++++++++++++++++++ src/platform/qt/LogWidget.h | 20 ++++++++++++++++++++ 6 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 src/platform/qt/LogWidget.cpp create mode 100644 src/platform/qt/LogWidget.h diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index bd1edadfd..4399bfcfb 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -109,6 +109,7 @@ set(SOURCE_FILES LogController.cpp LogConfigModel.cpp LogView.cpp + LogWidget.cpp MapView.cpp MemoryDump.cpp MemoryModel.cpp diff --git a/src/platform/qt/DebuggerConsole.cpp b/src/platform/qt/DebuggerConsole.cpp index 0a4beb909..a0fd266ac 100644 --- a/src/platform/qt/DebuggerConsole.cpp +++ b/src/platform/qt/DebuggerConsole.cpp @@ -8,7 +8,7 @@ #include "DebuggerConsoleController.h" #include "GBAApp.h" -#include +#include using namespace QGBA; @@ -19,23 +19,16 @@ DebuggerConsole::DebuggerConsole(DebuggerConsoleController* controller, QWidget* m_ui.setupUi(this); m_ui.prompt->installEventFilter(this); - m_ui.log->setFont(GBAApp::app()->monospaceFont()); m_ui.prompt->setFont(GBAApp::app()->monospaceFont()); connect(m_ui.prompt, &QLineEdit::returnPressed, this, &DebuggerConsole::postLine); - connect(controller, &DebuggerConsoleController::log, this, &DebuggerConsole::log); + connect(controller, &DebuggerConsoleController::log, m_ui.log, &LogWidget::log); connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::attach); connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::breakInto); controller->historyLoad(); } -void DebuggerConsole::log(const QString& line) { - m_ui.log->moveCursor(QTextCursor::End); - m_ui.log->insertPlainText(line); - m_ui.log->verticalScrollBar()->setValue(m_ui.log->verticalScrollBar()->maximum()); -} - void DebuggerConsole::postLine() { m_consoleController->attach(); QString line = m_ui.prompt->text(); @@ -44,7 +37,7 @@ void DebuggerConsole::postLine() { m_consoleController->enterLine(QString("\n")); } else { m_historyOffset = 0; - log(QString("> %1\n").arg(line)); + m_ui.log->log(QString("> %1\n").arg(line)); m_consoleController->enterLine(line); } } diff --git a/src/platform/qt/DebuggerConsole.h b/src/platform/qt/DebuggerConsole.h index d13ef4a13..f98635a68 100644 --- a/src/platform/qt/DebuggerConsole.h +++ b/src/platform/qt/DebuggerConsole.h @@ -18,7 +18,6 @@ public: DebuggerConsole(DebuggerConsoleController* controller, QWidget* parent = nullptr); private slots: - void log(const QString&); void postLine(); protected: diff --git a/src/platform/qt/DebuggerConsole.ui b/src/platform/qt/DebuggerConsole.ui index 4199e1e83..5cfe6512c 100644 --- a/src/platform/qt/DebuggerConsole.ui +++ b/src/platform/qt/DebuggerConsole.ui @@ -29,7 +29,7 @@ - + true @@ -37,6 +37,13 @@ + + + QGBA::LogWidget + QPlainTextEdit +
LogWidget.h
+
+
diff --git a/src/platform/qt/LogWidget.cpp b/src/platform/qt/LogWidget.cpp new file mode 100644 index 000000000..136df178c --- /dev/null +++ b/src/platform/qt/LogWidget.cpp @@ -0,0 +1,24 @@ +/* Copyright (c) 2013-2022 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 "LogWidget.h" + +#include "GBAApp.h" + +#include + +using namespace QGBA; + +LogWidget::LogWidget(QWidget* parent) + : QTextEdit(parent) +{ + setFont(GBAApp::app()->monospaceFont()); +} + +void LogWidget::log(const QString& line) { + moveCursor(QTextCursor::End); + insertPlainText(line); + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); +} diff --git a/src/platform/qt/LogWidget.h b/src/platform/qt/LogWidget.h new file mode 100644 index 000000000..700f7aaf6 --- /dev/null +++ b/src/platform/qt/LogWidget.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2022 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/. */ +#pragma once + +#include + +namespace QGBA { + +class LogWidget : public QTextEdit { +public: + LogWidget(QWidget* parent = nullptr); + +public slots: + void log(const QString&); +}; + +} From 68c57df1f6fd341642b038888658ace1be20c23f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 29 Aug 2021 18:23:50 -0700 Subject: [PATCH 09/11] Util: Add custom callbacks for hash tables --- include/mgba-util/table.h | 16 +++- src/util/table.c | 181 +++++++++++++++++++++++++++++++------- 2 files changed, 164 insertions(+), 33 deletions(-) diff --git a/include/mgba-util/table.h b/include/mgba-util/table.h index 8e668b767..ea2c21748 100644 --- a/include/mgba-util/table.h +++ b/include/mgba-util/table.h @@ -11,13 +11,22 @@ CXX_GUARD_START struct TableList; +typedef uint32_t (*HashFunction)(const void* key, size_t len, uint32_t seed); + +struct TableFunctions { + void (*deinitializer)(void*); + HashFunction hash; + bool (*equal)(const void*, const void*); + void* (*ref)(void*); + void (*deref)(void*); +}; struct Table { struct TableList* table; size_t tableSize; size_t size; - void (*deinitializer)(void*); uint32_t seed; + struct TableFunctions fn; }; void TableInit(struct Table*, size_t initialSize, void (*deinitializer)(void*)); @@ -33,19 +42,24 @@ void TableEnumerate(const struct Table*, void (*handler)(uint32_t key, void* val size_t TableSize(const struct Table*); void HashTableInit(struct Table* table, size_t initialSize, void (*deinitializer)(void*)); +void HashTableInitCustom(struct Table* table, size_t initialSize, const struct TableFunctions* funcs); void HashTableDeinit(struct Table* table); void* HashTableLookup(const struct Table*, const char* key); void* HashTableLookupBinary(const struct Table*, const void* key, size_t keylen); +void* HashTableLookupCustom(const struct Table*, void* key); void HashTableInsert(struct Table*, const char* key, void* value); void HashTableInsertBinary(struct Table*, const void* key, size_t keylen, void* value); +void HashTableInsertCustom(struct Table*, void* key, void* value); void HashTableRemove(struct Table*, const char* key); void HashTableRemoveBinary(struct Table*, const void* key, size_t keylen); +void HashTableRemoveCustom(struct Table*, void* key); void HashTableClear(struct Table*); void HashTableEnumerate(const struct Table*, void (*handler)(const char* key, void* value, void* user), void* user); void HashTableEnumerateBinary(const struct Table*, void (*handler)(const char* key, size_t keylen, void* value, void* user), void* user); +void HashTableEnumerateCustom(const struct Table*, void (*handler)(const char* key, void* value, void* user), void* user); const char* HashTableSearch(const struct Table* table, bool (*predicate)(const char* key, const void* value, const void* user), const void* user); const char* HashTableSearchPointer(const struct Table* table, const void* value); const char* HashTableSearchData(const struct Table* table, const void* value, size_t bytes); diff --git a/src/util/table.c b/src/util/table.c index a0d98b22e..b23c88de8 100644 --- a/src/util/table.c +++ b/src/util/table.c @@ -16,6 +16,7 @@ #define TABLE_COMPARATOR(LIST, INDEX) LIST->list[(INDEX)].key == key #define HASH_TABLE_STRNCMP_COMPARATOR(LIST, INDEX) LIST->list[(INDEX)].key == hash && strncmp(LIST->list[(INDEX)].stringKey, key, LIST->list[(INDEX)].keylen) == 0 #define HASH_TABLE_MEMCMP_COMPARATOR(LIST, INDEX) LIST->list[(INDEX)].key == hash && LIST->list[(INDEX)].keylen == keylen && memcmp(LIST->list[(INDEX)].stringKey, key, LIST->list[(INDEX)].keylen) == 0 +#define HASH_TABLE_CUSTOM_COMPARATOR(LIST, INDEX) LIST->list[(INDEX)].key == hash && table->fn.equal(LIST->list[(INDEX)].stringKey, key) #define TABLE_LOOKUP_START(COMPARATOR, LIST) \ size_t i; \ @@ -68,9 +69,13 @@ static struct TableList* _resizeAsNeeded(struct Table* table, struct TableList* static void _removeItemFromList(struct Table* table, struct TableList* list, size_t item) { --list->nEntries; --table->size; - free(list->list[item].stringKey); - if (table->deinitializer) { - table->deinitializer(list->list[item].value); + if (table->fn.deref) { + table->fn.deref(list->list[item].stringKey); + } else { + free(list->list[item].stringKey); + } + if (table->fn.deinitializer) { + table->fn.deinitializer(list->list[item].value); } if (item != list->nEntries) { list->list[item] = list->list[list->nEntries]; @@ -80,13 +85,19 @@ static void _removeItemFromList(struct Table* table, struct TableList* list, siz static void _rebalance(struct Table* table) { struct Table newTable; TableInit(&newTable, table->tableSize * REBALANCE_THRESHOLD, NULL); + memcpy(&newTable.fn, &table->fn, sizeof(newTable.fn)); newTable.seed = table->seed * 134775813 + 1; size_t i; for (i = 0; i < table->tableSize; ++i) { - const struct TableList* list = &table->table[i]; + struct TableList* list = &table->table[i]; size_t j; for (j = 0; j < list->nEntries; ++j) { - HashTableInsertBinaryMoveKey(&newTable, list->list[j].stringKey, list->list[j].keylen, list->list[j].value); + if (!table->fn.equal) { + HashTableInsertBinaryMoveKey(&newTable, list->list[j].stringKey, list->list[j].keylen, list->list[j].value); + } else { + HashTableInsertCustom(&newTable, list->list[j].stringKey, list->list[j].value); + table->fn.deref(list->list[j].stringKey); + } } free(list->list); } @@ -105,7 +116,9 @@ void TableInit(struct Table* table, size_t initialSize, void (*deinitializer)(vo table->tableSize = initialSize; table->table = calloc(table->tableSize, sizeof(struct TableList)); table->size = 0; - table->deinitializer = deinitializer; + table->fn = (struct TableFunctions) { + .deinitializer = deinitializer + }; table->seed = 0; size_t i; @@ -122,9 +135,13 @@ void TableDeinit(struct Table* table) { struct TableList* list = &table->table[i]; size_t j; for (j = 0; j < list->nEntries; ++j) { - free(list->list[j].stringKey); - if (table->deinitializer) { - table->deinitializer(list->list[j].value); + if (table->fn.deref) { + table->fn.deref(list->list[j].stringKey); + } else { + free(list->list[j].stringKey); + } + if (table->fn.deinitializer) { + table->fn.deinitializer(list->list[j].value); } } free(list->list); @@ -146,8 +163,8 @@ void TableInsert(struct Table* table, uint32_t key, void* value) { struct TableList* list = _getList(table, key); TABLE_LOOKUP_START(TABLE_COMPARATOR, list) { if (value != lookupResult->value) { - if (table->deinitializer) { - table->deinitializer(lookupResult->value); + if (table->fn.deinitializer) { + table->fn.deinitializer(lookupResult->value); } lookupResult->value = value; } @@ -172,10 +189,10 @@ void TableClear(struct Table* table) { size_t i; for (i = 0; i < table->tableSize; ++i) { struct TableList* list = &table->table[i]; - if (table->deinitializer) { + if (table->fn.deinitializer) { size_t j; for (j = 0; j < list->nEntries; ++j) { - table->deinitializer(list->list[j].value); + table->fn.deinitializer(list->list[j].value); } } free(list->list); @@ -205,12 +222,22 @@ void HashTableInit(struct Table* table, size_t initialSize, void (*deinitializer table->seed = 1; } +void HashTableInitCustom(struct Table* table, size_t initialSize, const struct TableFunctions* funcs) { + HashTableInit(table, initialSize, NULL); + table->fn = *funcs; +} + void HashTableDeinit(struct Table* table) { TableDeinit(table); } void* HashTableLookup(const struct Table* table, const char* key) { - uint32_t hash = hash32(key, strlen(key), table->seed); + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, strlen(key), table->seed); + } else { + hash = hash32(key, strlen(key), table->seed); + } const struct TableList* list = _getConstList(table, hash); TABLE_LOOKUP_START(HASH_TABLE_STRNCMP_COMPARATOR, list) { return lookupResult->value; @@ -219,7 +246,12 @@ void* HashTableLookup(const struct Table* table, const char* key) { } void* HashTableLookupBinary(const struct Table* table, const void* key, size_t keylen) { - uint32_t hash = hash32(key, keylen, table->seed); + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { + hash = hash32(key, keylen, table->seed); + } const struct TableList* list = _getConstList(table, hash); TABLE_LOOKUP_START(HASH_TABLE_MEMCMP_COMPARATOR, list) { return lookupResult->value; @@ -227,18 +259,36 @@ void* HashTableLookupBinary(const struct Table* table, const void* key, size_t k return 0; } +void* HashTableLookupCustom(const struct Table* table, void* key) { + uint32_t hash = table->fn.hash(key, 0, table->seed); + const struct TableList* list = _getConstList(table, hash); + TABLE_LOOKUP_START(HASH_TABLE_CUSTOM_COMPARATOR, list) { + return lookupResult->value; + } TABLE_LOOKUP_END; + return 0; +} + void HashTableInsert(struct Table* table, const char* key, void* value) { - uint32_t hash = hash32(key, strlen(key), table->seed); + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, strlen(key), table->seed); + } else { + hash = hash32(key, strlen(key), table->seed); + } struct TableList* list = _getList(table, hash); if (table->size >= table->tableSize * REBALANCE_THRESHOLD) { _rebalance(table); - hash = hash32(key, strlen(key), table->seed); + if (table->fn.hash) { + hash = table->fn.hash(key, strlen(key), table->seed); + } else { + hash = hash32(key, strlen(key), table->seed); + } list = _getList(table, hash); } TABLE_LOOKUP_START(HASH_TABLE_STRNCMP_COMPARATOR, list) { if (value != lookupResult->value) { - if (table->deinitializer) { - table->deinitializer(lookupResult->value); + if (table->fn.deinitializer) { + table->fn.deinitializer(lookupResult->value); } lookupResult->value = value; } @@ -254,17 +304,26 @@ void HashTableInsert(struct Table* table, const char* key, void* value) { } void HashTableInsertBinary(struct Table* table, const void* key, size_t keylen, void* value) { - uint32_t hash = hash32(key, keylen, table->seed); + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { + hash = hash32(key, keylen, table->seed); + } struct TableList* list = _getList(table, hash); if (table->size >= table->tableSize * REBALANCE_THRESHOLD) { _rebalance(table); - hash = hash32(key, keylen, table->seed); + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { + hash = hash32(key, keylen, table->seed); + } list = _getList(table, hash); } TABLE_LOOKUP_START(HASH_TABLE_MEMCMP_COMPARATOR, list) { if (value != lookupResult->value) { - if (table->deinitializer) { - table->deinitializer(lookupResult->value); + if (table->fn.deinitializer) { + table->fn.deinitializer(lookupResult->value); } lookupResult->value = value; } @@ -280,18 +339,53 @@ void HashTableInsertBinary(struct Table* table, const void* key, size_t keylen, ++table->size; } -void HashTableInsertBinaryMoveKey(struct Table* table, void* key, size_t keylen, void* value) { - uint32_t hash = hash32(key, keylen, table->seed); +void HashTableInsertCustom(struct Table* table, void* key, void* value) { + uint32_t hash = table->fn.hash(key, 0, table->seed); struct TableList* list = _getList(table, hash); if (table->size >= table->tableSize * REBALANCE_THRESHOLD) { _rebalance(table); + hash = table->fn.hash(key, 0, table->seed); + list = _getList(table, hash); + } + TABLE_LOOKUP_START(HASH_TABLE_CUSTOM_COMPARATOR, list) { + if (value != lookupResult->value) { + if (table->fn.deinitializer) { + table->fn.deinitializer(lookupResult->value); + } + lookupResult->value = value; + } + return; + } TABLE_LOOKUP_END; + list = _resizeAsNeeded(table, list, hash); + list->list[list->nEntries].key = hash; + list->list[list->nEntries].stringKey = table->fn.ref(key); + list->list[list->nEntries].keylen = 0; + list->list[list->nEntries].value = value; + ++list->nEntries; + ++table->size; +} + +void HashTableInsertBinaryMoveKey(struct Table* table, void* key, size_t keylen, void* value) { + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { hash = hash32(key, keylen, table->seed); + } + struct TableList* list = _getList(table, hash); + if (table->size >= table->tableSize * REBALANCE_THRESHOLD) { + _rebalance(table); + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { + hash = hash32(key, keylen, table->seed); + } list = _getList(table, hash); } TABLE_LOOKUP_START(HASH_TABLE_MEMCMP_COMPARATOR, list) { if (value != lookupResult->value) { - if (table->deinitializer) { - table->deinitializer(lookupResult->value); + if (table->fn.deinitializer) { + table->fn.deinitializer(lookupResult->value); } lookupResult->value = value; } @@ -307,7 +401,13 @@ void HashTableInsertBinaryMoveKey(struct Table* table, void* key, size_t keylen, } void HashTableRemove(struct Table* table, const char* key) { - uint32_t hash = hash32(key, strlen(key), table->seed); + uint32_t hash; + + if (table->fn.hash) { + hash = table->fn.hash(key, strlen(key), table->seed); + } else { + hash = hash32(key, strlen(key), table->seed); + } struct TableList* list = _getList(table, hash); TABLE_LOOKUP_START(HASH_TABLE_STRNCMP_COMPARATOR, list) { _removeItemFromList(table, list, i); // TODO: Move i out of the macro @@ -315,23 +415,40 @@ void HashTableRemove(struct Table* table, const char* key) { } void HashTableRemoveBinary(struct Table* table, const void* key, size_t keylen) { - uint32_t hash = hash32(key, keylen, table->seed); + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { + hash = hash32(key, keylen, table->seed); + } struct TableList* list = _getList(table, hash); TABLE_LOOKUP_START(HASH_TABLE_MEMCMP_COMPARATOR, list) { _removeItemFromList(table, list, i); // TODO: Move i out of the macro } TABLE_LOOKUP_END; } +void HashTableRemoveCustom(struct Table* table, void* key) { + uint32_t hash = table->fn.hash(key, 0, table->seed); + struct TableList* list = _getList(table, hash); + TABLE_LOOKUP_START(HASH_TABLE_CUSTOM_COMPARATOR, list) { + _removeItemFromList(table, list, i); // TODO: Move i out of the macro + } TABLE_LOOKUP_END; +} + void HashTableClear(struct Table* table) { size_t i; for (i = 0; i < table->tableSize; ++i) { struct TableList* list = &table->table[i]; size_t j; for (j = 0; j < list->nEntries; ++j) { - if (table->deinitializer) { - table->deinitializer(list->list[j].value); + if (table->fn.deinitializer) { + table->fn.deinitializer(list->list[j].value); + } + if (table->fn.deref) { + table->fn.deref(list->list[j].stringKey); + } else { + free(list->list[j].stringKey); } - free(list->list[j].stringKey); } free(list->list); list->listSize = LIST_INITIAL_SIZE; From 4c1d44692c4187bde16bbe645bdf7381198dc254 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 15 May 2022 01:17:53 -0700 Subject: [PATCH 10/11] Util: Add Table iterators --- include/mgba-util/table.h | 22 ++++++ src/util/CMakeLists.txt | 1 + src/util/table.c | 120 +++++++++++++++++++++++++++++ src/util/test/table.c | 158 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 301 insertions(+) create mode 100644 src/util/test/table.c diff --git a/include/mgba-util/table.h b/include/mgba-util/table.h index ea2c21748..b950fcb3b 100644 --- a/include/mgba-util/table.h +++ b/include/mgba-util/table.h @@ -29,6 +29,11 @@ struct Table { struct TableFunctions fn; }; +struct TableIterator { + size_t bucket; + size_t entry; +}; + void TableInit(struct Table*, size_t initialSize, void (*deinitializer)(void*)); void TableDeinit(struct Table*); @@ -41,6 +46,12 @@ void TableClear(struct Table*); void TableEnumerate(const struct Table*, void (*handler)(uint32_t key, void* value, void* user), void* user); size_t TableSize(const struct Table*); +bool TableIteratorStart(const struct Table*, struct TableIterator*); +bool TableIteratorNext(const struct Table*, struct TableIterator*); +uint32_t TableIteratorGetKey(const struct Table*, const struct TableIterator*); +void* TableIteratorGetValue(const struct Table*, const struct TableIterator*); +bool TableIteratorLookup(const struct Table*, struct TableIterator*, uint32_t key); + void HashTableInit(struct Table* table, size_t initialSize, void (*deinitializer)(void*)); void HashTableInitCustom(struct Table* table, size_t initialSize, const struct TableFunctions* funcs); void HashTableDeinit(struct Table* table); @@ -66,6 +77,17 @@ const char* HashTableSearchData(const struct Table* table, const void* value, si const char* HashTableSearchString(const struct Table* table, const char* value); size_t HashTableSize(const struct Table*); +bool HashTableIteratorStart(const struct Table*, struct TableIterator*); +bool HashTableIteratorNext(const struct Table*, struct TableIterator*); +const char* HashTableIteratorGetKey(const struct Table*, const struct TableIterator*); +const void* HashTableIteratorGetBinaryKey(const struct Table*, const struct TableIterator*); +size_t HashTableIteratorGetBinaryKeyLen(const struct Table*, const struct TableIterator*); +void* HashTableIteratorGetCustomKey(const struct Table*, const struct TableIterator*); +void* HashTableIteratorGetValue(const struct Table*, const struct TableIterator*); +bool HashTableIteratorLookup(const struct Table*, struct TableIterator*, const char* key); +bool HashTableIteratorLookupBinary(const struct Table*, struct TableIterator*, const void* key, size_t keylen); +bool HashTableIteratorLookupCustom(const struct Table*, struct TableIterator*, void* key); + CXX_GUARD_END #endif diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index d43f901f7..8d86f7b60 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -30,6 +30,7 @@ set(GUI_FILES set(TEST_FILES test/string-parser.c test/string-utf8.c + test/table.c test/text-codec.c test/vfs.c) diff --git a/src/util/table.c b/src/util/table.c index b23c88de8..ca256db7a 100644 --- a/src/util/table.c +++ b/src/util/table.c @@ -217,6 +217,52 @@ size_t TableSize(const struct Table* table) { return table->size; } +bool TableIteratorStart(const struct Table* table, struct TableIterator* iter) { + iter->entry = 0; + for (iter->bucket = 0; iter->bucket < table->tableSize; ++iter->bucket) { + if (table->table[iter->bucket].nEntries) { + break; + } + } + return iter->bucket < table->tableSize; +} + +bool TableIteratorNext(const struct Table* table, struct TableIterator* iter) { + if (iter->entry + 1 < table->table[iter->bucket].nEntries) { + ++iter->entry; + return true; + } + if (iter->bucket + 1 < table->tableSize) { + iter->entry = 0; + for (++iter->bucket; iter->bucket < table->tableSize; ++iter->bucket) { + if (table->table[iter->bucket].nEntries) { + break; + } + } + return iter->bucket < table->tableSize; + } + return false; +} + +uint32_t TableIteratorGetKey(const struct Table* table, const struct TableIterator* iter) { + return table->table[iter->bucket].list[iter->entry].key; +} + +void* TableIteratorGetValue(const struct Table* table, const struct TableIterator* iter) { + return table->table[iter->bucket].list[iter->entry].value; +} + +bool TableIteratorLookup(const struct Table* table, struct TableIterator* iter, uint32_t key) { + uint32_t bucket = key & (table->tableSize - 1); + const struct TableList* list = &table->table[bucket]; + TABLE_LOOKUP_START(TABLE_COMPARATOR, list) { + iter->bucket = bucket; + iter->entry = i; + return true; + } TABLE_LOOKUP_END; + return false; +} + void HashTableInit(struct Table* table, size_t initialSize, void (*deinitializer)(void*)) { TableInit(table, initialSize, deinitializer); table->seed = 1; @@ -531,3 +577,77 @@ const char* HashTableSearchString(const struct Table* table, const char* value) size_t HashTableSize(const struct Table* table) { return table->size; } + +bool HashTableIteratorStart(const struct Table* table, struct TableIterator* iter) { + return TableIteratorStart(table, iter); +} + +bool HashTableIteratorNext(const struct Table* table, struct TableIterator* iter) { + return TableIteratorNext(table, iter); +} + +const char* HashTableIteratorGetKey(const struct Table* table, const struct TableIterator* iter) { + return table->table[iter->bucket].list[iter->entry].stringKey; +} + +const void* HashTableIteratorGetBinaryKey(const struct Table* table, const struct TableIterator* iter) { + return table->table[iter->bucket].list[iter->entry].stringKey; +} + +size_t HashTableIteratorGetBinaryKeyLen(const struct Table* table, const struct TableIterator* iter) { + return table->table[iter->bucket].list[iter->entry].keylen; +} + +void* HashTableIteratorGetCustomKey(const struct Table* table, const struct TableIterator* iter) { + return (char*) table->table[iter->bucket].list[iter->entry].stringKey; +} + +void* HashTableIteratorGetValue(const struct Table* table, const struct TableIterator* iter) { + return TableIteratorGetValue(table, iter); +} + +bool HashTableIteratorLookup(const struct Table* table, struct TableIterator* iter, const char* key) { + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, strlen(key), table->seed); + } else { + hash = hash32(key, strlen(key), table->seed); + } + uint32_t bucket = hash & (table->tableSize - 1); + const struct TableList* list = &table->table[bucket]; + TABLE_LOOKUP_START(HASH_TABLE_STRNCMP_COMPARATOR, list) { + iter->bucket = bucket; + iter->entry = i; + return true; + } TABLE_LOOKUP_END; + return false; +} + +bool HashTableIteratorLookupBinary(const struct Table* table, struct TableIterator* iter, const void* key, size_t keylen) { + uint32_t hash; + if (table->fn.hash) { + hash = table->fn.hash(key, keylen, table->seed); + } else { + hash = hash32(key, keylen, table->seed); + } + uint32_t bucket = hash & (table->tableSize - 1); + const struct TableList* list = &table->table[bucket]; + TABLE_LOOKUP_START(HASH_TABLE_MEMCMP_COMPARATOR, list) { + iter->bucket = bucket; + iter->entry = i; + return true; + } TABLE_LOOKUP_END; + return false; +} + +bool HashTableIteratorLookupCustom(const struct Table* table, struct TableIterator* iter, void* key) { + uint32_t hash = table->fn.hash(key, 0, table->seed); + uint32_t bucket = hash & (table->tableSize - 1); + const struct TableList* list = &table->table[bucket]; + TABLE_LOOKUP_START(HASH_TABLE_CUSTOM_COMPARATOR, list) { + iter->bucket = bucket; + iter->entry = i; + return true; + } TABLE_LOOKUP_END; + return false; +} diff --git a/src/util/test/table.c b/src/util/test/table.c new file mode 100644 index 000000000..31d1b5f0a --- /dev/null +++ b/src/util/test/table.c @@ -0,0 +1,158 @@ +/* Copyright (c) 2013-2022 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 "util/test/suite.h" + +#include + +M_TEST_DEFINE(basic) { + struct Table table; + TableInit(&table, 0, NULL); + + size_t i; + for (i = 0; i < 5000; ++i) { + TableInsert(&table, i, (void*) i); + } + + for (i = 0; i < 5000; ++i) { + assert_int_equal(i, (size_t) TableLookup(&table, i)); + } + + TableDeinit(&table); +} + +M_TEST_DEFINE(iterator) { + struct Table table; + struct TableIterator iter; + + TableInit(&table, 0, NULL); + assert_false(TableIteratorStart(&table, &iter)); + + size_t i; + for (i = 0; i < 32; ++i) { + TableInsert(&table, i, (void*) i); + } + + assert_true(TableIteratorStart(&table, &iter)); + uint32_t mask = 0; + while (true) { + assert_int_equal(TableIteratorGetKey(&table, &iter), (uintptr_t) TableIteratorGetValue(&table, &iter)); + mask ^= 1 << TableIteratorGetKey(&table, &iter); + if (!TableIteratorNext(&table, &iter)) { + break; + } + } + assert_int_equal(mask, 0xFFFFFFFFU); + + TableDeinit(&table); +} + +M_TEST_DEFINE(iteratorLookup) { + struct Table table; + struct TableIterator iter; + + TableInit(&table, 0, NULL); + + size_t i; + for (i = 0; i < 500; ++i) { + TableInsert(&table, (i * 0x5DEECE66D) >> 16, (void*) i); + } + + for (i = 0; i < 500; ++i) { + assert_true(TableIteratorLookup(&table, &iter, (i * 0x5DEECE66D) >> 16)); + assert_int_equal(TableIteratorGetKey(&table, &iter), (i * 0x5DEECE66D) >> 16); + assert_int_equal((uintptr_t) TableIteratorGetValue(&table, &iter), i); + } + for (i = 1000; i < 1200; ++i) { + assert_false(TableIteratorLookup(&table, &iter, (i * 0x5DEECE66D) >> 16)); + } + + TableDeinit(&table); +} + +M_TEST_DEFINE(hash) { + struct Table table; + HashTableInit(&table, 0, NULL); + + size_t i; + for (i = 0; i < 5000; ++i) { + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%"PRIz"i", i); + HashTableInsert(&table, buffer, (void*) i); + } + + for (i = 0; i < 5000; ++i) { + char buffer[16]; + snprintf(buffer, sizeof(buffer), "%"PRIz"i", i); + assert_int_equal(i, (size_t) HashTableLookup(&table, buffer)); + } + + HashTableDeinit(&table); +} + +M_TEST_DEFINE(hashIterator) { + struct Table table; + struct TableIterator iter; + char buf[18]; + + HashTableInit(&table, 0, NULL); + assert_false(HashTableIteratorStart(&table, &iter)); + + size_t i; + for (i = 0; i < 32; ++i) { + snprintf(buf, sizeof(buf), "%zu", i); + HashTableInsert(&table, buf, (void*) i); + } + + assert_true(TableIteratorStart(&table, &iter)); + uint32_t mask = 0; + while (true) { + assert_int_equal(atoi(HashTableIteratorGetKey(&table, &iter)), (uintptr_t) HashTableIteratorGetValue(&table, &iter)); + mask ^= 1 << atoi(HashTableIteratorGetKey(&table, &iter)); + if (!HashTableIteratorNext(&table, &iter)) { + break; + } + } + assert_int_equal(mask, 0xFFFFFFFFU); + + HashTableDeinit(&table); +} + + +M_TEST_DEFINE(hashIteratorLookup) { + struct Table table; + struct TableIterator iter; + char buf[18]; + + HashTableInit(&table, 0, NULL); + + size_t i; + for (i = 0; i < 500; ++i) { + snprintf(buf, sizeof(buf), "%zu", (i * 0x5DEECE66D) >> 4); + HashTableInsert(&table, buf, (void*) i); + } + + for (i = 0; i < 500; ++i) { + snprintf(buf, sizeof(buf), "%zu", (i * 0x5DEECE66D) >> 4); + assert_true(HashTableIteratorLookup(&table, &iter, buf)); + assert_string_equal(HashTableIteratorGetKey(&table, &iter), buf); + assert_int_equal((uintptr_t) HashTableIteratorGetValue(&table, &iter), i); + } + for (i = 1000; i < 1200; ++i) { + snprintf(buf, sizeof(buf), "%zu", (i * 0x5DEECE66D) >> 4); + assert_false(HashTableIteratorLookup(&table, &iter, buf)); + } + + HashTableDeinit(&table); +} + +M_TEST_SUITE_DEFINE(Table, + cmocka_unit_test(basic), + cmocka_unit_test(iterator), + cmocka_unit_test(iteratorLookup), + cmocka_unit_test(hash), + cmocka_unit_test(hashIterator), + cmocka_unit_test(hashIteratorLookup), +) From a7710ed8d536c1efa8d8e0da2e67f52b39620274 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 27 May 2022 00:42:02 -0700 Subject: [PATCH 11/11] ARM: Fix warning spew --- src/arm/isa-arm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index 576eeb874..b3bb3c9da 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -287,7 +287,7 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { SHIFTER(cpu, opcode); \ int rd = (opcode >> 12) & 0xF; \ int rn = (opcode >> 16) & 0xF; \ - int32_t n = cpu->gprs[rn]; \ + int32_t n ATTRIBUTE_UNUSED = cpu->gprs[rn]; \ if (UNLIKELY(rn == ARM_PC && (opcode & 0x02000010) == 0x00000010)) { \ n += WORD_SIZE_ARM; \ } \ @@ -358,7 +358,7 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { uint32_t address; \ int rn = (opcode >> 16) & 0xF; \ int rd = (opcode >> 12) & 0xF; \ - int32_t d = cpu->gprs[rd]; \ + int32_t d ATTRIBUTE_UNUSED = cpu->gprs[rd]; \ if (UNLIKELY(rd == ARM_PC)) { \ d += WORD_SIZE_ARM; \ } \