Move CPU instruction impl to source file
This commit is contained in:
@@ -1232,6 +1232,485 @@ void CPU::ANDAbsoluteLong(uint32_t address) {
|
|||||||
SetNegativeFlag(A & 0x80000000);
|
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<uint8_t>(X - 1);
|
||||||
|
SetZeroFlag(X == 0);
|
||||||
|
SetNegativeFlag(X & 0x80);
|
||||||
|
} else { // 16-bit
|
||||||
|
X = static_cast<uint16_t>(X - 1);
|
||||||
|
SetZeroFlag(X == 0);
|
||||||
|
SetNegativeFlag(X & 0x8000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEY: Decrement Y register
|
||||||
|
void CPU::DEY() {
|
||||||
|
if (GetIndexSize()) { // 8-bit
|
||||||
|
Y = static_cast<uint8_t>(Y - 1);
|
||||||
|
SetZeroFlag(Y == 0);
|
||||||
|
SetNegativeFlag(Y & 0x80);
|
||||||
|
} else { // 16-bit
|
||||||
|
Y = static_cast<uint16_t>(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<uint8_t>(X + 1);
|
||||||
|
SetZeroFlag(X == 0);
|
||||||
|
SetNegativeFlag(X & 0x80);
|
||||||
|
} else { // 16-bit
|
||||||
|
X = static_cast<uint16_t>(X + 1);
|
||||||
|
SetZeroFlag(X == 0);
|
||||||
|
SetNegativeFlag(X & 0x8000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// INY: Increment Y register
|
||||||
|
void CPU::INY() {
|
||||||
|
if (GetIndexSize()) { // 8-bit
|
||||||
|
Y = static_cast<uint8_t>(Y + 1);
|
||||||
|
SetZeroFlag(Y == 0);
|
||||||
|
SetNegativeFlag(Y & 0x80);
|
||||||
|
} else { // 16-bit
|
||||||
|
Y = static_cast<uint16_t>(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<uint8_t>(address & 0xFFFF);
|
||||||
|
// Set the PBR to the upper 8 bits of the address
|
||||||
|
PB = static_cast<uint8_t>((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) {
|
void CPU::SBC(uint16_t value, bool isImmediate) {
|
||||||
uint16_t operand;
|
uint16_t operand;
|
||||||
if (!GetAccumulatorSize()) { // 16-bit mode
|
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<uint8_t>(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<uint8_t>(X));
|
||||||
|
} else {
|
||||||
|
memory.WriteWord(address, X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STY: Store Y register
|
||||||
|
void CPU::STY(uint16_t address) {
|
||||||
|
if (GetIndexSize()) {
|
||||||
|
memory.WriteByte(address, static_cast<uint8_t>(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 emu
|
||||||
} // namespace app
|
} // namespace app
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
@@ -372,662 +372,274 @@ class CPU : public Memory, public Loggable {
|
|||||||
void AND(uint16_t address, bool isImmediate = false);
|
void AND(uint16_t address, bool isImmediate = false);
|
||||||
|
|
||||||
// ASL: Arithmetic shift left
|
// ASL: Arithmetic shift left
|
||||||
void ASL(uint16_t address) {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BCC: Branch if carry clear
|
// BCC: Branch if carry clear
|
||||||
void BCC(int8_t offset) {
|
void 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
|
// BCS: Branch if carry set
|
||||||
void BCS(int8_t offset) {
|
void 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)
|
// BEQ: Branch if equal
|
||||||
void BEQ(int8_t offset) {
|
void BEQ(int8_t offset);
|
||||||
if (GetZeroFlag()) { // If the zero flag is set
|
|
||||||
PC += offset; // Add the offset to the program counter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BIT: Bit test
|
// BIT: Bit test
|
||||||
void BIT(uint16_t address) {
|
void 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)
|
// BMI: Branch if minus
|
||||||
void BMI(int8_t offset) {
|
void 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)
|
// BNE: Branch if not equal
|
||||||
void BNE(int8_t offset) {
|
void 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)
|
// BPL: Branch if plus
|
||||||
void BPL(int8_t offset) {
|
void BPL(int8_t offset);
|
||||||
if (!GetNegativeFlag()) { // If the negative flag is clear
|
|
||||||
PC += offset; // Add the offset to the program counter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BRA: Branch always
|
// BRA: Branch always
|
||||||
void BRA(int8_t offset) { PC += offset; }
|
void BRA(int8_t offset);
|
||||||
|
|
||||||
// BRK: Break
|
// BRK: Force interrupt
|
||||||
void BRK() {
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BRL: Branch always long
|
// BRL: Branch always long
|
||||||
void BRL(int16_t offset) {
|
void BRL(int16_t offset);
|
||||||
PC += offset; // Add the offset to the program counter
|
|
||||||
}
|
|
||||||
|
|
||||||
// BVC: Branch if overflow clear
|
// BVC: Branch if overflow clear
|
||||||
void BVC(int8_t offset) {
|
void 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
|
// BVS: Branch if overflow set
|
||||||
void BVS(int8_t offset) {
|
void 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
|
// CLC: Clear carry flag
|
||||||
void CLC() { status &= ~0x01; }
|
void CLC();
|
||||||
|
|
||||||
// CLD: Clear decimal mode
|
// CLD: Clear decimal mode
|
||||||
void CLD() { status &= ~0x08; }
|
void CLD();
|
||||||
|
|
||||||
// CLI: Clear interrupt disable flag
|
// CLI: Clear interrupt disable bit
|
||||||
void CLI() { status &= ~0x04; }
|
void CLI();
|
||||||
|
|
||||||
// CLV: Clear overflow flag
|
// CLV: Clear overflow flag
|
||||||
void CLV() { status &= ~0x40; }
|
void CLV();
|
||||||
|
|
||||||
// CMP: Compare TESTME
|
// CMP: Compare
|
||||||
// n Set if MSB of result is set; else cleared
|
void CMP(uint16_t address, bool isImmediate = false);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// COP: Coprocessor TESTME
|
// COP: Coprocessor enable
|
||||||
void COP() {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPX: Compare X register
|
// CPX: Compare X register
|
||||||
void CPX(uint16_t value, bool isImmediate = false) {
|
void CPX(uint16_t address, 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
|
// CPY: Compare Y register
|
||||||
void CPY(uint16_t value, bool isImmediate = false) {
|
void CPY(uint16_t address, 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
|
// DEC: Decrement memory
|
||||||
void DEC(uint16_t address) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEX: Decrement X register
|
// DEX: Decrement X register
|
||||||
void DEX() {
|
void DEX();
|
||||||
if (GetIndexSize()) { // 8-bit
|
|
||||||
X = static_cast<uint8_t>(X - 1);
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x80);
|
|
||||||
} else { // 16-bit
|
|
||||||
X = static_cast<uint16_t>(X - 1);
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x8000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEY: Decrement Y register
|
// DEY: Decrement Y register
|
||||||
void DEY() {
|
void DEY();
|
||||||
if (GetIndexSize()) { // 8-bit
|
|
||||||
Y = static_cast<uint8_t>(Y - 1);
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x80);
|
|
||||||
} else { // 16-bit
|
|
||||||
Y = static_cast<uint16_t>(Y - 1);
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x8000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOR: Exclusive OR TESTMEs
|
// EOR: Exclusive OR
|
||||||
void EOR(uint16_t address, bool isImmediate = false) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// INC: Increment
|
// INC: Increment memory
|
||||||
void INC(uint16_t address) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// INX: Increment X register
|
// INX: Increment X register
|
||||||
void INX() {
|
void INX();
|
||||||
if (GetIndexSize()) { // 8-bit
|
|
||||||
X = static_cast<uint8_t>(X + 1);
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x80);
|
|
||||||
} else { // 16-bit
|
|
||||||
X = static_cast<uint16_t>(X + 1);
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x8000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// INY: Increment Y register
|
// INY: Increment Y register
|
||||||
void INY() {
|
void INY();
|
||||||
if (GetIndexSize()) { // 8-bit
|
|
||||||
Y = static_cast<uint8_t>(Y + 1);
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x80);
|
|
||||||
} else { // 16-bit
|
|
||||||
Y = static_cast<uint16_t>(Y + 1);
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x8000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// JMP: Jump
|
// JMP: Jump
|
||||||
void JMP(uint16_t address) {
|
void JMP(uint16_t address);
|
||||||
PC = address; // Set program counter to the new address
|
|
||||||
}
|
|
||||||
|
|
||||||
// JML: Jump long
|
// JML: Jump long
|
||||||
void JML(uint32_t address) {
|
void JML(uint32_t address);
|
||||||
// Set the lower 16 bits of PC to the lower 16 bits of the address
|
|
||||||
PC = static_cast<uint8_t>(address & 0xFFFF);
|
|
||||||
// Set the PBR to the upper 8 bits of the address
|
|
||||||
PB = static_cast<uint8_t>((address >> 16) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSR: Jump to subroutine
|
// JSR: Jump to subroutine
|
||||||
void JSR(uint16_t address) {
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSL: Jump to subroutine long
|
// JSL: Jump to subroutine long
|
||||||
void JSL(uint32_t address) {
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// LDA: Load accumulator
|
// LDA: Load accumulator
|
||||||
void LDA(uint16_t address, bool isImmediate = false) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LDX: Load X register
|
// LDX: Load X register
|
||||||
void LDX(uint16_t address, bool isImmediate = false) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LDY: Load Y register
|
// LDY: Load Y register
|
||||||
void LDY(uint16_t address, bool isImmediate = false) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LSR: Logical shift right
|
// LSR: Logical shift right
|
||||||
void LSR(uint16_t address) {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MVN: Move negative ```
|
// MVN: Block move next
|
||||||
// MVP: Move positive ```
|
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
|
// NOP: No operation
|
||||||
void NOP() {
|
void NOP();
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// ORA: Logical OR
|
// ORA: Logical inclusive OR
|
||||||
void ORA(uint16_t address, bool isImmediate = false) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PEA: Push effective address
|
// PEA: Push effective absolute address
|
||||||
void PEA() {
|
void PEA(uint16_t address);
|
||||||
uint16_t address = FetchWord();
|
|
||||||
memory.PushWord(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PEI: Push effective indirect address
|
// PEI: Push effective indirect address
|
||||||
void PEI() {
|
void PEI(uint16_t address);
|
||||||
uint16_t address = FetchWord();
|
|
||||||
memory.PushWord(memory.ReadWord(address));
|
|
||||||
}
|
|
||||||
|
|
||||||
// PER: Push effective PC-relative address
|
// PER: Push effective relative address
|
||||||
void PER() {
|
void PER(uint16_t address);
|
||||||
uint16_t address = FetchWord();
|
|
||||||
memory.PushWord(PC + address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PHA: Push Accumulator on Stack
|
// PHA: Push accumulator
|
||||||
void PHA() { memory.PushByte(A); }
|
void PHA();
|
||||||
|
|
||||||
// PHB: Push Data Bank Register on Stack
|
// PHB: Push data bank register
|
||||||
void PHB() { memory.PushByte(DB); }
|
void PHB();
|
||||||
|
|
||||||
// PHD: Push Program Bank Register on Stack
|
// PHD: Push direct page register
|
||||||
void PHD() { memory.PushWord(D); }
|
void PHD();
|
||||||
|
|
||||||
// PHK: Push Program Bank Register on Stack
|
// PHK: Push program bank register
|
||||||
void PHK() { memory.PushByte(PB); }
|
void PHK();
|
||||||
|
|
||||||
// PHP: Push Processor Status Register on Stack
|
// PHP: Push processor status (flags)
|
||||||
void PHP() { memory.PushByte(status); }
|
void PHP();
|
||||||
|
|
||||||
// PHX: Push X Index Register on Stack
|
// PHX: Push X register
|
||||||
void PHX() { memory.PushByte(X); }
|
void PHX();
|
||||||
|
|
||||||
// PHY: Push Y Index Register on Stack
|
// PHY: Push Y register
|
||||||
void PHY() { memory.PushByte(Y); }
|
void PHY();
|
||||||
|
|
||||||
// PLA: Pull Accumulator from Stack
|
// PLA: Pull accumulator
|
||||||
void PLA() {
|
void PLA();
|
||||||
A = memory.PopByte();
|
|
||||||
SetNegativeFlag((A & 0x80) != 0);
|
|
||||||
SetZeroFlag(A == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLB: Pull data bank register
|
// PLB: Pull data bank register
|
||||||
void PLB() {
|
void PLB();
|
||||||
DB = memory.PopByte();
|
|
||||||
SetNegativeFlag((DB & 0x80) != 0);
|
|
||||||
SetZeroFlag(DB == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull Direct Page Register from Stack
|
// PLD: Pull direct page register
|
||||||
void PLD() {
|
void PLD();
|
||||||
D = memory.PopWord();
|
|
||||||
SetNegativeFlag((D & 0x8000) != 0);
|
|
||||||
SetZeroFlag(D == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull Processor Status Register from Stack
|
// PLP: Pull processor status (flags)
|
||||||
void PLP() { status = memory.PopByte(); }
|
void PLP();
|
||||||
|
|
||||||
// PLX: Pull X Index Register from Stack
|
// PLX: Pull X register
|
||||||
void PLX() {
|
void PLX();
|
||||||
X = memory.PopByte();
|
|
||||||
SetNegativeFlag((A & 0x80) != 0);
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PHY: Pull Y Index Register from Stack
|
// PLY: Pull Y register
|
||||||
void PLY() {
|
void PLY();
|
||||||
Y = memory.PopByte();
|
|
||||||
SetNegativeFlag((A & 0x80) != 0);
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// REP: Reset status bits
|
// REP: Reset processor status bits
|
||||||
void REP() {
|
void REP();
|
||||||
auto byte = FetchByte();
|
|
||||||
status &= ~byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ROL: Rotate left
|
// ROL: Rotate left
|
||||||
void ROL(uint16_t address) {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ROR: Rotate right
|
// ROR: Rotate right
|
||||||
void ROR(uint16_t address) {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RTI: Return from interrupt
|
// RTI: Return from interrupt
|
||||||
void RTI() {
|
void RTI();
|
||||||
status = memory.PopByte();
|
|
||||||
PC = memory.PopWord();
|
|
||||||
}
|
|
||||||
|
|
||||||
// RTL: Return from subroutine long
|
// RTL: Return from subroutine long
|
||||||
void RTL() {
|
void RTL();
|
||||||
PC = memory.PopWord();
|
|
||||||
PB = memory.PopByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
// RTS: Return from subroutine
|
// RTS: Return from subroutine
|
||||||
void RTS() { PC = memory.PopWord() + 1; }
|
void RTS();
|
||||||
|
|
||||||
// SBC: Subtract with carry
|
// SBC: Subtract with carry
|
||||||
void SBC(uint16_t operand, bool isImmediate = false);
|
void SBC(uint16_t operand, bool isImmediate = false);
|
||||||
|
|
||||||
// SEC: Set carry flag
|
// SEC: Set carry flag
|
||||||
void SEC() { status |= 0x01; }
|
void SEC();
|
||||||
|
|
||||||
// SED: Set decimal mode
|
// SED: Set decimal mode
|
||||||
void SED() { status |= 0x08; }
|
void SED();
|
||||||
|
|
||||||
// SEI: Set interrupt disable flag
|
// SEI: Set interrupt disable status
|
||||||
void SEI() { status |= 0x04; }
|
void SEI();
|
||||||
|
|
||||||
// SEP: Set status bits
|
// SEP: Set processor status bits
|
||||||
void SEP() {
|
void SEP();
|
||||||
auto byte = FetchByte();
|
|
||||||
status |= byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
// STA: Store accumulator
|
// STA: Store accumulator
|
||||||
void STA(uint16_t address) {
|
void STA(uint16_t address);
|
||||||
if (GetAccumulatorSize()) {
|
|
||||||
memory.WriteByte(address, static_cast<uint8_t>(A));
|
|
||||||
} else {
|
|
||||||
memory.WriteWord(address, A);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make this work with the Clock class of the CPU
|
// STP: Stop the processor
|
||||||
// STP: Stop the clock
|
void STP();
|
||||||
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).
|
|
||||||
}
|
|
||||||
|
|
||||||
// STX: Store X register
|
// STX: Store X register
|
||||||
void STX(uint16_t address) {
|
void STX(uint16_t address);
|
||||||
if (GetIndexSize()) {
|
|
||||||
memory.WriteByte(address, static_cast<uint8_t>(X));
|
|
||||||
} else {
|
|
||||||
memory.WriteWord(address, X);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// STY: Store Y register
|
// STY: Store Y register
|
||||||
void STY(uint16_t address) {
|
void STY(uint16_t address);
|
||||||
if (GetIndexSize()) {
|
|
||||||
memory.WriteByte(address, static_cast<uint8_t>(Y));
|
|
||||||
} else {
|
|
||||||
memory.WriteWord(address, Y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// STZ: Store zero
|
// STZ: Store zero
|
||||||
void STZ(uint16_t address) {
|
void STZ(uint16_t address);
|
||||||
if (GetAccumulatorSize()) {
|
|
||||||
memory.WriteByte(address, 0x00);
|
|
||||||
} else {
|
|
||||||
memory.WriteWord(address, 0x0000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TAX: Transfer accumulator to X
|
// TAX: Transfer accumulator to X
|
||||||
void TAX() {
|
void TAX();
|
||||||
X = A;
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TAY: Transfer accumulator to Y
|
// TAY: Transfer accumulator to Y
|
||||||
void TAY() {
|
void TAY();
|
||||||
Y = A;
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCD: Transfer accumulator to direct page register
|
// TCD: Transfer 16-bit accumulator to direct page register
|
||||||
void TCD() {
|
void TCD();
|
||||||
D = A;
|
|
||||||
SetZeroFlag(D == 0);
|
|
||||||
SetNegativeFlag(D & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCS: Transfer accumulator to stack pointer
|
// TCS: Transfer 16-bit accumulator to stack pointer
|
||||||
void TCS() { memory.SetSP(A); }
|
void TCS();
|
||||||
|
|
||||||
// TDC: Transfer direct page register to accumulator
|
// TDC: Transfer direct page register to 16-bit accumulator
|
||||||
void TDC() {
|
void TDC();
|
||||||
A = D;
|
|
||||||
SetZeroFlag(A == 0);
|
|
||||||
SetNegativeFlag(A & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TRB: Test and reset bits
|
// TRB: Test and reset bits
|
||||||
void TRB(uint16_t address) {
|
void 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
|
// TSB: Test and set bits
|
||||||
void TSB(uint16_t address) {
|
void 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
|
// TSC: Transfer stack pointer to 16-bit accumulator
|
||||||
void TSC() {
|
void TSC();
|
||||||
A = SP();
|
|
||||||
SetZeroFlag(A == 0);
|
|
||||||
SetNegativeFlag(A & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TSX: Transfer stack pointer to X
|
// TSX: Transfer stack pointer to X
|
||||||
void TSX() {
|
void TSX();
|
||||||
X = SP();
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TXA: Transfer X to accumulator
|
// TXA: Transfer X to accumulator
|
||||||
void TXA() {
|
void TXA();
|
||||||
A = X;
|
|
||||||
SetZeroFlag(A == 0);
|
|
||||||
SetNegativeFlag(A & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TXS: Transfer X to stack pointer
|
// TXS: Transfer X to stack pointer
|
||||||
void TXS() { memory.SetSP(X); }
|
void TXS();
|
||||||
|
|
||||||
// TXY: Transfer X to Y
|
// TXY: Transfer X to Y
|
||||||
void TXY() {
|
void TXY();
|
||||||
X = Y;
|
|
||||||
SetZeroFlag(X == 0);
|
|
||||||
SetNegativeFlag(X & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TYA: Transfer Y to accumulator
|
// TYA: Transfer Y to accumulator
|
||||||
void TYA() {
|
void TYA();
|
||||||
A = Y;
|
|
||||||
SetZeroFlag(A == 0);
|
|
||||||
SetNegativeFlag(A & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TYX: Transfer Y to X
|
// TYX: Transfer Y to X
|
||||||
void TYX() {
|
void TYX();
|
||||||
Y = X;
|
|
||||||
SetZeroFlag(Y == 0);
|
|
||||||
SetNegativeFlag(Y & 0x80);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make this communicate with the SNES class
|
// WAI: Wait for interrupt
|
||||||
// WAI: Wait for interrupt TESTME
|
void WAI();
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// XBA: Exchange B and A accumulator
|
// WDM: Reserved for future expansion
|
||||||
void XBA() {
|
void WDM();
|
||||||
uint8_t lowByte = A & 0xFF;
|
|
||||||
uint8_t highByte = (A >> 8) & 0xFF;
|
|
||||||
A = (lowByte << 8) | highByte;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XCE: Exchange Carry and Emulation Flags
|
// XBA: Exchange B and A
|
||||||
void XCE() {
|
void XBA();
|
||||||
uint8_t carry = status & 0x01;
|
|
||||||
status &= ~0x01;
|
// XCE: Exchange carry and emulation bits
|
||||||
status |= E;
|
void XCE();
|
||||||
E = carry;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t ReadByte(uint16_t address) const override;
|
uint8_t ReadByte(uint16_t address) const override;
|
||||||
uint16_t ReadWord(uint16_t address) const override;
|
uint16_t ReadWord(uint16_t address) const override;
|
||||||
|
|||||||
Reference in New Issue
Block a user