GBA I/O: Redo internal key input, enabling edge-based key IRQs

This commit is contained in:
Vicki Pfau 2021-10-14 01:59:59 -07:00
parent 511a061ab0
commit f696619b11
5 changed files with 33 additions and 35 deletions

View File

@ -16,6 +16,7 @@ Emulation fixes:
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032) - GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
- GB Video: Render SGB border when unmasking with ATTR/PAL_SET (fixes mgba.io/i/2261) - GB Video: Render SGB border when unmasking with ATTR/PAL_SET (fixes mgba.io/i/2261)
- GBA: Improve timing when not booting from BIOS - GBA: Improve timing when not booting from BIOS
- GBA I/O: Redo internal key input, enabling edge-based key IRQs
- GBA Memory: Fix misaligned 32-bit I/O loads (fixes mgba.io/i/2307) - GBA Memory: Fix misaligned 32-bit I/O loads (fixes mgba.io/i/2307)
- GBA SIO: Fix SI value for unattached MULTI mode - GBA SIO: Fix SI value for unattached MULTI mode
- GBA Video: Fix backdrop color if DISPCNT is first set to 0 (fixes mgba.io/i/2260) - GBA Video: Fix backdrop color if DISPCNT is first set to 0 (fixes mgba.io/i/2260)

View File

@ -85,7 +85,8 @@ struct GBA {
struct mTimingEvent irqEvent; struct mTimingEvent irqEvent;
uint32_t biosChecksum; uint32_t biosChecksum;
int* keySource; uint16_t keysActive;
uint16_t keysLast;
struct mRotationSource* rotationSource; struct mRotationSource* rotationSource;
struct GBALuminanceSource* luminanceSource; struct GBALuminanceSource* luminanceSource;
struct mRTCSource* rtcSource; struct mRTCSource* rtcSource;

View File

@ -146,7 +146,6 @@ struct GBACore {
#ifndef DISABLE_THREADING #ifndef DISABLE_THREADING
struct mVideoThreadProxy threadProxy; struct mVideoThreadProxy threadProxy;
#endif #endif
int keys;
struct mCPUComponent* components[CPU_COMPONENT_MAX]; struct mCPUComponent* components[CPU_COMPONENT_MAX];
const struct Configuration* overrides; const struct Configuration* overrides;
struct mDebuggerPlatform* debuggerPlatform; struct mDebuggerPlatform* debuggerPlatform;
@ -205,9 +204,6 @@ static bool _GBACoreInit(struct mCore* core) {
gbacore->proxyRenderer.logger = NULL; gbacore->proxyRenderer.logger = NULL;
#endif #endif
gbacore->keys = 0;
gba->keySource = &gbacore->keys;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetInit(&core->dirs); mDirectorySetInit(&core->dirs);
#endif #endif
@ -707,20 +703,20 @@ static bool _GBACoreSaveState(struct mCore* core, void* state) {
} }
static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) { static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core; struct GBA* gba = core->board;
gbacore->keys = keys; gba->keysActive = keys;
GBATestKeypadIRQ(core->board); GBATestKeypadIRQ(gba);
} }
static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) { static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core; struct GBA* gba = core->board;
gbacore->keys |= keys; gba->keysActive |= keys;
GBATestKeypadIRQ(core->board); GBATestKeypadIRQ(gba);
} }
static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) { static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core; struct GBA* gba = core->board;
gbacore->keys &= ~keys; gba->keysActive &= ~keys;
} }
static int32_t _GBACoreFrameCounter(const struct mCore* core) { static int32_t _GBACoreFrameCounter(const struct mCore* core) {

View File

@ -90,7 +90,8 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
GBAHardwareInit(&gba->memory.hw, NULL); GBAHardwareInit(&gba->memory.hw, NULL);
gba->keySource = 0; gba->keysActive = 0;
gba->keysLast = 0;
gba->rotationSource = 0; gba->rotationSource = 0;
gba->luminanceSource = 0; gba->luminanceSource = 0;
gba->rtcSource = 0; gba->rtcSource = 0;
@ -877,18 +878,22 @@ void GBAFrameEnded(struct GBA* gba) {
} }
void GBATestKeypadIRQ(struct GBA* gba) { void GBATestKeypadIRQ(struct GBA* gba) {
if (gba->keysActive == gba->keysLast) {
return;
}
uint16_t keycnt = gba->memory.io[REG_KEYCNT >> 1]; uint16_t keycnt = gba->memory.io[REG_KEYCNT >> 1];
if (!(keycnt & 0x4000)) { if (!(keycnt & 0x4000)) {
return; return;
} }
int isAnd = keycnt & 0x8000; int isAnd = keycnt & 0x8000;
if (!gba->keySource) {
// TODO?
return;
}
keycnt &= 0x3FF; keycnt &= 0x3FF;
uint16_t keyInput = *gba->keySource & keycnt; uint16_t keyInput = gba->keysActive & keycnt;
uint16_t lastInput = gba->keysLast & keycnt;
gba->keysLast = gba->keysActive;
if (keyInput == lastInput) {
return;
}
if (isAnd && keycnt == keyInput) { if (isAnd && keycnt == keyInput) {
GBARaiseIRQ(gba, IRQ_KEYPAD, 0); GBARaiseIRQ(gba, IRQ_KEYPAD, 0);

View File

@ -743,24 +743,19 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
callbacks->keysRead(callbacks->context); callbacks->keysRead(callbacks->context);
} }
} }
uint16_t input = 0;
if (gba->keyCallback) { if (gba->keyCallback) {
input = gba->keyCallback->readKeys(gba->keyCallback); gba->keysActive = gba->keyCallback->readKeys(gba->keyCallback);
if (gba->keySource) { }
*gba->keySource = input; uint16_t input = gba->keysActive;
if (!gba->allowOpposingDirections) {
unsigned rl = input & 0x030;
unsigned ud = input & 0x0C0;
input &= 0x30F;
if (rl != 0x030) {
input |= rl;
} }
} else if (gba->keySource) { if (ud != 0x0C0) {
input = *gba->keySource; input |= ud;
if (!gba->allowOpposingDirections) {
unsigned rl = input & 0x030;
unsigned ud = input & 0x0C0;
input &= 0x30F;
if (rl != 0x030) {
input |= rl;
}
if (ud != 0x0C0) {
input |= ud;
}
} }
} }
gba->memory.io[address >> 1] = 0x3FF ^ input; gba->memory.io[address >> 1] = 0x3FF ^ input;