Mesen-X/Core/CPU.cpp

186 lines
9 KiB
C++
Raw Normal View History

2014-06-10 16:58:37 -04:00
#include "stdafx.h"
#include "CPU.h"
int32_t CPU::CycleCount = 0;
int32_t CPU::RelativeCycleCount = 0;
2014-06-22 10:07:40 -04:00
uint32_t CPU::CyclePenalty = 0;
2014-06-15 09:35:17 -04:00
bool CPU::NMIFlag = false;
uint32_t CPU::IRQFlag = 0;
2014-06-14 18:20:56 -04:00
CPU::CPU(MemoryManager *memoryManager) : _memoryManager(memoryManager)
{
Func opTable[] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
&CPU::BRK, &CPU::ORA, nullptr, nullptr, &CPU::NOP, &CPU::ORA, &CPU::ASL_Memory, nullptr, &CPU::PHP, &CPU::ORA, &CPU::ASL_Acc, nullptr, &CPU::NOP, &CPU::ORA, &CPU::ASL_Memory, nullptr, //0
&CPU::BPL, &CPU::ORA, nullptr, nullptr, &CPU::NOP, &CPU::ORA, &CPU::ASL_Memory, nullptr, &CPU::CLC, &CPU::ORA, nullptr, nullptr, &CPU::NOP, &CPU::ORA, &CPU::ASL_Memory, nullptr, //1
&CPU::JSR, &CPU::AND, nullptr, nullptr, &CPU::BIT, &CPU::AND, &CPU::ROL_Memory, nullptr, &CPU::PLP, &CPU::AND, &CPU::ROL_Acc, nullptr, &CPU::BIT, &CPU::AND, &CPU::ROL_Memory, nullptr, //2
&CPU::BMI, &CPU::AND, nullptr, nullptr, &CPU::NOP, &CPU::AND, &CPU::ROL_Memory, nullptr, &CPU::SEC, &CPU::AND, nullptr, nullptr, &CPU::NOP, &CPU::AND, &CPU::ROL_Memory, nullptr, //3
&CPU::RTI, &CPU::EOR, nullptr, nullptr, &CPU::NOP, &CPU::EOR, &CPU::LSR_Memory, nullptr, &CPU::PHA, &CPU::EOR, &CPU::LSR_Acc, nullptr, &CPU::JMP_Abs, &CPU::EOR, &CPU::LSR_Memory, nullptr, //4
&CPU::BVC, &CPU::EOR, nullptr, nullptr, &CPU::NOP, &CPU::EOR, &CPU::LSR_Memory, nullptr, &CPU::CLI, &CPU::EOR, nullptr, nullptr, &CPU::NOP, &CPU::EOR, &CPU::LSR_Memory, nullptr, //5
&CPU::RTS, &CPU::ADC, nullptr, nullptr, &CPU::NOP, &CPU::ADC, &CPU::ROR_Memory, nullptr, &CPU::PLA, &CPU::ADC, &CPU::ROR_Acc, nullptr, &CPU::JMP_Ind, &CPU::ADC, &CPU::ROR_Memory, nullptr, //6
&CPU::BVS, &CPU::ADC, nullptr, nullptr, &CPU::NOP, &CPU::ADC, &CPU::ROR_Memory, nullptr, &CPU::SEI, &CPU::ADC, nullptr, nullptr, &CPU::NOP, &CPU::ADC, &CPU::ROR_Memory, nullptr, //7
&CPU::NOP, &CPU::STA, &CPU::NOP, nullptr, &CPU::STY, &CPU::STA, &CPU::STX, nullptr, &CPU::DEY, &CPU::NOP, &CPU::TXA, nullptr, &CPU::STY, &CPU::STA, &CPU::STX, nullptr, //8
&CPU::BCC, &CPU::STA, nullptr, nullptr, &CPU::STY, &CPU::STA, &CPU::STX, nullptr, &CPU::TYA, &CPU::STA, &CPU::TXS, nullptr, nullptr, &CPU::STA, nullptr, nullptr, //9
&CPU::LDY, &CPU::LDA, &CPU::LDX, nullptr, &CPU::LDY, &CPU::LDA, &CPU::LDX, nullptr, &CPU::TAY, &CPU::LDA, &CPU::TAX, nullptr, &CPU::LDY, &CPU::LDA, &CPU::LDX, nullptr, //A
&CPU::BCS, &CPU::LDA, nullptr, nullptr, &CPU::LDY, &CPU::LDA, &CPU::LDX, nullptr, &CPU::CLV, &CPU::LDA, &CPU::TSX, nullptr, &CPU::LDY, &CPU::LDA, &CPU::LDX, nullptr, //B
&CPU::CPY, &CPU::CPA, &CPU::NOP, nullptr, &CPU::CPY, &CPU::CPA, &CPU::DEC, nullptr, &CPU::INY, &CPU::CPA, &CPU::DEX, nullptr, &CPU::CPY, &CPU::CPA, &CPU::DEC, nullptr, //C
&CPU::BNE, &CPU::CPA, nullptr, nullptr, &CPU::NOP, &CPU::CPA, &CPU::DEC, nullptr, &CPU::CLD, &CPU::CPA, nullptr, nullptr, &CPU::NOP, &CPU::CPA, &CPU::DEC, nullptr, //D
&CPU::CPX, &CPU::SBC, &CPU::NOP, nullptr, &CPU::CPX, &CPU::SBC, &CPU::INC, nullptr, &CPU::INX, &CPU::SBC, &CPU::NOP, nullptr, &CPU::CPX, &CPU::SBC, &CPU::INC, nullptr, //E
&CPU::BEQ, &CPU::SBC, nullptr, nullptr, &CPU::NOP, &CPU::SBC, &CPU::INC, nullptr, &CPU::SED, &CPU::SBC, nullptr, nullptr, &CPU::NOP, &CPU::SBC, &CPU::INC, nullptr //F
};
AddrMode addrMode[] = {
Imm, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Abs, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imp, IndX, None, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndYW, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsYW, Imp, AbsY, AbsXW, AbsXW, AbsYW, AbsY,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndY, ZeroX, ZeroX, ZeroY, ZeroY, Imp, AbsY, Imp, AbsY, AbsX, AbsX, AbsY, AbsY,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
Imm, IndX, Imm, IndX, Zero, Zero, Zero, Zero, Imp, Imm, Imp, Imm, Abs, Abs, Abs, Abs,
Rel, IndY, None, IndYW, ZeroX, ZeroX, ZeroX, ZeroX, Imp, AbsY, Imp, AbsYW, AbsX, AbsX, AbsXW, AbsXW,
};
2014-06-21 00:37:20 -04:00
uint8_t cycles[] {
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4,
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
};
uint8_t cyclesPageCrossed[] {
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
2014-06-21 11:23:33 -04:00
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2014-06-21 00:37:20 -04:00
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
2014-06-21 11:23:33 -04:00
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2014-06-21 00:37:20 -04:00
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
2014-06-21 11:23:33 -04:00
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2014-06-21 00:37:20 -04:00
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
2014-06-21 11:23:33 -04:00
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2014-06-21 00:37:20 -04:00
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
2014-06-21 11:23:33 -04:00
3, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
2014-06-21 00:37:20 -04:00
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4,
2014-06-21 11:23:33 -04:00
3, 6, 2, 5, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5,
2014-06-21 00:37:20 -04:00
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
2014-06-21 11:23:33 -04:00
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
2014-06-21 00:37:20 -04:00
2, 6, 3, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
2014-06-21 11:23:33 -04:00
3, 6, 2, 8, 4, 4, 6, 6, 2, 5, 2, 7, 5, 5, 7, 7,
};
memcpy(_opTable, opTable, sizeof(opTable));
memcpy(_cycles, cycles, sizeof(cycles));
memcpy(_addrMode, addrMode, sizeof(addrMode));
memcpy(_cyclesPageCrossed, cyclesPageCrossed, sizeof(cyclesPageCrossed));
}
void CPU::Reset(bool softReset)
2014-06-10 16:58:37 -04:00
{
CPU::NMIFlag = false;
CPU::IRQFlag = 0;
2014-06-14 18:20:56 -04:00
CPU::CycleCount = 0;
CPU::RelativeCycleCount = 0;
_state.PC = MemoryReadWord(CPU::ResetVector);
if(softReset) {
SetFlags(PSFlags::Interrupt);
_state.SP -= 0x03;
} else {
_state.A = 0;
_state.SP = 0xFD;
_state.X = 0;
_state.Y = 0;
_state.PS = PSFlags::Reserved | PSFlags::Interrupt;
_runIRQ = false;
_runNMI = false;
}
2014-06-10 16:58:37 -04:00
}
2014-06-21 15:43:41 -04:00
uint32_t CPU::Exec()
2014-06-10 16:58:37 -04:00
{
//static ofstream log("log.txt", ios::out | ios::binary);
2014-06-21 15:43:41 -04:00
uint32_t executedCycles = 0;
if(!_runNMI && !_runIRQ) {
uint8_t opCode = GetOPCode();
2014-06-21 00:37:20 -04:00
if(CPU::NMIFlag) {
_runNMI = true;
} else if(opCode != 0x40 && CPU::IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
_runIRQ = true;
2014-06-21 00:37:20 -04:00
}
_instAddrMode = _addrMode[opCode];
2014-06-15 09:35:17 -04:00
if(_opTable[opCode] != nullptr) {
//std::cout << std::hex << (_state.PC - 1) << ": " << (short)opCode << std::endl;
2014-06-15 09:35:17 -04:00
(this->*_opTable[opCode])();
2014-06-22 10:07:40 -04:00
executedCycles = (IsPageCrossed() ? _cyclesPageCrossed[opCode] : _cycles[opCode]);
2014-06-15 09:35:17 -04:00
} else {
GetOperandAddr();
std::cout << "Invalid opcode: " << std::hex << (short)opCode;
//throw exception("Invalid opcode");
2014-06-15 09:35:17 -04:00
}
if(!_runIRQ && opCode == 0x40 && CPU::IRQFlag > 0 && !CheckFlag(PSFlags::Interrupt)) {
//"If an IRQ is pending and an RTI is executed that clears the I flag, the CPU will invoke the IRQ handler immediately after RTI finishes executing."
_runIRQ = true;
}
2014-06-14 18:20:56 -04:00
} else {
if(_runNMI) {
NMI();
_runNMI = false;
CPU::NMIFlag = false;
} else if(_runIRQ) {
IRQ();
}
_runIRQ = false;
2014-06-21 15:43:41 -04:00
executedCycles = 7;
2014-06-10 16:58:37 -04:00
}
2014-06-21 15:43:41 -04:00
CPU::CycleCount += executedCycles;
2014-06-22 10:07:40 -04:00
return executedCycles + GetCyclePenalty();
2014-06-10 16:58:37 -04:00
}
2014-06-25 21:52:37 -04:00
void CPU::EndFrame()
{
CPU::RelativeCycleCount += CPU::CycleCount;
CPU::CycleCount = 0;
}
2014-06-25 21:52:37 -04:00
void CPU::StreamState(bool saving)
{
Stream<uint16_t>(_state.PC);
Stream<uint8_t>(_state.SP);
Stream<uint8_t>(_state.PS);
2014-06-25 21:52:37 -04:00
Stream<uint8_t>(_state.A);
Stream<uint8_t>(_state.X);
Stream<uint8_t>(_state.Y);
Stream<int32_t>(CPU::CycleCount);
2014-06-25 21:52:37 -04:00
Stream<bool>(CPU::NMIFlag);
Stream<uint32_t>(CPU::IRQFlag);
Stream<bool>(_runNMI);
Stream<bool>(_runIRQ);
Stream<int32_t>(CPU::RelativeCycleCount);
2014-06-25 21:52:37 -04:00
}