mirror of
https://github.com/mlaux/gb6.git
synced 2026-10-24 16:02:16 +00:00
978 lines
33 KiB
C
978 lines
33 KiB
C
#include "tests.h"
|
|
|
|
// JP instruction
|
|
TEST(test_exec_jp_skip)
|
|
{
|
|
uint8_t rom[] = {
|
|
0x3e, 0x01, // 0x0000: ld a, 1
|
|
0xc3, 0x07, 0x00, // 0x0002: jp 0x0007
|
|
0x06, 0x02, // 0x0005: ld b, 2
|
|
0x0e, 0x03, // 0x0007: ld c, 3
|
|
0x10 // 0x0009: stop
|
|
};
|
|
run_program(rom, 0);
|
|
// A = 1, B = 0, C = 3
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 1);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0x00ff00ff, 0x03);
|
|
}
|
|
|
|
// JR instructions
|
|
TEST(test_exec_jr_forward)
|
|
{
|
|
// jr with positive displacement skips over instructions
|
|
uint8_t rom[] = {
|
|
0x3e, 0x11, // 0x0000: ld a, 0x11
|
|
0x18, 0x02, // 0x0002: jr +2 (skip to 0x0006)
|
|
0x3e, 0x22, // 0x0004: ld a, 0x22 (skipped)
|
|
0x0e, 0x33, // 0x0006: ld c, 0x33
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x11);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x33);
|
|
}
|
|
|
|
TEST(test_exec_jr_zero)
|
|
{
|
|
// jr with displacement 0 is effectively a no-op (jumps to next instruction)
|
|
uint8_t rom[] = {
|
|
0x3e, 0xaa, // 0x0000: ld a, 0xaa
|
|
0x18, 0x00, // 0x0002: jr +0 (jump to 0x0004)
|
|
0x0e, 0xbb, // 0x0004: ld c, 0xbb
|
|
0x10 // 0x0006: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0xbb);
|
|
}
|
|
|
|
TEST(test_exec_dec_a_loop)
|
|
{
|
|
// Classic countdown loop: ld a,5; loop: dec a; jr nz,loop
|
|
// A starts at 5, loop runs 5 times until A=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x05, // 0x0000: ld a, 5
|
|
0x3d, // 0x0002: dec a (loop start)
|
|
0x20, 0xfd, // 0x0003: jr nz, -3 (back to 0x0002)
|
|
0x10 // 0x0005: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x00);
|
|
}
|
|
|
|
// CP tests (comparison - sets flags)
|
|
TEST(test_exec_cp_equal)
|
|
{
|
|
// cp a, imm8 when equal - Z flag should be set
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42
|
|
0x10 // 0x0004: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42); // A unchanged by cp
|
|
ASSERT_EQ(get_dreg(REG_68K_D_FLAGS) & 0x04, 0x04); // Z flag set
|
|
}
|
|
|
|
TEST(test_exec_cp_not_equal)
|
|
{
|
|
// cp a, imm8 when not equal - Z flag should be clear
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10
|
|
0x10 // 0x0004: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42); // A unchanged
|
|
ASSERT_EQ(get_dreg(REG_68K_D_FLAGS) & 0x04, 0x00); // Z flag clear
|
|
}
|
|
|
|
TEST(test_exec_cp_carry)
|
|
{
|
|
// cp a, imm8 when A < imm8 - C flag should be set
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42)
|
|
0x10 // 0x0004: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_FLAGS) & 1, 1); // C flag set
|
|
}
|
|
|
|
TEST(test_exec_cp_hl_equal)
|
|
{
|
|
// cp a, (hl) when equal - Z flag should be set
|
|
uint8_t rom[] = {
|
|
0x21, 0x00, 0x50, // 0x0000: ld hl, 0x5000
|
|
0x36, 0x42, // 0x0003: ld (hl), 0x42
|
|
0x3e, 0x42, // 0x0005: ld a, 0x42
|
|
0xbe, // 0x0007: cp a, (hl)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_FLAGS) & 0x04, 0x04);
|
|
}
|
|
|
|
TEST(test_exec_cp_hl_not_equal)
|
|
{
|
|
// cp a, (hl) when not equal - Z flag should be clear
|
|
uint8_t rom[] = {
|
|
0x21, 0x00, 0x50, // 0x0000: ld hl, 0x5000
|
|
0x36, 0x10, // 0x0003: ld (hl), 0x10
|
|
0x3e, 0x42, // 0x0005: ld a, 0x42
|
|
0xbe, // 0x0007: cp a, (hl)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_FLAGS) & 0x04, 0x00);
|
|
}
|
|
|
|
TEST(test_exec_cp_hl_carry)
|
|
{
|
|
// cp a, (hl) when A < (hl) - C flag should be set
|
|
uint8_t rom[] = {
|
|
0x21, 0x00, 0x50, // 0x0000: ld hl, 0x5000
|
|
0x36, 0x42, // 0x0003: ld (hl), 0x42
|
|
0x3e, 0x10, // 0x0005: ld a, 0x10
|
|
0xbe, // 0x0007: cp a, (hl) (0x10 < 0x42)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_FLAGS) & 1, 1);
|
|
}
|
|
|
|
// Conditional JR tests
|
|
TEST(test_exec_jr_z_taken)
|
|
{
|
|
// jr z jumps when Z=1 (after cp equal)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (sets Z=1)
|
|
0x28, 0x02, // 0x0004: jr z, +2 (skip to 0x0008)
|
|
0x3e, 0x00, // 0x0006: ld a, 0x00 (skipped)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
}
|
|
|
|
TEST(test_exec_jr_z_not_taken)
|
|
{
|
|
// jr z doesn't jump when Z=0 (after cp not equal)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (sets Z=0)
|
|
0x28, 0x02, // 0x0004: jr z, +2 (not taken)
|
|
0x3e, 0x99, // 0x0006: ld a, 0x99 (executed)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_jr_nz_then_call)
|
|
{
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000 ld a, 10
|
|
0xfe, 0x10, // 0x0002: cp a, 10 (sets Z=1)
|
|
0x20, 0xfd, // 0x0004 jr nz, -5
|
|
0xcd, 0x0a, 0x00, // 0x0006 call 000a
|
|
0x10, // 0x0009 stop
|
|
0x3e, 0x99, // 0x000a ld a, $99
|
|
0xc9, // 0x000c ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_jr_c_taken)
|
|
{
|
|
// jr c jumps when C=1 (after cp with A < imm)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0x38, 0x02, // 0x0004: jr c, +2 (skip to 0x0008)
|
|
0x3e, 0x00, // 0x0006: ld a, 0x00 (skipped)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x10);
|
|
}
|
|
|
|
TEST(test_exec_jr_c_not_taken)
|
|
{
|
|
// jr c doesn't jump when C=0 (after cp with A >= imm)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0x38, 0x02, // 0x0004: jr c, +2 (not taken)
|
|
0x3e, 0x99, // 0x0006: ld a, 0x99 (executed)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_jr_nc_taken)
|
|
{
|
|
// jr nc jumps when C=0 (after cp with A >= imm)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0x30, 0x02, // 0x0004: jr nc, +2 (skip to 0x0008)
|
|
0x3e, 0x00, // 0x0006: ld a, 0x00 (skipped)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
}
|
|
|
|
TEST(test_exec_jr_nc_not_taken)
|
|
{
|
|
// jr nc doesn't jump when C=1 (after cp with A < imm)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0x30, 0x02, // 0x0004: jr nc, +2 (not taken)
|
|
0x3e, 0x99, // 0x0006: ld a, 0x99 (executed)
|
|
0x10 // 0x0008: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x99);
|
|
}
|
|
|
|
// Conditional JP tests
|
|
TEST(test_exec_jp_z_taken)
|
|
{
|
|
// jp z jumps when Z=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (sets Z=1)
|
|
0xca, 0x0a, 0x00, // 0x0004: jp z, 0x000a
|
|
0x3e, 0x00, // 0x0007: ld a, 0x00 (skipped)
|
|
0x10, // 0x0009: stop (skipped)
|
|
0x0e, 0x99, // 0x000a: ld c, 0x99
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_jp_z_not_taken)
|
|
{
|
|
// jp z doesn't jump when Z=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (sets Z=0)
|
|
0xca, 0x0a, 0x00, // 0x0004: jp z, 0x000a (not taken)
|
|
0x3e, 0x99, // 0x0007: ld a, 0x99 (executed)
|
|
0x10, // 0x0009: stop
|
|
0x3e, 0x00, // 0x000a: ld a, 0x00 (not reached)
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_jp_nz_taken)
|
|
{
|
|
// jp nz jumps when Z=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (sets Z=0)
|
|
0xc2, 0x0a, 0x00, // 0x0004: jp nz, 0x000a
|
|
0x3e, 0x00, // 0x0007: ld a, 0x00 (skipped)
|
|
0x10, // 0x0009: stop (skipped)
|
|
0x0e, 0x88, // 0x000a: ld c, 0x88
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x88);
|
|
}
|
|
|
|
TEST(test_exec_jp_nz_not_taken)
|
|
{
|
|
// jp nz doesn't jump when Z=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (sets Z=1)
|
|
0xc2, 0x0a, 0x00, // 0x0004: jp nz, 0x000a (not taken)
|
|
0x3e, 0x77, // 0x0007: ld a, 0x77 (executed)
|
|
0x10, // 0x0009: stop
|
|
0x3e, 0x00, // 0x000a: ld a, 0x00 (not reached)
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x77);
|
|
}
|
|
|
|
TEST(test_exec_jp_c_taken)
|
|
{
|
|
// jp c jumps when C=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0xda, 0x0a, 0x00, // 0x0004: jp c, 0x000a
|
|
0x3e, 0x00, // 0x0007: ld a, 0x00 (skipped)
|
|
0x10, // 0x0009: stop (skipped)
|
|
0x0e, 0x55, // 0x000a: ld c, 0x55
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x10);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x55);
|
|
}
|
|
|
|
TEST(test_exec_jp_c_not_taken)
|
|
{
|
|
// jp c doesn't jump when C=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0xda, 0x0a, 0x00, // 0x0004: jp c, 0x000a (not taken)
|
|
0x3e, 0x66, // 0x0007: ld a, 0x66 (executed)
|
|
0x10, // 0x0009: stop
|
|
0x3e, 0x00, // 0x000a: ld a, 0x00 (not reached)
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x66);
|
|
}
|
|
|
|
TEST(test_exec_jp_nc_taken)
|
|
{
|
|
// jp nc jumps when C=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0xd2, 0x0a, 0x00, // 0x0004: jp nc, 0x000a
|
|
0x3e, 0x00, // 0x0007: ld a, 0x00 (skipped)
|
|
0x10, // 0x0009: stop (skipped)
|
|
0x0e, 0x44, // 0x000a: ld c, 0x44
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x42);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x44);
|
|
}
|
|
|
|
TEST(test_exec_jp_nc_not_taken)
|
|
{
|
|
// jp nc doesn't jump when C=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0xd2, 0x0a, 0x00, // 0x0004: jp nc, 0x000a (not taken)
|
|
0x3e, 0xaa, // 0x0007: ld a, 0xaa (executed)
|
|
0x10, // 0x0009: stop
|
|
0x3e, 0x00, // 0x000a: ld a, 0x00 (not reached)
|
|
0x10 // 0x000c: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
}
|
|
|
|
// JP (HL)
|
|
TEST(test_jp_hl)
|
|
{
|
|
// jp (hl) - jump to address in HL
|
|
uint8_t rom[] = {
|
|
0x21, 0x08, 0x00, // 0x0000: ld hl, 0x0008
|
|
0xe9, // 0x0003: jp (hl)
|
|
0x3e, 0x11, // 0x0004: ld a, 0x11 (skipped)
|
|
0x10, // 0x0006: stop (skipped)
|
|
0x00, // 0x0007: padding
|
|
0x3e, 0x22, // 0x0008: ld a, 0x22
|
|
0x10 // 0x000a: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x22);
|
|
}
|
|
|
|
// Call/ret tests
|
|
TEST(test_exec_call_ret_simple)
|
|
{
|
|
// Simple call and return
|
|
uint8_t rom[] = {
|
|
0x3e, 0x11, // 0x0000: ld a, 0x11
|
|
0xcd, 0x08, 0x00, // 0x0002: call 0x0008
|
|
0x3e, 0x33, // 0x0005: ld a, 0x33 (after return)
|
|
0x10, // 0x0007: stop
|
|
// subroutine at 0x0008:
|
|
0x06, 0x22, // 0x0008: ld b, 0x22
|
|
0xc9 // 0x000a: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x33);
|
|
ASSERT_EQ((get_dreg(REG_68K_D_BC) >> 16) & 0xff, 0x22);
|
|
}
|
|
|
|
TEST(test_exec_call_ret_nested)
|
|
{
|
|
// Nested calls: main -> sub1 -> sub2
|
|
uint8_t rom[] = {
|
|
0x3e, 0x01, // 0x0000: ld a, 1
|
|
0xcd, 0x08, 0x00, // 0x0002: call sub1 (0x0008)
|
|
0x3e, 0x04, // 0x0005: ld a, 4
|
|
0x10, // 0x0007: stop
|
|
// sub1 at 0x0008:
|
|
0x3e, 0x02, // 0x0008: ld a, 2
|
|
0xcd, 0x10, 0x00, // 0x000a: call sub2 (0x0010)
|
|
0x3e, 0x03, // 0x000d: ld a, 3
|
|
0xc9, // 0x000f: ret from sub1
|
|
// sub2 at 0x0010:
|
|
0x0e, 0x99, // 0x0010: ld c, 0x99
|
|
0xc9 // 0x0012: ret from sub2
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x04);
|
|
}
|
|
|
|
TEST(test_exec_call_preserves_regs)
|
|
{
|
|
// Call should not clobber registers other than what subroutine modifies
|
|
uint8_t rom[] = {
|
|
0x3e, 0xaa, // 0x0000: ld a, 0xaa
|
|
0x06, 0xbb, // 0x0002: ld b, 0xbb
|
|
0xcd, 0x0a, 0x00, // 0x0004: call 0x000a
|
|
0x10, // 0x0007: stop
|
|
0x00, 0x00, // padding
|
|
// subroutine at 0x000a:
|
|
0x0e, 0xcc, // 0x000a: ld c, 0xcc
|
|
0xc9 // 0x000c: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
ASSERT_EQ((get_dreg(REG_68K_D_BC) >> 16) & 0xff, 0xbb);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0xcc);
|
|
}
|
|
|
|
// Conditional ret tests
|
|
TEST(test_exec_ret_nz_taken)
|
|
{
|
|
// ret nz returns when Z=0
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xaa, // 0x0003: ld a, 0xaa (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x42, // 0x0007: ld a, 0x42
|
|
0xfe, 0x10, // 0x0009: cp a, 0x10 (sets Z=0)
|
|
0xc0, // 0x000b: ret nz (taken)
|
|
0x3e, 0x00, // 0x000c: ld a, 0x00 (skipped)
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
}
|
|
|
|
TEST(test_exec_ret_nz_not_taken)
|
|
{
|
|
// ret nz doesn't return when Z=1
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xaa, // 0x0003: ld a, 0xaa (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x42, // 0x0007: ld a, 0x42
|
|
0xfe, 0x42, // 0x0009: cp a, 0x42 (sets Z=1)
|
|
0xc0, // 0x000b: ret nz (not taken)
|
|
0x0e, 0x99, // 0x000c: ld c, 0x99
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_ret_z_taken)
|
|
{
|
|
// ret z returns when Z=1
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xbb, // 0x0003: ld a, 0xbb (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x42, // 0x0007: ld a, 0x42
|
|
0xfe, 0x42, // 0x0009: cp a, 0x42 (sets Z=1)
|
|
0xc8, // 0x000b: ret z (taken)
|
|
0x3e, 0x00, // 0x000c: ld a, 0x00 (skipped)
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xbb);
|
|
}
|
|
|
|
TEST(test_exec_ret_z_not_taken)
|
|
{
|
|
// ret z doesn't return when Z=0
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xbb, // 0x0003: ld a, 0xbb (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x42, // 0x0007: ld a, 0x42
|
|
0xfe, 0x10, // 0x0009: cp a, 0x10 (sets Z=0)
|
|
0xc8, // 0x000b: ret z (not taken)
|
|
0x0e, 0x77, // 0x000c: ld c, 0x77
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xbb);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x77);
|
|
}
|
|
|
|
TEST(test_exec_ret_nc_taken)
|
|
{
|
|
// ret nc returns when C=0
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xcc, // 0x0003: ld a, 0xcc (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x42, // 0x0007: ld a, 0x42
|
|
0xfe, 0x10, // 0x0009: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0xd0, // 0x000b: ret nc (taken)
|
|
0x3e, 0x00, // 0x000c: ld a, 0x00 (skipped)
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xcc);
|
|
}
|
|
|
|
TEST(test_exec_ret_nc_not_taken)
|
|
{
|
|
// ret nc doesn't return when C=1
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xcc, // 0x0003: ld a, 0xcc (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x10, // 0x0007: ld a, 0x10
|
|
0xfe, 0x42, // 0x0009: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0xd0, // 0x000b: ret nc (not taken)
|
|
0x0e, 0x55, // 0x000c: ld c, 0x55
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xcc);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x55);
|
|
}
|
|
|
|
TEST(test_exec_ret_c_taken)
|
|
{
|
|
// ret c returns when C=1
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xdd, // 0x0003: ld a, 0xdd (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x10, // 0x0007: ld a, 0x10
|
|
0xfe, 0x42, // 0x0009: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0xd8, // 0x000b: ret c (taken)
|
|
0x3e, 0x00, // 0x000c: ld a, 0x00 (skipped)
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xdd);
|
|
}
|
|
|
|
TEST(test_exec_ret_c_not_taken)
|
|
{
|
|
// ret c doesn't return when C=0
|
|
uint8_t rom[] = {
|
|
0xcd, 0x07, 0x00, // 0x0000: call 0x0007
|
|
0x3e, 0xdd, // 0x0003: ld a, 0xdd (after return)
|
|
0x10, // 0x0005: stop
|
|
0x00, // 0x0006: padding
|
|
// subroutine at 0x0007:
|
|
0x3e, 0x42, // 0x0007: ld a, 0x42
|
|
0xfe, 0x10, // 0x0009: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0xd8, // 0x000b: ret c (not taken)
|
|
0x0e, 0x66, // 0x000c: ld c, 0x66
|
|
0xc9 // 0x000e: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xdd);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x66);
|
|
}
|
|
|
|
// Conditional call tests
|
|
TEST(test_exec_call_nz_taken)
|
|
{
|
|
// call nz calls when Z=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (sets Z=0)
|
|
0xc4, 0x0b, 0x00, // 0x0004: call nz, 0x000b (taken)
|
|
0x3e, 0xaa, // 0x0007: ld a, 0xaa (after return)
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x77, // 0x000b: ld c, 0x77
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x77);
|
|
}
|
|
|
|
TEST(test_exec_call_nz_not_taken)
|
|
{
|
|
// call nz doesn't call when Z=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (sets Z=1)
|
|
0xc4, 0x0b, 0x00, // 0x0004: call nz, 0x000b (not taken)
|
|
0x3e, 0xaa, // 0x0007: ld a, 0xaa
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x77, // 0x000b: ld c, 0x77
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x00);
|
|
}
|
|
|
|
TEST(test_exec_call_z_taken)
|
|
{
|
|
// call z calls when Z=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (sets Z=1)
|
|
0xcc, 0x0b, 0x00, // 0x0004: call z, 0x000b (taken)
|
|
0x3e, 0xbb, // 0x0007: ld a, 0xbb (after return)
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x88, // 0x000b: ld c, 0x88
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xbb);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x88);
|
|
}
|
|
|
|
TEST(test_exec_call_z_not_taken)
|
|
{
|
|
// call z doesn't call when Z=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (sets Z=0)
|
|
0xcc, 0x0b, 0x00, // 0x0004: call z, 0x000b (not taken)
|
|
0x3e, 0xbb, // 0x0007: ld a, 0xbb
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x88, // 0x000b: ld c, 0x88
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xbb);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x00);
|
|
}
|
|
|
|
TEST(test_exec_call_nc_taken)
|
|
{
|
|
// call nc calls when C=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0xd4, 0x0b, 0x00, // 0x0004: call nc, 0x000b (taken)
|
|
0x3e, 0xcc, // 0x0007: ld a, 0xcc (after return)
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x99, // 0x000b: ld c, 0x99
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xcc);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x99);
|
|
}
|
|
|
|
TEST(test_exec_call_nc_not_taken)
|
|
{
|
|
// call nc doesn't call when C=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0xd4, 0x0b, 0x00, // 0x0004: call nc, 0x000b (not taken)
|
|
0x3e, 0xcc, // 0x0007: ld a, 0xcc
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x99, // 0x000b: ld c, 0x99
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xcc);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x00);
|
|
}
|
|
|
|
TEST(test_exec_call_c_taken)
|
|
{
|
|
// call c calls when C=1
|
|
uint8_t rom[] = {
|
|
0x3e, 0x10, // 0x0000: ld a, 0x10
|
|
0xfe, 0x42, // 0x0002: cp a, 0x42 (0x10 < 0x42, sets C=1)
|
|
0xdc, 0x0b, 0x00, // 0x0004: call c, 0x000b (taken)
|
|
0x3e, 0xdd, // 0x0007: ld a, 0xdd (after return)
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x55, // 0x000b: ld c, 0x55
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xdd);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x55);
|
|
}
|
|
|
|
TEST(test_exec_call_c_not_taken)
|
|
{
|
|
// call c doesn't call when C=0
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x0000: ld a, 0x42
|
|
0xfe, 0x10, // 0x0002: cp a, 0x10 (0x42 >= 0x10, sets C=0)
|
|
0xdc, 0x0b, 0x00, // 0x0004: call c, 0x000b (not taken)
|
|
0x3e, 0xdd, // 0x0007: ld a, 0xdd
|
|
0x10, // 0x0009: stop
|
|
0x00, // 0x000a: padding
|
|
// subroutine at 0x000b:
|
|
0x0e, 0x55, // 0x000b: ld c, 0x55
|
|
0xc9 // 0x000d: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xdd);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_BC) & 0xff, 0x00);
|
|
}
|
|
|
|
// RST instruction
|
|
TEST(test_rst_28)
|
|
{
|
|
// rst 28h - call to address 0x0028
|
|
uint8_t rom[0x100] = {0};
|
|
// main code at 0x0000
|
|
rom[0x00] = 0x3e; rom[0x01] = 0x11; // ld a, 0x11
|
|
rom[0x02] = 0xef; // rst 28h
|
|
rom[0x03] = 0x3e; rom[0x04] = 0x33; // ld a, 0x33 (after return)
|
|
rom[0x05] = 0x10; // stop
|
|
// handler at 0x0028
|
|
rom[0x28] = 0x06; rom[0x29] = 0x22; // ld b, 0x22
|
|
rom[0x2a] = 0xc9; // ret
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0x33);
|
|
ASSERT_EQ((get_dreg(REG_68K_D_BC) >> 16) & 0xff, 0x22);
|
|
}
|
|
|
|
// Chained ret tests (Pokemon TryDoWildEncounter pattern)
|
|
TEST(test_chained_ret_nz_both_return)
|
|
{
|
|
// Test the actual Pokemon bug: ret nz -> ret nz
|
|
// Outer calls middle, middle calls inner
|
|
// Inner does: and a; ret nz (with A != 0, so returns)
|
|
// Middle does: ret nz (should also return because Z was 0)
|
|
// Outer should get control back and set A = 0xaa
|
|
uint8_t rom[] = {
|
|
0x3e, 0x42, // 0x00: ld a, 0x42 (nonzero)
|
|
0xcd, 0x20, 0x00, // 0x02: call middle (0x0020)
|
|
0x3e, 0xaa, // 0x05: ld a, 0xaa (should execute after both rets)
|
|
0x10, 0x00, // 0x07: stop
|
|
// padding to 0x10
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
// inner function at 0x10
|
|
0xa7, // 0x10: and a (Z=0 because A=0x42)
|
|
0xc0, // 0x11: ret nz (returns because Z=0)
|
|
0x3e, 0xdd, // 0x12: ld a, 0xdd (should NOT execute)
|
|
0xc9, // 0x14: ret
|
|
// padding to 0x20
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
// middle function at 0x20
|
|
0xcd, 0x10, 0x00, // 0x20: call inner (0x0010)
|
|
0xc0, // 0x23: ret nz (should return because Z=0 from inner)
|
|
0x3e, 0xcc, // 0x24: ld a, 0xcc (should NOT execute)
|
|
0xc9, // 0x26: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
}
|
|
|
|
TEST(test_chained_ret_nz_inner_falls_through)
|
|
{
|
|
// Inner does: and a; ret nz (with A == 0, so falls through)
|
|
// Inner then sets A = 0x42 and returns normally
|
|
// Middle does: ret nz (should return because now Z=0)
|
|
uint8_t rom[] = {
|
|
0x3e, 0x00, // 0x00: ld a, 0x00 (zero)
|
|
0xcd, 0x20, 0x00, // 0x02: call middle (0x0020)
|
|
0x3e, 0xaa, // 0x05: ld a, 0xaa (should execute after middle returns)
|
|
0x10, 0x00, // 0x07: stop
|
|
// padding to 0x10
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
// inner function at 0x10
|
|
0xa7, // 0x10: and a (Z=1 because A=0)
|
|
0xc0, // 0x11: ret nz (does NOT return because Z=1)
|
|
0x3e, 0x42, // 0x12: ld a, 0x42 (executes, sets A nonzero)
|
|
0xa7, // 0x14: and a (Z=0 now)
|
|
0xc9, // 0x15: ret
|
|
// padding to 0x20
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
// middle function at 0x20
|
|
0xcd, 0x10, 0x00, // 0x20: call inner (0x0010)
|
|
0xc0, // 0x23: ret nz (should return because Z=0 from inner's and a)
|
|
0x3e, 0xcc, // 0x24: ld a, 0xcc (should NOT execute)
|
|
0xc9, // 0x26: ret
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
}
|
|
|
|
TEST(test_chained_ret_nz_neither_returns)
|
|
{
|
|
// Inner does: and a; ret nz (with A == 0, so falls through)
|
|
// Inner returns with Z=1 (from xor a)
|
|
// Middle does: ret nz (should NOT return because Z=1)
|
|
// Middle falls through and sets A = 0xcc
|
|
uint8_t rom[] = {
|
|
0x3e, 0x00, // 0x00: ld a, 0x00 (zero)
|
|
0xcd, 0x20, 0x00, // 0x02: call middle (0x0020)
|
|
0x3e, 0xaa, // 0x05: ld a, 0xaa
|
|
0x10, 0x00, // 0x07: stop
|
|
// padding to 0x10
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
// inner function at 0x10
|
|
0xa7, // 0x10: and a (Z=1 because A=0)
|
|
0xc0, // 0x11: ret nz (does NOT return because Z=1)
|
|
0xaf, // 0x12: xor a (A=0, Z=1)
|
|
0xc9, // 0x13: ret
|
|
// padding to 0x20
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
// middle function at 0x20
|
|
0xcd, 0x10, 0x00, // 0x20: call inner (0x0010)
|
|
0xc0, // 0x23: ret nz (should NOT return because Z=1)
|
|
0x3e, 0xcc, // 0x24: ld a, 0xcc (should execute)
|
|
0xc9, // 0x26: ret
|
|
};
|
|
run_program(rom, 0);
|
|
// Middle's ret nz should NOT return, so A = 0xcc, then outer sets A = 0xaa
|
|
ASSERT_EQ(get_dreg(REG_68K_D_A) & 0xff, 0xaa);
|
|
}
|
|
|
|
// Interrupt enable/disable
|
|
TEST(test_ei)
|
|
{
|
|
// ei - enable interrupts
|
|
uint8_t rom[] = {
|
|
0xfb, // 0x0000: ei
|
|
0x10 // 0x0001: stop
|
|
};
|
|
run_program(rom, 0);
|
|
// big endian...
|
|
ASSERT_EQ(get_mem_byte(U16_INTERRUPTS_ENABLED + 1), 1);
|
|
}
|
|
|
|
TEST(test_di)
|
|
{
|
|
// di - disable interrupts
|
|
uint8_t rom[] = {
|
|
0x21, 0x00, 0x40, // 0x0000: ld hl, 0x4000
|
|
0x36, 0x01, // 0x0003: ld (hl), 0x01
|
|
0xf3, // 0x0000: di
|
|
0x10 // 0x0001: stop
|
|
};
|
|
run_program(rom, 0);
|
|
ASSERT_EQ(get_mem_byte(U16_INTERRUPTS_ENABLED + 1), 0);
|
|
}
|
|
|
|
void register_branch_tests(void)
|
|
{
|
|
printf("\nJP instruction:\n");
|
|
RUN_TEST(test_exec_jp_skip);
|
|
|
|
printf("\nJR instructions:\n");
|
|
RUN_TEST(test_exec_jr_forward);
|
|
RUN_TEST(test_exec_jr_zero);
|
|
RUN_TEST(test_exec_dec_a_loop);
|
|
|
|
printf("\nCP (comparison) tests:\n");
|
|
RUN_TEST(test_exec_cp_equal);
|
|
RUN_TEST(test_exec_cp_not_equal);
|
|
RUN_TEST(test_exec_cp_carry);
|
|
RUN_TEST(test_exec_cp_hl_equal);
|
|
RUN_TEST(test_exec_cp_hl_not_equal);
|
|
RUN_TEST(test_exec_cp_hl_carry);
|
|
|
|
printf("\nConditional JR tests:\n");
|
|
RUN_TEST(test_exec_jr_z_taken);
|
|
RUN_TEST(test_exec_jr_z_not_taken);
|
|
RUN_TEST(test_exec_jr_nz_then_call);
|
|
RUN_TEST(test_exec_jr_c_taken);
|
|
RUN_TEST(test_exec_jr_c_not_taken);
|
|
RUN_TEST(test_exec_jr_nc_taken);
|
|
RUN_TEST(test_exec_jr_nc_not_taken);
|
|
|
|
printf("\nConditional JP tests:\n");
|
|
RUN_TEST(test_exec_jp_z_taken);
|
|
RUN_TEST(test_exec_jp_z_not_taken);
|
|
RUN_TEST(test_exec_jp_nz_taken);
|
|
RUN_TEST(test_exec_jp_nz_not_taken);
|
|
RUN_TEST(test_exec_jp_c_taken);
|
|
RUN_TEST(test_exec_jp_c_not_taken);
|
|
RUN_TEST(test_exec_jp_nc_taken);
|
|
RUN_TEST(test_exec_jp_nc_not_taken);
|
|
|
|
printf("\nJP (HL):\n");
|
|
RUN_TEST(test_jp_hl);
|
|
|
|
printf("\nCall/ret tests:\n");
|
|
RUN_TEST(test_exec_call_ret_simple);
|
|
RUN_TEST(test_exec_call_ret_nested);
|
|
RUN_TEST(test_exec_call_preserves_regs);
|
|
|
|
printf("\nConditional ret tests:\n");
|
|
RUN_TEST(test_exec_ret_nz_taken);
|
|
RUN_TEST(test_exec_ret_nz_not_taken);
|
|
RUN_TEST(test_exec_ret_z_taken);
|
|
RUN_TEST(test_exec_ret_z_not_taken);
|
|
RUN_TEST(test_exec_ret_nc_taken);
|
|
RUN_TEST(test_exec_ret_nc_not_taken);
|
|
RUN_TEST(test_exec_ret_c_taken);
|
|
RUN_TEST(test_exec_ret_c_not_taken);
|
|
|
|
printf("\nConditional call tests:\n");
|
|
RUN_TEST(test_exec_call_nz_taken);
|
|
RUN_TEST(test_exec_call_nz_not_taken);
|
|
RUN_TEST(test_exec_call_z_taken);
|
|
RUN_TEST(test_exec_call_z_not_taken);
|
|
RUN_TEST(test_exec_call_nc_taken);
|
|
RUN_TEST(test_exec_call_nc_not_taken);
|
|
RUN_TEST(test_exec_call_c_taken);
|
|
RUN_TEST(test_exec_call_c_not_taken);
|
|
|
|
printf("\nRST tests:\n");
|
|
RUN_TEST(test_rst_28);
|
|
|
|
printf("\nChained ret preserves flags:\n");
|
|
RUN_TEST(test_chained_ret_nz_both_return);
|
|
RUN_TEST(test_chained_ret_nz_inner_falls_through);
|
|
RUN_TEST(test_chained_ret_nz_neither_returns);
|
|
|
|
printf("\nInterrupt enable/disable:\n");
|
|
RUN_TEST(test_ei);
|
|
RUN_TEST(test_di);
|
|
}
|