mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
EE rec: stop raising TLB misses on unknown MMIO too
The _ext_mem* fallbacks raise a TLB exception when a registered region gets an access its device has no case for. Under a recompiler that is the defect just removed from vtlb_Miss by another route: nothing diverts the block, so the raise only latches Status.EXL. Raise on the interpreter alone. Recompilers report instead, which is new - MEM_LOG is devbuild-only, so the raise was all a release build left.
This commit is contained in:
+30
-10
@@ -701,6 +701,26 @@ static void TAKES_R128 nullWrite128(u32 mem, r128 value)
|
||||
MEM_LOG("Write uninstalled memory at address %08x", mem);
|
||||
}
|
||||
|
||||
// paddr is post-translation, so cpuTlbMiss lands a physical address in
|
||||
// BadVAddr, Context and EntryHi. Recompilers do not raise; see vtlb_Miss.
|
||||
static void _ext_memUnknown(u32 paddr, bool write)
|
||||
{
|
||||
if (Cpu == &intCpu)
|
||||
{
|
||||
if (write)
|
||||
cpuTlbMissW(paddr, cpuRegs.branch);
|
||||
else
|
||||
cpuTlbMissR(paddr, cpuRegs.branch);
|
||||
return;
|
||||
}
|
||||
|
||||
// MEM_LOG at the call sites is devbuild-only.
|
||||
static int spamStop = 0;
|
||||
if (spamStop++ < 50 || IsDevBuild)
|
||||
Console.Error("Unknown memory %s at 0x%08x, pc=0x%08x",
|
||||
write ? "write" : "read", paddr, cpuRegs.pc);
|
||||
}
|
||||
|
||||
template<int p>
|
||||
static mem8_t _ext_memRead8 (u32 mem)
|
||||
{
|
||||
@@ -722,7 +742,7 @@ static mem8_t _ext_memRead8 (u32 mem)
|
||||
}
|
||||
|
||||
MEM_LOG("Unknown Memory Read8 from address %8.8x", mem);
|
||||
cpuTlbMissR(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -755,7 +775,7 @@ static mem16_t _ext_memRead16(u32 mem)
|
||||
default: break;
|
||||
}
|
||||
MEM_LOG("Unknown Memory read16 from address %8.8x", mem);
|
||||
cpuTlbMissR(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -778,7 +798,7 @@ static mem32_t _ext_memRead32(u32 mem)
|
||||
}
|
||||
|
||||
MEM_LOG("Unknown Memory read32 from address %8.8x (Status=%8.8x)", mem, cpuRegs.CP0.n.Status.val);
|
||||
cpuTlbMissR(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -800,7 +820,7 @@ static u64 _ext_memRead64(u32 mem)
|
||||
}
|
||||
|
||||
MEM_LOG("Unknown Memory read64 from address %8.8x", mem);
|
||||
cpuTlbMissR(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -826,7 +846,7 @@ static RETURNS_R128 _ext_memRead128(u32 mem)
|
||||
}
|
||||
|
||||
MEM_LOG("Unknown Memory read128 from address %8.8x", mem);
|
||||
cpuTlbMissR(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, false);
|
||||
return r128_zero();
|
||||
}
|
||||
|
||||
@@ -849,7 +869,7 @@ static void _ext_memWrite8 (u32 mem, mem8_t value)
|
||||
}
|
||||
|
||||
MEM_LOG("Unknown Memory write8 to address %x with data %2.2x", mem, value);
|
||||
cpuTlbMissW(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, true);
|
||||
}
|
||||
|
||||
template<int p>
|
||||
@@ -874,7 +894,7 @@ static void _ext_memWrite16(u32 mem, mem16_t value)
|
||||
default: break;
|
||||
}
|
||||
MEM_LOG("Unknown Memory write16 to address %x with data %4.4x", mem, value);
|
||||
cpuTlbMissW(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, true);
|
||||
}
|
||||
|
||||
template<int p>
|
||||
@@ -893,7 +913,7 @@ static void _ext_memWrite32(u32 mem, mem32_t value)
|
||||
default: break;
|
||||
}
|
||||
MEM_LOG("Unknown Memory write32 to address %x with data %8.8x", mem, value);
|
||||
cpuTlbMissW(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, true);
|
||||
}
|
||||
|
||||
template<int p>
|
||||
@@ -917,7 +937,7 @@ static void _ext_memWrite64(u32 mem, mem64_t value)
|
||||
}*/
|
||||
|
||||
MEM_LOG("Unknown Memory write64 to address %x with data %8.8x_%8.8x", mem, (u32)(value>>32), (u32)value);
|
||||
cpuTlbMissW(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, true);
|
||||
}
|
||||
|
||||
template<int p>
|
||||
@@ -950,7 +970,7 @@ static void TAKES_R128 _ext_memWrite128(u32 mem, r128 value)
|
||||
|
||||
alignas(16) const u128 uvalue = r128_to_u128(value);
|
||||
MEM_LOG("Unknown Memory write128 to address %x with data %8.8x_%8.8x_%8.8x_%8.8x", mem, uvalue._u32[3], uvalue._u32[2], uvalue._u32[1], uvalue._u32[0]);
|
||||
cpuTlbMissW(mem, cpuRegs.branch);
|
||||
_ext_memUnknown(mem, true);
|
||||
}
|
||||
|
||||
#define vtlb_RegisterHandlerTempl1(nam,t) vtlb_RegisterHandler(nam##Read8<t>,nam##Read16<t>,nam##Read32<t>,nam##Read64<t>,nam##Read128<t>, \
|
||||
|
||||
@@ -69,8 +69,6 @@ extern void vtlb_ReassignHandler( vtlbHandler rv,
|
||||
// vtlb_Miss. Recompilers use this to decide whether a compile-time resolved
|
||||
// handler call needs cpuRegs.pc flushed first: vtlb_Miss reads it, and under
|
||||
// the interpreter derives EPC from it, while a hardware handler never does.
|
||||
// Not a can-this-raise test — the tlb_fallback_* handlers (Memory.cpp) call
|
||||
// cpuTlbMissR/W too.
|
||||
extern bool vtlb_IsUnmappedHandlerID(vtlbHandler id);
|
||||
|
||||
|
||||
|
||||
@@ -266,6 +266,45 @@ TEST(EeRecTraps, LoadTlbMissDoesNotRaiseOnTheRecompiler)
|
||||
EXPECT_EQ(h.GetCp0Jit(8), 0u) << "BadVAddr";
|
||||
}
|
||||
|
||||
// 0xBF801000 is kseg1, so no TLB entry: it translates to 0x1f801000, IOP
|
||||
// hardware, whose 64-bit reader is _ext_memRead64<2> (Memory.cpp).
|
||||
namespace {
|
||||
std::vector<u32> UnknownMmioLoadProgram()
|
||||
{
|
||||
return {
|
||||
LUI(reg::a0, 0xBF80), // +0x0
|
||||
ee::LD(reg::v1, 0x1000, reg::a0),// +0x4
|
||||
ADDIU(reg::v0, reg::zero, 99), // +0x8
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(EeRecTraps, UnknownMmioAccessRaisesOnTheInterpreter)
|
||||
{
|
||||
EeRecTestHarness h;
|
||||
h.LoadProgram(UnknownMmioLoadProgram());
|
||||
h.RunInterpOnly();
|
||||
EXPECT_EQ(h.GetGpr64Interp(reg::v1), 0ull);
|
||||
EXPECT_EQ(h.GetGpr64Interp(reg::v0), 0ull) << "vector preempts the next op";
|
||||
EXPECT_EQ(h.GetCp0Interp(13) & 0xFFu, 0x08u) << "TLBL";
|
||||
EXPECT_NE(h.GetCp0Interp(12) & 0x2u, 0u) << "Status.EXL";
|
||||
EXPECT_EQ(h.GetCp0Interp(14), RecompilerTestEnvironment::kProgramPc + 4);
|
||||
EXPECT_EQ(h.GetCp0Interp(8), 0x1f801000u) << "BadVAddr = the paddr";
|
||||
}
|
||||
|
||||
TEST(EeRecTraps, UnknownMmioAccessDoesNotRaiseOnTheRecompiler)
|
||||
{
|
||||
EeRecTestHarness h;
|
||||
h.LoadProgram(UnknownMmioLoadProgram());
|
||||
h.RunJitNoDiff();
|
||||
EXPECT_EQ(h.GetGpr64Jit(reg::v1), 0ull);
|
||||
EXPECT_EQ(h.GetGpr64Jit(reg::v0), 99ull) << "the block must run on";
|
||||
EXPECT_EQ(h.GetCp0Jit(12) & 0x2u, 0u) << "Status.EXL must not latch";
|
||||
EXPECT_EQ(h.GetCp0Jit(13), 0u) << "CAUSE";
|
||||
EXPECT_EQ(h.GetCp0Jit(14), 0u) << "EPC";
|
||||
EXPECT_EQ(h.GetCp0Jit(8), 0u) << "BadVAddr";
|
||||
}
|
||||
|
||||
TEST(EeRecTraps, AluDelaySlotBranchSemanticsSurviveWithoutBracket)
|
||||
{
|
||||
// Non-raising (ALU) delay slots lose the cpuRegs.branch bracket under the
|
||||
|
||||
Reference in New Issue
Block a user