Mesen-X/Core/MemoryManager.cpp

212 lines
5.3 KiB
C++
Raw Normal View History

2014-06-14 11:27:55 -04:00
#include "stdafx.h"
#include "MemoryManager.h"
#include "BaseMapper.h"
#include "Debugger.h"
MemoryManager::MemoryManager(shared_ptr<BaseMapper> mapper)
{
_mapper = mapper;
_internalRAM = new uint8_t[InternalRAMSize];
2014-07-01 22:56:06 -04:00
for(int i = 0; i < 4; i++) {
_nametableRAM[i] = new uint8_t[NameTableScreenSize];
memset(_nametableRAM[i], 0, NameTableScreenSize);
}
_ramReadHandlers = new IMemoryHandler*[RAMSize];
_ramWriteHandlers = new IMemoryHandler*[RAMSize];
_vramReadHandlers = new IMemoryHandler*[VRAMSize];
_vramWriteHandlers = new IMemoryHandler*[VRAMSize];
memset(_internalRAM, 0, InternalRAMSize);
memset(_ramReadHandlers, 0, RAMSize * sizeof(IMemoryHandler*));
memset(_ramWriteHandlers, 0, RAMSize * sizeof(IMemoryHandler*));
2014-06-24 16:16:23 -04:00
memset(_vramReadHandlers, 0, VRAMSize * sizeof(IMemoryHandler*));
memset(_vramWriteHandlers, 0, VRAMSize * sizeof(IMemoryHandler*));
}
MemoryManager::~MemoryManager()
{
delete[] _internalRAM;
2014-07-01 22:56:06 -04:00
for(int i = 0; i < 4; i++) {
delete[] _nametableRAM[i];
}
delete[] _ramReadHandlers;
delete[] _ramWriteHandlers;
delete[] _vramReadHandlers;
delete[] _vramWriteHandlers;
}
2014-06-14 11:27:55 -04:00
uint8_t MemoryManager::ReadRegister(uint16_t addr)
{
if(_ramReadHandlers[addr]) {
return _ramReadHandlers[addr]->ReadRAM(addr);
2014-06-14 11:27:55 -04:00
} else {
return 0;
}
}
void MemoryManager::WriteRegister(uint16_t addr, uint8_t value)
{
if(_ramWriteHandlers[addr]) {
_ramWriteHandlers[addr]->WriteRAM(addr, value);
2014-06-15 21:45:36 -04:00
}
}
uint8_t MemoryManager::ReadMappedVRAM(uint16_t addr)
{
return _mapper->ReadVRAM(addr);
2014-06-15 21:45:36 -04:00
}
void MemoryManager::WriteMappedVRAM(uint16_t addr, uint8_t value)
{
return _mapper->WriteVRAM(addr, value);
2014-06-14 11:27:55 -04:00
}
void MemoryManager::InitializeMemoryHandlers(IMemoryHandler** memoryHandlers, IMemoryHandler* handler, vector<uint16_t> *addresses)
2014-06-14 11:27:55 -04:00
{
for(uint16_t address : *addresses) {
if(memoryHandlers[address] != nullptr) {
throw exception("Not supported");
2014-06-15 21:45:36 -04:00
}
memoryHandlers[address] = handler;
2014-06-15 21:45:36 -04:00
}
}
2014-06-15 21:45:36 -04:00
void MemoryManager::RegisterIODevice(IMemoryHandler *handler)
{
MemoryRanges ranges;
handler->GetMemoryRanges(ranges);
InitializeMemoryHandlers(_ramReadHandlers, handler, ranges.GetRAMReadAddresses());
InitializeMemoryHandlers(_ramWriteHandlers, handler, ranges.GetRAMWriteAddresses());
InitializeMemoryHandlers(_vramReadHandlers, handler, ranges.GetVRAMReadAddresses());
InitializeMemoryHandlers(_vramWriteHandlers, handler, ranges.GetVRAMWriteAddresses());
2014-06-14 11:27:55 -04:00
}
uint8_t* MemoryManager::GetInternalRAM()
{
return _internalRAM;
}
uint8_t MemoryManager::DebugRead(uint16_t addr)
2014-06-14 11:27:55 -04:00
{
if(addr <= 0x1FFF) {
return _internalRAM[addr & 0x07FF];
} else if(addr > 0x4017) {
return ReadRegister(addr);
}
return 0;
}
uint8_t MemoryManager::Read(uint16_t addr, bool forExecution)
{
Debugger::CheckBreakpoint(forExecution ? BreakpointType::Execute : BreakpointType::Read, addr);
uint8_t value;
2014-06-14 11:27:55 -04:00
if(addr <= 0x1FFF) {
value = _internalRAM[addr & 0x07FF];
2014-06-14 11:27:55 -04:00
} else {
value = ReadRegister(addr);
2014-06-14 11:27:55 -04:00
}
return value;
2014-06-14 11:27:55 -04:00
}
void MemoryManager::Write(uint16_t addr, uint8_t value)
{
Debugger::CheckBreakpoint(BreakpointType::Write, addr);
2014-06-14 18:20:56 -04:00
if(addr <= 0x1FFF) {
2014-06-14 11:27:55 -04:00
_internalRAM[addr & 0x07FF] = value;
} else {
WriteRegister(addr, value);
}
}
uint8_t MemoryManager::ReadVRAM(uint16_t addr)
{
addr &= 0x3FFF;
2014-06-15 21:45:36 -04:00
if(addr <= 0x1FFF) {
_mapper->NotifyVRAMAddressChange(addr);
return ReadMappedVRAM(addr);
2014-06-15 21:45:36 -04:00
} else {
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);
switch(_mapper->GetMirroringType()) {
case MirroringType::Vertical:
2014-07-01 22:56:06 -04:00
return _nametableRAM[(addr&0x400)>>10][addr & 0x3FF];
case MirroringType::Horizontal:
2014-07-01 22:56:06 -04:00
return _nametableRAM[(addr&0x800)>>11][addr & 0x3FF];
case MirroringType::FourScreens:
default:
2014-07-01 22:56:06 -04:00
return _nametableRAM[(addr&0xC00)>>10][addr & 0x3FF];
case MirroringType::ScreenAOnly:
2014-07-01 22:56:06 -04:00
return _nametableRAM[0][addr & 0x3FF];
case MirroringType::ScreenBOnly:
2014-07-01 22:56:06 -04:00
return _nametableRAM[1][addr & 0x3FF];
}
2014-06-15 21:45:36 -04:00
}
}
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
{
addr &= 0x3FFF;
2014-06-15 21:45:36 -04:00
if(addr <= 0x1FFF) {
_mapper->NotifyVRAMAddressChange(addr);
2014-06-15 21:45:36 -04:00
WriteMappedVRAM(addr, value);
} else {
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);
switch(_mapper->GetMirroringType()) {
case MirroringType::Vertical:
2014-07-01 22:56:06 -04:00
_nametableRAM[(addr&0x400)>>10][addr & 0x3FF] = value;
break;
case MirroringType::Horizontal:
2014-07-01 22:56:06 -04:00
_nametableRAM[(addr&0x800)>>11][addr & 0x3FF] = value;
break;
case MirroringType::ScreenAOnly: //Always write to 0x2000
2014-07-01 22:56:06 -04:00
_nametableRAM[0][addr & 0x3FF] = value;
break;
case MirroringType::ScreenBOnly: //Always write to 0x2400
2014-07-01 22:56:06 -04:00
_nametableRAM[1][addr & 0x3FF] = value;
break;
case MirroringType::FourScreens:
2014-07-01 22:56:06 -04:00
_nametableRAM[(addr&0xC00)>>10][addr & 0x3FF] = value;
break;
default:
throw exception("Not implemented yet");
}
2014-06-15 21:45:36 -04:00
}
2014-06-25 21:52:37 -04:00
}
void MemoryManager::StreamState(bool saving)
{
StreamArray<uint8_t>(_internalRAM, MemoryManager::InternalRAMSize);
2014-07-01 22:56:06 -04:00
for(int i = 0; i < 4; i++) {
StreamArray<uint8_t>(_nametableRAM[i], MemoryManager::NameTableScreenSize);
}
2014-06-15 21:45:36 -04:00
}