diff --git a/CHANGES b/CHANGES index 1fcd5f59a..9fb97aeff 100644 --- a/CHANGES +++ b/CHANGES @@ -44,6 +44,7 @@ Bugfixes: - GBA Video: Fix broken sprite blending hack (fixes mgba.io/i/532) - GBA I/O: Fix reading from a few invalid I/O registers (fixes mgba.io/i/876) - GBA Savedata: Fix size of SRAM saves (fixes mgba.io/i/883) + - GB: Revamp IRQ handling based on new information Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index 71d2c78b7..2acf592d4 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -42,7 +42,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE); * | 0x00036 - 0x00037: Index address * | 0x00038: Bus value * | 0x00039: Execution state - * | 0x0003A - 0x0003B: IRQ vector + * | 0x0003A - 0x0003B: Reserved * | 0x0003C - 0x0003F: EI pending cycles * | 0x00040 - 0x00043: Reserved (DI pending cycles) * | 0x00044 - 0x00047: Flags @@ -287,7 +287,7 @@ struct GBSerializedState { uint8_t bus; uint8_t executionState; - uint16_t irqVector; + uint16_t reserved; uint32_t eiPending; int32_t reservedDiPending; diff --git a/include/mgba/internal/lr35902/lr35902.h b/include/mgba/internal/lr35902/lr35902.h index 3e586f0ed..c5bfd1381 100644 --- a/include/mgba/internal/lr35902/lr35902.h +++ b/include/mgba/internal/lr35902/lr35902.h @@ -66,6 +66,7 @@ struct LR35902InterruptHandler { void (*reset)(struct LR35902Core* cpu); void (*processEvents)(struct LR35902Core* cpu); void (*setInterrupts)(struct LR35902Core* cpu, bool enable); + uint16_t (*irqVector)(struct LR35902Core* cpu); void (*halt)(struct LR35902Core* cpu); void (*stop)(struct LR35902Core* cpu); @@ -118,7 +119,6 @@ struct LR35902Core { LR35902Instruction instruction; bool irqPending; - uint16_t irqVector; struct LR35902Memory memory; struct LR35902InterruptHandler irqh; @@ -136,7 +136,7 @@ void LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot); void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot); void LR35902Reset(struct LR35902Core* cpu); -void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector); +void LR35902RaiseIRQ(struct LR35902Core* cpu); void LR35902Tick(struct LR35902Core* cpu); void LR35902Run(struct LR35902Core* cpu); diff --git a/src/gb/gb.c b/src/gb/gb.c index d4a5c3268..c75992461 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -39,6 +39,7 @@ static void GBDeinit(struct mCPUComponent* component); static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh); static void GBProcessEvents(struct LR35902Core* cpu); static void GBSetInterrupts(struct LR35902Core* cpu, bool enable); +static uint16_t GBIRQVector(struct LR35902Core* cpu); static void GBIllegal(struct LR35902Core* cpu); static void GBStop(struct LR35902Core* cpu); @@ -371,6 +372,7 @@ void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) { irqh->reset = GBReset; irqh->processEvents = GBProcessEvents; irqh->setInterrupts = GBSetInterrupts; + irqh->irqVector = GBIRQVector; irqh->hitIllegal = GBIllegal; irqh->stop = GBStop; irqh->halt = GBHalt; @@ -596,31 +598,7 @@ void GBUpdateIRQs(struct GB* gb) { if (!gb->memory.ime || gb->cpu->irqPending) { return; } - - if (irqs & (1 << GB_IRQ_VBLANK)) { - LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK); - gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK); - return; - } - if (irqs & (1 << GB_IRQ_LCDSTAT)) { - LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT); - gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT); - return; - } - if (irqs & (1 << GB_IRQ_TIMER)) { - LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER); - gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER); - return; - } - if (irqs & (1 << GB_IRQ_SIO)) { - LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO); - gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO); - return; - } - if (irqs & (1 << GB_IRQ_KEYPAD)) { - LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD); - gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD); - } + LR35902RaiseIRQ(gb->cpu); } void GBProcessEvents(struct LR35902Core* cpu) { @@ -663,6 +641,33 @@ void GBSetInterrupts(struct LR35902Core* cpu, bool enable) { } } +uint16_t GBIRQVector(struct LR35902Core* cpu) { + struct GB* gb = (struct GB*) cpu->master; + int irqs = gb->memory.ie & gb->memory.io[REG_IF]; + + if (irqs & (1 << GB_IRQ_VBLANK)) { + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK); + return GB_VECTOR_VBLANK; + } + if (irqs & (1 << GB_IRQ_LCDSTAT)) { + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT); + return GB_VECTOR_LCDSTAT; + } + if (irqs & (1 << GB_IRQ_TIMER)) { + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER); + return GB_VECTOR_TIMER; + } + if (irqs & (1 << GB_IRQ_SIO)) { + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO); + return GB_VECTOR_SIO; + } + if (irqs & (1 << GB_IRQ_KEYPAD)) { + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD); + return GB_VECTOR_KEYPAD; + } + return 0; +} + static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) { UNUSED(timing); UNUSED(cyclesLate); diff --git a/src/gb/serialize.c b/src/gb/serialize.c index ac5c58ba1..c37b3872b 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -47,7 +47,6 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) { STORE_16LE(gb->cpu->index, 0, &state->cpu.index); state->cpu.bus = gb->cpu->bus; state->cpu.executionState = gb->cpu->executionState; - STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); GBSerializedCpuFlags flags = 0; flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition); @@ -154,7 +153,6 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { LOAD_16LE(gb->cpu->index, 0, &state->cpu.index); gb->cpu->bus = state->cpu.bus; gb->cpu->executionState = state->cpu.executionState; - LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); GBSerializedCpuFlags flags; LOAD_32LE(flags, 0, &state->cpu.flags); diff --git a/src/lr35902/lr35902.c b/src/lr35902/lr35902.c index e4100a84a..6dd9db9ef 100644 --- a/src/lr35902/lr35902.c +++ b/src/lr35902/lr35902.c @@ -70,9 +70,8 @@ void LR35902Reset(struct LR35902Core* cpu) { cpu->irqh.reset(cpu); } -void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector) { +void LR35902RaiseIRQ(struct LR35902Core* cpu) { cpu->irqPending = true; - cpu->irqVector = vector; } static void _LR35902InstructionIRQStall(struct LR35902Core* cpu) { @@ -85,18 +84,19 @@ static void _LR35902InstructionIRQFinish(struct LR35902Core* cpu) { } static void _LR35902InstructionIRQDelay(struct LR35902Core* cpu) { - cpu->index = cpu->sp + 1; - cpu->bus = cpu->pc >> 8; + --cpu->sp; + cpu->index = cpu->sp; + cpu->bus = cpu->pc; cpu->executionState = LR35902_CORE_MEMORY_STORE; cpu->instruction = _LR35902InstructionIRQFinish; - cpu->pc = cpu->irqVector; + cpu->pc = cpu->irqh.irqVector(cpu); cpu->memory.setActiveRegion(cpu, cpu->pc); } static void _LR35902InstructionIRQ(struct LR35902Core* cpu) { - cpu->sp -= 2; /* TODO: Atomic incrementing? */ + --cpu->sp; cpu->index = cpu->sp; - cpu->bus = cpu->pc; + cpu->bus = cpu->pc >> 8; cpu->executionState = LR35902_CORE_MEMORY_STORE; cpu->instruction = _LR35902InstructionIRQDelay; } diff --git a/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/baseline_0000.png b/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/baseline_0000.png new file mode 100644 index 000000000..30590ffab Binary files /dev/null and b/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/baseline_0000.png differ diff --git a/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/test.gb b/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/test.gb new file mode 100644 index 000000000..404d9b0d6 Binary files /dev/null and b/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/test.gb differ diff --git a/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/test.sym b/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/test.sym new file mode 100644 index 000000000..84a14d360 --- /dev/null +++ b/src/platform/python/tests/cinema/gb/mooneye-gb/acceptance/interrupts/ie_push/test.sym @@ -0,0 +1,282 @@ +; this file was created with wlalink by ville helin . +; wla symbolic information for "/Users/vicki/Scratch/mooneye-gb/tests/build/acceptance/interrupts/ie_push.gb". + +[labels] +01:4bff print_load_font +01:4c0c print_string +01:4c16 print_a +01:4c20 print_newline +01:4c2b print_digit +01:4c38 print_regs +01:4c41 _print_sl_data0 +01:4c47 _print_sl_out0 +01:4c54 _print_sl_data1 +01:4c5a _print_sl_out1 +01:4c6c _print_sl_data2 +01:4c72 _print_sl_out2 +01:4c7f _print_sl_data3 +01:4c85 _print_sl_out3 +01:4c97 _print_sl_data4 +01:4c9d _print_sl_out4 +01:4caa _print_sl_data5 +01:4cb0 _print_sl_out5 +01:4cc2 _print_sl_data6 +01:4cc8 _print_sl_out6 +01:4cd5 _print_sl_data7 +01:4cdb _print_sl_out7 +01:4000 font +00:c000 regs_save +00:c000 regs_save.f +00:c001 regs_save.a +00:c002 regs_save.c +00:c003 regs_save.b +00:c004 regs_save.e +00:c005 regs_save.d +00:c006 regs_save.l +00:c007 regs_save.h +00:c008 regs_flags +00:c009 regs_assert +00:c009 regs_assert.f +00:c00a regs_assert.a +00:c00b regs_assert.c +00:c00c regs_assert.b +00:c00d regs_assert.e +00:c00e regs_assert.d +00:c00f regs_assert.l +00:c010 regs_assert.h +00:c011 memdump_len +00:c012 memdump_addr +01:47f0 memcpy +01:47f9 memset +01:4802 memcmp +01:4810 clear_vram +01:481a clear_oam +01:4824 disable_lcd_safe +01:482a _wait_ly_0 +01:4830 _wait_ly_1 +01:4839 reset_screen +01:484d process_results +01:4861 _wait_ly_2 +01:4867 _wait_ly_3 +01:487d _print_results_halt_0 +01:4880 _process_results_cb +01:488b _print_sl_data8 +01:4895 _print_sl_out8 +01:48af _print_sl_data9 +01:48ba _print_sl_out9 +01:48d2 _print_sl_data10 +01:48de _print_sl_out10 +01:48df dump_mem +01:48fe _dump_mem_line +01:4928 _check_asserts +01:4936 _print_sl_data11 +01:4939 _print_sl_out11 +01:4945 _print_sl_data12 +01:4947 _print_sl_out12 +01:494f _print_sl_data13 +01:4952 _print_sl_out13 +01:495c __check_assert_fail0 +01:4967 _print_sl_data14 +01:496a _print_sl_out14 +01:496d __check_assert_ok0 +01:4975 _print_sl_data15 +01:497a _print_sl_out15 +01:497c __check_assert_skip0 +01:4984 _print_sl_data16 +01:498c _print_sl_out16 +01:498c __check_assert_out0 +01:4998 _print_sl_data17 +01:499a _print_sl_out17 +01:49a2 _print_sl_data18 +01:49a5 _print_sl_out18 +01:49af __check_assert_fail1 +01:49ba _print_sl_data19 +01:49bd _print_sl_out19 +01:49c0 __check_assert_ok1 +01:49c8 _print_sl_data20 +01:49cd _print_sl_out20 +01:49cf __check_assert_skip1 +01:49d7 _print_sl_data21 +01:49df _print_sl_out21 +01:49df __check_assert_out1 +01:49ea _print_sl_data22 +01:49ed _print_sl_out22 +01:49f9 _print_sl_data23 +01:49fb _print_sl_out23 +01:4a03 _print_sl_data24 +01:4a06 _print_sl_out24 +01:4a10 __check_assert_fail2 +01:4a1b _print_sl_data25 +01:4a1e _print_sl_out25 +01:4a21 __check_assert_ok2 +01:4a29 _print_sl_data26 +01:4a2e _print_sl_out26 +01:4a30 __check_assert_skip2 +01:4a38 _print_sl_data27 +01:4a40 _print_sl_out27 +01:4a40 __check_assert_out2 +01:4a4c _print_sl_data28 +01:4a4e _print_sl_out28 +01:4a56 _print_sl_data29 +01:4a59 _print_sl_out29 +01:4a63 __check_assert_fail3 +01:4a6e _print_sl_data30 +01:4a71 _print_sl_out30 +01:4a74 __check_assert_ok3 +01:4a7c _print_sl_data31 +01:4a81 _print_sl_out31 +01:4a83 __check_assert_skip3 +01:4a8b _print_sl_data32 +01:4a93 _print_sl_out32 +01:4a93 __check_assert_out3 +01:4a9e _print_sl_data33 +01:4aa1 _print_sl_out33 +01:4aad _print_sl_data34 +01:4aaf _print_sl_out34 +01:4ab7 _print_sl_data35 +01:4aba _print_sl_out35 +01:4ac4 __check_assert_fail4 +01:4acf _print_sl_data36 +01:4ad2 _print_sl_out36 +01:4ad5 __check_assert_ok4 +01:4add _print_sl_data37 +01:4ae2 _print_sl_out37 +01:4ae4 __check_assert_skip4 +01:4aec _print_sl_data38 +01:4af4 _print_sl_out38 +01:4af4 __check_assert_out4 +01:4b00 _print_sl_data39 +01:4b02 _print_sl_out39 +01:4b0a _print_sl_data40 +01:4b0d _print_sl_out40 +01:4b17 __check_assert_fail5 +01:4b22 _print_sl_data41 +01:4b25 _print_sl_out41 +01:4b28 __check_assert_ok5 +01:4b30 _print_sl_data42 +01:4b35 _print_sl_out42 +01:4b37 __check_assert_skip5 +01:4b3f _print_sl_data43 +01:4b47 _print_sl_out43 +01:4b47 __check_assert_out5 +01:4b52 _print_sl_data44 +01:4b55 _print_sl_out44 +01:4b61 _print_sl_data45 +01:4b63 _print_sl_out45 +01:4b6b _print_sl_data46 +01:4b6e _print_sl_out46 +01:4b78 __check_assert_fail6 +01:4b83 _print_sl_data47 +01:4b86 _print_sl_out47 +01:4b89 __check_assert_ok6 +01:4b91 _print_sl_data48 +01:4b96 _print_sl_out48 +01:4b98 __check_assert_skip6 +01:4ba0 _print_sl_data49 +01:4ba8 _print_sl_out49 +01:4ba8 __check_assert_out6 +01:4bb4 _print_sl_data50 +01:4bb6 _print_sl_out50 +01:4bbe _print_sl_data51 +01:4bc1 _print_sl_out51 +01:4bcb __check_assert_fail7 +01:4bd6 _print_sl_data52 +01:4bd9 _print_sl_out52 +01:4bdc __check_assert_ok7 +01:4be4 _print_sl_data53 +01:4be9 _print_sl_out53 +01:4beb __check_assert_skip7 +01:4bf3 _print_sl_data54 +01:4bfb _print_sl_out54 +01:4bfb __check_assert_out7 +00:0200 round1 +00:0214 finish_round1 +00:021d round2 +00:0224 round3 +00:0235 target +00:0238 finish_round3 +00:023f round4 +00:0253 finish_round4 +00:0270 _wait_ly_4 +00:0276 _wait_ly_5 +00:028c _print_results_halt_1 +00:028f _test_ok_cb_0 +00:0297 _print_sl_data55 +00:029f _print_sl_out55 +00:1000 fail_round1_nointr +00:1017 _wait_ly_6 +00:101d _wait_ly_7 +00:1033 _print_results_halt_2 +00:1036 _test_failure_cb_0 +00:103e _print_sl_data56 +00:104f _print_sl_out56 +00:1052 fail_round1_nocancel +00:1069 _wait_ly_8 +00:106f _wait_ly_9 +00:1085 _print_results_halt_3 +00:1088 _test_failure_cb_1 +00:1090 _print_sl_data57 +00:10a2 _print_sl_out57 +00:10a5 fail_round1_if +00:10bc _wait_ly_10 +00:10c2 _wait_ly_11 +00:10d8 _print_results_halt_4 +00:10db _test_failure_cb_2 +00:10e3 _print_sl_data58 +00:10f3 _print_sl_out58 +00:10f6 fail_round2_intr +00:110d _wait_ly_12 +00:1113 _wait_ly_13 +00:1129 _print_results_halt_5 +00:112c _test_failure_cb_3 +00:1134 _print_sl_data59 +00:1146 _print_sl_out59 +00:1149 fail_round3_nointr +00:1160 _wait_ly_14 +00:1166 _wait_ly_15 +00:117c _print_results_halt_6 +00:117f _test_failure_cb_4 +00:1187 _print_sl_data60 +00:1198 _print_sl_out60 +00:119b fail_round3_cancel +00:11b2 _wait_ly_16 +00:11b8 _wait_ly_17 +00:11ce _print_results_halt_7 +00:11d1 _test_failure_cb_5 +00:11d9 _print_sl_data61 +00:11ed _print_sl_out61 +00:11f0 fail_round3_if +00:1207 _wait_ly_18 +00:120d _wait_ly_19 +00:1223 _print_results_halt_8 +00:1226 _test_failure_cb_6 +00:122e _print_sl_data62 +00:123e _print_sl_out62 +00:1241 fail_round4_nointr +00:1258 _wait_ly_20 +00:125e _wait_ly_21 +00:1274 _print_results_halt_9 +00:1277 _test_failure_cb_7 +00:127f _print_sl_data63 +00:1290 _print_sl_out63 +00:1293 fail_round4_cancel +00:12aa _wait_ly_22 +00:12b0 _wait_ly_23 +00:12c6 _print_results_halt_10 +00:12c9 _test_failure_cb_8 +00:12d1 _print_sl_data64 +00:12e5 _print_sl_out64 +00:12e8 fail_round4_if +00:12ff _wait_ly_24 +00:1305 _wait_ly_25 +00:131b _print_results_halt_11 +00:131e _test_failure_cb_9 +00:1326 _print_sl_data65 +00:1333 _print_sl_out65 +00:1336 fail_round4_vblank +00:134d _wait_ly_26 +00:1353 _wait_ly_27 +00:1369 _print_results_halt_12 +00:136c _test_failure_cb_10 +00:1374 _print_sl_data66 +00:1383 _print_sl_out66