GB: Revamp IRQ handling based on new information

This commit is contained in:
Vicki Pfau 2017-09-26 15:40:49 -07:00
parent 148e7cd0b5
commit a949fdfced
9 changed files with 324 additions and 38 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

View File

@ -0,0 +1,282 @@
; this file was created with wlalink by ville helin <vhelin@iki.fi>.
; 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