diff --git a/src/gbasm/tests/ld.c b/src/gbasm/tests/ld.c index 2a0545e..de9a6db 100644 --- a/src/gbasm/tests/ld.c +++ b/src/gbasm/tests/ld.c @@ -23,15 +23,31 @@ struct gbasm_test r8_r8 = { /* * Data for LD R8, D8 tests */ -static char ld_r8_d8_src[1024] = { 0 }; -static uint8_t ld_r8_d8_output[0x40]; +static char ld_r8_d8_src[] = "ld a, $12\n" + "ld b, $0\n" + "ld c, $0xff\n" + "ld d, $127\n" + "ld e, $0xfe\n" + "ld h, $-1\n" + "ld l, $-128\n" + "halt"; + +static uint8_t ld_r8_d8_output[] = { + 0x3e, 0x0c, + 0x06, 0x00, + 0x0e, 0xff, + 0x16, 0x7f, + 0x1e, 0xfe, + 0x26, 0xff, + 0x2e, 0x80, + 0x76, +}; struct gbasm_test r8_d8 = { - .init = init_r8_d8, .name = "r8/d8", .asm_source = ld_r8_d8_src, .expected_output = ld_r8_d8_output, - .expected_output_len = 0, + .expected_output_len = 15, }; static const struct gbasm_test *tests[] = { @@ -105,26 +121,3 @@ void init_r8_r8(void) gen_r8_r8_src(); gen_r8_r8_output(); } - -void gen_r8_d8_src(void) -{ - snprintf(ld_r8_d8_src, - sizeof(ld_r8_d8_src), - "ld a, $12\n" - "ld b, $0\n" - "ld c, $0xff\n" - "ld d, $127\n" - "ld e, $0xfe\n" - "ld h, $-1\n" - "ld l, $-128"); -} - -void gen_r8_d8_output(void) -{ -} - -void init_r8_d8(void) -{ - gen_r8_d8_src(); - gen_r8_d8_output(); -} diff --git a/src/gbemu/tests/cpu/ld.c b/src/gbemu/tests/cpu/ld.c new file mode 100644 index 0000000..54aa4db --- /dev/null +++ b/src/gbemu/tests/cpu/ld.c @@ -0,0 +1,73 @@ +#include "gbemu/tests/cpu/test.h" + +static struct gb_cpu_test test_ld_r8 = { + .init = NULL, + + .expected_regs_type = GB_CPU_TEST_REGS_8, + .expected = { + .regs_8 = { + .a = 0x01, + .b = 0x02, + .c = 0x03, + .d = 0x03, + .e = 0x02, + .f = 0x00, + .h = 0x01, + .l = 0x00, + .sp = 0x0000, + .pc = 10, + } + }, + + .src_prog = + "inc a\n" + "inc b\n" + "inc b\n" + "inc c\n" + "inc c\n" + "inc c\n" + "ld d, c\n" + "ld e, b\n" + "ld h, a\n" + "halt", + + .name = "/ld/r8", +}; + +static struct gb_cpu_test test_ld_d8 = { + .init = NULL, + + .expected_regs_type = GB_CPU_TEST_REGS_8, + .expected = { + .regs_8 = { + .a = 0xaa, + .b = 0x55, + .c = 0xff, + .d = 0xb0, + .e = 0xde, + .f = 0x00, + .h = 0xbe, + .l = 0xef, + .sp = 0x0000, + .pc = 15, + } + }, + + .src_prog = + "ld a, $0xaa\n" + "ld b, $0x55\n" + "ld c, $0xff\n" + "ld d, $0xb0\n" + "ld e, $0xde\n" + "ld h, $0xbe\n" + "ld l, $0xef\n" + "halt", + + .name = "/ld/d8", +}; + +struct gb_cpu_test* ld_tests[] = { + &test_ld_r8, + &test_ld_d8, + NULL +}; diff --git a/src/gbemu/tests/cpu/ld.h b/src/gbemu/tests/cpu/ld.h new file mode 100644 index 0000000..ee97f9f --- /dev/null +++ b/src/gbemu/tests/cpu/ld.h @@ -0,0 +1,8 @@ +#ifndef GB_CPU_TEST_LD_H +#define GB_CPU_TEST_LD_H + +#include "gbemu/tests/cpu/test.h" + +extern struct gb_cpu_test* ld_tests; + +#endif diff --git a/src/gbemu/tests/cpu/test.h b/src/gbemu/tests/cpu/test.h new file mode 100644 index 0000000..ba1fbc8 --- /dev/null +++ b/src/gbemu/tests/cpu/test.h @@ -0,0 +1,67 @@ +#ifndef GBEMU_CPU_TEST +#define GBEMU_CPU_TEST + +#include "gbemu/cpu.h" + +#include "common/common.h" + +#include + +/** + * A structure (which is only used for testing) which provides an abstraction + * for comparing to the real CPU state, in case that definition should change. + */ +struct gb_cpu_test_regs_16 { + uint16_t bc; + uint16_t de; + uint16_t hl; + uint16_t af; + uint16_t sp; + uint16_t pc; +}; + +/** + * A structure (which is only used for testing) which provides an abstraction + * for comparing to the real CPU state, in case that definition should change. + */ +struct gb_cpu_test_regs_8 { + uint8_t a; + uint8_t b; + uint8_t c; + uint8_t d; + uint8_t e; + uint8_t h; + uint8_t l; + uint8_t f; + + /** + * The SP and PC registers are only accessible via their 16-bit + * representations. + */ + uint16_t sp; + uint16_t pc; +}; + +enum gb_cpu_test_regs_type { + GB_CPU_TEST_REGS_8, + GB_CPU_TEST_REGS_16, +}; + +struct gb_cpu_test { + void (* init)(void); + + /** + * As a convenience for writing tests, support writing the expected + * state of the registers in either their 8-bit or 16-bit forms. + */ + enum gb_cpu_test_regs_type expected_regs_type; + union { + struct gb_cpu_test_regs_8 regs_8; + struct gb_cpu_test_regs_16 regs_16; + } expected; + + const char *src_prog; + const char *name; +}; + +#endif diff --git a/src/gbemu/tests/test.c b/src/gbemu/tests/test.c index 33fca78..6368901 100644 --- a/src/gbemu/tests/test.c +++ b/src/gbemu/tests/test.c @@ -1,6 +1,11 @@ #include "gbasm/assemble.h" #include "gbasm/emitter.h" + #include "gbemu/cpu.h" + +#include "gbemu/tests/cpu/test.h" +#include "gbemu/tests/cpu/ld.h" + #include "common/common.h" #include /* memset */ @@ -8,6 +13,38 @@ static uint8_t mem[4096] = { 0 }; +static struct gb_cpu_test **tests[] = { + &ld_tests, +}; + +static void gb_cpu_test_cmp_regs_8(const struct lr35902_state *cpu, + const struct gb_cpu_test_regs_8 *test_regs) +{ + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_A), ==, test_regs->a); + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_B), ==, test_regs->b); + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_C), ==, test_regs->c); + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_D), ==, test_regs->d); + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_E), ==, test_regs->e); + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_H), ==, test_regs->h); + g_assert_cmpint(lr35902_get_reg_8(cpu, LR35902_REG_L), ==, test_regs->l); + + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_SP), ==, test_regs->sp); + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_PC), ==, test_regs->pc); +} + +static void gb_cpu_test_cmp_regs_16(const struct lr35902_state *cpu, + const struct gb_cpu_test_regs_16 *test_regs) +{ + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_A), ==, test_regs->af); + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_B), ==, test_regs->bc); + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_C), ==, test_regs->de); + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_D), ==, test_regs->hl); + + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_SP), ==, test_regs->sp); + g_assert_cmpint(lr35902_get_reg_16(cpu, LR35902_REG_PC), ==, test_regs->pc); +} + + static uint8_t mem_read(struct lr35902_state *cpu, uint16_t addr) { return mem[addr]; @@ -18,18 +55,23 @@ static void mem_write(struct lr35902_state *cpu, uint16_t addr, uint8_t val) mem[addr] = val; } -static void test_inc(const void *test_data) +static void run_cpu_test(const void *test_data) { + const struct gb_cpu_test *test = test_data; struct emitter emitter; struct buffer_emitter buffer_emitter; struct lr35902_state cpu; - char *src; + char *src; int rc; - src = strdup("inc a\n inc b\n halt\n"); + if (test->init != NULL) { + test->init(); + } + + src = strdup(test->src_prog); memset(mem, 0, sizeof(mem)); buffer_emitter_init(&emitter, &buffer_emitter, mem, sizeof(mem)); - + rc = gbasm_assemble(src, &emitter); g_assert_cmpint(rc, ==, 0); @@ -38,56 +80,91 @@ static void test_inc(const void *test_data) lr35902_cycle(&cpu); } - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_A), ==, 1); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_B), ==, 1); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_C), ==, 0); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_D), ==, 0); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_E), ==, 0); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_H), ==, 0); - - free(src); -} - - -static void test_dec(const void *test_data) -{ - struct emitter emitter; - struct buffer_emitter buffer_emitter; - struct lr35902_state cpu; - char *src; - int rc; - - src = strdup("dec a\n inc c\n dec c\n dec de\n halt\n"); - memset(mem, 0, sizeof(mem)); - buffer_emitter_init(&emitter, &buffer_emitter, mem, sizeof(mem)); - - rc = gbasm_assemble(src, &emitter); - g_assert_cmpint(rc, ==, 0); - - lr35902_init(&cpu, mem_read, mem_write); - while (!cpu.halted) { - lr35902_cycle(&cpu); + switch(test->expected_regs_type) { + case GB_CPU_TEST_REGS_8: + gb_cpu_test_cmp_regs_8(&cpu, &test->expected.regs_8); + break; + case GB_CPU_TEST_REGS_16: + gb_cpu_test_cmp_regs_16(&cpu, &test->expected.regs_16); + break; + default: + g_assert(0); } - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_A), ==, 0xff); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_B), ==, 0); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_C), ==, 0); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_D), ==, 0xff); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_E), ==, 0xff); - g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_H), ==, 0); - - g_assert_cmpint(lr35902_get_reg_16(&cpu, LR35902_REG_DE), ==, 0xffff); - free(src); } + +/* static void test_inc(const void *test_data) */ +/* { */ +/* struct emitter emitter; */ +/* struct buffer_emitter buffer_emitter; */ +/* struct lr35902_state cpu; */ +/* char *src; */ +/* int rc; */ + +/* src = strdup("inc a\n inc b\n halt\n"); */ +/* memset(mem, 0, sizeof(mem)); */ +/* buffer_emitter_init(&emitter, &buffer_emitter, mem, sizeof(mem)); */ + +/* rc = gbasm_assemble(src, &emitter); */ +/* g_assert_cmpint(rc, ==, 0); */ + +/* lr35902_init(&cpu, mem_read, mem_write); */ +/* while (!cpu.halted) { */ +/* lr35902_cycle(&cpu); */ +/* } */ + +/* free(src); */ +/* } */ + + +/* static void test_dec(const void *test_data) */ +/* { */ +/* struct emitter emitter; */ +/* struct buffer_emitter buffer_emitter; */ +/* struct lr35902_state cpu; */ +/* char *src; */ +/* int rc; */ + +/* src = strdup("dec a\n inc c\n dec c\n dec de\n halt\n"); */ +/* memset(mem, 0, sizeof(mem)); */ +/* buffer_emitter_init(&emitter, &buffer_emitter, mem, sizeof(mem)); */ + +/* rc = gbasm_assemble(src, &emitter); */ +/* g_assert_cmpint(rc, ==, 0); */ + +/* lr35902_init(&cpu, mem_read, mem_write); */ +/* while (!cpu.halted) { */ +/* lr35902_cycle(&cpu); */ +/* } */ + +/* g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_A), ==, 0xff); */ +/* g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_B), ==, 0); */ +/* g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_C), ==, 0); */ +/* g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_D), ==, 0xff); */ +/* g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_E), ==, 0xff); */ +/* g_assert_cmpint(lr35902_get_reg_8(&cpu, LR35902_REG_H), ==, 0); */ + +/* g_assert_cmpint(lr35902_get_reg_16(&cpu, LR35902_REG_DE), ==, 0xffff); */ + +/* free(src); */ +/* } */ int main(int argc, char **argv) { + char test_name_buff[256]; + g_test_init(&argc, &argv, NULL); - - g_test_add_data_func("/gbemu/cpu/inc", NULL, test_inc); - g_test_add_data_func("/gbemu/cpu/dec", NULL, test_dec); - + + for (int i = 0; i < ARRAY_SIZE(tests); i++) { + for (int j = 0; tests[i][j] != NULL; j++) { + snprintf(test_name_buff, sizeof(test_name_buff), + "/gbemu/cpu%s", + tests[i][j]->name); + g_test_add_data_func(test_name_buff, tests[i][j], run_cpu_test); + } + } + return g_test_run(); }