GBC: Improved IO port behavior

Fixes unused_hwio-C test, and allows aevilia to run
This commit is contained in:
Sour 2020-07-03 00:38:55 -04:00
parent a15b22a05a
commit a22302134d
10 changed files with 92 additions and 19 deletions

View file

@ -31,7 +31,13 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile, bool sgbEnabled
MessageManager::Log("File: " + romFile.GetFileName());
MessageManager::Log("Game: " + header.GetCartName());
MessageManager::Log("Cart Type: " + std::to_string(header.CartType));
switch(header.CgbFlag & 0xC0) {
case 0x00: MessageManager::Log("Supports: Game Boy"); break;
case 0x80: MessageManager::Log("Supports: Game Boy Color (compatible with GB)"); break;
case 0xC0: MessageManager::Log("Supports: Game Boy Color only"); break;
}
MessageManager::Log("File size: " + std::to_string(romData.size() / 1024) + " KB");
if(header.GetCartRamSize() > 0) {
string sizeString = header.GetCartRamSize() > 1024 ? std::to_string(header.GetCartRamSize() / 1024) + " KB" : std::to_string(header.GetCartRamSize()) + " bytes";
MessageManager::Log("Cart RAM size: " + sizeString + (header.HasBattery() ? " (with battery)" : ""));

View file

@ -293,6 +293,17 @@ void GbApu::Write(uint16_t addr, uint8_t value)
}
}
uint8_t GbApu::ReadCgbRegister(uint16_t addr)
{
switch(addr) {
case 0xFF76: return _square1->GetOutput() | (_square2->GetOutput() << 4);
case 0xFF77: return _noise->GetOutput() | (_wave->GetOutput() << 4);
}
//Should not be called
return 0;
}
template<typename T>
void GbApu::ProcessLengthEnableFlag(uint8_t value, T &length, bool &lengthEnabled, bool &enabled)
{

View file

@ -57,6 +57,8 @@ public:
uint8_t Read(uint16_t addr);
void Write(uint16_t addr, uint8_t value);
uint8_t ReadCgbRegister(uint16_t addr);
template<typename T> void ProcessLengthEnableFlag(uint8_t value, T& length, bool& lengthEnabled, bool& enabled);
void Serialize(Serializer& s) override;

View file

@ -60,10 +60,6 @@ void GbDmaController::Write(uint8_t value)
uint8_t GbDmaController::ReadCgb(uint16_t addr)
{
switch(addr) {
case 0xFF51: return _state.CgbDmaSource >> 8;
case 0xFF52: return _state.CgbDmaSource & 0xFF;
case 0xFF53: return _state.CgbDmaDest >> 8;
case 0xFF54: return _state.CgbDmaDest & 0xFF;
case 0xFF55: return _state.CgbDmaLength | (_state.CgbHdmaDone ? 0x80 : 0);
}

View file

@ -248,18 +248,28 @@ uint8_t GbMemoryManager::ReadRegister(uint16_t addr)
} else if(addr >= 0xFF4C) {
if(_gameboy->IsCgb()) {
switch(addr) {
//FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch
case 0xFF4D: return _state.CgbHighSpeed ? 0x80 : 0;
case 0xFF51: case 0xFF52: case 0xFF53: case 0xFF54: case 0xFF55: //CGB - DMA
return _dmaController->ReadCgb(addr);
case 0xFF55: //CGB - DMA
return _ppu->IsCgbEnabled() ? _dmaController->ReadCgb(addr) : 0xFF;
case 0xFF4F: //CGB - VRAM bank
case 0xFF68: case 0xFF69: case 0xFF6A: case 0xFF6B: //CGB - Palette
return _ppu->ReadCgbRegister(addr);
//FF70 - SVBK - CGB Mode Only - WRAM Bank
case 0xFF70: return _state.CgbWorkRamBank;
case 0xFF70: return _ppu->IsCgbEnabled() ? (_state.CgbWorkRamBank | 0xF8) : 0xFF;
case 0xFF72: return _state.CgbRegFF72;
case 0xFF73: return _state.CgbRegFF73;
case 0xFF74:
if(_ppu->IsCgbEnabled()) {
return _state.CgbRegFF74;
}
return 0xFF;
case 0xFF75: return _state.CgbRegFF75 | 0x8F;
case 0xFF76: case 0xFF77:
return _apu->ReadCgbRegister(addr);
}
}
LogDebug("[Debug] GB - Missing read handler: $" + HexUtilities::ToHex(addr));
@ -274,7 +284,7 @@ uint8_t GbMemoryManager::ReadRegister(uint16_t addr)
case 0xFF00: return ReadInputPort(); break;
case 0xFF01: return _state.SerialData; //SB - Serial transfer data (R/W)
case 0xFF02: return _state.SerialControl | ~(_gameboy->IsCgb() ? 0x83 : 0x81); //SC - Serial Transfer Control (R/W)
case 0xFF02: return _state.SerialControl | 0x7E; //SC - Serial Transfer Control (R/W)
case 0xFF04: case 0xFF05: case 0xFF06: case 0xFF07:
return _timer->Read(addr);
@ -313,11 +323,15 @@ void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value)
switch(addr) {
case 0xFF4D:
//FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch
_state.CgbSwitchSpeedRequest = (value & 0x01) != 0;
if(_ppu->IsCgbEnabled()) {
_state.CgbSwitchSpeedRequest = (value & 0x01) != 0;
}
break;
case 0xFF51: case 0xFF52: case 0xFF53: case 0xFF54: case 0xFF55: //CGB - DMA
_dmaController->WriteCgb(addr, value);
if(_ppu->IsCgbEnabled()) {
_dmaController->WriteCgb(addr, value);
}
break;
case 0xFF4C: //CGB - "LCDMODE", set by boot rom to turn off CGB features for the LCD for DMG games
@ -333,10 +347,22 @@ void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value)
case 0xFF70:
//FF70 - SVBK - CGB Mode Only - WRAM Bank
_state.CgbWorkRamBank = std::max(1, value & 0x07);
RefreshMappings();
if(_ppu->IsCgbEnabled()) {
_state.CgbWorkRamBank = std::max(1, value & 0x07);
RefreshMappings();
}
break;
case 0xFF72: _state.CgbRegFF72 = value; break;
case 0xFF73: _state.CgbRegFF73 = value; break;
case 0xFF74:
if(_ppu->IsCgbEnabled()) {
_state.CgbRegFF74 = value;
}
break;
case 0xFF75: _state.CgbRegFF75 = value; break;
default:
LogDebug("[Debug] GBC - Missing write handler: $" + HexUtilities::ToHex(addr));
break;
@ -417,6 +443,11 @@ bool GbMemoryManager::IsHighSpeed()
return _state.CgbHighSpeed;
}
bool GbMemoryManager::IsBootRomDisabled()
{
return _state.DisableBootRom;
}
uint64_t GbMemoryManager::GetCycleCount()
{
return _state.CycleCount;
@ -485,7 +516,8 @@ void GbMemoryManager::Serialize(Serializer& s)
s.Stream(
_state.DisableBootRom, _state.IrqEnabled, _state.IrqRequests, _state.InputSelect,
_state.ApuCycleCount, _state.CgbHighSpeed, _state.CgbSwitchSpeedRequest, _state.CgbWorkRamBank,
_state.SerialData, _state.SerialControl, _state.SerialBitCount, _state.CycleCount
_state.SerialData, _state.SerialControl, _state.SerialBitCount, _state.CycleCount,
_state.CgbRegFF72, _state.CgbRegFF73, _state.CgbRegFF74, _state.CgbRegFF75
);
s.StreamArray(_state.MemoryType, 0x100);
s.StreamArray(_state.MemoryOffset, 0x100);

View file

@ -70,6 +70,8 @@ public:
void ToggleSpeed();
bool IsHighSpeed();
bool IsBootRomDisabled();
uint64_t GetCycleCount();
uint64_t GetApuCycleCount();

View file

@ -609,6 +609,11 @@ bool GbPpu::IsLcdEnabled()
return _state.LcdEnabled;
}
bool GbPpu::IsCgbEnabled()
{
return _state.CgbEnabled;
}
PpuMode GbPpu::GetMode()
{
return _state.Mode;
@ -892,11 +897,15 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma)
uint8_t GbPpu::ReadCgbRegister(uint16_t addr)
{
if(!_state.CgbEnabled) {
return 0xFF;
}
switch(addr) {
case 0xFF4F: return _state.CgbVramBank;
case 0xFF68: return _state.CgbBgPalPosition | (_state.CgbBgPalAutoInc ? 0x80 : 0);
case 0xFF4F: return _state.CgbVramBank | 0xFE;
case 0xFF68: return _state.CgbBgPalPosition | (_state.CgbBgPalAutoInc ? 0x80 : 0) | 0x40;
case 0xFF69: return (_state.CgbBgPalettes[_state.CgbBgPalPosition >> 1] >> ((_state.CgbBgPalPosition & 0x01) ? 8 : 0) & 0xFF);
case 0xFF6A: return _state.CgbObjPalPosition | (_state.CgbObjPalAutoInc ? 0x80 : 0);
case 0xFF6A: return _state.CgbObjPalPosition | (_state.CgbObjPalAutoInc ? 0x80 : 0) | 0x40;
case 0xFF6B: return (_state.CgbObjPalettes[_state.CgbObjPalPosition >> 1] >> ((_state.CgbObjPalPosition & 0x01) ? 8 : 0) & 0xFF);
}
LogDebug("[Debug] GBC - Missing read handler: $" + HexUtilities::ToHex(addr));
@ -905,6 +914,10 @@ uint8_t GbPpu::ReadCgbRegister(uint16_t addr)
void GbPpu::WriteCgbRegister(uint16_t addr, uint8_t value)
{
if(!_state.CgbEnabled && _memoryManager->IsBootRomDisabled()) {
return;
}
switch(addr) {
case 0xFF4C: _state.CgbEnabled = (value & 0x0C) == 0; break;
case 0xFF4F: _state.CgbVramBank = value & 0x01; break;

View file

@ -87,6 +87,7 @@ public:
uint8_t GetScanline();
uint16_t GetCycle();
bool IsLcdEnabled();
bool IsCgbEnabled();
PpuMode GetMode();
void Exec();

View file

@ -353,6 +353,11 @@ struct GbMemoryManagerState
bool CgbSwitchSpeedRequest;
bool CgbHighSpeed;
uint8_t CgbRegFF72;
uint8_t CgbRegFF73;
uint8_t CgbRegFF74;
uint8_t CgbRegFF75;
bool DisableBootRom;
uint8_t IrqRequests;
uint8_t IrqEnabled;

View file

@ -632,6 +632,11 @@ namespace Mesen.GUI
[MarshalAs(UnmanagedType.I1)] public bool CgbSwitchSpeedRequest;
[MarshalAs(UnmanagedType.I1)] public bool CgbHighSpeed;
public byte CgbRegFF72;
public byte CgbRegFF73;
public byte CgbRegFF74;
public byte CgbRegFF75;
[MarshalAs(UnmanagedType.I1)] public bool DisableBootRom;
public byte IrqRequests;
public byte IrqEnabled;