GBC: Improved IO port behavior
Fixes unused_hwio-C test, and allows aevilia to run
This commit is contained in:
parent
a15b22a05a
commit
a22302134d
10 changed files with 92 additions and 19 deletions
|
@ -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)" : ""));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
|
||||
void ToggleSpeed();
|
||||
bool IsHighSpeed();
|
||||
bool IsBootRomDisabled();
|
||||
|
||||
uint64_t GetCycleCount();
|
||||
uint64_t GetApuCycleCount();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
uint8_t GetScanline();
|
||||
uint16_t GetCycle();
|
||||
bool IsLcdEnabled();
|
||||
bool IsCgbEnabled();
|
||||
PpuMode GetMode();
|
||||
|
||||
void Exec();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue