From 1d8f0e05641346b04288f7f1544be6a221a3a373 Mon Sep 17 00:00:00 2001 From: Brad Grantham Date: Mon, 21 Dec 2020 14:59:37 -0800 Subject: [PATCH] Fix some instructions, add missing ones Get cpu6502 to pass functional tests from https://github.com/Klaus2m5/6502_65C02_functional_tests Set bit 5 on status register pushed during IRQ, NMI, BRK. Fix return address pushed for BRK Fix flag setting for ROR Fix flags pushed with PHP Fix return address for RTI Add 0xD5 - DEC zpg, X Add 0xE1 - SBC (ind, X) Add 0x61 - ADC (ind, X) Add 0x1E - ASL abs, x Add 0x21 - AND (ind, X) Add 0x96 - STX zpg, Y add 0x75 - ADC zpg, X --- cpu6502.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 10 deletions(-) diff --git a/cpu6502.h b/cpu6502.h index 2f2e55e..ce0ea3a 100644 --- a/cpu6502.h +++ b/cpu6502.h @@ -11,7 +11,7 @@ BUS template parameter must provide methods: uint8_t read(uint16_t addr); - void read(uint16_t addr, uint8_t data); + void write(uint16_t addr, uint8_t data); */ /* @@ -38,6 +38,7 @@ struct CPU6502 static constexpr uint8_t N = 0x80; static constexpr uint8_t V = 0x40; + static constexpr uint8_t B2 = 0x20; static constexpr uint8_t B = 0x10; static constexpr uint8_t D = 0x08; static constexpr uint8_t I = 0x04; @@ -165,7 +166,7 @@ struct CPU6502 { stack_push((pc - 1) >> 8); stack_push((pc - 1) & 0xFF); - stack_push(p); + stack_push(p | B2); uint8_t low = bus.read(0xFFFE); uint8_t high = bus.read(0xFFFF); pc = low + high * 256; @@ -176,7 +177,7 @@ struct CPU6502 { stack_push((pc - 1) >> 8); stack_push((pc - 1) & 0xFF); - stack_push(p); + stack_push(p | B2); uint8_t low = bus.read(0xFFFA); uint8_t high = bus.read(0xFFFB); pc = low + high * 256; @@ -200,9 +201,10 @@ struct CPU6502 switch(inst) { case 0x00: { // BRK - stack_push((pc - 1) >> 8); - stack_push((pc - 1) & 0xFF); - stack_push(p | B); // | B says the Synertek 6502 reference + stack_push((pc + 1) >> 8); + stack_push((pc + 1) & 0xFF); + stack_push(p | B2 | B); // | B says the Synertek 6502 reference + p |= I; uint8_t low = bus.read(0xFFFE); uint8_t high = bus.read(0xFFFF); pc = low + high * 256; @@ -286,6 +288,13 @@ struct CPU6502 break; } + case 0xD6: { // DEC zpg, X + uint8_t zpg = (read_pc_inc() + x) % 0xFF; + set_flags(N | Z, m = bus.read(zpg) - 1); + bus.write(zpg, m); + break; + } + case 0xDE: { // DEC abs, X uint8_t low = read_pc_inc(); uint8_t high = read_pc_inc(); @@ -576,6 +585,29 @@ struct CPU6502 break; } + case 0xE1: { // SBC ind, X + uint8_t zpg = (read_pc_inc() + x) & 0xFF; + uint8_t low = bus.read(zpg); + uint8_t high = bus.read((zpg + 1) & 0xFF); + uint16_t addr = low + high * 256; + if((addr - y) / 256 != addr / 256) + clk.add_cpu_cycles(1); + m = bus.read(addr); + uint8_t borrow = isset(C) ? 0 : 1; + if(isset(D)) { + uint8_t bcd = a / 16 * 10 + a % 16; + flag_change(C, !(bcd < m + borrow)); + flag_change(V, sbc_overflow_d(bcd, m, borrow)); + set_flags(N | Z, bcd = bcd - (m + borrow)); + a = bcd / 10 * 16 + bcd % 10; + } else { + flag_change(C, !(a < (m + borrow))); + flag_change(V, sbc_overflow(a, m, borrow)); + set_flags(N | Z, a = a - (m + borrow)); + } + break; + } + case 0xF1: { // SBC ind, Y uint8_t zpg = read_pc_inc(); uint8_t low = bus.read(zpg); @@ -703,6 +735,29 @@ struct CPU6502 break; } + case 0x61: { // ADC (ind, X) + uint8_t zpg = (read_pc_inc() + x) & 0xFF; + uint8_t low = bus.read(zpg); + uint8_t high = bus.read((zpg + 1) & 0xFF); + uint16_t addr = low + high * 256; + if((addr - y) / 256 != addr / 256) + clk.add_cpu_cycles(1); + m = bus.read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + uint8_t bcd = a / 16 * 10 + a % 16; + flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); + flag_change(V, adc_overflow_d(bcd, m, carry)); + set_flags(N | Z, bcd = bcd + m + carry); + a = bcd / 10 * 16 + bcd % 10; + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + case 0x6D: { // ADC abs uint8_t low = read_pc_inc(); uint8_t high = read_pc_inc(); @@ -811,6 +866,15 @@ struct CPU6502 break; } + case 0x1E: { // ASL abs + uint16_t addr = read_pc_inc() + read_pc_inc() * 256; + m = bus.read(addr + x); + flag_change(C, m & 0x80); + set_flags(N | Z, m = m << 1); + bus.write(addr + x, m); + break; + } + case 0x06: { // ASL uint8_t zpg = read_pc_inc(); m = bus.read(zpg); @@ -970,6 +1034,17 @@ struct CPU6502 break; } + case 0x21: { // AND (ind, X) + uint8_t zpg = (read_pc_inc() + x) & 0xFF; + uint8_t low = bus.read(zpg); + uint8_t high = bus.read((zpg + 1) & 0xFF); + uint16_t addr = low + high * 256; + if((addr - y) / 256 != addr / 256) + clk.add_cpu_cycles(1); + set_flags(N | Z, a = a & bus.read(addr)); + break; + } + case 0x31: { // AND (ind), y uint8_t zpg = read_pc_inc(); uint8_t low = bus.read(zpg); @@ -1032,7 +1107,7 @@ struct CPU6502 uint16_t addr = low + high * 256; m = bus.read(addr + x); bool c = isset(C); - flag_change(C, m & 0x80); + flag_change(C, m & 0x01); set_flags(N | Z, m = (c ? 0x80 : 0x00) | (m >> 1)); bus.write(addr + x, m); break; @@ -1042,7 +1117,7 @@ struct CPU6502 uint8_t zpg = (read_pc_inc() + x) & 0xFF; m = bus.read(zpg); bool c = isset(C); - flag_change(C, m & 0x01); + flag_change(C, m & 0x80); set_flags(N | Z, m = (c ? 0x01 : 0x00) | (m << 1)); bus.write(zpg, m); break; @@ -1192,7 +1267,7 @@ struct CPU6502 } case 0x08: { // PHP - stack_push(p); + stack_push(p | B2 | B); break; } @@ -1475,7 +1550,7 @@ struct CPU6502 p = stack_pull(); uint8_t pcl = stack_pull(); uint8_t pch = stack_pull(); - pc = pcl + pch * 256 + 1; + pc = pcl + pch * 256; break; } @@ -1512,6 +1587,13 @@ struct CPU6502 break; } + case 0x96: { // STX zpg, Y + uint8_t zpg = read_pc_inc(); + uint16_t addr = (zpg + y) & 0xFF; + bus.write(addr, x); + break; + } + case 0x84: { // STY uint8_t zpg = read_pc_inc(); bus.write(zpg, y); @@ -1605,6 +1687,25 @@ struct CPU6502 break; } + case 0x75: { // ADC zpg, X + uint8_t zpg = read_pc_inc(); + uint16_t addr = (zpg + x)& 0xFF; + m = bus.read(addr); + uint8_t carry = isset(C) ? 1 : 0; + if(isset(D)) { + uint8_t bcd = a / 16 * 10 + a % 16; + flag_change(C, ((uint16_t)bcd + (uint16_t)m + carry) > 99); + flag_change(V, adc_overflow_d(bcd, m, carry)); + set_flags(N | Z, bcd = bcd + m + carry); + a = bcd / 10 * 16 + bcd % 10; + } else { + flag_change(C, ((uint16_t)a + (uint16_t)m + carry) > 0xFF); + flag_change(V, adc_overflow(a, m, carry)); + set_flags(N | Z, a = a + m + carry); + } + break; + } + case 0x3A: { // DEC, 65C02 set_flags(N | Z, a = a - 1); break;