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
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#include "cpu_core.h"
|
#include "cpu_core.h"
|
||||||
@ -224,6 +224,7 @@ void CPU::Reset()
|
|||||||
g_state.downcount = 0;
|
g_state.downcount = 0;
|
||||||
g_state.pending_ticks = 0;
|
g_state.pending_ticks = 0;
|
||||||
g_state.gte_completion_tick = 0;
|
g_state.gte_completion_tick = 0;
|
||||||
|
g_state.muldiv_completion_tick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CPU::DoState(StateWrapper& sw)
|
bool CPU::DoState(StateWrapper& sw)
|
||||||
@ -231,6 +232,7 @@ bool CPU::DoState(StateWrapper& sw)
|
|||||||
sw.Do(&g_state.pending_ticks);
|
sw.Do(&g_state.pending_ticks);
|
||||||
sw.Do(&g_state.downcount);
|
sw.Do(&g_state.downcount);
|
||||||
sw.DoEx(&g_state.gte_completion_tick, 78, static_cast<u32>(0));
|
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.DoArray(g_state.regs.r, static_cast<u32>(Reg::count));
|
||||||
sw.Do(&g_state.pc);
|
sw.Do(&g_state.pc);
|
||||||
sw.Do(&g_state.npc);
|
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 == CPUExecutionMode::Interpreter) ? CPUExecutionMode::CachedInterpreter :
|
||||||
g_settings.cpu_execution_mode);
|
g_settings.cpu_execution_mode);
|
||||||
g_state.gte_completion_tick = 0;
|
g_state.gte_completion_tick = 0;
|
||||||
|
g_state.muldiv_completion_tick = 0;
|
||||||
UpdateMemoryPointers();
|
UpdateMemoryPointers();
|
||||||
UpdateDebugDispatcherFlag();
|
UpdateDebugDispatcherFlag();
|
||||||
}
|
}
|
||||||
@ -1100,6 +1103,8 @@ restart_instruction:
|
|||||||
const u32 value = g_state.regs.hi;
|
const u32 value = g_state.regs.hi;
|
||||||
WriteReg(inst.r.rd, value);
|
WriteReg(inst.r.rd, value);
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::hi), value);
|
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);
|
const u32 value = ReadReg(inst.r.rs);
|
||||||
g_state.regs.hi = value;
|
g_state.regs.hi = value;
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_MOVE(static_cast<u32>(Reg::hi), static_cast<u32>(inst.r.rs.GetValue()), value);
|
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;
|
const u32 value = g_state.regs.lo;
|
||||||
WriteReg(inst.r.rd, value);
|
WriteReg(inst.r.rd, value);
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::lo), value);
|
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);
|
const u32 value = ReadReg(inst.r.rs);
|
||||||
g_state.regs.lo = value;
|
g_state.regs.lo = value;
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
|
||||||
if constexpr (pgxp_mode == PGXPMode::CPU)
|
if constexpr (pgxp_mode == PGXPMode::CPU)
|
||||||
PGXP::CPU_MOVE(static_cast<u32>(Reg::lo), static_cast<u32>(inst.r.rs.GetValue()), value);
|
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.hi = Truncate32(result >> 32);
|
||||||
g_state.regs.lo = Truncate32(result);
|
g_state.regs.lo = Truncate32(result);
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
AddMulDivTicks(GetMultTicks(static_cast<s32>(lhs)));
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_MULT(inst, lhs, rhs);
|
PGXP::CPU_MULT(inst, lhs, rhs);
|
||||||
}
|
}
|
||||||
@ -1159,6 +1173,9 @@ restart_instruction:
|
|||||||
g_state.regs.hi = Truncate32(result >> 32);
|
g_state.regs.hi = Truncate32(result >> 32);
|
||||||
g_state.regs.lo = Truncate32(result);
|
g_state.regs.lo = Truncate32(result);
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
AddMulDivTicks(GetMultTicks(lhs));
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_MULTU(inst, lhs, rhs);
|
PGXP::CPU_MULTU(inst, lhs, rhs);
|
||||||
}
|
}
|
||||||
@ -1187,6 +1204,9 @@ restart_instruction:
|
|||||||
g_state.regs.hi = static_cast<u32>(num % denom);
|
g_state.regs.hi = static_cast<u32>(num % denom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
AddMulDivTicks(GetDivTicks());
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_DIV(inst, num, denom);
|
PGXP::CPU_DIV(inst, num, denom);
|
||||||
}
|
}
|
||||||
@ -1209,6 +1229,9 @@ restart_instruction:
|
|||||||
g_state.regs.hi = num % denom;
|
g_state.regs.hi = num % denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StallUntilMulDivComplete();
|
||||||
|
AddMulDivTicks(GetDivTicks());
|
||||||
|
|
||||||
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
if constexpr (pgxp_mode >= PGXPMode::CPU)
|
||||||
PGXP::CPU_DIVU(inst, num, denom);
|
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
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -76,6 +76,7 @@ struct ALIGN_TO_CACHE_LINE State
|
|||||||
u32 downcount = 0;
|
u32 downcount = 0;
|
||||||
u32 pending_ticks = 0;
|
u32 pending_ticks = 0;
|
||||||
u32 gte_completion_tick = 0;
|
u32 gte_completion_tick = 0;
|
||||||
|
u32 muldiv_completion_tick = 0;
|
||||||
|
|
||||||
Registers regs = {};
|
Registers regs = {};
|
||||||
Cop0Registers cop0_regs = {};
|
Cop0Registers cop0_regs = {};
|
||||||
@ -155,6 +156,8 @@ ALWAYS_INLINE static void ResetPendingTicks()
|
|||||||
{
|
{
|
||||||
g_state.gte_completion_tick =
|
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.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;
|
g_state.pending_ticks = 0;
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE static void AddPendingTicks(TickCount ticks)
|
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
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#pragma once
|
#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;
|
(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
|
// kernel call interception
|
||||||
void HandleA0Syscall();
|
void HandleA0Syscall();
|
||||||
void HandleB0Syscall();
|
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
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -6,7 +6,7 @@
|
|||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
|
||||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
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 constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||||
|
|
||||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user