Mesen-SX/Core/GbMbc3.h
2020-12-19 23:30:09 +03:00

115 lines
2.6 KiB
C++

#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<uint8_t>(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);
}
};