#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 T DebugCpuRead(uint16_t seg, uint16_t offset); template __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::value) { bool splitReads = !IsWordBus(addr) || (addr & 0x01); if(splitReads) { uint8_t lo = Read(seg, offset); uint8_t hi = Read(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(addr, value, opType); return value; } } else { Exec(); uint8_t value = InternalRead(addr); _emu->ProcessMemoryRead(addr, value, opType); return value; } } template __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::value) { bool splitWrites = !IsWordBus(addr) || (addr & 0x01); if(splitWrites) { Write(seg, offset, (uint8_t)value); Write(seg, offset + 1, (uint8_t)(value >> 8)); } else { Exec(); if(_emu->ProcessMemoryWrite(addr, value, opType)) { InternalWrite(addr, (uint8_t)value); InternalWrite(((seg << 4) + (uint16_t)(offset + 1)) & 0xFFFFF, value >> 8); } } } else { Exec(); if(_emu->ProcessMemoryWrite(addr, value, opType)) { InternalWrite(addr, value); } } } template T ReadPort(uint16_t port); template 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 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; };