5f055110fa
CPU/APU are decent - PPU is still just a scanline renderer No Super Game Boy support yet
95 lines
No EOL
2.5 KiB
C++
95 lines
No EOL
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);
|
|
}
|
|
}; |