diff --git a/Core/APU.cpp b/Core/APU.cpp index 743252b3..9799a482 100644 --- a/Core/APU.cpp +++ b/Core/APU.cpp @@ -21,8 +21,8 @@ APU::APU(MemoryManager* memoryManager) _mixer.reset(new SoundMixer()); - _squareChannel.push_back(unique_ptr(new SquareChannel(AudioChannel::Square1, _mixer.get(), true))); - _squareChannel.push_back(unique_ptr(new SquareChannel(AudioChannel::Square2, _mixer.get(), false))); + _squareChannel[0].reset(new SquareChannel(AudioChannel::Square1, _mixer.get(), true)); + _squareChannel[1].reset(new SquareChannel(AudioChannel::Square2, _mixer.get(), false)); _triangleChannel.reset(new TriangleChannel(AudioChannel::Triangle, _mixer.get())); _noiseChannel.reset(new NoiseChannel(AudioChannel::Noise, _mixer.get())); _deltaModulationChannel.reset(new DeltaModulationChannel(AudioChannel::DMC, _mixer.get(), _memoryManager)); diff --git a/Core/APU.h b/Core/APU.h index c3ac0905..6275d28e 100644 --- a/Core/APU.h +++ b/Core/APU.h @@ -24,7 +24,7 @@ class APU : public Snapshotable, public IMemoryHandler uint32_t _previousCycle; uint32_t _currentCycle; - vector> _squareChannel; + unique_ptr _squareChannel[2]; unique_ptr _triangleChannel; unique_ptr _noiseChannel; unique_ptr _deltaModulationChannel; diff --git a/Core/ApuFrameCounter.h b/Core/ApuFrameCounter.h index d7547dfc..12f27a93 100644 --- a/Core/ApuFrameCounter.h +++ b/Core/ApuFrameCounter.h @@ -14,14 +14,14 @@ enum class FrameType class ApuFrameCounter : public IMemoryHandler, public Snapshotable { private: - const vector> _stepCyclesNtsc = { { { 7457, 14913, 22371, 29828, 29829, 29830}, - { 7457, 14913, 22371, 29829, 37281, 37282} } }; - const vector> _stepCyclesPal = { { { 8313, 16627, 24939, 33252, 33253, 33254}, - { 8313, 16627, 24939, 33253, 41565, 41566} } }; - const vector> _frameType = { { { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None }, - { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None } } }; + const int32_t _stepCyclesNtsc[2][6] = { { 7457, 14913, 22371, 29828, 29829, 29830}, + { 7457, 14913, 22371, 29829, 37281, 37282} }; + const int32_t _stepCyclesPal[2][6] = { { 8313, 16627, 24939, 33252, 33253, 33254}, + { 8313, 16627, 24939, 33253, 41565, 41566} }; + const FrameType _frameType[2][6] = { { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None }, + { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None } }; - vector> _stepCycles; + int32_t _stepCycles[2][6]; NesModel _nesModel; int32_t _nextIrqCycle; int32_t _previousCycle; @@ -76,19 +76,16 @@ public: void SetNesModel(NesModel model) { - if(_nesModel != model || _stepCycles.size() == 0) { + if(_nesModel != model) { _nesModel = model; - _stepCycles.clear(); switch(model) { case NesModel::NTSC: case NesModel::Dendy: - _stepCycles.push_back(_stepCyclesNtsc[0]); - _stepCycles.push_back(_stepCyclesNtsc[1]); + memcpy(_stepCycles, _stepCyclesNtsc, sizeof(_stepCycles)); break; case NesModel::PAL: - _stepCycles.push_back(_stepCyclesPal[0]); - _stepCycles.push_back(_stepCyclesPal[1]); + memcpy(_stepCycles, _stepCyclesPal, sizeof(_stepCycles)); break; } } diff --git a/Core/ApuLengthCounter.h b/Core/ApuLengthCounter.h index 801567c9..691c6568 100644 --- a/Core/ApuLengthCounter.h +++ b/Core/ApuLengthCounter.h @@ -5,7 +5,7 @@ class ApuLengthCounter : public BaseApuChannel { private: - const vector _lcLookupTable = { { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 } }; + uint8_t _lcLookupTable[32] = { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 }; bool _enabled = false; bool _newHaltValue; static bool _needToRun; @@ -43,7 +43,9 @@ public: static bool NeedToRun() { - return ApuLengthCounter::_needToRun; + bool needToRun = ApuLengthCounter::_needToRun; + ApuLengthCounter::_needToRun = false; + return needToRun; } virtual void Reset(bool softReset) override @@ -83,14 +85,7 @@ public: { return _lengthCounter > 0; } - - virtual void Run(uint32_t targetCycle) override - { - ApuLengthCounter::_needToRun = false; - _lengthCounterHalt = _newHaltValue; - BaseApuChannel::Run(targetCycle); - } - + void ReloadCounter() { if(_lengthCounterReloadValue) { @@ -99,6 +94,8 @@ public: } _lengthCounterReloadValue = 0; } + + _lengthCounterHalt = _newHaltValue; } void TickLengthCounter() diff --git a/Core/BaseApuChannel.h b/Core/BaseApuChannel.h index 2b8b194c..bf606f43 100644 --- a/Core/BaseApuChannel.h +++ b/Core/BaseApuChannel.h @@ -71,26 +71,20 @@ public: } } - virtual void Run(uint32_t targetCycle) + void Run(uint32_t targetCycle) { - while(_previousCycle < targetCycle) { - if(_timer == 0) { - Clock(); - _timer = _period; - _previousCycle++; - } else { - uint32_t cyclesToRun = targetCycle - _previousCycle; - uint16_t skipCount = _timer > cyclesToRun ? cyclesToRun : _timer; - _timer -= skipCount; - _previousCycle += skipCount; - - if(cyclesToRun == 0) { - break; - } - } + int32_t cyclesToRun = targetCycle - _previousCycle; + while(cyclesToRun > _timer) { + cyclesToRun -= _timer + 1; + _previousCycle += _timer + 1; + Clock(); + _timer = _period; } + + _timer -= cyclesToRun; + _previousCycle = targetCycle; } - + uint8_t ReadRAM(uint16_t addr) override { return 0; diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index e1a1acbd..63e11188 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -5,7 +5,7 @@ #include "../Utilities/FolderUtilities.h" #include "CheatManager.h" #include "Debugger.h" -#include "MemoryDumper.h" +#include "MemoryManager.h" void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { } uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; } @@ -243,7 +243,7 @@ void BaseMapper::RemovePpuMemoryMapping(uint16_t startAddr, uint16_t endAddr) uint8_t BaseMapper::InternalReadRam(uint16_t addr) { - return _prgPages[addr >> 8] ? _prgPages[addr >> 8][addr & 0xFF] : 0; + return _prgPages[addr >> 8] ? _prgPages[addr >> 8][(uint8_t)addr] : 0; } void BaseMapper::SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType) @@ -546,10 +546,10 @@ void BaseMapper::Initialize(RomData &romData) for(int i = 0; i <= 0xFF; i++) { //Allow us to map a different page every 256 bytes - _prgPages.push_back(nullptr); - _prgPageAccessType.push_back(MemoryAccessType::NoAccess); - _chrPages.push_back(nullptr); - _chrPageAccessType.push_back(MemoryAccessType::NoAccess); + _prgPages[i] = nullptr; + _prgPageAccessType[i] = MemoryAccessType::NoAccess; + _chrPages[i] = nullptr; + _chrPageAccessType[i] = MemoryAccessType::NoAccess; } if(_chrRomSize == 0) { @@ -728,18 +728,18 @@ uint8_t BaseMapper::ReadRAM(uint16_t addr) if(_allowRegisterRead && _isReadRegisterAddr[addr]) { return ReadRegister(addr); } else if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Read) { - return _prgPages[addr >> 8][addr & 0xFF]; + return _prgPages[addr >> 8][(uint8_t)addr]; } else { //assert(false); } - return (addr & 0xFF00) >> 8; + return MemoryManager::GetOpenBus(); } void BaseMapper::WriteRAM(uint16_t addr, uint8_t value) { if(_isWriteRegisterAddr[addr]) { if(_hasBusConflicts) { - value &= _prgPages[addr >> 8][addr & 0xFF]; + value &= _prgPages[addr >> 8][(uint8_t)addr]; } WriteRegister(addr, value); } else { @@ -750,34 +750,17 @@ void BaseMapper::WriteRAM(uint16_t addr, uint8_t value) void BaseMapper::WritePrgRam(uint16_t addr, uint8_t value) { if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Write) { - _prgPages[addr >> 8][addr & 0xFF] = value; + _prgPages[addr >> 8][(uint8_t)addr] = value; } } -uint8_t BaseMapper::InternalReadVRAM(uint16_t addr) +void BaseMapper::ProcessVramAccess(uint16_t &addr) { - if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Read) { - return _chrPages[addr >> 8][addr & 0xFF]; - } - return 0; -} - -void BaseMapper::InternalWriteVRAM(uint16_t addr, uint8_t value) -{ - if(_chrPages[addr >> 8]) { - _chrPages[addr >> 8][addr & 0xFF] = value; - } -} - -uint8_t BaseMapper::ReadVRAM(uint16_t addr, MemoryOperationType operationType) -{ - return InternalReadVRAM(addr); -} - -void BaseMapper::WriteVRAM(uint16_t addr, uint8_t value) -{ - if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Write) { - _chrPages[addr >> 8][addr & 0xFF] = value; + addr &= 0x3FFF; + if(addr >= 0x3000) { + //Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves + //Required for proper MMC3 IRQ timing in Burai Fighter + addr -= 0x1000; } } @@ -787,6 +770,43 @@ void BaseMapper::NotifyVRAMAddressChange(uint16_t addr) //Used by MMC3/MMC5/etc } +uint8_t BaseMapper::InternalReadVRAM(uint16_t addr) +{ + if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Read) { + return _chrPages[addr >> 8][(uint8_t)addr]; + } + return 0; +} + +uint8_t BaseMapper::DebugReadVRAM(uint16_t addr) +{ + ProcessVramAccess(addr); + return InternalReadVRAM(addr); +} + +uint8_t BaseMapper::MapperReadVRAM(uint16_t addr, MemoryOperationType operationType) +{ + return InternalReadVRAM(addr); +} + +void BaseMapper::InternalWriteVRAM(uint16_t addr, uint8_t value) +{ + if(_chrPages[addr >> 8]) { + _chrPages[addr >> 8][(uint8_t)addr] = value; + } +} + +void BaseMapper::WriteVRAM(uint16_t addr, uint8_t value) +{ + ProcessVramAccess(addr); + Debugger::ProcessVramOperation(MemoryOperationType::Write, addr, value); + NotifyVRAMAddressChange(addr); + + if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Write) { + _chrPages[addr >> 8][(uint8_t)addr] = value; + } +} + bool BaseMapper::IsNes20() { return _nesHeader.GetRomHeaderVersion() == RomHeaderVersion::Nes2_0; @@ -869,7 +889,7 @@ void BaseMapper::SetMemoryValue(DebugMemoryType memoryType, uint32_t address, ui int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr) { - uint8_t *prgAddr = _prgPages[addr >> 8] + (addr & 0xFF); + uint8_t *prgAddr = _prgPages[addr >> 8] + (uint8_t)addr; if(prgAddr >= _prgRom && prgAddr < _prgRom + _prgSize) { return (uint32_t)(prgAddr - _prgRom); } @@ -878,7 +898,7 @@ int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr) int32_t BaseMapper::ToAbsoluteWorkRamAddress(uint16_t addr) { - uint8_t *prgRamAddr = _prgPages[addr >> 8] + (addr & 0xFF); + uint8_t *prgRamAddr = _prgPages[addr >> 8] + (uint8_t)addr; if(prgRamAddr >= _workRam && prgRamAddr < _workRam + _workRamSize) { return (uint32_t)(prgRamAddr - _workRam); } @@ -887,7 +907,7 @@ int32_t BaseMapper::ToAbsoluteWorkRamAddress(uint16_t addr) int32_t BaseMapper::ToAbsoluteSaveRamAddress(uint16_t addr) { - uint8_t *prgRamAddr = _prgPages[addr >> 8] + (addr & 0xFF); + uint8_t *prgRamAddr = _prgPages[addr >> 8] + (uint8_t)addr; if(prgRamAddr >= _saveRam && prgRamAddr < _saveRam + _saveRamSize) { return (uint32_t)(prgRamAddr - _saveRam); } @@ -896,7 +916,7 @@ int32_t BaseMapper::ToAbsoluteSaveRamAddress(uint16_t addr) int32_t BaseMapper::ToAbsoluteChrAddress(uint16_t addr) { - uint8_t *chrAddr = _chrPages[addr >> 8] + (addr & 0xFF); + uint8_t *chrAddr = _chrPages[addr >> 8] + (uint8_t)addr; if(chrAddr >= _chrRom && chrAddr < _chrRom + _chrRomSize) { return (uint32_t)(chrAddr - _chrRom); } diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 982caaf1..dceb6b13 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -7,52 +7,8 @@ #include "RomLoader.h" #include "EmulationSettings.h" #include "DebuggerTypes.h" - -enum class DebugMemoryType; - -enum class PrgMemoryType -{ - PrgRom, - SaveRam, - WorkRam, -}; - -enum class ChrMemoryType -{ - Default, - ChrRom, - ChrRam -}; - -enum MemoryAccessType -{ - Unspecified = -1, - NoAccess = 0x00, - Read = 0x01, - Write = 0x02, - ReadWrite = 0x03 -}; - -enum ChrSpecialPage -{ - NametableA = 0x7000, - NametableB = 0x7001 -}; - -struct CartridgeState -{ - uint32_t PrgRomSize; - uint32_t ChrRomSize; - uint32_t ChrRamSize; - - uint32_t PrgPageCount; - uint32_t PrgPageSize; - uint32_t PrgSelectedPages[64]; - uint32_t ChrPageCount; - uint32_t ChrPageSize; - uint32_t ChrSelectedPages[64]; - uint32_t Nametables[8]; -}; +#include "Debugger.h" +#include "Types.h" class BaseMapper : public IMemoryHandler, public Snapshotable, public INotificationListener { @@ -81,10 +37,10 @@ private: uint8_t _isReadRegisterAddr[0x10000]; uint8_t _isWriteRegisterAddr[0x10000]; - vector _prgPages; - vector _chrPages; - vector _prgPageAccessType; - vector _chrPageAccessType; + uint8_t* _prgPages[0x100]; + uint8_t* _chrPages[0x100]; + uint8_t _prgPageAccessType[0x100]; + uint8_t _chrPageAccessType[0x100]; uint32_t _prgPageNumbers[64]; uint32_t _chrPageNumbers[64]; @@ -213,15 +169,29 @@ public: string GetRomName(); RomFormat GetRomFormat(); - uint8_t ReadRAM(uint16_t addr) override; + __forceinline uint8_t ReadRAM(uint16_t addr) override; virtual void WriteRAM(uint16_t addr, uint8_t value) override; void WritePrgRam(uint16_t addr, uint8_t value); - uint8_t InternalReadVRAM(uint16_t addr); - virtual uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type = MemoryOperationType::Read); + __forceinline uint8_t InternalReadVRAM(uint16_t addr); + __forceinline virtual uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType operationType); + + __forceinline uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type = MemoryOperationType::PpuRenderingRead) + { + ProcessVramAccess(addr); + NotifyVRAMAddressChange(addr); + + uint8_t value = MapperReadVRAM(addr, type); + Debugger::ProcessVramOperation(type, addr, value); + return value; + } + void InternalWriteVRAM(uint16_t addr, uint8_t value); void WriteVRAM(uint16_t addr, uint8_t value); + __forceinline void ProcessVramAccess(uint16_t &addr); + uint8_t DebugReadVRAM(uint16_t addr); + static void InitializeRam(void* data, uint32_t length); //Debugger Helper Functions diff --git a/Core/CPU.h b/Core/CPU.h index 4a850fce..0b07c71a 100644 --- a/Core/CPU.h +++ b/Core/CPU.h @@ -5,7 +5,7 @@ #include "Snapshotable.h" #include "TraceLogger.h" #include "EmulationSettings.h" -#include "CpuState.h" +#include "Types.h" namespace PSFlags { diff --git a/Core/Console.cpp b/Core/Console.cpp index 87b243ce..583fca9b 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -64,12 +64,12 @@ void Console::Initialize(string romFilename, stringstream *filestream, string ip _memoryManager.reset(new MemoryManager(_mapper)); _cpu.reset(new CPU(_memoryManager.get())); if(HdNesPack::HasHdPack(_romFilepath)) { - _ppu.reset(new HdPpu(_memoryManager.get())); + _ppu.reset(new HdPpu(_mapper.get())); } else if(NsfMapper::GetInstance()) { //Disable most of the PPU for NSFs - _ppu.reset(new NsfPpu(_memoryManager.get())); + _ppu.reset(new NsfPpu(_mapper.get())); } else { - _ppu.reset(new PPU(_memoryManager.get())); + _ppu.reset(new PPU(_mapper.get())); } _apu.reset(new APU(_memoryManager.get())); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 3fc3b6f9..5ba0f5ce 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -442,7 +442,6 @@ - @@ -452,7 +451,6 @@ - @@ -591,7 +589,6 @@ - @@ -715,6 +712,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index b309e512..9d1f47a0 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -277,9 +277,6 @@ Debugger - - Debugger - Nes\APU @@ -1117,18 +1114,15 @@ Nes\Mappers\Unif - - Nes - - - Nes - Debugger Debugger + + Nes + diff --git a/Core/CpuState.h b/Core/CpuState.h deleted file mode 100644 index df902bff..00000000 --- a/Core/CpuState.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include "stdafx.h" - -struct State -{ - uint16_t PC = 0; - uint8_t SP = 0; - uint8_t A = 0; - uint8_t X = 0; - uint8_t Y = 0; - uint8_t PS = 0; - uint32_t IRQFlag = 0; - int32_t CycleCount = 0; - bool NMIFlag = false; - - //Used by debugger - uint16_t DebugPC = 0; -}; \ No newline at end of file diff --git a/Core/DebugState.h b/Core/DebugState.h deleted file mode 100644 index bff48f77..00000000 --- a/Core/DebugState.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "stdafx.h" -#include "CPU.h" -#include "PPU.h" -#include "BaseMapper.h" - -struct DebugState -{ - State CPU; - PPUDebugState PPU; - CartridgeState Cartridge; -}; diff --git a/Core/Debugger.h b/Core/Debugger.h index 3b5967ad..22137774 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -8,7 +8,6 @@ using std::atomic; using std::deque; using std::unordered_set; -#include "DebugState.h" #include "Breakpoint.h" #include "TraceLogger.h" #include "../Utilities/SimpleLock.h" @@ -26,6 +25,7 @@ class MemoryDumper; class MemoryAccessCounter; class Profiler; class CodeRunner; +class BaseMapper; class Debugger { diff --git a/Core/DebuggerTypes.h b/Core/DebuggerTypes.h index eeb96ab2..9f5da880 100644 --- a/Core/DebuggerTypes.h +++ b/Core/DebuggerTypes.h @@ -1,4 +1,5 @@ #pragma once +#include "Types.h" enum class DebuggerFlags { @@ -47,4 +48,21 @@ enum class CdlHighlightType None = 0, HighlightUsed = 1, HighlightUnused = 2, +}; + +struct PPUDebugState +{ + PPUControlFlags ControlFlags; + PPUStatusFlags StatusFlags; + PPUState State; + int32_t Scanline; + uint32_t Cycle; + uint32_t FrameCount; +}; + +struct DebugState +{ + State CPU; + PPUDebugState PPU; + CartridgeState Cartridge; }; \ No newline at end of file diff --git a/Core/DeltaModulationChannel.h b/Core/DeltaModulationChannel.h index 7026f850..a3e9edc8 100644 --- a/Core/DeltaModulationChannel.h +++ b/Core/DeltaModulationChannel.h @@ -8,8 +8,8 @@ class MemoryManager; class DeltaModulationChannel : public BaseApuChannel { private: - const vector _dmcPeriodLookupTableNtsc = { { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 } }; - const vector _dmcPeriodLookupTablePal = { { 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50 } }; + const uint16_t _dmcPeriodLookupTableNtsc[16] = { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 }; + const uint16_t _dmcPeriodLookupTablePal[16] = { 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50 }; static DeltaModulationChannel *Instance; MemoryManager *_memoryManager = nullptr; diff --git a/Core/EmulationSettings.cpp b/Core/EmulationSettings.cpp index 9073139b..ff1d083b 100644 --- a/Core/EmulationSettings.cpp +++ b/Core/EmulationSettings.cpp @@ -29,6 +29,7 @@ PpuModel EmulationSettings::_ppuModel = PpuModel::Ppu2C02; uint32_t EmulationSettings::_emulationSpeed = 100; uint32_t EmulationSettings::_turboSpeed = 300; +bool EmulationSettings::_hasOverclock = false; uint32_t EmulationSettings::_overclockRate = 100; uint32_t EmulationSettings::_extraScanlinesBeforeNmi = 0; uint32_t EmulationSettings::_extraScanlinesAfterNmi = 0; diff --git a/Core/EmulationSettings.h b/Core/EmulationSettings.h index c28a1d80..f466dfce 100644 --- a/Core/EmulationSettings.h +++ b/Core/EmulationSettings.h @@ -339,6 +339,7 @@ private: static uint32_t _emulationSpeed; static uint32_t _turboSpeed; + static bool _hasOverclock; static uint32_t _overclockRate; static bool _overclockAdjustApu; static bool _disableOverclocking; @@ -589,6 +590,7 @@ public: _effectiveOverclockRateSound = _overclockRate * (double)(1 + (double)(_extraScanlinesBeforeNmi + _extraScanlinesAfterNmi) / _ppuScanlineCount); _effectiveOverclockRate = _overclockRate; } + _hasOverclock = _effectiveOverclockRate != 100; } static void SetPpuScanlineCount(uint32_t scanlineCount) @@ -608,6 +610,11 @@ public: return _overclockRate; } + static bool HasOverclock() + { + return _hasOverclock; + } + static double GetOverclockRate(bool forApu = false, bool forSoundMixer = false) { if(forApu && _overclockAdjustApu || forSoundMixer) { diff --git a/Core/HdPpu.h b/Core/HdPpu.h index eef6bb4e..913abb35 100644 --- a/Core/HdPpu.h +++ b/Core/HdPpu.h @@ -18,17 +18,12 @@ protected: _lastSprite = nullptr; if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) { - uint32_t paletteOffset; - uint32_t color = GetPixelColor(paletteOffset); - if(color == 0) { - pixel = ReadPaletteRAM(0) | _intensifyColorBits; - } else { - pixel = ReadPaletteRAM(paletteOffset + color) | _intensifyColorBits; - } + uint32_t color = GetPixelColor(); + pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits; HdPpuPixelInfo &tileInfo = _screenTiles[bufferOffset]; if(_lastSprite && _flags.SpritesEnabled) { - tileInfo.Sprite.TileIndex = _memoryManager->ToAbsoluteChrAddress(_lastSprite->TileAddr) / 16; + tileInfo.Sprite.TileIndex = _mapper->ToAbsoluteChrAddress(_lastSprite->TileAddr) / 16; tileInfo.Sprite.PaletteColors = ReadPaletteRAM(_lastSprite->PaletteOffset + 1) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 2) << 8) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 3) << 16); tileInfo.Sprite.OffsetY = _lastSprite->OffsetY; @@ -55,7 +50,7 @@ protected: if(_flags.BackgroundEnabled) { TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile); - tileInfo.Tile.TileIndex = _memoryManager->ToAbsoluteChrAddress(lastTile->TileAddr) / 16; + tileInfo.Tile.TileIndex = _mapper->ToAbsoluteChrAddress(lastTile->TileAddr) / 16; tileInfo.Tile.PaletteColors = ReadPaletteRAM(lastTile->PaletteOffset + 1) | (ReadPaletteRAM(lastTile->PaletteOffset + 2) << 8) | (ReadPaletteRAM(lastTile->PaletteOffset + 3) << 16); tileInfo.Tile.OffsetY = lastTile->OffsetY; tileInfo.Tile.BackgroundPriority = false; @@ -76,7 +71,7 @@ protected: } public: - HdPpu(MemoryManager* memoryManager) : PPU(memoryManager) + HdPpu(BaseMapper* mapper) : PPU(mapper) { _screenTileBuffers[0] = new HdPpuPixelInfo[256 * 240]; _screenTileBuffers[1] = new HdPpuPixelInfo[256 * 240]; diff --git a/Core/IMemoryHandler.h b/Core/IMemoryHandler.h index a8606885..1a02691c 100644 --- a/Core/IMemoryHandler.h +++ b/Core/IMemoryHandler.h @@ -1,23 +1,7 @@ #pragma once #include "stdafx.h" - -enum class MemoryOperation -{ - Read = 1, - Write = 2, - Any = 3 -}; - -enum class MemoryOperationType -{ - Read = 0, - Write = 1, - ExecOpCode = 2, - ExecOperand = 3, - PpuRenderingRead = 4, - DummyRead = 5 -}; +#include "Types.h" class MemoryRanges { diff --git a/Core/JyCompany.h b/Core/JyCompany.h index edbd21fd..1ac454c3 100644 --- a/Core/JyCompany.h +++ b/Core/JyCompany.h @@ -343,12 +343,12 @@ protected: } } - uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type) override + uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType type) override { if(_irqSource == JyIrqSource::PpuRead && type == MemoryOperationType::PpuRenderingRead) { TickIrqCounter(); } - return BaseMapper::ReadVRAM(addr, type); + return BaseMapper::MapperReadVRAM(addr, type); } void NotifyVRAMAddressChange(uint16_t addr) override diff --git a/Core/LabelManager.cpp b/Core/LabelManager.cpp index 003fffa2..da156c93 100644 --- a/Core/LabelManager.cpp +++ b/Core/LabelManager.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "LabelManager.h" #include "Debugger.h" +#include "BaseMapper.h" LabelManager::LabelManager(shared_ptr mapper) { diff --git a/Core/MMC5.h b/Core/MMC5.h index 8a84dd7b..d89c5890 100644 --- a/Core/MMC5.h +++ b/Core/MMC5.h @@ -366,7 +366,7 @@ protected: BaseMapper::WriteRAM(addr, value); } - virtual uint8_t ReadVRAM(uint16_t addr, MemoryOperationType memoryOperationType) override + virtual uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType memoryOperationType) override { if(_extendedRamMode <= 1 && _verticalSplitEnabled && memoryOperationType == MemoryOperationType::PpuRenderingRead) { uint32_t cycle = PPU::GetCurrentCycle(); @@ -446,7 +446,7 @@ protected: } } } - return BaseMapper::ReadVRAM(addr, memoryOperationType); + return BaseMapper::MapperReadVRAM(addr, memoryOperationType); } void WriteRegister(uint16_t addr, uint8_t value) override diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp index 1d137eea..316070a2 100644 --- a/Core/MemoryDumper.cpp +++ b/Core/MemoryDumper.cpp @@ -55,7 +55,7 @@ uint32_t MemoryDumper::GetMemoryState(DebugMemoryType type, uint8_t *buffer) case DebugMemoryType::PpuMemory: for(int i = 0; i <= 0x3FFF; i++) { - buffer[i] = _memoryManager->DebugReadVRAM(i); + buffer[i] = _mapper->DebugReadVRAM(i); } return 0x4000; diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 9e5a03d0..445e69a9 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -163,51 +163,11 @@ void MemoryManager::DebugWrite(uint16_t addr, uint8_t value) } } -void MemoryManager::ProcessVramAccess(uint16_t &addr) -{ - addr &= 0x3FFF; - if(addr >= 0x3000) { - //Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves - //Required for proper MMC3 IRQ timing in Burai Fighter - addr -= 0x1000; - } - _mapper->NotifyVRAMAddressChange(addr); -} - -uint8_t MemoryManager::DebugReadVRAM(uint16_t addr) -{ - addr &= 0x3FFF; - if(addr >= 0x3000) { - addr -= 0x1000; - } - return _mapper->InternalReadVRAM(addr); -} - -uint8_t MemoryManager::ReadVRAM(uint16_t addr, MemoryOperationType operationType) -{ - ProcessVramAccess(addr); - uint8_t value = _mapper->ReadVRAM(addr, operationType); - Debugger::ProcessVramOperation(operationType, addr, value); - return value; -} - -void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value) -{ - Debugger::ProcessVramOperation(MemoryOperationType::Write, addr, value); - ProcessVramAccess(addr); - _mapper->WriteVRAM(addr, value); -} - uint32_t MemoryManager::ToAbsolutePrgAddress(uint16_t ramAddr) { return _mapper->ToAbsoluteAddress(ramAddr); } -uint32_t MemoryManager::ToAbsoluteChrAddress(uint16_t vramAddr) -{ - return _mapper->ToAbsoluteChrAddress(vramAddr); -} - void MemoryManager::StreamState(bool saving) { ArrayInfo internalRam = { _internalRAM, MemoryManager::InternalRAMSize }; diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 5a66a24c..91c3b13b 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -41,7 +41,6 @@ class MemoryManager: public Snapshotable uint8_t DebugRead(uint16_t addr, bool disableRegisterReads = true); uint16_t DebugReadWord(uint16_t addr); - uint8_t DebugReadVRAM(uint16_t addr); void DebugWrite(uint16_t addr, uint8_t value); uint8_t* GetInternalRAM(); @@ -51,12 +50,7 @@ class MemoryManager: public Snapshotable uint8_t Read(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read); void Write(uint16_t addr, uint8_t value); - void ProcessVramAccess(uint16_t &addr); - uint8_t ReadVRAM(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::PpuRenderingRead); - void WriteVRAM(uint16_t addr, uint8_t value); - uint32_t ToAbsolutePrgAddress(uint16_t ramAddr); - uint32_t ToAbsoluteChrAddress(uint16_t vramAddr); static uint8_t GetOpenBus(uint8_t mask = 0xFF); }; diff --git a/Core/NoiseChannel.h b/Core/NoiseChannel.h index f69cbe50..aecbff06 100644 --- a/Core/NoiseChannel.h +++ b/Core/NoiseChannel.h @@ -7,8 +7,8 @@ class NoiseChannel : public ApuEnvelope { private: - const vector _noisePeriodLookupTableNtsc = { { 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 } }; - const vector _noisePeriodLookupTablePal = { { 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 } }; + const uint16_t _noisePeriodLookupTableNtsc[16] = { 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 }; + const uint16_t _noisePeriodLookupTablePal[16] = { 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 }; //On power-up, the shift register is loaded with the value 1. uint16_t _shiftRegister = 1; diff --git a/Core/NsfPpu.h b/Core/NsfPpu.h index c6e8d922..0ba6dba5 100644 --- a/Core/NsfPpu.h +++ b/Core/NsfPpu.h @@ -15,8 +15,8 @@ protected: } public: - NsfPpu(MemoryManager* memoryManager) : PPU(memoryManager) + NsfPpu(BaseMapper* mapper) : PPU(mapper) { - _simpleMode = true; + } }; \ No newline at end of file diff --git a/Core/PPU.cpp b/Core/PPU.cpp index 3d10a6c3..a3b3dae4 100644 --- a/Core/PPU.cpp +++ b/Core/PPU.cpp @@ -8,13 +8,13 @@ PPU* PPU::Instance = nullptr; -PPU::PPU(MemoryManager *memoryManager) +PPU::PPU(BaseMapper *mapper) { PPU::Instance = this; EmulationSettings::SetPpuModel(PpuModel::Ppu2C02); - _memoryManager = memoryManager; + _mapper = mapper; _outputBuffers[0] = new uint16_t[256 * 240]; _outputBuffers[1] = new uint16_t[256 * 240]; @@ -29,8 +29,6 @@ PPU::PPU(MemoryManager *memoryManager) BaseMapper::InitializeRam(_spriteRAM, 0x100); BaseMapper::InitializeRam(_secondarySpriteRAM, 0x20); - _simpleMode = false; - Reset(); } @@ -55,6 +53,10 @@ void PPU::Reset() _flags = {}; _statusFlags = {}; + _previousTile = {}; + _currentTile = {}; + _nextTile = {}; + _intensifyColorBits = 0; _paletteRamMask = 0; _lastSprite = nullptr; @@ -67,7 +69,6 @@ void PPU::Reset() _renderingEnabled = false; _prevRenderingEnabled = false; _cyclesNeeded = 0.0; - _simpleMode = false; memset(_spriteTiles, 0, sizeof(SpriteInfo)); _spriteCount = 0; @@ -147,7 +148,7 @@ void PPU::UpdateVideoRamAddr() //Trigger memory read when setting the vram address - needed by MMC3 IRQ counter //"Should be clocked when A12 changes to 1 via $2007 read/write" - _memoryManager->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read); + _mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read); } else { //"During rendering (on the pre-render line and the visible lines 0-239, provided either background or sprite rendering is enabled), " //it will update v in an odd way, triggering a coarse X increment and a Y increment simultaneously" @@ -183,7 +184,7 @@ void PPU::SetOpenBus(uint8_t mask, uint8_t value) mask >>= 1; } - _openBus = openBus & 0xFF; + _openBus = (uint8_t)openBus; } } @@ -241,7 +242,7 @@ uint8_t PPU::ReadRAM(uint16_t addr) openBusMask = 0xFF; } else { returnValue = _memoryReadBuffer; - _memoryReadBuffer = _memoryManager->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read); + _memoryReadBuffer = _mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read); if((_state.VideoRamAddr & 0x3FFF) >= 0x3F00 && !EmulationSettings::CheckFlag(EmulationFlags::DisablePaletteRead)) { returnValue = ReadPaletteRAM(_state.VideoRamAddr) | (_openBus & 0xC0); @@ -325,7 +326,7 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value) if((_state.VideoRamAddr & 0x3FFF) >= 0x3F00) { WritePaletteRAM(_state.VideoRamAddr, value); } else { - _memoryManager->WriteVRAM(_state.VideoRamAddr, value); + _mapper->WriteVRAM(_state.VideoRamAddr, value); } UpdateVideoRamAddr(); break; @@ -343,16 +344,27 @@ uint8_t PPU::ReadPaletteRAM(uint16_t addr) if(addr == 0x10 || addr == 0x14 || addr == 0x18 || addr == 0x1C) { addr &= ~0x10; } - return (_paletteRAM[addr] & _paletteRamMask); + return _paletteRAM[addr]; } void PPU::WritePaletteRAM(uint16_t addr, uint8_t value) { addr &= 0x1F; - if(addr == 0x10 || addr == 0x14 || addr == 0x18 || addr == 0x1C) { - addr &= ~0x10; + if(addr == 0x00 || addr == 0x10) { + _paletteRAM[0x00] = value; + _paletteRAM[0x10] = value; + } else if(addr == 0x04 || addr == 0x14) { + _paletteRAM[0x04] = value; + _paletteRAM[0x14] = value; + } else if(addr == 0x08 || addr == 0x18) { + _paletteRAM[0x08] = value; + _paletteRAM[0x18] = value; + } else if(addr == 0x0C || addr == 0x1C) { + _paletteRAM[0x0C] = value; + _paletteRAM[0x1C] = value; + } else { + _paletteRAM[addr] = value; } - _paletteRAM[addr] = value; } bool PPU::IsRenderingEnabled() @@ -491,9 +503,8 @@ uint16_t PPU::GetAttributeAddr() void PPU::LoadTileInfo() { if(IsRenderingEnabled()) { - uint16_t tileIndex, shift; switch((_cycle - 1) & 0x07) { - case 0: + case 0: { _previousTile = _currentTile; _currentTile = _nextTile; @@ -501,22 +512,24 @@ void PPU::LoadTileInfo() LoadNextTile(); } - tileIndex = _memoryManager->ReadVRAM(GetNameTableAddr()); + uint8_t tileIndex = _mapper->ReadVRAM(GetNameTableAddr()); _nextTile.TileAddr = (tileIndex << 4) | (_state.VideoRamAddr >> 12) | _flags.BackgroundPatternAddr; _nextTile.OffsetY = _state.VideoRamAddr >> 12; break; + } - case 2: - shift = ((_state.VideoRamAddr >> 4) & 0x04) | (_state.VideoRamAddr & 0x02); - _nextTile.PaletteOffset = ((_memoryManager->ReadVRAM(GetAttributeAddr()) >> shift) & 0x03) << 2; + case 2: { + uint8_t shift = ((_state.VideoRamAddr >> 4) & 0x04) | (_state.VideoRamAddr & 0x02); + _nextTile.PaletteOffset = ((_mapper->ReadVRAM(GetAttributeAddr()) >> shift) & 0x03) << 2; break; + } case 3: - _nextTile.LowByte = _memoryManager->ReadVRAM(_nextTile.TileAddr); + _nextTile.LowByte = _mapper->ReadVRAM(_nextTile.TileAddr); break; case 5: - _nextTile.HighByte = _memoryManager->ReadVRAM(_nextTile.TileAddr + 8); + _nextTile.HighByte = _mapper->ReadVRAM(_nextTile.TileAddr + 8); if(_cycle == 334) { InitializeShiftRegisters(); } @@ -547,22 +560,23 @@ void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uin bool fetchLastSprite = true; if((_spriteIndex < _spriteCount || extraSprite) && spriteY < 240) { - _spriteTiles[_spriteIndex].BackgroundPriority = backgroundPriority; - _spriteTiles[_spriteIndex].HorizontalMirror = horizontalMirror; - _spriteTiles[_spriteIndex].VerticalMirror = verticalMirror; - _spriteTiles[_spriteIndex].PaletteOffset = ((attributes & 0x03) << 2) | 0x10; + SpriteInfo &info = _spriteTiles[_spriteIndex]; + info.BackgroundPriority = backgroundPriority; + info.HorizontalMirror = horizontalMirror; + info.VerticalMirror = verticalMirror; + info.PaletteOffset = ((attributes & 0x03) << 2) | 0x10; if(extraSprite) { //Use DebugReadVRAM for extra sprites to prevent side-effects. - _spriteTiles[_spriteIndex].LowByte = _memoryManager->DebugReadVRAM(tileAddr); - _spriteTiles[_spriteIndex].HighByte = _memoryManager->DebugReadVRAM(tileAddr + 8); + info.LowByte = _mapper->DebugReadVRAM(tileAddr); + info.HighByte = _mapper->DebugReadVRAM(tileAddr + 8); } else { fetchLastSprite = false; - _spriteTiles[_spriteIndex].LowByte = _memoryManager->ReadVRAM(tileAddr); - _spriteTiles[_spriteIndex].HighByte = _memoryManager->ReadVRAM(tileAddr + 8); + info.LowByte = _mapper->ReadVRAM(tileAddr); + info.HighByte = _mapper->ReadVRAM(tileAddr + 8); } - _spriteTiles[_spriteIndex].TileAddr = tileAddr; - _spriteTiles[_spriteIndex].OffsetY = lineOffset; - _spriteTiles[_spriteIndex].SpriteX = spriteX; + info.TileAddr = tileAddr; + info.OffsetY = lineOffset; + info.SpriteX = spriteX; } if(fetchLastSprite) { @@ -575,8 +589,8 @@ void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uin tileAddr = ((tileIndex << 4) | _flags.SpritePatternAddr) + lineOffset; } - _memoryManager->ReadVRAM(tileAddr); - _memoryManager->ReadVRAM(tileAddr + 8); + _mapper->ReadVRAM(tileAddr); + _mapper->ReadVRAM(tileAddr + 8); } _spriteIndex++; @@ -622,7 +636,7 @@ void PPU::ShiftTileRegisters() _state.HighBitShift <<= 1; } -uint32_t PPU::GetPixelColor(uint32_t &paletteOffset) +uint32_t PPU::GetPixelColor() { uint8_t offset = _state.XScroll; uint32_t backgroundColor = 0; @@ -661,60 +675,58 @@ uint32_t PPU::GetPixelColor(uint32_t &paletteOffset) if(EmulationSettings::GetSpritesEnabled() && (backgroundColor == 0 || !_spriteTiles[i].BackgroundPriority)) { //Check sprite priority - paletteOffset = _lastSprite->PaletteOffset; - return spriteColor; + return _lastSprite->PaletteOffset + spriteColor; } break; } } } } - paletteOffset = ((offset + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile).PaletteOffset; - return backgroundColor; + return ((offset + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile).PaletteOffset + backgroundColor; } void PPU::DrawPixel() { //This is called 3.7 million times per second - needs to be as fast as possible. - uint16_t &pixel = _currentOutputBuffer[(_scanline << 8) + _cycle - 1]; - if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) { - uint32_t paletteOffset; - uint32_t color = GetPixelColor(paletteOffset); - if(color == 0) { - pixel = ReadPaletteRAM(0x3F00) | _intensifyColorBits; - } else { - pixel = ReadPaletteRAM(0x3F00 + paletteOffset + color) | _intensifyColorBits; - } + uint32_t color = GetPixelColor(); + _currentOutputBuffer[(_scanline << 8) + _cycle - 1] = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits; } else { //"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color." - pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits; + _currentOutputBuffer[(_scanline << 8) + _cycle - 1] = (_paletteRAM[_state.VideoRamAddr & 0x1F] & _paletteRamMask) | _intensifyColorBits; } } -void PPU::ProcessPreVBlankScanline() +void PPU::ProcessScanline() { - //For pre-render scanline & all visible scanlines - if(_prevRenderingEnabled) { - //Use _prevRenderingEnabled to drive vert/horiz scrolling increments. - //This delays the flag by an extra cycle. So if rendering is disabled at cycle 254, - //the vertical scrolling increment will not be performed. - //This appears to fix freezes in Battletoads (Level 2), but may be incorrect. + if(_scanline == -1 && _cycle == 0) { + _statusFlags.SpriteOverflow = false; + _statusFlags.Sprite0Hit = false; + } else if(_cycle > 0 && _cycle <= 256) { + LoadTileInfo(); - //Update video ram address according to scrolling logic - if((_cycle > 0 && _cycle < 256 && (_cycle & 0x07) == 0) || _cycle == 328 || _cycle == 336) { + if(_prevRenderingEnabled && (_cycle & 0x07) == 0) { IncHorizontalScrolling(); - } else if(_cycle == 256) { - IncVerticalScrolling(); - } else if(_cycle == 257) { - //copy horizontal scrolling value from t - _state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F); + if(_cycle == 256) { + IncVerticalScrolling(); + } } - } - if(_cycle >= 257 && _cycle <= 320) { + if(_scanline >= 0) { + DrawPixel(); + ShiftTileRegisters(); + } else if(_cycle == 1) { + _statusFlags.VerticalBlank = false; + } + + CopyOAMData(); + } else if(_cycle >= 257 && _cycle <= 320) { if(_cycle == 257) { _spriteIndex = 0; + if(_prevRenderingEnabled) { + //copy horizontal scrolling value from t + _state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F); + } } if(IsRenderingEnabled()) { //"OAMADDR is set to 0 during each of ticks 257-320 (the sprite tile loading interval) of the pre-render and visible scanlines." (When rendering) @@ -725,75 +737,45 @@ void PPU::ProcessPreVBlankScanline() LoadSpriteTileInfo(); } else if((_cycle - 257) % 8 == 0) { //Garbage NT sprite fetch (257, 265, 273, etc.) - Required for proper MC-ACC IRQs (MMC3 clone) - _memoryManager->ReadVRAM(GetNameTableAddr()); + _mapper->ReadVRAM(GetNameTableAddr()); } else if((_cycle - 259) % 8 == 0) { //Garbage AT sprite fetch - _memoryManager->ReadVRAM(GetAttributeAddr()); + _mapper->ReadVRAM(GetAttributeAddr()); + } + + if(_scanline == -1 && _cycle >= 280 && _cycle <= 304) { + //copy vertical scrolling value from t + _state.VideoRamAddr = (_state.VideoRamAddr & ~0x7BE0) | (_state.TmpVideoRamAddr & 0x7BE0); } } - } else if(_cycle == 321 && IsRenderingEnabled()) { - _oamCopybuffer = _secondarySpriteRAM[0]; - } -} - -void PPU::ProcessPrerenderScanline() -{ - ProcessPreVBlankScanline(); - - if(_cycle == 0) { - _statusFlags.SpriteOverflow = false; - _statusFlags.Sprite0Hit = false; - } else if(_cycle == 1) { - _statusFlags.VerticalBlank = false; - } - - if(_cycle >= 1 && _cycle <= 256) { - LoadTileInfo(); - CopyOAMData(); - } else if(_cycle >= 280 && _cycle <= 304) { - if(IsRenderingEnabled()) { - //copy vertical scrolling value from t - _state.VideoRamAddr = (_state.VideoRamAddr & ~0x7BE0) | (_state.TmpVideoRamAddr & 0x7BE0); - } - } else if(_nesModel == NesModel::NTSC && _cycle == 339 && IsRenderingEnabled() && (_frameCount & 0x01)) { - //This behavior is NTSC-specific - PAL frames are always the same number of cycles - //"With rendering enabled, each odd PPU frame is one PPU clock shorter than normal" (skip from 339 to 0, going over 340) - _cycle = 340; } else if(_cycle >= 321 && _cycle <= 336) { + LoadTileInfo(); if(_cycle == 321) { - Debugger::SetLastFramePpuScroll( - ((_state.VideoRamAddr & 0x1F) << 3) | _state.XScroll | ((_state.VideoRamAddr & 0x400) ? 0x100 : 0), - (((_state.VideoRamAddr & 0x3E0) >> 2) | ((_state.VideoRamAddr & 0x7000) >> 12)) + ((_state.VideoRamAddr & 0x800) ? 240 : 0) - ); + if(IsRenderingEnabled()) { + _oamCopybuffer = _secondarySpriteRAM[0]; + } + if(_scanline == -1) { + Debugger::SetLastFramePpuScroll( + ((_state.VideoRamAddr & 0x1F) << 3) | _state.XScroll | ((_state.VideoRamAddr & 0x400) ? 0x100 : 0), + (((_state.VideoRamAddr & 0x3E0) >> 2) | ((_state.VideoRamAddr & 0x7000) >> 12)) + ((_state.VideoRamAddr & 0x800) ? 240 : 0) + ); + } + } else if(_prevRenderingEnabled && (_cycle == 328 || _cycle == 336)) { + IncHorizontalScrolling(); } - LoadTileInfo(); } else if(_cycle == 337 || _cycle == 339) { if(IsRenderingEnabled()) { - _memoryManager->ReadVRAM(GetNameTableAddr()); + _mapper->ReadVRAM(GetNameTableAddr()); + + if(_scanline == -1 && _nesModel == NesModel::NTSC && _cycle == 339 && (_frameCount & 0x01)) { + //This behavior is NTSC-specific - PAL frames are always the same number of cycles + //"With rendering enabled, each odd PPU frame is one PPU clock shorter than normal" (skip from 339 to 0, going over 340) + _cycle = 340; + } } } } -void PPU::ProcessVisibleScanline() -{ - if(_cycle > 0 && _cycle <= 256) { - LoadTileInfo(); - - DrawPixel(); - ShiftTileRegisters(); - - CopyOAMData(); - } else if(_cycle >= 321 && _cycle <= 336) { - LoadTileInfo(); - } else if(_cycle == 337 || _cycle == 339) { - if(IsRenderingEnabled()) { - _memoryManager->ReadVRAM(GetNameTableAddr()); - } - } - - ProcessPreVBlankScanline(); -} - void PPU::CopyOAMData() { if(_nesModel != NesModel::PAL && IsRenderingEnabled() || _nesModel == NesModel::PAL && (_scanline < 240 || _scanline > 260)) { @@ -801,7 +783,7 @@ void PPU::CopyOAMData() if(_cycle < 9 && _state.SpriteRamAddr >= 0x08 && _scanline == -1 && !EmulationSettings::CheckFlag(EmulationFlags::DisableOamAddrBug)) { //This should only be done if rendering is enabled (otherwise oam_stress test fails immediately) //"If OAMADDR is not less than eight when rendering starts, the eight bytes starting at OAMADDR & 0xF8 are copied to the first eight bytes of OAM" - _spriteRAM[_cycle - 1] = _spriteRAM[((_state.SpriteRamAddr & 0xF8) + _cycle - 1) & 0xFF]; + _spriteRAM[_cycle - 1] = _spriteRAM[(uint8_t)((_state.SpriteRamAddr & 0xF8) + _cycle - 1)]; } //Clear secondary OAM at between cycle 1 and 64 @@ -825,7 +807,7 @@ void PPU::CopyOAMData() if(_cycle & 0x01) { //Read a byte from the primary OAM on odd cycles - _oamCopybuffer = _spriteRAM[(_spriteAddrH << 2) + _spriteAddrL]; + _oamCopybuffer = _spriteRAM[(_spriteAddrH << 2) | _spriteAddrL]; } else { if(_oamCopyDone) { _spriteAddrH = (_spriteAddrH + 1) & 0x3F; @@ -962,34 +944,25 @@ void PPU::Exec() Debugger::ProcessPpuCycle(); - if(!_simpleMode) { - if(_scanline != -1 && _scanline < 240) { - ProcessVisibleScanline(); - } else if(_scanline == -1) { - ProcessPrerenderScanline(); - } else if(_scanline == _nmiScanline) { - BeginVBlank(); - } else if(_nesModel == NesModel::PAL && _scanline > _nmiScanline + 20) { - //"On a PAL machine, because of its extended vertical blank, the PPU begins refreshing OAM roughly 21 scanlines after NMI[2], to prevent it - //from decaying during the longer hiatus of rendering. Additionally, it will continue to refresh during the visible portion of the screen - //even if rendering is disabled. Because of this, OAM DMA must be done near the beginning of vertical blank on PAL, and everywhere else - //it is liable to conflict with the refresh. Since the refresh can't be disabled like on the NTSC hardware, OAM decay does not occur at all on the PAL NES." - if(_cycle > 0 && _cycle <= 256) { - CopyOAMData(); - } else if(_cycle >= 257 && _cycle < 320) { - _state.SpriteRamAddr = 0; - } - } - } else { - //Used by NSF player to speed things up - if(_scanline == _nmiScanline) { - BeginVBlank(); + if(_scanline < 240) { + ProcessScanline(); + } else if(_scanline == _nmiScanline) { + BeginVBlank(); + } else if(_nesModel == NesModel::PAL && _scanline > _nmiScanline + 20) { + //"On a PAL machine, because of its extended vertical blank, the PPU begins refreshing OAM roughly 21 scanlines after NMI[2], to prevent it + //from decaying during the longer hiatus of rendering. Additionally, it will continue to refresh during the visible portion of the screen + //even if rendering is disabled. Because of this, OAM DMA must be done near the beginning of vertical blank on PAL, and everywhere else + //it is liable to conflict with the refresh. Since the refresh can't be disabled like on the NTSC hardware, OAM decay does not occur at all on the PAL NES." + if(_cycle > 0 && _cycle <= 256) { + CopyOAMData(); + } else if(_cycle >= 257 && _cycle < 320) { + _state.SpriteRamAddr = 0; } } //Rendering enabled flag is apparently set with a 1 cycle delay (i.e setting it at cycle 5 will render cycle 6 like cycle 5 and then take the new settings for cycle 7) _prevRenderingEnabled = _renderingEnabled; - _renderingEnabled = _flags.BackgroundEnabled || _flags.SpritesEnabled; + _renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled; if(_updateVramAddrDelay > 0) { _updateVramAddrDelay--; @@ -998,15 +971,14 @@ void PPU::Exec() //Trigger memory read when setting the vram address - needed by MMC3 IRQ counter //"4) Should be clocked when A12 changes to 1 via $2006 write" - _memoryManager->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read); + _mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read); } } } void PPU::ExecStatic() { - double overclockRate = EmulationSettings::GetOverclockRate(); - if(overclockRate == 100) { + if(!EmulationSettings::HasOverclock()) { PPU::Instance->Exec(); PPU::Instance->Exec(); PPU::Instance->Exec(); @@ -1017,9 +989,9 @@ void PPU::ExecStatic() } else { if(PPU::Instance->_nesModel == NesModel::PAL) { //PAL PPU runs 3.2 clocks for every CPU clock, so we need to run an extra clock every 5 CPU clocks - Instance->_cyclesNeeded += 3.2 / (overclockRate / 100.0); + Instance->_cyclesNeeded += 3.2 / (EmulationSettings::GetOverclockRate() / 100.0); } else { - Instance->_cyclesNeeded += 3.0 / (overclockRate / 100.0); + Instance->_cyclesNeeded += 3.0 / (EmulationSettings::GetOverclockRate() / 100.0); } while(Instance->_cyclesNeeded >= 1.0) { diff --git a/Core/PPU.h b/Core/PPU.h index 7ad87b13..47f5484f 100644 --- a/Core/PPU.h +++ b/Core/PPU.h @@ -2,12 +2,15 @@ #include "stdafx.h" #include "Snapshotable.h" -#include "MemoryManager.h" #include "EmulationSettings.h" -#include "PpuState.h" +#include "Types.h" +#include "DebuggerTypes.h" +#include "IMemoryHandler.h" enum class NesModel; +class BaseMapper; + enum PPURegisters { Control = 0x00, @@ -26,7 +29,7 @@ class PPU : public IMemoryHandler, public Snapshotable protected: static PPU* Instance; - MemoryManager *_memoryManager; + BaseMapper *_mapper; PPUState _state; int32_t _scanline; @@ -83,9 +86,6 @@ class PPU : public IMemoryHandler, public Snapshotable double _cyclesNeeded; - //Used by NSF player for higher performance - bool _simpleMode; - uint16_t _updateVramAddr; uint8_t _updateVramAddrDelay; @@ -109,10 +109,7 @@ class PPU : public IMemoryHandler, public Snapshotable uint16_t GetNameTableAddr(); uint16_t GetAttributeAddr(); - __forceinline void ProcessPreVBlankScanline(); - void ProcessPrerenderScanline(); - __forceinline void ProcessVisibleScanline(); - + __forceinline void ProcessScanline(); __forceinline void CopyOAMData(); void BeginVBlank(); @@ -122,13 +119,13 @@ class PPU : public IMemoryHandler, public Snapshotable void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite); void LoadSpriteTileInfo(); void LoadExtraSprites(); - void ShiftTileRegisters(); + __forceinline void ShiftTileRegisters(); void InitializeShiftRegisters(); void LoadNextTile(); void UpdateMinimumDrawCycles(); - __forceinline uint32_t GetPixelColor(uint32_t &paletteOffset); + __forceinline uint32_t GetPixelColor(); __forceinline virtual void DrawPixel(); virtual void SendFrame(); @@ -141,11 +138,6 @@ class PPU : public IMemoryHandler, public Snapshotable } } - void SetSimpleMode() - { - _simpleMode = true; - } - void StreamState(bool saving) override; public: @@ -154,7 +146,7 @@ class PPU : public IMemoryHandler, public Snapshotable static const uint32_t PixelCount = 256*240; static const uint32_t OutputBufferSize = 256*240*2; - PPU(MemoryManager *memoryManager); + PPU(BaseMapper *mapper); virtual ~PPU(); void Reset(); @@ -170,7 +162,7 @@ class PPU : public IMemoryHandler, public Snapshotable ranges.AddHandler(MemoryOperation::Write, 0x4014); } - uint8_t ReadPaletteRAM(uint16_t addr); + __forceinline uint8_t ReadPaletteRAM(uint16_t addr); void WritePaletteRAM(uint16_t addr, uint8_t value); uint8_t ReadRAM(uint16_t addr) override; diff --git a/Core/PpuState.h b/Core/PpuState.h deleted file mode 100644 index e1e7bc14..00000000 --- a/Core/PpuState.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include "stdafx.h" - -struct PPUControlFlags -{ - bool VerticalWrite; - uint16_t SpritePatternAddr; - uint16_t BackgroundPatternAddr; - bool LargeSprites; - bool VBlank; - - bool Grayscale; - bool BackgroundMask; - bool SpriteMask; - bool BackgroundEnabled; - bool SpritesEnabled; - bool IntensifyRed; - bool IntensifyGreen; - bool IntensifyBlue; -}; - -struct PPUStatusFlags -{ - bool SpriteOverflow; - bool Sprite0Hit; - bool VerticalBlank; -}; - -struct PPUState -{ - uint8_t Control; - uint8_t Mask; - uint8_t Status; - uint32_t SpriteRamAddr; - uint16_t VideoRamAddr; - uint8_t XScroll; - uint16_t TmpVideoRamAddr; - bool WriteToggle; - - uint16_t HighBitShift; - uint16_t LowBitShift; -}; - -struct TileInfo -{ - uint8_t LowByte; - uint8_t HighByte; - uint32_t PaletteOffset; - - uint16_t TileAddr; //used by HD ppu - uint8_t OffsetY; //used by HD ppu -}; - -struct SpriteInfo : TileInfo -{ - bool HorizontalMirror; - bool BackgroundPriority; - uint8_t SpriteX; - - bool VerticalMirror; //used by HD ppu -}; - -struct PPUDebugState -{ - PPUControlFlags ControlFlags; - PPUStatusFlags StatusFlags; - PPUState State; - int32_t Scanline; - uint32_t Cycle; - uint32_t FrameCount; -}; \ No newline at end of file diff --git a/Core/SquareChannel.h b/Core/SquareChannel.h index 82cf7d09..6cdcd120 100644 --- a/Core/SquareChannel.h +++ b/Core/SquareChannel.h @@ -7,12 +7,12 @@ class SquareChannel : public ApuEnvelope { private: - const vector> _dutySequences = { { + const uint8_t _dutySequences[4][8] = { { 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 1, 1 }, { 0, 0, 0, 0, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 0, 0 } - } }; + }; bool _isChannel1 = false; diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index 88db8fe7..137952de 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "TraceLogger.h" #include "DisassemblyInfo.h" -#include "DebugState.h" +#include "DebuggerTypes.h" #include "Console.h" #include "MemoryManager.h" #include "LabelManager.h" diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index ab170edc..75dac9c7 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -1,7 +1,6 @@ #pragma once #include "stdafx.h" -#include "CpuState.h" -#include "PpuState.h" +#include "DebuggerTypes.h" class DisassemblyInfo; class MemoryManager; diff --git a/Core/TriangleChannel.h b/Core/TriangleChannel.h index 0410887b..c2da2a9a 100644 --- a/Core/TriangleChannel.h +++ b/Core/TriangleChannel.h @@ -7,7 +7,7 @@ class TriangleChannel : public ApuLengthCounter { private: - const vector _sequence = { { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } }; + const uint8_t _sequence[32] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; uint8_t _linearCounter = 0; uint8_t _linearCounterReload = 0; diff --git a/Core/Types.h b/Core/Types.h new file mode 100644 index 00000000..817968cf --- /dev/null +++ b/Core/Types.h @@ -0,0 +1,139 @@ +#pragma once +#include "stdafx.h" + +enum class MemoryOperation +{ + Read = 1, + Write = 2, + Any = 3 +}; + +enum class MemoryOperationType +{ + Read = 0, + Write = 1, + ExecOpCode = 2, + ExecOperand = 3, + PpuRenderingRead = 4, + DummyRead = 5 +}; + +struct State +{ + uint16_t PC = 0; + uint8_t SP = 0; + uint8_t A = 0; + uint8_t X = 0; + uint8_t Y = 0; + uint8_t PS = 0; + uint32_t IRQFlag = 0; + int32_t CycleCount = 0; + bool NMIFlag = false; + + //Used by debugger + uint16_t DebugPC = 0; +}; + +enum class PrgMemoryType +{ + PrgRom, + SaveRam, + WorkRam, +}; + +enum class ChrMemoryType +{ + Default, + ChrRom, + ChrRam +}; + +enum MemoryAccessType +{ + Unspecified = -1, + NoAccess = 0x00, + Read = 0x01, + Write = 0x02, + ReadWrite = 0x03 +}; + +enum ChrSpecialPage +{ + NametableA = 0x7000, + NametableB = 0x7001 +}; + +struct CartridgeState +{ + uint32_t PrgRomSize; + uint32_t ChrRomSize; + uint32_t ChrRamSize; + + uint32_t PrgPageCount; + uint32_t PrgPageSize; + uint32_t PrgSelectedPages[64]; + uint32_t ChrPageCount; + uint32_t ChrPageSize; + uint32_t ChrSelectedPages[64]; + uint32_t Nametables[8]; +}; + + +struct PPUControlFlags +{ + bool VerticalWrite; + uint16_t SpritePatternAddr; + uint16_t BackgroundPatternAddr; + bool LargeSprites; + bool VBlank; + + bool Grayscale; + bool BackgroundMask; + bool SpriteMask; + bool BackgroundEnabled; + bool SpritesEnabled; + bool IntensifyRed; + bool IntensifyGreen; + bool IntensifyBlue; +}; + +struct PPUStatusFlags +{ + bool SpriteOverflow; + bool Sprite0Hit; + bool VerticalBlank; +}; + +struct PPUState +{ + uint8_t Control; + uint8_t Mask; + uint8_t Status; + uint32_t SpriteRamAddr; + uint16_t VideoRamAddr; + uint8_t XScroll; + uint16_t TmpVideoRamAddr; + bool WriteToggle; + + uint16_t HighBitShift; + uint16_t LowBitShift; +}; + +struct TileInfo +{ + uint8_t LowByte; + uint8_t HighByte; + uint32_t PaletteOffset; + + uint16_t TileAddr; //used by HD ppu + uint8_t OffsetY; //used by HD ppu +}; + +struct SpriteInfo : TileInfo +{ + bool HorizontalMirror; + bool BackgroundPriority; + uint8_t SpriteX; + + bool VerticalMirror; //used by HD ppu +}; \ No newline at end of file