#include #include #include #include "app/emu/cpu/cpu.h" namespace yaze { namespace app { namespace emu { /** * 65816 Instruction Set */ void Cpu::And(uint32_t low, uint32_t high) { if (GetAccumulatorSize()) { CheckInt(); uint8_t value = ReadByte(low); A = (A & 0xff00) | ((A & value) & 0xff); } else { uint16_t value = ReadWord(low, high, true); A &= value; } SetZN(A, GetAccumulatorSize()); } void Cpu::Eor(uint32_t low, uint32_t high) { if (GetAccumulatorSize()) { CheckInt(); uint8_t value = ReadByte(low); A = (A & 0xff00) | ((A ^ value) & 0xff); } else { uint16_t value = ReadWord(low, high, true); A ^= value; } SetZN(A, GetAccumulatorSize()); } void Cpu::Adc(uint32_t low, uint32_t high) { if (GetAccumulatorSize()) { CheckInt(); 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 { result = (A & 0xff) + value + GetCarryFlag(); } 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 { 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(value & 0x80); SetOverflowFlag(value & 0x40); } else { uint16_t value = ReadWord(low, high, true); uint16_t result = A & value; SetZeroFlag(result == 0); SetNegativeFlag(value & 0x8000); SetOverflowFlag(value & 0x4000); } } void Cpu::Lda(uint32_t low, uint32_t high) { if (GetAccumulatorSize()) { CheckInt(); 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 { uint16_t value = ReadWord(low, high, true); A |= value; SetZeroFlag(A == 0); SetNegativeFlag(A & 0x8000); } } } // namespace emu } // namespace app } // namespace yaze