Merge pull request #1176 from FioraAeterna/pagecrossings

MMU: support loads/stores that cross page boundaries
This commit is contained in:
skidau 2014-10-01 13:22:52 +10:00
commit 19fbefd9bd
1 changed files with 73 additions and 11 deletions

View File

@ -34,6 +34,8 @@
namespace Memory namespace Memory
{ {
#define HW_PAGE_SIZE 4096
// EFB RE // EFB RE
/* /*
GXPeekZ GXPeekZ
@ -123,6 +125,39 @@ inline void ReadFromHardware(T &_var, const u32 em_address, const u32 effective_
else else
{ {
// MMU // MMU
// Handle loads that cross page boundaries (ewwww)
if (sizeof(T) > 1 && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T))
{
_var = 0;
// This could be unaligned down to the byte level... hopefully this is rare, so doing it this
// way isn't too terrible.
// TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions.
// Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned!
u32 tlb_addr = TranslateAddress(em_address, flag);
for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++)
{
// Start of the new page... translate the address again!
if (!(addr & (HW_PAGE_SIZE-1)))
tlb_addr = TranslateAddress(addr, flag);
// Important: we need to generate the DSI on the first store that caused the fault, NOT
// the address of the start of the load.
if (tlb_addr == 0)
{
if (flag == FLAG_READ)
{
GenerateDSIException(addr, false);
break;
}
}
else
{
_var <<= 8;
_var |= m_pRAM[tlb_addr & RAM_MASK];
}
}
}
else
{
u32 tlb_addr = TranslateAddress(em_address, flag); u32 tlb_addr = TranslateAddress(em_address, flag);
if (tlb_addr == 0) if (tlb_addr == 0)
{ {
@ -137,6 +172,7 @@ inline void ReadFromHardware(T &_var, const u32 em_address, const u32 effective_
} }
} }
} }
}
template <typename T> template <typename T>
@ -208,6 +244,32 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
else else
{ {
// MMU // MMU
// Handle stores that cross page boundaries (ewwww)
if (sizeof(T) > 1 && (em_address & (HW_PAGE_SIZE-1)) > HW_PAGE_SIZE - sizeof(T))
{
T val = bswap(data);
u32 tlb_addr = TranslateAddress(em_address, flag);
for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++)
{
if (!(addr & (HW_PAGE_SIZE-1)))
tlb_addr = TranslateAddress(addr, flag);
if (tlb_addr == 0)
{
if (flag == FLAG_WRITE)
{
GenerateDSIException(addr, true);
break;
}
}
else
{
m_pRAM[tlb_addr & RAM_MASK] = (u8)val;
val >>= 8;
}
}
}
else
{
u32 tlb_addr = TranslateAddress(em_address, flag); u32 tlb_addr = TranslateAddress(em_address, flag);
if (tlb_addr == 0) if (tlb_addr == 0)
{ {
@ -222,6 +284,7 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
} }
} }
} }
}
// ===================== // =====================
@ -607,7 +670,6 @@ void SDRUpdated()
#define TLB_WAYS 2 #define TLB_WAYS 2
#define NUM_TLBS 2 #define NUM_TLBS 2
#define HW_PAGE_SIZE 4096
#define HW_PAGE_INDEX_SHIFT 12 #define HW_PAGE_INDEX_SHIFT 12
#define HW_PAGE_INDEX_MASK 0x3f #define HW_PAGE_INDEX_MASK 0x3f
#define HW_PAGE_TAG_SHIFT 18 #define HW_PAGE_TAG_SHIFT 18