diff --git a/src/app/emu/cpu.cc b/src/app/emu/cpu.cc index ecb8c1e2..727fa634 100644 --- a/src/app/emu/cpu.cc +++ b/src/app/emu/cpu.cc @@ -1232,6 +1232,485 @@ void CPU::ANDAbsoluteLong(uint32_t address) { SetNegativeFlag(A & 0x80000000); } +void CPU::ASL(uint16_t address) { + uint8_t value = memory.ReadByte(address); + SetCarryFlag(!(value & 0x80)); // Set carry flag if bit 7 is set + value <<= 1; // Shift left + value &= 0xFE; // Clear bit 0 + memory.WriteByte(address, value); + SetNegativeFlag(!value); + SetZeroFlag(value); +} + +void CPU::BCC(int8_t offset) { + if (!GetCarryFlag()) { // If the carry flag is clear + PC += offset; // Add the offset to the program counter + } +} + +// BCS: Branch if carry set +void CPU::BCS(int8_t offset) { + if (GetCarryFlag()) { // If the carry flag is set + PC += offset; // Add the offset to the program counter + } +} + +// BEQ: Branch if equal (zero set) +void CPU::BEQ(int8_t offset) { + if (GetZeroFlag()) { // If the zero flag is set + PC += offset; // Add the offset to the program counter + } +} + +// BIT: Bit test +void CPU::BIT(uint16_t address) { + uint8_t value = memory.ReadByte(address); + SetNegativeFlag(value & 0x80); + SetOverflowFlag(value & 0x40); + SetZeroFlag((A & value) == 0); +} + +// BMI: Branch if minus (negative set) +void CPU::BMI(int8_t offset) { + if (GetNegativeFlag()) { // If the negative flag is set + PC += offset; // Add the offset to the program counter + } +} + +// BNE: Branch if not equal (zero clear) +void CPU::BNE(int8_t offset) { + if (!GetZeroFlag()) { // If the zero flag is clear + PC += offset; // Add the offset to the program counter + } +} + +// BPL: Branch if plus (negative clear) +void CPU::BPL(int8_t offset) { + if (!GetNegativeFlag()) { // If the negative flag is clear + PC += offset; // Add the offset to the program counter + } +} + +// BRA: Branch always +void CPU::BRA(int8_t offset) { PC += offset; } + +// BRK: Break +void CPU::BRK() { + PC += 2; // Increment the program counter by 2 + memory.PushWord(PC); + memory.PushByte(status); + SetInterruptFlag(true); + try { + PC = memory.ReadWord(0xFFFE); + } catch (const std::exception& e) { + std::cout << "BRK: " << e.what() << std::endl; + } +} + +// BRL: Branch always long +void CPU::BRL(int16_t offset) { + PC += offset; // Add the offset to the program counter +} + +// BVC: Branch if overflow clear +void CPU::BVC(int8_t offset) { + if (!GetOverflowFlag()) { // If the overflow flag is clear + PC += offset; // Add the offset to the program counter + } +} + +// BVS: Branch if overflow set +void CPU::BVS(int8_t offset) { + if (GetOverflowFlag()) { // If the overflow flag is set + PC += offset; // Add the offset to the program counter + } +} + +// CLC: Clear carry flag +void CPU::CLC() { status &= ~0x01; } + +// CLD: Clear decimal mode +void CPU::CLD() { status &= ~0x08; } + +// CLI: Clear interrupt disable flag +void CPU::CLI() { status &= ~0x04; } + +// CLV: Clear overflow flag +void CPU::CLV() { status &= ~0x40; } + +// CMP: Compare TESTME +// n Set if MSB of result is set; else cleared +// z Set if result is zero; else cleared +// c Set if no borrow; else cleared +void CPU::CMP(uint8_t value, bool isImmediate = false) { + if (GetAccumulatorSize()) { // 8-bit + uint8_t result = isImmediate ? A - value : A - memory.ReadByte(value); + SetZeroFlag(result == 0); + SetNegativeFlag(result & 0x80); + SetCarryFlag(A >= value); + } else { // 16-bit + uint16_t result = isImmediate ? A - value : A - memory.ReadWord(value); + SetZeroFlag(result == 0); + SetNegativeFlag(result & 0x8000); + SetCarryFlag(A >= value); + } +} + +// COP: Coprocessor TESTME +void CPU::COP() { + PC += 2; // Increment the program counter by 2 + memory.PushWord(PC); + memory.PushByte(status); + SetInterruptFlag(true); + if (E) { + PC = memory.ReadWord(0xFFF4); + } else { + PC = memory.ReadWord(0xFFE4); + } + SetDecimalFlag(false); +} + +// CPX: Compare X register +void CPU::CPX(uint16_t value, bool isImmediate = false) { + if (GetIndexSize()) { // 8-bit + uint8_t memory_value = isImmediate ? value : memory.ReadByte(value); + compare(X, memory_value); + } else { // 16-bit + uint16_t memory_value = isImmediate ? value : memory.ReadWord(value); + compare(X, memory_value); + } +} + +// CPY: Compare Y register +void CPU::CPY(uint16_t value, bool isImmediate = false) { + if (GetIndexSize()) { // 8-bit + uint8_t memory_value = isImmediate ? value : memory.ReadByte(value); + compare(Y, memory_value); + } else { // 16-bit + uint16_t memory_value = isImmediate ? value : memory.ReadWord(value); + compare(Y, memory_value); + } +} + +// DEC: Decrement TESTME +void CPU::DEC(uint16_t address) { + if (GetAccumulatorSize()) { + uint8_t value = memory.ReadByte(address); + value--; + memory.WriteByte(address, value); + SetZeroFlag(value == 0); + SetNegativeFlag(value & 0x80); + } else { + uint16_t value = memory.ReadWord(address); + value--; + memory.WriteWord(address, value); + SetZeroFlag(value == 0); + SetNegativeFlag(value & 0x8000); + } +} + +// DEX: Decrement X register +void CPU::DEX() { + if (GetIndexSize()) { // 8-bit + X = static_cast(X - 1); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x80); + } else { // 16-bit + X = static_cast(X - 1); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x8000); + } +} + +// DEY: Decrement Y register +void CPU::DEY() { + if (GetIndexSize()) { // 8-bit + Y = static_cast(Y - 1); + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x80); + } else { // 16-bit + Y = static_cast(Y - 1); + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x8000); + } +} + +// EOR: Exclusive OR TESTMEs +void CPU::EOR(uint16_t address, bool isImmediate = false) { + if (GetAccumulatorSize()) { + A ^= isImmediate ? address : memory.ReadByte(address); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); + } else { + A ^= isImmediate ? address : memory.ReadWord(address); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x8000); + } +} + +// INC: Increment +void CPU::INC(uint16_t address) { + if (GetAccumulatorSize()) { + uint8_t value = memory.ReadByte(address); + value++; + memory.WriteByte(address, value); + SetNegativeFlag(value & 0x80); + SetZeroFlag(value == 0); + } else { + uint16_t value = memory.ReadWord(address); + value++; + memory.WriteWord(address, value); + SetNegativeFlag(value & 0x8000); + SetZeroFlag(value == 0); + } +} + +// INX: Increment X register +void CPU::INX() { + if (GetIndexSize()) { // 8-bit + X = static_cast(X + 1); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x80); + } else { // 16-bit + X = static_cast(X + 1); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x8000); + } +} + +// INY: Increment Y register +void CPU::INY() { + if (GetIndexSize()) { // 8-bit + Y = static_cast(Y + 1); + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x80); + } else { // 16-bit + Y = static_cast(Y + 1); + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x8000); + } +} + +// JMP: Jump +void CPU::JMP(uint16_t address) { + PC = address; // Set program counter to the new address +} + +// JML: Jump long +void CPU::JML(uint32_t address) { + // Set the lower 16 bits of PC to the lower 16 bits of the address + PC = static_cast(address & 0xFFFF); + // Set the PBR to the upper 8 bits of the address + PB = static_cast((address >> 16) & 0xFF); +} + +// JSR: Jump to subroutine +void CPU::JSR(uint16_t address) { + PC -= 1; // Subtract 1 from program counter + memory.PushWord(PC); // Push the program counter onto the stack + PC = address; // Set program counter to the new address +} + +// JSL: Jump to subroutine long +void CPU::JSL(uint32_t address) { + PC -= 1; // Subtract 1 from program counter + memory.PushLong(PC); // Push the program counter onto the stack as a long + // value (24 bits) + PC = address; // Set program counter to the new address +} + +// LDA: Load accumulator +void CPU::LDA(uint16_t address, bool isImmediate = false) { + if (GetAccumulatorSize()) { + A = isImmediate ? address : memory.ReadByte(address); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); + } else { + A = isImmediate ? memory.ReadWord(PC) : memory.ReadWord(address); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x8000); + } +} + +// LDX: Load X register +void CPU::LDX(uint16_t address, bool isImmediate = false) { + if (GetIndexSize()) { + X = isImmediate ? address : memory.ReadByte(address); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x80); + } else { + X = isImmediate ? address : memory.ReadWord(address); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x8000); + } +} + +// LDY: Load Y register +void CPU::LDY(uint16_t address, bool isImmediate = false) { + if (GetIndexSize()) { + Y = isImmediate ? address : memory.ReadByte(address); + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x80); + } else { + Y = isImmediate ? address : memory.ReadWord(address); + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x8000); + } +} + +// LSR: Logical shift right +void CPU::LSR(uint16_t address) { + uint8_t value = memory.ReadByte(address); + SetCarryFlag(value & 0x01); + value >>= 1; + memory.WriteByte(address, value); + SetNegativeFlag(false); + SetZeroFlag(value == 0); +} + +// MVN: Move negative ``` +// MVP: Move positive ``` + +// NOP: No operation +void CPU::NOP() { + // Do nothing +} + +// ORA: Logical OR +void CPU::ORA(uint16_t address, bool isImmediate = false) { + if (GetAccumulatorSize()) { + A |= isImmediate ? address : memory.ReadByte(address); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); + } else { + A |= isImmediate ? address : memory.ReadWord(address); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x8000); + } +} + +// PEA: Push effective address +void CPU::PEA() { + uint16_t address = FetchWord(); + memory.PushWord(address); +} + +// PEI: Push effective indirect address +void CPU::PEI() { + uint16_t address = FetchWord(); + memory.PushWord(memory.ReadWord(address)); +} + +// PER: Push effective PC-relative address +void CPU::PER() { + uint16_t address = FetchWord(); + memory.PushWord(PC + address); +} + +// PHA: Push Accumulator on Stack +void CPU::PHA() { memory.PushByte(A); } + +// PHB: Push Data Bank Register on Stack +void CPU::PHB() { memory.PushByte(DB); } + +// PHD: Push Program Bank Register on Stack +void CPU::PHD() { memory.PushWord(D); } + +// PHK: Push Program Bank Register on Stack +void CPU::PHK() { memory.PushByte(PB); } + +// PHP: Push Processor Status Register on Stack +void CPU::PHP() { memory.PushByte(status); } + +// PHX: Push X Index Register on Stack +void CPU::PHX() { memory.PushByte(X); } + +// PHY: Push Y Index Register on Stack +void CPU::PHY() { memory.PushByte(Y); } + +// PLA: Pull Accumulator from Stack +void CPU::PLA() { + A = memory.PopByte(); + SetNegativeFlag((A & 0x80) != 0); + SetZeroFlag(A == 0); +} + +// PLB: Pull data bank register +void CPU::PLB() { + DB = memory.PopByte(); + SetNegativeFlag((DB & 0x80) != 0); + SetZeroFlag(DB == 0); +} + +// Pull Direct Page Register from Stack +void CPU::PLD() { + D = memory.PopWord(); + SetNegativeFlag((D & 0x8000) != 0); + SetZeroFlag(D == 0); +} + +// Pull Processor Status Register from Stack +void CPU::PLP() { status = memory.PopByte(); } + +// PLX: Pull X Index Register from Stack +void CPU::PLX() { + X = memory.PopByte(); + SetNegativeFlag((A & 0x80) != 0); + SetZeroFlag(X == 0); +} + +// PHY: Pull Y Index Register from Stack +void CPU::PLY() { + Y = memory.PopByte(); + SetNegativeFlag((A & 0x80) != 0); + SetZeroFlag(Y == 0); +} + +// REP: Reset status bits +void CPU::REP() { + auto byte = FetchByte(); + status &= ~byte; +} + +// ROL: Rotate left +void CPU::ROL(uint16_t address) { + uint8_t value = memory.ReadByte(address); + uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; + SetCarryFlag(value & 0x80); + value <<= 1; + value |= carry; + memory.WriteByte(address, value); + SetNegativeFlag(value & 0x80); + SetZeroFlag(value == 0); +} + +// ROR: Rotate right +void CPU::ROR(uint16_t address) { + uint8_t value = memory.ReadByte(address); + uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; + SetCarryFlag(value & 0x01); + value >>= 1; + value |= carry; + memory.WriteByte(address, value); + SetNegativeFlag(value & 0x80); + SetZeroFlag(value == 0); +} + +// RTI: Return from interrupt +void CPU::RTI() { + status = memory.PopByte(); + PC = memory.PopWord(); +} + +// RTL: Return from subroutine long +void CPU::RTL() { + PC = memory.PopWord(); + PB = memory.PopByte(); +} + +// RTS: Return from subroutine +void CPU::RTS() { PC = memory.PopWord() + 1; } // ASL: Arithmetic shift left + void CPU::SBC(uint16_t value, bool isImmediate) { uint16_t operand; if (!GetAccumulatorSize()) { // 16-bit mode @@ -1265,6 +1744,180 @@ void CPU::SBC(uint16_t value, bool isImmediate) { } } +// SEC: Set carry flag +void CPU::SEC() { status |= 0x01; } + +// SED: Set decimal mode +void CPU::SED() { status |= 0x08; } + +// SEI: Set interrupt disable flag +void CPU::SEI() { status |= 0x04; } + +// SEP: Set status bits +void CPU::SEP() { + auto byte = FetchByte(); + status |= byte; +} + +// STA: Store accumulator +void CPU::STA(uint16_t address) { + if (GetAccumulatorSize()) { + memory.WriteByte(address, static_cast(A)); + } else { + memory.WriteWord(address, A); + } +} + +// TODO: Make this work with the Clock class of the CPU +// STP: Stop the clock +void CPU::STP() { + // During the next phase 2 clock cycle, stop the processors oscillator input + // The processor is effectively shut down until a reset occurs (RES` pin). +} + +// STX: Store X register +void CPU::STX(uint16_t address) { + if (GetIndexSize()) { + memory.WriteByte(address, static_cast(X)); + } else { + memory.WriteWord(address, X); + } +} + +// STY: Store Y register +void CPU::STY(uint16_t address) { + if (GetIndexSize()) { + memory.WriteByte(address, static_cast(Y)); + } else { + memory.WriteWord(address, Y); + } +} + +// STZ: Store zero +void CPU::STZ(uint16_t address) { + if (GetAccumulatorSize()) { + memory.WriteByte(address, 0x00); + } else { + memory.WriteWord(address, 0x0000); + } +} + +// TAX: Transfer accumulator to X +void CPU::TAX() { + X = A; + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x80); +} + +// TAY: Transfer accumulator to Y +void CPU::TAY() { + Y = A; + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x80); +} + +// TCD: Transfer accumulator to direct page register +void CPU::TCD() { + D = A; + SetZeroFlag(D == 0); + SetNegativeFlag(D & 0x80); +} + +// TCS: Transfer accumulator to stack pointer +void CPU::TCS() { memory.SetSP(A); } + +// TDC: Transfer direct page register to accumulator +void CPU::TDC() { + A = D; + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); +} + +// TRB: Test and reset bits +void CPU::TRB(uint16_t address) { + uint8_t value = memory.ReadByte(address); + SetZeroFlag((A & value) == 0); + value &= ~A; + memory.WriteByte(address, value); +} + +// TSB: Test and set bits +void CPU::TSB(uint16_t address) { + uint8_t value = memory.ReadByte(address); + SetZeroFlag((A & value) == 0); + value |= A; + memory.WriteByte(address, value); +} + +// TSC: Transfer stack pointer to accumulator +void CPU::TSC() { + A = SP(); + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); +} + +// TSX: Transfer stack pointer to X +void CPU::TSX() { + X = SP(); + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x80); +} + +// TXA: Transfer X to accumulator +void CPU::TXA() { + A = X; + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); +} + +// TXS: Transfer X to stack pointer +void CPU::TXS() { memory.SetSP(X); } + +// TXY: Transfer X to Y +void CPU::TXY() { + X = Y; + SetZeroFlag(X == 0); + SetNegativeFlag(X & 0x80); +} + +// TYA: Transfer Y to accumulator +void CPU::TYA() { + A = Y; + SetZeroFlag(A == 0); + SetNegativeFlag(A & 0x80); +} + +// TYX: Transfer Y to X +void CPU::TYX() { + Y = X; + SetZeroFlag(Y == 0); + SetNegativeFlag(Y & 0x80); +} + +// TODO: Make this communicate with the SNES class +// WAI: Wait for interrupt TESTME +void CPU::WAI() { + // Pull the RDY pin low + // Power consumption is reduced(?) + // RDY remains low until an external hardware interupt + // (NMI, IRQ, ABORT, or RESET) is received from the SNES class +} + +// XBA: Exchange B and A accumulator +void CPU::XBA() { + uint8_t lowByte = A & 0xFF; + uint8_t highByte = (A >> 8) & 0xFF; + A = (lowByte << 8) | highByte; +} + +// XCE: Exchange Carry and Emulation Flags +void CPU::XCE() { + uint8_t carry = status & 0x01; + status &= ~0x01; + status |= E; + E = carry; +} + } // namespace emu } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/emu/cpu.h b/src/app/emu/cpu.h index bd506246..1375d86c 100644 --- a/src/app/emu/cpu.h +++ b/src/app/emu/cpu.h @@ -372,662 +372,274 @@ class CPU : public Memory, public Loggable { void AND(uint16_t address, bool isImmediate = false); // ASL: Arithmetic shift left - void ASL(uint16_t address) { - uint8_t value = memory.ReadByte(address); - SetCarryFlag(!(value & 0x80)); // Set carry flag if bit 7 is set - value <<= 1; // Shift left - value &= 0xFE; // Clear bit 0 - memory.WriteByte(address, value); - SetNegativeFlag(!value); - SetZeroFlag(value); - } + void ASL(uint16_t address); // BCC: Branch if carry clear - void BCC(int8_t offset) { - if (!GetCarryFlag()) { // If the carry flag is clear - PC += offset; // Add the offset to the program counter - } - } + void BCC(int8_t offset); // BCS: Branch if carry set - void BCS(int8_t offset) { - if (GetCarryFlag()) { // If the carry flag is set - PC += offset; // Add the offset to the program counter - } - } + void BCS(int8_t offset); - // BEQ: Branch if equal (zero set) - void BEQ(int8_t offset) { - if (GetZeroFlag()) { // If the zero flag is set - PC += offset; // Add the offset to the program counter - } - } + // BEQ: Branch if equal + void BEQ(int8_t offset); // BIT: Bit test - void BIT(uint16_t address) { - uint8_t value = memory.ReadByte(address); - SetNegativeFlag(value & 0x80); - SetOverflowFlag(value & 0x40); - SetZeroFlag((A & value) == 0); - } + void BIT(uint16_t address); - // BMI: Branch if minus (negative set) - void BMI(int8_t offset) { - if (GetNegativeFlag()) { // If the negative flag is set - PC += offset; // Add the offset to the program counter - } - } + // BMI: Branch if minus + void BMI(int8_t offset); - // BNE: Branch if not equal (zero clear) - void BNE(int8_t offset) { - if (!GetZeroFlag()) { // If the zero flag is clear - PC += offset; // Add the offset to the program counter - } - } + // BNE: Branch if not equal + void BNE(int8_t offset); - // BPL: Branch if plus (negative clear) - void BPL(int8_t offset) { - if (!GetNegativeFlag()) { // If the negative flag is clear - PC += offset; // Add the offset to the program counter - } - } + // BPL: Branch if plus + void BPL(int8_t offset); // BRA: Branch always - void BRA(int8_t offset) { PC += offset; } + void BRA(int8_t offset); - // BRK: Break - void BRK() { - PC += 2; // Increment the program counter by 2 - memory.PushWord(PC); - memory.PushByte(status); - SetInterruptFlag(true); - try { - PC = memory.ReadWord(0xFFFE); - } catch (const std::exception& e) { - std::cout << "BRK: " << e.what() << std::endl; - } - } + // BRK: Force interrupt + void BRK(); // BRL: Branch always long - void BRL(int16_t offset) { - PC += offset; // Add the offset to the program counter - } + void BRL(int16_t offset); // BVC: Branch if overflow clear - void BVC(int8_t offset) { - if (!GetOverflowFlag()) { // If the overflow flag is clear - PC += offset; // Add the offset to the program counter - } - } + void BVC(int8_t offset); // BVS: Branch if overflow set - void BVS(int8_t offset) { - if (GetOverflowFlag()) { // If the overflow flag is set - PC += offset; // Add the offset to the program counter - } - } + void BVS(int8_t offset); // CLC: Clear carry flag - void CLC() { status &= ~0x01; } + void CLC(); // CLD: Clear decimal mode - void CLD() { status &= ~0x08; } + void CLD(); - // CLI: Clear interrupt disable flag - void CLI() { status &= ~0x04; } + // CLI: Clear interrupt disable bit + void CLI(); // CLV: Clear overflow flag - void CLV() { status &= ~0x40; } + void CLV(); - // CMP: Compare TESTME - // n Set if MSB of result is set; else cleared - // z Set if result is zero; else cleared - // c Set if no borrow; else cleared - void CMP(uint8_t value, bool isImmediate = false) { - if (GetAccumulatorSize()) { // 8-bit - uint8_t result = isImmediate ? A - value : A - memory.ReadByte(value); - SetZeroFlag(result == 0); - SetNegativeFlag(result & 0x80); - SetCarryFlag(A >= value); - } else { // 16-bit - uint16_t result = isImmediate ? A - value : A - memory.ReadWord(value); - SetZeroFlag(result == 0); - SetNegativeFlag(result & 0x8000); - SetCarryFlag(A >= value); - } - } + // CMP: Compare + void CMP(uint16_t address, bool isImmediate = false); - // COP: Coprocessor TESTME - void COP() { - PC += 2; // Increment the program counter by 2 - memory.PushWord(PC); - memory.PushByte(status); - SetInterruptFlag(true); - if (E) { - PC = memory.ReadWord(0xFFF4); - } else { - PC = memory.ReadWord(0xFFE4); - } - SetDecimalFlag(false); - } + // COP: Coprocessor enable + void COP(); // CPX: Compare X register - void CPX(uint16_t value, bool isImmediate = false) { - if (GetIndexSize()) { // 8-bit - uint8_t memory_value = isImmediate ? value : memory.ReadByte(value); - compare(X, memory_value); - } else { // 16-bit - uint16_t memory_value = isImmediate ? value : memory.ReadWord(value); - compare(X, memory_value); - } - } + void CPX(uint16_t address, bool isImmediate = false); // CPY: Compare Y register - void CPY(uint16_t value, bool isImmediate = false) { - if (GetIndexSize()) { // 8-bit - uint8_t memory_value = isImmediate ? value : memory.ReadByte(value); - compare(Y, memory_value); - } else { // 16-bit - uint16_t memory_value = isImmediate ? value : memory.ReadWord(value); - compare(Y, memory_value); - } - } + void CPY(uint16_t address, bool isImmediate = false); - // DEC: Decrement TESTME - void DEC(uint16_t address) { - if (GetAccumulatorSize()) { - uint8_t value = memory.ReadByte(address); - value--; - memory.WriteByte(address, value); - SetZeroFlag(value == 0); - SetNegativeFlag(value & 0x80); - } else { - uint16_t value = memory.ReadWord(address); - value--; - memory.WriteWord(address, value); - SetZeroFlag(value == 0); - SetNegativeFlag(value & 0x8000); - } - } + // DEC: Decrement memory + void DEC(uint16_t address); // DEX: Decrement X register - void DEX() { - if (GetIndexSize()) { // 8-bit - X = static_cast(X - 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } else { // 16-bit - X = static_cast(X - 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x8000); - } - } + void DEX(); // DEY: Decrement Y register - void DEY() { - if (GetIndexSize()) { // 8-bit - Y = static_cast(Y - 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } else { // 16-bit - Y = static_cast(Y - 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x8000); - } - } + void DEY(); - // EOR: Exclusive OR TESTMEs - void EOR(uint16_t address, bool isImmediate = false) { - if (GetAccumulatorSize()) { - A ^= isImmediate ? address : memory.ReadByte(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { - A ^= isImmediate ? address : memory.ReadWord(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - } + // EOR: Exclusive OR + void EOR(uint16_t address, bool isImmediate = false); - // INC: Increment - void INC(uint16_t address) { - if (GetAccumulatorSize()) { - uint8_t value = memory.ReadByte(address); - value++; - memory.WriteByte(address, value); - SetNegativeFlag(value & 0x80); - SetZeroFlag(value == 0); - } else { - uint16_t value = memory.ReadWord(address); - value++; - memory.WriteWord(address, value); - SetNegativeFlag(value & 0x8000); - SetZeroFlag(value == 0); - } - } + // INC: Increment memory + void INC(uint16_t address); // INX: Increment X register - void INX() { - if (GetIndexSize()) { // 8-bit - X = static_cast(X + 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } else { // 16-bit - X = static_cast(X + 1); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x8000); - } - } + void INX(); // INY: Increment Y register - void INY() { - if (GetIndexSize()) { // 8-bit - Y = static_cast(Y + 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } else { // 16-bit - Y = static_cast(Y + 1); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x8000); - } - } + void INY(); // JMP: Jump - void JMP(uint16_t address) { - PC = address; // Set program counter to the new address - } + void JMP(uint16_t address); // JML: Jump long - void JML(uint32_t address) { - // Set the lower 16 bits of PC to the lower 16 bits of the address - PC = static_cast(address & 0xFFFF); - // Set the PBR to the upper 8 bits of the address - PB = static_cast((address >> 16) & 0xFF); - } + void JML(uint32_t address); // JSR: Jump to subroutine - void JSR(uint16_t address) { - PC -= 1; // Subtract 1 from program counter - memory.PushWord(PC); // Push the program counter onto the stack - PC = address; // Set program counter to the new address - } + void JSR(uint16_t address); // JSL: Jump to subroutine long - void JSL(uint32_t address) { - PC -= 1; // Subtract 1 from program counter - memory.PushLong(PC); // Push the program counter onto the stack as a long - // value (24 bits) - PC = address; // Set program counter to the new address - } + void JSL(uint32_t address); // LDA: Load accumulator - void LDA(uint16_t address, bool isImmediate = false) { - if (GetAccumulatorSize()) { - A = isImmediate ? address : memory.ReadByte(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { - A = isImmediate ? memory.ReadWord(PC) : memory.ReadWord(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - } + void LDA(uint16_t address, bool isImmediate = false); // LDX: Load X register - void LDX(uint16_t address, bool isImmediate = false) { - if (GetIndexSize()) { - X = isImmediate ? address : memory.ReadByte(address); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } else { - X = isImmediate ? address : memory.ReadWord(address); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x8000); - } - } + void LDX(uint16_t address, bool isImmediate = false); // LDY: Load Y register - void LDY(uint16_t address, bool isImmediate = false) { - if (GetIndexSize()) { - Y = isImmediate ? address : memory.ReadByte(address); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } else { - Y = isImmediate ? address : memory.ReadWord(address); - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x8000); - } - } + void LDY(uint16_t address, bool isImmediate = false); // LSR: Logical shift right - void LSR(uint16_t address) { - uint8_t value = memory.ReadByte(address); - SetCarryFlag(value & 0x01); - value >>= 1; - memory.WriteByte(address, value); - SetNegativeFlag(false); - SetZeroFlag(value == 0); - } + void LSR(uint16_t address); - // MVN: Move negative ``` - // MVP: Move positive ``` + // MVN: Block move next + void MVN(uint16_t source, uint16_t dest, uint16_t length); + + // MVP: Block move previous + void MVP(uint16_t source, uint16_t dest, uint16_t length); // NOP: No operation - void NOP() { - // Do nothing - } + void NOP(); - // ORA: Logical OR - void ORA(uint16_t address, bool isImmediate = false) { - if (GetAccumulatorSize()) { - A |= isImmediate ? address : memory.ReadByte(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } else { - A |= isImmediate ? address : memory.ReadWord(address); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x8000); - } - } + // ORA: Logical inclusive OR + void ORA(uint16_t address, bool isImmediate = false); - // PEA: Push effective address - void PEA() { - uint16_t address = FetchWord(); - memory.PushWord(address); - } + // PEA: Push effective absolute address + void PEA(uint16_t address); // PEI: Push effective indirect address - void PEI() { - uint16_t address = FetchWord(); - memory.PushWord(memory.ReadWord(address)); - } + void PEI(uint16_t address); - // PER: Push effective PC-relative address - void PER() { - uint16_t address = FetchWord(); - memory.PushWord(PC + address); - } + // PER: Push effective relative address + void PER(uint16_t address); - // PHA: Push Accumulator on Stack - void PHA() { memory.PushByte(A); } + // PHA: Push accumulator + void PHA(); - // PHB: Push Data Bank Register on Stack - void PHB() { memory.PushByte(DB); } + // PHB: Push data bank register + void PHB(); - // PHD: Push Program Bank Register on Stack - void PHD() { memory.PushWord(D); } + // PHD: Push direct page register + void PHD(); - // PHK: Push Program Bank Register on Stack - void PHK() { memory.PushByte(PB); } + // PHK: Push program bank register + void PHK(); - // PHP: Push Processor Status Register on Stack - void PHP() { memory.PushByte(status); } + // PHP: Push processor status (flags) + void PHP(); - // PHX: Push X Index Register on Stack - void PHX() { memory.PushByte(X); } + // PHX: Push X register + void PHX(); - // PHY: Push Y Index Register on Stack - void PHY() { memory.PushByte(Y); } + // PHY: Push Y register + void PHY(); - // PLA: Pull Accumulator from Stack - void PLA() { - A = memory.PopByte(); - SetNegativeFlag((A & 0x80) != 0); - SetZeroFlag(A == 0); - } + // PLA: Pull accumulator + void PLA(); // PLB: Pull data bank register - void PLB() { - DB = memory.PopByte(); - SetNegativeFlag((DB & 0x80) != 0); - SetZeroFlag(DB == 0); - } + void PLB(); - // Pull Direct Page Register from Stack - void PLD() { - D = memory.PopWord(); - SetNegativeFlag((D & 0x8000) != 0); - SetZeroFlag(D == 0); - } + // PLD: Pull direct page register + void PLD(); - // Pull Processor Status Register from Stack - void PLP() { status = memory.PopByte(); } + // PLP: Pull processor status (flags) + void PLP(); - // PLX: Pull X Index Register from Stack - void PLX() { - X = memory.PopByte(); - SetNegativeFlag((A & 0x80) != 0); - SetZeroFlag(X == 0); - } + // PLX: Pull X register + void PLX(); - // PHY: Pull Y Index Register from Stack - void PLY() { - Y = memory.PopByte(); - SetNegativeFlag((A & 0x80) != 0); - SetZeroFlag(Y == 0); - } + // PLY: Pull Y register + void PLY(); - // REP: Reset status bits - void REP() { - auto byte = FetchByte(); - status &= ~byte; - } + // REP: Reset processor status bits + void REP(); // ROL: Rotate left - void ROL(uint16_t address) { - uint8_t value = memory.ReadByte(address); - uint8_t carry = GetCarryFlag() ? 0x01 : 0x00; - SetCarryFlag(value & 0x80); - value <<= 1; - value |= carry; - memory.WriteByte(address, value); - SetNegativeFlag(value & 0x80); - SetZeroFlag(value == 0); - } + void ROL(uint16_t address); // ROR: Rotate right - void ROR(uint16_t address) { - uint8_t value = memory.ReadByte(address); - uint8_t carry = GetCarryFlag() ? 0x80 : 0x00; - SetCarryFlag(value & 0x01); - value >>= 1; - value |= carry; - memory.WriteByte(address, value); - SetNegativeFlag(value & 0x80); - SetZeroFlag(value == 0); - } + void ROR(uint16_t address); // RTI: Return from interrupt - void RTI() { - status = memory.PopByte(); - PC = memory.PopWord(); - } + void RTI(); // RTL: Return from subroutine long - void RTL() { - PC = memory.PopWord(); - PB = memory.PopByte(); - } + void RTL(); // RTS: Return from subroutine - void RTS() { PC = memory.PopWord() + 1; } + void RTS(); // SBC: Subtract with carry void SBC(uint16_t operand, bool isImmediate = false); // SEC: Set carry flag - void SEC() { status |= 0x01; } + void SEC(); // SED: Set decimal mode - void SED() { status |= 0x08; } + void SED(); - // SEI: Set interrupt disable flag - void SEI() { status |= 0x04; } + // SEI: Set interrupt disable status + void SEI(); - // SEP: Set status bits - void SEP() { - auto byte = FetchByte(); - status |= byte; - } + // SEP: Set processor status bits + void SEP(); // STA: Store accumulator - void STA(uint16_t address) { - if (GetAccumulatorSize()) { - memory.WriteByte(address, static_cast(A)); - } else { - memory.WriteWord(address, A); - } - } + void STA(uint16_t address); - // TODO: Make this work with the Clock class of the CPU - // STP: Stop the clock - void STP() { - // During the next phase 2 clock cycle, stop the processors oscillator input - // The processor is effectively shut down until a reset occurs (RES` pin). - } + // STP: Stop the processor + void STP(); // STX: Store X register - void STX(uint16_t address) { - if (GetIndexSize()) { - memory.WriteByte(address, static_cast(X)); - } else { - memory.WriteWord(address, X); - } - } + void STX(uint16_t address); // STY: Store Y register - void STY(uint16_t address) { - if (GetIndexSize()) { - memory.WriteByte(address, static_cast(Y)); - } else { - memory.WriteWord(address, Y); - } - } + void STY(uint16_t address); // STZ: Store zero - void STZ(uint16_t address) { - if (GetAccumulatorSize()) { - memory.WriteByte(address, 0x00); - } else { - memory.WriteWord(address, 0x0000); - } - } + void STZ(uint16_t address); // TAX: Transfer accumulator to X - void TAX() { - X = A; - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } + void TAX(); // TAY: Transfer accumulator to Y - void TAY() { - Y = A; - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } + void TAY(); - // TCD: Transfer accumulator to direct page register - void TCD() { - D = A; - SetZeroFlag(D == 0); - SetNegativeFlag(D & 0x80); - } + // TCD: Transfer 16-bit accumulator to direct page register + void TCD(); - // TCS: Transfer accumulator to stack pointer - void TCS() { memory.SetSP(A); } + // TCS: Transfer 16-bit accumulator to stack pointer + void TCS(); - // TDC: Transfer direct page register to accumulator - void TDC() { - A = D; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } + // TDC: Transfer direct page register to 16-bit accumulator + void TDC(); // TRB: Test and reset bits - void TRB(uint16_t address) { - uint8_t value = memory.ReadByte(address); - SetZeroFlag((A & value) == 0); - value &= ~A; - memory.WriteByte(address, value); - } + void TRB(uint16_t address); // TSB: Test and set bits - void TSB(uint16_t address) { - uint8_t value = memory.ReadByte(address); - SetZeroFlag((A & value) == 0); - value |= A; - memory.WriteByte(address, value); - } + void TSB(uint16_t address); - // TSC: Transfer stack pointer to accumulator - void TSC() { - A = SP(); - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } + // TSC: Transfer stack pointer to 16-bit accumulator + void TSC(); // TSX: Transfer stack pointer to X - void TSX() { - X = SP(); - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } + void TSX(); // TXA: Transfer X to accumulator - void TXA() { - A = X; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } + void TXA(); // TXS: Transfer X to stack pointer - void TXS() { memory.SetSP(X); } + void TXS(); // TXY: Transfer X to Y - void TXY() { - X = Y; - SetZeroFlag(X == 0); - SetNegativeFlag(X & 0x80); - } + void TXY(); // TYA: Transfer Y to accumulator - void TYA() { - A = Y; - SetZeroFlag(A == 0); - SetNegativeFlag(A & 0x80); - } + void TYA(); // TYX: Transfer Y to X - void TYX() { - Y = X; - SetZeroFlag(Y == 0); - SetNegativeFlag(Y & 0x80); - } + void TYX(); - // TODO: Make this communicate with the SNES class - // WAI: Wait for interrupt TESTME - void WAI() { - // Pull the RDY pin low - // Power consumption is reduced(?) - // RDY remains low until an external hardware interupt - // (NMI, IRQ, ABORT, or RESET) is received from the SNES class - } + // WAI: Wait for interrupt + void WAI(); - // XBA: Exchange B and A accumulator - void XBA() { - uint8_t lowByte = A & 0xFF; - uint8_t highByte = (A >> 8) & 0xFF; - A = (lowByte << 8) | highByte; - } + // WDM: Reserved for future expansion + void WDM(); - // XCE: Exchange Carry and Emulation Flags - void XCE() { - uint8_t carry = status & 0x01; - status &= ~0x01; - status |= E; - E = carry; - } + // XBA: Exchange B and A + void XBA(); + + // XCE: Exchange carry and emulation bits + void XCE(); uint8_t ReadByte(uint16_t address) const override; uint16_t ReadWord(uint16_t address) const override;