mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-28 17:39:16 -04:00
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:
@@ -12,6 +12,7 @@
|
||||
#include <filesystem>
|
||||
#include <cctype>
|
||||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
@@ -750,6 +751,7 @@ namespace ps2recomp
|
||||
m_stubFunctions.clear();
|
||||
m_stubFunctionStarts.clear();
|
||||
m_stubHandlerBindingsByStart.clear();
|
||||
m_correctnessCriticalFunctionStarts.clear();
|
||||
|
||||
for (const auto &name : m_config.skipFunctions)
|
||||
{
|
||||
@@ -809,6 +811,7 @@ namespace ps2recomp
|
||||
m_symbols = m_elfParser->extractSymbols();
|
||||
m_sections = m_elfParser->getSections();
|
||||
m_relocations = m_elfParser->getRelocations();
|
||||
collectCorrectnessCriticalFunctionStarts();
|
||||
|
||||
if (m_functions.empty())
|
||||
{
|
||||
@@ -937,24 +940,81 @@ namespace ps2recomp
|
||||
|
||||
size_t processedCount = 0;
|
||||
size_t failedCount = 0;
|
||||
size_t correctnessCriticalFailureCount = 0;
|
||||
|
||||
for (uint32_t initializerStart : m_correctnessCriticalFunctionStarts)
|
||||
{
|
||||
const auto functionIt = std::find_if(
|
||||
m_functions.begin(), m_functions.end(),
|
||||
[initializerStart](const Function &function)
|
||||
{ return function.start == initializerStart; });
|
||||
if (functionIt == m_functions.end())
|
||||
{
|
||||
const auto bindingIt = m_stubHandlerBindingsByStart.find(initializerStart);
|
||||
if (bindingIt != m_stubHandlerBindingsByStart.end() &&
|
||||
resolveStubTarget(bindingIt->second) != StubTarget::Unknown)
|
||||
{
|
||||
Function manualInitializer{};
|
||||
manualInitializer.name = "manual_initializer_" + bindingIt->second;
|
||||
manualInitializer.start = initializerStart;
|
||||
manualInitializer.end = initializerStart + 4u;
|
||||
m_functions.push_back(std::move(manualInitializer));
|
||||
m_reporter.info(
|
||||
"correctness-critical",
|
||||
"Synthesized initializer entry for resolved handler '" +
|
||||
bindingIt->second + "'");
|
||||
continue;
|
||||
}
|
||||
|
||||
++correctnessCriticalFailureCount;
|
||||
m_reporter.recordCorrectnessCriticalFailure();
|
||||
m_reporter.errorAt(
|
||||
"correctness-critical",
|
||||
".ctors/.init_array",
|
||||
initializerStart,
|
||||
"Initializer table target has no discovered guest function or manual handler");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &function : m_functions)
|
||||
{
|
||||
m_reporter.recordFunctionProcessed();
|
||||
const bool correctnessCritical = isCorrectnessCriticalFunction(function);
|
||||
|
||||
if (isStubFunction(function))
|
||||
{
|
||||
function.isStub = true;
|
||||
function.isSkipped = false;
|
||||
m_reporter.recordFunctionStubbed();
|
||||
continue;
|
||||
if (!correctnessCritical || hasResolvedStubHandler(function))
|
||||
{
|
||||
function.isStub = true;
|
||||
function.isSkipped = false;
|
||||
m_reporter.recordFunctionStubbed();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_reporter.recordCorrectnessCriticalGuestFallback();
|
||||
m_reporter.warningAt(
|
||||
"correctness-critical",
|
||||
function.name,
|
||||
function.start,
|
||||
"Unresolved initializer stub ignored; recompiling the original guest function");
|
||||
}
|
||||
|
||||
if (shouldSkipFunction(function))
|
||||
{
|
||||
function.isSkipped = true;
|
||||
function.isStub = false;
|
||||
m_reporter.recordFunctionSkipped();
|
||||
continue;
|
||||
if (!correctnessCritical)
|
||||
{
|
||||
function.isSkipped = true;
|
||||
function.isStub = false;
|
||||
m_reporter.recordFunctionSkipped();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_reporter.recordCorrectnessCriticalGuestFallback();
|
||||
m_reporter.warningAt(
|
||||
"correctness-critical",
|
||||
function.name,
|
||||
function.start,
|
||||
"Initializer skip ignored; recompiling the original guest function");
|
||||
}
|
||||
|
||||
if (!decodeFunction(function))
|
||||
@@ -962,11 +1022,26 @@ namespace ps2recomp
|
||||
++failedCount;
|
||||
m_reporter.recordDecodeFailure();
|
||||
m_reporter.recordFunctionSkipped();
|
||||
m_reporter.warningAt("decode", function.name, function.start, "Skipping function due decode failure");
|
||||
function.isSkipped = true;
|
||||
if (correctnessCritical)
|
||||
{
|
||||
++correctnessCriticalFailureCount;
|
||||
m_reporter.recordCorrectnessCriticalFailure();
|
||||
m_reporter.errorAt(
|
||||
"correctness-critical",
|
||||
function.name,
|
||||
function.start,
|
||||
"Initializer could not be recompiled and has no resolved manual handler");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_reporter.warningAt("decode", function.name, function.start, "Skipping function due decode failure");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
function.isStub = false;
|
||||
function.isSkipped = false;
|
||||
function.isRecompiled = true;
|
||||
m_reporter.recordFunctionRecompiled();
|
||||
#if _DEBUG
|
||||
@@ -992,7 +1067,7 @@ namespace ps2recomp
|
||||
}
|
||||
|
||||
m_reporter.progress("recompilation pass completed");
|
||||
return true;
|
||||
return correctnessCriticalFailureCount == 0u;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -1964,6 +2039,64 @@ namespace ps2recomp
|
||||
return ps2_runtime_calls::isStubName(function.name);
|
||||
}
|
||||
|
||||
bool PS2Recompiler::IsCorrectnessCriticalFunctionName(const std::string &name)
|
||||
{
|
||||
static constexpr const char *kPrefixes[] = {
|
||||
"__ct__",
|
||||
"__sinit_",
|
||||
"_GLOBAL__sub_I_",
|
||||
"GLOBAL__sub_I_",
|
||||
"__static_initialization_and_destruction_0",
|
||||
"__do_global_ctors",
|
||||
};
|
||||
|
||||
for (const char *prefix : kPrefixes)
|
||||
{
|
||||
if (name.rfind(prefix, 0u) == 0u)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PS2Recompiler::isCorrectnessCriticalFunction(const Function &function) const
|
||||
{
|
||||
return IsCorrectnessCriticalFunctionName(function.name) ||
|
||||
m_correctnessCriticalFunctionStarts.contains(function.start);
|
||||
}
|
||||
|
||||
bool PS2Recompiler::hasResolvedStubHandler(const Function &function) const
|
||||
{
|
||||
std::string handlerName = function.name;
|
||||
const auto bindingIt = m_stubHandlerBindingsByStart.find(function.start);
|
||||
if (bindingIt != m_stubHandlerBindingsByStart.end() && !bindingIt->second.empty())
|
||||
handlerName = bindingIt->second;
|
||||
return resolveStubTarget(handlerName) != StubTarget::Unknown;
|
||||
}
|
||||
|
||||
void PS2Recompiler::collectCorrectnessCriticalFunctionStarts()
|
||||
{
|
||||
m_correctnessCriticalFunctionStarts.clear();
|
||||
for (const Section §ion : m_sections)
|
||||
{
|
||||
if (section.name != ".ctors" &&
|
||||
section.name != ".init_array" &&
|
||||
section.name != ".preinit_array")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (section.data == nullptr || section.size < sizeof(uint32_t))
|
||||
continue;
|
||||
|
||||
for (uint32_t offset = 0; offset + sizeof(uint32_t) <= section.size; offset += sizeof(uint32_t))
|
||||
{
|
||||
uint32_t target = 0u;
|
||||
std::memcpy(&target, section.data + offset, sizeof(target));
|
||||
if (target != 0u && target != 0xFFFFFFFFu)
|
||||
m_correctnessCriticalFunctionStarts.insert(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PS2Recompiler::writeToFile(const std::string &path, const std::string &content)
|
||||
{
|
||||
std::ofstream file(path);
|
||||
|
||||
@@ -113,6 +113,18 @@ namespace ps2recomp
|
||||
m_counters.generatedFunctions += count;
|
||||
}
|
||||
|
||||
void RecompilerReporter::recordCorrectnessCriticalGuestFallback()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
++m_counters.correctnessCriticalGuestFallbacks;
|
||||
}
|
||||
|
||||
void RecompilerReporter::recordCorrectnessCriticalFailure()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
++m_counters.correctnessCriticalFailures;
|
||||
}
|
||||
|
||||
void RecompilerReporter::recordIndirectFallbackPromotion(const std::string &functionName,
|
||||
const std::vector<uint32_t> &jumpAddresses,
|
||||
size_t promotedEntryCount)
|
||||
@@ -183,6 +195,8 @@ namespace ps2recomp
|
||||
os << "Indirect fallback promotions: " << m_counters.indirectFallbackPromotions
|
||||
<< " (" << m_counters.indirectFallbackEntries << " fallback entries)" << std::endl;
|
||||
os << "Unhandled instructions: " << m_counters.unhandledInstructions << std::endl;
|
||||
os << "Correctness-critical guest fallbacks: " << m_counters.correctnessCriticalGuestFallbacks
|
||||
<< ", failures: " << m_counters.correctnessCriticalFailures << std::endl;
|
||||
|
||||
size_t warnings = 0;
|
||||
size_t errors = 0;
|
||||
|
||||
@@ -209,8 +209,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], {})); "
|
||||
"__m128 res = PS2_VADD(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs, vft, vft, shuffle_pattern,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -230,8 +229,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], {})); "
|
||||
"__m128 res = PS2_VSUB(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs, vft, vft, shuffle_pattern,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -285,8 +283,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
|
||||
"__m128 res = PS2_VADD(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs, vft,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -301,8 +298,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_set1_ps(ctx->vu0_q)); "
|
||||
"__m128 res = PS2_VADD(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -317,8 +313,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_set1_ps(ctx->vu0_i)); "
|
||||
"__m128 res = PS2_VADD(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -402,12 +397,13 @@ namespace ps2recomp
|
||||
uint8_t vfs = inst.rd;
|
||||
uint8_t vft = inst.rt;
|
||||
uint8_t dest_mask = inst.vectorInfo.vectorField;
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
|
||||
return fmt::format("{{ __m128 fs_yzx = _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], _MM_SHUFFLE(3,0,2,1)); "
|
||||
"__m128 ft_zxy = _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], _MM_SHUFFLE(3,1,0,2)); "
|
||||
"__m128 mul_res = PS2_VMUL(fs_yzx, ft_zxy); "
|
||||
"__m128 res = PS2_VSUB(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
vfs, vft,
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs, vfs, vft, vft,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
vfd, vfd);
|
||||
@@ -450,8 +446,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); "
|
||||
"__m128 res = PS2_VSUB(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs, vft,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -509,8 +504,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_set1_ps(ctx->vu0_q)); "
|
||||
"__m128 res = PS2_VSUB(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -525,8 +519,7 @@ namespace ps2recomp
|
||||
return fmt::format("{{ __m128 mul_res = PS2_VMUL(ctx->vu0_vf[{}], _mm_set1_ps(ctx->vu0_i)); "
|
||||
"__m128 res = PS2_VSUB(ctx->vu0_acc, mul_res); "
|
||||
"__m128i mask = _mm_set_epi32({}, {}, {}, {}); "
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); "
|
||||
"ctx->vu0_acc = res; }}",
|
||||
"ctx->vu0_vf[{}] = _mm_blendv_ps(ctx->vu0_vf[{}], res, _mm_castsi128_ps(mask)); }}",
|
||||
vfs,
|
||||
(dest_mask & 0x1) ? -1 : 0, (dest_mask & 0x2) ? -1 : 0,
|
||||
(dest_mask & 0x4) ? -1 : 0, (dest_mask & 0x8) ? -1 : 0,
|
||||
@@ -730,8 +723,11 @@ namespace ps2recomp
|
||||
uint8_t vfs = inst.rd;
|
||||
uint8_t vft = inst.rt;
|
||||
uint8_t dest_mask = inst.vectorInfo.vectorField;
|
||||
return fmt::format("{{ __m128 res = PS2_VMUL(ctx->vu0_vf[{}], ctx->vu0_vf[{}]); ctx->vu0_acc = _mm_blendv_ps(ctx->vu0_acc, res, {}); }}",
|
||||
vfs, vft, codegen::vuMaskExpr(dest_mask));
|
||||
return fmt::format("{{ __m128 fs_yzx = _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], _MM_SHUFFLE(3,0,2,1)); "
|
||||
"__m128 ft_zxy = _mm_shuffle_ps(ctx->vu0_vf[{}], ctx->vu0_vf[{}], _MM_SHUFFLE(3,1,0,2)); "
|
||||
"__m128 res = PS2_VMUL(fs_yzx, ft_zxy); "
|
||||
"ctx->vu0_acc = _mm_blendv_ps(ctx->vu0_acc, res, {}); }}",
|
||||
vfs, vfs, vft, vft, codegen::vuMaskExpr(dest_mask));
|
||||
}
|
||||
|
||||
std::string CodeGenerator::translateVU_VITOF(const Instruction &inst, int shift)
|
||||
|
||||
@@ -29,124 +29,77 @@ namespace ps2recomp
|
||||
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_castps_si128(ctx->vu0_vf[{}]));", rt, rd);
|
||||
case COP2_CFC2:
|
||||
{
|
||||
switch (rd) // Control register number is in rd
|
||||
// CFC2/CTC2 use the same 5-bit register field for VI0..VI15 and the VU special control registers.
|
||||
if (rd < 16)
|
||||
{
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, static_cast<uint32_t>(ctx->vi[{}]));", rt, rd);
|
||||
}
|
||||
|
||||
switch (rd)
|
||||
{
|
||||
case VU0_CR_STATUS:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_status);", rt);
|
||||
case VU0_CR_MAC:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_mac_flags);", rt);
|
||||
case VU0_CR_VPU_STAT:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat);", rt);
|
||||
case VU0_CR_CLIP:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_clip_flags & 0x00FFFFFFu);", rt);
|
||||
case VU0_CR_R:
|
||||
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_castps_si128(ctx->vu0_r));", rt);
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, static_cast<uint32_t>(_mm_cvtsi128_si32(_mm_castps_si128(ctx->vu0_r))));", rt);
|
||||
case VU0_CR_I:
|
||||
return fmt::format("{{ uint32_t bits; std::memcpy(&bits, &ctx->vu0_i, sizeof(bits)); SET_GPR_U32(ctx, {}, bits); }}", rt);
|
||||
case VU0_CR_CLIP:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_clip_flags);", rt);
|
||||
case VU0_CR_Q:
|
||||
return fmt::format("{{ uint32_t bits; std::memcpy(&bits, &ctx->vu0_q, sizeof(bits)); SET_GPR_U32(ctx, {}, bits); }}", rt);
|
||||
case VU0_CR_TPC:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_tpc);", rt);
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_tpc >> 3);", rt);
|
||||
case VU0_CR_CMSAR0:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar0);", rt);
|
||||
case VU0_CR_FBRST:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst);", rt);
|
||||
case VU0_CR_VPU_STAT2:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat2);", rt);
|
||||
case VU0_CR_TPC2:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_tpc2);", rt);
|
||||
case VU0_CR_VPU_STAT:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat);", rt);
|
||||
case VU0_CR_CMSAR1:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar1);", rt);
|
||||
case VU0_CR_FBRST2:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst2);", rt);
|
||||
case VU0_CR_VPU_STAT3:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat3);", rt);
|
||||
case VU0_CR_CMSAR2:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar2);", rt);
|
||||
case VU0_CR_FBRST3:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst3);", rt);
|
||||
case VU0_CR_VPU_STAT4:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_vpu_stat4);", rt);
|
||||
case VU0_CR_CMSAR3:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_cmsar3);", rt);
|
||||
case VU0_CR_FBRST4:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_fbrst4);", rt);
|
||||
case VU0_CR_ACC:
|
||||
return fmt::format("SET_GPR_VEC(ctx, {}, _mm_castps_si128(ctx->vu0_acc));", rt);
|
||||
case VU0_CR_INFO: // I dd found on offical docs but ok
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_info);", rt);
|
||||
case VU0_CR_CLIP2:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_clip_flags2);", rt);
|
||||
case VU0_CR_P:
|
||||
return fmt::format("{{ uint32_t bits; std::memcpy(&bits, &ctx->vu0_p, sizeof(bits)); SET_GPR_U32(ctx, {}, bits); }}", rt);
|
||||
case VU0_CR_XITOP: // Maybe this does not exist, maybe we handle to vu0_itop
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_xitop);", rt);
|
||||
case VU0_CR_ITOP:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_itop);", rt);
|
||||
case VU0_CR_TOP:
|
||||
return fmt::format("SET_GPR_U32(ctx, {}, ctx->vu0_top);", rt);
|
||||
default:
|
||||
return fmt::format("// Unimplemented CFC2 VU CReg: {}", rt);
|
||||
return fmt::format("// Unimplemented CFC2 VU control register: {}", rd);
|
||||
}
|
||||
}
|
||||
case COP2_QMTC2:
|
||||
return fmt::format("ctx->vu0_vf[{}] = _mm_castsi128_ps(GPR_VEC(ctx, {}));", rd, rt);
|
||||
case COP2_CTC2:
|
||||
{
|
||||
switch (rd) // Control register number is in rd
|
||||
if (rd < 16)
|
||||
{
|
||||
if (rd == 0)
|
||||
{
|
||||
return "// CTC2 write to VI0 ignored";
|
||||
}
|
||||
return fmt::format("ctx->vi[{}] = static_cast<uint16_t>(GPR_U32(ctx, {}));", rd, rt);
|
||||
}
|
||||
|
||||
switch (rd)
|
||||
{
|
||||
case VU0_CR_STATUS:
|
||||
return fmt::format("ctx->vu0_status = GPR_U32(ctx, {}) & 0xFFFF;", rt);
|
||||
return fmt::format("ctx->vu0_status = static_cast<uint16_t>(GPR_U32(ctx, {}) & 0xFFFFu);", rt);
|
||||
case VU0_CR_MAC:
|
||||
return fmt::format("ctx->vu0_mac_flags = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_TPC:
|
||||
case VU0_CR_VPU_STAT:
|
||||
return fmt::format("ctx->vu0_vpu_stat = GPR_U32(ctx, {});", rt);
|
||||
return fmt::format("// CTC2 write to read-only VU control register {} ignored", rd);
|
||||
case VU0_CR_CLIP:
|
||||
return fmt::format("ctx->vu0_clip_flags = GPR_U32(ctx, {});", rt);
|
||||
return fmt::format("ctx->vu0_clip_flags = GPR_U32(ctx, {}) & 0x00FFFFFFu;", rt);
|
||||
case VU0_CR_R:
|
||||
return fmt::format("ctx->vu0_r = _mm_castsi128_ps(GPR_VEC(ctx, {}));", rt);
|
||||
return fmt::format("ctx->vu0_r = _mm_castsi128_ps(_mm_set1_epi32(static_cast<int32_t>(GPR_U32(ctx, {}))));", rt);
|
||||
case VU0_CR_I:
|
||||
return fmt::format("{{ uint32_t tmp = GPR_U32(ctx, {}); std::memcpy(&ctx->vu0_i, &tmp, sizeof(tmp)); }}", rt);
|
||||
case VU0_CR_TPC:
|
||||
return fmt::format("ctx->vu0_tpc = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_Q:
|
||||
return fmt::format("{{ uint32_t tmp = GPR_U32(ctx, {}); std::memcpy(&ctx->vu0_q, &tmp, sizeof(tmp)); }}", rt);
|
||||
case VU0_CR_CMSAR0:
|
||||
return fmt::format("ctx->vu0_cmsar0 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_FBRST:
|
||||
return fmt::format("ctx->vu0_fbrst = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_VPU_STAT2:
|
||||
return fmt::format("ctx->vu0_vpu_stat2 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_TPC2:
|
||||
return fmt::format("ctx->vu0_tpc2 = GPR_U32(ctx, {});", rt);
|
||||
return fmt::format("ctx->vu0_fbrst = GPR_U32(ctx, {}) & 0x00000C0Cu;", rt);
|
||||
case VU0_CR_CMSAR1:
|
||||
return fmt::format("ctx->vu0_cmsar1 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_FBRST2:
|
||||
return fmt::format("ctx->vu0_fbrst2 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_VPU_STAT3:
|
||||
return fmt::format("ctx->vu0_vpu_stat3 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_CMSAR2:
|
||||
return fmt::format("ctx->vu0_cmsar2 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_FBRST3:
|
||||
return fmt::format("ctx->vu0_fbrst3 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_VPU_STAT4:
|
||||
return fmt::format("ctx->vu0_vpu_stat4 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_CMSAR3:
|
||||
return fmt::format("ctx->vu0_cmsar3 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_FBRST4:
|
||||
return fmt::format("ctx->vu0_fbrst4 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_ACC:
|
||||
return fmt::format("ctx->vu0_acc = _mm_castsi128_ps(GPR_VEC(ctx, {}));", rt);
|
||||
case VU0_CR_INFO:
|
||||
return fmt::format("ctx->vu0_info = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_CLIP2:
|
||||
return fmt::format("ctx->vu0_clip_flags2 = GPR_U32(ctx, {});", rt);
|
||||
case VU0_CR_P:
|
||||
return fmt::format("{{ uint32_t tmp = GPR_U32(ctx, {}); std::memcpy(&ctx->vu0_p, &tmp, sizeof(tmp)); }}", rt);
|
||||
case VU0_CR_XITOP:
|
||||
return fmt::format("ctx->vu0_xitop = GPR_U32(ctx, {}) & 0x3FF;", rt);
|
||||
case VU0_CR_ITOP:
|
||||
return fmt::format("ctx->vu0_itop = GPR_U32(ctx, {}) & 0x3FF;", rt);
|
||||
case VU0_CR_TOP:
|
||||
return fmt::format("ctx->vu0_top = GPR_U32(ctx, {}) & 0x3FF;", rt);
|
||||
default:
|
||||
return fmt::format("// Unimplemented CTC2 VU CReg: {}", rd);
|
||||
return fmt::format("// Unimplemented CTC2 VU control register: {}", rd);
|
||||
}
|
||||
}
|
||||
case COP2_BC:
|
||||
|
||||
Reference in New Issue
Block a user