GPU: Decode GP1 command bits 29-31, only GP1(10h) ignores bits 30-31

Hardware shows GP1(40h..FFh) are not mirrors, fixes GameShark Sampler Disc
resetting the GPU per glyph. Unfortunately it also relies on I_STAT going
active before the exception triggers, which I'm not going to fix (at least
not at the moment) due to the performance impact.
This commit is contained in:
Stenzek committed 2026-11-07 13:26:23 +10:00
1 parent bb4e9ac5e6
commit da82096f22
2 files changed
+48 -22

No files matched your search

+40
View File
@@ -264,6 +264,46 @@ TEST_F(GPUFrontend, V2InternalRegisterQueries)
EXPECT_EQ(GPU::ReadRegister(0), 0u);
}
TEST_F(GPUFrontend, GP1HighCommandBitsAreDecoded)
{
constexpr u32 DISPLAY_DISABLE = 1u << 23;
GPU::WriteRegister(4, 0x03000000); // display on
for (const u32 v : {0x23000001u, 0x43000001u, 0x83000001u, 0xC3000001u})
{
GPU::WriteRegister(4, v);
EXPECT_EQ(GPU::ReadRegister(4) & DISPLAY_DISABLE, 0u) << std::hex << v;
}
// GameShark Sampler Disc writes this before every glyph, it must not reset.
GPU::WriteRegister(0, 0xE10006A5);
for (const u32 v : {0x40000000u, 0x80000000u, 0xC0000000u})
{
GPU::WriteRegister(4, v);
EXPECT_EQ(GPU::ReadRegister(4) & DISPLAY_DISABLE, 0u) << std::hex << v;
EXPECT_EQ(GPU::ReadRegister(4) & 0x7FFu, 0x6A5u) << std::hex << v;
}
GPU::WriteRegister(4, 0x03000001);
EXPECT_NE(GPU::ReadRegister(4) & DISPLAY_DISABLE, 0u);
}
TEST_F(GPUFrontend, GP1InfoIgnoresBits30And31)
{
GPU::WriteRegister(0, 0xE3001234);
GPU::WriteRegister(0, 0xE4005678);
for (const u32 v : {0x50000004u, 0x90000004u, 0xD0000004u})
{
GPU::WriteRegister(4, 0x10000003);
ASSERT_EQ(GPU::ReadRegister(0), 0x1234u);
GPU::WriteRegister(4, v);
EXPECT_EQ(GPU::ReadRegister(0), 0x5678u) << std::hex << v;
}
GPU::WriteRegister(4, 0x10000003);
GPU::WriteRegister(4, 0x30000004); // bit 29 is decoded: no read
EXPECT_EQ(GPU::ReadRegister(0), 0x1234u);
}
TEST_F(GPUFrontend, V2StatusReportsFieldAndUpperTextureAddress)
{
EXPECT_NE(GPU::ReadRegister(4) & (1u << 13), 0u);
+8 -22
View File
@@ -2007,7 +2007,7 @@ u32 GPU::ReadGPUREAD()
void GPU::WriteGP1(u32 value)
{
const u32 command = (value >> 24) & 0x3Fu;
const u32 command = value >> 24;
const u32 param = value & UINT32_C(0x00FFFFFF);
switch (command)
{
@@ -2163,30 +2163,16 @@ void GPU::WriteGP1(u32 value)
}
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
default:
{
HandleGetGPUInfoCommand(value);
// GP1(10h) ignores command bits 24-27 and 30-31, every other command decodes the full byte,
// so 40h..FFh are not mirrors of 00h..3Fh (measured on v0 and v2 GPUs).
if ((command & 0x30u) == 0x10u) [[likely]]
HandleGetGPUInfoCommand(value);
else
DEV_LOG("Unimplemented GP1 command 0x{:02X}", command);
}
break;
[[unlikely]] default:
ERROR_LOG("Unimplemented GP1 command 0x{:02X}", command);
break;
}
}