mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 12:05:52 +00:00
CPU/Interpreter: Emulate lo/hi read stall after mult/div
Still need to do the recompiler.
This commit is contained in:
parent
74064af730
commit
115ba4433c
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "cpu_core.h"
|
||||
@ -224,6 +224,7 @@ void CPU::Reset()
|
||||
g_state.downcount = 0;
|
||||
g_state.pending_ticks = 0;
|
||||
g_state.gte_completion_tick = 0;
|
||||
g_state.muldiv_completion_tick = 0;
|
||||
}
|
||||
|
||||
bool CPU::DoState(StateWrapper& sw)
|
||||
@ -231,6 +232,7 @@ bool CPU::DoState(StateWrapper& sw)
|
||||
sw.Do(&g_state.pending_ticks);
|
||||
sw.Do(&g_state.downcount);
|
||||
sw.DoEx(&g_state.gte_completion_tick, 78, static_cast<u32>(0));
|
||||
sw.DoEx(&g_state.muldiv_completion_tick, 80, static_cast<u32>(0));
|
||||
sw.DoArray(g_state.regs.r, static_cast<u32>(Reg::count));
|
||||
sw.Do(&g_state.pc);
|
||||
sw.Do(&g_state.npc);
|
||||
@ -301,6 +303,7 @@ bool CPU::DoState(StateWrapper& sw)
|
||||
((g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter) ? CPUExecutionMode::CachedInterpreter :
|
||||
g_settings.cpu_execution_mode);
|
||||
g_state.gte_completion_tick = 0;
|
||||
g_state.muldiv_completion_tick = 0;
|
||||
UpdateMemoryPointers();
|
||||
UpdateDebugDispatcherFlag();
|
||||
}
|
||||
@ -1100,6 +1103,8 @@ restart_instruction:
|
||||
const u32 value = g_state.regs.hi;
|
||||
WriteReg(inst.r.rd, value);
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::hi), value);
|
||||
}
|
||||
@ -1110,6 +1115,8 @@ restart_instruction:
|
||||
const u32 value = ReadReg(inst.r.rs);
|
||||
g_state.regs.hi = value;
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_MOVE(static_cast<u32>(Reg::hi), static_cast<u32>(inst.r.rs.GetValue()), value);
|
||||
}
|
||||
@ -1120,6 +1127,8 @@ restart_instruction:
|
||||
const u32 value = g_state.regs.lo;
|
||||
WriteReg(inst.r.rd, value);
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::lo), value);
|
||||
}
|
||||
@ -1130,6 +1139,8 @@ restart_instruction:
|
||||
const u32 value = ReadReg(inst.r.rs);
|
||||
g_state.regs.lo = value;
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
|
||||
if constexpr (pgxp_mode == PGXPMode::CPU)
|
||||
PGXP::CPU_MOVE(static_cast<u32>(Reg::lo), static_cast<u32>(inst.r.rs.GetValue()), value);
|
||||
}
|
||||
@ -1145,6 +1156,9 @@ restart_instruction:
|
||||
g_state.regs.hi = Truncate32(result >> 32);
|
||||
g_state.regs.lo = Truncate32(result);
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
AddMulDivTicks(GetMultTicks(static_cast<s32>(lhs)));
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_MULT(inst, lhs, rhs);
|
||||
}
|
||||
@ -1159,6 +1173,9 @@ restart_instruction:
|
||||
g_state.regs.hi = Truncate32(result >> 32);
|
||||
g_state.regs.lo = Truncate32(result);
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
AddMulDivTicks(GetMultTicks(lhs));
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_MULTU(inst, lhs, rhs);
|
||||
}
|
||||
@ -1187,6 +1204,9 @@ restart_instruction:
|
||||
g_state.regs.hi = static_cast<u32>(num % denom);
|
||||
}
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
AddMulDivTicks(GetDivTicks());
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_DIV(inst, num, denom);
|
||||
}
|
||||
@ -1209,6 +1229,9 @@ restart_instruction:
|
||||
g_state.regs.hi = num % denom;
|
||||
}
|
||||
|
||||
StallUntilMulDivComplete();
|
||||
AddMulDivTicks(GetDivTicks());
|
||||
|
||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||
PGXP::CPU_DIVU(inst, num, denom);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
@ -76,6 +76,7 @@ struct ALIGN_TO_CACHE_LINE State
|
||||
u32 downcount = 0;
|
||||
u32 pending_ticks = 0;
|
||||
u32 gte_completion_tick = 0;
|
||||
u32 muldiv_completion_tick = 0;
|
||||
|
||||
Registers regs = {};
|
||||
Cop0Registers cop0_regs = {};
|
||||
@ -155,6 +156,8 @@ ALWAYS_INLINE static void ResetPendingTicks()
|
||||
{
|
||||
g_state.gte_completion_tick =
|
||||
(g_state.pending_ticks < g_state.gte_completion_tick) ? (g_state.gte_completion_tick - g_state.pending_ticks) : 0;
|
||||
g_state.muldiv_completion_tick =
|
||||
(g_state.pending_ticks < g_state.muldiv_completion_tick) ? (g_state.muldiv_completion_tick - g_state.pending_ticks) : 0;
|
||||
g_state.pending_ticks = 0;
|
||||
}
|
||||
ALWAYS_INLINE static void AddPendingTicks(TickCount ticks)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
@ -132,6 +132,36 @@ ALWAYS_INLINE static void StallUntilGTEComplete()
|
||||
(g_state.gte_completion_tick > g_state.pending_ticks) ? g_state.gte_completion_tick : g_state.pending_ticks;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static void AddMulDivTicks(TickCount ticks)
|
||||
{
|
||||
g_state.muldiv_completion_tick = g_state.pending_ticks + ticks;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static void StallUntilMulDivComplete()
|
||||
{
|
||||
g_state.pending_ticks =
|
||||
(g_state.muldiv_completion_tick > g_state.pending_ticks) ? g_state.muldiv_completion_tick : g_state.pending_ticks;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static constexpr TickCount GetMultTicks(s32 rs)
|
||||
{
|
||||
// Subtract one because of the instruction cycle.
|
||||
if (rs < 0)
|
||||
return (rs >= -2048) ? (6 - 1) : ((rs >= -1048576) ? (9 - 1) : (13 - 1));
|
||||
else
|
||||
return (rs < 0x800) ? (6 - 1) : ((rs < 0x100000) ? (9 - 1) : (13 - 1));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static constexpr TickCount GetMultTicks(u32 rs)
|
||||
{
|
||||
return (rs < 0x800) ? (6 - 1) : ((rs < 0x100000) ? (9 - 1) : (13 - 1));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static constexpr TickCount GetDivTicks()
|
||||
{
|
||||
return (36 - 1);
|
||||
}
|
||||
|
||||
// kernel call interception
|
||||
void HandleA0Syscall();
|
||||
void HandleB0Syscall();
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
@ -6,7 +6,7 @@
|
||||
#include "common/types.h"
|
||||
|
||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
||||
static constexpr u32 SAVE_STATE_VERSION = 79;
|
||||
static constexpr u32 SAVE_STATE_VERSION = 80;
|
||||
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||
|
||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||
|
Loading…
x
Reference in New Issue
Block a user