diff --git a/tests/test_cpu_interrupts.cpp b/tests/test_cpu_interrupts.cpp new file mode 100644 index 0000000..af3fd0c --- /dev/null +++ b/tests/test_cpu_interrupts.cpp @@ -0,0 +1,68 @@ +#include "doctest.h" + +#include "cpu/cpu.h" +#include "memory/ram.h" + +TEST_CASE("EI followed by DI should not trigger interrupt") +{ + u8 test_ram[] = { + 0xFB, // EI + 0xF3, // DI + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + RAM r(test_ram, 0x20, true); + Cpu cpu(&r); + + cpu.state.IE = 0x1F; // Enable all types of interrupts + cpu.state.IF = 0x1F; // All interrupts pending + + CHECK(cpu.state.PC == 0x0); + CHECK(cpu.state.IME == IME_OFF); + + cpu.step(); + + CHECK(cpu.state.PC == 0x1); + CHECK(cpu.state.IME == IME_SCHEDULED); + + cpu.step(); + + CHECK(cpu.state.PC == 0x2); + CHECK(cpu.state.IME == IME_OFF); + + cpu.step(); + + CHECK(cpu.state.PC == 0x3); + CHECK(cpu.state.IME == IME_OFF); +} + +TEST_CASE("interrupt triggers call to correct ISR") +{ + RAM r(0x100); + Cpu cpu(&r); + + cpu.state.IME = IME_ON; + cpu.state.IE = INT_MASK; + + InterruptType it; + u8 expected_pc; + + SUBCASE("VBlank") { it = INT_VBlank; expected_pc = 0x40; } + SUBCASE("LCDSTAT") { it = INT_LCDSTAT; expected_pc = 0x48; } + SUBCASE("Timer") { it = INT_Timer; expected_pc = 0x50; } + SUBCASE("Serial") { it = INT_Serial; expected_pc = 0x58; } + SUBCASE("Joypad") { it = INT_Joypad; expected_pc = 0x60; } + + cpu.signalInterrupt(it); + + CHECK(cpu.state.IF == it); + + cpu.step(); + + CHECK(cpu.state.IF == 0); + CHECK(cpu.state.PC == expected_pc); + CHECK(cpu.state.IME == IME_OFF); + +}