Files
yaze/src/app/emu/cpu/internal/instructions.cc
2024-04-25 00:22:38 -04:00

402 lines
11 KiB
C++

#include <iostream>
#include <string>
#include <vector>
#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