Skip to content

Commit

Permalink
Improve port 3F accuracy
Browse files Browse the repository at this point in the history
  • Loading branch information
drhelius committed Dec 29, 2024
1 parent 66d4dc6 commit 7b5e7bd
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 170 deletions.
164 changes: 10 additions & 154 deletions src/GameGearIOPorts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
*/

#include "GameGearIOPorts.h"
#include "Audio.h"
#include "Video.h"
#include "Input.h"
#include "Cartridge.h"
#include "Memory.h"

GameGearIOPorts::GameGearIOPorts(Audio* pAudio, Video* pVideo, Input* pInput, Cartridge* pCartridge, Memory* pMemory)
{
Expand All @@ -31,8 +26,7 @@ GameGearIOPorts::GameGearIOPorts(Audio* pAudio, Video* pVideo, Input* pInput, Ca
m_pInput = pInput;
m_pCartridge = pCartridge;
m_pMemory = pMemory;
m_Port3F = 0;
m_Port3F_HC = 0;
Reset();
}

GameGearIOPorts::~GameGearIOPorts()
Expand All @@ -41,165 +35,27 @@ GameGearIOPorts::~GameGearIOPorts()

void GameGearIOPorts::Reset()
{
m_Port3F = 0;
m_Port3F_HC = 0;
m_Port2 = 0;
}

u8 GameGearIOPorts::DoInput(u8 port)
{
if (port < 0x07)
{
switch (port)
{
case 0x00:
{
u8 port00 = m_pInput->GetPort00();
if (m_pCartridge->GetZone() != Cartridge::CartridgeJapanGG)
port00 |= 0x40;
return port00;
}
case 0x01:
return 0x7F;
case 0x02:
return m_Port2;
case 0x03:
case 0x05:
return 0x00;
default:
return 0xFF;
}
}
else if (port < 0x40)
{
// Reads return $FF (GG)
Debug("--> ** Attempting to read from port $%X", port);
return 0xFF;
}
else if ((port >= 0x40) && (port < 0x80))
{
// Reads from even addresses return the V counter
// Reads from odd addresses return the H counter
if ((port & 0x01) == 0x00)
return m_pVideo->GetVCounter();
else
return m_pVideo->GetHCounter();
}
else if ((port >= 0x80) && (port < 0xC0))
{
// Reads from even addresses return the VDP data port contents
// Reads from odd address return the VDP status flags
if ((port & 0x01) == 0x00)
return m_pVideo->GetDataPort();
else
return m_pVideo->GetStatusFlags();
}
else
{
// Reads from $C0 and $DC return the I/O port A/B register.
// Reads from $C1 and $DD return the I/O port B/misc. register.
// The remaining locations return $FF.
switch (port)
{
case 0xC0:
case 0xDC:
{
return m_pInput->GetPortDC();
}
case 0xC1:
case 0xDD:
{
return ((m_pInput->GetPortDD() & 0x3F) | (m_Port3F & 0xC0));
}
default:
{
Debug("--> ** Attempting to read from port $%X", port);
return 0xFF;
}
}
}
}

void GameGearIOPorts::DoOutput(u8 port, u8 value)
{
if (port < 0x07)
{
if (port == 0x06)
{
// SN76489 PSG
m_pAudio->WriteGGStereoRegister(value);
}
else if (port == 0x02)
{
m_Port2 = value;
}
}
else if (port < 0x40)
{
// Writes to even addresses go to memory control register.
// Writes to odd addresses go to I/O control register.
if ((port & 0x01) == 0x00)
{
Debug("--> ** Output to memory control port $%X: %X", port, value);
m_pMemory->SetPort3E(value);
}
else
{
if (((value & 0x01) && !(m_Port3F_HC & 0x01)) || ((value & 0x08) && !(m_Port3F_HC & 0x08)))
m_pVideo->LatchHCounter();
m_Port3F_HC = value & 0x05;

m_Port3F = ((value & 0x80) | (value & 0x20) << 1) & 0xC0;
if (m_pCartridge->GetZone() == Cartridge::CartridgeJapanGG)
m_Port3F ^= 0xC0;
}
}
else if ((port >= 0x40) && (port < 0x80))
{
// Writes to any address go to the SN76489 PSG
m_pAudio->WriteAudioRegister(value);
}
else if ((port >= 0x80) && (port < 0xC0))
{
// Writes to even addresses go to the VDP data port.
// Writes to odd addresses go to the VDP control port.
if ((port & 0x01) == 0x00)
m_pVideo->WriteData(value);
else
m_pVideo->WriteControl(value);
}
#ifdef DEBUG_GEARSYSTEM
else
{
// Writes have no effect.
if ((port == 0xDE) || (port == 0xDF))
{
Debug("--> ** Output to keyboard port $%X: %X", port, value);
}
else if ((port == 0xF0) || (port == 0xF1) || (port == 0xF2))
{
Debug("--> ** Output to YM2413 port $%X: %X", port, value);
}
else
{
Debug("--> ** Output to port $%X: %X", port, value);
}
}
#endif
m_Port3F = 0xFF;
m_Ports[0] = 0xC0;
m_Ports[1] = 0x7F;
m_Ports[2] = 0xFF;
m_Ports[3] = 0x00;
m_Ports[4] = 0xFF;
m_Ports[5] = 0x00;
}

void GameGearIOPorts::SaveState(std::ostream& stream)
{
using namespace std;

stream.write(reinterpret_cast<const char*> (&m_Port3F), sizeof(m_Port3F));
stream.write(reinterpret_cast<const char*> (&m_Port3F_HC), sizeof(m_Port3F_HC));
stream.write(reinterpret_cast<const char*> (m_Ports), sizeof(m_Ports));
}

void GameGearIOPorts::LoadState(std::istream& stream)
{
using namespace std;

stream.read(reinterpret_cast<char*> (&m_Port3F), sizeof(m_Port3F));
stream.read(reinterpret_cast<char*> (&m_Port3F_HC), sizeof(m_Port3F_HC));
stream.read(reinterpret_cast<char*> (m_Ports), sizeof(m_Ports));
}
144 changes: 142 additions & 2 deletions src/GameGearIOPorts.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,155 @@ class GameGearIOPorts : public IOPorts
virtual void DoOutput(u8 port, u8 value);
virtual void SaveState(std::ostream& stream);
virtual void LoadState(std::istream& stream);

private:
Audio* m_pAudio;
Video* m_pVideo;
Input* m_pInput;
Memory* m_pMemory;
Cartridge* m_pCartridge;
u8 m_Port3F;
u8 m_Port3F_HC;
u8 m_Port2;
u8 m_Ports[6];
};

