402 lines
11 KiB
C++
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
|