GBA: Add keypad IRQs (fixes #733)
Vicki Pfau vi@endrift.com
Fri, 02 Jun 2017 18:34:24 -0700
5 files changed,
44 insertions(+),
6 deletions(-)
M
include/mgba/internal/gba/gba.h
→
include/mgba/internal/gba/gba.h
@@ -175,6 +175,8 @@ bool GBAIsBIOS(struct VFile* vf);
void GBAGetGameCode(const struct GBA* gba, char* out); void GBAGetGameTitle(const struct GBA* gba, char* out); +void GBATestKeypadIRQ(struct GBA* gba); + void GBAFrameStarted(struct GBA* gba); void GBAFrameEnded(struct GBA* gba);
M
src/gba/core.c
→
src/gba/core.c
@@ -398,16 +398,19 @@
static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) { struct GBACore* gbacore = (struct GBACore*) core; gbacore->keys = keys; + GBATestKeypadIRQ(core->board); } static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) { struct GBACore* gbacore = (struct GBACore*) core; gbacore->keys |= keys; + GBATestKeypadIRQ(core->board); } static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) { struct GBACore* gbacore = (struct GBACore*) core; gbacore->keys &= ~keys; + GBATestKeypadIRQ(core->board); } static int32_t _GBACoreFrameCounter(const struct mCore* core) {
M
src/gba/gba.c
→
src/gba/gba.c
@@ -409,10 +409,6 @@ gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
} void GBAWriteIE(struct GBA* gba, uint16_t value) { - if (value & (1 << IRQ_KEYPAD)) { - mLOG(GBA, STUB, "Keypad interrupts not implemented"); - } - if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) { ARMRaiseIRQ(gba->cpu); }@@ -637,7 +633,7 @@ }
} void GBAFrameStarted(struct GBA* gba) { - UNUSED(gba); + GBATestKeypadIRQ(gba); size_t c; for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {@@ -681,6 +677,33 @@ struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
if (callbacks->videoFrameEnded) { callbacks->videoFrameEnded(callbacks->context); } + } +} + +void GBATestKeypadIRQ(struct GBA* gba) { + uint16_t keycnt = gba->memory.io[REG_KEYCNT >> 1]; + if (!(keycnt & 0x4000)) { + return; + } + int isAnd = keycnt & 0x8000; + uint16_t keyInput; + + if (!gba->keySource) { + // TODO? + return; + } + + keycnt &= 0x3FF; + keyInput = *gba->keySource; + + if (popcount32(keyInput) > 2) { + keycnt = keycnt; + } + + if (isAnd && keycnt == keyInput) { + GBARaiseIRQ(gba, IRQ_KEYPAD); + } else if (!isAnd && keyInput) { + GBARaiseIRQ(gba, IRQ_KEYPAD); } }
M
src/gba/io.c
→
src/gba/io.c
@@ -537,6 +537,11 @@ value = GBASIOWriteRegister(&gba->sio, address, value);
break; // Interrupts and misc + case REG_KEYCNT: + value &= 0xC3FF; + gba->memory.io[address >> 1] = value; + GBATestKeypadIRQ(gba); + return; case REG_WAITCNT: value &= 0x5FFF; GBAAdjustWaitstates(gba, value);@@ -689,6 +694,7 @@ case REG_TM1CNT_HI:
case REG_TM2CNT_HI: case REG_TM3CNT_HI: case REG_KEYINPUT: + case REG_KEYCNT: case REG_IE: return true; }@@ -721,6 +727,9 @@ } else {
uint16_t input = 0x3FF; if (gba->keyCallback) { input = gba->keyCallback->readKeys(gba->keyCallback); + if (gba->keySource) { + *gba->keySource = input; + } } else if (gba->keySource) { input = *gba->keySource; }@@ -814,7 +823,6 @@ gba->memory.io[REG_JOYSTAT >> 1] &= ~JOYSTAT_RECV_BIT;
break; case REG_SOUNDBIAS: - case REG_KEYCNT: case REG_POSTFLG: mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address); break;@@ -863,6 +871,7 @@ case REG_TM0CNT_HI:
case REG_TM1CNT_HI: case REG_TM2CNT_HI: case REG_TM3CNT_HI: + case REG_KEYCNT: case REG_SIOMULTI0: case REG_SIOMULTI1: case REG_SIOMULTI2: