/* * Apple // emulator for *ix * * This software package is subject to the GNU General Public License * version 3 or later (your choice) as published by the Free Software * Foundation. * * Copyright 2013-2015 Aaron Culliney * */ // // Tests for virtual 65c02 CPU (opcodes and addressing modes) // #include "testcommon.h" #include "uthash.h" #define MSG_SIZE 256 #define fC C_Flag_6502 // [C]arry #define fZ Z_Flag_6502 // [Z]ero #define fI I_Flag_6502 // [I]nterrupt #define fD D_Flag_6502 // [D]ecimal #define fB B_Flag_6502 // [B]reak #define fX X_Flag_6502 // [X]tra (reserved)... #define fV V_Flag_6502 // o[V]erflow #define fN N_Flag_6502 // [N]egative #define TEST_LOC 0x1f82 #define TEST_LOC_LO 0x82 #define RW_NONE 0x0 #define RW_READ 0x1 #define RW_WRITE 0x2 #define MSG_FLAGS0 "A:%02X op %02X = %02X : %s (emul2ix = %02X : %s)" #define HEADER0() \ uint8_t result = 0x0; \ uint8_t flags = 0x0; \ char buf0[MSG_SIZE]; \ char buf1[MSG_SIZE]; \ char msgbuf[MSG_SIZE]; #define VERIFY_FLAGS() \ flags_to_string(flags, buf0); \ flags_to_string(cpu65_f, buf1); \ snprintf(msgbuf, MSG_SIZE, MSG_FLAGS0, regA, val, result, buf0, cpu65_a, buf1); \ ASSERTm(msgbuf, cpu65_f == flags); static void testcpu_setup(void *arg) { cpu65_uninterrupt(0xff); extern int32_t cpu65_cycles_to_execute; extern int32_t cpu65_cycle_count; cpu65_cycle_count = 0; cpu65_cycles_to_execute = 1; cpu65_pc = TEST_LOC; cpu65_a = 0x0; cpu65_x = 0x0; cpu65_y = 0x0; cpu65_f = 0x0; cpu65_sp = 0xff; cpu65_ea = 0xffff; cpu65_d = 0xff; cpu65_rw = 0xff; cpu65_opcode = 0xff; cpu65_opcycles = 0xff; // clear ZP & stack memory memset(apple_ii_64k, 0x0, 0x200); // clear prog memory and absolute addressing test locations memset(((void*)apple_ii_64k)+TEST_LOC, 0x0, 0x300); } static void testcpu_teardown(void *arg) { // ... } static void testcpu_set_opcodeX(uint8_t op, uint8_t val, uint8_t arg1, uint16_t addrs) { cpu65_pc = addrs; apple_ii_64k[0][addrs] = op; apple_ii_64k[0][(uint16_t)(addrs+1)] = val; apple_ii_64k[0][(uint16_t)(addrs+2)] = arg1; } static void testcpu_set_opcode3(uint8_t op, uint8_t val, uint8_t arg1) { testcpu_set_opcodeX(op, val, arg1, TEST_LOC); } static void testcpu_set_opcode2(uint8_t op, uint8_t val) { uint8_t arg1 = (uint8_t)random(); testcpu_set_opcode3(op, val, arg1); } static void testcpu_set_opcode1(uint8_t op) { uint8_t val = (uint8_t)random(); uint8_t arg1 = (uint8_t)random(); testcpu_set_opcode3(op, val, arg1); } static bool check_skip_illegal_bcd(uint8_t bcd0, uint8_t bcd1) { if (bcd0 >= 0xA0) { return true; } if ((bcd0 & 0x0f) >= 0x0A) { return true; } if (bcd1 >= 0xA0) { return true; } if ((bcd1 & 0x0f) >= 0x0A) { return true; } return false; } static void flags_to_string(uint8_t flags, char *buf) { snprintf(buf, MSG_SIZE, "%c%c%c%c%c%c%c%c", (flags & N_Flag_6502) ? 'N' : '-', (flags & V_Flag_6502) ? 'V' : '-', (flags & X_Flag_6502) ? 'X' : '-', (flags & B_Flag_6502) ? 'B' : '-', (flags & D_Flag_6502) ? 'D' : '-', (flags & I_Flag_6502) ? 'I' : '-', (flags & Z_Flag_6502) ? 'Z' : '-', (flags & C_Flag_6502) ? 'C' : '-' ); } // ---------------------------------------------------------------------------- // ADC instructions static void logic_ADC_dec(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { // componentize uint8_t x_lo = 0x0; uint8_t x_hi = 0x0; uint8_t a_lo = (((uint8_t)_a) & 0x0f); uint8_t b_lo = (((uint8_t)_b) & 0x0f); uint8_t a_hi = (((uint8_t)_a) & 0xf0)>>4; uint8_t b_hi = (((uint8_t)_b) & 0xf0)>>4; uint8_t carry = (*flags & fC) ? 1 : 0; *flags &= ~ fC; // BCD add x_lo = a_lo + b_lo + carry; carry = 0; if (x_lo > 9) { x_lo += 6; carry = (x_lo>>4); // +1 or +2 x_lo &= 0x0f; } x_hi = a_hi + b_hi + carry; if (x_hi > 9) { *flags |= fC; x_hi += 6; } // merge result x_hi <<= 4; *result = x_hi | x_lo; // flags if (*result == 0x00) { *flags |= fZ; } if (*result & 0x80) { *flags |= fN; } } static void logic_ADC(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { if (*flags & fD) { logic_ADC_dec(_a, _b, result, flags); return; } int8_t a = (int8_t)_a; int8_t b = (int8_t)_b; bool signA = a>>7; bool signB = b>>7; int8_t carry = (*flags & fC) ? 1 : 0; *flags &= ~fC; int8_t res = a + b + carry; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } int32_t res32 = (uint8_t)a+(uint8_t)b+(uint8_t)carry; if (res32 & 0x00000100) { *flags |= fC; } if (signA == signB) { uint8_t signResult = (res&0xff)>>7; if (signA != signResult) { *flags |= fV; } } *result = (uint8_t)(res & 0xff); } TEST test_ADC_imm(uint8_t regA, uint8_t val, bool decimal, bool carry) { HEADER0(); flags |= decimal ? (fD) : 0x00; flags |= carry ? (fC) : 0x00; if (decimal && check_skip_illegal_bcd(regA, val)) { // NOTE : FIXME TODO skip undocumented/illegal BCD SKIPm("Z"); } logic_ADC(regA, val, &result, &flags); testcpu_set_opcode2(0x69, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f |= decimal ? (fD) : 0x00; cpu65_f |= carry ? (fC) : 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); snprintf(msgbuf, MSG_SIZE, MSG_FLAGS0, regA, val, result, buf0, cpu65_a, buf1); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x69); ASSERT(cpu65_opcycles == (decimal ? 3 : 2)); PASS(); } TEST test_ADC_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode2(0x65, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x65); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_ADC_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_ADC(regA, val, &result, &flags); uint8_t idx = arg0 + regX; testcpu_set_opcode2(0x75, arg0); apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x75); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_ADC_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode3(0x6d, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x6d); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_ADC_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode3(0x7d, lobyte, hibyte); uint8_t cycle_count = 0; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x7d); cycle_count += 4; ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_ADC_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode3(0x79, lobyte, hibyte); uint8_t cycle_count = 0; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x79); cycle_count += 4; ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_ADC_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode2(0x61, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x61); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ADC_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode2(0x71, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 0; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x71); cycle_count += 5; ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_ADC_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ADC(regA, val, &result, &flags); testcpu_set_opcode2(0x72, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x72); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // AND instructions static void logic_AND(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t b = (uint8_t)_b; uint8_t res = a & b; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = res; } TEST test_AND_imm(uint8_t regA, uint8_t val) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode2(0x29, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); snprintf(msgbuf, MSG_SIZE, MSG_FLAGS0, regA, val, result, buf0, cpu65_a, buf1); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x29); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_AND_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode2(0x25, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x25); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_AND_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode2(0x35, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x35); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_AND_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode3(0x2d, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x2d); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_AND_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode3(0x3d, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x3d); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_AND_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode3(0x39, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x39); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_AND_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode2(0x21, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x21); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_AND_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode2(0x31, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 5; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x31); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_AND_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_AND(regA, val, &result, &flags); testcpu_set_opcode2(0x32, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x32); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // ASL instructions static void logic_ASL(/*uint8_t*/int _a, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; *flags |= (a & 0x80) ? fC : 0; uint8_t res = a<<1; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = res; } TEST test_ASL_acc(uint8_t regA) { uint8_t val = 0xff; HEADER0(); logic_ASL(regA, &result, &flags); testcpu_set_opcode1(0x0a); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == 0); ASSERT(cpu65_opcode == 0x0a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_ASL_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_ASL(val, &result, &flags); testcpu_set_opcode2(0x06, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x06); ASSERT(cpu65_opcycles == (5)); PASS(); } TEST test_ASL_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_ASL(val, &result, &flags); testcpu_set_opcode2(0x16, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x16); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ASL_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ASL(val, &result, &flags); testcpu_set_opcode3(0x0e, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x0e); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ASL_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ASL(val, &result, &flags); testcpu_set_opcode3(0x1e, lobyte, hibyte); uint8_t cycle_count = 6; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x1e); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // Branch instructions TEST test_BCC(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fC : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (!flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0x90; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x90); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BCS(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fC : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0xB0; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xB0); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BEQ(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fZ : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0xF0; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xF0); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BNE(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fZ : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (!flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0xD0; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xD0); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BMI(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fN : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0x30; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x30); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BPL(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fN : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (!flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0x10; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x10); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BRA(volatile int8_t off, volatile bool flag, volatile uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fN : 0; uint8_t cycle_count = 3; uint16_t newpc = addrs+2; uint16_t prebranch = newpc; newpc += off; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } apple_ii_64k[0][addrs] = 0x80; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x80); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BVC(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fV : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (!flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0x50; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x50); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_BVS(int8_t off, bool flag, uint16_t addrs) { HEADER0(); cpu65_pc = addrs; flags |= flag ? fV : 0; uint8_t cycle_count = 2; uint16_t newpc = addrs+2; if (flag) { uint16_t prebranch = newpc; newpc += off; ++cycle_count; if ((newpc&0xFF00) != (prebranch&0xFF00)) { ++cycle_count; } } apple_ii_64k[0][addrs] = 0x70; apple_ii_64k[0][(uint16_t)(addrs+1)] = off; apple_ii_64k[0][(uint16_t)(addrs+2)] = (uint8_t)random(); cpu65_a = 0xed; cpu65_x = 0xde; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0xed); ASSERT(cpu65_x == 0xde); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == flags); ASSERT(cpu65_ea == (uint16_t)(addrs+1)); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x70); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // BIT instructions TEST test_BIT_imm(uint8_t regA, uint8_t val) { HEADER0(); if ((regA & val) == 0x0) { flags = fZ; } testcpu_set_opcode2(0x89, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x89); ASSERT(cpu65_opcycles == (2)); PASS(); } static void logic_BIT(uint8_t regA, uint8_t val, uint8_t *flags) { if ((regA & val) == 0x0) { *flags |= fZ; } if (val & 0x80) { *flags |= fN; } if (val & 0x40) { *flags |= fV; } } TEST test_BIT_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_BIT(regA, val, &flags); testcpu_set_opcode2(0x24, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x24); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_BIT_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_BIT(regA, val, &flags); testcpu_set_opcode2(0x34, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x34); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_BIT_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_BIT(regA, val, &flags); testcpu_set_opcode3(0x2c, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x2c); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_BIT_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_BIT(regA, val, &flags); testcpu_set_opcode3(0x3c, lobyte, hibyte); uint8_t cycle_count = 0; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x3c); cycle_count += 4; ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // BRK operand (and IRQ handling) TEST test_BRK() { testcpu_set_opcode1(0x00); ASSERT(apple_ii_64k[0][0x1ff] != 0x1f); ASSERT(apple_ii_64k[0][0x1fe] != TEST_LOC_LO+2); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == 0xc3fa); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == (fB|fX|fI)); ASSERT(cpu65_sp == 0xfc); ASSERT(apple_ii_64k[0][0x1ff] == 0x1f); ASSERT(apple_ii_64k[0][0x1fe] == TEST_LOC_LO+2); ASSERT(apple_ii_64k[0][0x1fd] == cpu65_flags_encode[B_Flag|X_Flag]); //ASSERT(cpu65_ea == 0xfffe); -- EA is managed differently on ARM ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x0); ASSERT(cpu65_opcycles == (7)); PASS(); } // FIXME TODO : this tests the Apple //e vm, so it prolly should be moved machine/memory tests ... TEST test_IRQ() { testcpu_set_opcode1(0xea/*NOP*/); // Implementation NOTE: first an instruction, then reset is handled cpu65_interrupt(IRQGeneric); ASSERT(apple_ii_64k[0][0x1ff] != 0x1f); ASSERT(apple_ii_64k[0][0x1fe] != TEST_LOC_LO+1); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == 0xc3fd); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == (fB|fX|fI|fZ)); // Implementation NOTE : Z set by 2nd BIT instruction at C3FA ASSERT(cpu65_sp == 0xfc); ASSERT(apple_ii_64k[0][0x1ff] == 0x1f); ASSERT(apple_ii_64k[0][0x1fe] == TEST_LOC_LO); ASSERT(apple_ii_64k[0][0x1fd] == cpu65_flags_encode[X_Flag]); ASSERT(cpu65_ea == 0xc015); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x2c); ASSERT(cpu65_opcycles == (4)); PASS(); } // ---------------------------------------------------------------------------- // CLx operands TEST test_CLC() { testcpu_set_opcode1(0x18); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = fC; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x18); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_CLD(uint8_t regA, uint8_t val) { testcpu_set_opcode1(0xd8); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = fD; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xd8); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_CLI(uint8_t regA, uint8_t val) { testcpu_set_opcode1(0x58); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = fI; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x58); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_CLV(uint8_t regA, uint8_t val) { testcpu_set_opcode1(0xb8); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = fV; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xb8); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // CMP instructions static void logic_CMP(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t b = (uint8_t)_b; uint8_t res = a - b; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } if (b <= a) { *flags |= fC; } } TEST test_CMP_imm(uint8_t regA, uint8_t val) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode2(0xC9, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xC9); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_CMP_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode2(0xc5, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xc5); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_CMP_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode2(0xd5, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xd5); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_CMP_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode3(0xcd, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xcd); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_CMP_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode3(0xdd, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xdd); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_CMP_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode3(0xd9, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xd9); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_CMP_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode2(0xc1, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xc1); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_CMP_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode2(0xd1, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 5; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xd1); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // 65c02 : 0xD2 TEST test_CMP_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_CMP(regA, val, &flags); testcpu_set_opcode2(0xd2, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xd2); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // CPx CPy instructions TEST test_CPX_imm(uint8_t regX, uint8_t val) { HEADER0(); uint8_t regA = 0xaa; logic_CMP(regX, val, &flags); testcpu_set_opcode2(0xe0, val); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xe0); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_CPX_zpage(uint8_t regX, uint8_t val, uint8_t arg0) { HEADER0(); uint8_t regA = 0x55; logic_CMP(regX, val, &flags); testcpu_set_opcode2(0xe4, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xe4); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_CPX_abs(uint8_t regX, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); uint8_t regA = 0xAA; logic_CMP(regX, val, &flags); testcpu_set_opcode3(0xec, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xec); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_CPY_imm(uint8_t regY, uint8_t val) { HEADER0(); uint8_t regA = 0xaa; logic_CMP(regY, val, &flags); testcpu_set_opcode2(0xc0, val); cpu65_a = regA; cpu65_x = 0x66; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x66); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xc0); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_CPY_zpage(uint8_t regY, uint8_t val, uint8_t arg0) { HEADER0(); uint8_t regA = 0x55; logic_CMP(regY, val, &flags); testcpu_set_opcode2(0xc4, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x27; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x27); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xc4); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_CPY_abs(uint8_t regY, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); uint8_t regA = 0xAA; logic_CMP(regY, val, &flags); testcpu_set_opcode3(0xcc, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x7b; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x7b); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xcc); ASSERT(cpu65_opcycles == (4)); PASS(); } // ---------------------------------------------------------------------------- // DEA, DEX, DEY instructions static void logic_DEx(/*uint8_t*/int _a, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t res = a-1; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = res; } TEST test_DEA(uint8_t regA) { HEADER0(); uint8_t val = regA; logic_DEx(regA, &result, &flags); testcpu_set_opcode1(0x3a); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == result); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x3a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_DEX(uint8_t regX) { HEADER0(); uint8_t regA = 0x12; uint8_t val = regX; logic_DEx(regX, &result, &flags); testcpu_set_opcode1(0xca); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == result); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xca); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_DEY(uint8_t regY) { HEADER0(); uint8_t regA = 0x12; uint8_t val = regY; logic_DEx(regY, &result, &flags); testcpu_set_opcode1(0x88); cpu65_a = regA; cpu65_x = 0x13; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x13); ASSERT(cpu65_y == result); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x88); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // DEC instructions TEST test_DEC_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_DEx(val, &result, &flags); testcpu_set_opcode2(0xc6, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(apple_ii_64k[0][arg0] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xc6); ASSERT(cpu65_opcycles == (5)); PASS(); } TEST test_DEC_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_DEx(val, &result, &flags); testcpu_set_opcode2(0xd6, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(apple_ii_64k[0][idx] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xd6); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_DEC_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_DEx(val, &result, &flags); testcpu_set_opcode3(0xce, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(apple_ii_64k[0][addrs] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xce); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_DEC_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_DEx(val, &result, &flags); testcpu_set_opcode3(0xde, lobyte, hibyte); uint8_t cycle_count = 6; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(apple_ii_64k[0][addrs] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xde); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // EOR instructions static void logic_EOR(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t b = (uint8_t)_b; uint8_t res = a ^ b; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = res; } TEST test_EOR_imm(uint8_t regA, uint8_t val) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode2(0x49, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); snprintf(msgbuf, MSG_SIZE, MSG_FLAGS0, regA, val, result, buf0, cpu65_a, buf1); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x49); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_EOR_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode2(0x45, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x45); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_EOR_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode2(0x55, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x55); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_EOR_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode3(0x4d, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x4d); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_EOR_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode3(0x5d, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x5d); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_EOR_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode3(0x59, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x59); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_EOR_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode2(0x41, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x41); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_EOR_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode2(0x51, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 5; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x51); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // 65c02 : 0x52 TEST test_EOR_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_EOR(regA, val, &result, &flags); testcpu_set_opcode2(0x52, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x52); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // INA, INX, INY instructions static void logic_INx(/*uint8_t*/int _a, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t res = a+1; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = res; } TEST test_INA(uint8_t regA) { HEADER0(); uint8_t val = regA; logic_INx(regA, &result, &flags); testcpu_set_opcode1(0x1a); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == result); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x1a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_INX(uint8_t regX) { HEADER0(); uint8_t regA = 0x31; uint8_t val = regX; logic_INx(regX, &result, &flags); testcpu_set_opcode1(0xe8); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == result); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xe8); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_INY(uint8_t regY) { HEADER0(); uint8_t regA = 0x21; uint8_t val = regY; logic_INx(regY, &result, &flags); testcpu_set_opcode1(0xc8); cpu65_a = regA; cpu65_x = 0x13; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x13); ASSERT(cpu65_y == result); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xc8); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // INC instructions TEST test_INC_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_INx(val, &result, &flags); testcpu_set_opcode2(0xe6, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(apple_ii_64k[0][arg0] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xe6); ASSERT(cpu65_opcycles == (5)); PASS(); } TEST test_INC_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_INx(val, &result, &flags); testcpu_set_opcode2(0xf6, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(apple_ii_64k[0][idx] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xf6); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_INC_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_INx(val, &result, &flags); testcpu_set_opcode3(0xee, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(apple_ii_64k[0][addrs] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xee); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_INC_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_INx(val, &result, &flags); testcpu_set_opcode3(0xfe, lobyte, hibyte); uint8_t cycle_count = 6; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(apple_ii_64k[0][addrs] == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0xfe); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // JMP instructions TEST test_JMP_abs(uint8_t lobyte, uint8_t hibyte, uint16_t insAddrs) { HEADER0(); testcpu_set_opcodeX(0x4c, lobyte, hibyte, insAddrs); uint8_t regA = (uint8_t)random(); uint8_t regX = (uint8_t)random(); uint8_t regY = (uint8_t)random(); uint8_t f = (uint8_t)random(); uint8_t sp = (uint8_t)random(); uint16_t addrs = (hibyte<<8) | lobyte; cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = sp; cpu65_f = f; cpu65_run(); ASSERT(cpu65_pc == addrs); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == regY); ASSERT(cpu65_f == f); ASSERT(cpu65_sp == sp); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x4c); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_JMP_ind(uint8_t _lobyte, uint8_t _hibyte, uint16_t insAddrs) { HEADER0(); testcpu_set_opcodeX(0x6c, _lobyte, _hibyte, insAddrs); uint8_t regA = (uint8_t)random(); uint8_t regX = (uint8_t)random(); uint8_t regY = (uint8_t)random(); uint8_t f = (uint8_t)random(); uint8_t sp = (uint8_t)random(); uint16_t _addrs = (_hibyte<<8) | _lobyte; if ((_addrs >= 0xbfff) && (_addrs < 0xd000)) { // HACK FIXME TODO NOTE : for now don't test slot memory ... PASS(); } uint8_t lo = apple_ii_64k[0][_addrs]; ++_addrs; if (_lobyte == 0xff) { _addrs -= 0x100; } uint8_t hi = apple_ii_64k[0][_addrs]; uint16_t addr = (hi<<8) | lo; if (_lobyte == 0xff) { _addrs += 0x100; } --_addrs; #if 0 // Interesting memory will be HI ROM ... enable this to sanity-check if (addr != 0) { fprintf(stderr, "%04x -> (%04x)\n", _addrs, addr); } #endif cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = sp; cpu65_f = f; cpu65_run(); ASSERT(cpu65_pc == addr); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == regY); ASSERT(cpu65_f == f); ASSERT(cpu65_sp == sp); //ASSERT(cpu65_ea == _addrs); -- EA is managed differently on ARM ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x6c); ASSERT(cpu65_opcycles == (6)); PASS(); } // 65c02 : 0x7C TEST test_JMP_abs_ind_x(uint8_t _lobyte, uint8_t _hibyte, uint16_t insAddrs, uint8_t _regX) { HEADER0(); testcpu_set_opcodeX(0x7c, _lobyte, _hibyte, insAddrs); uint8_t regA = (uint8_t)random(); uint8_t regX = _regX; uint8_t regY = (uint8_t)random(); uint8_t f = (uint8_t)random(); uint8_t sp = (uint8_t)random(); uint16_t _addrs = (_hibyte<<8) | _lobyte; _addrs += regX; if ((_addrs >= 0xbfff) && (_addrs < 0xd000)) { // HACK FIXME TODO NOTE : for now don't test slot memory ... PASS(); } uint8_t lo = apple_ii_64k[0][_addrs]; ++_addrs; uint8_t hi = apple_ii_64k[0][_addrs]; uint16_t addr = (hi<<8) | lo; --_addrs; #if 0 // Interesting memory will be HI ROM ... enable this to sanity-check if (addr != 0) { fprintf(stderr, "%04x -> (%04x)\n", _addrs, addr); } #endif cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = sp; cpu65_f = f; cpu65_run(); ASSERT(cpu65_pc == addr); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == regY); ASSERT(cpu65_f == f); ASSERT(cpu65_sp == sp); //ASSERT(cpu65_ea == _addrs); -- EA is managed differently on ARM ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x7c); ASSERT(cpu65_opcycles == (6)); PASS(); } // ---------------------------------------------------------------------------- // JSR operand TEST test_JSR_abs(uint8_t lobyte, uint8_t hibyte, uint16_t insAddrs) { HEADER0(); testcpu_set_opcodeX(0x20, lobyte, hibyte, insAddrs); uint8_t regA = (uint8_t)random(); uint8_t regX = (uint8_t)random(); uint8_t regY = (uint8_t)random(); uint8_t f = (uint8_t)random(); uint16_t addrs = (hibyte<<8) | lobyte; insAddrs += 2; uint8_t hi_ret = (insAddrs >> 8) & 0xff; uint8_t lo_ret = insAddrs & 0xff; cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = 0xff; cpu65_f = f; cpu65_run(); ASSERT(cpu65_pc == addrs); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == regY); ASSERT(cpu65_f == f); ASSERT(cpu65_sp == 0xfd); ASSERT(apple_ii_64k[0][0x1ff] == hi_ret); ASSERT(apple_ii_64k[0][0x1fe] == lo_ret); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x20); ASSERT(cpu65_opcycles == (6)); PASS(); } // ---------------------------------------------------------------------------- // LDA instructions static void logic_LDx(/*uint8_t*/int _b, uint8_t *flags) { uint8_t b = (uint8_t)_b; if ((b & 0xff) == 0x0) { *flags |= fZ; } if (b & 0x80) { *flags |= fN; } } TEST test_LDA_imm(uint8_t regA, uint8_t val) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xa9, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == val); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa9); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_LDA_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xa5, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == val); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa5); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_LDA_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xb5, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == val); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xb5); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_LDA_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode3(0xad, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == val); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xad); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_LDA_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode3(0xbd, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == val); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xbd); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_LDA_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode3(0xb9, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == val); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xb9); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_LDA_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xa1, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == val); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa1); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_LDA_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xb1, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 5; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == val); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xb1); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // 65c02 : 0xB2 TEST test_LDA_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xb2, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == val); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xb2); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // LDX LDY instructions TEST test_LDX_imm(uint8_t regX, uint8_t val) { HEADER0(); uint8_t regA = 0xaa; logic_LDx(val, &flags); testcpu_set_opcode2(0xa2, val); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == val); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa2); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_LDX_zpage(uint8_t regX, uint8_t val, uint8_t arg0) { HEADER0(); uint8_t regA = 0x55; logic_LDx(val, &flags); testcpu_set_opcode2(0xa6, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == val); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa6); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_LDX_zpage_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY) { HEADER0(); logic_LDx(val, &flags); testcpu_set_opcode2(0xb6, arg0); uint8_t idx = arg0+regY; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = 0x3e; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == val); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xb6); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_LDX_abs(uint8_t regX, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); uint8_t regA = 0xab; logic_LDx(val, &flags); testcpu_set_opcode3(0xae, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == val); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xae); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_LDX_abs_y(uint8_t regX, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); uint8_t regA = 0xba; logic_LDx(val, &flags); testcpu_set_opcode3(0xbe, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == val); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xbe); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_LDY_imm(uint8_t regY, uint8_t val) { HEADER0(); uint8_t regA = 0xaa; logic_LDx(val, &flags); testcpu_set_opcode2(0xa0, val); cpu65_a = regA; cpu65_x = 0x18; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x18); ASSERT(cpu65_y == val); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa0); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_LDY_zpage(uint8_t regY, uint8_t val, uint8_t arg0) { HEADER0(); uint8_t regA = 0x55; logic_LDx(val, &flags); testcpu_set_opcode2(0xa4, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x4e; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x4e); ASSERT(cpu65_y == val); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xa4); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_LDY_zpage_x(uint8_t regY, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); uint8_t regA = 0xa9; logic_LDx(val, &flags); testcpu_set_opcode2(0xb4, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == val); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xb4); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_LDY_abs(uint8_t regY, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); uint8_t regA = 0xab; logic_LDx(val, &flags); testcpu_set_opcode3(0xac, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x1a; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x1a); ASSERT(cpu65_y == val); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xac); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_LDY_abs_x(uint8_t regY, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); uint8_t regA = 0x5a; logic_LDx(val, &flags); testcpu_set_opcode3(0xbc, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == val); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xbc); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // LSR instructions static void logic_LSR(/*uint8_t*/int _a, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; *flags |= (a & 0x01) ? fC : 0; uint8_t res = a>>1; if ((res & 0xff) == 0x0) { *flags |= fZ; } *flags &= ~fN; *result = res; } TEST test_LSR_acc(uint8_t regA) { uint8_t val = 0xff; HEADER0(); logic_LSR(regA, &result, &flags); testcpu_set_opcode1(0x4a); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x4a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_LSR_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_LSR(val, &result, &flags); testcpu_set_opcode2(0x46, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x46); ASSERT(cpu65_opcycles == (5)); PASS(); } TEST test_LSR_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_LSR(val, &result, &flags); testcpu_set_opcode2(0x56, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x56); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_LSR_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LSR(val, &result, &flags); testcpu_set_opcode3(0x4e, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x4e); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_LSR_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_LSR(val, &result, &flags); testcpu_set_opcode3(0x5e, lobyte, hibyte); uint8_t cycle_count = 6; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x5e); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // NOP operand TEST test_NOP() { testcpu_set_opcode1(0xea); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x55; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == 0x55); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xea); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // ORA instructions static void logic_ORA(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t b = (uint8_t)_b; uint8_t res = a | b; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = res; } TEST test_ORA_imm(uint8_t regA, uint8_t val) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode2(0x09, val); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); snprintf(msgbuf, MSG_SIZE, MSG_FLAGS0, regA, val, result, buf0, cpu65_a, buf1); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x09); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_ORA_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode2(0x05, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x05); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_ORA_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode2(0x15, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x15); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_ORA_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode3(0x0d, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x0d); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_ORA_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode3(0x1d, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x1d); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_ORA_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode3(0x19, lobyte, hibyte); uint8_t cycle_count = 4; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x19); ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_ORA_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode2(0x01, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x01); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ORA_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode2(0x11, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 5; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x11); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // 65c02 : 0x12 TEST test_ORA_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_ORA(regA, val, &result, &flags); testcpu_set_opcode2(0x12, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0x12); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // PHx instructions TEST test_PHA() { testcpu_set_opcode1(0x48); uint8_t regA = (uint8_t)random(); apple_ii_64k[0][0x1ff] = ~regA; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = 0x55; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == 0x55); ASSERT(cpu65_sp == 0xfe); ASSERT(apple_ii_64k[0][0x1ff] == regA); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x48); ASSERT(cpu65_opcycles == (3)); PASS(); } static int test_PLP(uint8_t flags); TEST test_PHP(uint8_t flags) { testcpu_set_opcode1(0x08); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = flags; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == flags); ASSERT(cpu65_sp == 0xfe); ASSERT(apple_ii_64k[0][0x1ff] == flags); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x08); ASSERT(cpu65_opcycles == (3)); cpu65_pc = TEST_LOC; test_PLP(flags); PASS(); } TEST test_PHX() { testcpu_set_opcode1(0xda); uint8_t regX = (uint8_t)random(); cpu65_a = 0x03; cpu65_x = regX; cpu65_y = 0x05; cpu65_f = 0x53; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x03); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_f == 0x53); ASSERT(cpu65_sp == 0xfe); ASSERT(apple_ii_64k[0][0x1ff] == regX); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xda); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_PHY() { testcpu_set_opcode1(0x5a); uint8_t regY = (uint8_t)random(); cpu65_a = 0x03; cpu65_x = 0x50; cpu65_y = regY; cpu65_f = 0x53; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x03); ASSERT(cpu65_x == 0x50); ASSERT(cpu65_y == regY); ASSERT(cpu65_f == 0x53); ASSERT(cpu65_sp == 0xfe); ASSERT(apple_ii_64k[0][0x1ff] == regY); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x5a); ASSERT(cpu65_opcycles == (3)); PASS(); } // ---------------------------------------------------------------------------- // PLx instructions static void logic_PLx(/*uint8_t*/int _a, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t res = a | a; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } } TEST test_PLA(uint8_t regA) { HEADER0(); uint8_t val = regA; uint8_t sp = 0x80; logic_PLx(regA, &flags); testcpu_set_opcode1(0x68); apple_ii_64k[0][0x101+sp] = regA; cpu65_a = 0x00; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = 0x00; cpu65_sp = sp; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == sp+1); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x68); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_PLP(uint8_t flags) { uint8_t sp = 0x80; ASSERT(cpu65_pc == TEST_LOC); testcpu_set_opcode1(0x28); apple_ii_64k[0][0x101+sp] = flags; cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = ~flags; cpu65_sp = sp; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == sp+1); ASSERT(cpu65_f == (flags | fB | fX)); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x28); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_PLX(uint8_t regX) { HEADER0(); uint8_t regA = 0x00; uint8_t val = 0x00; uint8_t sp = 0x80; logic_PLx(regX, &flags); testcpu_set_opcode1(0xfa); apple_ii_64k[0][0x101+sp] = regX; cpu65_a = 0x43; cpu65_x = 0x00; cpu65_y = 0x04; cpu65_f = 0x00; cpu65_sp = sp; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x43); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == sp+1); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xfa); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_PLY(uint8_t regY) { HEADER0(); uint8_t regA = 0x00; uint8_t val = 0x00; uint8_t sp = 0x80; logic_PLx(regY, &flags); testcpu_set_opcode1(0x7a); apple_ii_64k[0][0x101+sp] = regY; cpu65_a = 0x43; cpu65_x = 0x34; cpu65_y = 0x00; cpu65_f = 0x00; cpu65_sp = sp; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x43); ASSERT(cpu65_x == 0x34); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == sp+1); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x7a); ASSERT(cpu65_opcycles == (4)); PASS(); } // ---------------------------------------------------------------------------- // ROL instructions static void logic_ROL(/*uint8_t*/int _a, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint16_t res = a<<1; if (*flags & fC) { res |= 0x1; } if (res & 0x100) { *flags |= fC; } else { *flags &= ~fC; } if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = (res & 0xff); } TEST test_ROL_acc(uint8_t regA, bool carry) { uint8_t val = 0xff; HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROL(regA, &result, &flags); testcpu_set_opcode1(0x2a); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == 0); ASSERT(cpu65_opcode == 0x2a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_ROL_zpage(bool regA, uint8_t val, uint8_t arg0, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROL(val, &result, &flags); testcpu_set_opcode2(0x26, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x26); ASSERT(cpu65_opcycles == (5)); PASS(); } TEST test_ROL_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROL(val, &result, &flags); testcpu_set_opcode2(0x36, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x36); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ROL_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROL(val, &result, &flags); testcpu_set_opcode3(0x2e, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x2e); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ROL_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROL(val, &result, &flags); testcpu_set_opcode3(0x3e, lobyte, hibyte); uint8_t cycle_count = 6; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x3e); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // ROR instructions static void logic_ROR(/*uint8_t*/int _a, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; bool carry = (a & 0x01); uint8_t res = a>>1; if (*flags & fC) { res |= 0x80; } if (carry) { *flags |= fC; } else { *flags &= ~fC; } if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } *result = (res & 0xff); } TEST test_ROR_acc(uint8_t regA, bool carry) { uint8_t val = 0xff; HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROR(regA, &result, &flags); testcpu_set_opcode1(0x6a); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == 0); ASSERT(cpu65_opcode == 0x6a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_ROR_zpage(bool regA, uint8_t val, uint8_t arg0, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROR(val, &result, &flags); testcpu_set_opcode2(0x66, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x66); ASSERT(cpu65_opcycles == (5)); PASS(); } TEST test_ROR_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROR(val, &result, &flags); testcpu_set_opcode2(0x76, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x76); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ROR_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROR(val, &result, &flags); testcpu_set_opcode3(0x6e, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x6e); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_ROR_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte, bool carry) { HEADER0(); flags |= carry ? (fC) : 0x00; logic_ROR(val, &result, &flags); testcpu_set_opcode3(0x7e, lobyte, hibyte); uint8_t cycle_count = 6; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = carry ? (fC) : 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x7e); ASSERT(cpu65_opcycles == cycle_count); PASS(); } // ---------------------------------------------------------------------------- // RTI operand TEST test_RTI(uint8_t flags) { testcpu_set_opcode1(0x40); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = 0x00; cpu65_sp = 0x80; uint8_t lo_ret = (uint8_t)random(); uint8_t hi_ret = (uint8_t)random(); apple_ii_64k[0][0x181] = flags; apple_ii_64k[0][0x182] = lo_ret; apple_ii_64k[0][0x183] = hi_ret; cpu65_run(); ASSERT(cpu65_pc == ((hi_ret<<8)| lo_ret)); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == (flags | fB | fX)); ASSERT(cpu65_sp == 0x83); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x40); ASSERT(cpu65_opcycles == (6)); PASS(); } // ---------------------------------------------------------------------------- // RTS operand TEST test_RTS(uint8_t lobyte, uint8_t hibyte, uint16_t insAddrs) { testcpu_set_opcodeX(0x60, random(), random(), insAddrs); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_f = 0x00; cpu65_sp = 0x80; apple_ii_64k[0][0x181] = lobyte; apple_ii_64k[0][0x182] = hibyte; cpu65_run(); uint16_t newpc = ((hibyte<<8) | lobyte) + 1; ASSERT(cpu65_pc == newpc); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_sp == 0x82); ASSERT(cpu65_ea == insAddrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x60); ASSERT(cpu65_opcycles == (6)); PASS(); } // ---------------------------------------------------------------------------- // SBC instructions static void logic_SBC_dec(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { // componentize uint8_t x_lo = 0x0; uint8_t x_hi = 0x0; uint8_t a_lo = (((uint8_t)_a) & 0x0f); uint8_t b_lo = (((uint8_t)_b) & 0x0f); uint8_t a_hi = (((uint8_t)_a) & 0xf0)>>4; uint8_t b_hi = (((uint8_t)_b) & 0xf0)>>4; uint8_t borrow = ((*flags & fC) == 0x0) ? 1 : 0; *flags |= fC; // BCD subtract x_lo = a_lo - b_lo - borrow; borrow = 0; if (x_lo > 9) { borrow = 1; x_lo -= 6; x_lo &= 0x0f; } x_hi = a_hi - b_hi - borrow; if (x_hi > 9) { *flags &= ~fC; x_hi -= 6; } // merge result x_hi <<= 4; *result = x_hi | x_lo; // flags if (*result == 0x00) { *flags |= fZ; } if (*result & 0x80) { *flags |= fN; } } static void logic_SBC(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { if (*flags & fD) { logic_SBC_dec(_a, _b, result, flags); return; } int8_t a = (int8_t)_a; int8_t b = (int8_t)_b; bool signA = a>>7; bool signB = b>>7; int8_t borrow = ((*flags & fC) == 0x0) ? 1 : 0; *flags |= fC; int8_t res = a - b - borrow; if ((res & 0xff) == 0x0) { *flags |= fZ; } if (res & 0x80) { *flags |= fN; } uint32_t res32 = (uint8_t)a-(uint8_t)b-(uint8_t)borrow; if (res32 & 0x80000000) { *flags &= ~fC; } if (signA != signB) { uint8_t signResult = (res&0xff)>>7; if (signA != signResult) { *flags |= fV; } } *result = (uint8_t)(res & 0xff); } TEST test_SBC_imm(uint8_t regA, uint8_t val, bool decimal, bool carry) { HEADER0(); if (decimal && check_skip_illegal_bcd(regA, val)) { // NOTE : FIXME TODO skip undocumented/illegal BCD SKIPm("Z"); } flags |= decimal ? (fD) : 0x00; flags |= carry ? (fC) : 0x00; logic_SBC(regA, val, &result, &flags); testcpu_set_opcode2(0xe9, val); cpu65_a = regA; cpu65_x = 0x33; cpu65_y = 0x44; cpu65_sp = 0x88; cpu65_f |= decimal ? (fD) : 0x00; cpu65_f |= carry ? (fC) : 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x33); ASSERT(cpu65_y == 0x44); ASSERT(cpu65_sp == 0x88); snprintf(msgbuf, MSG_SIZE, MSG_FLAGS0, regA, val, result, buf0, cpu65_a, buf1); ASSERTm(msgbuf, cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC+1); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xe9); ASSERT(cpu65_opcycles == (decimal ? 3 : 2)); PASS(); } TEST test_SBC_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode2(0xe5, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xe5); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_SBC_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); logic_SBC(regA, val, &result, &flags); uint8_t idx = arg0 + regX; testcpu_set_opcode2(0xf5, arg0); apple_ii_64k[0][idx] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xf5); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_SBC_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode3(0xed, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xed); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_SBC_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode3(0xfd, lobyte, hibyte); uint8_t cycle_count = 0; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xfd); cycle_count += 4; ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_SBC_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode3(0xf9, lobyte, hibyte); uint8_t cycle_count = 0; uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)hibyte) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xf9); cycle_count += 4; ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_SBC_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode2(0xe1, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xe1); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_SBC_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode2(0xf1, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint8_t cycle_count = 0; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; if ((uint8_t)((addrs>>8)&0xff) != (uint8_t)val_zp1) { ++cycle_count; } apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xf1); cycle_count += 5; ASSERT(cpu65_opcycles == cycle_count); PASS(); } TEST test_SBC_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_SBC(regA, val, &result, &flags); testcpu_set_opcode2(0xf2, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_a == result); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_READ); ASSERT(cpu65_opcode == 0xf2); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // SEx operands [sic] TEST test_SEC() { testcpu_set_opcode1(0x38); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == (fC)); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x38); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_SED(uint8_t regA, uint8_t val) { testcpu_set_opcode1(0xf8); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == (fD)); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xf8); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_SEI(uint8_t regA, uint8_t val) { testcpu_set_opcode1(0x78); cpu65_a = 0x02; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x02); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == (fI)); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x78); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // STA instructions TEST test_STA_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); testcpu_set_opcode2(0x85, arg0); cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x85); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_STA_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); testcpu_set_opcode2(0x95, arg0); uint8_t idx = arg0+regX; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == regA); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x95); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_STA_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x8d, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regA); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x8d); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_STA_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x9d, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regA); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x9d); ASSERT(cpu65_opcycles == 5); PASS(); } TEST test_STA_abs_y(uint8_t regA, uint8_t val, uint8_t regY, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x99, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regY; cpu65_a = regA; cpu65_x = 0x02; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x02); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == RW_WRITE); ASSERT(cpu65_opcode == 0x99); ASSERT(cpu65_opcycles == 5); PASS(); } TEST test_STA_ind_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode2(0x81, arg0); uint8_t idx_lo = arg0 + regX; uint8_t idx_hi = idx_lo+1; uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][idx_lo] = lobyte; apple_ii_64k[0][idx_hi] = hibyte; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x15; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x15); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x81); ASSERT(cpu65_opcycles == (6)); PASS(); } TEST test_STA_ind_y(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regY, uint8_t val_zp0, uint8_t val_zp1) { HEADER0(); testcpu_set_opcode2(0x91, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = val_zp0; apple_ii_64k[0][idx1] = val_zp1; uint16_t addrs = val_zp0 | (val_zp1<<8); addrs += (uint8_t)regY; cpu65_a = regA; cpu65_x = 0x84; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x84); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x91); ASSERT(cpu65_opcycles == 6); PASS(); } // 65c02 : 0x92 TEST test_STA_ind_zpage(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode2(0x92, arg0); uint8_t idx0 = arg0; uint8_t idx1 = arg0+1; apple_ii_64k[0][idx0] = lobyte; apple_ii_64k[0][idx1] = hibyte; uint16_t addrs = lobyte | (hibyte<<8); cpu65_a = regA; cpu65_x = 0x14; cpu65_y = 0x85; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x14); ASSERT(cpu65_y == 0x85); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regA); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x92); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // STx instructions TEST test_STX_zpage(uint8_t regX, uint8_t val, uint8_t arg0) { HEADER0(); testcpu_set_opcode2(0x86, arg0); cpu65_a = 0xe3; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == regX); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == 0xe3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == regX); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x86); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_STX_zpage_y(uint8_t regX, uint8_t val, uint8_t arg0, uint8_t regY) { HEADER0(); testcpu_set_opcode2(0x96, arg0); uint8_t idx = arg0+regY; cpu65_a = 0xcc; cpu65_x = regX; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == regX); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == 0xcc); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == regX); ASSERT(cpu65_rw == RW_WRITE); ASSERT(cpu65_opcode == 0x96); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_STX_abs(uint8_t regX, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x8e, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); cpu65_a = 0xf4; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regX); ASSERT(cpu65_a == 0xf4); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regX); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x8e); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_STY_zpage(uint8_t regY, uint8_t val, uint8_t arg0) { HEADER0(); testcpu_set_opcode2(0x84, arg0); cpu65_a = 0xa8; cpu65_x = 0x03; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == regY); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == 0xa8); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == regY); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x84); ASSERT(cpu65_opcycles == (3)); PASS(); } TEST test_STY_zpage_x(uint8_t regY, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); testcpu_set_opcode2(0x94, arg0); uint8_t idx = arg0+regX; cpu65_a = 0x11; cpu65_x = regX; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == regY); ASSERT(cpu65_a == 0x11); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == regY); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x94); ASSERT(cpu65_opcycles == (4)); PASS(); } TEST test_STY_abs(uint8_t regY, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x8c, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); cpu65_a = 0x4f; cpu65_x = 0xf4; cpu65_y = regY; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == regY); ASSERT(cpu65_a == 0x4f); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == regY); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x8c); ASSERT(cpu65_opcycles == (4)); PASS(); } // 65c02 : 0x64 TEST test_STZ_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); testcpu_set_opcode2(0x64, arg0); apple_ii_64k[0][arg0] = 0xff; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == 0x00); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == 0x00); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x64); ASSERT(cpu65_opcycles == (3)); PASS(); } // 65c02 : 0x74 TEST test_STZ_zpage_x(uint8_t regA, uint8_t val, uint8_t arg0, uint8_t regX) { HEADER0(); testcpu_set_opcode2(0x74, arg0); uint8_t idx = arg0+regX; apple_ii_64k[0][idx] = 0xff; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][idx] == 0x00); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == idx); ASSERT(cpu65_d == 0x00); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x74); ASSERT(cpu65_opcycles == (4)); PASS(); } // 65c02 : 0x9C TEST test_STZ_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x9c, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = 0xff; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == 0x00); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0x00); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x9c); ASSERT(cpu65_opcycles == (4)); PASS(); } // 65c02 : 0x9E TEST test_STZ_abs_x(uint8_t regA, uint8_t val, uint8_t regX, uint8_t lobyte, uint8_t hibyte) { HEADER0(); testcpu_set_opcode3(0x9e, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); addrs = addrs + regX; apple_ii_64k[0][addrs] = 0xff; cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == 0x00); ASSERT(cpu65_a == regA); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == 0x00); ASSERT(cpu65_rw == (RW_WRITE)); ASSERT(cpu65_opcode == 0x9e); ASSERT(cpu65_opcycles == 5); PASS(); } // ---------------------------------------------------------------------------- // TAx, TxA instructions static void logic_TAx(/*uint8_t*/int _a, uint8_t *flags) { uint8_t a = (uint8_t)_a; if ((a & 0xff) == 0x0) { *flags |= fZ; } if (a & 0x80) { *flags |= fN; } } TEST test_TAX(uint8_t regA) { HEADER0(); uint8_t val = regA; logic_TAx(regA, &flags); uint8_t regX = ~regA; testcpu_set_opcode1(0xaa); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == regA); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xaa); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_TAY(uint8_t regA) { HEADER0(); uint8_t val = regA; logic_TAx(regA, &flags); uint8_t regY = ~regA; testcpu_set_opcode1(0xa8); cpu65_a = regA; cpu65_x = 0x6e; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x6e); ASSERT(cpu65_y == regA); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xa8); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_TXA(uint8_t regX) { HEADER0(); uint8_t val = regX; logic_TAx(regX, &flags); uint8_t regA = ~regX; testcpu_set_opcode1(0x8a); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regX); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x8a); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_TYA(uint8_t regY) { HEADER0(); uint8_t val = regY; logic_TAx(regY, &flags); uint8_t regA = ~regY; testcpu_set_opcode1(0x98); cpu65_a = regA; cpu65_x = 0xa4; cpu65_y = regY; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regY); ASSERT(cpu65_x == 0xa4); ASSERT(cpu65_y == regY); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x98); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // TRB & TSB operands static void logic_TRB(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t b = (uint8_t)_b; uint8_t res = (~a) & b; if ((a & b) == 0x0) { *flags |= fZ; } *result = res; } TEST test_TRB_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_TRB(regA, val, &result, &flags); testcpu_set_opcode3(0x1c, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x1c); ASSERT(cpu65_opcycles == (6)); PASS(); } // 65c02 : 0x14 TEST test_TRB_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_TRB(regA, val, &result, &flags); testcpu_set_opcode2(0x14, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == result); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x14); ASSERT(cpu65_opcycles == (5)); PASS(); } static void logic_TSB(/*uint8_t*/int _a, /*uint8_t*/int _b, uint8_t *result, uint8_t *flags) { uint8_t a = (uint8_t)_a; uint8_t b = (uint8_t)_b; uint8_t res = a | b; if ((a & b) == 0x0) { *flags |= fZ; } *result = res; } // 65c02 : 0x0C TEST test_TSB_abs(uint8_t regA, uint8_t val, uint8_t lobyte, uint8_t hibyte) { HEADER0(); logic_TSB(regA, val, &result, &flags); testcpu_set_opcode3(0x0c, lobyte, hibyte); uint16_t addrs = lobyte | (hibyte<<8); apple_ii_64k[0][addrs] = val; cpu65_a = regA; cpu65_x = 0xf4; cpu65_y = 0x05; cpu65_sp = 0x81; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][addrs] == result); ASSERT(cpu65_pc == TEST_LOC+3); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0xf4); ASSERT(cpu65_y == 0x05); ASSERT(cpu65_sp == 0x81); VERIFY_FLAGS(); ASSERT(cpu65_ea == addrs); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x0c); ASSERT(cpu65_opcycles == (6)); PASS(); } // 65c02 : 0x04 TEST test_TSB_zpage(uint8_t regA, uint8_t val, uint8_t arg0) { HEADER0(); logic_TSB(regA, val, &result, &flags); testcpu_set_opcode2(0x04, arg0); apple_ii_64k[0][arg0] = val; cpu65_a = regA; cpu65_x = 0x03; cpu65_y = 0x04; cpu65_sp = 0x80; cpu65_f = 0x00; cpu65_run(); ASSERT(apple_ii_64k[0][arg0] == result); ASSERT(cpu65_pc == TEST_LOC+2); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == 0x03); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == 0x80); VERIFY_FLAGS(); ASSERT(cpu65_ea == arg0); ASSERT(cpu65_d == result); ASSERT(cpu65_rw == (RW_READ|RW_WRITE)); ASSERT(cpu65_opcode == 0x04); ASSERT(cpu65_opcycles == (5)); PASS(); } // ---------------------------------------------------------------------------- // TSX, TXS instructions static void logic_TSX(/*uint8_t*/int _a, uint8_t *flags) { uint8_t a = (uint8_t)_a; if ((a & 0xff) == 0x0) { *flags |= fZ; } if (a & 0x80) { *flags |= fN; } } TEST test_TSX(uint8_t sp) { HEADER0(); uint8_t regA = (uint8_t)random(); uint8_t val = regA; uint8_t regX = ~sp; logic_TSX(sp, &flags); testcpu_set_opcode1(0xba); cpu65_a = regA; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = sp; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == regA); ASSERT(cpu65_x == sp); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == sp); VERIFY_FLAGS(); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0xba); ASSERT(cpu65_opcycles == (2)); PASS(); } TEST test_TXS(uint8_t regX) { HEADER0(); uint8_t sp = ~regX; testcpu_set_opcode1(0x9a); cpu65_a = 0x22; cpu65_x = regX; cpu65_y = 0x04; cpu65_sp = sp; cpu65_f = 0x00; cpu65_run(); ASSERT(cpu65_pc == TEST_LOC+1); ASSERT(cpu65_a == 0x22); ASSERT(cpu65_x == regX); ASSERT(cpu65_y == 0x04); ASSERT(cpu65_sp == regX); ASSERT(cpu65_f == 0x00); ASSERT(cpu65_ea == TEST_LOC); ASSERT(cpu65_d == 0xff); ASSERT(cpu65_rw == RW_NONE); ASSERT(cpu65_opcode == 0x9a); ASSERT(cpu65_opcycles == (2)); PASS(); } // ---------------------------------------------------------------------------- // Test Suite static unsigned int testcounter = 0; typedef int(*test_func_ptr0)(void); typedef int(*test_func_ptr)(uint8_t x, ...); typedef struct test_func_t { unsigned int id; char *name; void *func; UT_hash_handle hh; } test_func_t; static test_func_t *test_funcs = NULL; #define A2_ADD_TEST(TEST) \ do { \ test_func_t *test_func = malloc(sizeof(test_func_t)); \ test_func->id = testcounter; \ test_func->name = strdup(#TEST); \ test_func->func = TEST; \ HASH_ADD_INT(test_funcs, id, test_func); \ ++testcounter; \ } while(0); #define A2_REMOVE_TEST(TEST) \ do { \ HASH_DEL(test_funcs, TEST); \ free(TEST->name); \ free(TEST); \ } while(0); #define A2_RUN_TESTp(TEST, ...) RUN_TESTp( ((test_func_ptr)(TEST)), __VA_ARGS__) GREATEST_SUITE(test_suite_cpu) { GREATEST_SET_SETUP_CB(testcpu_setup, NULL); GREATEST_SET_TEARDOWN_CB(testcpu_teardown, NULL); srandom(time(NULL)); video_init(); test_common_init(); assert(cpu_thread_id == 0 && "This test is not designed to run with alternate CPU thread"); extern void reinitialize(void); reinitialize(); extern volatile uint8_t emul_reinitialize; emul_reinitialize = 0; test_func_t *func=NULL, *tmp=NULL; // -------------------------------- A2_ADD_TEST(test_BRK); A2_ADD_TEST(test_IRQ); A2_ADD_TEST(test_CLC); A2_ADD_TEST(test_CLD); A2_ADD_TEST(test_CLI); A2_ADD_TEST(test_CLV); A2_ADD_TEST(test_NOP); A2_ADD_TEST(test_PHA); A2_ADD_TEST(test_PHX); A2_ADD_TEST(test_PHY); A2_ADD_TEST(test_SEC); A2_ADD_TEST(test_SED); A2_ADD_TEST(test_SEI); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); RUN_TEST(((test_func_ptr0)(func->func))); A2_REMOVE_TEST(func); } // ------------------------------------------------------------------------ // Branch tests : // NOTE : these should be a comprehensive exercise of the branching logic greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; A2_ADD_TEST(test_BCC); A2_ADD_TEST(test_BCS); A2_ADD_TEST(test_BEQ); A2_ADD_TEST(test_BNE); A2_ADD_TEST(test_BMI); A2_ADD_TEST(test_BPL); A2_ADD_TEST(test_BRA); A2_ADD_TEST(test_BVC); A2_ADD_TEST(test_BVS); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); for (uint16_t addrs = 0x1f02; addrs < 0x2000; addrs++) { for (uint8_t flag = 0x00; flag < 0x02; flag++) { uint8_t off=0x00; do { A2_RUN_TESTp( func->func, off, flag, addrs); } while (++off); } } // 16bit branch overflow tests for (uint16_t addrs = 0xff00; addrs >= 0xff00 || addrs < 0x00fe; addrs++) { for (uint8_t flag = 0x00; flag < 0x02; flag++) { uint8_t off=0x00; do { A2_RUN_TESTp(func->func, off, flag, addrs); } while (++off); } } // 16bit branch underflow tests for (uint16_t addrs = 0x00fe; addrs <= 0x00fe || addrs > 0xff00; addrs--) { for (uint8_t flag = 0x00; flag < 0x02; flag++) { uint8_t off=0x00; do { A2_RUN_TESTp(func->func, off, flag, addrs); } while (++off); } } fprintf(GREATEST_STDOUT, "...OK\n"); A2_REMOVE_TEST(func); } greatest_info.flags = 0x0; // ------------------------------------------------------------------------ // Immediate addressing mode tests #1 : // NOTE : these should be a comprehensive exercise of the instruction logic greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; A2_ADD_TEST(test_ADC_imm); A2_ADD_TEST(test_AND_imm); A2_ADD_TEST(test_BIT_imm); A2_ADD_TEST(test_CMP_imm); A2_ADD_TEST(test_CPX_imm); A2_ADD_TEST(test_CPY_imm); A2_ADD_TEST(test_EOR_imm); A2_ADD_TEST(test_LDA_imm); A2_ADD_TEST(test_LDX_imm); A2_ADD_TEST(test_LDY_imm); A2_ADD_TEST(test_ORA_imm); A2_ADD_TEST(test_SBC_imm); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); // test comprehensive logic in immediate mode (since no addressing to test) ... uint8_t regA=0x00; do { uint8_t val=0x00; do { A2_RUN_TESTp( func->func, regA, val, /*decimal*/false, /*carry*/false); A2_RUN_TESTp( func->func, regA, val, /*decimal*/ true, /*carry*/false); A2_RUN_TESTp( func->func, regA, val, /*decimal*/false, /*carry*/true); A2_RUN_TESTp( func->func, regA, val, /*decimal*/ true, /*carry*/true); } while (++val); } while (++regA); fprintf(GREATEST_STDOUT, "...OK\n"); A2_REMOVE_TEST(func); } greatest_info.flags = 0x0; // ------------------------------------------------------------------------ // Immediate/absolute addressing mode tests greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; A2_ADD_TEST(test_JMP_abs); A2_ADD_TEST(test_JMP_abs_ind_x); A2_ADD_TEST(test_JMP_ind); A2_ADD_TEST(test_JSR_abs); A2_ADD_TEST(test_RTS); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); // test comprehensive logic in immediate mode (since no addressing to test) ... uint8_t lobyte=0x00; do { uint8_t hibyte=0x00; do { A2_RUN_TESTp( func->func, lobyte, hibyte, TEST_LOC, (uint8_t)random()); } while (++hibyte); } while (++lobyte); // test 16bit overflow/underflow lobyte=0x00; do { uint8_t regX=0x00; do { A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFC, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFD, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFE, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0xFFFF, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0000, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0001, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0002, regX); A2_RUN_TESTp( func->func, lobyte, (uint8_t)random(), 0x0003, regX); } while (++regX); } while (++lobyte); fprintf(GREATEST_STDOUT, "...OK\n"); A2_REMOVE_TEST(func); } greatest_info.flags = 0x0; // ------------------------------------------------------------------------ // Accumulator addressing & PLx tests : // NOTE : these should be a comprehensive exercise of the instruction logic greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; A2_ADD_TEST(test_ASL_acc); A2_ADD_TEST(test_DEA); A2_ADD_TEST(test_DEX); A2_ADD_TEST(test_DEY); A2_ADD_TEST(test_INA); A2_ADD_TEST(test_INX); A2_ADD_TEST(test_INY); A2_ADD_TEST(test_LSR_acc); A2_ADD_TEST(test_PHP); A2_ADD_TEST(test_PLA); A2_ADD_TEST(test_PLP); A2_ADD_TEST(test_PLX); A2_ADD_TEST(test_PLY); A2_ADD_TEST(test_ROL_acc); A2_ADD_TEST(test_ROR_acc); A2_ADD_TEST(test_RTI); A2_ADD_TEST(test_TAX); A2_ADD_TEST(test_TAY); A2_ADD_TEST(test_TSX); A2_ADD_TEST(test_TXS); A2_ADD_TEST(test_TXA); A2_ADD_TEST(test_TYA); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s (SILENCED OUTPUT) :\n", func->name); // test comprehensive logic in immediate mode (since no addressing to test) ... uint8_t regA=0x00; do { A2_RUN_TESTp( func->func, regA, true); A2_RUN_TESTp( func->func, regA, false); } while (++regA); fprintf(GREATEST_STDOUT, "...OK\n"); A2_REMOVE_TEST(func); } greatest_info.flags = 0x0; // ------------------------------------------------------------------------ // Other addressing modes tests : // NOTE : unlike immediate-mode addressing tests above, these tests are not designed to be a comprehensive test of // instruction logic. Rather--for clarity--they are designed to comprehensively test the addressing logic, // including all edge cases // -------------------------------- #ifdef ANDROID greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; #endif A2_ADD_TEST(test_ADC_zpage); A2_ADD_TEST(test_AND_zpage); A2_ADD_TEST(test_ASL_zpage); A2_ADD_TEST(test_BIT_zpage); A2_ADD_TEST(test_CMP_zpage); A2_ADD_TEST(test_CPX_zpage); A2_ADD_TEST(test_CPY_zpage); A2_ADD_TEST(test_DEC_zpage); A2_ADD_TEST(test_EOR_zpage); A2_ADD_TEST(test_INC_zpage); A2_ADD_TEST(test_LDA_zpage); A2_ADD_TEST(test_LDX_zpage); A2_ADD_TEST(test_LDY_zpage); A2_ADD_TEST(test_LSR_zpage); A2_ADD_TEST(test_ORA_zpage); A2_ADD_TEST(test_ROL_zpage); A2_ADD_TEST(test_ROR_zpage); A2_ADD_TEST(test_SBC_zpage); A2_ADD_TEST(test_STA_zpage); A2_ADD_TEST(test_STX_zpage); A2_ADD_TEST(test_STY_zpage); A2_ADD_TEST(test_STZ_zpage); A2_ADD_TEST(test_TRB_zpage); A2_ADD_TEST(test_TSB_zpage); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... uint8_t arg0 = 0x00; do { A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, /*carry*/false); ++arg0; } while (arg0); #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } // -------------------------------- greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; A2_ADD_TEST(test_ADC_zpage_x); A2_ADD_TEST(test_AND_zpage_x); A2_ADD_TEST(test_ASL_zpage_x); A2_ADD_TEST(test_BIT_zpage_x); A2_ADD_TEST(test_CMP_zpage_x); A2_ADD_TEST(test_DEC_zpage_x); A2_ADD_TEST(test_EOR_zpage_x); A2_ADD_TEST(test_INC_zpage_x); A2_ADD_TEST(test_LDA_zpage_x); A2_ADD_TEST(test_LDX_zpage_y); // ...y A2_ADD_TEST(test_LDY_zpage_x); A2_ADD_TEST(test_LSR_zpage_x); A2_ADD_TEST(test_ORA_zpage_x); A2_ADD_TEST(test_SBC_zpage_x); A2_ADD_TEST(test_ROL_zpage_x); A2_ADD_TEST(test_ROR_zpage_x); A2_ADD_TEST(test_STA_zpage_x); A2_ADD_TEST(test_STX_zpage_y); // ...y A2_ADD_TEST(test_STY_zpage_x); A2_ADD_TEST(test_STZ_zpage_x); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... uint8_t regX = 0x0; do { uint8_t arg0 = 0x0; do { A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, regX, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, arg0, regX, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, regX, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, arg0, regX, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, regX, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, arg0, regX, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, regX, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, arg0, regX, /*carry*/false); } while (++arg0); } while (++regX); fprintf(GREATEST_STDOUT, "...OK\n"); A2_REMOVE_TEST(func); } greatest_info.flags = 0x0; // -------------------------------- #ifdef ANDROID greatest_info.flags = GREATEST_FLAG_SILENT_SUCCESS; #endif A2_ADD_TEST(test_ADC_abs); A2_ADD_TEST(test_AND_abs); A2_ADD_TEST(test_ASL_abs); A2_ADD_TEST(test_BIT_abs); A2_ADD_TEST(test_CMP_abs); A2_ADD_TEST(test_CPX_abs); A2_ADD_TEST(test_CPY_abs); A2_ADD_TEST(test_DEC_abs); A2_ADD_TEST(test_EOR_abs); A2_ADD_TEST(test_INC_abs); A2_ADD_TEST(test_LDA_abs); A2_ADD_TEST(test_LDX_abs); A2_ADD_TEST(test_LDY_abs); A2_ADD_TEST(test_LSR_abs); A2_ADD_TEST(test_ORA_abs); A2_ADD_TEST(test_ROL_abs); A2_ADD_TEST(test_ROR_abs); A2_ADD_TEST(test_SBC_abs); A2_ADD_TEST(test_STA_abs); A2_ADD_TEST(test_STX_abs); A2_ADD_TEST(test_STY_abs); A2_ADD_TEST(test_STZ_abs); A2_ADD_TEST(test_TRB_abs); A2_ADD_TEST(test_TSB_abs); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { uint8_t hibyte = 0x1f; A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, lobyte, hibyte, /*carry*/true); } #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } // -------------------------------- A2_ADD_TEST(test_ADC_abs_x); A2_ADD_TEST(test_AND_abs_x); A2_ADD_TEST(test_ASL_abs_x); A2_ADD_TEST(test_BIT_abs_x); A2_ADD_TEST(test_CMP_abs_x); A2_ADD_TEST(test_DEC_abs_x); A2_ADD_TEST(test_EOR_abs_x); A2_ADD_TEST(test_INC_abs_x); A2_ADD_TEST(test_LDA_abs_x); A2_ADD_TEST(test_LDY_abs_x); A2_ADD_TEST(test_LSR_abs_x); A2_ADD_TEST(test_ORA_abs_x); A2_ADD_TEST(test_ROL_abs_x); A2_ADD_TEST(test_ROR_abs_x); A2_ADD_TEST(test_SBC_abs_x); A2_ADD_TEST(test_STA_abs_x); A2_ADD_TEST(test_STZ_abs_x); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... uint8_t hibyte = 0x1f; uint8_t lobyte = 0x20; for (uint8_t regX=0x50; regX>0x4f; regX+=0x30) { A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, regX, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, regX, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, regX, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, regX, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, regX, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, regX, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, regX, lobyte, hibyte, /*carry*/true); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, regX, lobyte, hibyte, /*carry*/false); A2_RUN_TESTp( func->func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff, /*carry*/true); // wrap to zpage A2_RUN_TESTp( func->func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff, /*carry*/false); // wrap to zpage } #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } // -------------------------------- A2_ADD_TEST(test_ADC_abs_y); A2_ADD_TEST(test_AND_abs_y); A2_ADD_TEST(test_CMP_abs_y); A2_ADD_TEST(test_EOR_abs_y); A2_ADD_TEST(test_LDA_abs_y); A2_ADD_TEST(test_LDX_abs_y); A2_ADD_TEST(test_ORA_abs_y); A2_ADD_TEST(test_SBC_abs_y); A2_ADD_TEST(test_STA_abs_y); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... uint8_t hibyte = 0x1f; uint8_t lobyte = 0x20; for (uint8_t regY=0x50; regY>0x4f; regY+=0x30) { A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, regY, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, regY, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, regY, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, regY, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0x24, /*val*/0x42, 0x20, 0xfe, 0xff); // wrap to zpage } #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } // -------------------------------- A2_ADD_TEST(test_ADC_ind_x); A2_ADD_TEST(test_AND_ind_x); A2_ADD_TEST(test_CMP_ind_x); A2_ADD_TEST(test_EOR_ind_x); A2_ADD_TEST(test_LDA_ind_x); A2_ADD_TEST(test_ORA_ind_x); A2_ADD_TEST(test_SBC_ind_x); A2_ADD_TEST(test_STA_ind_x); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... uint8_t hibyte = 0x1f; for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { for (uint8_t regX=0x42; regX>0x3F; regX+=0x40) { A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x24, regX, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x24, regX, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, /*arg0*/0x24, regX, lobyte, hibyte); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, /*arg0*/0x24, regX, lobyte, hibyte); } } #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } // -------------------------------- A2_ADD_TEST(test_ADC_ind_y); A2_ADD_TEST(test_AND_ind_y); A2_ADD_TEST(test_CMP_ind_y); A2_ADD_TEST(test_EOR_ind_y); A2_ADD_TEST(test_LDA_ind_y); A2_ADD_TEST(test_ORA_ind_y); A2_ADD_TEST(test_SBC_ind_y); A2_ADD_TEST(test_STA_ind_y); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x24, /*regY*/0x10, /*val_zp0*/0x22, /*val_zp1*/0x1f); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x24, /*regY*/0x80, /*val_zp0*/0x80, /*val_zp1*/0x1f); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, /*arg0*/0x24, /*regY*/0xAA, /*val_zp0*/0xAA, /*val_zp1*/0x1f); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, /*arg0*/0x24, /*regY*/0x80, /*val_zp0*/0x90, /*val_zp1*/0xff); #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } // -------------------------------- A2_ADD_TEST(test_ADC_ind_zpage); A2_ADD_TEST(test_AND_ind_zpage); A2_ADD_TEST(test_CMP_ind_zpage); A2_ADD_TEST(test_EOR_ind_zpage); A2_ADD_TEST(test_LDA_ind_zpage); A2_ADD_TEST(test_ORA_ind_zpage); A2_ADD_TEST(test_SBC_ind_zpage); A2_ADD_TEST(test_STA_ind_zpage); HASH_ITER(hh, test_funcs, func, tmp) { fprintf(GREATEST_STDOUT, "\n%s :\n", func->name); // test addressing is working ... for (uint8_t lobyte=0xfd; lobyte>0xf0; lobyte++) { uint8_t hibyte = 0x1f; A2_RUN_TESTp( func->func, /*A*/0x0f, /*val*/0x0f, /*arg0*/0x00, /*lobyte*/0x33, /*hibyte*/0x1f); A2_RUN_TESTp( func->func, /*A*/0x7f, /*val*/0x7f, /*arg0*/0x7f, /*lobyte*/0x33, /*hibyte*/0x1f); A2_RUN_TESTp( func->func, /*A*/0xaa, /*val*/0x55, /*arg0*/0xAB, /*lobyte*/0x33, /*hibyte*/0x1f); A2_RUN_TESTp( func->func, /*A*/0x00, /*val*/0xff, /*arg0*/0xff, /*lobyte*/0x33, /*hibyte*/0x1f); } #ifdef ANDROID fprintf(GREATEST_STDOUT, "...OK\n"); #endif A2_REMOVE_TEST(func); } } SUITE(test_suite_cpu); GREATEST_MAIN_DEFS(); int test_cpu(int argc, char **argv) { GREATEST_MAIN_BEGIN(); RUN_SUITE(test_suite_cpu); GREATEST_MAIN_END(); } #if !defined(__APPLE__) && !defined(ANDROID) int main(int argc, char **argv) { test_cpu(argc, argv); } #endif