mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
EE: the D-cache store-tag lookup dropped the top three bits of the tag
DXSTG takes a guest physical page from TagLo and has to turn it into the host pointer our tags carry. It did that by routing the page through its KSEG0 alias, which meant masking the tag to 29 bits first -- and KSEG0 is only 512 MB wide, so the mask was not a formality. Every physical page at or above 0x20000000 folded into the low half of the map and resolved to whatever happened to live at the folded address. The consequence that matters is that a page past the end of the physical map folded onto real memory: 0x60129000 resolved to 0x00129000, and the eviction wrote 64 bytes of cache line into guest RAM the tag never named. Use vtlb_GetPhyPtr instead, which is what the debugger and PSM already use to ask this question. It covers the whole 1 GB physical map and answers null both for a handler page and for an address off the end of the map, so the unbacked case is now decided by the same lookup that produces the pointer rather than by a truncation. Where a tag naming one of our main-RAM mirrors resolves changes as a side effect of that, and is deliberately left unpinned. Those mirrors are our physical map's, not a console's: an SCPH-30001 has no RAM at those physical addresses, and an eviction steered at one reached nothing at all. There is no hardware answer to hold us to, so nothing asserts one.
This commit is contained in:
+13
-4
@@ -482,13 +482,22 @@ namespace R5900
|
|||||||
// an MMIO handler page, or a physical address that does not exist --
|
// an MMIO handler page, or a physical address that does not exist --
|
||||||
// is marked unbacked; the line still caches and reports its flags,
|
// is marked unbacked; the line still caches and reports its flags,
|
||||||
// and loses its data on eviction (see the comment on CacheTag).
|
// and loses its data on eviction (see the comment on CacheTag).
|
||||||
|
//
|
||||||
|
// The lookup goes through the physical map, not through the KSEG0
|
||||||
|
// alias of the page: KSEG0 is only 512 MB wide, so routing a
|
||||||
|
// physical page through it meant masking the tag to 29 bits, and
|
||||||
|
// every page at or above 0x20000000 then folded into the low half
|
||||||
|
// of the map and resolved to whatever lives there. A page past the
|
||||||
|
// end of the map folded onto ordinary RAM and the write-back went
|
||||||
|
// into it. vtlb_GetPhyPtr covers the whole 1 GB physical map and
|
||||||
|
// answers null both for a handler page and for an address off the
|
||||||
|
// end of it.
|
||||||
const u32 pageTag = cpuRegs.CP0.n.TagLo & ~static_cast<u32>(CacheTag::ALL_BITS);
|
const u32 pageTag = cpuRegs.CP0.n.TagLo & ~static_cast<u32>(CacheTag::ALL_BITS);
|
||||||
const u32 alias = 0x80000000u | (pageTag & 0x1FFFFFFFu);
|
void* const host = vtlb_GetPhyPtr(pageTag);
|
||||||
const VTLBVirtual vmv = vtlbdata.vmap[alias >> VTLB_PAGE_BITS];
|
const bool backed = host != nullptr;
|
||||||
const bool backed = !vmv.isHandler(alias);
|
|
||||||
|
|
||||||
line.tag.setValidPFN(backed);
|
line.tag.setValidPFN(backed);
|
||||||
line.tag.setAddr(backed ? vmv.assumePtr(alias) : static_cast<uptr>(pageTag));
|
line.tag.setAddr(backed ? reinterpret_cast<uptr>(host) : static_cast<uptr>(pageTag));
|
||||||
line.tag.rawValue &= ~CacheTag::ALL_FLAGS;
|
line.tag.rawValue &= ~CacheTag::ALL_FLAGS;
|
||||||
line.tag.rawValue |= (cpuRegs.CP0.n.TagLo & CacheTag::ALL_FLAGS);
|
line.tag.rawValue |= (cpuRegs.CP0.n.TagLo & CacheTag::ALL_FLAGS);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user