#include "stdafx.h" #include "MemoryManager.h" #include "Console.h" #include "BaseCartridge.h" #include "Cpu.h" #include "Ppu.h" #include "DmaController.h" #include "RegisterHandlerA.h" #include "RegisterHandlerB.h" #include "RamHandler.h" #include "MessageManager.h" #include "DebugTypes.h" #include "EmuSettings.h" #include "Sa1.h" #include "Gsu.h" #include "Cx4.h" #include "Gameboy.h" #include "BaseCoprocessor.h" #include "CheatManager.h" #include "../Utilities/Serializer.h" #include "../Utilities/HexUtilities.h" void MemoryManager::Initialize(Console* console) { _masterClock = 0; _openBus = 0; _cpuSpeed = 8; _console = console; _regs = console->GetInternalRegisters().get(); _cpu = console->GetCpu().get(); _ppu = console->GetPpu().get(); _cart = console->GetCartridge().get(); _cheatManager = console->GetCheatManager().get(); _workRam = new uint8_t[MemoryManager::WorkRamSize]; _console->GetSettings()->InitializeRam(_workRam, MemoryManager::WorkRamSize); _registerHandlerA.reset(new RegisterHandlerA( console->GetDmaController().get(), console->GetInternalRegisters().get(), console->GetControlManager().get() )); _registerHandlerB.reset(new RegisterHandlerB( _console, _ppu, console->GetSpc().get(), _workRam )); for (uint32_t i = 0; i < 128 * 1024; i += 0x1000) { _workRamHandlers.push_back( unique_ptr(new RamHandler(_workRam, i, MemoryManager::WorkRamSize, SnesMemoryType::WorkRam))); } _mappings.RegisterHandler(0x7E, 0x7F, 0x0000, 0xFFFF, _workRamHandlers); _mappings.RegisterHandler(0x00, 0x3F, 0x2000, 0x2FFF, _registerHandlerB.get()); _mappings.RegisterHandler(0x80, 0xBF, 0x2000, 0x2FFF, _registerHandlerB.get()); _mappings.RegisterHandler(0x00, 0x3F, 0x4000, 0x4FFF, _registerHandlerA.get()); _mappings.RegisterHandler(0x80, 0xBF, 0x4000, 0x4FFF, _registerHandlerA.get()); _mappings.RegisterHandler(0x00, 0x3F, 0x0000, 0x0FFF, _workRamHandlers[0].get()); _mappings.RegisterHandler(0x80, 0xBF, 0x0000, 0x0FFF, _workRamHandlers[0].get()); _mappings.RegisterHandler(0x00, 0x3F, 0x1000, 0x1FFF, _workRamHandlers[1].get()); _mappings.RegisterHandler(0x80, 0xBF, 0x1000, 0x1FFF, _workRamHandlers[1].get()); _cart->Init(_mappings); GenerateMasterClockTable(); Reset(); } MemoryManager::~MemoryManager() { delete[] _workRam; } void MemoryManager::Reset() { _masterClock = 0; _hClock = 0; _dramRefreshPosition = 538 - (_masterClock & 0x07); _nextEventClock = _dramRefreshPosition; _nextEvent = SnesEventType::DramRefresh; } void MemoryManager::GenerateMasterClockTable() { for (int i = 0; i < 0x800; i++) { uint8_t bank = (i & 0x300) >> 8; if (bank == 1) { //Banks $40-$7F - Slow _masterClockTable[i] = 8; } else if (bank == 3) { //Banks $C0-$FF //Slow or fast (depending on register) _masterClockTable[i] = (i >= 0x400) ? 6 : 8; } else { //Banks $00-$3F and $80-$BF uint8_t page = (i & 0xFF); if (page <= 0x1F) { //Slow _masterClockTable[i] = 8; } else if (page >= 0x20 && page <= 0x3F) { //Fast _masterClockTable[i] = 6; } else if (page == 0x40 || page == 0x41) { //Extra slow _masterClockTable[i] = 12; } else if (page >= 0x42 && page <= 0x5F) { //Fast _masterClockTable[i] = 6; } else if (page >= 0x60 && page <= 0x7F) { //Slow _masterClockTable[i] = 8; } else if (bank == 0) { //Slow _masterClockTable[i] = 8; } else { //page >= $80 //Slow or fast (depending on register) _masterClockTable[i] = (i >= 0x400) ? 6 : 8; } } } } void MemoryManager::IncMasterClock4() { Exec(); Exec(); } void MemoryManager::IncMasterClock6() { Exec(); Exec(); Exec(); } void MemoryManager::IncMasterClock8() { Exec(); Exec(); Exec(); Exec(); } void MemoryManager::IncMasterClock40() { Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); Exec(); } void MemoryManager::IncMasterClockStartup() { for (int i = 0; i < 182 / 2; i++) { Exec(); } } void MemoryManager::IncrementMasterClockValue(uint16_t cyclesToRun) { switch (cyclesToRun) { case 12: Exec(); case 10: Exec(); case 8: Exec(); case 6: Exec(); case 4: Exec(); case 2: Exec(); } } void MemoryManager::Exec() { _masterClock += 2; _hClock += 2; if (_hClock == _nextEventClock) { ProcessEvent(); } if ((_hClock & 0x03) == 0) { _console->ProcessPpuCycle(); _regs->ProcessIrqCounters(); } _cart->SyncCoprocessors(); } void MemoryManager::ProcessEvent() { switch (_nextEvent) { case SnesEventType::HdmaInit: _console->GetDmaController()->BeginHdmaInit(); _nextEvent = SnesEventType::DramRefresh; _nextEventClock = _dramRefreshPosition; break; case SnesEventType::DramRefresh: IncMasterClock40(); _cpu->IncreaseCycleCount<5>(); if (_ppu->GetScanline() < _ppu->GetVblankStart()) { _nextEvent = SnesEventType::HdmaStart; _nextEventClock = 276 * 4; } else { _nextEvent = SnesEventType::EndOfScanline; _nextEventClock = 1360; } break; case SnesEventType::HdmaStart: _console->GetDmaController()->BeginHdmaTransfer(); _nextEvent = SnesEventType::EndOfScanline; _nextEventClock = 1360; break; case SnesEventType::EndOfScanline: if (_ppu->ProcessEndOfScanline(_hClock)) { _hClock = 0; if (_ppu->GetScanline() == 0) { _nextEvent = SnesEventType::HdmaInit; _nextEventClock = 12 + (_masterClock & 0x07); } else { _dramRefreshPosition = 538 - (_masterClock & 0x07); _nextEvent = SnesEventType::DramRefresh; _nextEventClock = _dramRefreshPosition; } } else { _nextEventClock += 2; } break; } } uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type) { IncrementMasterClockValue(_cpuSpeed - 4); uint8_t value; IMemoryHandler* handler = _mappings.GetHandler(addr); if (handler) { value = handler->Read(addr); _memTypeBusA = handler->GetMemoryType(); _openBus = value; } else { //open bus value = _openBus; LogDebug("[Debug] Read - missing handler: $" + HexUtilities::ToHex(addr)); } _cheatManager->ApplyCheat(addr, value); _console->ProcessMemoryRead(addr, value, type); IncMasterClock4(); return value; } uint8_t MemoryManager::ReadDma(uint32_t addr, bool forBusA) { _cpu->DetectNmiSignalEdge(); IncMasterClock4(); uint8_t value; IMemoryHandler* handler = _mappings.GetHandler(addr); if (handler) { if (forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) { //Trying to read from bus B using bus A returns open bus value = _openBus; } else if (handler == _registerHandlerA.get()) { uint16_t regAddr = addr & 0xFFFF; if (regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) { //Trying to read the DMA controller with DMA returns open bus value = _openBus; } else { value = handler->Read(addr); } } else { value = handler->Read(addr); if (handler != _registerHandlerB.get()) { _memTypeBusA = handler->GetMemoryType(); } } _openBus = value; } else { //open bus value = _openBus; LogDebug("[Debug] Read - missing handler: $" + HexUtilities::ToHex(addr)); } _cheatManager->ApplyCheat(addr, value); _console->ProcessMemoryRead(addr, value, MemoryOperationType::DmaRead); return value; } uint8_t MemoryManager::Peek(uint32_t addr) { return _mappings.Peek(addr); } uint16_t MemoryManager::PeekWord(uint32_t addr) { return _mappings.PeekWord(addr); } void MemoryManager::PeekBlock(uint32_t addr, uint8_t* dest) { _mappings.PeekBlock(addr, dest); } void MemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type) { IncrementMasterClockValue(_cpuSpeed); _console->ProcessMemoryWrite(addr, value, type); IMemoryHandler* handler = _mappings.GetHandler(addr); if (handler) { handler->Write(addr, value); _memTypeBusA = handler->GetMemoryType(); } else { LogDebug("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); } } void MemoryManager::WriteDma(uint32_t addr, uint8_t value, bool forBusA) { _cpu->DetectNmiSignalEdge(); IncMasterClock4(); _console->ProcessMemoryWrite(addr, value, MemoryOperationType::DmaWrite); IMemoryHandler* handler = _mappings.GetHandler(addr); if (handler) { if (forBusA && handler == _registerHandlerB.get() && (addr & 0xFF00) == 0x2100) { //Trying to write to bus B using bus A does nothing } else if (handler == _registerHandlerA.get()) { uint16_t regAddr = addr & 0xFFFF; if (regAddr == 0x420B || regAddr == 0x420C || (regAddr >= 0x4300 && regAddr <= 0x437F)) { //Trying to write to the DMA controller with DMA does nothing } else { handler->Write(addr, value); } } else { handler->Write(addr, value); if (handler != _registerHandlerB.get()) { _memTypeBusA = handler->GetMemoryType(); } } } else { LogDebug("[Debug] Write - missing handler: $" + HexUtilities::ToHex(addr) + " = " + HexUtilities::ToHex(value)); } } uint8_t MemoryManager::GetOpenBus() { return _openBus; } uint64_t MemoryManager::GetMasterClock() { return _masterClock; } uint16_t MemoryManager::GetHClock() { return _hClock; } uint8_t* MemoryManager::DebugGetWorkRam() { return _workRam; } MemoryMappings* MemoryManager::GetMemoryMappings() { return &_mappings; } uint8_t MemoryManager::GetCpuSpeed(uint32_t addr) { return _masterClockTable[(_regs->IsFastRomEnabled() << 10) | ((addr & 0xC00000) >> 14) | ((addr & 0xFF00) >> 8)]; } uint8_t MemoryManager::GetCpuSpeed() { return _cpuSpeed; } void MemoryManager::SetCpuSpeed(uint8_t speed) { _cpuSpeed = speed; } SnesMemoryType MemoryManager::GetMemoryTypeBusA() { return _memTypeBusA; } bool MemoryManager::IsRegister(uint32_t cpuAddress) { IMemoryHandler* handler = _mappings.GetHandler(cpuAddress); return handler == _registerHandlerA.get() || handler == _registerHandlerB.get(); } bool MemoryManager::IsWorkRam(uint32_t cpuAddress) { IMemoryHandler* handler = _mappings.GetHandler(cpuAddress); return handler && handler->GetMemoryType() == SnesMemoryType::WorkRam; } void MemoryManager::Serialize(Serializer& s) { s.Stream(_masterClock, _openBus, _cpuSpeed, _hClock, _dramRefreshPosition); s.StreamArray(_workRam, MemoryManager::WorkRamSize); if (s.GetVersion() < 8) { bool unusedHasEvent[1369]; s.StreamArray(unusedHasEvent, sizeof(unusedHasEvent)); } s.Stream(_registerHandlerB.get()); }