Feature/agressive recompiler (#146)

* feat: added guestBranchKind enum to categorize branch types
feat: added missingFunctionPolicy enum to define behaviors for missing function scenarios
refactor: added handle guest branches and report missing functions
feat lookupFunction to utilize new dispatch logic and improve error handling for unregistered functions

* fix: fix test conflict

* feat: added debug sound driver logs

* feat: emmiter for return

* feat: added recompiler reporter
feat: added strict diagnostics flag for heavy debug calls

* feat: staticc table insted of hashmap for runtime

* feat: back file to ignore

* feat: explode code across helpers and classes

* feat: update codegen test
feat: better guest nop check

* feat: fix link problem on linux

* feat: fix Segmentation fault

* feat: added recompile replace for DMA and MMIO
feat: added a clean memory helpers
feat: use memory helpers across the project
feat: fix ucrt on msvc

* feat: undo messup merge
This commit is contained in:
Ranieri
2026-07-07 10:14:25 -03:00
committed by GitHub
parent 61621b8313
commit 52edf07657
24 changed files with 1756 additions and 70 deletions
+163
View File
@@ -113,6 +113,49 @@ namespace
return tag;
}
uint64_t makeGifTagPrim(uint16_t nloop, uint16_t prim, uint8_t flg, uint8_t nreg, bool eop = true, bool pre = true)
{
uint64_t tag = makeGifTag(nloop, flg, nreg, eop);
if (pre)
tag |= (1ull << 46);
tag |= (static_cast<uint64_t>(prim & 0x7FFu) << 47);
return tag;
}
uint64_t makeGsFrame(uint32_t fbp, uint32_t fbw, uint32_t psm, uint32_t mask = 0u)
{
return static_cast<uint64_t>(fbp & 0x1FFu) |
(static_cast<uint64_t>(fbw & 0x3Fu) << 16u) |
(static_cast<uint64_t>(psm & 0x3Fu) << 24u) |
(static_cast<uint64_t>(mask) << 32u);
}
uint64_t makeGsScissor(uint32_t x0, uint32_t x1, uint32_t y0, uint32_t y1)
{
return static_cast<uint64_t>(x0 & 0x7FFu) |
(static_cast<uint64_t>(x1 & 0x7FFu) << 16u) |
(static_cast<uint64_t>(y0 & 0x7FFu) << 32u) |
(static_cast<uint64_t>(y1 & 0x7FFu) << 48u);
}
void appendPackedRgbaq(std::vector<uint8_t> &packet, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
appendU64(packet, static_cast<uint64_t>(r) | (static_cast<uint64_t>(g) << 32u));
appendU64(packet, static_cast<uint64_t>(b) | (static_cast<uint64_t>(a) << 32u));
}
void appendPackedXyzf2(std::vector<uint8_t> &packet, uint32_t x, uint32_t y, uint32_t z)
{
appendU64(packet, static_cast<uint64_t>(x & 0xFFFFu) | (static_cast<uint64_t>(y & 0xFFFFu) << 32u));
appendU64(packet, static_cast<uint64_t>(z & 0xFFFFFFu) << 4u);
}
void appendPackedUv(std::vector<uint8_t> &packet, uint32_t u, uint32_t v)
{
appendU64(packet, static_cast<uint64_t>(u & 0x3FFFu) | (static_cast<uint64_t>(v & 0x3FFFu) << 32u));
appendU64(packet, 0u);
}
uint32_t makeVuLowerSpecial(uint8_t specialOp, uint8_t is, uint8_t it = 0u, uint8_t id = 0u, uint8_t dest = 0u)
{
return (0x40u << 25) |
@@ -970,6 +1013,126 @@ void register_ps2_memory_tests()
t.IsTrue(contentOk, "scratchpad alias chain payload should match scratchpad bytes");
});
tc.Run("native GIF image upload recognizes canonical load-image chain", [](TestCase &t)
{
PS2Memory mem;
t.IsTrue(mem.initialize(), "PS2Memory initialize should succeed");
GS gs;
gs.init(mem.getGSVRAM(), static_cast<uint32_t>(PS2_GS_VRAM_SIZE), &mem.gs());
constexpr uint32_t kGifCh = 0x1000A000u;
constexpr uint32_t kDStat = 0x1000E010u;
constexpr uint32_t kChain = 0x00028000u;
constexpr uint32_t kPixels = 0x00029000u;
constexpr uint32_t kQwc = 1u;
uint8_t *rdram = mem.getRDRAM();
for (uint32_t i = 0; i < kQwc * 16u; ++i)
{
rdram[kPixels + i] = static_cast<uint8_t>(0x40u + i);
}
uint32_t chain = kChain;
chain = writeTextureUploadSetup(rdram, chain, 0u, GS_PSM_CT32);
chain = writeTextureImageRef(rdram, chain, kQwc, kPixels);
writeDmaTag(rdram, chain, makeDmaTag(0u, 7u, 0u, false)); // END.
t.IsTrue(mem.writeIORegister(kGifCh + 0x30u, kChain), "write GIF TADR should succeed");
t.IsTrue(mem.tryProcessNativeGifImageUploadChain(gs, kChain, 0x105u),
"canonical load-image chain should use the native upload path");
t.Equals(gs.nativeImageUploadCount(), 1ull, "native GIF DMA chain should upload through GS fast path");
t.Equals(mem.gifCopyCount(), 1ull, "native GIF DMA chain should still count as a GIF DMA copy");
t.IsTrue((mem.readIORegister(kDStat) & (1u << 2u)) != 0u,
"native GIF DMA chain should raise D_STAT GIF completion");
t.Equals(mem.readIORegister(kGifCh + 0x20u), 0u, "native GIF DMA chain should clear GIF QWC");
t.Equals(mem.readIORegister(kGifCh + 0x00u) & 0x100u, 0u,
"native GIF DMA chain should clear GIF STR");
t.Equals(mem.readIORegister(kGifCh + 0x00u) & 0x70000000u, 0x70000000u,
"native GIF DMA chain should latch the terminal END tag id");
bool pixelsOk = true;
for (uint32_t x = 0; x < 4u && pixelsOk; ++x)
{
const uint32_t dstOff = GSPSMCT32::addrPSMCT32(0u, 1u, x, 0u);
const uint32_t srcOff = kPixels + x * 4u;
for (uint32_t c = 0; c < 4u; ++c)
{
if (mem.getGSVRAM()[dstOff + c] != rdram[srcOff + c])
{
pixelsOk = false;
break;
}
}
}
t.IsTrue(pixelsOk, "native GIF DMA chain should upload image payload into GS VRAM");
});
tc.Run("native GIF packed chain matches generic packed primitive packet", [](TestCase &t)
{
PS2Memory mem;
t.IsTrue(mem.initialize(), "PS2Memory initialize should succeed");
GS nativeGs;
nativeGs.init(mem.getGSVRAM(), static_cast<uint32_t>(PS2_GS_VRAM_SIZE), &mem.gs());
GSRegisters genericRegs{};
std::vector<uint8_t> genericVram(PS2_GS_VRAM_SIZE, 0u);
GS genericGs;
genericGs.init(genericVram.data(), static_cast<uint32_t>(genericVram.size()), &genericRegs);
std::vector<uint8_t> packet;
appendU64(packet, makeGifTag(4u, GIF_FMT_PACKED, 1u, false));
appendU64(packet, 0x0Eull);
appendU64(packet, makeGsFrame(0u, 1u, GS_PSM_CT32));
appendU64(packet, GS_REG_FRAME_1);
appendU64(packet, makeGsScissor(0u, 7u, 0u, 7u));
appendU64(packet, GS_REG_SCISSOR_1);
appendU64(packet, 1ull << 17u); // ZTST always.
appendU64(packet, GS_REG_TEST_1);
appendU64(packet, 1ull << 32u); // Mask Z writes so the test framebuffer remains visible.
appendU64(packet, GS_REG_ZBUF_1);
constexpr uint16_t kSpritePrim = static_cast<uint16_t>(GS_PRIM_SPRITE);
appendU64(packet, makeGifTagPrim(2u, kSpritePrim, GIF_FMT_PACKED, 3u, true, true));
appendU64(packet, static_cast<uint64_t>(GS_REG_UV) |
(static_cast<uint64_t>(GS_REG_RGBAQ) << 4u) |
(static_cast<uint64_t>(GS_REG_XYZF2) << 8u));
appendPackedUv(packet, 0u, 0u);
appendPackedRgbaq(packet, 0x20u, 0x40u, 0x80u, 0x80u);
appendPackedXyzf2(packet, 0u, 0u, 0u);
appendPackedUv(packet, 0u, 0u);
appendPackedRgbaq(packet, 0xE0u, 0x30u, 0x10u, 0x80u);
appendPackedXyzf2(packet, 64u, 64u, 0u);
genericGs.processGIFPacket(packet.data(), static_cast<uint32_t>(packet.size()));
constexpr uint32_t kGifCh = 0x1000A000u;
constexpr uint32_t kDStat = 0x1000E010u;
constexpr uint32_t kScratchTag = 0xF0000000u;
uint8_t *scratch = mem.getScratchpad();
writeDmaTag(scratch, 0u, makeDmaTag(static_cast<uint16_t>(packet.size() / 16u), 7u, 0u, false));
std::memcpy(scratch + 16u, packet.data(), packet.size());
t.IsTrue(mem.writeIORegister(kGifCh + 0x30u, kScratchTag), "write GIF TADR scratchpad alias should succeed");
t.IsTrue(mem.tryProcessNativeGifPackedChain(nativeGs, kScratchTag, 0x105u),
"packed primitive chain should use the native packed GIF path");
t.Equals(nativeGs.nativePackedGIFPacketCount(), 1ull, "native packed GIF packet counter should increment");
t.Equals(mem.gifCopyCount(), 1ull, "native packed GIF chain should still count as a GIF DMA copy");
t.IsTrue((mem.readIORegister(kDStat) & (1u << 2u)) != 0u,
"native packed GIF chain should raise D_STAT GIF completion");
t.Equals(mem.readIORegister(kGifCh + 0x20u), 0u, "native packed GIF chain should clear GIF QWC");
t.Equals(mem.readIORegister(kGifCh + 0x00u) & 0x100u, 0u,
"native packed GIF chain should clear GIF STR");
const uint32_t nativePixel = nativeGs.ReadVram(GS_PSM_CT32, 0u, 1u, 1u, 1u);
const uint32_t genericPixel = genericGs.ReadVram(GS_PSM_CT32, 0u, 1u, 1u, 1u);
t.IsTrue(genericPixel != 0u, "generic packed primitive packet should draw a test pixel");
t.Equals(nativePixel, genericPixel, "native packed GIF chain should match generic GS packet output");
});
tc.Run("GIF DMA chain REF keeps CT32 image data after paletted upload", [](TestCase &t)
{
PS2Memory mem;