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);
|
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>
|
template<int p>
|
||||||
static mem8_t _ext_memRead8 (u32 mem)
|
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);
|
MEM_LOG("Unknown Memory Read8 from address %8.8x", mem);
|
||||||
cpuTlbMissR(mem, cpuRegs.branch);
|
_ext_memUnknown(mem, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +775,7 @@ static mem16_t _ext_memRead16(u32 mem)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
MEM_LOG("Unknown Memory read16 from address %8.8x", mem);
|
MEM_LOG("Unknown Memory read16 from address %8.8x", mem);
|
||||||
cpuTlbMissR(mem, cpuRegs.branch);
|
_ext_memUnknown(mem, false);
|
||||||
return 0;
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +820,7 @@ static u64 _ext_memRead64(u32 mem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MEM_LOG("Unknown Memory read64 from address %8.8x", mem);
|
MEM_LOG("Unknown Memory read64 from address %8.8x", mem);
|
||||||
cpuTlbMissR(mem, cpuRegs.branch);
|
_ext_memUnknown(mem, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,7 +846,7 @@ static RETURNS_R128 _ext_memRead128(u32 mem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MEM_LOG("Unknown Memory read128 from address %8.8x", mem);
|
MEM_LOG("Unknown Memory read128 from address %8.8x", mem);
|
||||||
cpuTlbMissR(mem, cpuRegs.branch);
|
_ext_memUnknown(mem, false);
|
||||||
return r128_zero();
|
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);
|
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>
|
template<int p>
|
||||||
@@ -874,7 +894,7 @@ static void _ext_memWrite16(u32 mem, mem16_t value)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
MEM_LOG("Unknown Memory write16 to address %x with data %4.4x", mem, value);
|
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>
|
template<int p>
|
||||||
@@ -893,7 +913,7 @@ static void _ext_memWrite32(u32 mem, mem32_t value)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
MEM_LOG("Unknown Memory write32 to address %x with data %8.8x", mem, value);
|
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>
|
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);
|
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>
|
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);
|
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]);
|
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>, \
|
#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
|
// 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
|
// 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.
|
// 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);
|
extern bool vtlb_IsUnmappedHandlerID(vtlbHandler id);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -266,6 +266,45 @@ TEST(EeRecTraps, LoadTlbMissDoesNotRaiseOnTheRecompiler)
|
|||||||
EXPECT_EQ(h.GetCp0Jit(8), 0u) << "BadVAddr";
|
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)
|
TEST(EeRecTraps, AluDelaySlotBranchSemanticsSurviveWithoutBracket)
|
||||||
{
|
{
|
||||||
// Non-raising (ALU) delay slots lose the cpuRegs.branch bracket under the
|
// Non-raising (ALU) delay slots lose the cpuRegs.branch bracket under the
|
||||||
|
|||||||
Reference in New Issue
Block a user