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 Video: Render SGB border when unmasking with ATTR/PAL_SET (fixes mgba.io/i/2261)
- 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 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)

View File

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

View File

@ -146,7 +146,6 @@ struct GBACore {
#ifndef DISABLE_THREADING
struct mVideoThreadProxy threadProxy;
#endif
int keys;
struct mCPUComponent* components[CPU_COMPONENT_MAX];
const struct Configuration* overrides;
struct mDebuggerPlatform* debuggerPlatform;
@ -205,9 +204,6 @@ static bool _GBACoreInit(struct mCore* core) {
gbacore->proxyRenderer.logger = NULL;
#endif
gbacore->keys = 0;
gba->keySource = &gbacore->keys;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetInit(&core->dirs);
#endif
@ -707,20 +703,20 @@ static bool _GBACoreSaveState(struct mCore* core, void* state) {
}
static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys = keys;
GBATestKeypadIRQ(core->board);
struct GBA* gba = core->board;
gba->keysActive = keys;
GBATestKeypadIRQ(gba);
}
static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys |= keys;
GBATestKeypadIRQ(core->board);
struct GBA* gba = core->board;
gba->keysActive |= keys;
GBATestKeypadIRQ(gba);
}
static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) {
struct GBACore* gbacore = (struct GBACore*) core;
gbacore->keys &= ~keys;
struct GBA* gba = core->board;
gba->keysActive &= ~keys;
}
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);
gba->keySource = 0;
gba->keysActive = 0;
gba->keysLast = 0;
gba->rotationSource = 0;
gba->luminanceSource = 0;
gba->rtcSource = 0;
@ -877,18 +878,22 @@ void GBAFrameEnded(struct GBA* gba) {
}
void GBATestKeypadIRQ(struct GBA* gba) {
if (gba->keysActive == gba->keysLast) {
return;
}
uint16_t keycnt = gba->memory.io[REG_KEYCNT >> 1];
if (!(keycnt & 0x4000)) {
return;
}
int isAnd = keycnt & 0x8000;
if (!gba->keySource) {
// TODO?
return;
}
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) {
GBARaiseIRQ(gba, IRQ_KEYPAD, 0);

View File

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