#include "Audio.h"
#include "Video.h"
#include "Input.h"
#include "Cartridge.h"
#include "Memory.h"

inline u8 GameGearIOPorts::DoInput(u8 port)
{
if (port < 0x07)
{
if (port == 0x00)
{
u8 start_button = m_pInput->GetPort00();
if (m_pCartridge->GetZone() != Cartridge::CartridgeJapanGG)
start_button |= 0x40;
return start_button;
}
else if (port < 6)
return m_Ports[port];
else
return 0xFF;
}
else if (port < 0x40)
{
// Reads return $FF (GG)
Debug("--> ** Attempting to read from port $%X", port);
return 0xFF;
}
else if (port < 0x80)
{
// Reads from even addresses return the V counter
if ((port & 0x01) == 0x00)
return m_pVideo->GetVCounter();
// Reads from odd addresses return the H counter
else
return m_pVideo->GetHCounter();
}
else if (port < 0xC0)
{
// Reads from even addresses return the VDP data port contents
if ((port & 0x01) == 0x00)
return m_pVideo->GetDataPort();
// Reads from odd address return the VDP status flags
else
return m_pVideo->GetStatusFlags();
}
else
{
switch (port)
{
// Reads from $C0 and $DC return the I/O port A/B register.
case 0xC0:
case 0xDC:
{
return m_pInput->GetPortDC();
}
// Reads from $C1 and $DD return the I/O port B/misc. register.
case 0xC1:
case 0xDD:
{
return ((m_pInput->GetPortDD() & 0x3F) | (m_Port3F & 0xC0));
}
// The remaining locations return $FF.
default:
{
Debug("--> ** Attempting to read from port $%X", port);
return 0xFF;
}
}
}
}

inline void GameGearIOPorts::DoOutput(u8 port, u8 value)
{
if (port < 0x07)
{
if (port == 0x06)
{
// SN76489 PSG
m_pAudio->WriteGGStereoRegister(value);
}
else if (port != 0x00)
{
m_Ports[port] = value;
}
}
else if (port < 0x40)
{
// Writes to even addresses go to memory control register.
if ((port & 0x01) == 0x00)
{
Debug("--> ** Output to memory control port $%X: %X", port, value);
m_pMemory->SetPort3E(value);
}
// Writes to odd addresses go to I/O control register.
else
{
bool th_changed_a = (value & 0x02) && (value & 0x20) && !(m_Port3F & 0x20);
bool th_changed_b = (value & 0x08) && (value & 0x80) && !(m_Port3F & 0x80);

if (th_changed_a || th_changed_b)
m_pVideo->LatchHCounter();

m_Port3F = value;
}
}
else if (port < 0x80)
{
// Writes to any address go to the SN76489 PSG
m_pAudio->WriteAudioRegister(value);
}
else if (port < 0xC0)
{
// Writes to even addresses go to the VDP data port.
if ((port & 0x01) == 0x00)
m_pVideo->WriteData(value);
// Writes to odd addresses go to the VDP control port.
else
m_pVideo->WriteControl(value);
}
#ifdef DEBUG_GEARSYSTEM
else
{
// Writes have no effect.
if ((port == 0xDE) || (port == 0xDF))
{
Debug("--> ** Output to keyboard port $%X: %X", port, value);
}
else if ((port == 0xF0) || (port == 0xF1) || (port == 0xF2))
{
Debug("--> ** Output to YM2413 port $%X: %X", port, value);
}
else
{
Debug("--> ** Output to port $%X: %X", port, value);
}
}
#endif
}

#endif /* GAMEGEARIOPORTS_H */
9 changes: 1 addition & 8 deletions src/Input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,7 @@ u8 Input::GetPortDD()

u8 Input::GetPort00()
{
if (m_bPhaser)
{
return 0x00;
}
else
{
return (IsSetBit(m_Joypad1, Key_Start) ? 0x80 : 0) & 0x80;
}
return (IsSetBit(m_Joypad1, Key_Start) ? 0x80 : 0) & 0x80;
}

u8 Input::GetGlassesRegistry()
Expand Down
2 changes: 1 addition & 1 deletion src/SmsIOPorts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SmsIOPorts::SmsIOPorts(Audio* pAudio, Video* pVideo, Input* pInput, Cartridge* p
m_pCartridge = pCartridge;
m_pMemory = pMemory;
m_pProcessor = pProcessor;
m_Port3F = 0xFF;
Reset();
}

SmsIOPorts::~SmsIOPorts()
Expand Down
Loading

0 comments on commit 7b5e7bd

Please sign in to comment.