refactor: refactor VU1 (#191)

* feat: implement fix and changes based on dark cloud report
fix: fix GS AFAIL for RGB/alpha/Z, ZMSK
fix: fix VU1 flags mask and pipeline
fix: small VU1 cache fix
feat: __ct__, __sinit_ are not sillent stubs anymore

* feat: fix song JP pulling

* feat: sound update for lotR

* feat: prevent guest execution to be very slow

* fix: small gs size bug

* feat: refactor VU
fix: fix cliping and other issues on gs
fix: fix wrong vu0 register on recompiler

* fix fix ACC scheduler stall
feat: remove unused test
fix: .fix overflow e underflow on FMAC

* feat: small setting  for windows test
This commit is contained in:
Ranieri
2026-08-05 14:50:24 -03:00
committed by GitHub
parent 61300792a0
commit f49ca4edbc
34 changed files with 5506 additions and 1015 deletions
+188
View File
@@ -155,6 +155,102 @@ static bool writeMinimalMipsElfWithJalFallbackTarget(const std::filesystem::path
return writer.save(elfPath.string());
}
static bool writeMinimalMipsElfWithInitializer(const std::filesystem::path &elfPath,
const std::string &functionName,
uint32_t initializerTarget)
{
ELFIO::elfio writer;
writer.create(ELFIO::ELFCLASS32, ELFIO::ELFDATA2LSB);
writer.set_os_abi(ELFIO::ELFOSABI_NONE);
writer.set_type(ELFIO::ET_EXEC);
writer.set_machine(ELFIO::EM_MIPS);
writer.set_entry(0x00100000u);
ELFIO::section *text = writer.sections.add(".text");
text->set_type(ELFIO::SHT_PROGBITS);
text->set_flags(ELFIO::SHF_ALLOC | ELFIO::SHF_EXECINSTR);
text->set_addr_align(4);
text->set_address(0x00100000u);
const std::array<uint32_t, 2> textWords = {
0x03E00008u, // jr $ra
0x00000000u, // nop
};
text->set_data(reinterpret_cast<const char *>(textWords.data()),
static_cast<ELFIO::Elf_Word>(textWords.size() * sizeof(uint32_t)));
ELFIO::section *ctors = writer.sections.add(".ctors");
ctors->set_type(ELFIO::SHT_PROGBITS);
ctors->set_flags(ELFIO::SHF_ALLOC | ELFIO::SHF_WRITE);
ctors->set_addr_align(4);
ctors->set_address(0x00200000u);
ctors->set_data(reinterpret_cast<const char *>(&initializerTarget),
static_cast<ELFIO::Elf_Word>(sizeof(initializerTarget)));
ELFIO::section *strtab = writer.sections.add(".strtab");
strtab->set_type(ELFIO::SHT_STRTAB);
strtab->set_addr_align(1);
ELFIO::section *symtab = writer.sections.add(".symtab");
symtab->set_type(ELFIO::SHT_SYMTAB);
symtab->set_info(1);
symtab->set_link(strtab->get_index());
symtab->set_addr_align(4);
symtab->set_entry_size(writer.get_default_entry_size(ELFIO::SHT_SYMTAB));
ELFIO::symbol_section_accessor symbols(writer, symtab);
ELFIO::string_section_accessor strings(strtab);
symbols.add_symbol(strings, "", 0, 0,
ELFIO::STB_LOCAL, ELFIO::STT_NOTYPE, 0, ELFIO::SHN_UNDEF);
symbols.add_symbol(strings, functionName.c_str(), text->get_address(), text->get_size(),
ELFIO::STB_GLOBAL, ELFIO::STT_FUNC, 0, text->get_index());
ELFIO::segment *textSegment = writer.segments.add();
textSegment->set_type(ELFIO::PT_LOAD);
textSegment->set_flags(ELFIO::PF_R | ELFIO::PF_X);
textSegment->set_align(0x1000);
textSegment->add_section_index(text->get_index(), text->get_addr_align());
ELFIO::segment *dataSegment = writer.segments.add();
dataSegment->set_type(ELFIO::PT_LOAD);
dataSegment->set_flags(ELFIO::PF_R | ELFIO::PF_W);
dataSegment->set_align(0x1000);
dataSegment->add_section_index(ctors->get_index(), ctors->get_addr_align());
return writer.save(elfPath.string());
}
static bool writeRecompilerTestConfig(const std::filesystem::path &configPath,
const std::filesystem::path &elfPath,
const std::filesystem::path &outputPath,
const std::vector<std::string> &skip,
const std::vector<std::string> &stubs = {})
{
std::ofstream config(configPath);
if (!config)
return false;
config << "[general]\n";
config << "input = \"" << elfPath.generic_string() << "\"\n";
config << "output = \"" << outputPath.generic_string() << "\"\n";
config << "skip = [";
for (size_t i = 0; i < skip.size(); ++i)
{
if (i != 0u)
config << ", ";
config << '"' << skip[i] << '"';
}
config << "]\n";
config << "stubs = [";
for (size_t i = 0; i < stubs.size(); ++i)
{
if (i != 0u)
config << ", ";
config << '"' << stubs[i] << '"';
}
config << "]\n";
return static_cast<bool>(config);
}
void register_ps2_recompiler_tests()
{
MiniTest::Case("PS2Recompiler", [](TestCase &tc)
@@ -890,6 +986,98 @@ void register_ps2_recompiler_tests()
"__sbprintf should be left for recompilation");
});
tc.Run("initializer skips fall back to guest recompilation", [](TestCase &t) {
const std::string uniqueSuffix =
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count());
const std::filesystem::path tempRoot =
std::filesystem::temp_directory_path() / ("ps2recomp-initializer-" + uniqueSuffix);
const std::filesystem::path elfPath = tempRoot / "initializer.elf";
const std::filesystem::path configPath = tempRoot / "initializer.toml";
const std::filesystem::path outputPath = tempRoot / "output";
std::filesystem::create_directories(tempRoot);
const bool elfWritten =
writeMinimalMipsElfWithInitializer(elfPath, "__sinit_test.cpp", 0x00100000u);
const bool configWritten =
writeRecompilerTestConfig(configPath, elfPath, outputPath, {"__sinit_test.cpp"});
t.IsTrue(elfWritten && configWritten,
"initializer regression inputs should be generated");
if (elfWritten && configWritten)
{
PS2Recompiler recompiler(configPath.string());
t.IsTrue(recompiler.initialize(),
"initializer regression config should initialize");
t.IsTrue(recompiler.recompile(),
"a decodable skipped initializer should use guest fallback");
const RecompilerReporter::Counters &counters = recompiler.reportCounters();
t.Equals(counters.correctnessCriticalGuestFallbacks, static_cast<size_t>(1u),
"the ignored initializer skip should be reported");
t.Equals(counters.correctnessCriticalFailures, static_cast<size_t>(0u),
"guest fallback should avoid a correctness-critical failure");
t.Equals(counters.functionsSkipped, static_cast<size_t>(0u),
"the initializer should not remain skipped");
t.Equals(counters.functionsRecompiled, static_cast<size_t>(1u),
"the original initializer body should be recompiled");
}
std::error_code removeError;
std::filesystem::remove_all(tempRoot, removeError);
});
tc.Run("missing constructor-table targets fail recompilation", [](TestCase &t) {
const std::string uniqueSuffix =
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count());
const std::filesystem::path tempRoot =
std::filesystem::temp_directory_path() / ("ps2recomp-missing-initializer-" + uniqueSuffix);
const std::filesystem::path elfPath = tempRoot / "initializer.elf";
const std::filesystem::path configPath = tempRoot / "initializer.toml";
const std::filesystem::path outputPath = tempRoot / "output";
std::filesystem::create_directories(tempRoot);
const bool elfWritten =
writeMinimalMipsElfWithInitializer(elfPath, "ordinary_entry", 0x00100040u);
const bool configWritten =
writeRecompilerTestConfig(configPath, elfPath, outputPath, {});
t.IsTrue(elfWritten && configWritten,
"missing-initializer regression inputs should be generated");
if (elfWritten && configWritten)
{
{
PS2Recompiler recompiler(configPath.string());
t.IsTrue(recompiler.initialize(),
"missing-initializer regression config should initialize");
t.IsFalse(recompiler.recompile(),
"an unresolved .ctors target should be correctness-fatal");
t.Equals(recompiler.reportCounters().correctnessCriticalFailures,
static_cast<size_t>(1u),
"the unresolved constructor target should appear in the report");
}
const bool overrideWritten =
writeRecompilerTestConfig(
configPath, elfPath, outputPath, {},
{"memclr@0x00100040"});
t.IsTrue(overrideWritten,
"manual initializer override config should be generated");
if (overrideWritten)
{
PS2Recompiler overridden(configPath.string());
t.IsTrue(overridden.initialize(),
"manual initializer override should initialize");
t.IsTrue(overridden.recompile(),
"a resolved address-bound handler should satisfy the constructor target");
t.Equals(overridden.reportCounters().functionsStubbed,
static_cast<size_t>(1u),
"the resolved manual initializer should be emitted as a stub binding");
}
}
std::error_code removeError;
std::filesystem::remove_all(tempRoot, removeError);
});
tc.Run("respect max length for .cpp filenames", [](TestCase& t) {
t.IsTrue(PS2Recompiler::ClampFilenameLength("ReallyLongFunctionNameReallyLongFunctionNameReallyLongFunctionName_0x12345678",".cpp",50).length() <= 50,"Function name must be max 50 characters");