From 0b7ad7c0db74a4fb35b1ab01feb9b357a0b4ee11 Mon Sep 17 00:00:00 2001 From: Sour Date: Thu, 21 Feb 2019 22:10:41 -0500 Subject: [PATCH] CPU: Added all idle cycles + added DRAM refresh delay --- Core/Cpu.Instructions.cpp | 382 ++++++++++++++++++++++++++++++++------ Core/Cpu.cpp | 372 ++++++++++++++++++++++++++----------- Core/Cpu.h | 57 +++++- Core/MemoryManager.h | 22 ++- Core/Ppu.cpp | 7 + 5 files changed, 666 insertions(+), 174 deletions(-) diff --git a/Core/Cpu.Instructions.cpp b/Core/Cpu.Instructions.cpp index f5a55d6..22d8136 100644 --- a/Core/Cpu.Instructions.cpp +++ b/Core/Cpu.Instructions.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "Cpu.h" +#include "MemoryManager.h" /************************ Add/substract operations @@ -217,6 +218,12 @@ void Cpu::BranchRelative(bool branch) { int8_t offset = _operand; if(branch) { + Idle(); + if(_state.EmulationMode) { + if(((uint16_t)(_state.PC + offset) & 0xFF00) != (_state.PC & 0xFF00)) { + Idle(); + } + } _state.PC = (uint16_t)(_state.PC + offset); } } @@ -307,6 +314,16 @@ void Cpu::INC() IncDec(1); } +void Cpu::DEC_Acc() +{ + SetRegister(_state.A, _state.A - 1, CheckFlag(ProcFlags::MemoryMode8)); +} + +void Cpu::INC_Acc() +{ + SetRegister(_state.A, _state.A + 1, CheckFlag(ProcFlags::MemoryMode8)); +} + void Cpu::IncDecReg(uint16_t ®, int8_t offset) { SetRegister(reg, reg + offset, CheckFlag(ProcFlags::IndexMode8)); @@ -314,18 +331,16 @@ void Cpu::IncDecReg(uint16_t ®, int8_t offset) void Cpu::IncDec(int8_t offset) { - if(_instAddrMode == AddrMode::Acc) { - SetRegister(_state.A, _state.A + offset, CheckFlag(ProcFlags::MemoryMode8)); + if(CheckFlag(ProcFlags::MemoryMode8)) { + uint8_t value = GetByteValue() + offset; + SetZeroNegativeFlags(value); + Idle(); + Write(_operand, value); } else { - if(CheckFlag(ProcFlags::MemoryMode8)) { - uint8_t value = GetByteValue() + offset; - SetZeroNegativeFlags(value); - Write(_operand, value); - } else { - uint16_t value = GetWordValue() + offset; - SetZeroNegativeFlags(value); - WriteWord(_operand, value); - } + uint16_t value = GetWordValue() + offset; + SetZeroNegativeFlags(value); + Idle(); + WriteWord(_operand, value); } } @@ -388,6 +403,7 @@ void Cpu::JMP() void Cpu::JSL() { PushByte(_state.K); + Idle(); PushWord(_state.PC - 1); _state.K = (_operand >> 16) & 0xFF; _state.PC = (uint16_t)_operand; @@ -401,6 +417,9 @@ void Cpu::JSR() void Cpu::RTI() { + Idle(); + Idle(); + if(_state.EmulationMode) { SetPS(PopByte()); _state.PC = PopWord(); @@ -413,6 +432,9 @@ void Cpu::RTI() void Cpu::RTL() { + Idle(); + Idle(); + _state.PC = PopWord(); _state.PC++; _state.K = PopByte(); @@ -420,7 +442,11 @@ void Cpu::RTL() void Cpu::RTS() { + Idle(); + Idle(); + _state.PC = PopWord(); + Idle(); _state.PC++; } @@ -429,6 +455,9 @@ Interrupts ***********/ void Cpu::ProcessInterrupt(uint16_t vector) { + Idle(); + Idle(); + if(_state.EmulationMode) { PushWord(_state.PC); PushByte(_state.PS | 0x20); @@ -541,71 +570,83 @@ template T Cpu::RollRight(T value) return result; } +void Cpu::ASL_Acc() +{ + if(CheckFlag(ProcFlags::MemoryMode8)) { + _state.A = (_state.A & 0xFF00) | (ShiftLeft((uint8_t)_state.A)); + } else { + _state.A = ShiftLeft(_state.A); + } +} + void Cpu::ASL() { - if(_instAddrMode == AddrMode::Acc) { - if(CheckFlag(ProcFlags::MemoryMode8)) { - _state.A = (_state.A & 0xFF00) | (ShiftLeft((uint8_t)_state.A)); - } else { - _state.A = ShiftLeft(_state.A); - } + if(CheckFlag(ProcFlags::MemoryMode8)) { + Idle(); + Write(_operand, ShiftLeft(GetByteValue())); } else { - if(CheckFlag(ProcFlags::MemoryMode8)) { - Write(_operand, ShiftLeft(GetByteValue())); - } else { - WriteWord(_operand, ShiftLeft(GetWordValue())); - } + Idle(); + WriteWord(_operand, ShiftLeft(GetWordValue())); + } +} + +void Cpu::LSR_Acc() +{ + if(CheckFlag(ProcFlags::MemoryMode8)) { + _state.A = (_state.A & 0xFF00) | ShiftRight((uint8_t)_state.A); + } else { + _state.A = ShiftRight(_state.A); } } void Cpu::LSR() { - if(_instAddrMode == AddrMode::Acc) { - if(CheckFlag(ProcFlags::MemoryMode8)) { - _state.A = (_state.A & 0xFF00) | ShiftRight((uint8_t)_state.A); - } else { - _state.A = ShiftRight(_state.A); - } + if(CheckFlag(ProcFlags::MemoryMode8)) { + Idle(); + Write(_operand, ShiftRight(GetByteValue())); } else { - if(CheckFlag(ProcFlags::MemoryMode8)) { - Write(_operand, ShiftRight(GetByteValue())); - } else { - WriteWord(_operand, ShiftRight(GetWordValue())); - } + Idle(); + WriteWord(_operand, ShiftRight(GetWordValue())); + } +} + +void Cpu::ROL_Acc() +{ + if(CheckFlag(ProcFlags::MemoryMode8)) { + _state.A = (_state.A & 0xFF00) | RollLeft((uint8_t)_state.A); + } else { + _state.A = RollLeft(_state.A); } } void Cpu::ROL() { - if(_instAddrMode == AddrMode::Acc) { - if(CheckFlag(ProcFlags::MemoryMode8)) { - _state.A = (_state.A & 0xFF00) | RollLeft((uint8_t)_state.A); - } else { - _state.A = RollLeft(_state.A); - } + if(CheckFlag(ProcFlags::MemoryMode8)) { + Idle(); + Write(_operand, RollLeft(GetByteValue())); } else { - if(CheckFlag(ProcFlags::MemoryMode8)) { - Write(_operand, RollLeft(GetByteValue())); - } else { - WriteWord(_operand, RollLeft(GetWordValue())); - } + Idle(); + WriteWord(_operand, RollLeft(GetWordValue())); + } +} + +void Cpu::ROR_Acc() +{ + if(CheckFlag(ProcFlags::MemoryMode8)) { + _state.A = (_state.A & 0xFF00) | RollRight((uint8_t)_state.A); + } else { + _state.A = RollRight(_state.A); } } void Cpu::ROR() { - if(_instAddrMode == AddrMode::Acc) { - if(CheckFlag(ProcFlags::MemoryMode8)) { - _state.A = (_state.A & 0xFF00) | RollRight((uint8_t)_state.A); - } else { - _state.A = RollRight(_state.A); - } + if(CheckFlag(ProcFlags::MemoryMode8)) { + Idle(); + Write(_operand, RollRight(GetByteValue())); } else { - if(CheckFlag(ProcFlags::MemoryMode8)) { - Write(_operand, RollRight(GetByteValue())); - } else { - WriteWord(_operand, RollRight(GetWordValue())); - } + Idle(); + WriteWord(_operand, RollRight(GetWordValue())); } } @@ -620,10 +661,20 @@ void Cpu::MVN() do { uint8_t value = ReadData(srcBank | _state.X); Write(destBank | _state.Y, value); - + + Idle(); + Idle(); + _state.X++; _state.Y++; _state.A--; + + if(_state.A != 0xFFFF) { + //"Idle" cycles, instruction re-reads OP code and operands before every new byte + _memoryManager->Read((_state.K << 16) | (_state.PC - 3), MemoryOperationType::Read); + _memoryManager->Read((_state.K << 16) | (_state.PC - 2), MemoryOperationType::Read); + _memoryManager->Read((_state.K << 16) | (_state.PC - 1), MemoryOperationType::Read); + } } while(_state.A != 0xFFFF); } @@ -636,9 +687,19 @@ void Cpu::MVP() uint8_t value = ReadData(srcBank | _state.X); Write(destBank | _state.Y, value); + Idle(); + Idle(); + _state.X--; _state.Y--; _state.A--; + + if(_state.A != 0xFFFF) { + //"Idle" cycles, instruction re-reads OP code and operands before every new byte + _memoryManager->Read((_state.K << 16) | (_state.PC - 3), MemoryOperationType::Read); + _memoryManager->Read((_state.K << 16) | (_state.PC - 2), MemoryOperationType::Read); + _memoryManager->Read((_state.K << 16) | (_state.PC - 1), MemoryOperationType::Read); + } } while(_state.A != 0xFFFF); } @@ -654,52 +715,64 @@ void Cpu::PEA() void Cpu::PEI() { //Push Effective Indirect address + Idle(); PushWord(ReadDataWord(_operand)); } void Cpu::PER() { //Push Effective Relative address + Idle(); PushWord((uint16_t)((int16_t)_operand + _state.PC)); } void Cpu::PHB() { + Idle(); PushByte(_state.DBR); } void Cpu::PHD() { + Idle(); PushWord(_state.D); } void Cpu::PHK() { //"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack" + Idle(); PushByte(_state.K); } void Cpu::PHP() { //"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack" + Idle(); PushByte(_state.PS); } void Cpu::PLB() { //"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack" + Idle(); + Idle(); SetRegister(_state.DBR, PopByte()); } void Cpu::PLD() { //"PHD and PLD push and pull two bytes from the stack." + Idle(); + Idle(); SetRegister(_state.D, PopWord(), false); } void Cpu::PLP() { //"For PLP, (all of) the flags are pulled from the stack. Note that when the e flag is 1, the m and x flag are forced to 1, so after the PLP, both flags will still be 1 no matter what value is pulled from the stack." + Idle(); + Idle(); if(_state.EmulationMode) { SetPS(PopByte() | ProcFlags::MemoryMode8 | ProcFlags::IndexMode8); } else { @@ -710,32 +783,41 @@ void Cpu::PLP() void Cpu::PHA() { //"When the m flag is 0, PHA and PLA push and pull a 16-bit value, and when the m flag is 1, PHA and PLA push and pull an 8-bit value. " + Idle(); PushRegister(_state.A, CheckFlag(ProcFlags::MemoryMode8)); } void Cpu::PHX() { + Idle(); PushRegister(_state.X, CheckFlag(ProcFlags::IndexMode8)); } void Cpu::PHY() { + Idle(); PushRegister(_state.Y, CheckFlag(ProcFlags::IndexMode8)); } void Cpu::PLA() { //"When the m flag is 0, PHA and PLA push and pull a 16-bit value, and when the m flag is 1, PHA and PLA push and pull an 8-bit value." + Idle(); + Idle(); PullRegister(_state.A, CheckFlag(ProcFlags::MemoryMode8)); } void Cpu::PLX() { + Idle(); + Idle(); PullRegister(_state.X, CheckFlag(ProcFlags::IndexMode8)); } void Cpu::PLY() { + Idle(); + Idle(); PullRegister(_state.Y, CheckFlag(ProcFlags::IndexMode8)); } @@ -853,9 +935,9 @@ template void Cpu::TestBits(T value, bool alterZeroFlagOnly) void Cpu::BIT() { if(CheckFlag(ProcFlags::MemoryMode8)) { - TestBits(GetByteValue(), _instAddrMode <= AddrMode::ImmM); + TestBits(GetByteValue(), _immediateMode); } else { - TestBits(GetWordValue(), _instAddrMode <= AddrMode::ImmM); + TestBits(GetWordValue(), _immediateMode); } } @@ -866,14 +948,16 @@ void Cpu::TRB() uint8_t value = ReadData(_operand); value &= ~_state.A; + Idle(); Write(_operand, value); } else { TestBits(GetWordValue(), true); - + uint16_t value = ReadDataWord(_operand); value &= ~_state.A; + Idle(); WriteWord(_operand, value); - } + } } void Cpu::TSB() @@ -958,6 +1042,7 @@ void Cpu::TYX() void Cpu::XBA() { + Idle(); _state.A = ((_state.A & 0xFF) << 8) | ((_state.A >> 8) & 0xFF); SetZeroNegativeFlags((uint8_t)_state.A); } @@ -1002,4 +1087,179 @@ void Cpu::STP() void Cpu::WAI() { //Wait for interrupt -} \ No newline at end of file +} + +/**************** +Addressing modes +*****************/ +void Cpu::AddrMode_Abs() +{ + _operand = GetDataAddress(ReadOperandWord()); +} + +void Cpu::AddrMode_AbsIdxX() +{ + _operand = (GetDataAddress(ReadOperandWord()) + _state.X) & 0xFFFFFF; + Idle(); +} + +void Cpu::AddrMode_AbsIdxY() +{ + _operand = (GetDataAddress(ReadOperandWord()) + _state.Y) & 0xFFFFFF; + Idle(); +} + +void Cpu::AddrMode_AbsLng() +{ + _operand = ReadOperandLong(); +} + +void Cpu::AddrMode_AbsLngIdxX() +{ + _operand = (ReadOperandLong() + _state.X) & 0xFFFFFF; +} + +void Cpu::AddrMode_AbsJmp() +{ + _operand = GetProgramAddress(ReadOperandWord()); +} + +void Cpu::AddrMode_AbsLngJmp() +{ + _operand = ReadOperandLong(); +} + +void Cpu::AddrMode_AbsIdxXInd() +{ + _operand = GetProgramAddress(ReadDataWord(GetProgramAddress(ReadOperandWord() + _state.X))); + Idle(); +} + +void Cpu::AddrMode_AbsInd() +{ + _operand = ReadDataWord(ReadOperandWord()); +} + +void Cpu::AddrMode_AbsIndLng() +{ + _operand = ReadDataLong(ReadOperandWord()); +} + +void Cpu::AddrMode_Acc() +{ + Idle(); +} + +void Cpu::AddrMode_BlkMov() +{ + _operand = ReadOperandWord(); +} + +uint8_t Cpu::ReadDirectOperandByte() +{ + uint8_t value = ReadOperandByte(); + if(_state.D & 0xFF) { + //Add 1 cycle for direct register low (DL) not equal 0 + Idle(); + } + return value; +} + +void Cpu::AddrMode_Dir() +{ + _operand = GetDirectAddress(ReadDirectOperandByte()); +} + +void Cpu::AddrMode_DirIdxX() +{ + _operand = GetDirectAddress(ReadDirectOperandByte() + _state.X); + Idle(); +} + +void Cpu::AddrMode_DirIdxY() +{ + _operand = GetDirectAddress(ReadDirectOperandByte() + _state.Y); + Idle(); +} + +void Cpu::AddrMode_DirInd() +{ + _operand = GetDataAddress(GetDirectAddressIndirectWord(ReadDirectOperandByte())); +} + +void Cpu::AddrMode_DirIdxIndX() +{ + uint8_t operandByte = ReadDirectOperandByte(); + Idle(); + _operand = GetDataAddress(GetDirectAddressIndirectWord(operandByte + _state.X)); +} + +void Cpu::AddrMode_DirIndIdxY() +{ + _operand = (GetDataAddress(GetDirectAddressIndirectWord(ReadDirectOperandByte())) + _state.Y) & 0xFFFFFF; + Idle(); +} + +void Cpu::AddrMode_DirIndLng() +{ + _operand = GetDirectAddressIndirectLong(ReadDirectOperandByte()); +} + +void Cpu::AddrMode_DirIndLngIdxY() +{ + _operand = (GetDirectAddressIndirectLong(ReadDirectOperandByte()) + _state.Y) & 0xFFFFFF; +} + +void Cpu::AddrMode_Imm8() +{ + _immediateMode = true; + _operand = ReadOperandByte(); +} + +void Cpu::AddrMode_Imm16() +{ + _immediateMode = true; + _operand = ReadOperandWord(); +} + +void Cpu::AddrMode_ImmX() +{ + _immediateMode = true; + _operand = CheckFlag(ProcFlags::IndexMode8) ? ReadOperandByte() : ReadOperandWord(); +} + +void Cpu::AddrMode_ImmM() +{ + _immediateMode = true; + _operand = CheckFlag(ProcFlags::MemoryMode8) ? ReadOperandByte() : ReadOperandWord(); +} + +void Cpu::AddrMode_Imp() +{ + Idle(); +} + +void Cpu::AddrMode_RelLng() +{ + _operand = ReadOperandWord(); + Idle(); +} + +void Cpu::AddrMode_Rel() +{ + _operand = ReadOperandByte(); +} + +void Cpu::AddrMode_StkRel() +{ + _operand = (uint16_t)(ReadOperandByte() + _state.SP); + Idle(); +} + +void Cpu::AddrMode_StkRelIndIdxY() +{ + uint16_t addr = (uint16_t)(ReadOperandByte() + _state.SP); + Idle(); + _operand = (GetDataAddress(ReadDataWord(addr)) + _state.Y) & 0xFFFFFF; + Idle(); +} diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index 8954e4d..8b43f5d 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -5,51 +5,6 @@ Cpu::Cpu(shared_ptr memoryManager) { - typedef Cpu C; - Func opTable[256] = { - //0 1 2 3 4 5 6 7 8 9 A B C D E F - &C::BRK, &C::ORA, &C::COP, &C::ORA, &C::TSB, &C::ORA, &C::ASL, &C::ORA, &C::PHP, &C::ORA, &C::ASL, &C::PHD, &C::TSB, &C::ORA, &C::ASL, &C::ORA, // 0 - &C::BPL, &C::ORA, &C::ORA, &C::ORA, &C::TRB, &C::ORA, &C::ASL, &C::ORA, &C::CLC, &C::ORA, &C::INC, &C::TCS, &C::TRB, &C::ORA, &C::ASL, &C::ORA, // 1 - &C::JSR, &C::AND, &C::JSL, &C::AND, &C::BIT, &C::AND, &C::ROL, &C::AND, &C::PLP, &C::AND, &C::ROL, &C::PLD, &C::BIT, &C::AND, &C::ROL, &C::AND, // 2 - &C::BMI, &C::AND, &C::AND, &C::AND, &C::BIT, &C::AND, &C::ROL, &C::AND, &C::SEC, &C::AND, &C::DEC, &C::TSC, &C::BIT, &C::AND, &C::ROL, &C::AND, // 3 - &C::RTI, &C::EOR, &C::WDM, &C::EOR, &C::MVP, &C::EOR, &C::LSR, &C::EOR, &C::PHA, &C::EOR, &C::LSR, &C::PHK, &C::JMP, &C::EOR, &C::LSR, &C::EOR, // 4 - &C::BVC, &C::EOR, &C::EOR, &C::EOR, &C::MVN, &C::EOR, &C::LSR, &C::EOR, &C::CLI, &C::EOR, &C::PHY, &C::TCD, &C::JML, &C::EOR, &C::LSR, &C::EOR, // 5 - &C::RTS, &C::ADC, &C::PER, &C::ADC, &C::STZ, &C::ADC, &C::ROR, &C::ADC, &C::PLA, &C::ADC, &C::ROR, &C::RTL, &C::JMP, &C::ADC, &C::ROR, &C::ADC, // 6 - &C::BVS, &C::ADC, &C::ADC, &C::ADC, &C::STZ, &C::ADC, &C::ROR, &C::ADC, &C::SEI, &C::ADC, &C::PLY, &C::TDC, &C::JMP, &C::ADC, &C::ROR, &C::ADC, // 7 - &C::BRA, &C::STA, &C::BRL, &C::STA, &C::STY, &C::STA, &C::STX, &C::STA, &C::DEY, &C::BIT, &C::TXA, &C::PHB, &C::STY, &C::STA, &C::STX, &C::STA, // 8 - &C::BCC, &C::STA, &C::STA, &C::STA, &C::STY, &C::STA, &C::STX, &C::STA, &C::TYA, &C::STA, &C::TXS, &C::TXY, &C::STZ, &C::STA, &C::STZ, &C::STA, // 9 - &C::LDY, &C::LDA, &C::LDX, &C::LDA, &C::LDY, &C::LDA, &C::LDX, &C::LDA, &C::TAY, &C::LDA, &C::TAX, &C::PLB, &C::LDY, &C::LDA, &C::LDX, &C::LDA, // A - &C::BCS, &C::LDA, &C::LDA, &C::LDA, &C::LDY, &C::LDA, &C::LDX, &C::LDA, &C::CLV, &C::LDA, &C::TSX, &C::TYX, &C::LDY, &C::LDA, &C::LDX, &C::LDA, // B - &C::CPY, &C::CMP, &C::REP, &C::CMP, &C::CPY, &C::CMP, &C::DEC, &C::CMP, &C::INY, &C::CMP, &C::DEX, &C::WAI, &C::CPY, &C::CMP, &C::DEC, &C::CMP, // C - &C::BNE, &C::CMP, &C::CMP, &C::CMP, &C::PEI, &C::CMP, &C::DEC, &C::CMP, &C::CLD, &C::CMP, &C::PHX, &C::STP, &C::JML, &C::CMP, &C::DEC, &C::CMP, // D - &C::CPX, &C::SBC, &C::SEP, &C::SBC, &C::CPX, &C::SBC, &C::INC, &C::SBC, &C::INX, &C::SBC, &C::NOP, &C::XBA, &C::CPX, &C::SBC, &C::INC, &C::SBC, // E - &C::BEQ, &C::SBC, &C::SBC, &C::SBC, &C::PEA, &C::SBC, &C::INC, &C::SBC, &C::SED, &C::SBC, &C::PLX, &C::XCE, &C::JSR, &C::SBC, &C::INC, &C::SBC // F - }; - - typedef AddrMode M; - AddrMode addrMode[256] = { - //0 1 2 3 4 5 6 7 8 9 A B C D E F - M::Stk, M::DirIdxIndX, M::Stk, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 0 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 1 - M::AbsJmp,M::DirIdxIndX, M::AbsLngJmp,M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 2 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Acc, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 3 - M::Stk, M::DirIdxIndX, M::Imm8, M::StkRel, M::BlkMov, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::AbsJmp, M::Abs, M::Abs, M::AbsLng, // 4 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::BlkMov, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsLngJmp, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 5 - M::Stk, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Stk, M::ImmM, M::Acc, M::Stk, M::AbsInd, M::Abs, M::Abs, M::AbsLng, // 6 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 7 - M::Rel, M::DirIdxIndX, M::RelLng, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // 8 - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::Abs, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // 9 - M::ImmX, M::DirIdxIndX, M::ImmX, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Stk, M::Abs, M::Abs, M::Abs, M::AbsLng, // A - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::DirIdxX, M::DirIdxX, M::DirIdxY, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Imp, M::Imp, M::AbsIdxX, M::AbsIdxX, M::AbsIdxY, M::AbsLngIdxX, // B - M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // C - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Dir, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIndLng, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX, // D - M::ImmX, M::DirIdxIndX, M::Imm8, M::StkRel, M::Dir, M::Dir, M::Dir, M::DirIndLng, M::Imp, M::ImmM, M::Imp, M::Imp, M::Abs, M::Abs, M::Abs, M::AbsLng, // E - M::Rel, M::DirIndIdxY, M::DirInd, M::StkRelIndIdxY, M::Imm16, M::DirIdxX, M::DirIdxX, M::DirIndLngIdxY, M::Imp, M::AbsIdxY, M::Stk, M::Imp, M::AbsIdxXInd, M::AbsIdxX, M::AbsIdxX, M::AbsLngIdxX // F - }; - - memcpy(_opTable, opTable, sizeof(opTable)); - memcpy(_addrMode, addrMode, sizeof(addrMode)); - _memoryManager = memoryManager; _state = {}; _state.PC = ReadDataWord(Cpu::ResetVector); @@ -71,13 +26,267 @@ void Cpu::Reset() void Cpu::Exec() { - uint8_t opCode = GetOpCode(); - _instAddrMode = _addrMode[opCode]; - _operand = FetchEffectiveAddress(); - (this->*_opTable[opCode])(); - - opCount++; + _immediateMode = false; + switch(GetOpCode()) { + case 0x00: BRK(); break; + case 0x01: AddrMode_DirIdxIndX(); ORA(); break; + case 0x02: COP(); break; + case 0x03: AddrMode_StkRel(); ORA(); break; + case 0x04: AddrMode_Dir(); TSB(); break; + case 0x05: AddrMode_Dir(); ORA(); break; + case 0x06: AddrMode_Dir(); ASL(); break; + case 0x07: AddrMode_DirIndLng(); ORA(); break; + case 0x08: PHP(); break; + case 0x09: AddrMode_ImmM(); ORA(); break; + case 0x0A: AddrMode_Acc(); ASL_Acc(); break; + case 0x0B: PHD(); break; + case 0x0C: AddrMode_Abs(); TSB(); break; + case 0x0D: AddrMode_Abs(); ORA(); break; + case 0x0E: AddrMode_Abs(); ASL(); break; + case 0x0F: AddrMode_AbsLng(); ORA(); break; + case 0x10: AddrMode_Rel(); BPL(); break; + case 0x11: AddrMode_DirIndIdxY(); ORA(); break; + case 0x12: AddrMode_DirInd(); ORA(); break; + case 0x13: AddrMode_StkRelIndIdxY(); ORA(); break; + case 0x14: AddrMode_Dir(); TRB(); break; + case 0x15: AddrMode_DirIdxX(); ORA(); break; + case 0x16: AddrMode_DirIdxX(); ASL(); break; + case 0x17: AddrMode_DirIndLngIdxY(); ORA(); break; + case 0x18: AddrMode_Imp(); CLC(); break; + case 0x19: AddrMode_AbsIdxY(); ORA(); break; + case 0x1A: AddrMode_Acc(); INC_Acc(); break; + case 0x1B: AddrMode_Imp(); TCS(); break; + case 0x1C: AddrMode_Abs(); TRB(); break; + case 0x1D: AddrMode_AbsIdxX(); ORA(); break; + case 0x1E: AddrMode_AbsIdxX(); ASL(); break; + case 0x1F: AddrMode_AbsLngIdxX(); ORA(); break; + case 0x20: AddrMode_AbsJmp(); Idle(); JSR(); break; + case 0x21: AddrMode_DirIdxIndX(); AND(); break; + case 0x22: AddrMode_AbsLngJmp(); JSL(); break; + case 0x23: AddrMode_StkRel(); AND(); break; + case 0x24: AddrMode_Dir(); BIT(); break; + case 0x25: AddrMode_Dir(); AND(); break; + case 0x26: AddrMode_Dir(); ROL(); break; + case 0x27: AddrMode_DirIndLng(); AND(); break; + case 0x28: PLP(); break; + case 0x29: AddrMode_ImmM(); AND(); break; + case 0x2A: AddrMode_Acc(); ROL_Acc(); break; + case 0x2B: PLD(); break; + case 0x2C: AddrMode_Abs(); BIT(); break; + case 0x2D: AddrMode_Abs(); AND(); break; + case 0x2E: AddrMode_Abs(); ROL(); break; + case 0x2F: AddrMode_AbsLng(); AND(); break; + case 0x30: AddrMode_Rel(); BMI(); break; + case 0x31: AddrMode_DirIndIdxY(); AND(); break; + case 0x32: AddrMode_DirInd(); AND(); break; + case 0x33: AddrMode_StkRelIndIdxY(); AND(); break; + case 0x34: AddrMode_DirIdxX(); BIT(); break; + case 0x35: AddrMode_DirIdxX(); AND(); break; + case 0x36: AddrMode_DirIdxX(); ROL(); break; + case 0x37: AddrMode_DirIndLngIdxY(); AND(); break; + case 0x38: AddrMode_Imp(); SEC(); break; + case 0x39: AddrMode_AbsIdxY(); AND(); break; + case 0x3A: AddrMode_Acc(); DEC_Acc(); break; + case 0x3B: AddrMode_Imp(); TSC(); break; + case 0x3C: AddrMode_AbsIdxX(); BIT(); break; + case 0x3D: AddrMode_AbsIdxX(); AND(); break; + case 0x3E: AddrMode_AbsIdxX(); ROL(); break; + case 0x3F: AddrMode_AbsLngIdxX(); AND(); break; + case 0x40: RTI(); break; + case 0x41: AddrMode_DirIdxIndX(); EOR(); break; + case 0x42: AddrMode_Imm8(); WDM(); break; + case 0x43: AddrMode_StkRel(); EOR(); break; + case 0x44: AddrMode_BlkMov(); MVP(); break; + case 0x45: AddrMode_Dir(); EOR(); break; + case 0x46: AddrMode_Dir(); LSR(); break; + case 0x47: AddrMode_DirIndLng(); EOR(); break; + case 0x48: PHA(); break; + case 0x49: AddrMode_ImmM(); EOR(); break; + case 0x4A: AddrMode_Acc(); LSR_Acc(); break; + case 0x4B: PHK(); break; + case 0x4C: AddrMode_AbsJmp(); JMP(); break; + case 0x4D: AddrMode_Abs(); EOR(); break; + case 0x4E: AddrMode_Abs(); LSR(); break; + case 0x4F: AddrMode_AbsLng(); EOR(); break; + case 0x50: AddrMode_Rel(); BVC(); break; + case 0x51: AddrMode_DirIndIdxY(); EOR(); break; + case 0x52: AddrMode_DirInd(); EOR(); break; + case 0x53: AddrMode_StkRelIndIdxY(); EOR(); break; + case 0x54: AddrMode_BlkMov(); MVN(); break; + case 0x55: AddrMode_DirIdxX(); EOR(); break; + case 0x56: AddrMode_DirIdxX(); LSR(); break; + case 0x57: AddrMode_DirIndLngIdxY(); EOR(); break; + case 0x58: AddrMode_Imp(); CLI(); break; + case 0x59: AddrMode_AbsIdxY(); EOR(); break; + case 0x5A: PHY(); break; + case 0x5B: AddrMode_Imp(); TCD(); break; + case 0x5C: AddrMode_AbsLngJmp(); JML(); break; + case 0x5D: AddrMode_AbsIdxX(); EOR(); break; + case 0x5E: AddrMode_AbsIdxX(); LSR(); break; + case 0x5F: AddrMode_AbsLngIdxX(); EOR(); break; + case 0x60: RTS(); break; + case 0x61: AddrMode_DirIdxIndX(); ADC(); break; + case 0x62: AddrMode_RelLng(); PER(); break; + case 0x63: AddrMode_StkRel(); ADC(); break; + case 0x64: AddrMode_Dir(); STZ(); break; + case 0x65: AddrMode_Dir(); ADC(); break; + case 0x66: AddrMode_Dir(); ROR(); break; + case 0x67: AddrMode_DirIndLng(); ADC(); break; + case 0x68: PLA(); break; + case 0x69: AddrMode_ImmM(); ADC(); break; + case 0x6A: AddrMode_Acc(); ROR_Acc(); break; + case 0x6B: RTL(); break; + case 0x6C: AddrMode_AbsInd(); JMP(); break; + case 0x6D: AddrMode_Abs(); ADC(); break; + case 0x6E: AddrMode_Abs(); ROR(); break; + case 0x6F: AddrMode_AbsLng(); ADC(); break; + case 0x70: AddrMode_Rel(); BVS(); break; + case 0x71: AddrMode_DirIndIdxY(); ADC(); break; + case 0x72: AddrMode_DirInd(); ADC(); break; + case 0x73: AddrMode_StkRelIndIdxY(); ADC(); break; + case 0x74: AddrMode_DirIdxX(); STZ(); break; + case 0x75: AddrMode_DirIdxX(); ADC(); break; + case 0x76: AddrMode_DirIdxX(); ROR(); break; + case 0x77: AddrMode_DirIndLngIdxY(); ADC(); break; + case 0x78: AddrMode_Imp(); SEI(); break; + case 0x79: AddrMode_AbsIdxY(); ADC(); break; + case 0x7A: PLY(); break; + case 0x7B: AddrMode_Imp(); TDC(); break; + case 0x7C: AddrMode_AbsIdxXInd(); JMP(); break; + case 0x7D: AddrMode_AbsIdxX(); ADC(); break; + case 0x7E: AddrMode_AbsIdxX(); ROR(); break; + case 0x7F: AddrMode_AbsLngIdxX(); ADC(); break; + case 0x80: AddrMode_Rel(); BRA(); break; + case 0x81: AddrMode_DirIdxIndX(); STA(); break; + case 0x82: AddrMode_RelLng(); BRL(); break; + case 0x83: AddrMode_StkRel(); STA(); break; + case 0x84: AddrMode_Dir(); STY(); break; + case 0x85: AddrMode_Dir(); STA(); break; + case 0x86: AddrMode_Dir(); STX(); break; + case 0x87: AddrMode_DirIndLng(); STA(); break; + case 0x88: AddrMode_Imp(); DEY(); break; + case 0x89: AddrMode_ImmM(); BIT(); break; + case 0x8A: AddrMode_Imp(); TXA(); break; + case 0x8B: PHB(); break; + case 0x8C: AddrMode_Abs(); STY(); break; + case 0x8D: AddrMode_Abs(); STA(); break; + case 0x8E: AddrMode_Abs(); STX(); break; + case 0x8F: AddrMode_AbsLng(); STA(); break; + case 0x90: AddrMode_Rel(); BCC(); break; + case 0x91: AddrMode_DirIndIdxY(); STA(); break; + case 0x92: AddrMode_DirInd(); STA(); break; + case 0x93: AddrMode_StkRelIndIdxY(); STA(); break; + case 0x94: AddrMode_DirIdxX(); STY(); break; + case 0x95: AddrMode_DirIdxX(); STA(); break; + case 0x96: AddrMode_DirIdxY(); STX(); break; + case 0x97: AddrMode_DirIndLngIdxY(); STA(); break; + case 0x98: AddrMode_Imp(); TYA(); break; + case 0x99: AddrMode_AbsIdxY(); STA(); break; + case 0x9A: AddrMode_Imp(); TXS(); break; + case 0x9B: AddrMode_Imp(); TXY(); break; + case 0x9C: AddrMode_Abs(); STZ(); break; + case 0x9D: AddrMode_AbsIdxX(); STA(); break; + case 0x9E: AddrMode_AbsIdxX(); STZ(); break; + case 0x9F: AddrMode_AbsLngIdxX(); STA(); break; + case 0xA0: AddrMode_ImmX(); LDY(); break; + case 0xA1: AddrMode_DirIdxIndX(); LDA(); break; + case 0xA2: AddrMode_ImmX(); LDX(); break; + case 0xA3: AddrMode_StkRel(); LDA(); break; + case 0xA4: AddrMode_Dir(); LDY(); break; + case 0xA5: AddrMode_Dir(); LDA(); break; + case 0xA6: AddrMode_Dir(); LDX(); break; + case 0xA7: AddrMode_DirIndLng(); LDA(); break; + case 0xA8: AddrMode_Imp(); TAY(); break; + case 0xA9: AddrMode_ImmM(); LDA(); break; + case 0xAA: AddrMode_Imp(); TAX(); break; + case 0xAB: PLB(); break; + case 0xAC: AddrMode_Abs(); LDY(); break; + case 0xAD: AddrMode_Abs(); LDA(); break; + case 0xAE: AddrMode_Abs(); LDX(); break; + case 0xAF: AddrMode_AbsLng(); LDA(); break; + case 0xB0: AddrMode_Rel(); BCS(); break; + case 0xB1: AddrMode_DirIndIdxY(); LDA(); break; + case 0xB2: AddrMode_DirInd(); LDA(); break; + case 0xB3: AddrMode_StkRelIndIdxY(); LDA(); break; + case 0xB4: AddrMode_DirIdxX(); LDY(); break; + case 0xB5: AddrMode_DirIdxX(); LDA(); break; + case 0xB6: AddrMode_DirIdxY(); LDX(); break; + case 0xB7: AddrMode_DirIndLngIdxY(); LDA(); break; + case 0xB8: AddrMode_Imp(); CLV(); break; + case 0xB9: AddrMode_AbsIdxY(); LDA(); break; + case 0xBA: AddrMode_Imp(); TSX(); break; + case 0xBB: AddrMode_Imp(); TYX(); break; + case 0xBC: AddrMode_AbsIdxX(); LDY(); break; + case 0xBD: AddrMode_AbsIdxX(); LDA(); break; + case 0xBE: AddrMode_AbsIdxY(); LDX(); break; + case 0xBF: AddrMode_AbsLngIdxX(); LDA(); break; + case 0xC0: AddrMode_ImmX(); CPY(); break; + case 0xC1: AddrMode_DirIdxIndX(); CMP(); break; + case 0xC2: AddrMode_Imm8(); REP(); break; + case 0xC3: AddrMode_StkRel(); CMP(); break; + case 0xC4: AddrMode_Dir(); CPY(); break; + case 0xC5: AddrMode_Dir(); CMP(); break; + case 0xC6: AddrMode_Dir(); DEC(); break; + case 0xC7: AddrMode_DirIndLng(); CMP(); break; + case 0xC8: AddrMode_Imp(); INY(); break; + case 0xC9: AddrMode_ImmM(); CMP(); break; + case 0xCA: AddrMode_Imp(); DEX(); break; + case 0xCB: AddrMode_Imp(); WAI(); break; + case 0xCC: AddrMode_Abs(); CPY(); break; + case 0xCD: AddrMode_Abs(); CMP(); break; + case 0xCE: AddrMode_Abs(); DEC(); break; + case 0xCF: AddrMode_AbsLng(); CMP(); break; + case 0xD0: AddrMode_Rel(); BNE(); break; + case 0xD1: AddrMode_DirIndIdxY(); CMP(); break; + case 0xD2: AddrMode_DirInd(); CMP(); break; + case 0xD3: AddrMode_StkRelIndIdxY(); CMP(); break; + case 0xD4: AddrMode_Dir(); PEI(); break; + case 0xD5: AddrMode_DirIdxX(); CMP(); break; + case 0xD6: AddrMode_DirIdxX(); DEC(); break; + case 0xD7: AddrMode_DirIndLngIdxY(); CMP(); break; + case 0xD8: AddrMode_Imp(); CLD(); break; + case 0xD9: AddrMode_AbsIdxY(); CMP(); break; + case 0xDA: PHX(); break; + case 0xDB: AddrMode_Imp(); STP(); break; + case 0xDC: AddrMode_AbsIndLng(); JML(); break; + case 0xDD: AddrMode_AbsIdxX(); CMP(); break; + case 0xDE: AddrMode_AbsIdxX(); DEC(); break; + case 0xDF: AddrMode_AbsLngIdxX(); CMP(); break; + case 0xE0: AddrMode_ImmX(); CPX(); break; + case 0xE1: AddrMode_DirIdxIndX(); SBC(); break; + case 0xE2: AddrMode_Imm8(); SEP(); break; + case 0xE3: AddrMode_StkRel(); SBC(); break; + case 0xE4: AddrMode_Dir(); CPX(); break; + case 0xE5: AddrMode_Dir(); SBC(); break; + case 0xE6: AddrMode_Dir(); INC(); break; + case 0xE7: AddrMode_DirIndLng(); SBC(); break; + case 0xE8: AddrMode_Imp(); INX(); break; + case 0xE9: AddrMode_ImmM(); SBC(); break; + case 0xEA: AddrMode_Imp(); NOP(); break; + case 0xEB: AddrMode_Imp(); XBA(); break; + case 0xEC: AddrMode_Abs(); CPX(); break; + case 0xED: AddrMode_Abs(); SBC(); break; + case 0xEE: AddrMode_Abs(); INC(); break; + case 0xEF: AddrMode_AbsLng(); SBC(); break; + case 0xF0: AddrMode_Rel(); BEQ(); break; + case 0xF1: AddrMode_DirIndIdxY(); SBC(); break; + case 0xF2: AddrMode_DirInd(); SBC(); break; + case 0xF3: AddrMode_StkRelIndIdxY(); SBC(); break; + case 0xF4: AddrMode_Imm16(); PEA(); break; + case 0xF5: AddrMode_DirIdxX(); SBC(); break; + case 0xF6: AddrMode_DirIdxX(); INC(); break; + case 0xF7: AddrMode_DirIndLngIdxY(); SBC(); break; + case 0xF8: AddrMode_Imp(); SED(); break; + case 0xF9: AddrMode_AbsIdxY(); SBC(); break; + case 0xFA: PLX(); break; + case 0xFB: AddrMode_Imp(); XCE(); break; + case 0xFC: AddrMode_AbsIdxXInd(); JSR(); break; + case 0xFD: AddrMode_AbsIdxX(); SBC(); break; + case 0xFE: AddrMode_AbsIdxX(); INC(); break; + case 0xFF: AddrMode_AbsLngIdxX(); SBC(); break; + } + if(_nmiFlag) { ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector); _nmiFlag = false; @@ -127,9 +336,9 @@ uint8_t Cpu::GetOpCode() return opCode; } -void Cpu::DummyRead() +void Cpu::Idle() { - ReadCode(_state.PC, MemoryOperationType::DummyRead); + _memoryManager->ProcessCpuInternalOperation(); } uint8_t Cpu::ReadOperandByte() @@ -168,7 +377,7 @@ uint16_t Cpu::ReadCodeWord(uint16_t addr, MemoryOperationType type) uint8_t Cpu::ReadData(uint32_t addr, MemoryOperationType type) { _state.CycleCount++; - return _memoryManager->Read(addr, type); + return _memoryManager->Read(addr & 0xFFFFFF, type); } uint16_t Cpu::ReadDataWord(uint32_t addr, MemoryOperationType type) @@ -200,7 +409,7 @@ void Cpu::WriteWord(uint32_t addr, uint16_t value, MemoryOperationType type) uint8_t Cpu::GetByteValue() { - if(_instAddrMode <= AddrMode::ImmM) { + if(_immediateMode) { return (uint8_t)_operand; } else { return ReadData(_operand); @@ -209,7 +418,7 @@ uint8_t Cpu::GetByteValue() uint16_t Cpu::GetWordValue() { - if(_instAddrMode <= AddrMode::ImmM) { + if(_immediateMode) { return (uint16_t)_operand; } else { return ReadDataWord(_operand); @@ -266,57 +475,6 @@ uint32_t Cpu::GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationM return (b3 << 16) | (b2 << 8) | b1; } -uint32_t Cpu::FetchEffectiveAddress() -{ - switch(_instAddrMode) { - case AddrMode::Abs: return GetDataAddress(ReadOperandWord()); - case AddrMode::AbsIdxX: return (GetDataAddress(ReadOperandWord()) + _state.X) & 0xFFFFFF; - case AddrMode::AbsIdxY: return (GetDataAddress(ReadOperandWord()) + _state.Y) & 0xFFFFFF; - case AddrMode::AbsLng: return ReadOperandLong(); - case AddrMode::AbsLngIdxX: return (ReadOperandLong() + _state.X) & 0xFFFFFF; - - case AddrMode::AbsJmp: return GetProgramAddress(ReadOperandWord()); - case AddrMode::AbsLngJmp: return ReadOperandLong(); - case AddrMode::AbsIdxXInd: return GetProgramAddress(ReadDataWord(GetProgramAddress(ReadOperandWord() + _state.X))); //JMP/JSR - case AddrMode::AbsInd: return ReadDataWord(ReadOperandWord()); //JMP only - case AddrMode::AbsIndLng: return ReadDataLong(ReadOperandWord()); //JML only - - case AddrMode::Acc: DummyRead(); return 0; - - case AddrMode::BlkMov: return ReadOperandWord(); - - case AddrMode::Dir: return GetDirectAddress(ReadOperandByte()); - case AddrMode::DirIdxX: return GetDirectAddress(ReadOperandByte() + _state.X); - case AddrMode::DirIdxY: return GetDirectAddress(ReadOperandByte() + _state.Y); - - case AddrMode::DirInd: return GetDataAddress(GetDirectAddressIndirectWord(ReadOperandByte())); - case AddrMode::DirIdxIndX: return GetDataAddress(GetDirectAddressIndirectWord(ReadOperandByte() + _state.X)); - case AddrMode::DirIndIdxY: return (GetDataAddress(GetDirectAddressIndirectWord(ReadOperandByte())) + _state.Y) & 0xFFFFFF; - case AddrMode::DirIndLng: return GetDirectAddressIndirectLong(ReadOperandByte()); - case AddrMode::DirIndLngIdxY: return (GetDirectAddressIndirectLong(ReadOperandByte()) + _state.Y) & 0xFFFFFF; - - case AddrMode::Imm8: return ReadOperandByte(); - case AddrMode::Imm16: return ReadOperandWord(); - case AddrMode::ImmX: return CheckFlag(ProcFlags::IndexMode8) ? ReadOperandByte() : ReadOperandWord(); - case AddrMode::ImmM: return CheckFlag(ProcFlags::MemoryMode8) ? ReadOperandByte() : ReadOperandWord(); - - case AddrMode::Imp: DummyRead(); return 0; - - case AddrMode::RelLng: return ReadOperandWord(); - case AddrMode::Rel: return ReadOperandByte(); - - case AddrMode::Stk: return 0; - case AddrMode::StkRel: return (uint16_t)(ReadOperandByte() + _state.SP); - - case AddrMode::StkRelIndIdxY: { - uint16_t addr = (uint16_t)(ReadOperandByte() + _state.SP); - return (GetDataAddress(ReadDataWord(addr)) + _state.Y) & 0xFFFFFF; - } - } - - throw std::runtime_error("Unreacheable code"); -} - void Cpu::SetSP(uint16_t sp) { if(_state.EmulationMode) { diff --git a/Core/Cpu.h b/Core/Cpu.h index 7173b7c..bbf7d38 100644 --- a/Core/Cpu.h +++ b/Core/Cpu.h @@ -7,7 +7,6 @@ class MemoryManager; class Cpu { public: - uint64_t opCount = 0; uint16_t GetPc() { return _state.PC; } CpuState GetState() { return _state; } int32_t GetLastOperand() { return (int32_t)_operand; } @@ -27,8 +26,10 @@ private: typedef void(Cpu::*Func)(); shared_ptr _memoryManager; + + bool _immediateMode = false; + CpuState _state; - AddrMode _instAddrMode; uint32_t _operand; bool _nmiFlag; uint8_t _irqSource; @@ -46,12 +47,11 @@ private: uint8_t GetOpCode(); - void DummyRead(); + void Idle(); uint8_t ReadOperandByte(); uint16_t ReadOperandWord(); uint32_t ReadOperandLong(); - uint32_t FetchEffectiveAddress(); void SetSP(uint16_t sp); void SetPS(uint8_t ps); @@ -128,6 +128,9 @@ private: void DEC(); void INC(); + void DEC_Acc(); + void INC_Acc(); + void IncDecReg(uint16_t & reg, int8_t offset); void IncDec(int8_t offset); @@ -162,9 +165,13 @@ private: template T RollRight(T value); //Shift operations + void ASL_Acc(); void ASL(); + void LSR_Acc(); void LSR(); + void ROL_Acc(); void ROL(); + void ROR_Acc(); void ROR(); //Move operations @@ -237,6 +244,46 @@ private: void STP(); void WAI(); + //Addressing modes + void AddrMode_Abs(); + void AddrMode_AbsIdxX(); + void AddrMode_AbsIdxY(); + void AddrMode_AbsLng(); + void AddrMode_AbsLngIdxX(); + + void AddrMode_AbsJmp(); + void AddrMode_AbsLngJmp(); + void AddrMode_AbsIdxXInd(); //JMP/JSR + void AddrMode_AbsInd(); //JMP only + void AddrMode_AbsIndLng(); //JML only + + void AddrMode_Acc(); + + void AddrMode_BlkMov(); + + uint8_t ReadDirectOperandByte(); + void AddrMode_Dir(); + void AddrMode_DirIdxX(); + void AddrMode_DirIdxY(); + void AddrMode_DirInd(); + void AddrMode_DirIdxIndX(); + void AddrMode_DirIndIdxY(); + void AddrMode_DirIndLng(); + void AddrMode_DirIndLngIdxY(); + + void AddrMode_Imm8(); + void AddrMode_Imm16(); + void AddrMode_ImmX(); + void AddrMode_ImmM(); + + void AddrMode_Imp(); + + void AddrMode_RelLng(); + void AddrMode_Rel(); + + void AddrMode_StkRel(); + void AddrMode_StkRelIndIdxY(); + public: Cpu(shared_ptr memoryManager); ~Cpu(); @@ -248,4 +295,4 @@ public: void SetIrqSource(IrqSource source); bool CheckIrqSource(IrqSource source); void ClearIrqSource(IrqSource source); -}; \ No newline at end of file +}; diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index e137294..2af0ba6 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -101,6 +101,7 @@ private: uint8_t * _workRam; uint64_t _masterClock; + uint8_t _previousSpeed; uint64_t _lastMasterClock; uint8_t _masterClockTable[2][0x10000]; @@ -217,7 +218,26 @@ public: void IncrementMasterClock(uint32_t addr) { - _masterClock += _masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8]; + _previousSpeed = _masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8]; + _masterClock += _previousSpeed; + while(_lastMasterClock < _masterClock - 3) { + _ppu->Exec(); + _lastMasterClock += 4; + } + } + + void ProcessCpuInternalOperation() + { + _masterClock += 6; + while(_lastMasterClock < _masterClock - 3) { + _ppu->Exec(); + _lastMasterClock += 4; + } + } + + void ProcessDramRefresh() + { + _masterClock += 40; while(_lastMasterClock < _masterClock - 3) { _ppu->Exec(); _lastMasterClock += 4; diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index e29a4ec..ada6c12 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -90,9 +90,13 @@ void Ppu::Exec() if(_regs->IsNmiEnabled()) { _console->GetCpu()->SetNmiFlag(); } + } else if(_scanline == 240 && _cycle == 0 && _frameCount & 0x01) { + //Skip 1 tick every other frame + _cycle++; } else if(_scanline == 261) { _regs->SetNmiFlag(false); _scanline = 0; + if(_mosaicEnabled) { _mosaicStartScanline = 0; } @@ -115,6 +119,9 @@ void Ppu::Exec() if(_cycle == 278 && _scanline < 225) { _console->GetDmaController()->ProcessHdmaChannels(); + } else if(_cycle == 134) { + //TODO Approximation + _console->GetMemoryManager()->ProcessDramRefresh(); } }