Mesen-S/Core/GbMbc3.h
Sour 5f055110fa Added Game Boy support
CPU/APU are decent - PPU is still just a scanline renderer
No Super Game Boy support yet
2020-05-18 16:11:08 -04:00

95 lines
2.5 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);
}
};