Mesen2/Core/WS/WsMemoryManager.h

169 lines
4.5 KiB
C++

#pragma once
#include "pch.h"
#include "WS/WsCpu.h"
#include "WS/APU/WsApu.h"
#include "WS/WsPpu.h"
#include "WS/WsTypes.h"
#include "Utilities/ISerializable.h"
class WsConsole;
class WsTimer;
class WsControlManager;
class WsCart;
class WsSerial;
class WsDmaController;
class WsEeprom;
class Emulator;
class WsMemoryManager final : public ISerializable
{
private:
WsConsole* _console = nullptr;
WsCpu* _cpu = nullptr;
WsPpu* _ppu = nullptr;
WsApu* _apu = nullptr;
WsControlManager* _controlManager = nullptr;
WsCart* _cart = nullptr;
WsTimer* _timer = nullptr;
WsSerial* _serial = nullptr;
WsDmaController* _dmaController = nullptr;
WsEeprom* _eeprom = nullptr;
Emulator* _emu = nullptr;
uint8_t* _prgRom = nullptr;
uint32_t _prgRomSize = 0;
uint8_t* _saveRam = nullptr;
uint32_t _saveRamSize = 0;
uint8_t* _bootRom = nullptr;
uint32_t _bootRomSize = 0;
uint32_t _workRamSize = 0;
WsMemoryManagerState _state = {};
uint8_t* _reads[256] = {};
uint8_t* _writes[256] = {};
bool IsWordPort(uint16_t port);
uint8_t GetPortWaitStates(uint16_t port);
bool IsUnmappedPort(uint16_t port);
public:
WsMemoryManager() {}
void Init(Emulator* emu, WsConsole* console, WsCpu* cpu, WsPpu* ppu, WsControlManager* controlManager, WsCart* cart, WsTimer* timer, WsDmaController* dmaController, WsEeprom* eeprom, WsApu* apu, WsSerial* serial);
WsMemoryManagerState& GetState() { return _state; }
void RefreshMappings();
void Map(uint32_t start, uint32_t end, MemoryType type, uint32_t offset, bool readonly);
void Unmap(uint32_t start, uint32_t end);
__forceinline void Exec()
{
_cpu->IncCycleCount();
_ppu->Exec();
_apu->Run();
}
__forceinline uint8_t InternalRead(uint32_t addr)
{
uint8_t* handler = _reads[addr >> 12];
uint8_t value = 0x90;
if(handler) {
value = handler[addr & 0xFFF];
}
//TODOWS open bus
return value;
}
__forceinline void InternalWrite(uint32_t addr, uint8_t value)
{
//TODOWS open bus
uint8_t* handler = _writes[addr >> 12];
if(handler) {
handler[addr & 0xFFF] = value;
}
}
uint8_t DebugRead(uint32_t addr);
void DebugWrite(uint32_t addr, uint8_t value);
template<typename T>
T DebugCpuRead(uint16_t seg, uint16_t offset);
template<typename T>
__forceinline T Read(uint16_t seg, uint16_t offset, MemoryOperationType opType = MemoryOperationType::Read)
{
uint32_t addr = ((seg << 4) + offset) & 0xFFFFF;
if constexpr(std::is_same<T, uint16_t>::value) {
bool splitReads = !IsWordBus(addr) || (addr & 0x01);
if(splitReads) {
uint8_t lo = Read<uint8_t>(seg, offset);
uint8_t hi = Read<uint8_t>(seg, offset + 1);
return lo | (hi << 8);
} else {
Exec();
uint8_t lo = InternalRead(addr);
uint8_t hi = InternalRead(((seg << 4) + (uint16_t)(offset + 1)) & 0xFFFFF);
uint16_t value = lo | (hi << 8);
_emu->ProcessMemoryRead<CpuType::Ws, 2>(addr, value, opType);
return value;
}
} else {
Exec();
uint8_t value = InternalRead(addr);
_emu->ProcessMemoryRead<CpuType::Ws, 1>(addr, value, opType);
return value;
}
}
template<typename T>
__forceinline void Write(uint16_t seg, uint16_t offset, T value, MemoryOperationType opType = MemoryOperationType::Write)
{
uint32_t addr = ((seg << 4) + offset) & 0xFFFFF;
if constexpr(std::is_same<T, uint16_t>::value) {
bool splitWrites = !IsWordBus(addr) || (addr & 0x01);
if(splitWrites) {
Write<uint8_t>(seg, offset, (uint8_t)value);
Write<uint8_t>(seg, offset + 1, (uint8_t)(value >> 8));
} else {
Exec();
if(_emu->ProcessMemoryWrite<CpuType::Ws, 2>(addr, value, opType)) {
InternalWrite(addr, (uint8_t)value);
InternalWrite(((seg << 4) + (uint16_t)(offset + 1)) & 0xFFFFF, value >> 8);
}
}
} else {
Exec();
if(_emu->ProcessMemoryWrite<CpuType::Ws>(addr, value, opType)) {
InternalWrite(addr, value);
}
}
}
template<typename T> T ReadPort(uint16_t port);
template<typename T> void WritePort(uint16_t port, T value);
uint8_t InternalReadPort(uint16_t port, bool isWordAccess);
void InternalWritePort(uint16_t port, uint8_t value, bool isWordAccess);
template<typename T> T DebugReadPort(uint16_t port);
bool IsWordBus(uint32_t addr);
uint8_t GetWaitStates(uint32_t addr);
void SetIrqSource(WsIrqSource src);
void ClearIrqSource(WsIrqSource src);
uint8_t GetActiveIrqs();
uint8_t GetIrqVector();
__forceinline bool HasPendingIrq()
{
return (GetActiveIrqs() & _state.EnabledIrqs) != 0;
}
AddressInfo GetAbsoluteAddress(uint32_t relAddr);
int GetRelativeAddress(AddressInfo& absAddress);
void Serialize(Serializer& s) override;
};