mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-10-21 10:08:59 +02:00
Fundamentally, all this does is enforce the invariant that we always translate effective addresses based on the current BAT registers and page table before we do anything else with them. This change can be logically divided into three parts. The first part is creating a table to represent the current BAT state, and keeping it up to date (PowerPC::IBATUpdated, PowerPC::DBATUpdated, etc.). This does nothing by itself, but it's necessary for the other parts. The second part (mostly in MMU.cpp) is simply removing all the hardcoded checks for specific untranslated addresses, and consistently translating addresses using the current BAT configuration. Very straightforward, but a lot of code changes because we hardcoded assumptions all over the place. The third part (mostly in Memmap.cpp) is making the fastmem arena reflect the current BAT configuration. We do this by redoing the mapping (calling memmap()) based on the BAT table whenever it changes. One additional minor change is that translation can fail in two ways: either the segment is a direct store segment, or page table lookup failed. The difference doesn't usually matter, but the difference affects cache instructions, like dcbz.
119 lines
3.3 KiB
C++
119 lines
3.3 KiB
C++
// Copyright 2008 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "Common/CommonFuncs.h"
|
|
#include "Common/CommonTypes.h"
|
|
|
|
// Enable memory checks in the Debug/DebugFast builds, but NOT in release
|
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
#define ENABLE_MEM_CHECK
|
|
#endif
|
|
|
|
// Global declarations
|
|
class PointerWrap;
|
|
namespace MMIO
|
|
{
|
|
class Mapping;
|
|
}
|
|
|
|
namespace Memory
|
|
{
|
|
// Base is a pointer to the base of the memory map. Yes, some MMU tricks
|
|
// are used to set up a full GC or Wii memory map in process memory. on
|
|
// 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that
|
|
// some things are mirrored too many times, but eh... it works.
|
|
|
|
// In 64-bit, this might point to "high memory" (above the 32-bit limit),
|
|
// so be sure to load it into a 64-bit register.
|
|
extern u8* physical_base;
|
|
extern u8* logical_base;
|
|
|
|
// These are guaranteed to point to "low memory" addresses (sub-32-bit).
|
|
extern u8* m_pRAM;
|
|
extern u8* m_pEXRAM;
|
|
extern u8* m_pL1Cache;
|
|
extern u8* m_pFakeVMEM;
|
|
extern bool bFakeVMEM;
|
|
|
|
enum
|
|
{
|
|
// RAM_SIZE is the amount allocated by the emulator, whereas REALRAM_SIZE is
|
|
// what will be reported in lowmem, and thus used by emulated software.
|
|
// Note: Writing to lowmem is done by IPL. If using retail IPL, it will
|
|
// always be set to 24MB.
|
|
REALRAM_SIZE = 0x01800000,
|
|
RAM_SIZE = ROUND_UP_POW2(REALRAM_SIZE),
|
|
RAM_MASK = RAM_SIZE - 1,
|
|
FAKEVMEM_SIZE = 0x02000000,
|
|
FAKEVMEM_MASK = FAKEVMEM_SIZE - 1,
|
|
L1_CACHE_SIZE = 0x00040000,
|
|
L1_CACHE_MASK = L1_CACHE_SIZE - 1,
|
|
IO_SIZE = 0x00010000,
|
|
EXRAM_SIZE = 0x04000000,
|
|
EXRAM_MASK = EXRAM_SIZE - 1,
|
|
};
|
|
|
|
// MMIO mapping object.
|
|
extern std::unique_ptr<MMIO::Mapping> mmio_mapping;
|
|
|
|
// Init and Shutdown
|
|
bool IsInitialized();
|
|
void Init();
|
|
void Shutdown();
|
|
void DoState(PointerWrap& p);
|
|
|
|
void UpdateLogicalMemory(u32* dbat_table);
|
|
|
|
void Clear();
|
|
bool AreMemoryBreakpointsActivated();
|
|
|
|
// Routines to access physically addressed memory, designed for use by
|
|
// emulated hardware outside the CPU. Use "Device_" prefix.
|
|
std::string GetString(u32 em_address, size_t size = 0);
|
|
u8* GetPointer(const u32 address);
|
|
void CopyFromEmu(void* data, u32 address, size_t size);
|
|
void CopyToEmu(u32 address, const void* data, size_t size);
|
|
void Memset(u32 address, u8 value, size_t size);
|
|
u8 Read_U8(const u32 address);
|
|
u16 Read_U16(const u32 address);
|
|
u32 Read_U32(const u32 address);
|
|
u64 Read_U64(const u32 address);
|
|
void Write_U8(const u8 var, const u32 address);
|
|
void Write_U16(const u16 var, const u32 address);
|
|
void Write_U32(const u32 var, const u32 address);
|
|
void Write_U64(const u64 var, const u32 address);
|
|
void Write_U32_Swap(const u32 var, const u32 address);
|
|
void Write_U64_Swap(const u64 var, const u32 address);
|
|
|
|
// Templated functions for byteswapped copies.
|
|
template <typename T>
|
|
void CopyFromEmuSwapped(T* data, u32 address, size_t size)
|
|
{
|
|
const T* src = reinterpret_cast<T*>(GetPointer(address));
|
|
|
|
if (src == nullptr)
|
|
return;
|
|
|
|
for (size_t i = 0; i < size / sizeof(T); i++)
|
|
data[i] = Common::FromBigEndian(src[i]);
|
|
}
|
|
|
|
template <typename T>
|
|
void CopyToEmuSwapped(u32 address, const T* data, size_t size)
|
|
{
|
|
T* dest = reinterpret_cast<T*>(GetPointer(address));
|
|
|
|
if (dest == nullptr)
|
|
return;
|
|
|
|
for (size_t i = 0; i < size / sizeof(T); i++)
|
|
dest[i] = Common::FromBigEndian(data[i]);
|
|
}
|
|
}
|