#include #include #include #include "6502.h" #include "bus.h" #include "memory.h" enum { ROM_START = 0xf800, ROM_END = 0xffff, ROM_SIZE = 2048, RAM_START = 0x0000, RAM_END = 0x01ff, RAM_SIZE = 512 }; static cpu_6502_t cpu; static bus_t bus; static memory_t rom; static memory_t ram; static uint8_t code[ROM_SIZE]; static int codesize; void setup( void ) { bus_init( &bus ); cpu_6502_init( &cpu, &bus, true ); cpu.debug_flags |= DEBUG_STATUS | DEBUG_STACK | DEBUG_ZERO_PAGE; memory_init( &rom, MEMORY_ROM, ROM_START, ROM_SIZE, true ); bus_register( &bus, &rom.base, ROM_START, ROM_END ); memory_init( &ram, MEMORY_RAM, RAM_START, RAM_SIZE, true ); bus_register( &bus, &ram.base, RAM_START, RAM_END ); // install code start vector code[0] = ROM_START & 0x00ff; code[1] = ( ROM_START & 0xff00 ) >> 8; codesize = 2; memory_set( &rom, 0x07fc, code, codesize ); } void teardown( void ) { bus_deinit( &bus ); } START_TEST( test_cpu_6502_nop ) { cpu_6502_t before_cpu; memory_t before_ram; cpu_6502_reset( &cpu ); memory_reset( &rom ); memory_reset( &ram ); memset( code, 0, ROM_SIZE ); code[0] = 0xea; // NOP codesize = 1; memory_set( &rom, 0x00, code, codesize ); memcpy( &before_cpu, &cpu, sizeof( cpu ) ); memory_copy( &before_ram, &ram ); cpu_6502_run( &cpu, 1 ); fprintf( stderr, "state before:\n" ); cpu_6502_print_debug( &before_cpu ); fprintf( stderr, "state after:\n" ); cpu_6502_print_debug( &cpu ); ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK ); ck_assert_int_eq( cpu.PC, before_cpu.PC+1 ); ck_assert_int_eq( cpu.SP, before_cpu.SP ); ck_assert_int_eq( cpu.PS, before_cpu.PS ); ck_assert_int_eq( cpu.A, before_cpu.A ); ck_assert_int_eq( cpu.X, before_cpu.X ); ck_assert_int_eq( cpu.Y, before_cpu.Y ); ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size ); memory_deinit( &before_ram ); } END_TEST START_TEST( test_cpu_6502_txs ) { cpu_6502_t before_cpu; memory_t before_ram; cpu_6502_reset( &cpu ); memory_reset( &rom ); memory_reset( &ram ); memset( code, 0, ROM_SIZE ); code[0] = 0x9a; // TXS codesize = 1; memory_set( &rom, 0x00, code, codesize ); cpu.X = 0xff; memcpy( &before_cpu, &cpu, sizeof( cpu ) ); memory_copy( &before_ram, &ram ); cpu_6502_run( &cpu, 1 ); fprintf( stderr, "state before:\n" ); cpu_6502_print_debug( &before_cpu ); fprintf( stderr, "state after:\n" ); cpu_6502_print_debug( &cpu ); ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK ); ck_assert_int_eq( cpu.PC, before_cpu.PC+1 ); ck_assert_int_eq( cpu.SP, cpu.X ); ck_assert_int_eq( cpu.PS, before_cpu.PS ); ck_assert_int_eq( cpu.A, before_cpu.A ); ck_assert_int_eq( cpu.X, 0xff ); ck_assert_int_eq( cpu.Y, before_cpu.Y ); ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size ); memory_deinit( &before_ram ); } END_TEST START_TEST( test_cpu_6502_ldx_pos ) { cpu_6502_t before_cpu; memory_t before_ram; cpu_6502_reset( &cpu ); memory_reset( &rom ); memory_reset( &ram ); memset( code, 0, ROM_SIZE ); code[0] = 0xa2; // LDX immediate code[1] = 0x01; // #$1 codesize = 2; memory_set( &rom, 0x00, code, codesize ); cpu.X = 0xff; memcpy( &before_cpu, &cpu, sizeof( cpu ) ); memory_copy( &before_ram, &ram ); cpu_6502_run( &cpu, 1 ); fprintf( stderr, "state before:\n" ); cpu_6502_print_debug( &before_cpu ); fprintf( stderr, "state after:\n" ); cpu_6502_print_debug( &cpu ); ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK ); ck_assert_int_eq( cpu.PC, before_cpu.PC+2 ); ck_assert_int_eq( cpu.SP, before_cpu.SP ); ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) ); ck_assert( !cpu_6502_is_zero( &cpu ) ); ck_assert( !cpu_6502_is_negative( &cpu ) ); ck_assert_int_eq( cpu.A, before_cpu.A ); ck_assert_int_eq( cpu.X, 0x01 ); ck_assert_int_eq( cpu.Y, before_cpu.Y ); ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size ); memory_deinit( &before_ram ); } END_TEST START_TEST( test_cpu_6502_ldx_neg ) { cpu_6502_t before_cpu; memory_t before_ram; cpu_6502_reset( &cpu ); memory_reset( &rom ); memory_reset( &ram ); memset( code, 0, ROM_SIZE ); code[0] = 0xa2; // LDX immediate code[1] = 0xff; // #-1 codesize = 2; memory_set( &rom, 0x00, code, codesize ); memcpy( &before_cpu, &cpu, sizeof( cpu ) ); memory_copy( &before_ram, &ram ); cpu_6502_run( &cpu, 1 ); fprintf( stderr, "state before:\n" ); cpu_6502_print_debug( &before_cpu ); fprintf( stderr, "state after:\n" ); cpu_6502_print_debug( &cpu ); ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK ); ck_assert_int_eq( cpu.PC, before_cpu.PC+2 ); ck_assert_int_eq( cpu.SP, before_cpu.SP ); ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) ); ck_assert( !cpu_6502_is_zero( &cpu ) ); ck_assert( cpu_6502_is_negative( &cpu ) ); ck_assert_int_eq( cpu.A, before_cpu.A ); ck_assert_int_eq( cpu.X, 0xff ); ck_assert_int_eq( cpu.Y, before_cpu.Y ); ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size ); memory_deinit( &before_ram ); } END_TEST START_TEST( test_cpu_6502_ldx_zero ) { cpu_6502_t before_cpu; memory_t before_ram; cpu_6502_reset( &cpu ); memory_reset( &rom ); memory_reset( &ram ); memset( code, 0, ROM_SIZE ); code[0] = 0xa2; // LDX immediate code[1] = 0x00; // #$0 codesize = 2; memory_set( &rom, 0x00, code, codesize ); cpu.X = 0xff; memcpy( &before_cpu, &cpu, sizeof( cpu ) ); memory_copy( &before_ram, &ram ); cpu_6502_run( &cpu, 1 ); fprintf( stderr, "state before:\n" ); cpu_6502_print_debug( &before_cpu ); fprintf( stderr, "state after:\n" ); cpu_6502_print_debug( &cpu ); ck_assert_int_eq( cpu.error_state, ERROR_STATE_OK ); ck_assert_int_eq( cpu.PC, before_cpu.PC+2 ); ck_assert_int_eq( cpu.SP, before_cpu.SP ); ck_assert_int_eq( cpu.PS & ~( PS_N | PS_Z ), before_cpu.PS & ~( PS_N | PS_Z ) ); ck_assert( cpu_6502_is_zero( &cpu ) ); ck_assert( !cpu_6502_is_negative( &cpu ) ); ck_assert_int_eq( cpu.A, before_cpu.A ); ck_assert_int_eq( cpu.X, 0x00 ); ck_assert_int_eq( cpu.Y, before_cpu.Y ); ck_assert_mem_eq( ram.cell, before_ram.cell, ram.size ); memory_deinit( &before_ram ); } END_TEST static void create_cpu_6502_testcase( Suite *suite, const char *name, const TTest *test_func ) { TCase *tc; tc = tcase_create( name ); tcase_add_unchecked_fixture( tc, setup, teardown); tcase_add_test( tc, test_func ); suite_add_tcase( suite, tc ); } static Suite *make_cpu_6502_testsuite( void ) { Suite *suite; suite = suite_create( "6502 CPU tests" ); create_cpu_6502_testcase( suite, "NOP", test_cpu_6502_nop ); create_cpu_6502_testcase( suite, "TXS", test_cpu_6502_txs ); create_cpu_6502_testcase( suite, "LDX (positive)", test_cpu_6502_ldx_pos ); create_cpu_6502_testcase( suite, "LDX (negative)", test_cpu_6502_ldx_neg ); create_cpu_6502_testcase( suite, "LDX (zero)", test_cpu_6502_ldx_zero ); return suite; } int main( void ) { SRunner *runner; int tests_failed = 0; runner = srunner_create( make_cpu_6502_testsuite( ) ); srunner_set_fork_status( runner, CK_NOFORK ); srunner_set_log( runner, "test.log" ); srunner_set_xml( runner, "test.xml" ); srunner_run_all( runner, CK_VERBOSE ); tests_failed = srunner_ntests_failed( runner ); srunner_free( runner ); exit( ( tests_failed == 0 ) ? EXIT_SUCCESS : EXIT_FAILURE ); }