Feature/iop emulator (#244)

* refactor: from guest  threads to EE scheduler

* feat: bad wip mpeg fix for code veronica

* feat: cheap copy from host
feat: small perf o vsync tick

* feat: added EE clock Hz
fix: fix MPEG out of sync with new EE refactor

* fix: fix lotr tests

* fix: fix cri dtx loading
fix: fix wrong mmi instruction translation
fix: fix thread info params
feat: added EE  timers decoder and consumer
feat: split SFI and IOP memory to prevent collision and overrides

* feat: revert wrong changes

* refactor: change GS architecture

* feat: IOP emulator
refactor: codegen to catch callbacks on mips code
feat: added a lot of entries or IOP emulator

* feat: analyzer resolve the complete constant-producing sequence with five-instruction backward scan stopped at LUI and therefore

* feat: remove recompiled version of GetRomName
refactor: split IOP emulator logic
feat: added more HLE IOP modules
feat: added ps2_path

* eat: enhance ELF parser with improved callable entry detection and control flow analysis

* feat: update memory hint handling and enhance entry point discovery logic

* feat: add SET_GPR_ZE32 macro for zero-extending loads with unsigned semantics

* refactor: Refactor PS2 IOP Host Adapter and Memory Management
feat: Added PS2Vfs for virtual file system operations, including file opening, reading, writing, and path resolution.
feat: Improve VIF1 data processing to handle GIF image packets more efficiently.

* feat: added a lot of tests

* fix: fix texture caching
feat: wip multi version on dbcman

* feat: remove LLE IOPs
This commit is contained in:
Ranieri
2026-09-19 21:31:44 -03:00
committed by GitHub
parent 14b1e5cb39
commit 75d729ce40
139 changed files with 15625 additions and 9178 deletions
@@ -0,0 +1,99 @@
#include "gs_test_support.h"
#include "runtime/gs/ps2_gs_memory.h"
using namespace GSTest;
namespace
{
template<uint8_t Psm>
void addressCoverage()
{
BackendFixture f;
GSMem::TexturePageCache cache;
uint32_t random = 0x51375A9Du;
for (auto& byte : f.vram)
{
random ^= random << 13;
random ^= random >> 17;
random ^= random << 5;
byte = static_cast<uint8_t>(random);
}
constexpr auto mode = static_cast<GSMem::PixelStorageMode>(Psm);
constexpr auto extent = GSMem::PixelStorageTraits<mode>::PageExtent();
uint32_t checked = 0;
const auto check = [&](uint32_t base, uint32_t bw, uint32_t x, uint32_t y)
{
const auto direct = f.backend.ReadVram(Psm, base, bw, x, y);
const auto cached = GSMem::ReadTexture(cache, f.vram.data(), Psm, base, bw, x, y);
if (cached != direct)
{
std::ostringstream error;
error << "PSM=" << unsigned(Psm) << " BP=" << base << " BW=" << bw << " XY=" << x << ',' << y;
expectEqual(cached, direct, error.str());
}
++checked;
};
// Every local texel, for every 256-byte base offset inside an 8 KiB page.
for (uint32_t offset = 0; offset < 32; ++offset)
for (uint32_t y = 0; y < extent.y; ++y)
for (uint32_t x = 0; x < extent.x; ++x)
check(32 + offset, 2, x, y);
for (uint32_t base : {0u, 31u, 32u, 12160u, 16256u, 16383u})
for (uint32_t bw : {0u, 1u, 2u, 3u, 7u, 8u, 10u, 63u})
for (uint32_t y : {0u, 1u, 7u, 8u, 15u, 16u, 31u, 32u, 63u, 64u, 127u, 128u, 255u, 256u, 511u, 512u, 1023u, 2047u})
for (uint32_t x : {0u, 1u, 7u, 8u, 15u, 16u, 31u, 32u, 63u, 64u, 127u, 128u, 255u, 256u, 511u, 512u, 1023u, 2047u})
check(base, bw, x, y);
std::cout << checked << " cached/direct comparisons\n";
}
void aliasLanes()
{
BackendFixture f;
GSMem::TexturePageCache cache;
constexpr uint32_t base = 31;
const auto read = [&](uint32_t psm)
{
return GSMem::ReadTexture(cache, f.vram.data(), psm, base, 2, 8, 0);
};
f.backend.WriteVram(GS_PSM_CT32, base, 2, 8, 0, 0xAB123456);
expectEqual(read(GS_PSM_T8H), 0xAB, "8H lane on a crossing page");
f.backend.WriteVram(GS_PSM_CT24, base, 2, 8, 0, 0x654321);
expectEqual(read(GS_PSM_CT32), 0xAB123456, "changing PSM does not refresh the physical page");
cache.Invalidate();
expectEqual(read(GS_PSM_CT32), 0xAB654321, "CT24 upload preserves alpha");
f.backend.WriteVram(GS_PSM_T4HL, base, 2, 8, 0, 5);
expectEqual(read(GS_PSM_T4HL), 11, "low nibble remains cached before flush");
cache.Invalidate();
expectEqual(read(GS_PSM_T4HL), 5, "low nibble after flush");
expectEqual(read(GS_PSM_T4HH), 10, "high nibble preserved");
expectEqual(read(GS_PSM_CT24), 0x654321, "RGB plane preserved");
}
void physicalTagAliases()
{
BackendFixture f;
GSMem::TexturePageCache cache;
f.backend.WriteVram(GS_PSM_CT32, 32, 2, 0, 0, kRed);
expectEqual(GSMem::ReadTexture(cache, f.vram.data(), GS_PSM_CT32, 32, 2, 0, 0), kRed, "prime aligned view");
f.backend.WriteVram(GS_PSM_CT32, 32, 2, 0, 0, kGreen);
// Both descriptors resolve to the very same physical byte, so this is a hit.
expectEqual(GSMem::ReadTexture(cache, f.vram.data(), GS_PSM_CT32, 31, 2, 8, 0), kRed, "alias descriptor keeps the same cached bytes");
cache.Invalidate();
expectEqual(GSMem::ReadTexture(cache, f.vram.data(), GS_PSM_CT32, 31, 2, 8, 0), kGreen, "alias after flush");
}
}
int main(int argc, char** argv)
{
return run(argc, argv, {
{"ct32", addressCoverage<GS_PSM_CT32>}, {"ct24", addressCoverage<GS_PSM_CT24>},
{"ct16", addressCoverage<GS_PSM_CT16>}, {"ct16s", addressCoverage<GS_PSM_CT16S>},
{"t8", addressCoverage<GS_PSM_T8>}, {"t4", addressCoverage<GS_PSM_T4>},
{"t8h", addressCoverage<GS_PSM_T8H>}, {"t4hl", addressCoverage<GS_PSM_T4HL>},
{"t4hh", addressCoverage<GS_PSM_T4HH>}, {"z32", addressCoverage<GS_PSM_Z32>},
{"z24", addressCoverage<GS_PSM_Z24>}, {"z16", addressCoverage<GS_PSM_Z16>},
{"z16s", addressCoverage<GS_PSM_Z16S>}, {"alias_lanes", aliasLanes},
{"physical_tag_aliases", physicalTagAliases}
});
}