#include "cpu.h" #include #include #include namespace yaze { namespace app { namespace emu { uint8_t CPU::ReadByte(uint16_t addr) const { return memory.at(addr); // Read a byte from memory at the specified address } uint16_t CPU::ReadWord(uint16_t address) const { uint8_t low = ReadByte(address); uint8_t high = ReadByte(address + 1); return (high << 8) | low; } uint32_t CPU::ReadWordLong(uint16_t address) const { uint8_t low = ReadByte(address); uint8_t mid = ReadByte(address + 1); uint8_t high = ReadByte(address + 2); return (high << 16) | (mid << 8) | low; } uint8_t CPU::FetchByte() { uint8_t byte = memory.ReadWord(PC); // Read a byte from memory at PC PC++; // Increment the Program Counter return byte; } uint16_t CPU::FetchWord() { uint16_t value = memory.ReadWord(PC); PC += 2; return value; } uint32_t CPU::FetchLong() { uint32_t value = memory.ReadWordLong(PC); PC += 3; return value; } int8_t CPU::FetchSignedByte() { return static_cast(FetchByte()); } int16_t CPU::FetchSignedWord() { auto offset = static_cast(FetchWord()); return offset; } uint8_t CPU::FetchByteDirectPage(uint8_t operand) { // Calculate the effective address in the Direct Page uint16_t effectiveAddress = D + operand; // Fetch the byte from memory uint8_t fetchedByte = memory.ReadByte(effectiveAddress); PC++; // Increment the Program Counter return fetchedByte; } uint16_t CPU::DirectPageIndexedIndirectX() { uint8_t dp = FetchByte(); return ReadWord((dp + X) & 0xFF); } uint16_t CPU::StackRelative() { uint8_t sr = FetchByte(); return SP + sr; } uint16_t CPU::DirectPage() { return FetchByte(); } uint16_t CPU::DirectPageIndirectLong() { uint8_t dp = FetchByte(); return ReadWordLong(dp); } uint16_t CPU::Immediate() { return PC++; } uint16_t CPU::Absolute() { return FetchWord(); } uint16_t CPU::AbsoluteLong() { return FetchLong(); } uint16_t CPU::DirectPageIndirectIndexedY() { uint8_t dp = FetchByte(); return ReadWord(dp) + Y; } uint16_t CPU::DirectPageIndirect() { uint8_t dp = FetchByte(); return ReadWord(dp); } uint16_t CPU::StackRelativeIndirectIndexedY() { uint8_t sr = FetchByte(); return ReadWord(SP + sr) + Y; } uint16_t CPU::DirectPageIndexedX() { uint8_t dp = FetchByte(); return (dp + X) & 0xFF; } uint16_t CPU::DirectPageIndirectLongIndexedY() { uint8_t dp = FetchByte(); return ReadWordLong(dp) + Y; } uint16_t CPU::AbsoluteIndexedY() { return FetchWord() + Y; } uint16_t CPU::AbsoluteIndexedX() { return FetchWord() + X; } uint16_t CPU::AbsoluteLongIndexedX() { return FetchLong() + X; } void CPU::ExecuteInstruction(uint8_t opcode) { // uint8_t opcode = FetchByte(); uint8_t operand = -1; switch (opcode) { case 0x61: // ADC DP Indexed Indirect, X operand = memory.ReadByte(DirectPageIndexedIndirectX()); ADC(operand); break; case 0x63: // ADC Stack Relative operand = memory.ReadByte(StackRelative()); ADC(operand); break; case 0x65: // ADC Direct Page operand = FetchByteDirectPage(PC); ADC(operand); break; case 0x67: // ADC DP Indirect Long operand = memory.ReadByte(DirectPageIndirectLong()); ADC(operand); break; case 0x69: // ADC Immediate operand = memory.ReadByte(Immediate()); ADC(operand); break; case 0x6D: // ADC Absolute operand = memory.ReadByte(Absolute()); ADC(operand); break; case 0x6F: // ADC Absolute Long operand = memory.ReadByte(AbsoluteLong()); ADC(operand); break; case 0x71: // ADC DP Indirect Indexed, Y operand = memory.ReadByte(DirectPageIndirectIndexedY()); ADC(operand); break; case 0x72: // ADC DP Indirect operand = memory.ReadByte(DirectPageIndirect()); ADC(operand); break; case 0x73: // ADC SR Indirect Indexed, Y operand = memory.ReadByte(StackRelativeIndirectIndexedY()); ADC(operand); break; case 0x75: // ADC DP Indexed, X operand = memory.ReadByte(DirectPageIndexedX()); ADC(operand); break; case 0x77: // ADC DP Indirect Long Indexed, Y operand = memory.ReadByte(DirectPageIndirectLongIndexedY()); ADC(operand); break; case 0x79: // ADC Absolute Indexed, Y operand = memory.ReadByte(AbsoluteIndexedY()); ADC(operand); break; case 0x7D: // ADC Absolute Indexed, X operand = memory.ReadByte(AbsoluteIndexedX()); ADC(operand); break; case 0x7F: // ADC Absolute Long Indexed, X operand = memory.ReadByte(AbsoluteLongIndexedX()); ADC(operand); break; case 0x21: // AND DP Indexed Indirect, X // AND(); break; case 0x23: // AND Stack Relative // AND(); break; case 0x25: // AND Direct Page // AND(); break; case 0x27: // AND DP Indirect Long // AND(); break; case 0x29: // AND Immediate // AND(); break; case 0x2D: // AND Absolute // AND(); break; case 0x2F: // AND Absolute Long // AND(); break; case 0x31: // AND DP Indirect Indexed, Y // AND(); break; case 0x32: // AND DP Indirect // AND(); break; case 0x33: // AND SR Indirect Indexed, Y // AND(); break; case 0x35: // AND DP Indexed, X // AND(); break; case 0x37: // AND DP Indirect Long Indexed, Y // AND(); break; case 0x39: // AND Absolute Indexed, Y // AND(); break; case 0x3D: // AND Absolute Indexed, X // AND(); break; case 0x3F: // AND Absolute Long Indexed, X // AND(); break; case 0x06: // ASL Direct Page // ASL(); break; case 0x0A: // ASL Accumulator // ASL(); break; case 0x0E: // ASL Absolute // ASL(); break; case 0x16: // ASL DP Indexed, X // ASL(); break; case 0x1E: // ASL Absolute Indexed, X // ASL(); break; case 0x90: // BCC Branch if carry clear operand = memory.ReadByte(PC); BCC(operand); break; case 0xB0: // BCS Branch if carry set // BCS(); break; case 0xF0: // BEQ Branch if equal (zero set) operand = memory.ReadByte(PC); BEQ(operand); break; case 0x24: // BIT Direct Page // BIT(); break; case 0x2C: // BIT Absolute // BIT(); break; case 0x34: // BIT DP Indexed, X // BIT(); break; case 0x3C: // BIT Absolute Indexed, X // BIT(); break; case 0x89: // BIT Immediate // BIT(); break; case 0x30: // BMI Branch if minus (negative set) // BMI(); break; case 0xD0: // BNE Branch if not equal (zero clear) // BNE(); break; case 0x10: // BPL Branch if plus (negative clear) // BPL(); break; case 0x80: // BRA Branch always // BRA(); break; case 0x00: // BRK Break // BRK(); break; case 0x82: // BRL Branch always long PC += FetchSignedWord(); break; case 0x50: // BVC Branch if overflow clear // BVC(); break; case 0x70: // BVS Branch if overflow set // BVS(); break; case 0x18: // CLC Clear carry CLC(); break; case 0xD8: // CLD Clear decimal CLD(); break; case 0x58: // CLI Clear interrupt disable CLI(); break; case 0xB8: // CLV Clear overflow CLV(); break; case 0xC1: // CMP DP Indexed Indirect, X // CMP(); break; case 0xC3: // CMP Stack Relative // CMP(); break; case 0xC5: // CMP Direct Page // CMP(); break; case 0xC7: // CMP DP Indirect Long // CMP(); break; case 0xC9: // CMP Immediate // CMP(); break; case 0xCD: // CMP Absolute // CMP(); break; case 0xCF: // CMP Absolute Long // CMP(); break; case 0xD1: // CMP DP Indirect Indexed, Y // CMP(); break; case 0xD2: // CMP DP Indirect // CMP(); break; case 0xD3: // CMP SR Indirect Indexed, Y // CMP(); break; case 0xD5: // CMP DP Indexed, X // CMP(); break; case 0xD7: // CMP DP Indirect Long Indexed, Y // CMP(); break; case 0xD9: // CMP Absolute Indexed, Y // CMP(); break; case 0xDD: // CMP Absolute Indexed, X // CMP(); break; case 0xDF: // CMP Absolute Long Indexed, X // CMP(); break; case 0x02: // COP Coprocessor // COP(); break; case 0xE0: // CPX Immediate // CPX(); break; case 0xE4: // CPX Direct Page // CPX(); break; case 0xEC: // CPX Absolute // CPX(); break; case 0xC0: // CPY Immediate // CPY(); break; case 0xC4: // CPY Direct Page // CPY(); break; case 0xCC: // CPY Absolute // CPY(); break; case 0x3A: // DEC Accumulator // DEC(); break; case 0xC6: // DEC Direct Page // DEC(); break; case 0xCE: // DEC Absolute // DEC(); break; case 0xD6: // DEC DP Indexed, X // DEC(); break; case 0xDE: // DEC Absolute Indexed, X // DEC(); break; case 0xCA: // DEX Decrement X register // DEX(); break; case 0x88: // DEY Decrement Y register // DEY(); break; case 0x41: // EOR DP Indexed Indirect, X // EOR(); break; case 0x43: // EOR Stack Relative // EOR(); break; case 0x45: // EOR Direct Page // EOR(); break; case 0x47: // EOR DP Indirect Long // EOR(); break; case 0x49: // EOR Immediate // EOR(); break; case 0x4D: // EOR Absolute // EOR(); break; case 0x4F: // EOR Absolute Long // EOR(); break; case 0x51: // EOR DP Indirect Indexed, Y // EOR(); break; case 0x52: // EOR DP Indirect // EOR(); break; case 0x53: // EOR SR Indirect Indexed, Y // EOR(); break; case 0x55: // EOR DP Indexed, X // EOR(); break; case 0x57: // EOR DP Indirect Long Indexed, Y // EOR(); break; case 0x59: // EOR Absolute Indexed, Y // EOR(); break; case 0x5D: // EOR Absolute Indexed, X // EOR(); break; case 0x5F: // EOR Absolute Long Indexed, X // EOR(); break; case 0x1A: // INC Accumulator // INC(); break; case 0xE6: // INC Direct Page // INC(); break; case 0xEE: // INC Absolute // INC(); break; case 0xF6: // INC DP Indexed, X // INC(); break; case 0xFE: // INC Absolute Indexed, X // INC(); break; case 0xE8: // INX Increment X register INX(); break; case 0xC8: // INY Increment Y register INY(); break; case 0x4C: // JMP Absolute // JMP(); break; case 0x5C: // JMP Absolute Long // JMP(); break; case 0x6C: // JMP Absolute Indirect // JMP(); break; case 0x7C: // JMP Absolute Indexed Indirect, X // JMP(); break; case 0xDC: // JMP Absolute Indirect Long // JMP(); break; case 0x20: // JSR Absolute // JSR(); break; case 0x22: // JSL Absolute Long // JSL(); break; case 0xFC: // JSR Absolute Indexed Indirect, X // JSR(); break; case 0xA1: // LDA DP Indexed Indirect, X // LDA(); break; case 0xA3: // LDA Stack Relative // LDA(); break; case 0xA5: // LDA Direct Page // LDA(); break; case 0xA7: // LDA DP Indirect Long // LDA(); break; case 0xA9: // LDA Immediate LDA(); break; case 0xAD: // LDA Absolute // LDA(); break; case 0xAF: // LDA Absolute Long // LDA(); break; case 0xB1: // LDA DP Indirect Indexed, Y // LDA(); break; case 0xB2: // LDA DP Indirect // LDA(); break; case 0xB3: // LDA SR Indirect Indexed, Y // LDA(); break; case 0xB5: // LDA DP Indexed, X // LDA(); break; case 0xB7: // LDA DP Indirect Long Indexed, Y // LDA(); break; case 0xB9: // LDA Absolute Indexed, Y // LDA(); break; case 0xBD: // LDA Absolute Indexed, X // LDA(); break; case 0xBF: // LDA Absolute Long Indexed, X // LDA(); break; case 0xA2: // LDX Immediate // LDX(); break; case 0xA6: // LDX Direct Page // LDX(); break; case 0xAE: // LDX Absolute // LDX(); break; case 0xB6: // LDX DP Indexed, Y // LDX(); break; case 0xBE: // LDX Absolute Indexed, Y // LDX(); break; case 0xA0: // LDY Immediate // LDY(); break; case 0xA4: // LDY Direct Page // LDY(); break; case 0xAC: // LDY Absolute // LDY(); break; case 0xB4: // LDY DP Indexed, X // LDY(); break; case 0xBC: // LDY Absolute Indexed, X // LDY(); break; case 0x46: // LSR Direct Page // LSR(); break; case 0x4A: // LSR Accumulator // LSR(); break; case 0x4E: // LSR Absolute // LSR(); break; case 0x56: // LSR DP Indexed, X // LSR(); break; case 0x5E: // LSR Absolute Indexed, X // LSR(); break; case 0x54: // MVN Block Move Next // MVN(); break; case 0xEA: // NOP No Operation // NOP(); break; case 0x01: // ORA DP Indexed Indirect, X // ORA(); break; case 0x03: // ORA Stack Relative // ORA(); break; case 0x05: // ORA Direct Page // ORA(); break; case 0x07: // ORA DP Indirect Long // ORA(); break; case 0x09: // ORA Immediate // ORA(); break; case 0x0D: // ORA Absolute // ORA(); break; case 0x0F: // ORA Absolute Long // ORA(); break; case 0x11: // ORA DP Indirect Indexed, Y // ORA(); break; case 0x12: // ORA DP Indirect // ORA(); break; case 0x13: // ORA SR Indirect Indexed, Y // ORA(); break; case 0x15: // ORA DP Indexed, X // ORA(); break; case 0x17: // ORA DP Indirect Long Indexed, Y // ORA(); break; case 0x19: // ORA Absolute Indexed, Y // ORA(); break; case 0x1D: // ORA Absolute Indexed, X // ORA(); break; case 0x1F: // ORA Absolute Long Indexed, X // ORA(); break; case 0xF4: // PEA Push Effective Absolute address // PEA(); break; case 0xD4: // PEI Push Effective Indirect address // PEI(); break; case 0x62: // PER Push Effective PC Relative Indirect address // PER(); break; case 0x48: // PHA Push Accumulator // PHA(); break; case 0x8B: // PHB Push Data Bank Register // PHB(); break; case 0x0B: // PHD Push Direct Page Register // PHD(); break; case 0x4B: // PHK Push Program Bank Register // PHK(); break; case 0x08: // PHP Push Processor Status Register // PHP(); break; case 0xDA: // PHX Push X register // PHX(); break; case 0x5A: // PHY Push Y register // PHY(); break; case 0x68: // PLA Pull Accumulator // PLA(); break; case 0xAB: // PLB Pull Data Bank Register // PLB(); break; case 0x2B: // PLD Pull Direct Page Register // PLD(); break; case 0x28: // PLP Pull Processor Status Register // PLP(); break; case 0xFA: // PLX Pull X register // PLX(); break; case 0x7A: // PLY Pull Y register // PLY(); break; case 0xC2: // REP Reset status bits REP(); break; case 0x26: // ROL Direct Page // ROL(); break; case 0x2A: // ROL Accumulator // ROL(); break; case 0x2E: // ROL Absolute // ROL(); break; case 0x36: // ROL DP Indexed, X // ROL(); break; case 0x3E: // ROL Absolute Indexed, X // ROL(); break; case 0x66: // ROR Direct Page // ROR(); break; case 0x6A: // ROR Accumulator // ROR(); break; case 0x6E: // ROR Absolute // ROR(); break; case 0x76: // ROR DP Indexed, X // ROR(); break; case 0x7E: // ROR Absolute Indexed, X // ROR(); break; case 0x40: // RTI Return from interrupt // RTI(); break; case 0x6B: // RTL Return from subroutine long // RTL(); break; case 0x60: // RTS Return from subroutine // RTS(); break; case 0xE1: // SBC DP Indexed Indirect, X // SBC(); break; case 0xE3: // SBC Stack Relative // SBC(); break; case 0xE5: // SBC Direct Page // SBC(); break; case 0xE7: // SBC DP Indirect Long // SBC(); break; case 0xE9: // SBC Immediate // SBC(); break; case 0xED: // SBC Absolute // SBC(); break; case 0xEF: // SBC Absolute Long // SBC(); break; case 0xF1: // SBC DP Indirect Indexed, Y // SBC(); break; case 0xF2: // SBC DP Indirect // SBC(); break; case 0xF3: // SBC SR Indirect Indexed, Y // SBC(); break; case 0xF5: // SBC DP Indexed, X // SBC(); break; case 0xF7: // SBC DP Indirect Long Indexed, Y // SBC(); break; case 0xF9: // SBC Absolute Indexed, Y // SBC(); break; case 0xFD: // SBC Absolute Indexed, X // SBC(); break; case 0xFF: // SBC Absolute Long Indexed, X // SBC(); break; case 0x38: // SEC Set carry SEC(); break; case 0xF8: // SED Set decimal SED(); break; case 0x78: // SEI Set interrupt disable SEI(); break; case 0xE2: // SEP Set status bits SEP(); break; case 0x81: // STA DP Indexed Indirect, X // STA(); break; case 0x83: // STA Stack Relative // STA(); break; case 0x85: // STA Direct Page // STA(); break; case 0x87: // STA DP Indirect Long // STA(); break; case 0x8D: // STA Absolute // STA(); break; case 0x8F: // STA Absolute Long // STA(); break; case 0x91: // STA DP Indirect Indexed, Y // STA(); break; case 0x92: // STA DP Indirect // STA(); break; case 0x93: // STA SR Indirect Indexed, Y // STA(); break; case 0x95: // STA DP Indexed, X // STA(); break; case 0x97: // STA DP Indirect Long Indexed, Y // STA(); break; case 0x99: // STA Absolute Indexed, Y // STA(); break; case 0x9D: // STA Absolute Indexed, X // STA(); break; case 0x9F: // STA Absolute Long Indexed, X // STA(); break; case 0xDB: // STP Stop the clock // STP(); break; case 0x86: // STX Direct Page // STX(); break; case 0x8E: // STX Absolute // STX(); break; case 0x96: // STX DP Indexed, Y // STX(); break; case 0x84: // STY Direct Page // STY(); break; case 0x8C: // STY Absolute // STY(); break; case 0x94: // STY DP Indexed, X // STY(); break; case 0x64: // STZ Direct Page // STZ(); break; case 0x74: // STZ DP Indexed, X // STZ(); break; case 0x9C: // STZ Absolute // STZ(); break; case 0x9E: // STZ Absolute Indexed, X // STZ(); break; case 0xAA: // TAX TAX(); break; case 0xA8: // TAY TAY(); break; case 0x5B: // TCD TCD(); break; case 0x1B: // TCS TCS(); break; case 0x7B: // TDC TDC(); break; case 0x14: // TRB Direct Page // TRB(); break; case 0x1C: // TRB Absolute // TRB(); break; case 0x04: // TSB Direct Page // TSB(); break; case 0x0C: // TSB Absolute // TSB(); break; case 0x3B: // TSC TSC(); break; case 0xBA: // TSX TSX(); break; case 0x8A: // TXA TXA(); break; case 0x9A: // TXS TXS(); break; case 0x9B: // TXY TXY(); break; case 0x98: // TYA TYA(); break; case 0xBB: // TYX TYX(); break; case 0xCB: // WAI // WAI(); break; case 0xEB: // XBA // XBA(); break; case 0xFB: // XCE // XCE(); break; default: std::cerr << "Unknown instruction: " << std::hex << static_cast(opcode) << std::endl; break; } } void CPU::ADC(uint8_t operand) { auto C = (bool)GetCarryFlag(); if (GetAccumulatorSize()) { // 8-bit mode uint16_t result = (A & 0xFF) + (operand & 0xFF); // + (C ? 1 : 0); SetCarryFlag(!(result > 0xFF)); // Update the carry flag // Update the overflow flag bool overflow = (~(A ^ operand) & (A ^ result) & 0x80) != 0; if (overflow) { status |= 0x40; // Set overflow flag } else { status &= ~0x40; // Clear overflow flag } // Update the accumulator A = (A & 0xFF00) | (result & 0xFF); SetZeroFlag(A == 0); SetNegativeFlag(A & 0x80); } else { uint32_t result = A + operand; // + (C ? 1 : 0); SetCarryFlag(!(result > 0xFFFF)); // Update the carry flag // Update the overflow flag bool overflow = (~(A ^ operand) & (A ^ result) & 0x8000) != 0; SetOverflowFlag(overflow); // Update the accumulator A = result & 0xFFFF; SetZeroFlag(A == 0); SetNegativeFlag(A & 0x8000); } } } // namespace emu } // namespace app } // namespace yaze