From 268a7f2a0e1562f57d27f5068a377c788c17fdb1 Mon Sep 17 00:00:00 2001 From: scawful Date: Thu, 25 Apr 2024 00:22:38 -0400 Subject: [PATCH] Update Cpu --- src/app/emu/cpu/cpu.cc | 2515 ++++++++++++---------- src/app/emu/cpu/cpu.h | 139 +- src/app/emu/cpu/internal/addressing.cc | 217 +- src/app/emu/cpu/internal/instructions.cc | 1391 +++--------- 4 files changed, 1980 insertions(+), 2282 deletions(-) diff --git a/src/app/emu/cpu/cpu.cc b/src/app/emu/cpu/cpu.cc index 9d4c4b31..ccac0f7f 100644 --- a/src/app/emu/cpu/cpu.cc +++ b/src/app/emu/cpu/cpu.cc @@ -73,7 +73,7 @@ void Cpu::RunOpcode() { SetFlags(status); // updates x and m flags, clears // upper half of x and y if needed PB = 0; - PC = ReadWord(0xfffc); + PC = ReadWord(0xfffc, 0xfffd); return; } if (stopped_) { @@ -97,14 +97,14 @@ void Cpu::RunOpcode() { ReadByte((PB << 16) | PC); DoInterrupt(); } else { - // uint8_t opcode = ReadOpcode(); - ExecuteInstruction(ReadByte((PB << 16) | PC)); + uint8_t opcode = ReadOpcode(); + ExecuteInstruction(opcode); } } void Cpu::DoInterrupt() { callbacks_.idle(false); - PushByte(status); + PushByte(PB); PushWord(PC); PushByte(status); SetInterruptFlag(true); @@ -113,1389 +113,1711 @@ void Cpu::DoInterrupt() { int_wanted_ = false; if (nmi_wanted_) { nmi_wanted_ = false; - PC = ReadWord(0xffea); + PC = ReadWord(0xffea, 0xffeb); } else { // irq - PC = ReadWord(0xffee); + PC = ReadWord(0xffee, 0xffef); } } void Cpu::ExecuteInstruction(uint8_t opcode) { uint8_t instruction_length = 0; + uint16_t cache_pc = PC; uint32_t operand = 0; bool immediate = false; bool accumulator_mode = GetAccumulatorSize(); switch (opcode) { - case 0x61: // ADC DP Indexed Indirect, X - { - operand = ReadByte(DirectPageIndexedIndirectX()); - ADC(operand); + case 0x00: { // brk imm(s) + uint32_t vector = (E) ? 0xfffe : 0xffe6; + ReadOpcode(); + if (!E) PushByte(PB); + PushWord(PC, false); + PushByte(status); + SetInterruptFlag(true); + SetDecimalFlag(false); + PB = 0; + PC = ReadWord(vector, vector + 1, true); break; } - case 0x63: // ADC Stack Relative - { - operand = ReadByte(StackRelative()); - ADC(operand); + case 0x01: { // ora idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + ORA(low, high); break; } - case 0x65: // ADC Direct Page - { - operand = ReadByte(DirectPage()); - ADC(operand); + case 0x02: { // cop imm(s) + uint32_t vector = (E) ? 0xfff4 : 0xffe4; + ReadOpcode(); + if (!E) PushByte(PB); + PushWord(PC, false); + PushByte(status); + SetInterruptFlag(true); + SetDecimalFlag(false); + PB = 0; + PC = ReadWord(vector, vector + 1, true); break; } - case 0x67: // ADC DP Indirect Long - { - operand = ReadWord(DirectPageIndirectLong()); - ADC(operand); + case 0x03: { // ora sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + ORA(low, high); break; } - case 0x69: // ADC Immediate - { - operand = Immediate(); - immediate = true; - ADC(operand); + case 0x04: { // tsb dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Tsb(low, high); break; } - case 0x6D: // ADC Absolute - { - operand = ReadWord(Absolute()); - ADC(operand); + case 0x05: { // ora dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + ORA(low, high); break; } - case 0x6F: // ADC Absolute Long - { - operand = ReadWord(AbsoluteLong()); - ADC(operand); + case 0x06: { // asl dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Asl(low, high); break; } - case 0x71: // ADC DP Indirect Indexed, Y - { - operand = ReadByteOrWord(DirectPageIndirectIndexedY()); - ADC(operand); + case 0x07: { // ora idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + ORA(low, high); break; } - case 0x72: // ADC DP Indirect - { - operand = ReadByte(DirectPageIndirect()); - ADC(operand); + case 0x08: { // php imp + callbacks_.idle(false); + CheckInt(); + PushByte(status); break; } - case 0x73: // ADC SR Indirect Indexed, Y - { - operand = ReadByte(StackRelativeIndirectIndexedY()); - ADC(operand); + case 0x09: { // ora imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + ORA(low, high); break; } - case 0x75: // ADC DP Indexed, X - { - operand = ReadByteOrWord(DirectPageIndexedX()); - ADC(operand); + case 0x0a: { // asla imp + AdrImp(); + if (GetAccumulatorSize()) { + SetCarryFlag(A & 0x80); + A = (A & 0xff00) | ((A << 1) & 0xff); + } else { + SetCarryFlag(A & 0x8000); + A <<= 1; + } + SetZN(A, GetAccumulatorSize()); break; } - case 0x77: // ADC DP Indirect Long Indexed, Y - { - operand = ReadByteOrWord(DirectPageIndirectLongIndexedY()); - ADC(operand); + case 0x0b: { // phd imp + callbacks_.idle(false); + PushWord(D, true); break; } - case 0x79: // ADC Absolute Indexed, Y - { - operand = ReadWord(AbsoluteIndexedY()); - ADC(operand); + case 0x0c: { // tsb abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Tsb(low, high); break; } - case 0x7D: // ADC Absolute Indexed, X - { - operand = ReadWord(AbsoluteIndexedX()); - ADC(operand); + case 0x0d: { // ora abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + ORA(low, high); break; } - case 0x7F: // ADC Absolute Long Indexed, X - { - operand = ReadByteOrWord(AbsoluteLongIndexedX()); - ADC(operand); + case 0x0e: { // asl abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Asl(low, high); break; } - - case 0x21: // AND DP Indexed Indirect, X - { - operand = ReadByteOrWord(DirectPageIndexedIndirectX()); - AND(operand, true); // Not immediate, but value has been retrieved + case 0x0f: { // ora abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + ORA(low, high); break; } - case 0x23: // AND Stack Relative - { - operand = StackRelative(); - AND(operand); - break; - } - case 0x25: // AND Direct Page - { - operand = DirectPage(); - AND(operand); - break; - } - case 0x27: // AND DP Indirect Long - { - operand = DirectPageIndirectLong(); - AND(operand); - break; - } - case 0x29: // AND Immediate - { - operand = Immediate(); - immediate = true; - AND(operand, true); - break; - } - case 0x2D: // AND Absolute - { - operand = Absolute(); - AND(operand); - break; - } - case 0x2F: // AND Absolute Long - { - operand = AbsoluteLong(); - ANDAbsoluteLong(operand); - break; - } - case 0x31: // AND DP Indirect Indexed, Y - { - operand = DirectPageIndirectIndexedY(); - AND(operand); - break; - } - case 0x32: // AND DP Indirect - { - operand = DirectPageIndirect(); - AND(operand); - break; - } - case 0x33: // AND SR Indirect Indexed, Y - { - operand = StackRelativeIndirectIndexedY(); - AND(operand); - break; - } - case 0x35: // AND DP Indexed, X - { - operand = DirectPageIndexedX(); - AND(operand); - break; - } - case 0x37: // AND DP Indirect Long Indexed, Y - { - operand = DirectPageIndirectLongIndexedY(); - AND(operand); - break; - } - case 0x39: // AND Absolute Indexed, Y - { - operand = AbsoluteIndexedY(); - AND(operand); - break; - } - case 0x3D: // AND Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - AND(operand); - break; - } - case 0x3F: // AND Absolute Long Indexed, X - { - operand = AbsoluteLongIndexedX(); - AND(operand); - break; - } - - case 0x06: // ASL Direct Page - { - operand = DirectPage(); - ASL(operand); - break; - } - case 0x0A: // ASL Accumulator - { - A <<= 1; - A &= 0xFE; - SetCarryFlag(A & 0x80); - SetNegativeFlag(A); - SetZeroFlag(!A); - break; - } - case 0x0E: // ASL Absolute - { - operand = Absolute(); - ASL(operand); - break; - } - case 0x16: // ASL DP Indexed, X - { - operand = ReadByteOrWord((0x00 << 16) + DirectPageIndexedX()); - ASL(operand); - break; - } - case 0x1E: // ASL Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - ASL(operand); - break; - } - - case 0x90: // BCC Branch if carry clear - { - operand = FetchByte(); - DoBranch(!GetCarryFlag()); - break; - } - - case 0xB0: // BCS Branch if carry set - { - operand = FetchByte(); - DoBranch(GetCarryFlag()); - break; - } - - case 0xF0: // BEQ Branch if equal (zero set) - { - operand = FetchByte(); - DoBranch(GetZeroFlag()); - break; - } - - case 0x24: // BIT Direct Page - { - operand = DirectPage(); - BIT(operand); - break; - } - case 0x2C: // BIT Absolute - { - operand = Absolute(); - BIT(operand); - break; - } - case 0x34: // BIT DP Indexed, X - { - operand = DirectPageIndexedX(); - BIT(operand); - break; - } - case 0x3C: // BIT Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - BIT(operand); - break; - } - case 0x89: // BIT Immediate - { - operand = Immediate(); - BIT(operand); - immediate = true; - break; - } - - case 0x30: // BMI Branch if minus (negative set) - { - DoBranch(GetNegativeFlag()); - break; - } - - case 0xD0: // BNE Branch if not equal (zero clear) - { - DoBranch(!GetZeroFlag()); - break; - } - - case 0x10: // BPL Branch if plus (negative clear) - { - operand = FetchByte(); + case 0x10: { // bpl rel DoBranch(!GetNegativeFlag()); break; } - - case 0x80: // BRA Branch always - { - operand = FetchByte(); - DoBranch(true); + case 0x11: { // ora idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + ORA(low, high); break; } - - case 0x00: // BRK Break - { - BRK(); + case 0x12: { // ora idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + ORA(low, high); break; } - - case 0x82: // BRL Branch always long - { - operand = FetchWord(); - BRL(operand); + case 0x13: { // ora isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + ORA(low, high); break; } - - case 0x50: // BVC Branch if overflow clear - { - operand = FetchByte(); + case 0x14: { // trb dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Trb(low, high); + break; + } + case 0x15: { // ora dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + ORA(low, high); + break; + } + case 0x16: { // asl dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Asl(low, high); + break; + } + case 0x17: { // ora ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + ORA(low, high); + break; + } + case 0x18: { // clc imp + AdrImp(); + SetCarryFlag(false); + break; + } + case 0x19: { // ora aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + ORA(low, high); + break; + } + case 0x1a: { // inca imp + AdrImp(); + if (GetAccumulatorSize()) { + A = (A & 0xff00) | ((A + 1) & 0xff); + } else { + A++; + } + SetZN(A, GetAccumulatorSize()); + break; + } + case 0x1b: { // tcs imp + AdrImp(); + SetSP(A); + break; + } + case 0x1c: { // trb abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Trb(low, high); + break; + } + case 0x1d: { // ora abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + ORA(low, high); + break; + } + case 0x1e: { // asl abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Asl(low, high); + break; + } + case 0x1f: { // ora alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + ORA(low, high); + break; + } + case 0x20: { // jsr abs + uint16_t value = ReadOpcodeWord(false); + callbacks_.idle(false); + PushWord(PC - 1, true); + PC = value; + break; + } + case 0x21: { // and idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + And(low, high); + break; + } + case 0x22: { // jsl abl + uint16_t value = ReadOpcodeWord(false); + PushByte(PB); + callbacks_.idle(false); + uint8_t newK = ReadOpcode(); + PushWord(PC - 1, true); + PC = value; + PB = newK; + break; + } + case 0x23: { // and sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + And(low, high); + break; + } + case 0x24: { // bit dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Bit(low, high); + break; + } + case 0x25: { // and dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + And(low, high); + break; + } + case 0x26: { // rol dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Rol(low, high); + break; + } + case 0x27: { // and idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + And(low, high); + break; + } + case 0x28: { // plp imp + callbacks_.idle(false); + callbacks_.idle(false); + CheckInt(); + SetFlags(PopByte()); + break; + } + case 0x29: { // and imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + And(low, high); + break; + } + case 0x2a: { // rola imp + AdrImp(); + int result = (A << 1) | GetCarryFlag(); + if (GetAccumulatorSize()) { + SetCarryFlag(result & 0x100); + A = (A & 0xff00) | (result & 0xff); + } else { + SetCarryFlag(result & 0x10000); + A = result; + } + SetZN(A, GetAccumulatorSize()); + break; + } + case 0x2b: { // pld imp + callbacks_.idle(false); + callbacks_.idle(false); + D = PopWord(true); + SetZN(D, false); + break; + } + case 0x2c: { // bit abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Bit(low, high); + break; + } + case 0x2d: { // and abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + And(low, high); + break; + } + case 0x2e: { // rol abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Rol(low, high); + break; + } + case 0x2f: { // and abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + And(low, high); + break; + } + case 0x30: { // bmi rel + DoBranch(GetNegativeFlag()); + break; + } + case 0x31: { // and idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + And(low, high); + break; + } + case 0x32: { // and idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + And(low, high); + break; + } + case 0x33: { // and isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + And(low, high); + break; + } + case 0x34: { // bit dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Bit(low, high); + break; + } + case 0x35: { // and dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + And(low, high); + break; + } + case 0x36: { // rol dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Rol(low, high); + break; + } + case 0x37: { // and ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + And(low, high); + break; + } + case 0x38: { // sec imp + AdrImp(); + SetCarryFlag(true); + break; + } + case 0x39: { // and aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + And(low, high); + break; + } + case 0x3a: { // deca imp + AdrImp(); + if (GetAccumulatorSize()) { + A = (A & 0xff00) | ((A - 1) & 0xff); + } else { + A--; + } + SetZN(A, GetAccumulatorSize()); + break; + } + case 0x3b: { // tsc imp + AdrImp(); + A = SP(); + SetZN(A, false); + break; + } + case 0x3c: { // bit abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Bit(low, high); + break; + } + case 0x3d: { // and abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + And(low, high); + break; + } + case 0x3e: { // rol abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Rol(low, high); + break; + } + case 0x3f: { // and alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + And(low, high); + break; + } + case 0x40: { // rti imp + callbacks_.idle(false); + callbacks_.idle(false); + SetFlags(PopByte()); + PC = PopWord(false); + CheckInt(); + PB = PopByte(); + break; + } + case 0x41: { // eor idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + Eor(low, high); + break; + } + case 0x42: { // wdm imm(s) + CheckInt(); + ReadOpcode(); + break; + } + case 0x43: { // eor sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + Eor(low, high); + break; + } + case 0x44: { // mvp bm + uint8_t dest = ReadOpcode(); + uint8_t src = ReadOpcode(); + DB = dest; + WriteByte((dest << 16) | Y, ReadByte((src << 16) | X)); + A--; + X--; + Y--; + if (A != 0xffff) { + PC -= 3; + } + if (GetIndexSize()) { + X &= 0xff; + Y &= 0xff; + } + callbacks_.idle(false); + CheckInt(); + callbacks_.idle(false); + break; + } + case 0x45: { // eor dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Eor(low, high); + break; + } + case 0x46: { // lsr dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Lsr(low, high); + break; + } + case 0x47: { // eor idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + Eor(low, high); + break; + } + case 0x48: { // pha imp + callbacks_.idle(false); + if (GetAccumulatorSize()) { + CheckInt(); + PushByte(A); + } else { + PushWord(A, true); + } + break; + } + case 0x49: { // eor imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + Eor(low, high); + break; + } + case 0x4a: { // lsra imp + AdrImp(); + SetCarryFlag(A & 1); + if (GetAccumulatorSize()) { + A = (A & 0xff00) | ((A >> 1) & 0x7f); + } else { + A >>= 1; + } + SetZN(A, GetAccumulatorSize()); + break; + } + case 0x4b: { // phk imp + callbacks_.idle(false); + CheckInt(); + PushByte(PB); + break; + } + case 0x4c: { // jmp abs + PC = ReadOpcodeWord(true); + break; + } + case 0x4d: { // eor abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Eor(low, high); + break; + } + case 0x4e: { // lsr abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Lsr(low, high); + break; + } + case 0x4f: { // eor abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + Eor(low, high); + break; + } + case 0x50: { // bvc rel DoBranch(!GetOverflowFlag()); break; } - - case 0x70: // BVS Branch if overflow set - { - operand = FetchByte(); + case 0x51: { // eor idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + Eor(low, high); + break; + } + case 0x52: { // eor idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + Eor(low, high); + break; + } + case 0x53: { // eor isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + Eor(low, high); + break; + } + case 0x54: { // mvn bm + uint8_t dest = ReadOpcode(); + uint8_t src = ReadOpcode(); + DB = dest; + WriteByte((dest << 16) | Y, ReadByte((src << 16) | X)); + A--; + X++; + Y++; + if (A != 0xffff) { + PC -= 3; + } + if (GetIndexSize()) { + X &= 0xff; + Y &= 0xff; + } + callbacks_.idle(false); + CheckInt(); + callbacks_.idle(false); + break; + } + case 0x55: { // eor dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Eor(low, high); + break; + } + case 0x56: { // lsr dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Lsr(low, high); + break; + } + case 0x57: { // eor ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + Eor(low, high); + break; + } + case 0x58: { // cli imp + AdrImp(); + SetInterruptFlag(false); + break; + } + case 0x59: { // eor aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + Eor(low, high); + break; + } + case 0x5a: { // phy imp + callbacks_.idle(false); + if (GetIndexSize()) { + CheckInt(); + PushByte(Y); + } else { + PushWord(Y, true); + } + break; + } + case 0x5b: { // tcd imp + AdrImp(); + D = A; + SetZN(D, false); + break; + } + case 0x5c: { // jml abl + uint16_t value = ReadOpcodeWord(false); + CheckInt(); + PB = ReadOpcode(); + PC = value; + break; + } + case 0x5d: { // eor abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Eor(low, high); + break; + } + case 0x5e: { // lsr abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Lsr(low, high); + break; + } + case 0x5f: { // eor alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + Eor(low, high); + break; + } + case 0x60: { // rts imp + callbacks_.idle(false); + callbacks_.idle(false); + PC = PopWord(false) + 1; + CheckInt(); + callbacks_.idle(false); + break; + } + case 0x61: { // adc idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + Adc(low, high); + break; + } + case 0x62: { // per rll + uint16_t value = ReadOpcodeWord(false); + callbacks_.idle(false); + PushWord(PC + (int16_t)value, true); + break; + } + case 0x63: { // adc sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + Adc(low, high); + break; + } + case 0x64: { // stz dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Stz(low, high); + break; + } + case 0x65: { // adc dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Adc(low, high); + break; + } + case 0x66: { // ror dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Ror(low, high); + break; + } + case 0x67: { // adc idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + Adc(low, high); + break; + } + case 0x68: { // pla imp + callbacks_.idle(false); + callbacks_.idle(false); + if (GetAccumulatorSize()) { + CheckInt(); + A = (A & 0xff00) | PopByte(); + } else { + A = PopWord(true); + } + SetZN(A, GetAccumulatorSize()); + break; + } + case 0x69: { // adc imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + Adc(low, high); + break; + } + case 0x6a: { // rora imp + AdrImp(); + bool carry = A & 1; + auto C = GetCarryFlag(); + if (GetAccumulatorSize()) { + A = (A & 0xff00) | ((A >> 1) & 0x7f) | (C << 7); + } else { + A = (A >> 1) | (C << 15); + } + SetCarryFlag(carry); + SetZN(A, GetAccumulatorSize()); + break; + } + case 0x6b: { // rtl imp + callbacks_.idle(false); + callbacks_.idle(false); + PC = PopWord(false) + 1; + CheckInt(); + PB = PopByte(); + break; + } + case 0x6c: { // jmp ind + uint16_t adr = ReadOpcodeWord(false); + PC = ReadWord(adr, (adr + 1) & 0xffff, true); + break; + } + case 0x6d: { // adc abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Adc(low, high); + break; + } + case 0x6e: { // ror abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Ror(low, high); + break; + } + case 0x6f: { // adc abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + Adc(low, high); + break; + } + case 0x70: { // bvs rel DoBranch(GetOverflowFlag()); break; } - - case 0x18: // CLC Clear carry - { - CLC(); + case 0x71: { // adc idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + Adc(low, high); break; } - - case 0xD8: // CLD Clear decimal - { - CLD(); + case 0x72: { // adc idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + Adc(low, high); break; } - - case 0x58: // CLI Clear interrupt disable - { - CLI(); + case 0x73: { // adc isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + Adc(low, high); break; } - - case 0xB8: // CLV Clear overflow - { - CLV(); + case 0x74: { // stz dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Stz(low, high); break; } - - case 0xC1: // CMP DP Indexed Indirect, X - { - operand = ReadByteOrWord(DirectPageIndexedIndirectX()); - CMP(operand); + case 0x75: { // adc dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Adc(low, high); break; } - case 0xC3: // CMP Stack Relative - { - operand = StackRelative(); - CMP(operand); + case 0x76: { // ror dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Ror(low, high); break; } - case 0xC5: // CMP Direct Page - { - operand = DirectPage(); - CMP(operand); + case 0x77: { // adc ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + Adc(low, high); break; } - case 0xC7: // CMP DP Indirect Long - { - operand = DirectPageIndirectLong(); - CMP(operand); + case 0x78: { // sei imp + AdrImp(); + SetInterruptFlag(true); break; } - case 0xC9: // CMP Immediate - { - operand = Immediate(); - immediate = true; - CMP(operand, immediate); + case 0x79: { // adc aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + Adc(low, high); break; } - case 0xCD: // CMP Absolute - { - operand = Absolute(AccessType::Data); - CMP(operand); + case 0x7a: { // ply imp + callbacks_.idle(false); + callbacks_.idle(false); + if (GetIndexSize()) { + CheckInt(); + Y = PopByte(); + } else { + Y = PopWord(true); + } + SetZN(Y, GetIndexSize()); break; } - case 0xCF: // CMP Absolute Long - { - operand = AbsoluteLong(); - CMP(operand); + case 0x7b: { // tdc imp + AdrImp(); + A = D; + SetZN(A, false); break; } - case 0xD1: // CMP DP Indirect Indexed, Y - { - operand = DirectPageIndirectIndexedY(); - CMP(operand); + case 0x7c: { // jmp iax + uint16_t adr = ReadOpcodeWord(false); + callbacks_.idle(false); + PC = ReadWord((PB << 16) | ((adr + X) & 0xffff), + ((PB << 16) | ((adr + X + 1) & 0xffff)), true); break; } - case 0xD2: // CMP DP Indirect - { - operand = DirectPageIndirect(); - CMP(operand); + case 0x7d: { // adc abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Adc(low, high); break; } - case 0xD3: // CMP SR Indirect Indexed, Y - { - operand = StackRelativeIndirectIndexedY(); - CMP(operand); + case 0x7e: { // ror abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Ror(low, high); break; } - case 0xD5: // CMP DP Indexed, X - { - operand = DirectPageIndexedX(); - CMP(operand); + case 0x7f: { // adc alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + Adc(low, high); break; } - case 0xD7: // CMP DP Indirect Long Indexed, Y - { - operand = DirectPageIndirectLongIndexedY(); - CMP(operand); + case 0x80: { // bra rel + DoBranch(true); break; } - case 0xD9: // CMP Absolute Indexed, Y - { - operand = AbsoluteIndexedY(); - CMP(operand); + case 0x81: { // sta idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + Sta(low, high); break; } - case 0xDD: // CMP Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - CMP(operand); + case 0x82: { // brl rll + PC += (int16_t)ReadOpcodeWord(false); + CheckInt(); + callbacks_.idle(false); break; } - case 0xDF: // CMP Absolute Long Indexed, X - { - operand = AbsoluteLongIndexedX(); - CMP(operand); + case 0x83: { // sta sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + Sta(low, high); break; } - - case 0x02: // COP - { - COP(); + case 0x84: { // sty dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Sty(low, high); break; } - - case 0xE0: // CPX Immediate - { - operand = Immediate(/*index_size=*/true); - immediate = true; - CPX(operand, immediate); + case 0x85: { // sta dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Sta(low, high); break; } - case 0xE4: // CPX Direct Page - { - operand = DirectPage(); - CPX(operand); + case 0x86: { // stx dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Stx(low, high); break; } - case 0xEC: // CPX Absolute - { - operand = Absolute(); - CPX(operand); + case 0x87: { // sta idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + Sta(low, high); break; } - - case 0xC0: // CPY Immediate - { - operand = Immediate(); - immediate = true; - CPY(operand, immediate); + case 0x88: { // dey imp + AdrImp(); + if (GetIndexSize()) { + Y = (Y - 1) & 0xff; + } else { + Y--; + } + SetZN(Y, GetIndexSize()); break; } - case 0xC4: // CPY Direct Page - { - operand = DirectPage(); - CPY(operand); + case 0x89: { // biti imm(m) + if (GetAccumulatorSize()) { + CheckInt(); + uint8_t result = (A & 0xff) & ReadOpcode(); + SetZeroFlag(result == 0); + } else { + uint16_t result = A & ReadOpcodeWord(true); + SetZeroFlag(result == 0); + } break; } - case 0xCC: // CPY Absolute - { - operand = Absolute(); - CPY(operand); + case 0x8a: { // txa imp + AdrImp(); + if (GetAccumulatorSize()) { + A = (A & 0xff00) | (X & 0xff); + } else { + A = X; + } + SetZN(A, GetAccumulatorSize()); break; } - - case 0x3A: // DEC Accumulator - { - DEC(A, /*accumulator=*/true); + case 0x8b: { // phb imp + callbacks_.idle(false); + CheckInt(); + PushByte(DB); break; } - case 0xC6: // DEC Direct Page - { - operand = DirectPage(); - DEC(operand); + case 0x8c: { // sty abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Sty(low, high); break; } - case 0xCE: // DEC Absolute - { - operand = Absolute(); - DEC(operand); + case 0x8d: { // sta abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Sta(low, high); break; } - case 0xD6: // DEC DP Indexed, X - { - operand = DirectPageIndexedX(); - DEC(operand); + case 0x8e: { // stx abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Stx(low, high); break; } - case 0xDE: // DEC Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - DEC(operand); + case 0x8f: { // sta abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + Sta(low, high); break; } - - case 0xCA: // DEX - { - DEX(); + case 0x90: { // bcc rel + DoBranch(!GetCarryFlag()); break; } - - case 0x88: // DEY - { - DEY(); + case 0x91: { // sta idy + uint32_t low = 0; + uint32_t high = AdrIdy(&low, true); + Sta(low, high); break; } - - case 0x41: // EOR DP Indexed Indirect, X - { - operand = DirectPageIndexedIndirectX(); - EOR(operand); + case 0x92: { // sta idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + Sta(low, high); break; } - case 0x43: // EOR Stack Relative - { - operand = StackRelative(); - EOR(operand); + case 0x93: { // sta isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + Sta(low, high); break; } - case 0x45: // EOR Direct Page - { - operand = DirectPage(); - EOR(operand); + case 0x94: { // sty dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Sty(low, high); break; } - case 0x47: // EOR DP Indirect Long - { - operand = DirectPageIndirectLong(); - EOR(operand); + case 0x95: { // sta dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Sta(low, high); break; } - case 0x49: // EOR Immediate - { - operand = Immediate(); - immediate = true; - EOR(operand, immediate); + case 0x96: { // stx dpy + uint32_t low = 0; + uint32_t high = AdrDpy(&low); + Stx(low, high); break; } - case 0x4D: // EOR Absolute - { - operand = Absolute(); - EOR(operand); + case 0x97: { // sta ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + Sta(low, high); break; } - case 0x4F: // EOR Absolute Long - { - operand = AbsoluteLong(); - EOR(operand); + case 0x98: { // tya imp + AdrImp(); + if (GetAccumulatorSize()) { + A = (A & 0xff00) | (Y & 0xff); + } else { + A = Y; + } + SetZN(A, GetAccumulatorSize()); break; } - case 0x51: // EOR DP Indirect Indexed, Y - { - operand = DirectPageIndirectIndexedY(); - EOR(operand); + case 0x99: { // sta aby + uint32_t low = 0; + uint32_t high = AdrAby(&low, true); + Sta(low, high); break; } - case 0x52: // EOR DP Indirect - { - operand = DirectPageIndirect(); - EOR(operand); + case 0x9a: { // txs imp + AdrImp(); + SetSP(X); break; } - case 0x53: // EOR SR Indirect Indexed, Y - { - operand = StackRelativeIndirectIndexedY(); - EOR(operand); + case 0x9b: { // txy imp + AdrImp(); + if (GetIndexSize()) { + Y = X & 0xff; + } else { + Y = X; + } + SetZN(Y, GetIndexSize()); break; } - case 0x55: // EOR DP Indexed, X - { - operand = DirectPageIndexedX(); - EOR(operand); + case 0x9c: { // stz abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Stz(low, high); break; } - case 0x57: // EOR DP Indirect Long Indexed, Y - { - operand = ReadByteOrWord(DirectPageIndirectLongIndexedY()); - EOR(operand); + case 0x9d: { // sta abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Sta(low, high); break; } - case 0x59: // EOR Absolute Indexed, Y - { - operand = AbsoluteIndexedY(); - EOR(operand); + case 0x9e: { // stz abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Stz(low, high); break; } - case 0x5D: // EOR Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - EOR(operand); + case 0x9f: { // sta alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + Sta(low, high); break; } - case 0x5F: // EOR Absolute Long Indexed, X - { - operand = AbsoluteLongIndexedX(); - EOR(operand); + case 0xa0: { // ldy imm(x) + uint32_t low = 0; + uint32_t high = Immediate(&low, true); + Ldy(low, high); break; } - - case 0x1A: // INC Accumulator - { - INC(A, /*accumulator=*/true); + case 0xa1: { // lda idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + Lda(low, high); break; } - case 0xE6: // INC Direct Page - { - operand = DirectPage(); - INC(operand); + case 0xa2: { // ldx imm(x) + uint32_t low = 0; + uint32_t high = Immediate(&low, true); + Ldx(low, high); break; } - case 0xEE: // INC Absolute - { - operand = Absolute(); - INC(operand); + case 0xa3: { // lda sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + Lda(low, high); break; } - case 0xF6: // INC DP Indexed, X - { - operand = DirectPageIndexedX(); - INC(operand); + case 0xa4: { // ldy dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Ldy(low, high); break; } - case 0xFE: // INC Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - INC(operand); + case 0xa5: { // lda dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Lda(low, high); break; } - - case 0xE8: // INX - { - INX(); + case 0xa6: { // ldx dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Ldx(low, high); break; } - - case 0xC8: // INY - { - INY(); + case 0xa7: { // lda idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + Lda(low, high); break; } - - case 0x4C: // JMP Absolute - { - JMP(Absolute()); + case 0xa8: { // tay imp + AdrImp(); + if (GetIndexSize()) { + Y = A & 0xff; + } else { + Y = A; + } + SetZN(Y, GetIndexSize()); break; } - case 0x5C: // JMP Absolute Long - { - JML(FetchWord()); + case 0xa9: { // lda imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + Lda(low, high); break; } - case 0x6C: // JMP Absolute Indirect - { - JMP(AbsoluteIndirect()); + case 0xaa: { // tax imp + AdrImp(); + if (GetIndexSize()) { + X = A & 0xff; + } else { + X = A; + } + SetZN(X, GetIndexSize()); break; } - case 0x7C: // JMP Absolute Indexed Indirect - { - JMP(AbsoluteIndexedIndirect()); + case 0xab: { // plb imp + callbacks_.idle(false); + callbacks_.idle(false); + CheckInt(); + DB = PopByte(); + SetZN(DB, true); break; } - case 0xDC: // JMP Absolute Indirect Long - { - operand = AbsoluteIndirectLong(); - JMP(operand); - PB = operand >> 16; + case 0xac: { // ldy abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Ldy(low, high); break; } - - case 0x20: // JSR Absolute - { - operand = Absolute(AccessType::Control); - PB = (operand >> 16); - JSR(operand); + case 0xad: { // lda abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Lda(low, high); break; } - - case 0x22: // JSL Absolute Long - { - JSL(FetchWord()); + case 0xae: { // ldx abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Ldx(low, high); break; } - - case 0xFC: // JSR Absolute Indexed Indirect - { - JSR(AbsoluteIndexedIndirect()); + case 0xaf: { // lda abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + Lda(low, high); break; } - - case 0xA1: // LDA DP Indexed Indirect, X - { - operand = DirectPageIndexedIndirectX(); - LDA(operand); + case 0xb0: { // bcs rel + DoBranch(GetCarryFlag()); break; } - case 0xA3: // LDA Stack Relative - { - operand = StackRelative(); - LDA(operand); + case 0xb1: { // lda idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + Lda(low, high); break; } - case 0xA5: // LDA Direct Page - { - operand = DirectPage(); - LDA(operand, false, true); + case 0xb2: { // lda idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + Lda(low, high); break; } - case 0xA7: // LDA DP Indirect Long - { - operand = DirectPageIndirectLong(); - LDA(operand); + case 0xb3: { // lda isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + Lda(low, high); break; } - case 0xA9: // LDA Immediate - { - operand = Immediate(); - immediate = true; - LDA(operand, immediate); + case 0xb4: { // ldy dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Ldy(low, high); break; } - case 0xAD: // LDA Absolute - { - operand = Absolute(); - LDA(operand); + case 0xb5: { // lda dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Lda(low, high); break; } - case 0xAF: // LDA Absolute Long - { - operand = AbsoluteLong(); - LDA(operand); + case 0xb6: { // ldx dpy + uint32_t low = 0; + uint32_t high = AdrDpy(&low); + Ldx(low, high); break; } - case 0xB1: // LDA DP Indirect Indexed, Y - { - operand = DirectPageIndirectIndexedY(); - LDA(operand); + case 0xb7: { // lda ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + Lda(low, high); break; } - case 0xB2: // LDA DP Indirect - { - operand = DirectPageIndirect(); - LDA(operand); + case 0xb8: { // clv imp + AdrImp(); + SetOverflowFlag(false); break; } - case 0xB3: // LDA SR Indirect Indexed, Y - { - operand = StackRelativeIndirectIndexedY(); - LDA(operand); + case 0xb9: { // lda aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + Lda(low, high); break; } - case 0xB5: // LDA DP Indexed, X - { - operand = DirectPageIndexedX(); - LDA(operand); + case 0xba: { // tsx imp + AdrImp(); + if (GetIndexSize()) { + SetSP(X & 0xff); + } else { + SetSP(X); + } + SetZN(X, GetIndexSize()); break; } - case 0xB7: // LDA DP Indirect Long Indexed, Y - { - operand = DirectPageIndirectLongIndexedY(); - LDA(operand); + case 0xbb: { // tyx imp + AdrImp(); + if (GetIndexSize()) { + X = Y & 0xff; + } else { + X = Y; + } + SetZN(X, GetIndexSize()); break; } - case 0xB9: // LDA Absolute Indexed, Y - { - operand = AbsoluteIndexedY(); - LDA(operand); + case 0xbc: { // ldy abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Ldy(low, high); break; } - case 0xBD: // LDA Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - LDA(operand, false, false, true); + case 0xbd: { // lda abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Lda(low, high); break; } - case 0xBF: // LDA Absolute Long Indexed, X - { - operand = AbsoluteLongIndexedX(); - LDA(operand); + case 0xbe: { // ldx aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + Ldx(low, high); break; } - - case 0xA2: // LDX Immediate - { - operand = Immediate(); - immediate = true; - LDX(operand, immediate); + case 0xbf: { // lda alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + Lda(low, high); break; } - case 0xA6: // LDX Direct Page - { - operand = DirectPage(); - LDX(operand); + case 0xc0: { // cpy imm(x) + uint32_t low = 0; + uint32_t high = Immediate(&low, true); + Cpy(low, high); break; } - case 0xAE: // LDX Absolute - { - operand = Absolute(); - LDX(operand); + case 0xc1: { // cmp idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + Cmp(low, high); break; } - case 0xB6: // LDX DP Indexed, Y - { - operand = DirectPageIndexedY(); - LDX(operand); + case 0xc2: { // rep imm(s) + uint8_t val = ReadOpcode(); + CheckInt(); + SetFlags(status & ~val); + callbacks_.idle(false); break; } - case 0xBE: // LDX Absolute Indexed, Y - { - operand = AbsoluteIndexedY(); - LDX(operand); + case 0xc3: { // cmp sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + Cmp(low, high); break; } - - case 0xA0: // LDY Immediate - { - operand = Immediate(); - immediate = true; - LDY(operand, immediate); + case 0xc4: { // cpy dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Cpy(low, high); break; } - case 0xA4: // LDY Direct Page - { - operand = DirectPage(); - LDY(operand); + case 0xc5: { // cmp dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Cmp(low, high); break; } - case 0xAC: // LDY Absolute - { - operand = Absolute(); - LDY(operand); + case 0xc6: { // dec dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Dec(low, high); break; } - case 0xB4: // LDY DP Indexed, X - { - operand = DirectPageIndexedX(); - LDY(operand); + case 0xc7: { // cmp idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + Cmp(low, high); break; } - case 0xBC: // LDY Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - LDY(operand); + case 0xc8: { // iny imp + AdrImp(); + if (GetIndexSize()) { + Y = (Y + 1) & 0xff; + } else { + Y++; + } + SetZN(Y, GetIndexSize()); break; } - - case 0x46: // LSR Direct Page - { - operand = DirectPage(); - LSR(operand); + case 0xc9: { // cmp imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + Cmp(low, high); break; } - case 0x4A: // LSR Accumulator - { - LSR(A, /*accumulator=*/true); + case 0xca: { // dex imp + AdrImp(); + if (GetIndexSize()) { + X = (X - 1) & 0xff; + } else { + X--; + } + SetZN(X, GetIndexSize()); break; } - case 0x4E: // LSR Absolute - { - operand = Absolute(); - LSR(operand); + case 0xcb: { // wai imp + waiting_ = true; + callbacks_.idle(false); + callbacks_.idle(false); break; } - case 0x56: // LSR DP Indexed, X - { - operand = DirectPageIndexedX(); - LSR(operand); + case 0xcc: { // cpy abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Cpy(low, high); break; } - case 0x5E: // LSR Absolute Indexed, X - { - operand = AbsoluteIndexedX(); - LSR(operand); + case 0xcd: { // cmp abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Cmp(low, high); break; } - - case 0x42: - WDM(); + case 0xce: { // dec abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Dec(low, high); break; - - case 0x44: - MVP(); + } + case 0xcf: { // cmp abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + Cmp(low, high); break; - - case 0x54: - MVN(); + } + case 0xd0: { // bne rel + DoBranch(!GetZeroFlag()); break; - - case 0xEA: // NOP - NOP(); + } + case 0xd1: { // cmp idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + Cmp(low, high); break; - - case 0x01: // ORA DP Indexed Indirect, X - operand = DirectPageIndexedIndirectX(); - ORA(operand); + } + case 0xd2: { // cmp idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + Cmp(low, high); break; - case 0x03: // ORA Stack Relative - operand = StackRelative(); - ORA(operand); + } + case 0xd3: { // cmp isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + Cmp(low, high); break; - case 0x05: // ORA Direct Page - operand = DirectPage(); - ORA(operand); + } + case 0xd4: { // pei dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + PushWord(ReadWord(low, high, false), true); break; - case 0x07: // ORA DP Indirect Long - operand = DirectPageIndirectLong(); - ORA(operand); + } + case 0xd5: { // cmp dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Cmp(low, high); break; - case 0x09: // ORA Immediate - operand = Immediate(); - immediate = true; - ORA(operand, immediate); + } + case 0xd6: { // dec dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Dec(low, high); break; - case 0x0D: // ORA Absolute - operand = Absolute(); - ORA(operand); + } + case 0xd7: { // cmp ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + Cmp(low, high); break; - case 0x0F: // ORA Absolute Long - operand = AbsoluteLong(); - ORA(operand); + } + case 0xd8: { // cld imp + AdrImp(); + SetDecimalFlag(false); break; - case 0x11: // ORA DP Indirect Indexed, Y - operand = DirectPageIndirectIndexedY(); - ORA(operand); + } + case 0xd9: { // cmp aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + Cmp(low, high); break; - case 0x12: // ORA DP Indirect - operand = DirectPageIndirect(); - ORA(operand); + } + case 0xda: { // phx imp + callbacks_.idle(false); + if (GetIndexSize()) { + CheckInt(); + PushByte(X); + } else { + PushWord(X, true); + } break; - case 0x13: // ORA SR Indirect Indexed, Y - operand = StackRelativeIndirectIndexedY(); - ORA(operand); + } + case 0xdb: { // stp imp + stopped_ = true; + callbacks_.idle(false); + callbacks_.idle(false); break; - case 0x15: // ORA DP Indexed, X - operand = DirectPageIndexedX(); - ORA(operand); + } + case 0xdc: { // jml ial + uint16_t adr = ReadOpcodeWord(false); + PC = ReadWord(adr, ((adr + 1) & 0xffff), false); + CheckInt(); + PB = ReadByte((adr + 2) & 0xffff); break; - case 0x17: // ORA DP Indirect Long Indexed, Y - operand = DirectPageIndirectLongIndexedY(); - ORA(operand); + } + case 0xdd: { // cmp abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Cmp(low, high); break; - case 0x19: // ORA Absolute Indexed, Y - operand = AbsoluteIndexedY(); - ORA(operand); + } + case 0xde: { // dec abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Dec(low, high); break; - case 0x1D: // ORA Absolute Indexed, X - operand = AbsoluteIndexedX(); - ORA(operand); + } + case 0xdf: { // cmp alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + Cmp(low, high); break; - case 0x1F: // ORA Absolute Long Indexed, X - operand = AbsoluteLongIndexedX(); - ORA(operand); + } + case 0xe0: { // cpx imm(x) + uint32_t low = 0; + uint32_t high = Immediate(&low, true); + Cpx(low, high); break; - - case 0xF4: // PEA Push Effective Absolute address - PEA(); + } + case 0xe1: { // sbc idx + uint32_t low = 0; + uint32_t high = AdrIdx(&low); + Sbc(low, high); break; - - case 0xD4: // PEI Push Effective Indirect address - PEI(); + } + case 0xe2: { // sep imm(s) + uint8_t val = ReadOpcode(); + CheckInt(); + SetFlags(status | val); + callbacks_.idle(false); break; - - case 0x62: // PER Push Effective PC Relative Indirect address - PER(); + } + case 0xe3: { // sbc sr + uint32_t low = 0; + uint32_t high = AdrSr(&low); + Sbc(low, high); break; - - case 0x48: // PHA Push Accumulator - PHA(); + } + case 0xe4: { // cpx dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Cpx(low, high); break; - - case 0x8B: // PHB Push Data Bank Register - PHB(); + } + case 0xe5: { // sbc dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Sbc(low, high); break; - - case 0x0B: // PHD Push Direct Page Register - PHD(); - break; - - case 0x4B: // PHK Push Program Bank Register - PHK(); - break; - - case 0x08: // PHP Push Processor Status Register - PHP(); - break; - - case 0xDA: // PHX Push X register - PHX(); - break; - - case 0x5A: // PHY Push Y register - PHY(); - break; - - case 0x68: // PLA Pull Accumulator - PLA(); - break; - - case 0xAB: // PLB Pull Data Bank Register - PLB(); - break; - - case 0x2B: // PLD Pull Direct Page Register - PLD(); - break; - - case 0x28: // PLP Pull Processor Status Register - PLP(); - break; - - case 0xFA: // PLX Pull X register - PLX(); + } + case 0xe6: { // inc dp + uint32_t low = 0; + uint32_t high = AdrDp(&low); + Inc(low, high); break; - - case 0x7A: // PLY Pull Y register - PLY(); + } + case 0xe7: { // sbc idl + uint32_t low = 0; + uint32_t high = AdrIdl(&low); + Sbc(low, high); break; - - case 0xC2: // REP Reset status bits - operand = FetchByte(); - immediate = true; - REP(); - break; - - case 0x26: // ROL Direct Page - operand = DirectPage(); - ROL(operand); - break; - case 0x2A: // ROL Accumulator - ROL(A, /*accumulator=*/true); - break; - case 0x2E: // ROL Absolute - operand = Absolute(); - ROL(operand); - break; - case 0x36: // ROL DP Indexed, X - operand = DirectPageIndexedX(); - ROL(operand); - break; - case 0x3E: // ROL Absolute Indexed, X - operand = AbsoluteIndexedX(); - ROL(operand); - break; - - case 0x66: // ROR Direct Page - operand = DirectPage(); - ROR(operand); - break; - case 0x6A: // ROR Accumulator - ROR(A, /*accumulator=*/true); - break; - case 0x6E: // ROR Absolute - operand = Absolute(); - ROR(operand); - break; - case 0x76: // ROR DP Indexed, X - operand = DirectPageIndexedX(); - ROR(operand); - break; - case 0x7E: // ROR Absolute Indexed, X - operand = AbsoluteIndexedX(); - ROR(operand); - break; - - case 0x40: // RTI Return from interrupt - RTI(); - break; - - case 0x6B: // RTL Return from subroutine long - RTL(); - break; - - case 0x60: // RTS Return from subroutine - RTS(); - break; - - case 0xE1: // SBC DP Indexed Indirect, X - operand = DirectPageIndexedIndirectX(); - SBC(operand); - break; - case 0xE3: // SBC Stack Relative - operand = StackRelative(); - SBC(operand); - break; - case 0xE5: // SBC Direct Page - operand = DirectPage(); - SBC(operand); - break; - case 0xE7: // SBC DP Indirect Long - operand = DirectPageIndirectLong(); - SBC(operand); - break; - case 0xE9: // SBC Immediate - operand = Immediate(); - immediate = true; - SBC(operand, immediate); - break; - case 0xED: // SBC Absolute - operand = Absolute(); - SBC(operand); - break; - case 0xEF: // SBC Absolute Long - operand = AbsoluteLong(); - SBC(operand); - break; - case 0xF1: // SBC DP Indirect Indexed, Y - operand = DirectPageIndirectIndexedY(); - SBC(operand); - break; - case 0xF2: // SBC DP Indirect - operand = DirectPageIndirect(); - SBC(operand); - break; - case 0xF3: // SBC SR Indirect Indexed, Y - operand = StackRelativeIndirectIndexedY(); - SBC(operand); - break; - case 0xF5: // SBC DP Indexed, X - operand = DirectPageIndexedX(); - SBC(operand); - break; - case 0xF7: // SBC DP Indirect Long Indexed, Y - operand = DirectPageIndirectLongIndexedY(); - SBC(operand); - break; - case 0xF9: // SBC Absolute Indexed, Y - operand = AbsoluteIndexedY(); - SBC(operand); - break; - case 0xFD: // SBC Absolute Indexed, X - operand = AbsoluteIndexedX(); - SBC(operand); - break; - case 0xFF: // SBC Absolute Long Indexed, X - operand = AbsoluteLongIndexedX(); - SBC(operand); - break; - - case 0x38: // SEC Set carry - SEC(); - break; - - case 0xF8: // SED Set decimal - SED(); - break; - - case 0x78: // SEI Set interrupt disable - SEI(); - break; - - case 0xE2: // SEP Set status bits - operand = FetchByte(); - immediate = true; - SEP(); - break; - - case 0x81: // STA DP Indexed Indirect, X - operand = DirectPageIndexedIndirectX(); - STA(operand); - break; - case 0x83: // STA Stack Relative - operand = StackRelative(); - STA(operand); - break; - case 0x85: // STA Direct Page - operand = DirectPage(); - STA(operand); - break; - case 0x87: // STA DP Indirect Long - operand = DirectPageIndirectLong(); - STA(operand); - break; - case 0x8D: // STA Absolute - operand = Absolute(AccessType::Data); - STA(operand); - break; - case 0x8F: // STA Absolute Long - operand = AbsoluteLong(); - STA(operand); - break; - case 0x91: // STA DP Indirect Indexed, Y - operand = DirectPageIndirectIndexedY(); - STA(operand); - break; - case 0x92: // STA DP Indirect - operand = DirectPageIndirect(); - STA(operand); - break; - case 0x93: // STA SR Indirect Indexed, Y - operand = StackRelativeIndirectIndexedY(); - STA(operand); - break; - case 0x95: // STA DP Indexed, X - operand = DirectPageIndexedX(); - STA(operand); - break; - case 0x97: // STA DP Indirect Long Indexed, Y - { - operand = DirectPageIndirectLongIndexedY(); - STA(operand); - break; - } - case 0x99: // STA Absolute Indexed, Y - operand = AbsoluteIndexedY(); - STA(operand); - break; - case 0x9D: // STA Absolute Indexed, X - operand = AbsoluteIndexedX(); - STA(operand); - break; - case 0x9F: // STA Absolute Long Indexed, X - operand = AbsoluteLongIndexedX(); - STA(operand); - break; - - case 0xDB: // STP Stop the processor - STP(); - break; - - case 0x86: // STX Direct Page - operand = DirectPage(); - STX(operand); - break; - case 0x8E: // STX Absolute - operand = Absolute(); - STX(operand); - break; - case 0x96: // STX DP Indexed, Y - operand = DirectPageIndexedY(); - STX(operand); - break; - - case 0x84: // STY Direct Page - operand = DirectPage(); - STY(operand); - break; - case 0x8C: // STY Absolute - operand = Absolute(); - STY(operand); - break; - case 0x94: // STY DP Indexed, X - operand = DirectPageIndexedX(); - STY(operand); - break; - - case 0x64: // STZ Direct Page - operand = DirectPage(); - STZ(operand); + } + case 0xe8: { // inx imp + AdrImp(); + if (GetIndexSize()) { + X = (X + 1) & 0xff; + } else { + X++; + } + SetZN(X, GetIndexSize()); break; - case 0x74: // STZ DP Indexed, X - operand = DirectPageIndexedX(); - STZ(operand); + } + case 0xe9: { // sbc imm(m) + uint32_t low = 0; + uint32_t high = Immediate(&low, false); + Sbc(low, high); break; - case 0x9C: // STZ Absolute - operand = Absolute(); - STZ(operand); + } + case 0xea: { // nop imp + AdrImp(); + // no operation break; - case 0x9E: // STZ Absolute Indexed, X - operand = AbsoluteIndexedX(); - STZ(operand); + } + case 0xeb: { // xba imp + uint8_t low = A & 0xff; + uint8_t high = A >> 8; + A = (low << 8) | high; + SetZN(high, true); + callbacks_.idle(false); + CheckInt(); + callbacks_.idle(false); break; - - case 0xAA: // TAX Transfer accumulator to X - TAX(); + } + case 0xec: { // cpx abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Cpx(low, high); break; - - case 0xA8: // TAY Transfer accumulator to Y - TAY(); + } + case 0xed: { // sbc abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Sbc(low, high); break; - - case 0x5B: // TCD - TCD(); + } + case 0xee: { // inc abs + uint32_t low = 0; + uint32_t high = Absolute(&low); + Inc(low, high); break; - - case 0x1B: // TCS - TCS(); + } + case 0xef: { // sbc abl + uint32_t low = 0; + uint32_t high = AdrAbl(&low); + Sbc(low, high); break; - - case 0x7B: // TDC - TDC(); + } + case 0xf0: { // beq rel + DoBranch(GetZeroFlag()); break; - - case 0x14: // TRB Direct Page - operand = DirectPage(); - TRB(operand); + } + case 0xf1: { // sbc idy(r) + uint32_t low = 0; + uint32_t high = AdrIdy(&low, false); + Sbc(low, high); break; - case 0x1C: // TRB Absolute - operand = Absolute(); - TRB(operand); + } + case 0xf2: { // sbc idp + uint32_t low = 0; + uint32_t high = AdrIdp(&low); + Sbc(low, high); break; - - case 0x04: // TSB Direct Page - operand = DirectPage(); - TSB(operand); + } + case 0xf3: { // sbc isy + uint32_t low = 0; + uint32_t high = AdrIsy(&low); + Sbc(low, high); break; - case 0x0C: // TSB Absolute - operand = Absolute(); - TSB(operand); + } + case 0xf4: { // pea imm(l) + PushWord(ReadOpcodeWord(false), true); break; - - case 0x3B: // TSC - TSC(); - break; - - case 0xBA: // TSX Transfer stack pointer to X - TSX(); - break; - - case 0x8A: // TXA Transfer X to accumulator - TXA(); - break; - - case 0x9A: // TXS Transfer X to stack pointer - TXS(); - break; - - case 0x9B: // TXY Transfer X to Y - TXY(); - break; - - case 0x98: // TYA Transfer Y to accumulator - TYA(); + } + case 0xf5: { // sbc dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Sbc(low, high); break; - - case 0xBB: // TYX Transfer Y to X - TYX(); + } + case 0xf6: { // inc dpx + uint32_t low = 0; + uint32_t high = AdrDpx(&low); + Inc(low, high); break; - - case 0xCB: // WAI Wait for interrupt - WAI(); + } + case 0xf7: { // sbc ily + uint32_t low = 0; + uint32_t high = AdrIly(&low); + Sbc(low, high); break; - - case 0xEB: // XBA Exchange B and A - XBA(); + } + case 0xf8: { // sed imp + AdrImp(); + SetDecimalFlag(true); break; - - case 0xFB: // XCE Exchange carry and emulation bits - XCE(); + } + case 0xf9: { // sbc aby(r) + uint32_t low = 0; + uint32_t high = AdrAby(&low, false); + Sbc(low, high); + break; + } + case 0xfa: { // plx imp + callbacks_.idle(false); + callbacks_.idle(false); + if (GetIndexSize()) { + CheckInt(); + X = PopByte(); + } else { + X = PopWord(true); + } + SetZN(X, GetIndexSize()); break; - default: - std::cerr << "Unknown instruction: " << std::hex - << static_cast(opcode) << std::endl; + } + case 0xfb: { // xce imp + AdrImp(); + bool temp = GetCarryFlag(); + SetCarryFlag(E); + E = temp; + SetFlags(status); // updates x and m flags, clears upper half of x and y + // if needed break; + } + case 0xfc: { // jsr iax + uint8_t adrl = ReadOpcode(); + PushWord(PC, false); + uint16_t adr = adrl | (ReadOpcode() << 8); + callbacks_.idle(false); + uint16_t value = ReadWord((PB << 16) | ((adr + X) & 0xffff), + (PB << 16) | ((adr + X + 1) & 0xffff), true); + PC = value; + break; + } + case 0xfd: { // sbc abx(r) + uint32_t low = 0; + uint32_t high = AdrAbx(&low, false); + Sbc(low, high); + break; + } + case 0xfe: { // inc abx + uint32_t low = 0; + uint32_t high = AdrAbx(&low, true); + Inc(low, high); + break; + } + case 0xff: { // sbc alx + uint32_t low = 0; + uint32_t high = AdrAlx(&low); + Sbc(low, high); + break; + } } - if (log_instructions_) { - LogInstructions(PC, opcode, operand, immediate, accumulator_mode); + LogInstructions(cache_pc, opcode, operand, immediate, accumulator_mode); } - instruction_length = GetInstructionLength(opcode); - UpdatePC(instruction_length); + // instruction_length = GetInstructionLength(opcode); + // UpdatePC(instruction_length); } void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand, @@ -1605,7 +1927,7 @@ void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand, std::cout << std::endl; } } - +/** uint8_t Cpu::GetInstructionLength(uint8_t opcode) { switch (opcode) { case 0x00: // BRK @@ -1953,6 +2275,7 @@ uint8_t Cpu::GetInstructionLength(uint8_t opcode) { return 1; // Default to 1 as a safe fallback } } +*/ } // namespace emu } // namespace app diff --git a/src/app/emu/cpu/cpu.h b/src/app/emu/cpu/cpu.h index 69c62e24..40e5950e 100644 --- a/src/app/emu/cpu/cpu.h +++ b/src/app/emu/cpu/cpu.h @@ -116,8 +116,19 @@ class Cpu : public Loggable, public core::ExperimentFlags { } } + void SetZN(uint16_t value, bool byte) { + if (byte) { + SetZeroFlag((value & 0xff) == 0); + SetNegativeFlag(value & 0x80); + } else { + SetZeroFlag(value == 0); + SetNegativeFlag(value & 0x8000); + } + } + // Setting flags in the status register bool m() { return GetAccumulatorSize() ? 1 : 0; } + bool xf() { return GetIndexSize() ? 1 : 0; } int GetAccumulatorSize() const { return status & 0x20; } int GetIndexSize() const { return status & 0x10; } void SetAccumulatorSize(bool set) { SetFlag(0x20, set); } @@ -152,15 +163,15 @@ class Cpu : public Loggable, public core::ExperimentFlags { } // Memory access routines - uint8_t ReadByte(uint32_t address) const { - return callbacks_.read_byte(address); - } - uint16_t ReadWord(uint32_t address) const { + uint8_t ReadByte(uint32_t address) { return callbacks_.read_byte(address); } + uint16_t ReadWord(uint32_t address, uint32_t address_high, + bool int_check = false) { uint8_t value = ReadByte(address); - uint8_t value2 = ReadByte(address + 1); + if (int_check) CheckInt(); + uint8_t value2 = ReadByte(address_high); return value | (value2 << 8); } - uint32_t ReadWordLong(uint32_t address) const { + uint32_t ReadWordLong(uint32_t address) { uint8_t value = ReadByte(address); uint8_t value2 = ReadByte(address + 1); uint8_t value3 = ReadByte(address + 2); @@ -171,9 +182,17 @@ class Cpu : public Loggable, public core::ExperimentFlags { callbacks_.write_byte(address, value); } - void WriteWord(uint32_t address, uint16_t value) { - WriteByte(address, value & 0xFF); - WriteByte(address + 1, value >> 8); + void WriteWord(uint32_t address, uint32_t address_high, uint16_t value, + bool reversed = false, bool int_check = false) { + if (reversed) { + WriteByte(address_high, value >> 8); + if (int_check) CheckInt(); + WriteByte(address, value & 0xFF); + } else { + WriteByte(address, value & 0xFF); + if (int_check) CheckInt(); + WriteByte(address_high, value >> 8); + } } void WriteLong(uint32_t address, uint32_t value) { WriteByte(address, value & 0xFF); @@ -181,54 +200,6 @@ class Cpu : public Loggable, public core::ExperimentFlags { WriteByte(address + 2, value >> 16); } - uint8_t FetchByte() { - uint32_t address = (PB << 16) | PC + 1; - uint8_t byte = ReadByte(address); - return byte; - } - - uint16_t FetchWord() { - uint32_t address = (PB << 16) | PC + 1; - uint16_t value = ReadWord(address); - return value; - } - - uint32_t FetchLong() { - uint32_t value = ReadWordLong((PB << 16) | PC + 1); - return value; - } - - int8_t FetchSignedByte() { return static_cast(FetchByte()); } - - int16_t FetchSignedWord() { - auto offset = static_cast(FetchWord()); - return offset; - } - - uint8_t FetchByteDirectPage(uint8_t operand) { - uint16_t distance = D * 0x100; - - // Calculate the effective address in the Direct Page - uint16_t effectiveAddress = operand + distance; - - // Fetch the byte from memory - uint8_t fetchedByte = ReadByte(effectiveAddress); - - next_pc_ = PC + 1; - - return fetchedByte; - } - - uint16_t ReadByteOrWord(uint32_t address) { - if (GetAccumulatorSize()) { - // 8-bit mode - return ReadByte(address) & 0xFF; - } else { - // 16-bit mode - return ReadWord(address); - } - } - void PushByte(uint8_t value) { WriteByte(SP(), value); SetSP(SP() - 1); @@ -272,11 +243,8 @@ class Cpu : public Loggable, public core::ExperimentFlags { void set_int_delay(bool delay) { int_delay_ = delay; } - // ========================================================================== // Addressing Modes - void AdrImp(); - // Effective Address: // Bank: Data Bank Register if locating data // Program Bank Register if transferring control @@ -284,7 +252,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { // Low: First operand byte // // LDA addr - uint32_t Absolute(AccessType access_type = AccessType::Data); + uint32_t Absolute(uint32_t* low); // Effective Address: // The Data Bank Register is concatened with the 16-bit operand @@ -293,6 +261,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { // // LDA addr, X uint32_t AbsoluteIndexedX(); + uint32_t AdrAbx(uint32_t* low, bool write); // Effective Address: // The Data Bank Register is concatened with the 16-bit operand @@ -301,6 +270,17 @@ class Cpu : public Loggable, public core::ExperimentFlags { // // LDA addr, Y uint32_t AbsoluteIndexedY(); + uint32_t AdrAby(uint32_t* low, bool write); + + void AdrImp(); + uint32_t AdrIdx(uint32_t* low); + + uint32_t AdrIdp(uint32_t* low); + uint32_t AdrIdy(uint32_t* low, bool write); + uint32_t AdrIdl(uint32_t* low); + uint32_t AdrIly(uint32_t* low); + uint32_t AdrIsy(uint32_t* low); + uint32_t Immediate(uint32_t* low, bool xFlag); // Effective Address: // Bank: Program Bank Register (PBR) @@ -333,12 +313,14 @@ class Cpu : public Loggable, public core::ExperimentFlags { // // LDA long uint32_t AbsoluteLong(); + uint32_t AdrAbl(uint32_t* low); // Effective Address: // The 24-bit operand is added to X based on the emulation mode // // LDA long, X uint32_t AbsoluteLongIndexedX(); + uint32_t AdrAlx(uint32_t* low); // Source Effective Address: // Bank: Second operand byte @@ -360,6 +342,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { // // LDA dp uint16_t DirectPage(); + uint32_t AdrDp(uint32_t* low); // Effective Address: // Bank: Zero @@ -368,6 +351,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { // // LDA dp, X uint16_t DirectPageIndexedX(); + uint32_t AdrDpx(uint32_t* low); // Effective Address: // Bank: Zero @@ -375,6 +359,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { // based on the emulation mode // LDA dp, Y uint16_t DirectPageIndexedY(); + uint32_t AdrDpy(uint32_t* low); // Effective Address: // Bank: Data bank register @@ -432,6 +417,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { uint16_t Immediate(bool index_size = false); uint16_t StackRelative(); + uint32_t AdrSr(uint32_t* low); // Effective Address: // The Data Bank Register is concatenated to the Indirect Address; @@ -572,7 +558,7 @@ class Cpu : public Loggable, public core::ExperimentFlags { void NOP(); // ORA: Logical inclusive OR - void ORA(uint16_t address, bool immediate = false); + void ORA(uint32_t low, uint32_t high); // PEA: Push effective absolute address void PEA(); @@ -724,7 +710,30 @@ class Cpu : public Loggable, public core::ExperimentFlags { // XCE: Exchange carry and emulation bits void XCE(); - // ========================================================================== + void And(uint32_t low, uint32_t high); + void Eor(uint32_t low, uint32_t high); + void Adc(uint32_t low, uint32_t high); + void Sbc(uint32_t low, uint32_t high); + void Cmp(uint32_t low, uint32_t high); + void Cpx(uint32_t low, uint32_t high); + void Cpy(uint32_t low, uint32_t high); + void Bit(uint32_t low, uint32_t high); + void Lda(uint32_t low, uint32_t high); + void Ldx(uint32_t low, uint32_t high); + void Ldy(uint32_t low, uint32_t high); + void Sta(uint32_t low, uint32_t high); + void Stx(uint32_t low, uint32_t high); + void Sty(uint32_t low, uint32_t high); + void Stz(uint32_t low, uint32_t high); + void Ror(uint32_t low, uint32_t high); + void Rol(uint32_t low, uint32_t high); + void Lsr(uint32_t low, uint32_t high); + void Asl(uint32_t low, uint32_t high); + void Inc(uint32_t low, uint32_t high); + void Dec(uint32_t low, uint32_t high); + void Tsb(uint32_t low, uint32_t high); + void Trb(uint32_t low, uint32_t high); + uint16_t SP() const { return memory.SP(); } void SetSP(uint16_t value) { memory.SetSP(value); } @@ -745,7 +754,8 @@ class Cpu : public Loggable, public core::ExperimentFlags { auto GetBreakpoints() { return breakpoints_; } void CheckInt() { - int_wanted_ = (nmi_wanted_ || (irq_wanted_ && !GetInterruptFlag()))&& !int_delay_; + int_wanted_ = + (nmi_wanted_ || (irq_wanted_ && !GetInterruptFlag())) && !int_delay_; int_delay_ = false; } @@ -790,7 +800,6 @@ class Cpu : public Loggable, public core::ExperimentFlags { bool int_wanted_ = false; bool int_delay_ = false; - memory::CpuCallbacks callbacks_; memory::Memory& memory; Clock& clock; diff --git a/src/app/emu/cpu/internal/addressing.cc b/src/app/emu/cpu/internal/addressing.cc index 1f26a6e9..7086cfd4 100644 --- a/src/app/emu/cpu/internal/addressing.cc +++ b/src/app/emu/cpu/internal/addressing.cc @@ -3,7 +3,6 @@ namespace yaze { namespace app { namespace emu { -// addressing modes void Cpu::AdrImp() { // only for 2-cycle implied opcodes @@ -17,125 +16,175 @@ void Cpu::AdrImp() { } } - -uint32_t Cpu::Absolute(Cpu::AccessType access_type) { - auto operand = FetchWord(); - uint32_t bank = - (access_type == Cpu::AccessType::Data) ? (DB << 16) : (PB << 16); - return bank | (operand & 0xFFFF); -} - -uint32_t Cpu::AbsoluteIndexedX() { - uint16_t address = ReadWord((PB << 16) | (PC + 1)); - uint32_t effective_address = (DB << 16) | ((address + X) & 0xFFFF); - return effective_address; -} - -uint32_t Cpu::AbsoluteIndexedY() { - uint16_t address = ReadWord((PB << 16) | (PC + 1)); - uint32_t effective_address = (DB << 16) | address + Y; - return effective_address; -} - -uint16_t Cpu::AbsoluteIndexedIndirect() { - uint16_t address = FetchWord() + X; - callbacks_.idle(false); - return ReadWord((DB << 16) | address & 0xFFFF); -} - -uint16_t Cpu::AbsoluteIndirect() { - uint16_t address = FetchWord(); - return ReadWord((PB << 16) | address); -} - -uint32_t Cpu::AbsoluteIndirectLong() { - uint16_t address = FetchWord(); - return ReadWordLong((PB << 16) | address); -} - -uint32_t Cpu::AbsoluteLong() { return FetchLong(); } - -uint32_t Cpu::AbsoluteLongIndexedX() { return FetchLong() + X; } - -void Cpu::BlockMove(uint16_t source, uint16_t dest, uint16_t length) { - for (int i = 0; i < length; i++) { - WriteByte(dest + i, ReadByte(source + i)); +uint32_t Cpu::Immediate(uint32_t* low, bool xFlag) { + if ((xFlag && GetIndexSize()) || (!xFlag && GetAccumulatorSize())) { + *low = (PB << 16) | PC++; + return 0; + } else { + *low = (PB << 16) | PC++; + return (PB << 16) | PC++; } } +uint32_t Cpu::AdrDpx(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + callbacks_.idle(false); + *low = (D + adr + X) & 0xffff; + return (D + adr + X + 1) & 0xffff; +} + +uint32_t Cpu::AdrDpy(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + callbacks_.idle(false); + *low = (D + adr + Y) & 0xffff; + return (D + adr + Y + 1) & 0xffff; +} + +uint32_t Cpu::AdrIdp(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + uint16_t pointer = ReadWord((D + adr) & 0xffff, false); + *low = (DB << 16) + pointer; + return ((DB << 16) + pointer + 1) & 0xffffff; +} + +uint32_t Cpu::AdrIdy(uint32_t* low, bool write) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + uint16_t pointer = ReadWord((D + adr) & 0xffff, false); + // writing opcode or x = 0 or page crossed: 1 extra cycle + if (write || !GetIndexSize() || ((pointer >> 8) != ((pointer + Y) >> 8))) + callbacks_.idle(false); + *low = ((DB << 16) + pointer + Y) & 0xffffff; + return ((DB << 16) + pointer + Y + 1) & 0xffffff; +} + +uint32_t Cpu::AdrIdl(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + uint32_t pointer = ReadWord((D + adr) & 0xffff, false); + pointer |= ReadByte((D + adr + 2) & 0xffff) << 16; + *low = pointer; + return (pointer + 1) & 0xffffff; +} + +uint32_t Cpu::AdrIly(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + uint32_t pointer = ReadWord((D + adr) & 0xffff, false); + pointer |= ReadByte((D + adr + 2) & 0xffff) << 16; + *low = (pointer + Y) & 0xffffff; + return (pointer + Y + 1) & 0xffffff; +} + +uint32_t Cpu::AdrSr(uint32_t* low) { + uint8_t adr = ReadOpcode(); + callbacks_.idle(false); + *low = (SP() + adr) & 0xffff; + return (SP() + adr + 1) & 0xffff; +} + +uint32_t Cpu::AdrIsy(uint32_t* low) { + uint8_t adr = ReadOpcode(); + callbacks_.idle(false); + uint16_t pointer = ReadWord((SP() + adr) & 0xffff, false); + callbacks_.idle(false); + *low = ((DB << 16) + pointer + Y) & 0xffffff; + return ((DB << 16) + pointer + Y + 1) & 0xffffff; +} + +uint32_t Cpu::Absolute(uint32_t* low) { + uint16_t adr = ReadOpcodeWord(false); + *low = (DB << 16) + adr; + return ((DB << 16) + adr + 1) & 0xffffff; +} + +uint32_t Cpu::AdrAbx(uint32_t* low, bool write) { + uint16_t adr = ReadOpcodeWord(false); + // writing opcode or x = 0 or page crossed: 1 extra cycle + if (write || !GetIndexSize() || ((adr >> 8) != ((adr + X) >> 8))) + callbacks_.idle(false); + *low = ((DB << 16) + adr + X) & 0xffffff; + return ((DB << 16) + adr + X + 1) & 0xffffff; +} + +uint32_t Cpu::AdrAby(uint32_t* low, bool write) { + uint16_t adr = ReadOpcodeWord(false); + // writing opcode or x = 0 or page crossed: 1 extra cycle + if (write || !GetIndexSize() || ((adr >> 8) != ((adr + Y) >> 8))) + callbacks_.idle(false); + *low = ((DB << 16) + adr + Y) & 0xffffff; + return ((DB << 16) + adr + Y + 1) & 0xffffff; +} + +uint32_t Cpu::AdrAbl(uint32_t* low) { + uint32_t adr = ReadOpcodeWord(false); + adr |= ReadOpcode() << 16; + *low = adr; + return (adr + 1) & 0xffffff; +} + +uint32_t Cpu::AdrAlx(uint32_t* low) { + uint32_t adr = ReadOpcodeWord(false); + adr |= ReadOpcode() << 16; + *low = (adr + X) & 0xffffff; + return (adr + X + 1) & 0xffffff; +} + +uint32_t Cpu::AdrDp(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); // dpr not 0: 1 extra cycle + *low = (D + adr) & 0xffff; + return (D + adr + 1) & 0xffff; +} + uint16_t Cpu::DirectPage() { - uint8_t dp = FetchByte(); + uint8_t dp = ReadOpcode(); return D + dp; } uint16_t Cpu::DirectPageIndexedX() { - uint8_t operand = FetchByte(); + uint8_t operand = ReadOpcode(); uint16_t x_by_mode = GetAccumulatorSize() ? X : X & 0xFF; return D + operand + x_by_mode; } uint16_t Cpu::DirectPageIndexedY() { - uint8_t operand = FetchByte(); + uint8_t operand = ReadOpcode(); return (operand + Y) & 0xFF; } -uint16_t Cpu::DirectPageIndexedIndirectX() { - uint8_t operand = FetchByte(); - if (D & 0xFF) { - callbacks_.idle(false); // dpr not 0: 1 extra cycle - } +uint32_t Cpu::AdrIdx(uint32_t* low) { + uint8_t adr = ReadOpcode(); + if (D & 0xff) callbacks_.idle(false); callbacks_.idle(false); - uint16_t indirect_address = D + operand + X; - uint16_t effective_address = ReadWord(indirect_address & 0xFFFF); - return effective_address; -} - -uint16_t Cpu::DirectPageIndirect() { - uint8_t dp = FetchByte(); - uint16_t effective_address = D + dp; - return ReadWord(effective_address); + uint16_t pointer = ReadWord((D + adr + X) & 0xffff, false); + *low = (DB << 16) + pointer; + return ((DB << 16) + pointer + 1) & 0xffffff; } uint32_t Cpu::DirectPageIndirectLong() { - uint8_t dp = FetchByte(); + uint8_t dp = ReadOpcode(); uint16_t effective_address = D + dp; return ReadWordLong((0x00 << 0x10) | effective_address); } -uint16_t Cpu::DirectPageIndirectIndexedY() { - uint8_t operand = FetchByte(); - uint16_t indirect_address = D + operand; - return ReadWord(indirect_address) + Y; -} - uint32_t Cpu::DirectPageIndirectLongIndexedY() { - uint8_t operand = FetchByte(); + uint8_t operand = ReadOpcode(); uint16_t indirect_address = D + operand; uint16_t y_by_mode = GetAccumulatorSize() ? Y : Y & 0xFF; uint32_t effective_address = ReadWordLong(indirect_address) + y_by_mode; return effective_address; } -uint16_t Cpu::Immediate(bool index_size) { - bool bit_mode = index_size ? GetIndexSize() : GetAccumulatorSize(); - if (bit_mode) { - return ReadByte((PB << 16) | PC + 1); - } else { - return ReadWord((PB << 16) | PC + 1); - } -} - uint16_t Cpu::StackRelative() { - uint8_t sr = FetchByte(); + uint8_t sr = ReadOpcode(); uint16_t effective_address = SP() + sr; return effective_address; } -uint32_t Cpu::StackRelativeIndirectIndexedY() { - uint8_t sr = FetchByte(); - return (DB << 0x10) | (ReadWord(SP() + sr) + Y); -} - } // namespace emu } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/emu/cpu/internal/instructions.cc b/src/app/emu/cpu/internal/instructions.cc index 0d12671a..c00d1f25 100644 --- a/src/app/emu/cpu/internal/instructions.cc +++ b/src/app/emu/cpu/internal/instructions.cc @@ -12,1074 +12,391 @@ namespace emu { * 65816 Instruction Set */ -void Cpu::ADC(uint16_t operand) { - bool C = GetCarryFlag(); - if (GetAccumulatorSize()) { // 8-bit mode +void Cpu::And(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { CheckInt(); - uint16_t result = static_cast(A & 0xFF) + - static_cast(operand) + (C ? 1 : 0); - SetCarryFlag(result > 0xFF); // Update the carry flag - - // Update the overflow flag - bool overflow = (~(A ^ operand) & (A ^ result) & 0x80) != 0; - SetOverflowFlag(overflow); - - // Update the accumulator with proper wrap-around - A = (A & 0xFF00) | (result & 0xFF); - - SetZeroFlag((A & 0xFF) == 0); - SetNegativeFlag(A & 0x80); + uint8_t value = ReadByte(low); + A = (A & 0xff00) | ((A & value) & 0xff); } else { - uint32_t result = - static_cast(A) + static_cast(operand) + (C ? 1 : 0); - SetCarryFlag(result > 0xFFFF); // Update the carry flag - - // Update the overflow flag - bool overflow = (~(A ^ operand) & (A ^ result) & 0x8000) != 0; - SetOverflowFlag(overflow); - - // Update the accumulator - A = result & 0xFFFF; - - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); + uint16_t value = ReadWord(low, high, true); + A &= value; } + SetZN(A, GetAccumulatorSize()); } -void Cpu::AND(uint32_t value, bool isImmediate) { - uint16_t operand; - if (GetAccumulatorSize()) { // 8-bit mode +void Cpu::Eor(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { CheckInt(); - operand = isImmediate ? value : ReadByte(value); - A &= operand; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { // 16-bit mode - operand = isImmediate ? value : ReadWord(value); - A &= operand; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); + uint8_t value = ReadByte(low); + A = (A & 0xff00) | ((A ^ value) & 0xff); + } else { + uint16_t value = ReadWord(low, high, true); + A ^= value; } + SetZN(A, GetAccumulatorSize()); } -// New function for absolute long addressing mode -void Cpu::ANDAbsoluteLong(uint32_t address) { - uint32_t operand32 = ReadWordLong(address); - A &= operand32; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); -} - -void Cpu::ASL(uint16_t address) { - if (GetAccumulatorSize()) { // 8-bit mode - uint8_t value = ReadByte(address); - callbacks_.idle(false); - SetCarryFlag(value & 0x80); - value <<= 1; +void Cpu::Adc(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { CheckInt(); - WriteByte(address, value); - SetZeroFlag(value == 0); - SetNegativeFlag(value & 0x80); - } else { // 16-bit mode - uint16_t value = ReadWord(address); - callbacks_.idle(false); - SetCarryFlag(value & 0x8000); - value <<= 1; - WriteWord(address, value); - SetZeroFlag(value == 0); - SetNegativeFlag(value & 0x8000); - } -} - -void Cpu::BCC(int8_t offset) { - if (!GetCarryFlag()) { // If the carry flag is clear - next_pc_ = offset; - } -} - -void Cpu::BCS(int8_t offset) { - if (GetCarryFlag()) { // If the carry flag is set - next_pc_ = offset; - } -} - -void Cpu::BEQ(int8_t offset) { - if (GetZeroFlag()) { // If the zero flag is set - next_pc_ = offset; - } -} - -void Cpu::BIT(uint16_t address) { - CheckInt(); - uint8_t value = ReadByte(address); - SetNegativeFlag(value & 0x80); - SetOverflowFlag(value & 0x40); - SetZeroFlag((A & value) == 0); -} - -void Cpu::BMI(int8_t offset) { - if (GetNegativeFlag()) { // If the negative flag is set - next_pc_ = PC + offset; - } -} - -void Cpu::BNE(int8_t offset) { - if (!GetZeroFlag()) { // If the zero flag is clear - // PC += offset; - next_pc_ = PC + offset; - } -} - -void Cpu::BPL(int8_t offset) { - if (!GetNegativeFlag()) { // If the negative flag is clear - next_pc_ = PC + offset; - } -} - -void Cpu::BRA(int8_t offset) { next_pc_ = PC + offset; } - -void Cpu::BRK() { - // ReadOpcode(); - next_pc_ = PC + 2; // Increment the program counter by 2 - ReadByte(PC); // Read the next byte - PushByte(PB); - PushByte(PC); // ,false - PushByte(status); - SetInterruptFlag(true); - SetDecimalFlag(false); - next_pb_ = 0; - next_pc_ = ReadWord(0xFFE6); // ,true -} - -void Cpu::BRL(int16_t offset) { - next_pc_ = PC + offset; - CheckInt(); - callbacks_.idle(false); -} - -void Cpu::BVC(int8_t offset) { - if (!GetOverflowFlag()) { // If the overflow flag is clear - next_pc_ = offset; - } -} - -void Cpu::BVS(int8_t offset) { - if (GetOverflowFlag()) { // If the overflow flag is set - next_pc_ = offset; - } -} - -void Cpu::CLC() { - AdrImp(); - status &= ~0x01; -} - -void Cpu::CLD() { - AdrImp(); - status &= ~0x08; -} - -void Cpu::CLI() { - AdrImp(); - status &= ~0x04; -} - -void Cpu::CLV() { - AdrImp(); - status &= ~0x40; -} - -// n Set if MSB of result is set; else cleared -// z Set if result is zero; else cleared -// c Set if no borrow; else cleared -void Cpu::CMP(uint32_t value, bool isImmediate) { - if (GetAccumulatorSize()) { // 8-bit - CheckInt(); - uint8_t result; - if (isImmediate) { - result = A - (value & 0xFF); + uint8_t value = ReadByte(low); + int result = 0; + if (GetDecimalFlag()) { + result = (A & 0xf) + (value & 0xf) + GetCarryFlag(); + if (result > 0x9) result = ((result + 0x6) & 0xf) + 0x10; + result = (A & 0xf0) + (value & 0xf0) + result; } else { - uint8_t memory_value = ReadByte(value); - result = A - memory_value; + result = (A & 0xff) + value + GetCarryFlag(); } - SetZeroFlag(result == 0); - SetNegativeFlag(result & 0x80); - SetCarryFlag(A >= (value & 0xFF)); - } else { // 16-bit - uint16_t result; - if (isImmediate) { - result = A - (value & 0xFFFF); + SetOverflowFlag((A & 0x80) == (value & 0x80) && + (value & 0x80) != (result & 0x80)); + if (GetDecimalFlag() && result > 0x9f) result += 0x60; + SetCarryFlag(result > 0xff); + A = (A & 0xff00) | (result & 0xff); + } else { + uint16_t value = ReadWord(low, high, true); + int result = 0; + if (GetDecimalFlag()) { + result = (A & 0xf) + (value & 0xf) + GetCarryFlag(); + if (result > 0x9) result = ((result + 0x6) & 0xf) + 0x10; + result = (A & 0xf0) + (value & 0xf0) + result; + if (result > 0x9f) result = ((result + 0x60) & 0xff) + 0x100; + result = (A & 0xf00) + (value & 0xf00) + result; + if (result > 0x9ff) result = ((result + 0x600) & 0xfff) + 0x1000; + result = (A & 0xf000) + (value & 0xf000) + result; } else { - uint16_t memory_value = ReadWord(value); - result = A - memory_value; + result = A + value + GetCarryFlag(); } + SetOverflowFlag((A & 0x8000) == (value & 0x8000) && + (value & 0x8000) != (result & 0x8000)); + if (GetDecimalFlag() && result > 0x9fff) result += 0x6000; + SetCarryFlag(result > 0xffff); + A = result; + } + SetZN(A, GetAccumulatorSize()); +} + +void Cpu::Sbc(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + CheckInt(); + uint8_t value = ReadByte(low) ^ 0xff; + int result = 0; + if (GetDecimalFlag()) { + result = (A & 0xf) + (value & 0xf) + GetCarryFlag(); + if (result < 0x10) + result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f); + result = (A & 0xf0) + (value & 0xf0) + result; + } else { + result = (A & 0xff) + value + GetCarryFlag(); + } + SetOverflowFlag((A & 0x80) == (value & 0x80) && + (value & 0x80) != (result & 0x80)); + if (GetDecimalFlag() && result < 0x100) result -= 0x60; + SetCarryFlag(result > 0xff); + A = (A & 0xff00) | (result & 0xff); + } else { + uint16_t value = ReadWord(low, high, true) ^ 0xffff; + int result = 0; + if (GetDecimalFlag()) { + result = (A & 0xf) + (value & 0xf) + GetCarryFlag(); + if (result < 0x10) + result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f); + result = (A & 0xf0) + (value & 0xf0) + result; + if (result < 0x100) + result = (result - 0x60) & ((result - 0x60 < 0) ? 0xff : 0x1ff); + result = (A & 0xf00) + (value & 0xf00) + result; + if (result < 0x1000) + result = (result - 0x600) & ((result - 0x600 < 0) ? 0xfff : 0x1fff); + result = (A & 0xf000) + (value & 0xf000) + result; + } else { + result = A + value + GetCarryFlag(); + } + SetOverflowFlag((A & 0x8000) == (value & 0x8000) && + (value & 0x8000) != (result & 0x8000)); + if (GetDecimalFlag() && result < 0x10000) result -= 0x6000; + SetCarryFlag(result > 0xffff); + A = result; + } + SetZN(A, GetAccumulatorSize()); +} + +void Cpu::Cmp(uint32_t low, uint32_t high) { + int result = 0; + if (GetAccumulatorSize()) { + CheckInt(); + uint8_t value = ReadByte(low) ^ 0xff; + result = (A & 0xff) + value + 1; + SetCarryFlag(result > 0xff); + } else { + uint16_t value = ReadWord(low, high, true) ^ 0xffff; + result = A + value + 1; + SetCarryFlag(result > 0xffff); + } + SetZN(result, GetAccumulatorSize()); +} + +void Cpu::Cpx(uint32_t low, uint32_t high) { + int result = 0; + if (GetIndexSize()) { + CheckInt(); + uint8_t value = ReadByte(low) ^ 0xff; + result = (X & 0xff) + value + 1; + SetCarryFlag(result > 0xff); + } else { + uint16_t value = ReadWord(low, high, true) ^ 0xffff; + result = X + value + 1; + SetCarryFlag(result > 0xffff); + } + SetZN(result, GetIndexSize()); +} + +void Cpu::Cpy(uint32_t low, uint32_t high) { + int result = 0; + if (GetIndexSize()) { + CheckInt(); + uint8_t value = ReadByte(low) ^ 0xff; + result = (Y & 0xff) + value + 1; + SetCarryFlag(result > 0xff); + } else { + uint16_t value = ReadWord(low, high, true) ^ 0xffff; + result = Y + value + 1; + SetCarryFlag(result > 0xffff); + } + SetZN(result, GetIndexSize()); +} + +void Cpu::Bit(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + CheckInt(); + uint8_t value = ReadByte(low); + uint8_t result = (A & 0xff) & value; SetZeroFlag(result == 0); - SetNegativeFlag(result & 0x8000); - SetCarryFlag(A >= (value & 0xFFFF)); - } -} - -void Cpu::COP() { - next_pc_ = PC + 2; // Increment the program counter by 2 - PushWord(next_pc_); - PushByte(status); - SetInterruptFlag(true); - if (E) { - next_pc_ = ReadWord(0xFFF4); - } else { - next_pc_ = ReadWord(0xFFE4); - } - SetDecimalFlag(false); - next_pb_ = 0; - next_pc_ = ReadWord(0xFFE4); -} - -void Cpu::CPX(uint32_t value, bool isImmediate) { - if (GetIndexSize()) { // 8-bit - CheckInt(); - uint8_t memory_value = isImmediate ? value : ReadByte(value); - compare(X, memory_value); - } else { // 16-bit - uint16_t memory_value = isImmediate ? value : ReadWord(value); - compare(X, memory_value); - } -} - -void Cpu::CPY(uint32_t value, bool isImmediate) { - if (GetIndexSize()) { // 8-bit - CheckInt(); - uint8_t memory_value = isImmediate ? value : ReadByte(value); - compare(Y, memory_value); - } else { // 16-bit - uint16_t memory_value = isImmediate ? value : ReadWord(value); - compare(Y, memory_value); - } -} - -void Cpu::DEC(uint32_t address, bool accumulator) { - if (accumulator) { - AdrImp(); - if (GetAccumulatorSize()) { // 8-bit - A = (A - 1) & 0xFF; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { // 16-bit - A = (A - 1) & 0xFFFF; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - return; - } - - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - value--; - callbacks_.idle(false); - CheckInt(); - WriteByte(address, value); - SetZeroFlag(value == 0); SetNegativeFlag(value & 0x80); + SetOverflowFlag(value & 0x40); } else { - uint16_t value = ReadWord(address); - value--; - callbacks_.idle(false); - WriteWord(address, value); - SetZeroFlag(value == 0); + uint16_t value = ReadWord(low, high, true); + uint16_t result = A & value; + SetZeroFlag(result == 0); SetNegativeFlag(value & 0x8000); + SetOverflowFlag(value & 0x4000); } } -void Cpu::DEX() { - AdrImp(); - if (GetIndexSize()) { // 8-bit - X = static_cast(X - 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } else { // 16-bit - X = static_cast(X - 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x8000); - } -} - -void Cpu::DEY() { - AdrImp(); - if (GetIndexSize()) { // 8-bit - Y = static_cast(Y - 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } else { // 16-bit - Y = static_cast(Y - 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x8000); - } -} - -void Cpu::EOR(uint32_t address, bool isImmediate) { +void Cpu::Lda(uint32_t low, uint32_t high) { if (GetAccumulatorSize()) { CheckInt(); - A ^= isImmediate ? address : ReadByte(address); + A = (A & 0xff00) | ReadByte(low); + } else { + A = ReadWord(low, high, true); + } + SetZN(A, GetAccumulatorSize()); +} + +void Cpu::Ldx(uint32_t low, uint32_t high) { + if (GetIndexSize()) { + CheckInt(); + X = ReadByte(low); + } else { + X = ReadWord(low, high, true); + } + SetZN(X, GetIndexSize()); +} + +void Cpu::Ldy(uint32_t low, uint32_t high) { + if (GetIndexSize()) { + CheckInt(); + Y = ReadByte(low); + } else { + Y = ReadWord(low, high, true); + } + SetZN(Y, GetIndexSize()); +} + +void Cpu::Sta(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + CheckInt(); + WriteByte(low, A); + } else { + WriteWord(low, high, A, false, true); + } +} + +void Cpu::Stx(uint32_t low, uint32_t high) { + if (GetIndexSize()) { + CheckInt(); + WriteByte(low, X); + } else { + WriteWord(low, high, X, false, true); + } +} + +void Cpu::Sty(uint32_t low, uint32_t high) { + if (GetIndexSize()) { + CheckInt(); + WriteByte(low, Y); + } else { + WriteWord(low, high, Y, false, true); + } +} + +void Cpu::Stz(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + CheckInt(); + WriteByte(low, 0); + } else { + WriteWord(low, high, 0, false, true); + } +} + +void Cpu::Ror(uint32_t low, uint32_t high) { + bool carry = false; + int result = 0; + if (GetAccumulatorSize()) { + uint8_t value = ReadByte(low); + callbacks_.idle(false); + carry = value & 1; + result = (value >> 1) | (GetCarryFlag() << 7); + CheckInt(); + WriteByte(low, result); + } else { + uint16_t value = ReadWord(low, high, false); + callbacks_.idle(false); + carry = value & 1; + result = (value >> 1) | (GetCarryFlag() << 15); + WriteWord(low, high, result, true, true); + } + SetZN(result, GetAccumulatorSize()); + SetCarryFlag(carry); +} + +void Cpu::Rol(uint32_t low, uint32_t high) { + int result = 0; + if (GetAccumulatorSize()) { + result = (ReadByte(low) << 1) | GetCarryFlag(); + callbacks_.idle(false); + SetCarryFlag(result & 0x100); + CheckInt(); + WriteByte(low, result); + } else { + result = (ReadWord(low, high, false) << 1) | GetCarryFlag(); + callbacks_.idle(false); + SetCarryFlag(result & 0x10000); + WriteWord(low, high, result, true, true); + } + SetZN(result, GetAccumulatorSize()); +} + +void Cpu::Lsr(uint32_t low, uint32_t high) { + int result = 0; + if (GetAccumulatorSize()) { + uint8_t value = ReadByte(low); + callbacks_.idle(false); + SetCarryFlag(value & 1); + result = value >> 1; + CheckInt(); + WriteByte(low, result); + } else { + uint16_t value = ReadWord(low, high, false); + callbacks_.idle(false); + SetCarryFlag(value & 1); + result = value >> 1; + WriteWord(low, high, result, true, true); + } + SetZN(result, GetAccumulatorSize()); +} + +void Cpu::Asl(uint32_t low, uint32_t high) { + int result = 0; + if (GetAccumulatorSize()) { + result = ReadByte(low) << 1; + callbacks_.idle(false); + SetCarryFlag(result & 0x100); + CheckInt(); + WriteByte(low, result); + } else { + result = ReadWord(low, high, false) << 1; + callbacks_.idle(false); + SetCarryFlag(result & 0x10000); + WriteWord(low, high, result, true, true); + } + SetZN(result, GetAccumulatorSize()); +} + +void Cpu::Inc(uint32_t low, uint32_t high) { + int result = 0; + if (GetAccumulatorSize()) { + result = ReadByte(low) + 1; + callbacks_.idle(false); + CheckInt(); + WriteByte(low, result); + } else { + result = ReadWord(low, high, false) + 1; + callbacks_.idle(false); + WriteWord(low, high, result, true, true); + } + SetZN(result, GetAccumulatorSize()); +} + +void Cpu::Dec(uint32_t low, uint32_t high) { + int result = 0; + if (GetAccumulatorSize()) { + result = ReadByte(low) - 1; + callbacks_.idle(false); + CheckInt(); + WriteByte(low, result); + } else { + result = ReadWord(low, high, false) - 1; + callbacks_.idle(false); + WriteWord(low, high, result, true, true); + } + SetZN(result, GetAccumulatorSize()); +} + +void Cpu::Tsb(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + uint8_t value = ReadByte(low); + callbacks_.idle(false); + SetZeroFlag(((A & 0xff) & value) == 0); + CheckInt(); + WriteByte(low, value | (A & 0xff)); + } else { + uint16_t value = ReadWord(low, high, false); + callbacks_.idle(false); + SetZeroFlag((A & value) == 0); + WriteWord(low, high, value | A, true, true); + } +} + +void Cpu::Trb(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + uint8_t value = ReadByte(low); + callbacks_.idle(false); + SetZeroFlag(((A & 0xff) & value) == 0); + CheckInt(); + WriteByte(low, value & ~(A & 0xff)); + } else { + uint16_t value = ReadWord(low, high, false); + callbacks_.idle(false); + SetZeroFlag((A & value) == 0); + WriteWord(low, high, value & ~A, true, true); + } +} + +void Cpu::ORA(uint32_t low, uint32_t high) { + if (GetAccumulatorSize()) { + CheckInt(); + uint8_t value = ReadByte(low); + A = (A & 0xFF00) | ((A | value) & 0xFF); SetZeroFlag(A == 0); SetNegativeFlag(A & 0x80); } else { - A ^= isImmediate ? address : ReadWord(address); + uint16_t value = ReadWord(low, high, true); + A |= value; SetZeroFlag(A == 0); SetNegativeFlag(A & 0x8000); } } -void Cpu::INC(uint32_t address, bool accumulator) { - if (accumulator) { - AdrImp(); - if (GetAccumulatorSize()) { // 8-bit - A = (A + 1) & 0xFF; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { // 16-bit - A = (A + 1) & 0xFFFF; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - return; - } - - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - value++; - callbacks_.idle(false); - CheckInt(); - WriteByte(address, value); - SetNegativeFlag(value & 0x80); - SetZeroFlag(value == 0); - } else { - uint16_t value = ReadWord(address); - value++; - callbacks_.idle(false); - WriteWord(address, value); - SetNegativeFlag(value & 0x8000); - SetZeroFlag(value == 0); - } -} - -void Cpu::INX() { - AdrImp(); - if (GetIndexSize()) { // 8-bit - X = static_cast(X + 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } else { // 16-bit - X = static_cast(X + 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x8000); - } -} - -void Cpu::INY() { - AdrImp(); - if (GetIndexSize()) { // 8-bit - Y = static_cast(Y + 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } else { // 16-bit - Y = static_cast(Y + 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x8000); - } -} - -void Cpu::JMP(uint16_t address) { - next_pc_ = address; // Set program counter to the new address -} - -void Cpu::JML(uint16_t address) { - CheckInt(); - next_pc_ = address; - uint8_t new_pb = ReadByte(PC + 2); - next_pb_ = new_pb; -} - -void Cpu::JSR(uint16_t address) { - callbacks_.idle(false); - PushWord(PC); // Push the program counter onto the stack - next_pc_ = address; // Set program counter to the new address -} - -void Cpu::JSL(uint16_t address) { - PushByte(PB); - callbacks_.idle(false); - uint8_t new_pb = ReadByte(PC + 2); - PushWord(PC); - next_pc_ = address; // Set program counter to the new address - next_pb_ = new_pb; -} - -void Cpu::LDA(uint16_t address, bool isImmediate, bool direct_page, - bool data_bank) { - uint8_t bank = PB; - if (direct_page) { - bank = 0; - } - if (GetAccumulatorSize()) { - CheckInt(); - A = isImmediate ? address : ReadByte((bank << 16) | address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { - A = isImmediate ? address : ReadWord((bank << 16) | address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } -} - -void Cpu::LDX(uint16_t address, bool isImmediate) { - if (GetIndexSize()) { - CheckInt(); - X = isImmediate ? address : ReadByte(address); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } else { - X = isImmediate ? address : ReadWord(address); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x8000); - } -} - -void Cpu::LDY(uint16_t address, bool isImmediate) { - if (GetIndexSize()) { - CheckInt(); - Y = isImmediate ? address : ReadByte(address); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } else { - Y = isImmediate ? address : ReadWord(address); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x8000); - } -} - -void Cpu::LSR(uint16_t address, bool accumulator) { - if (accumulator) { - AdrImp(); - if (GetAccumulatorSize()) { // 8-bit - SetCarryFlag(A & 0x01); - A >>= 1; - SetZeroFlag(A == 0); - SetNegativeFlag(false); - } else { // 16-bit - SetCarryFlag(A & 0x0001); - A >>= 1; - SetZeroFlag(A == 0); - SetNegativeFlag(false); - } - return; - } - - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - callbacks_.idle(false); - SetCarryFlag(value & 0x01); - value >>= 1; - CheckInt(); - WriteByte(address, value); - SetNegativeFlag(false); - SetZeroFlag(value == 0); - } else { - uint16_t value = ReadWord(address); - SetCarryFlag(value & 0x0001); - value >>= 1; - WriteWord(address, value); - SetNegativeFlag(false); - SetZeroFlag(value == 0); - } -} - -void Cpu::MVN() { - uint8_t dest = ReadByte(PC + 1); - uint8_t src = ReadByte(PC + 2); - next_pc_ = PC + 3; - DB = dest; - WriteByte((dest << 16) | Y, ReadByte((src << 16) | X)); - A--; - X++; - Y++; - if (A != 0xFFFF) { - next_pc_ -= 3; - } - if (GetIndexSize()) { - X &= 0xFF; - Y &= 0xFF; - } - callbacks_.idle(false); - CheckInt(); - callbacks_.idle(false); -} - -void Cpu::MVP() { - uint8_t dest = ReadByte(PC + 1); - uint8_t src = ReadByte(PC + 2); - next_pc_ = PC + 3; - DB = dest; - WriteByte((dest << 16) | Y, ReadByte((src << 16) | X)); - A--; - X--; - Y--; - if (A != 0xFFFF) { - next_pc_ -= 3; - } - if (GetIndexSize()) { - X &= 0xFF; - Y &= 0xFF; - } - callbacks_.idle(false); - CheckInt(); - callbacks_.idle(false); -} - -void Cpu::NOP() { AdrImp(); } - -void Cpu::ORA(uint16_t address, bool isImmediate) { - if (GetAccumulatorSize()) { - CheckInt(); - A |= isImmediate ? address : ReadByte(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { - A |= isImmediate ? address : ReadWord(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } -} - -void Cpu::PEA() { - uint16_t address = FetchWord(); - PushWord(address); -} - -void Cpu::PEI() { - uint16_t address = FetchWord(); - PushWord(ReadWord(address)); -} - -void Cpu::PER() { - uint16_t address = FetchWord(); - callbacks_.idle(false); - PushWord(PC + address); -} - -void Cpu::PHA() { - callbacks_.idle(false); - if (GetAccumulatorSize()) { - CheckInt(); - PushByte(static_cast(A)); - } else { - PushWord(A); - } -} - -void Cpu::PHB() { - callbacks_.idle(false); - CheckInt(); - PushByte(DB); -} - -void Cpu::PHD() { - callbacks_.idle(false); - PushWord(D); -} - -void Cpu::PHK() { - callbacks_.idle(false); - CheckInt(); - PushByte(PB); -} - -void Cpu::PHP() { - callbacks_.idle(false); - CheckInt(); - PushByte(status); -} - -void Cpu::PHX() { - callbacks_.idle(false); - if (GetIndexSize()) { - CheckInt(); - PushByte(static_cast(X)); - } else { - PushWord(X); - } -} - -void Cpu::PHY() { - callbacks_.idle(false); - if (GetIndexSize()) { - CheckInt(); - PushByte(static_cast(Y)); - } else { - PushWord(Y); - } -} - -void Cpu::PLA() { - callbacks_.idle(false); - callbacks_.idle(false); - if (GetAccumulatorSize()) { - CheckInt(); - A = PopByte(); - SetNegativeFlag((A & 0x80) != 0); - } else { - A = PopWord(); - SetNegativeFlag((A & 0x8000) != 0); - } - SetZeroFlag(A == 0); -} - -void Cpu::PLB() { - callbacks_.idle(false); - callbacks_.idle(false); - CheckInt(); - DB = PopByte(); - SetNegativeFlag((DB & 0x80) != 0); - SetZeroFlag(DB == 0); -} - -// Pull Direct Page Register from Stack -void Cpu::PLD() { - callbacks_.idle(false); - callbacks_.idle(false); - D = PopWord(); - SetNegativeFlag((D & 0x8000) != 0); - SetZeroFlag(D == 0); -} - -// Pull Processor Status Register from Stack -void Cpu::PLP() { - callbacks_.idle(false); - callbacks_.idle(false); - CheckInt(); - status = PopByte(); -} - -void Cpu::PLX() { - callbacks_.idle(false); - callbacks_.idle(false); - if (GetIndexSize()) { - CheckInt(); - X = PopByte(); - SetNegativeFlag((A & 0x80) != 0); - } else { - X = PopWord(); - SetNegativeFlag((A & 0x8000) != 0); - } - - SetZeroFlag(X == 0); -} - -void Cpu::PLY() { - callbacks_.idle(false); - callbacks_.idle(false); - if (GetIndexSize()) { - CheckInt(); - Y = PopByte(); - SetNegativeFlag((A & 0x80) != 0); - } else { - Y = PopWord(); - SetNegativeFlag((A & 0x8000) != 0); - } - SetZeroFlag(Y == 0); -} - -void Cpu::REP() { - auto byte = FetchByte(); - CheckInt(); - status &= ~byte; - callbacks_.idle(false); -} - -void Cpu::ROL(uint32_t address, bool accumulator) { - if (accumulator) { - AdrImp(); - if (GetAccumulatorSize()) { // 8-bit - uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; - SetCarryFlag(A & 0x80); - A <<= 1; - A |= carry; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { // 16-bit - uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; - SetCarryFlag(A & 0x8000); - A <<= 1; - A |= carry; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - return; - } - - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - callbacks_.idle(false); - uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; - SetCarryFlag(value & 0x80); - value <<= 1; - value |= carry; - CheckInt(); - WriteByte(address, value); - SetNegativeFlag(value & 0x80); - SetZeroFlag(value == 0); - } else { - uint16_t value = ReadWord(address); - callbacks_.idle(false); - uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; - SetCarryFlag(value & 0x8000); - value <<= 1; - value |= carry; - WriteWord(address, value); - SetNegativeFlag(value & 0x8000); - SetZeroFlag(value == 0); - } -} - -void Cpu::ROR(uint32_t address, bool accumulator) { - if (accumulator) { - AdrImp(); - if (GetAccumulatorSize()) { // 8-bit - uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; - SetCarryFlag(A & 0x01); - A >>= 1; - A |= carry; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { // 16-bit - uint8_t carry = GetCarryFlag() ? 0x8000 : 0x00; - SetCarryFlag(A & 0x0001); - A >>= 1; - A |= carry; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - return; - } - - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - callbacks_.idle(false); - uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; - SetCarryFlag(value & 0x01); - value >>= 1; - value |= carry; - CheckInt(); - WriteByte(address, value); - SetNegativeFlag(value & 0x80); - SetZeroFlag(value == 0); - } else { - uint16_t value = ReadWord(address); - callbacks_.idle(false); - uint8_t carry = GetCarryFlag() ? 0x8000 : 0x00; - SetCarryFlag(value & 0x0001); - value >>= 1; - value |= carry; - WriteWord(address, value); - SetNegativeFlag(value & 0x8000); - SetZeroFlag(value == 0); - } -} - -void Cpu::RTI() { - callbacks_.idle(false); - callbacks_.idle(false); - status = PopByte(); - next_pc_ = PopWord(); - CheckInt(); - next_pb_ = PopByte(); -} - -void Cpu::RTL() { - callbacks_.idle(false); - callbacks_.idle(false); - next_pc_ = PopWord(); - CheckInt(); - next_pb_ = PopByte(); -} - -void Cpu::RTS() { - callbacks_.idle(false); - callbacks_.idle(false); - last_call_frame_ = PopWord(); - CheckInt(); - callbacks_.idle(false); -} - -void Cpu::SBC(uint32_t value, bool isImmediate) { - uint16_t operand; - if (!GetAccumulatorSize()) { // 16-bit mode - operand = isImmediate ? value : ReadWord(value); - uint16_t result = A - operand - (GetCarryFlag() ? 0 : 1); - SetCarryFlag(!(result > 0xFFFF)); // Update the carry flag - - // Update the overflow flag - bool overflow = ((A ^ operand) & (A ^ result) & 0x8000) != 0; - SetOverflowFlag(overflow); - - // Update the accumulator - A = result & 0xFFFF; - - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } else { // 8-bit mode - CheckInt(); - operand = isImmediate ? value : ReadByte(value); - uint8_t result = A - operand - (GetCarryFlag() ? 0 : 1); - SetCarryFlag(!(result > 0xFF)); // Update the carry flag - - // Update the overflow flag - bool overflow = ((A ^ operand) & (A ^ result) & 0x80) != 0; - SetOverflowFlag(overflow); - - // Update the accumulator - A = result & 0xFF; - - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } -} - -void Cpu::SEC() { - AdrImp(); - status |= 0x01; -} - -void Cpu::SED() { - AdrImp(); - status |= 0x08; -} - -void Cpu::SEI() { - AdrImp(); - status |= 0x04; -} - -void Cpu::SEP() { - auto byte = FetchByte(); - CheckInt(); - status |= byte; - callbacks_.idle(false); -} - -void Cpu::STA(uint32_t address) { - if (GetAccumulatorSize()) { - CheckInt(); - WriteByte(address, static_cast(A)); - } else { - WriteWord(address, A); - } -} - -void Cpu::STP() { - stopped_ = true; - callbacks_.idle(false); - callbacks_.idle(false); -} - -void Cpu::STX(uint16_t address) { - if (GetIndexSize()) { - CheckInt(); - WriteByte(address, static_cast(X)); - } else { - WriteWord(address, X); - } -} - -void Cpu::STY(uint16_t address) { - if (GetIndexSize()) { - CheckInt(); - WriteByte(address, static_cast(Y)); - } else { - WriteWord(address, Y); - } -} - -void Cpu::STZ(uint16_t address) { - if (GetAccumulatorSize()) { - CheckInt(); - WriteByte(address, 0x00); - } else { - WriteWord(address, 0x0000); - } -} - -void Cpu::TAX() { - AdrImp(); - if (GetIndexSize()) { - X = A & 0xFF; - } else { - X = A; - } - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); -} - -void Cpu::TAY() { - AdrImp(); - if (GetIndexSize()) { - Y = A & 0xFF; - } else { - Y = A; - } - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); -} - -void Cpu::TCD() { - AdrImp(); - D = A; - SetZeroFlag(D == 0); - SetNegativeFlag(D & 0x80); -} - -void Cpu::TCS() { - AdrImp(); - SetSP(A); -} - -void Cpu::TDC() { - AdrImp(); - A = D; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); -} - -void Cpu::TRB(uint16_t address) { - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - callbacks_.idle(false); - SetZeroFlag((A & value) == 0); - value &= ~A; - CheckInt(); - WriteByte(address, value); - } else { - uint16_t value = ReadWord(address); - callbacks_.idle(false); - SetZeroFlag((A & value) == 0); - value &= ~A; - WriteWord(address, value); - } -} - -void Cpu::TSB(uint16_t address) { - if (GetAccumulatorSize()) { - uint8_t value = ReadByte(address); - callbacks_.idle(false); - SetZeroFlag((A & value) == 0); - value |= A; - CheckInt(); - WriteByte(address, value); - } else { - uint16_t value = ReadWord(address); - callbacks_.idle(false); - SetZeroFlag((A & value) == 0); - value |= A; - WriteWord(address, value); - } -} - -void Cpu::TSC() { - AdrImp(); - A = SP(); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); -} - -void Cpu::TSX() { - AdrImp(); - if (GetIndexSize()) { - X = SP() & 0xFF; - } else { - X = SP(); - } - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); -} - -void Cpu::TXA() { - AdrImp(); - if (GetAccumulatorSize()) { - A = X & 0xFF; - } else { - A = X; - } - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); -} - -void Cpu::TXS() { - AdrImp(); - SetSP(X); -} - -void Cpu::TXY() { - AdrImp(); - if (GetIndexSize()) { - Y = X & 0xFF; - } else { - Y = X; - } - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); -} - -void Cpu::TYA() { - AdrImp(); - if (GetAccumulatorSize()) { - A = Y & 0xFF; - } else { - A = Y; - } - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); -} - -void Cpu::TYX() { - AdrImp(); - if (GetIndexSize()) { - X = Y & 0xFF; - } else { - X = Y; - } - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); -} - -void Cpu::WAI() { - waiting_ = true; - callbacks_.idle(false); - callbacks_.idle(false); -} - -void Cpu::WDM() { - CheckInt(); - ReadByte(PC); -} - -void Cpu::XBA() { - uint8_t lowByte = A & 0xFF; - uint8_t highByte = (A >> 8) & 0xFF; - A = (lowByte << 8) | highByte; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - callbacks_.idle(false); - CheckInt(); - callbacks_.idle(false); -} - -void Cpu::XCE() { - AdrImp(); - uint8_t carry = status & 0x01; - status &= ~0x01; - status |= E; - E = carry; -} - } // namespace emu } // namespace app } // namespace yaze \ No newline at end of file