1
0
Fork 0
2019-nes-emulator/Source/CPU/Instructions.cpp

752 lines
12 KiB
C++

#include "CPU/CPU.hpp"
#include "NES.hpp"
// --------------- ARITHMETIC --------------- //
void CPU::ADC()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
uint16_t tempSum = acc + fetchedByte;
tempSum += status.carry;
status.carry = (tempSum & 0xFF00u) ? 1u : 0u;
bool accSign = IsNegative(acc);
bool valSign = IsNegative(fetchedByte);
bool sumSign = IsNegative(tempSum);
acc = tempSum;
// If sign of operands does not match sign of result -> overflow
status.overflow = ((accSign == valSign) && (accSign != sumSign)) ? 1u : 0u;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
cycles += (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::SBC()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
uint16_t tempDiff = acc - fetchedByte;
tempDiff -= (1u - status.carry);
status.carry = (tempDiff & 0xFF00) ? 0u : 1u;
bool accSign = IsNegative(acc);
bool valSign = IsNegative(fetchedByte);
bool sumSign = IsNegative(tempDiff);
// Set and truncate most-significant byte of temp sum
acc = tempDiff;
// If sign of operands does not match sign of result -> overflow
status.overflow = ((accSign != valSign) && (valSign == sumSign)) ? 1u : 0u;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
cycles += (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::CMP()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
status.carry = (acc >= fetchedByte) ? 1u : 0u;
status.zero = (acc == fetchedByte) ? 1u : 0u;
status.negative = (IsNegative(acc - fetchedByte)) ? 1u : 0u;
cycles += (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::CPX()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
status.carry = (x >= fetchedByte) ? 1u : 0u;
status.zero = (x == fetchedByte) ? 1u : 0u;
status.negative = (IsNegative(x - fetchedByte)) ? 1u : 0u;
}
void CPU::CPY()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
status.carry = (y >= fetchedByte) ? 1u : 0u;
status.zero = (y == fetchedByte) ? 1u : 0u;
status.negative = (IsNegative(y - fetchedByte)) ? 1u : 0u;
}
// --------------- BRANCHES --------------- //
void CPU::BPL()
{
if (!status.negative)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BMI()
{
if (status.negative)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BVC()
{
if (!status.overflow)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BVS()
{
if (status.overflow)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BCC()
{
if (!status.carry)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BCS()
{
if (status.carry)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BNE()
{
if (!status.zero)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
void CPU::BEQ()
{
if (status.zero)
{
pc = fetchedAddress;
cycles += (pageBoundaryCrossed) ? 2u : 1u;
}
}
// --------------- INCREMENT/DECREMENT --------------- //
void CPU::INC()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
++fetchedByte;
nes->Write(BusSource::CPU, fetchedAddress, fetchedByte);
status.zero = fetchedByte ? 0u : 1u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
}
void CPU::INX()
{
++x;
status.zero = x ? 0u : 1u;
status.negative = (IsNegative(x)) ? 1u : 0u;
}
void CPU::INY()
{
++y;
status.zero = y ? 0u : 1u;
status.negative = (IsNegative(y)) ? 1u : 0u;
}
void CPU::DEC()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
--fetchedByte;
nes->Write(BusSource::CPU, fetchedAddress, fetchedByte);
status.zero = fetchedByte ? 0u : 1u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
}
void CPU::DEX()
{
--x;
status.zero = x ? 0u : 1u;
status.negative = (IsNegative(x)) ? 1u : 0u;
}
void CPU::DEY()
{
--y;
status.zero = y ? 0u : 1u;
status.negative = (IsNegative(y)) ? 1u : 0u;
}
// --------------- JUMPS & CALLS --------------- //
void CPU::JMP()
{
pc = fetchedAddress;
}
void CPU::JSR()
{
uint8_t pcMsb = ((pc - 1u) & 0xFF00u) >> 8u;
uint8_t pcLsb = (pc - 1u) & 0xFFu;
StackPush(pcMsb);
StackPush(pcLsb);
pc = fetchedAddress;
}
void CPU::RTS()
{
uint8_t pcLsb = StackPop();
uint8_t pcMsb = StackPop();
uint16_t address = ComposeAddress(pcMsb, pcLsb) + 1u;
pc = address;
}
// --------------- LOAD/STORE --------------- //
void CPU::LDA()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
cycles += (pageBoundaryCrossed) ? 1u : 0u;
acc = fetchedByte;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
void CPU::LDX()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
cycles += (pageBoundaryCrossed) ? 1u : 0u;
x = fetchedByte;
status.zero = x ? 0u : 1u;
status.negative = (IsNegative(x)) ? 1u : 0u;
}
void CPU::LDY()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
cycles += (pageBoundaryCrossed) ? 1u : 0u;
y = fetchedByte;
status.zero = y ? 0u : 1u;
status.negative = (IsNegative(y)) ? 1u : 0u;
}
void CPU::STA()
{
nes->Write(BusSource::CPU, fetchedAddress, acc);
}
void CPU::STX()
{
nes->Write(BusSource::CPU, fetchedAddress, x);
}
void CPU::STY()
{
nes->Write(BusSource::CPU, fetchedAddress, y);
}
// --------------- LOGICAL --------------- //
void CPU::AND()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
acc &= fetchedByte;
cycles += (pageBoundaryCrossed) ? 1u : 0u;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
void CPU::EOR()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
acc ^= fetchedByte;
cycles += (pageBoundaryCrossed) ? 1u : 0u;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
void CPU::ORA()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
acc |= fetchedByte;
cycles += (pageBoundaryCrossed) ? 1u : 0u;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
void CPU::BIT()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
status.zero = (acc & fetchedByte) ? 0u : 1u;
status.overflow = (TestBits(fetchedByte, (1u << 6u))) ? 1u : 0u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
}
// --------------- SHIFTS --------------- //
void CPU::ASL()
{
if (instructions[opcode].fetch == &CPU::Implicit)
{
fetchedByte = acc;
}
else
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
}
// Set carry to fetchedByte of MSB pre-shift
if (TestBits(fetchedByte, 0x80))
{
status.carry = 1u;
}
else
{
status.carry = 0u;
}
fetchedByte <<= 1u;
status.zero = fetchedByte ? 0u : 1u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
if (instructions[opcode].fetch == &CPU::Implicit)
{
acc = fetchedByte;
}
else
{
nes->Write(BusSource::CPU, fetchedAddress, fetchedByte);
}
}
void CPU::LSR()
{
if (instructions[opcode].fetch == &CPU::Implicit)
{
fetchedByte = acc;
}
else
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
}
// Set carry to fetchedByte of LSB pre-shift
if (TestBits(fetchedByte, 0x01))
{
status.carry = 1u;
}
else
{
status.carry = 0u;
}
fetchedByte >>= 1u;
status.zero = fetchedByte ? 0u : 1u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
if (instructions[opcode].fetch == &CPU::Implicit)
{
acc = fetchedByte;
}
else
{
nes->Write(BusSource::CPU, fetchedAddress, fetchedByte);
}
}
void CPU::ROL()
{
if (instructions[opcode].fetch == &CPU::Implicit)
{
fetchedByte = acc;
}
else
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
}
uint8_t oldCarry = status.carry;
// Set carry to fetchedByte of MSB pre-shift
if (TestBits(fetchedByte, 0x80))
{
status.carry = 1u;
}
else
{
status.carry = 0u;
}
fetchedByte <<= 1u;
// Put old carry at LSB
if (oldCarry)
{
fetchedByte |= 0x1u;
}
status.zero = fetchedByte ? 0u : 1u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
if (instructions[opcode].fetch == &CPU::Implicit)
{
acc = fetchedByte;
}
else
{
nes->Write(BusSource::CPU, fetchedAddress, fetchedByte);
}
}
void CPU::ROR()
{
if (instructions[opcode].fetch == &CPU::Implicit)
{
fetchedByte = acc;
}
else
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
}
uint8_t oldCarry = status.carry;
// Set carry to fetchedByte of LSB pre-shift
if (TestBits(fetchedByte, 0x01))
{
status.carry = 1u;
}
else
{
status.carry = 0u;
}
fetchedByte >>= 1u;
// Put old carry at MSB
if (oldCarry)
{
fetchedByte |= 0x80u;
}
status.zero = fetchedByte ? 0u : 1u;
status.negative = (IsNegative(fetchedByte)) ? 1u : 0u;
if (instructions[opcode].fetch == &CPU::Implicit)
{
acc = fetchedByte;
}
else
{
nes->Write(BusSource::CPU, fetchedAddress, fetchedByte);
}
}
// --------------- STACK --------------- //
void CPU::PHP()
{
Status statusCopy = status;
statusCopy.b1 = 1u;
statusCopy.b0 = 1u;
StackPush(statusCopy.GetByte());
}
void CPU::PLP()
{
uint8_t stackCopy = StackPop();
status.SetByte(stackCopy);
status.b1 = 1u;
status.b0 = 0u;
}
void CPU::PHA()
{
StackPush(acc);
}
void CPU::PLA()
{
acc = StackPop();
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
// --------------- STATUS FLAG CHANGES --------------- //
void CPU::CLC()
{
status.carry = 0u;
}
void CPU::SEC()
{
status.carry = 1u;
}
void CPU::CLI()
{
status.interruptDisable = 0u;
}
void CPU::SEI()
{
status.interruptDisable = 1u;
}
void CPU::CLV()
{
status.overflow = 0u;
}
void CPU::CLD()
{
status.decimal = 0u;
}
void CPU::SED()
{
status.decimal = 1u;
}
// --------------- SYSTEM --------------- //
void CPU::BRK()
{
uint8_t pcMsb = (pc & 0xFF00u) >> 8u;
uint8_t pcLsb = pc & 0xFFu;
StackPush(pcMsb);
StackPush(pcLsb);
Status statusCopy = status;
statusCopy.b1 = 1u;
statusCopy.b0 = 0u;
StackPush(statusCopy.GetByte());
pcMsb = nes->Read(BusSource::CPU, IRQ_VECTOR_MSB);
pcLsb = nes->Read(BusSource::CPU, IRQ_VECTOR_LSB);
pc = ComposeAddress(pcMsb, pcLsb);
}
void CPU::NOP()
{
// Do nothing
cycles += (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::RTI()
{
uint8_t statusCopy = StackPop();
status.SetByte(statusCopy);
status.b1 = 1u;
uint8_t pcLsb = StackPop();
uint8_t pcMsb = StackPop();
pc = ComposeAddress(pcMsb, pcLsb);
}
// --------------- TRANSFERS --------------- //
void CPU::TXA()
{
acc = x;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
void CPU::TYA()
{
acc = y;
status.zero = acc ? 0u : 1u;
status.negative = (IsNegative(acc)) ? 1u : 0u;
}
void CPU::TXS()
{
sp = x;
}
void CPU::TAY()
{
y = acc;
status.zero = y ? 0u : 1u;
status.negative = (IsNegative(y)) ? 1u : 0u;
}
void CPU::TAX()
{
x = acc;
status.zero = x ? 0u : 1u;
status.negative = (IsNegative(x)) ? 1u : 0u;
}
void CPU::TSX()
{
x = sp;
status.zero = x ? 0u : 1u;
status.negative = (IsNegative(x)) ? 1u : 0u;
}
// --------------- UNOFFICIAL --------------- //
void CPU::LAX()
{
LDA();
TAX();
}
void CPU::SAX()
{
uint8_t byte = acc & x;
nes->Write(BusSource::CPU, fetchedAddress, byte);
}
void CPU::DCP()
{
DEC();
CMP();
cycles -= (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::ISC()
{
INC();
SBC();
cycles -= (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::SLO()
{
ASL();
ORA();
cycles -= (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::RLA()
{
ROL();
AND();
cycles -= (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::SRE()
{
LSR();
EOR();
cycles -= (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::RRA()
{
ROR();
ADC();
cycles -= (pageBoundaryCrossed) ? 1u : 0u;
}
void CPU::ANC()
{
AND();
status.carry = (fetchedByte & 0x80u) >> 7u;
}
void CPU::ALR()
{
AND();
LSR();
}
void CPU::ARR()
{
AND();
ROR();
status.carry = (fetchedByte & 0x40u) >> 6u;
status.overflow = ((fetchedByte & 0x40u) >> 6u) ^ ((fetchedByte & 0x20u) >> 5u);
}
void CPU::AXS()
{
fetchedByte = nes->Read(BusSource::CPU, fetchedAddress);
x = (acc & x) - fetchedByte;
status.negative = (IsNegative(x)) ? 1u : 0u;
status.zero = x ? 0u : 1u;
status.carry = (x & 0xFF00u) ? 1u : 0u;
}