Files
yaze/src/app/emu/cpu/cpu.cc
2024-12-31 21:00:27 -05:00

2263 lines
54 KiB
C++

#include "cpu.h"
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
#include "app/emu/cpu/internal/opcodes.h"
namespace yaze {
namespace emu {
void Cpu::Reset(bool hard) {
if (hard) {
A = 0;
X = 0;
Y = 0;
PC = 0;
PB = 0;
D = 0;
DB = 0;
E = 1;
status = 0x34;
irq_wanted_ = false;
}
reset_wanted_ = true;
stopped_ = false;
waiting_ = false;
nmi_wanted_ = false;
int_wanted_ = false;
int_delay_ = false;
}
void Cpu::RunOpcode() {
if (reset_wanted_) {
reset_wanted_ = false;
// reset: brk/interrupt without writes
auto sp = SP();
ReadByte((PB << 16) | PC);
callbacks_.idle(false);
ReadByte(0x100 | (sp-- & 0xff));
ReadByte(0x100 | (sp-- & 0xff));
ReadByte(0x100 | (sp-- & 0xff));
sp = (sp & 0xff) | 0x100;
SetSP(sp);
E = 1;
SetInterruptFlag(true);
SetDecimalFlag(false);
SetFlags(status); // updates x and m flags, clears
// upper half of x and y if needed
PB = 0;
PC = ReadWord(0xfffc, 0xfffd);
return;
}
if (stopped_) {
callbacks_.idle(true);
return;
}
if (waiting_) {
if (irq_wanted_ || nmi_wanted_) {
waiting_ = false;
callbacks_.idle(false);
CheckInt();
callbacks_.idle(false);
return;
} else {
callbacks_.idle(true);
return;
}
}
// not stopped or waiting, execute a opcode or go to interrupt
if (int_wanted_) {
ReadByte((PB << 16) | PC);
DoInterrupt();
} else {
uint8_t opcode = ReadOpcode();
ExecuteInstruction(opcode);
}
}
void Cpu::DoInterrupt() {
callbacks_.idle(false);
PushByte(PB);
PushWord(PC);
PushByte(status);
SetInterruptFlag(true);
SetDecimalFlag(false);
PB = 0;
int_wanted_ = false;
if (nmi_wanted_) {
nmi_wanted_ = false;
PC = ReadWord(0xffea, 0xffeb);
} else { // irq
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 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 0x01: { // ora idx
uint32_t low = 0;
uint32_t high = AdrIdx(&low);
ORA(low, high);
break;
}
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 0x03: { // ora sr
uint32_t low = 0;
uint32_t high = AdrSr(&low);
ORA(low, high);
break;
}
case 0x04: { // tsb dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Tsb(low, high);
break;
}
case 0x05: { // ora dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
ORA(low, high);
break;
}
case 0x06: { // asl dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Asl(low, high);
break;
}
case 0x07: { // ora idl
uint32_t low = 0;
uint32_t high = AdrIdl(&low);
ORA(low, high);
break;
}
case 0x08: { // php imp
callbacks_.idle(false);
CheckInt();
PushByte(status);
break;
}
case 0x09: { // ora imm(m)
uint32_t low = 0;
uint32_t high = Immediate(&low, false);
ORA(low, high);
break;
}
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 0x0b: { // phd imp
callbacks_.idle(false);
PushWord(D, true);
break;
}
case 0x0c: { // tsb abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Tsb(low, high);
break;
}
case 0x0d: { // ora abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
ORA(low, high);
break;
}
case 0x0e: { // asl abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Asl(low, high);
break;
}
case 0x0f: { // ora abl
uint32_t low = 0;
uint32_t high = AdrAbl(&low);
ORA(low, high);
break;
}
case 0x10: { // bpl rel
DoBranch(!GetNegativeFlag());
break;
}
case 0x11: { // ora idy(r)
uint32_t low = 0;
uint32_t high = AdrIdy(&low, false);
ORA(low, high);
break;
}
case 0x12: { // ora idp
uint32_t low = 0;
uint32_t high = AdrIdp(&low);
ORA(low, high);
break;
}
case 0x13: { // ora isy
uint32_t low = 0;
uint32_t high = AdrIsy(&low);
ORA(low, high);
break;
}
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 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 0x71: { // adc idy(r)
uint32_t low = 0;
uint32_t high = AdrIdy(&low, false);
Adc(low, high);
break;
}
case 0x72: { // adc idp
uint32_t low = 0;
uint32_t high = AdrIdp(&low);
Adc(low, high);
break;
}
case 0x73: { // adc isy
uint32_t low = 0;
uint32_t high = AdrIsy(&low);
Adc(low, high);
break;
}
case 0x74: { // stz dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Stz(low, high);
break;
}
case 0x75: { // adc dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Adc(low, high);
break;
}
case 0x76: { // ror dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Ror(low, high);
break;
}
case 0x77: { // adc ily
uint32_t low = 0;
uint32_t high = AdrIly(&low);
Adc(low, high);
break;
}
case 0x78: { // sei imp
AdrImp();
SetInterruptFlag(true);
break;
}
case 0x79: { // adc aby(r)
uint32_t low = 0;
uint32_t high = AdrAby(&low, false);
Adc(low, high);
break;
}
case 0x7a: { // ply imp
callbacks_.idle(false);
callbacks_.idle(false);
if (GetIndexSize()) {
CheckInt();
Y = PopByte();
} else {
Y = PopWord(true);
}
SetZN(Y, GetIndexSize());
break;
}
case 0x7b: { // tdc imp
AdrImp();
A = D;
SetZN(A, false);
break;
}
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 0x7d: { // adc abx(r)
uint32_t low = 0;
uint32_t high = AdrAbx(&low, false);
Adc(low, high);
break;
}
case 0x7e: { // ror abx
uint32_t low = 0;
uint32_t high = AdrAbx(&low, true);
Ror(low, high);
break;
}
case 0x7f: { // adc alx
uint32_t low = 0;
uint32_t high = AdrAlx(&low);
Adc(low, high);
break;
}
case 0x80: { // bra rel
DoBranch(true);
break;
}
case 0x81: { // sta idx
uint32_t low = 0;
uint32_t high = AdrIdx(&low);
Sta(low, high);
break;
}
case 0x82: { // brl rll
PC += (int16_t)ReadOpcodeWord(false);
CheckInt();
callbacks_.idle(false);
break;
}
case 0x83: { // sta sr
uint32_t low = 0;
uint32_t high = AdrSr(&low);
Sta(low, high);
break;
}
case 0x84: { // sty dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Sty(low, high);
break;
}
case 0x85: { // sta dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Sta(low, high);
break;
}
case 0x86: { // stx dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Stx(low, high);
break;
}
case 0x87: { // sta idl
uint32_t low = 0;
uint32_t high = AdrIdl(&low);
Sta(low, high);
break;
}
case 0x88: { // dey imp
AdrImp();
if (GetIndexSize()) {
Y = (Y - 1) & 0xff;
} else {
Y--;
}
SetZN(Y, GetIndexSize());
break;
}
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 0x8a: { // txa imp
AdrImp();
if (GetAccumulatorSize()) {
A = (A & 0xff00) | (X & 0xff);
} else {
A = X;
}
SetZN(A, GetAccumulatorSize());
break;
}
case 0x8b: { // phb imp
callbacks_.idle(false);
CheckInt();
PushByte(DB);
break;
}
case 0x8c: { // sty abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Sty(low, high);
break;
}
case 0x8d: { // sta abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Sta(low, high);
break;
}
case 0x8e: { // stx abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Stx(low, high);
break;
}
case 0x8f: { // sta abl
uint32_t low = 0;
uint32_t high = AdrAbl(&low);
Sta(low, high);
break;
}
case 0x90: { // bcc rel
DoBranch(!GetCarryFlag());
break;
}
case 0x91: { // sta idy
uint32_t low = 0;
uint32_t high = AdrIdy(&low, true);
Sta(low, high);
break;
}
case 0x92: { // sta idp
uint32_t low = 0;
uint32_t high = AdrIdp(&low);
Sta(low, high);
break;
}
case 0x93: { // sta isy
uint32_t low = 0;
uint32_t high = AdrIsy(&low);
Sta(low, high);
break;
}
case 0x94: { // sty dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Sty(low, high);
break;
}
case 0x95: { // sta dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Sta(low, high);
break;
}
case 0x96: { // stx dpy
uint32_t low = 0;
uint32_t high = AdrDpy(&low);
Stx(low, high);
break;
}
case 0x97: { // sta ily
uint32_t low = 0;
uint32_t high = AdrIly(&low);
Sta(low, high);
break;
}
case 0x98: { // tya imp
AdrImp();
if (GetAccumulatorSize()) {
A = (A & 0xff00) | (Y & 0xff);
} else {
A = Y;
}
SetZN(A, GetAccumulatorSize());
break;
}
case 0x99: { // sta aby
uint32_t low = 0;
uint32_t high = AdrAby(&low, true);
Sta(low, high);
break;
}
case 0x9a: { // txs imp
AdrImp();
SetSP(X);
break;
}
case 0x9b: { // txy imp
AdrImp();
if (GetIndexSize()) {
Y = X & 0xff;
} else {
Y = X;
}
SetZN(Y, GetIndexSize());
break;
}
case 0x9c: { // stz abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Stz(low, high);
break;
}
case 0x9d: { // sta abx
uint32_t low = 0;
uint32_t high = AdrAbx(&low, true);
Sta(low, high);
break;
}
case 0x9e: { // stz abx
uint32_t low = 0;
uint32_t high = AdrAbx(&low, true);
Stz(low, high);
break;
}
case 0x9f: { // sta alx
uint32_t low = 0;
uint32_t high = AdrAlx(&low);
Sta(low, high);
break;
}
case 0xa0: { // ldy imm(x)
uint32_t low = 0;
uint32_t high = Immediate(&low, true);
Ldy(low, high);
break;
}
case 0xa1: { // lda idx
uint32_t low = 0;
uint32_t high = AdrIdx(&low);
Lda(low, high);
break;
}
case 0xa2: { // ldx imm(x)
uint32_t low = 0;
uint32_t high = Immediate(&low, true);
Ldx(low, high);
break;
}
case 0xa3: { // lda sr
uint32_t low = 0;
uint32_t high = AdrSr(&low);
Lda(low, high);
break;
}
case 0xa4: { // ldy dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Ldy(low, high);
break;
}
case 0xa5: { // lda dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Lda(low, high);
break;
}
case 0xa6: { // ldx dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Ldx(low, high);
break;
}
case 0xa7: { // lda idl
uint32_t low = 0;
uint32_t high = AdrIdl(&low);
Lda(low, high);
break;
}
case 0xa8: { // tay imp
AdrImp();
if (GetIndexSize()) {
Y = A & 0xff;
} else {
Y = A;
}
SetZN(Y, GetIndexSize());
break;
}
case 0xa9: { // lda imm(m)
uint32_t low = 0;
uint32_t high = Immediate(&low, false);
Lda(low, high);
break;
}
case 0xaa: { // tax imp
AdrImp();
if (GetIndexSize()) {
X = A & 0xff;
} else {
X = A;
}
SetZN(X, GetIndexSize());
break;
}
case 0xab: { // plb imp
callbacks_.idle(false);
callbacks_.idle(false);
CheckInt();
DB = PopByte();
SetZN(DB, true);
break;
}
case 0xac: { // ldy abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Ldy(low, high);
break;
}
case 0xad: { // lda abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Lda(low, high);
break;
}
case 0xae: { // ldx abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Ldx(low, high);
break;
}
case 0xaf: { // lda abl
uint32_t low = 0;
uint32_t high = AdrAbl(&low);
Lda(low, high);
break;
}
case 0xb0: { // bcs rel
DoBranch(GetCarryFlag());
break;
}
case 0xb1: { // lda idy(r)
uint32_t low = 0;
uint32_t high = AdrIdy(&low, false);
Lda(low, high);
break;
}
case 0xb2: { // lda idp
uint32_t low = 0;
uint32_t high = AdrIdp(&low);
Lda(low, high);
break;
}
case 0xb3: { // lda isy
uint32_t low = 0;
uint32_t high = AdrIsy(&low);
Lda(low, high);
break;
}
case 0xb4: { // ldy dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Ldy(low, high);
break;
}
case 0xb5: { // lda dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Lda(low, high);
break;
}
case 0xb6: { // ldx dpy
uint32_t low = 0;
uint32_t high = AdrDpy(&low);
Ldx(low, high);
break;
}
case 0xb7: { // lda ily
uint32_t low = 0;
uint32_t high = AdrIly(&low);
Lda(low, high);
break;
}
case 0xb8: { // clv imp
AdrImp();
SetOverflowFlag(false);
break;
}
case 0xb9: { // lda aby(r)
uint32_t low = 0;
uint32_t high = AdrAby(&low, false);
Lda(low, high);
break;
}
case 0xba: { // tsx imp
AdrImp();
if (GetIndexSize()) {
SetSP(X & 0xff);
} else {
SetSP(X);
}
SetZN(X, GetIndexSize());
break;
}
case 0xbb: { // tyx imp
AdrImp();
if (GetIndexSize()) {
X = Y & 0xff;
} else {
X = Y;
}
SetZN(X, GetIndexSize());
break;
}
case 0xbc: { // ldy abx(r)
uint32_t low = 0;
uint32_t high = AdrAbx(&low, false);
Ldy(low, high);
break;
}
case 0xbd: { // lda abx(r)
uint32_t low = 0;
uint32_t high = AdrAbx(&low, false);
Lda(low, high);
break;
}
case 0xbe: { // ldx aby(r)
uint32_t low = 0;
uint32_t high = AdrAby(&low, false);
Ldx(low, high);
break;
}
case 0xbf: { // lda alx
uint32_t low = 0;
uint32_t high = AdrAlx(&low);
Lda(low, high);
break;
}
case 0xc0: { // cpy imm(x)
uint32_t low = 0;
uint32_t high = Immediate(&low, true);
Cpy(low, high);
break;
}
case 0xc1: { // cmp idx
uint32_t low = 0;
uint32_t high = AdrIdx(&low);
Cmp(low, high);
break;
}
case 0xc2: { // rep imm(s)
uint8_t val = ReadOpcode();
CheckInt();
SetFlags(status & ~val);
callbacks_.idle(false);
break;
}
case 0xc3: { // cmp sr
uint32_t low = 0;
uint32_t high = AdrSr(&low);
Cmp(low, high);
break;
}
case 0xc4: { // cpy dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Cpy(low, high);
break;
}
case 0xc5: { // cmp dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Cmp(low, high);
break;
}
case 0xc6: { // dec dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Dec(low, high);
break;
}
case 0xc7: { // cmp idl
uint32_t low = 0;
uint32_t high = AdrIdl(&low);
Cmp(low, high);
break;
}
case 0xc8: { // iny imp
AdrImp();
if (GetIndexSize()) {
Y = (Y + 1) & 0xff;
} else {
Y++;
}
SetZN(Y, GetIndexSize());
break;
}
case 0xc9: { // cmp imm(m)
uint32_t low = 0;
uint32_t high = Immediate(&low, false);
Cmp(low, high);
break;
}
case 0xca: { // dex imp
AdrImp();
if (GetIndexSize()) {
X = (X - 1) & 0xff;
} else {
X--;
}
SetZN(X, GetIndexSize());
break;
}
case 0xcb: { // wai imp
waiting_ = true;
callbacks_.idle(false);
callbacks_.idle(false);
break;
}
case 0xcc: { // cpy abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Cpy(low, high);
break;
}
case 0xcd: { // cmp abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Cmp(low, high);
break;
}
case 0xce: { // dec abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Dec(low, high);
break;
}
case 0xcf: { // cmp abl
uint32_t low = 0;
uint32_t high = AdrAbl(&low);
Cmp(low, high);
break;
}
case 0xd0: { // bne rel
DoBranch(!GetZeroFlag());
break;
}
case 0xd1: { // cmp idy(r)
uint32_t low = 0;
uint32_t high = AdrIdy(&low, false);
Cmp(low, high);
break;
}
case 0xd2: { // cmp idp
uint32_t low = 0;
uint32_t high = AdrIdp(&low);
Cmp(low, high);
break;
}
case 0xd3: { // cmp isy
uint32_t low = 0;
uint32_t high = AdrIsy(&low);
Cmp(low, high);
break;
}
case 0xd4: { // pei dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
PushWord(ReadWord(low, high, false), true);
break;
}
case 0xd5: { // cmp dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Cmp(low, high);
break;
}
case 0xd6: { // dec dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Dec(low, high);
break;
}
case 0xd7: { // cmp ily
uint32_t low = 0;
uint32_t high = AdrIly(&low);
Cmp(low, high);
break;
}
case 0xd8: { // cld imp
AdrImp();
SetDecimalFlag(false);
break;
}
case 0xd9: { // cmp aby(r)
uint32_t low = 0;
uint32_t high = AdrAby(&low, false);
Cmp(low, high);
break;
}
case 0xda: { // phx imp
callbacks_.idle(false);
if (GetIndexSize()) {
CheckInt();
PushByte(X);
} else {
PushWord(X, true);
}
break;
}
case 0xdb: { // stp imp
stopped_ = true;
callbacks_.idle(false);
callbacks_.idle(false);
break;
}
case 0xdc: { // jml ial
uint16_t adr = ReadOpcodeWord(false);
PC = ReadWord(adr, ((adr + 1) & 0xffff), false);
CheckInt();
PB = ReadByte((adr + 2) & 0xffff);
break;
}
case 0xdd: { // cmp abx(r)
uint32_t low = 0;
uint32_t high = AdrAbx(&low, false);
Cmp(low, high);
break;
}
case 0xde: { // dec abx
uint32_t low = 0;
uint32_t high = AdrAbx(&low, true);
Dec(low, high);
break;
}
case 0xdf: { // cmp alx
uint32_t low = 0;
uint32_t high = AdrAlx(&low);
Cmp(low, high);
break;
}
case 0xe0: { // cpx imm(x)
uint32_t low = 0;
uint32_t high = Immediate(&low, true);
Cpx(low, high);
break;
}
case 0xe1: { // sbc idx
uint32_t low = 0;
uint32_t high = AdrIdx(&low);
Sbc(low, high);
break;
}
case 0xe2: { // sep imm(s)
uint8_t val = ReadOpcode();
CheckInt();
SetFlags(status | val);
callbacks_.idle(false);
break;
}
case 0xe3: { // sbc sr
uint32_t low = 0;
uint32_t high = AdrSr(&low);
Sbc(low, high);
break;
}
case 0xe4: { // cpx dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Cpx(low, high);
break;
}
case 0xe5: { // sbc dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Sbc(low, high);
break;
}
case 0xe6: { // inc dp
uint32_t low = 0;
uint32_t high = AdrDp(&low);
Inc(low, high);
break;
}
case 0xe7: { // sbc idl
uint32_t low = 0;
uint32_t high = AdrIdl(&low);
Sbc(low, high);
break;
}
case 0xe8: { // inx imp
AdrImp();
if (GetIndexSize()) {
X = (X + 1) & 0xff;
} else {
X++;
}
SetZN(X, GetIndexSize());
break;
}
case 0xe9: { // sbc imm(m)
uint32_t low = 0;
uint32_t high = Immediate(&low, false);
Sbc(low, high);
break;
}
case 0xea: { // nop imp
AdrImp();
// no operation
break;
}
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 0xec: { // cpx abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Cpx(low, high);
break;
}
case 0xed: { // sbc abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Sbc(low, high);
break;
}
case 0xee: { // inc abs
uint32_t low = 0;
uint32_t high = Absolute(&low);
Inc(low, high);
break;
}
case 0xef: { // sbc abl
uint32_t low = 0;
uint32_t high = AdrAbl(&low);
Sbc(low, high);
break;
}
case 0xf0: { // beq rel
DoBranch(GetZeroFlag());
break;
}
case 0xf1: { // sbc idy(r)
uint32_t low = 0;
uint32_t high = AdrIdy(&low, false);
Sbc(low, high);
break;
}
case 0xf2: { // sbc idp
uint32_t low = 0;
uint32_t high = AdrIdp(&low);
Sbc(low, high);
break;
}
case 0xf3: { // sbc isy
uint32_t low = 0;
uint32_t high = AdrIsy(&low);
Sbc(low, high);
break;
}
case 0xf4: { // pea imm(l)
PushWord(ReadOpcodeWord(false), true);
break;
}
case 0xf5: { // sbc dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Sbc(low, high);
break;
}
case 0xf6: { // inc dpx
uint32_t low = 0;
uint32_t high = AdrDpx(&low);
Inc(low, high);
break;
}
case 0xf7: { // sbc ily
uint32_t low = 0;
uint32_t high = AdrIly(&low);
Sbc(low, high);
break;
}
case 0xf8: { // sed imp
AdrImp();
SetDecimalFlag(true);
break;
}
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;
}
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(cache_pc, opcode, operand, immediate, accumulator_mode);
}
// instruction_length = GetInstructionLength(opcode);
// UpdatePC(instruction_length);
}
void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
bool immediate, bool accumulator_mode) {
if (core::ExperimentFlags::get().kLogInstructions) {
std::ostringstream oss;
oss << "$" << std::uppercase << std::setw(2) << std::setfill('0')
<< static_cast<int>(PB) << ":" << std::hex << PC << ": 0x"
<< std::setw(2) << std::setfill('0') << std::hex
<< static_cast<int>(opcode) << " " << opcode_to_mnemonic.at(opcode)
<< " ";
// Log the operand.
std::string ops;
if (operand) {
if (immediate) {
ops += "#";
}
std::ostringstream oss_ops;
oss_ops << "$";
if (accumulator_mode) {
oss_ops << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(operand);
} else {
oss_ops << std::hex << std::setw(4) << std::setfill('0')
<< static_cast<int>(operand);
}
ops = oss_ops.str();
}
oss << ops << std::endl;
InstructionEntry entry(PC, opcode, ops, oss.str());
instruction_log_.push_back(entry);
} else {
// Log the address and opcode.
std::cout << "\033[1;36m"
<< "$" << std::uppercase << std::setw(2) << std::setfill('0')
<< static_cast<int>(PB) << ":" << std::hex << PC;
std::cout << " \033[1;32m"
<< ": 0x" << std::hex << std::uppercase << std::setw(2)
<< std::setfill('0') << static_cast<int>(opcode) << " ";
std::cout << " \033[1;35m" << opcode_to_mnemonic.at(opcode) << " "
<< "\033[0m";
// Log the operand.
if (operand) {
if (immediate) {
std::cout << "#";
}
std::cout << "$";
if (accumulator_mode) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << operand;
} else {
std::cout << std::hex << std::setw(4) << std::setfill('0')
<< static_cast<int>(operand);
}
bool x_indexing, y_indexing;
auto x_indexed_instruction_opcodes = {0x15, 0x16, 0x17, 0x55, 0x56,
0x57, 0xD5, 0xD6, 0xD7, 0xF5,
0xF6, 0xF7, 0xBD};
auto y_indexed_instruction_opcodes = {0x19, 0x97, 0x1D, 0x59, 0x5D, 0x99,
0x9D, 0xB9, 0xD9, 0xDD, 0xF9, 0xFD};
if (std::find(x_indexed_instruction_opcodes.begin(),
x_indexed_instruction_opcodes.end(),
opcode) != x_indexed_instruction_opcodes.end()) {
x_indexing = true;
} else {
x_indexing = false;
}
if (std::find(y_indexed_instruction_opcodes.begin(),
y_indexed_instruction_opcodes.end(),
opcode) != y_indexed_instruction_opcodes.end()) {
y_indexing = true;
} else {
y_indexing = false;
}
if (x_indexing) {
std::cout << ", X";
}
if (y_indexing) {
std::cout << ", Y";
}
}
// Log the registers and flags.
std::cout << std::right;
std::cout << "\033[1;33m"
<< " A:" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(A);
std::cout << " X:" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(X);
std::cout << " Y:" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(Y);
std::cout << " S:" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(status);
std::cout << " DB:" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(DB);
std::cout << " D:" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(D);
std::cout << " SP:" << std::hex << std::setw(4) << std::setfill('0')
<< SP();
std::cout << std::endl;
}
}
/**
uint8_t Cpu::GetInstructionLength(uint8_t opcode) {
switch (opcode) {
case 0x00: // BRK
case 0x02: // COP
PC = next_pc_;
PB = next_pb_;
return 0;
case 0x20: // JSR Absolute
case 0x4C: // JMP Absolute
case 0x6C: // JMP Absolute Indirect
case 0x7C: // JMP Absolute Indexed Indirect
case 0xFC: // JSR Absolute Indexed Indirect
case 0xDC: // JMP Absolute Indirect Long
case 0x6B: // RTL
case 0x82: // BRL Relative Long
PC = next_pc_;
return 0;
case 0x22: // JSL Absolute Long
case 0x5C: // JMP Absolute Indexed Indirect
PC = next_pc_;
PB = next_pb_;
return 0;
case 0x80: // BRA Relative
PC += next_pc_;
return 2;
case 0x60: // RTS
PC = last_call_frame_;
return 3;
// Branch Instructions (BCC, BCS, BNE, BEQ, etc.)
case 0x90: // BCC near
if (!GetCarryFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0xB0: // BCS near
if (GetCarryFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x30: // BMI near
if (GetNegativeFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0xF0: // BEQ near
if (GetZeroFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0xD0: // BNE Relative
if (!GetZeroFlag()) {
PC += next_pc_;
}
return 2;
case 0x10: // BPL Relative
if (!GetNegativeFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x50: // BVC Relative
if (!GetOverflowFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x70: // BVS Relative
if (GetOverflowFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x18: // CLC
case 0xD8: // CLD
case 0x58: // CLI
case 0xB8: // CLV
case 0xCA: // DEX
case 0x88: // DEY
case 0xE8: // INX
case 0xC8: // INY
case 0xEA: // NOP
case 0x48: // PHA
case 0x8B: // PHB
case 0x0B: // PHD
case 0x4B: // PHK
case 0x08: // PHP
case 0xDA: // PHX
case 0x5A: // PHY
case 0x68: // PLA
case 0xAB: // PLB
case 0x2B: // PLD
case 0x28: // PLP
case 0xFA: // PLX
case 0x7A: // PLY
case 0x40: // RTI
case 0x38: // SEC
case 0xF8: // SED
case 0xBB: // TYX
case 0x78: // SEI
case 0xAA: // TAX
case 0xA8: // TAY
case 0xBA: // TSX
case 0x8A: // TXA
case 0x9B: // TXY
case 0x9A: // TXS
case 0x98: // TYA
case 0x0A: // ASL Accumulator
case 0x2A: // ROL Accumulator
case 0xFB: // XCE
case 0x5B: // TCD
case 0x1B: // TCS
case 0x3A: // DEC Accumulator
case 0x1A: // INC Accumulator
case 0x7B: // TDC
case 0x3B: // TSC
case 0xEB: // XBA
case 0xCB: // WAI
case 0xDB: // STP
case 0x4A: // LSR Accumulator
case 0x6A: // ROR Accumulator
return 1;
case 0xC2: // REP
case 0xE2: // SEP
case 0xE4: // CPX Direct Page
case 0xC4: // CPY Direct Page
case 0xD6: // DEC Direct Page Indexed, X
case 0x45: // EOR Direct Page
case 0xA5: // LDA Direct Page
case 0x05: // ORA Direct Page
case 0x85: // STA Direct Page
case 0xC6: // DEC Direct Page
case 0x97: // STA Direct Page Indexed Y
case 0x25: // AND Direct Page
case 0x32: // AND Direct Page Indirect Indexed Y
case 0x27: // AND Direct Page Indirect Long
case 0x35: // AND Direct Page Indexed X
case 0x21: // AND Direct Page Indirect Indexed Y
case 0x31: // AND Direct Page Indirect Long Indexed Y
case 0x37: // AND Direct Page Indirect Long Indexed Y
case 0x23: // AND Direct Page Indirect Indexed X
case 0x33: // AND Direct Page Indirect Long Indexed Y
case 0xE6: // INC Direct Page
case 0x81: // STA Direct Page Indirect, X
case 0x01: // ORA Direct Page Indirect, X
case 0x19: // ORA Direct Page Indirect Indexed, Y
case 0x1D: // ORA Absolute Indexed, X
case 0x89: // BIT Immediate
case 0x91: // STA Direct Page Indirect Indexed, Y
case 0x65: // ADC Direct Page
case 0x72: // ADC Direct Page Indirect
case 0x67: // ADC Direct Page Indirect Long
case 0x75: // ADC Direct Page Indexed, X
case 0x61: // ADC Direct Page Indirect, X
case 0x71: // ADC DP Indirect Indexed, Y
case 0x77: // ADC DP Indirect Long Indexed, Y
case 0x63: // ADC Stack Relative
case 0x73: // ADC SR Indirect Indexed, Y
case 0x06: // ASL Direct Page
case 0x16: // ASL Direct Page Indexed, X
case 0xB2: // LDA Direct Page Indirect
case 0x57: // EOR Direct Page Indirect Long Indexed, Y
case 0xC1: // CMP Direct Page Indexed Indirect, X
case 0xC3: // CMP Stack Relative
case 0xC5: // CMP Direct Page
case 0x47: // EOR Direct Page Indirect Long
case 0x55: // EOR Direct Page Indexed, X
case 0x41: // EOR Direct Page Indirect, X
case 0x51: // EOR Direct Page Indirect Indexed, Y
case 0x43: // EOR Direct Page Indirect Indexed, X
case 0x53: // EOR Direct Page Indirect Long Indexed, Y
case 0xA1: // LDA Direct Page Indexed Indirect, X
case 0xA3: // LDA Stack Relative
case 0xA7: // LDA Direct Page Indirect Long
case 0xB5: // LDA Direct Page Indexed, X
case 0xB1: // LDA Direct Page Indirect Indexed, Y
case 0xB7: // LDA Direct Page Indirect Long Indexed, Y
case 0xB3: // LDA Direct Page Indirect Indexed, X
case 0xB6: // LDX Direct Page Indexed, Y
case 0xB4: // LDY Direct Page Indexed, X
case 0x46: // LSR Direct Page
case 0x56: // LSR Direct Page Indexed, X
case 0xE1: // SBC Direct Page Indexed Indirect, X
case 0xE3: // SBC Stack Relative
case 0xE5: // SBC Direct Page
case 0xE7: // SBC Direct Page Indirect Long
case 0xF2: // SBC Direct Page Indirect
case 0xF1: // SBC Direct Page Indirect Indexed, Y
case 0xF3: // SBC SR Indirect Indexed, Y
case 0xF5: // SBC Direct Page Indexed, X
case 0xF7: // SBC Direct Page Indirect Long Indexed, Y
case 0xF6: // INC Direct Page Indexed, X
case 0x86: // STX Direct Page
case 0x84: // STY Direct Page
case 0x64: // STZ Direct Page
case 0x74: // STZ Direct Page Indexed, X
case 0x04: // TSB Direct Page
case 0x14: // TRB Direct Page
case 0x44: // MVN
case 0x54: // MVP
case 0x24: // BIT Direct Page
case 0x34: // BIT Direct Page Indexed, X
case 0x94: // STY Direct Page Indexed, X
case 0x87: // STA Direct Page Indirect Long
case 0x92: // STA Direct Page Indirect
case 0x93: // STA SR Indirect Indexed, Y
case 0x95: // STA Direct Page Indexed, X
case 0x96: // STX Direct Page Indexed, Y
case 0xC7: // CMP Direct Page Indirect Long
case 0xD7: // CMP DP Indirect Long Indexed, Y
case 0xD2: // CMP DP Indirect
case 0xD1: // CMP DP Indirect Indexed, Y
case 0x03: // ORA Stack Relative
case 0x13: // ORA SR Indirect Indexed, Y
case 0x07: // ORA Direct Page Indirect Long
case 0x11: // ORA DP Indirect Indexed, Y
case 0x12: // ORA DP Indirect
case 0x15: // ORA DP Indexed, X
case 0x17: // ORA DP Indirect Long Indexed, Y
case 0x26: // ROL Direct Page
case 0x36: // ROL Direct Page Indexed, X
case 0x66: // ROR Direct Page
case 0x76: // ROR Direct Page Indexed, X
case 0x42: // WDM
case 0xD3: // CMP Stack Relative Indirect Indexed, Y
case 0x52: // EOR Direct Page Indirect
case 0xA4: // LDA Direct Page
case 0xA6: // LDX Direct Page
case 0xD4: // PEI
return 2;
case 0x69: // ADC Immediate
case 0x29: // AND Immediate
case 0xC9: // CMP Immediate
case 0x49: // EOR Immediate
case 0xA9: // LDA Immediate
case 0x09: // ORA Immediate
case 0xE9: // SBC Immediate
return GetAccumulatorSize() ? 2 : 3;
case 0xE0: // CPX Immediate
case 0xC0: // CPY Immediate
case 0xA2: // LDX Immediate
case 0xA0: // LDY Immediate
return GetIndexSize() ? 2 : 3;
case 0x0E: // ASL Absolute
case 0x1E: // ASL Absolute Indexed, X
case 0x2D: // AND Absolute
case 0xCD: // CMP Absolute
case 0xEC: // CPX Absolute
case 0xCC: // CPY Absolute
case 0x4D: // EOR Absolute
case 0xAD: // LDA Absolute
case 0xAE: // LDX Absolute
case 0xAC: // LDY Absolute
case 0x0D: // ORA Absolute
case 0xED: // SBC Absolute
case 0x8D: // STA Absolute
case 0x8E: // STX Absolute
case 0x8C: // STY Absolute
case 0xBD: // LDA Absolute Indexed X
case 0xBC: // LDY Absolute Indexed X
case 0x3D: // AND Absolute Indexed X
case 0x39: // AND Absolute Indexed Y
case 0x9C: // STZ Absolute Indexed X
case 0x9D: // STA Absolute Indexed X
case 0x99: // STA Absolute Indexed Y
case 0x3C: // BIT Absolute Indexed X
case 0x7D: // ADC Absolute Indexed, X
case 0x79: // ADC Absolute Indexed, Y
case 0x6D: // ADC Absolute
case 0x5D: // EOR Absolute Indexed, X
case 0x59: // EOR Absolute Indexed, Y
case 0x83: // STA Stack Relative Indirect Indexed, Y
case 0xCE: // DEC Absolute
case 0xD5: // CMP DP Indexed, X
case 0xD9: // CMP Absolute Indexed, Y
case 0xDD: // CMP Absolute Indexed, X
case 0x0C: // TSB Absolute
case 0x1C: // TRB Absolute
case 0xF9: // SBC Absolute Indexed, Y
case 0xFD: // SBC Absolute Indexed, X
case 0x2C: // BIT Absolute
case 0x2E: // ROL Absolute
case 0x3E: // ROL Absolute Indexed, X
case 0x4E: // LSR Absolute
case 0x5E: // LSR Absolute Indexed, X
case 0xDE: // DEC Absolute Indexed, X
case 0xEE: // INC Absolute
case 0xB9: // LDA Absolute Indexed, Y
case 0xBE: // LDX Absolute Indexed, Y
case 0xFE: // INC Absolute Indexed, X
case 0xF4: // PEA
case 0x62: // PER
case 0x6E: // ROR Absolute
case 0x7E: // ROR Absolute Indexed, X
return 3;
case 0x6F: // ADC Absolute Long
case 0x2F: // AND Absolute Long
case 0xCF: // CMP Absolute Long
case 0x4F: // EOR Absolute Long
case 0xAF: // LDA Absolute Long
case 0x0F: // ORA Absolute Long
case 0xEF: // SBC Absolute Long
case 0x8F: // STA Absolute Long
case 0x7F: // ADC Absolute Long Indexed, X
case 0x3F: // AND Absolute Long Indexed, X
case 0xDF: // CMP Absolute Long Indexed, X
case 0x5F: // EOR Absolute Long Indexed, X
case 0x9F: // STA Absolute Long Indexed, X
case 0x1F: // ORA Absolute Long Indexed, X
case 0xBF: // LDA Absolute Long Indexed, X
case 0x9E: // STZ Absolute Long Indexed, X
case 0xFF: // SBC Absolute Long Indexed, X
return 4;
default:
auto mnemonic = opcode_to_mnemonic.at(opcode);
std::cerr << "Unknown instruction length: " << std::hex
<< static_cast<int>(opcode) << ", " << mnemonic << std::endl;
throw std::runtime_error("Unknown instruction length");
return 1; // Default to 1 as a safe fallback
}
}
*/
} // namespace emu
} // namespace yaze