Skip to content

Commit 274301c

Browse files
committed
Improve accuracy of PPU/CPU timings to pass more Mooneye tests
1 parent 9fa9aba commit 274301c

3 files changed

Lines changed: 46 additions & 15 deletions

File tree

src/core/cpu.cpp

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,50 @@ uint8_t CPU::handle_interrupts() {
278278

279279
uint8_t CPU::execute_interrupt(uint8_t bit, uint16_t vector) {
280280
ime = false;
281+
ime_delay = 0; // Cancel any scheduled EI enable
282+
283+
// Push high byte
284+
sp--;
285+
mmu->write_byte(sp, (pc >> 8) & 0xFF);
286+
287+
// Cancellation check - if the first push overwrote IE (0xFFFF) and disabled the intented interrupt, then abort
288+
uint8_t ie_reg = mmu->read_byte(0xFFFF);
289+
290+
// Check if current interrupt bit is still enabled
291+
if (!(ie_reg & (1 << bit))) {
292+
// The original interrupt was disabled by the push; re-evaluate if any interrupt is now valid
293+
uint8_t if_reg = mmu->read_byte(0xFF0F);
294+
uint8_t pending = if_reg & ie_reg & 0x1F;
295+
296+
if (pending == 0) {
297+
// No interrupts are enabled, cancel dispatch
298+
sp--;
299+
mmu->write_byte(sp, pc & 0xFF);
300+
pc = 0x0000;
301+
return 20;
302+
} else {
303+
// An interrupt is still pending - find highest priority (0 = V-blank, 1 = STAT, 2 = Timer, 3 = Serial, 4 = Joypad)
304+
for (int i = 0; i < 5; i++) {
305+
if (pending & (1 << i)) {
306+
bit = i;
307+
vector = 0x0040 + (i * 0x08);
308+
break;
309+
}
310+
}
311+
}
312+
}
313+
314+
// Push low byte
315+
sp--;
316+
mmu->write_byte(sp, pc & 0xFF);
281317

282318
// Clear the specific interrupt bit in IF register
283319
uint8_t if_reg = mmu->read_byte(0xFF0F);
284320
mmu->write_byte(0xFF0F, if_reg & ~(1 << bit));
285-
286-
// Push PC to stack
287-
sp -= 2;
288-
mmu->write_word(sp, pc);
289-
290-
// Jump to the interrupt handler vector
321+
322+
// Jump to vector
291323
pc = vector;
292324

293-
// Interrupt dispatch takes approximately 20 clock cycles total
294-
// (5 machine cycles: 2 for internal logic + 2 for pushing PC + 1 for jump)
295325
return 20;
296326
}
297327

@@ -1105,6 +1135,7 @@ uint8_t CPU::JR_NZ_e8() {
11051135

11061136
uint8_t CPU::DI() {
11071137
ime = false;
1138+
ime_delay = 0;
11081139
return 4;
11091140
}
11101141

src/core/ppu.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,19 @@ void PPU::tick(uint8_t cycles) {
7070
}
7171
break;
7272

73-
// Pixel transfer (172 cycles)
73+
// Pixel transfer (172 cycles, emulated as 168 for timing accuracy)
7474
case 3:
75-
if (ppu_cycles >= 172) {
76-
ppu_cycles -= 172;
75+
if (ppu_cycles >= 168) {
76+
ppu_cycles -= 168;
7777
mode = 0;
7878
draw_scanline(); // Draw the current line at the end of transfer
7979
}
8080
break;
8181

82-
// H-blank (204 cycles)
82+
// H-blank (204 cycles, emulated as 208 for timing accuracy)
8383
case 0:
84-
if (ppu_cycles >= 204) {
85-
ppu_cycles -= 204;
84+
if (ppu_cycles >= 208) {
85+
ppu_cycles -= 208;
8686
current_ly++;
8787

8888
if (current_ly == 144) {

0 commit comments

Comments
 (0)