#pragma once #include "stdafx.h" #include "GbCart.h" #include "GbMemoryManager.h" #include "../Utilities/Serializer.h" class GbMbc3 : public GbCart { private: bool _hasRtcTimer = false; bool _ramRtcEnabled = false; uint8_t _prgBank = 1; uint8_t _ramBank = 0; uint8_t _rtcRegisters[5] = {}; public: GbMbc3(bool hasRtcTimer) { _hasRtcTimer = hasRtcTimer; } void InitCart() override { _memoryManager->MapRegisters(0x0000, 0x7FFF, RegisterAccess::Write); } void RefreshMappings() override { constexpr int prgBankSize = 0x4000; Map(0x0000, 0x3FFF, GbMemoryType::PrgRom, 0, true); Map(0x4000, 0x7FFF, GbMemoryType::PrgRom, _prgBank * prgBankSize, true); if(_ramRtcEnabled && _ramBank <= 3) { Map(0xA000, 0xBFFF, GbMemoryType::CartRam, _ramBank, false); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::None); } else if(_hasRtcTimer && _ramRtcEnabled && _ramBank >= 0x08 && _ramBank <= 0x0C) { _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::ReadWrite); } else { Unmap(0xA000, 0xBFFF); _memoryManager->MapRegisters(0xA000, 0xBFFF, RegisterAccess::Read); } } uint8_t ReadRegister(uint16_t addr) override { if(_ramRtcEnabled) { //Disabled RAM/RTC registers returns 0xFF on reads (?) return 0xFF; } //RTC register read (TODO) switch(_ramBank) { case 0x08: return _rtcRegisters[0]; //Seconds case 0x09: return _rtcRegisters[1]; //Minutes case 0x0A: return _rtcRegisters[2]; //Hours case 0x0B: return _rtcRegisters[3]; //Day counter case 0x0C: return _rtcRegisters[4]; //Day counter (upper bit) + carry/halt flags } //Not reached return 0xFF; } void WriteRegister(uint16_t addr, uint8_t value) override { if(addr <= 0x7FFF) { switch(addr & 0x6000) { case 0x0000: _ramRtcEnabled = ((value & 0x0F) == 0x0A); break; case 0x2000: _prgBank = std::max(1, value); break; case 0x4000: _ramBank = value & 0x0F; break; case 0x6000: //RTC register read latch break; } RefreshMappings(); } else if(addr >= 0xA000 && addr <= 0xBFFF) { //RTC register write (TODO) switch(_ramBank) { case 0x08: _rtcRegisters[0] = value; break; //Seconds case 0x09: _rtcRegisters[1] = value; break; //Minutes case 0x0A: _rtcRegisters[2] = value; break; //Hours case 0x0B: _rtcRegisters[3] = value; break; //Day counter case 0x0C: _rtcRegisters[4] = value; break; //Day counter (upper bit) + carry/halt flags } } } void Serialize(Serializer& s) override { s.Stream(_ramRtcEnabled, _prgBank, _ramBank); s.StreamArray(_rtcRegisters, 5); } };