Mesen2/Core/NES/NesMemoryManager.cpp

164 lines
4.7 KiB
C++

#include "pch.h"
#include "NES/NesMemoryManager.h"
#include "NES/BaseMapper.h"
#include "NES/NesConsole.h"
#include "Shared/CheatManager.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Utilities/Serializer.h"
#include "Shared/MemoryOperationType.h"
NesMemoryManager::NesMemoryManager(NesConsole* console, BaseMapper* mapper)
{
_console = console;
_emu = console->GetEmulator();
_cheatManager = _emu->GetCheatManager();
_mapper = mapper;
_internalRamSize = mapper->GetInternalRamSize();
_internalRam = new uint8_t[_internalRamSize];
_emu->RegisterMemory(MemoryType::NesInternalRam, _internalRam, _internalRamSize);
if(_internalRamSize == NesMemoryManager::NesInternalRamSize) {
_internalRamHandler.reset(new InternalRamHandler<0x7FF>());
((InternalRamHandler<0x7FF>*)_internalRamHandler.get())->SetInternalRam(_internalRam);
} else if(_internalRamSize == NesMemoryManager::FamicomBoxInternalRamSize) {
_internalRamHandler.reset(new InternalRamHandler<0x1FFF>());
((InternalRamHandler<0x1FFF>*)_internalRamHandler.get())->SetInternalRam(_internalRam);
} else {
throw std::runtime_error("unsupported memory size");
}
_ramReadHandlers = new INesMemoryHandler*[NesMemoryManager::CpuMemorySize];
_ramWriteHandlers = new INesMemoryHandler*[NesMemoryManager::CpuMemorySize];
for(int i = 0; i < NesMemoryManager::CpuMemorySize; i++) {
_ramReadHandlers[i] = &_openBusHandler;
_ramWriteHandlers[i] = &_openBusHandler;
}
RegisterIODevice(_internalRamHandler.get());
}
NesMemoryManager::~NesMemoryManager()
{
delete[] _internalRam;
delete[] _ramReadHandlers;
delete[] _ramWriteHandlers;
}
void NesMemoryManager::Reset(bool softReset)
{
if(!softReset) {
_console->InitializeRam(_internalRam, _internalRamSize);
}
_mapper->Reset(softReset);
}
void NesMemoryManager::InitializeMemoryHandlers(INesMemoryHandler** memoryHandlers, INesMemoryHandler* handler, vector<uint16_t> *addresses, bool allowOverride)
{
for(uint16_t address : *addresses) {
if(!allowOverride && memoryHandlers[address] != &_openBusHandler && memoryHandlers[address] != handler) {
throw std::runtime_error("Not supported");
}
memoryHandlers[address] = handler;
}
}
void NesMemoryManager::RegisterIODevice(INesMemoryHandler*handler)
{
MemoryRanges ranges;
handler->GetMemoryRanges(ranges);
InitializeMemoryHandlers(_ramReadHandlers, handler, ranges.GetRAMReadAddresses(), ranges.GetAllowOverride());
InitializeMemoryHandlers(_ramWriteHandlers, handler, ranges.GetRAMWriteAddresses(), ranges.GetAllowOverride());
}
void NesMemoryManager::RegisterWriteHandler(INesMemoryHandler* handler, uint32_t start, uint32_t end)
{
for(uint32_t i = start; i < end; i++) {
_ramWriteHandlers[i] = handler;
}
}
void NesMemoryManager::UnregisterIODevice(INesMemoryHandler*handler)
{
MemoryRanges ranges;
handler->GetMemoryRanges(ranges);
for(uint16_t address : *ranges.GetRAMReadAddresses()) {
_ramReadHandlers[address] = &_openBusHandler;
}
for(uint16_t address : *ranges.GetRAMWriteAddresses()) {
_ramWriteHandlers[address] = &_openBusHandler;
}
}
uint8_t* NesMemoryManager::GetInternalRam()
{
return _internalRam;
}
uint8_t NesMemoryManager::DebugRead(uint16_t addr)
{
uint8_t value = _ramReadHandlers[addr]->PeekRam(addr);
if(_cheatManager->HasCheats<CpuType::Nes>()) {
_cheatManager->ApplyCheat<CpuType::Nes>(addr, value);
}
return value;
}
uint16_t NesMemoryManager::DebugReadWord(uint16_t addr)
{
return DebugRead(addr) | (DebugRead(addr + 1) << 8);
}
uint8_t NesMemoryManager::Read(uint16_t addr, MemoryOperationType operationType)
{
uint8_t value = _ramReadHandlers[addr]->ReadRam(addr);
if(_cheatManager->HasCheats<CpuType::Nes>()) {
_cheatManager->ApplyCheat<CpuType::Nes>(addr, value);
}
_emu->ProcessMemoryRead<CpuType::Nes>(addr, value, operationType);
_openBusHandler.SetOpenBus(value);
return value;
}
void NesMemoryManager::Write(uint16_t addr, uint8_t value, MemoryOperationType operationType)
{
_emu->ProcessMemoryWrite<CpuType::Nes>(addr, value, operationType);
_ramWriteHandlers[addr]->WriteRam(addr, value);
}
void NesMemoryManager::DebugWrite(uint16_t addr, uint8_t value, bool disableSideEffects)
{
if(addr <= 0x1FFF) {
_ramWriteHandlers[addr]->WriteRam(addr, value);
} else {
INesMemoryHandler* handler = _ramReadHandlers[addr];
if(handler) {
if(disableSideEffects) {
if(handler == _mapper) {
//Only allow writes to prg/chr ram/rom (e.g not ppu, apu, mapper registers, etc.)
((BaseMapper*)handler)->DebugWriteRam(addr, value);
}
} else {
handler->WriteRam(addr, value);
}
}
}
}
void NesMemoryManager::Serialize(Serializer &s)
{
SVArray(_internalRam, _internalRamSize);
}
uint8_t NesMemoryManager::GetOpenBus(uint8_t mask)
{
return _openBusHandler.GetOpenBus() & mask;
}