tests - Sort tests into subdirectories
This commit is contained in:
parent
2762b3aa8b
commit
15c4811804
9 changed files with 5 additions and 1 deletions
13
tests/cpu/test_cpu_exception.cpp
Normal file
13
tests/cpu/test_cpu_exception.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "doctest.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <memory/ram.h>
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("Undefined instructions throw exception")
|
||||
{
|
||||
u8 test_mem[] = { 0xd3, 0x00, 0x00, 0x00 };
|
||||
RAM r(test_mem, 0x4, true);
|
||||
Cpu c(&r);
|
||||
|
||||
REQUIRE_THROWS_AS(c.step(), CpuException);
|
||||
}
|
68
tests/cpu/test_cpu_interrupts.cpp
Normal file
68
tests/cpu/test_cpu_interrupts.cpp
Normal file
|
@ -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);
|
||||
|
||||
}
|
39
tests/cpu/test_cpu_prefix.cpp
Normal file
39
tests/cpu/test_cpu_prefix.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "doctest.h"
|
||||
|
||||
#include "cpu/cpu.h"
|
||||
#include "memory/ram.h"
|
||||
|
||||
TEST_CASE("Bit set, clear and test")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0xCB, 0xD7, // SET 2, A
|
||||
0xCB, 0x57, // BIT 2, A
|
||||
0xCB, 0x97, // RES 2, A
|
||||
0xCB, 0x57, // BIT 2, A
|
||||
};
|
||||
RAM r(test_ram, 0x8, true);
|
||||
Cpu cpu(&r);
|
||||
|
||||
CHECK(cpu.state.PC == 0x00);
|
||||
CHECK(cpu.state.A == 0b00000000);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x02);
|
||||
CHECK(cpu.state.A == 0b00000100);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x04);
|
||||
CHECK(!cpu.state.zero);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x06);
|
||||
CHECK(cpu.state.A == 0b00000000);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x08);
|
||||
CHECK(cpu.state.zero);
|
||||
}
|
292
tests/cpu/test_cpu_simple.cpp
Normal file
292
tests/cpu/test_cpu_simple.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
#include "doctest.h"
|
||||
|
||||
#include <cpu/cpu.h>
|
||||
#include <memory/ram.h>
|
||||
|
||||
|
||||
TEST_CASE("simple load and add")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0x3E, 0x10, // LD A, $0x10
|
||||
0x87, // ADD A, A
|
||||
};
|
||||
RAM r(test_ram, 3, true);
|
||||
Cpu cpu(&r);
|
||||
|
||||
CHECK(cpu.state.PC == 0x0);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x2);
|
||||
CHECK(cpu.state.A == 0x10);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x3);
|
||||
CHECK(cpu.state.A == 0x20);
|
||||
}
|
||||
|
||||
TEST_CASE("direct jump")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0xC3, 0x05, 0x00, // JMP $0x0005
|
||||
0x00, 0x00, // NOP NOP
|
||||
0xC3, 0x00, 0x00, // JMP $0x0000
|
||||
};
|
||||
|
||||
RAM r(test_ram, 8, true);
|
||||
Cpu cpu(&r);
|
||||
|
||||
CHECK(cpu.state.PC == 0x0000);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x0005);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x0000);
|
||||
}
|
||||
|
||||
TEST_CASE("LD HL, nn; LD A, [HL]; LD A, n; LD [HL], A")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0x21, 0x20, 0x00, // LD HL, $0x0020
|
||||
0x7E, // LD A, [HL]
|
||||
0x3E,0x5A, // LD A, $0x5A
|
||||
0x77, // LD [HL], A
|
||||
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,
|
||||
0xA5, // . = 0x0020
|
||||
};
|
||||
|
||||
RAM r(test_ram, 0x0021, false);
|
||||
Cpu cpu(&r);
|
||||
|
||||
CHECK(cpu.state.PC == 0x0);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x3);
|
||||
CHECK(cpu.state.HL == 0x0020);
|
||||
CHECK(cpu.state.A == 0x0);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x4);
|
||||
CHECK(cpu.state.A == 0xA5);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x6);
|
||||
CHECK(cpu.state.A == 0x5A);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x7);
|
||||
CHECK(test_ram[0x20] == 0x5A);
|
||||
}
|
||||
|
||||
TEST_CASE("PUSH rr ; POP rr")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
/* 0x0000 */ 0x31, 0x10, 0x00, // LD SP, $0x0010
|
||||
/* 0x0003 */ 0x01, 0xAA, 0x55, // LD BC, $0x55AA
|
||||
/* 0x0006 */ 0xC5, // PUSH BC
|
||||
/* 0x0007 */ 0x01, 0x55, 0xAA, // LD BC, $0xAA55
|
||||
/* 0x000A */ 0xD1, // POP DE
|
||||
/* 0x000B */ 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* 0x0010 */ 0x12, 0x34,
|
||||
};
|
||||
|
||||
RAM r(test_ram, 0x0012, false);
|
||||
Cpu cpu(&r);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x0003);
|
||||
CHECK(cpu.state.SP == 0x0010);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x0006);
|
||||
CHECK(cpu.state.BC == 0x55AA);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x0007);
|
||||
CHECK(cpu.state.SP == 0x000E);
|
||||
CHECK(test_ram[0x000E] == 0xAA);
|
||||
CHECK(test_ram[0x000F] == 0x55);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x000A);
|
||||
CHECK(cpu.state.BC == 0xAA55);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x000B);
|
||||
CHECK(cpu.state.DE == 0x55AA);
|
||||
}
|
||||
|
||||
TEST_CASE("CALL ; RET")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
/* 0x0000 */ 0x31, 0x10, 0x00, // LD SP, $0x0010
|
||||
/* 0x0003 */ 0xCD, 0x0A, 0x00, // CALL $0x000A
|
||||
/* 0x0006 */ 0x00, 0x00, 0x00, 0x00, // 4 x NOP
|
||||
/* 0x000A */ 0x00, // NOP
|
||||
/* 0x000B */ 0xC9, // RET
|
||||
/* 0x000C */ 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
/* 0x000D */ 0xaa, 0xaa, 0xaa,
|
||||
/* 0x0010 */
|
||||
};
|
||||
|
||||
RAM r(test_ram, 0x10, false);
|
||||
Cpu cpu(&r);
|
||||
|
||||
cpu.step(); // LD SP, $0x0010
|
||||
|
||||
CHECK(cpu.state.PC == 0x0003);
|
||||
CHECK(cpu.state.SP == 0x0010);
|
||||
|
||||
cpu.step(); // CALL $0x000A
|
||||
|
||||
CHECK(cpu.state.PC == 0x000A);
|
||||
CHECK(cpu.state.SP == 0x000E);
|
||||
CHECK(test_ram[0x000F] == 0x00);
|
||||
CHECK(test_ram[0x000E] == 0x06);
|
||||
|
||||
cpu.step(); // NOP
|
||||
|
||||
CHECK(cpu.state.PC == 0x000B);
|
||||
CHECK(cpu.state.SP == 0x000E);
|
||||
CHECK(test_ram[0x000F] == 0x00);
|
||||
CHECK(test_ram[0x000E] == 0x06);
|
||||
|
||||
cpu.step(); // RET
|
||||
|
||||
CHECK(cpu.state.PC == 0x0006);
|
||||
CHECK(cpu.state.SP == 0x0010);
|
||||
}
|
||||
|
||||
TEST_CASE("JR e")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0x18, 0x02,
|
||||
0x00, 0x00,
|
||||
0x18, (u8)(-0x06),
|
||||
};
|
||||
|
||||
RAM r(test_ram, 0x6, true);
|
||||
Cpu cpu(&r);
|
||||
|
||||
CHECK(cpu.state.PC == 0x0);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x4);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == 0x0);
|
||||
}
|
||||
|
||||
TEST_CASE("RST op leads to correct call")
|
||||
{
|
||||
u8 test_ram[] = { 0x00 };
|
||||
RAM r(test_ram, 0x1, true);
|
||||
|
||||
Cpu cpu(&r);
|
||||
|
||||
u16 expected_pc;
|
||||
|
||||
SUBCASE("RST $00") { test_ram[0] = 0xC7; expected_pc = 0x00; }
|
||||
SUBCASE("RST $08") { test_ram[0] = 0xCF; expected_pc = 0x08; }
|
||||
SUBCASE("RST $10") { test_ram[0] = 0xD7; expected_pc = 0x10; }
|
||||
SUBCASE("RST $18") { test_ram[0] = 0xDF; expected_pc = 0x18; }
|
||||
SUBCASE("RST $20") { test_ram[0] = 0xE7; expected_pc = 0x20; }
|
||||
SUBCASE("RST $28") { test_ram[0] = 0xEF; expected_pc = 0x28; }
|
||||
SUBCASE("RST $30") { test_ram[0] = 0xF7; expected_pc = 0x30; }
|
||||
SUBCASE("RST $38") { test_ram[0] = 0xFF; expected_pc = 0x38; }
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.PC == expected_pc);
|
||||
}
|
||||
|
||||
TEST_CASE("DAA")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0x80, // ADD A,B
|
||||
0x27, // DAA
|
||||
0x90, // SUB A,B
|
||||
0x27, // DAA
|
||||
};
|
||||
|
||||
RAM r(test_ram, 0x4, true);
|
||||
Cpu cpu(&r);
|
||||
|
||||
cpu.state.A = 0x45;
|
||||
cpu.state.B = 0x38;
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.A == 0x7D);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.A == 0x83);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.A == 0x4B);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.A == 0x45);
|
||||
}
|
||||
|
||||
TEST_CASE("HALT exits on interrupt")
|
||||
{
|
||||
u8 test_ram[] = {
|
||||
0x76,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
RAM r(test_ram, 0x3, true);
|
||||
Cpu cpu(&r);
|
||||
|
||||
cpu.state.IE = INT_MASK;
|
||||
cpu.state.IF = 0;
|
||||
cpu.state.IME = IME_ON;
|
||||
|
||||
CHECK(cpu.state.halted == false);
|
||||
|
||||
cpu.step();
|
||||
CHECK(cpu.state.halted == true);
|
||||
CHECK(cpu.state.PC == 0x01);
|
||||
|
||||
cpu.step();
|
||||
CHECK(cpu.state.halted == true);
|
||||
CHECK(cpu.state.PC == 0x01);
|
||||
|
||||
cpu.step();
|
||||
CHECK(cpu.state.halted == true);
|
||||
CHECK(cpu.state.PC == 0x01);
|
||||
|
||||
cpu.signalInterrupt(INT_LCDSTAT);
|
||||
|
||||
CHECK(cpu.state.IF == INT_LCDSTAT);
|
||||
|
||||
cpu.step();
|
||||
|
||||
CHECK(cpu.state.halted == false);
|
||||
CHECK(cpu.state.IF == 0);
|
||||
CHECK(cpu.state.IME == IME_OFF);
|
||||
CHECK(cpu.state.PC == 0x48);
|
||||
}
|
31
tests/cpu/test_cpu_state.cpp
Normal file
31
tests/cpu/test_cpu_state.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "doctest.h"
|
||||
|
||||
#include "cpu/cpu.h"
|
||||
|
||||
TEST_CASE("16-bit registers map to two 8-bit registers")
|
||||
{
|
||||
Cpu_state c;
|
||||
|
||||
c.BC = 0xAA55;
|
||||
CHECK(c.B == 0xAA);
|
||||
CHECK(c.C == 0x55);
|
||||
|
||||
c.DE = 0x1122;
|
||||
CHECK(c.D == 0x11);
|
||||
CHECK(c.E == 0x22);
|
||||
|
||||
c.HL = 0x3344;
|
||||
CHECK(c.H == 0x33);
|
||||
CHECK(c.L == 0x44);
|
||||
}
|
||||
|
||||
TEST_CASE("SI works correctly")
|
||||
{
|
||||
Cpu_state c;
|
||||
|
||||
|
||||
c.IE = 0b10000111;
|
||||
c.IF = 0b10011100;
|
||||
|
||||
CHECK(c.SI() == 0b00000100);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue