#include "cpu.h" #include #include #include #include #include #include "app/emu/cpu/internal/opcodes.h" namespace yaze { namespace app { 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 (flags()->kLogInstructions) { std::ostringstream oss; oss << "$" << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(PB) << ":" << std::hex << PC << ": 0x" << std::setw(2) << std::setfill('0') << std::hex << static_cast(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(operand); } else { oss_ops << std::hex << std::setw(4) << std::setfill('0') << static_cast(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(PB) << ":" << std::hex << PC; std::cout << " \033[1;32m" << ": 0x" << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(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(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(A); std::cout << " X:" << std::hex << std::setw(2) << std::setfill('0') << static_cast(X); std::cout << " Y:" << std::hex << std::setw(2) << std::setfill('0') << static_cast(Y); std::cout << " S:" << std::hex << std::setw(2) << std::setfill('0') << static_cast(status); std::cout << " DB:" << std::hex << std::setw(2) << std::setfill('0') << static_cast(DB); std::cout << " D:" << std::hex << std::setw(2) << std::setfill('0') << static_cast(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(opcode) << ", " << mnemonic << std::endl; throw std::runtime_error("Unknown instruction length"); return 1; // Default to 1 as a safe fallback } } */ } // namespace emu } // namespace app } // namespace yaze