mirror of https://github.com/mgba-emu/mgba.git
GBA: Add keypad IRQs (fixes #733)
This commit is contained in:
parent
1caa17c00b
commit
9c23eb8428
1
CHANGES
1
CHANGES
|
@ -21,6 +21,7 @@ Features:
|
||||||
- Debugger: Segment/bank support
|
- Debugger: Segment/bank support
|
||||||
- GB: Symbol table support
|
- GB: Symbol table support
|
||||||
- GB MBC: Add MBC1 multicart support
|
- GB MBC: Add MBC1 multicart support
|
||||||
|
- GBA: Implement keypad interrupts
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- LR35902: Fix core never exiting with certain event patterns
|
- LR35902: Fix core never exiting with certain event patterns
|
||||||
- GB Timer: Improve DIV reset behavior
|
- GB Timer: Improve DIV reset behavior
|
||||||
|
|
|
@ -175,6 +175,8 @@ bool GBAIsBIOS(struct VFile* vf);
|
||||||
void GBAGetGameCode(const struct GBA* gba, char* out);
|
void GBAGetGameCode(const struct GBA* gba, char* out);
|
||||||
void GBAGetGameTitle(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 GBAFrameStarted(struct GBA* gba);
|
||||||
void GBAFrameEnded(struct GBA* gba);
|
void GBAFrameEnded(struct GBA* gba);
|
||||||
|
|
||||||
|
|
|
@ -398,16 +398,19 @@ 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 GBACore* gbacore = (struct GBACore*) core;
|
||||||
gbacore->keys = keys;
|
gbacore->keys = keys;
|
||||||
|
GBATestKeypadIRQ(core->board);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 GBACore* gbacore = (struct GBACore*) core;
|
||||||
gbacore->keys |= keys;
|
gbacore->keys |= keys;
|
||||||
|
GBATestKeypadIRQ(core->board);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 GBACore* gbacore = (struct GBACore*) core;
|
||||||
gbacore->keys &= ~keys;
|
gbacore->keys &= ~keys;
|
||||||
|
GBATestKeypadIRQ(core->board);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t _GBACoreFrameCounter(const struct mCore* core) {
|
static int32_t _GBACoreFrameCounter(const struct mCore* core) {
|
||||||
|
|
|
@ -409,10 +409,6 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAWriteIE(struct GBA* gba, uint16_t value) {
|
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]) {
|
if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {
|
||||||
ARMRaiseIRQ(gba->cpu);
|
ARMRaiseIRQ(gba->cpu);
|
||||||
}
|
}
|
||||||
|
@ -637,7 +633,7 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAFrameStarted(struct GBA* gba) {
|
void GBAFrameStarted(struct GBA* gba) {
|
||||||
UNUSED(gba);
|
GBATestKeypadIRQ(gba);
|
||||||
|
|
||||||
size_t c;
|
size_t c;
|
||||||
for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
|
for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
|
||||||
|
@ -684,6 +680,33 @@ void GBAFrameEnded(struct GBA* gba) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
|
void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
|
||||||
size_t immediate;
|
size_t immediate;
|
||||||
for (immediate = 0; immediate < gba->cpu->numComponents; ++immediate) {
|
for (immediate = 0; immediate < gba->cpu->numComponents; ++immediate) {
|
||||||
|
|
11
src/gba/io.c
11
src/gba/io.c
|
@ -537,6 +537,11 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Interrupts and misc
|
// Interrupts and misc
|
||||||
|
case REG_KEYCNT:
|
||||||
|
value &= 0xC3FF;
|
||||||
|
gba->memory.io[address >> 1] = value;
|
||||||
|
GBATestKeypadIRQ(gba);
|
||||||
|
return;
|
||||||
case REG_WAITCNT:
|
case REG_WAITCNT:
|
||||||
value &= 0x5FFF;
|
value &= 0x5FFF;
|
||||||
GBAAdjustWaitstates(gba, value);
|
GBAAdjustWaitstates(gba, value);
|
||||||
|
@ -689,6 +694,7 @@ bool GBAIOIsReadConstant(uint32_t address) {
|
||||||
case REG_TM2CNT_HI:
|
case REG_TM2CNT_HI:
|
||||||
case REG_TM3CNT_HI:
|
case REG_TM3CNT_HI:
|
||||||
case REG_KEYINPUT:
|
case REG_KEYINPUT:
|
||||||
|
case REG_KEYCNT:
|
||||||
case REG_IE:
|
case REG_IE:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -721,6 +727,9 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
|
||||||
uint16_t input = 0x3FF;
|
uint16_t input = 0x3FF;
|
||||||
if (gba->keyCallback) {
|
if (gba->keyCallback) {
|
||||||
input = gba->keyCallback->readKeys(gba->keyCallback);
|
input = gba->keyCallback->readKeys(gba->keyCallback);
|
||||||
|
if (gba->keySource) {
|
||||||
|
*gba->keySource = input;
|
||||||
|
}
|
||||||
} else if (gba->keySource) {
|
} else if (gba->keySource) {
|
||||||
input = *gba->keySource;
|
input = *gba->keySource;
|
||||||
}
|
}
|
||||||
|
@ -814,7 +823,6 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REG_SOUNDBIAS:
|
case REG_SOUNDBIAS:
|
||||||
case REG_KEYCNT:
|
|
||||||
case REG_POSTFLG:
|
case REG_POSTFLG:
|
||||||
mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address);
|
mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address);
|
||||||
break;
|
break;
|
||||||
|
@ -863,6 +871,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
|
||||||
case REG_TM1CNT_HI:
|
case REG_TM1CNT_HI:
|
||||||
case REG_TM2CNT_HI:
|
case REG_TM2CNT_HI:
|
||||||
case REG_TM3CNT_HI:
|
case REG_TM3CNT_HI:
|
||||||
|
case REG_KEYCNT:
|
||||||
case REG_SIOMULTI0:
|
case REG_SIOMULTI0:
|
||||||
case REG_SIOMULTI1:
|
case REG_SIOMULTI1:
|
||||||
case REG_SIOMULTI2:
|
case REG_SIOMULTI2:
|
||||||
|
|
Loading…
Reference in New Issue