mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 12:05:23 +00:00
PPU: restore previous NJ mode handling option
Fix the divergence between PPU Interpreter and LLVM.
This commit is contained in:
parent
1c0b3fc7e0
commit
e9efa73eed
8 changed files with 69 additions and 49 deletions
|
@ -54,6 +54,7 @@ enum class ppu_exec_bit : u64
|
|||
has_rc,
|
||||
set_sat,
|
||||
use_nj,
|
||||
fix_nj,
|
||||
set_vnan,
|
||||
fix_vnan,
|
||||
set_fpcc,
|
||||
|
@ -73,7 +74,7 @@ struct ppu_exec_select
|
|||
static ppu_intrp_func_t select(bs_t<ppu_exec_bit> selected, F func)
|
||||
{
|
||||
// Make sure there is no flag duplication, otherwise skip flag
|
||||
if constexpr (((Flags0 != Flag) && ...))
|
||||
if constexpr (((Flags0 != Flag) && ...) && (Flag != fix_vnan || ((Flags0 != set_vnan) && ...)) && (Flag != fix_nj || ((Flags0 != use_nj) && ...)))
|
||||
{
|
||||
// Test only relevant flags at runtime initialization (compile both variants)
|
||||
if (selected & Flag)
|
||||
|
@ -766,10 +767,10 @@ inline v128 ppu_select_vnan(v128 a, v128 b, Vector128 auto... args)
|
|||
}
|
||||
|
||||
// Flush denormals to zero if NJ is 1
|
||||
template <ppu_exec_bit... Flags>
|
||||
template <bool Result = false, ppu_exec_bit... Flags>
|
||||
inline v128 ppu_flush_denormal(const v128& mask, const v128& a)
|
||||
{
|
||||
if constexpr (((Flags == use_nj) || ...))
|
||||
if constexpr (((Flags == use_nj) || ...) || (Result && ((Flags == fix_nj) || ...)))
|
||||
{
|
||||
return gv_andn(gv_shr32(gv_eq32(mask & a, gv_bcst32(0)), 1), a);
|
||||
}
|
||||
|
@ -826,14 +827,14 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto MTVSCR()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<set_sat, use_nj>();
|
||||
return ppu_exec_select<Flags...>::template select<set_sat, use_nj, fix_nj>();
|
||||
|
||||
static const auto exec = [](auto&& sat, auto&& nj, auto&& jm_mask, auto&& b)
|
||||
{
|
||||
const u32 vscr = b._u32[3];
|
||||
if constexpr (((Flags == set_sat) || ...))
|
||||
sat._u = vscr & 1;
|
||||
if constexpr (((Flags == use_nj) || ...))
|
||||
if constexpr (((Flags == use_nj || Flags == fix_nj) || ...))
|
||||
jm_mask = (vscr & 0x10000) ? 0x7f80'0000 : 0x7fff'ffff;
|
||||
nj = (vscr & 0x10000) != 0;
|
||||
};
|
||||
|
@ -860,14 +861,14 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VADDFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](auto&& d, auto&& a_, auto&& b_, auto&& jm_mask)
|
||||
{
|
||||
const auto m = gv_bcst32(jm_mask, &ppu_thread::jm_mask);
|
||||
const auto a = ppu_flush_denormal<Flags...>(m, a_);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, b_);
|
||||
d = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(gv_addfs(a, b), a, b));
|
||||
const auto a = ppu_flush_denormal<false, Flags...>(m, a_);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, b_);
|
||||
d = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(gv_addfs(a, b), a, b));
|
||||
};
|
||||
|
||||
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
||||
|
@ -1508,15 +1509,15 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VMADDFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](auto&& d, auto&& a_, auto&& b_, auto&& c_, auto&& jm_mask)
|
||||
{
|
||||
const auto m = gv_bcst32(jm_mask, &ppu_thread::jm_mask);
|
||||
const auto a = ppu_flush_denormal<Flags...>(m, a_);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, b_);
|
||||
const auto c = ppu_flush_denormal<Flags...>(m, c_);
|
||||
d = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(gv_fmafs(a, c, b)));
|
||||
const auto a = ppu_flush_denormal<false, Flags...>(m, a_);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, b_);
|
||||
const auto c = ppu_flush_denormal<false, Flags...>(m, c_);
|
||||
d = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(gv_fmafs(a, c, b)));
|
||||
};
|
||||
|
||||
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.jm_mask);
|
||||
|
@ -1526,11 +1527,11 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VMAXFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& jm_mask)
|
||||
{
|
||||
d = ppu_flush_denormal<Flags...>(gv_bcst32(jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(gv_maxfs(a, b), a, b));
|
||||
d = ppu_flush_denormal<true, Flags...>(gv_bcst32(jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(gv_maxfs(a, b), a, b));
|
||||
};
|
||||
|
||||
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
||||
|
@ -1673,11 +1674,11 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VMINFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& jm_mask)
|
||||
{
|
||||
d = ppu_flush_denormal<Flags...>(gv_bcst32(jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(gv_minfs(a, b), a, b));
|
||||
d = ppu_flush_denormal<true, Flags...>(gv_bcst32(jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(gv_minfs(a, b), a, b));
|
||||
};
|
||||
|
||||
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
||||
|
@ -2087,17 +2088,17 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VNMSUBFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
// An odd case with (FLT_MIN, FLT_MIN, FLT_MIN) produces FLT_MIN instead of 0
|
||||
const auto s = _mm_set1_ps(-0.0f);
|
||||
const auto m = gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask);
|
||||
const auto a = ppu_flush_denormal<Flags...>(m, ppu.vr[op.va]);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto c = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vc]);
|
||||
const auto a = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.va]);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto c = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vc]);
|
||||
const auto r = _mm_xor_ps(gv_fmafs(a, c, _mm_xor_ps(b, s)), s);
|
||||
ppu.vr[op.rd] = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(r));
|
||||
ppu.vr[op.rd] = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(r));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2315,14 +2316,14 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VREFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto a = _mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const auto m = gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto result = _mm_div_ps(a, b);
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(result, a, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(result, a, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2331,11 +2332,11 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VRFIM()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto m = gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vb]);
|
||||
v128 d;
|
||||
|
||||
for (uint w = 0; w < 4; w++)
|
||||
|
@ -2343,7 +2344,7 @@ auto VRFIM()
|
|||
d._f[w] = std::floor(b._f[w]);
|
||||
}
|
||||
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(d, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(d, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2352,7 +2353,7 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VRFIN()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto b = ppu.vr[op.vb];
|
||||
|
@ -2363,7 +2364,7 @@ auto VRFIN()
|
|||
d._f[w] = std::nearbyint(b._f[w]);
|
||||
}
|
||||
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(d, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(d, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2372,11 +2373,11 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VRFIP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto m = gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vb]);
|
||||
v128 d;
|
||||
|
||||
for (uint w = 0; w < 4; w++)
|
||||
|
@ -2384,7 +2385,7 @@ auto VRFIP()
|
|||
d._f[w] = std::ceil(b._f[w]);
|
||||
}
|
||||
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(d, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(d, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2393,7 +2394,7 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VRFIZ()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto b = ppu.vr[op.vb];
|
||||
|
@ -2404,7 +2405,7 @@ auto VRFIZ()
|
|||
d._f[w] = std::truncf(b._f[w]);
|
||||
}
|
||||
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(d, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask), ppu_set_vnan<Flags...>(d, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2470,14 +2471,14 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VRSQRTEFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto a = _mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const auto m = gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto result = _mm_div_ps(a, _mm_sqrt_ps(b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(result, a, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(result, a, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -2905,14 +2906,14 @@ template <u32 Build, ppu_exec_bit... Flags>
|
|||
auto VSUBFP()
|
||||
{
|
||||
if constexpr (Build == 0xf1a6)
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, set_vnan, fix_vnan>();
|
||||
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
||||
|
||||
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
|
||||
const auto m = gv_bcst32(ppu.jm_mask, &ppu_thread::jm_mask);
|
||||
const auto a = ppu_flush_denormal<Flags...>(m, ppu.vr[op.va]);
|
||||
const auto b = ppu_flush_denormal<Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto a = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.va]);
|
||||
const auto b = ppu_flush_denormal<false, Flags...>(m, ppu.vr[op.vb]);
|
||||
const auto r = gv_subfs(a, b);
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<Flags...>(m, ppu_set_vnan<Flags...>(r, a, b));
|
||||
ppu.vr[op.vd] = ppu_flush_denormal<true, Flags...>(m, ppu_set_vnan<Flags...>(r, a, b));
|
||||
};
|
||||
RETURN_(ppu, op);
|
||||
}
|
||||
|
@ -7583,6 +7584,8 @@ ppu_interpreter_rt_base::ppu_interpreter_rt_base() noexcept
|
|||
selected += set_sat;
|
||||
if (g_cfg.core.ppu_use_nj_bit)
|
||||
selected += use_nj;
|
||||
if (g_cfg.core.ppu_llvm_nj_fixup)
|
||||
selected += fix_nj;
|
||||
if (g_cfg.core.ppu_set_vnan)
|
||||
selected += set_vnan;
|
||||
if (g_cfg.core.ppu_fix_vnan)
|
||||
|
|
|
@ -3071,13 +3071,14 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
|||
non_win32,
|
||||
accurate_dfma,
|
||||
fixup_vnan,
|
||||
accurate_jm,
|
||||
fixup_nj_denormals,
|
||||
accurate_cache_line_stores,
|
||||
reservations_128_byte,
|
||||
greedy_mode,
|
||||
accurate_sat,
|
||||
accurate_fpcc,
|
||||
accurate_vnan,
|
||||
accurate_nj_mode,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
@ -3091,8 +3092,8 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
|||
settings += ppu_settings::accurate_dfma;
|
||||
if (g_cfg.core.ppu_fix_vnan)
|
||||
settings += ppu_settings::fixup_vnan;
|
||||
if (g_cfg.core.ppu_use_nj_bit)
|
||||
settings += ppu_settings::accurate_jm;
|
||||
if (g_cfg.core.ppu_llvm_nj_fixup)
|
||||
settings += ppu_settings::fixup_nj_denormals;
|
||||
if (has_dcbz == 2)
|
||||
settings += ppu_settings::accurate_cache_line_stores;
|
||||
if (g_cfg.core.ppu_128_reservations_loop_max_length)
|
||||
|
@ -3104,7 +3105,9 @@ bool ppu_initialize(const ppu_module& info, bool check_only)
|
|||
if (g_cfg.core.ppu_set_fpcc)
|
||||
settings += ppu_settings::accurate_fpcc, fmt::throw_exception("FPCC Not implemented");
|
||||
if (g_cfg.core.ppu_set_vnan)
|
||||
settings += ppu_settings::accurate_vnan, fmt::throw_exception("VNAN Not implemented");
|
||||
settings += ppu_settings::accurate_vnan, settings -= ppu_settings::fixup_vnan, fmt::throw_exception("VNAN Not implemented");
|
||||
if (g_cfg.core.ppu_use_nj_bit)
|
||||
settings += ppu_settings::accurate_nj_mode, settings -= ppu_settings::fixup_nj_denormals, fmt::throw_exception("NJ Not implemented");
|
||||
|
||||
// Write version, hash, CPU, settings
|
||||
fmt::append(obj_name, "v5-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
|
||||
|
|
|
@ -291,7 +291,7 @@ Value* PPUTranslator::VecHandleDenormal(Value* val)
|
|||
Value* PPUTranslator::VecHandleResult(Value* val)
|
||||
{
|
||||
val = g_cfg.core.ppu_fix_vnan ? VecHandleNan(val) : val;
|
||||
val = g_cfg.core.ppu_use_nj_bit ? VecHandleDenormal(val) : val;
|
||||
val = g_cfg.core.ppu_llvm_nj_fixup ? VecHandleDenormal(val) : val;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -649,7 +649,7 @@ void PPUTranslator::MTVSCR(ppu_opcode_t op)
|
|||
const auto vscr = m_ir->CreateExtractElement(GetVr(op.vb, VrType::vi32), m_ir->getInt32(m_is_be ? 3 : 0));
|
||||
const auto nj = Trunc(m_ir->CreateLShr(vscr, 16), GetType<bool>());
|
||||
RegStore(nj, m_nj);
|
||||
if (g_cfg.core.ppu_use_nj_bit)
|
||||
if (g_cfg.core.ppu_llvm_nj_fixup)
|
||||
RegStore(m_ir->CreateSelect(nj, m_ir->getInt32(0x7f80'0000), m_ir->getInt32(0x7fff'ffff)), m_jm_mask);
|
||||
if (g_cfg.core.ppu_set_sat_bit)
|
||||
RegStore(m_ir->CreateInsertElement(ConstantAggregateZero::get(GetType<u32[4]>()), m_ir->CreateAnd(vscr, 1), m_ir->getInt32(0)), m_sat);
|
||||
|
|
|
@ -55,6 +55,7 @@ struct cfg_root : cfg::node
|
|||
cfg::_int<-1, 14> ppu_128_reservations_loop_max_length{ this, "Accurate PPU 128-byte Reservation Op Max Length", 0, true }; // -1: Always accurate, 0: Never accurate, 1-14: max accurate loop length
|
||||
cfg::_int<-64, 64> stub_ppu_traps{ this, "Stub PPU Traps", 0, true }; // Hack, skip PPU traps for rare cases where the trap is continueable (specify relative instructions to skip)
|
||||
cfg::_bool full_width_avx512{ this, "Full Width AVX-512", false };
|
||||
cfg::_bool ppu_llvm_nj_fixup{ this, "PPU LLVM Java Mode Handling", true }; // Partially respect current Java Mode for alti-vec ops by PPU LLVM
|
||||
cfg::_bool use_accurate_dfma{ this, "Use Accurate DFMA", true }; // Enable accurate double-precision FMA for CPUs which do not support it natively
|
||||
cfg::_bool ppu_set_sat_bit{ this, "PPU Set Saturation Bit", false }; // Accuracy. If unset, completely disable saturation flag handling.
|
||||
cfg::_bool ppu_use_nj_bit{ this, "PPU Use Non-Java Mode Bit", false }; // Accuracy. If unset, ignore NJ flag completely.
|
||||
|
|
|
@ -38,6 +38,7 @@ enum class emu_settings_type
|
|||
ClocksScale,
|
||||
PerformanceReport,
|
||||
FullWidthAVX512,
|
||||
PPUNJFixup,
|
||||
AccurateDFMA,
|
||||
AccuratePPUSAT,
|
||||
AccuratePPUNJ,
|
||||
|
@ -195,6 +196,7 @@ inline static const QMap<emu_settings_type, cfg_location> settings_location =
|
|||
{ emu_settings_type::PerformanceReport, { "Core", "Enable Performance Report"}},
|
||||
{ emu_settings_type::FullWidthAVX512, { "Core", "Full Width AVX-512"}},
|
||||
{ emu_settings_type::NumPPUThreads, { "Core", "PPU Threads"}},
|
||||
{ emu_settings_type::PPUNJFixup, { "Core", "PPU LLVM Java Mode Handling"}},
|
||||
{ emu_settings_type::AccurateDFMA, { "Core", "Use Accurate DFMA"}},
|
||||
{ emu_settings_type::AccuratePPUSAT, { "Core", "PPU Set Saturation Bit"}},
|
||||
{ emu_settings_type::AccuratePPUNJ, { "Core", "PPU Use Non-Java Mode Bit"}},
|
||||
|
|
|
@ -1151,6 +1151,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
|
|||
SubscribeTooltip(ui->accurateDFMA, tooltips.settings.accurate_dfma);
|
||||
ui->accurateDFMA->setDisabled(utils::has_fma3() || utils::has_fma4());
|
||||
|
||||
m_emu_settings->EnhanceCheckBox(ui->ppuNJFixup, emu_settings_type::PPUNJFixup);
|
||||
SubscribeTooltip(ui->ppuNJFixup, tooltips.settings.fixup_ppunj);
|
||||
|
||||
m_emu_settings->EnhanceCheckBox(ui->accuratePPUSAT, emu_settings_type::AccuratePPUSAT);
|
||||
SubscribeTooltip(ui->accuratePPUSAT, tooltips.settings.accurate_ppusat);
|
||||
|
||||
|
|
|
@ -2063,6 +2063,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ppuNJFixup">
|
||||
<property name="text">
|
||||
<string>PPU Non-Java Mode Fixup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="accuratePPUSAT">
|
||||
<property name="text">
|
||||
|
|
|
@ -70,6 +70,7 @@ public:
|
|||
const QString spu_block_size = tr("This option controls the SPU analyser, particularly the size of compiled units. The Mega and Giga modes may improve performance by tying smaller units together, decreasing the number of compiled units but increasing their size.\nUse the Safe mode for maximum compatibility.");
|
||||
const QString preferred_spu_threads = tr("Some SPU stages are sensitive to race conditions and allowing a limited number at a time helps alleviate performance stalls.\nSetting this to a smaller value might improve performance and reduce stuttering in some games.\nLeave this on auto if performance is negatively affected when setting a small value.");
|
||||
const QString full_width_avx512 = tr("Enables the use of code with full width AVX-512.\nThis code can be executed much faster, but may cause a loss in performance if your CPU model experiences downclocking on wide AVX-512 loads.\nNote that AVX-512 instructions will be used regardless of this option, just at 128 and 256 bit width.");
|
||||
const QString fixup_ppunj = tr("Legacy option. Fixup result vector values in Non-Java Mode in PPU LLVM.\nIf unsure, do not modify this setting.");
|
||||
const QString accurate_dfma = tr("Use accurate double-precision FMA instructions in PPU and SPU backends.\nWhile disabling it might give a decent performance boost if your CPU doesn't support FMA, it may also introduce subtle bugs that otherwise do not occur.\nYou shouldn't disable it if your CPU supports FMA.");
|
||||
const QString accurate_ppusat = tr("Accurately set Saturation Bit values in PPU backends.\nIf unsure, do not modify this setting.");
|
||||
const QString accurate_ppunj = tr("Respect Non-Java Mode Bit values for vector ops in PPU backends.\nIf unsure, do not modify this setting.");
|
||||
|
|
Loading…
Add table
Reference in a new issue