mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-24 19:59:08 +02:00
Merge pull request #22683 from hrydgard/address-space
CPU: Give each MIPSState an address space for its memory accesses
This commit is contained in:
22 files changed
+177
-96
No files matched your search
@@ -111,7 +111,7 @@ void ArmJitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
VPUSH(D8, 8);
|
||||
|
||||
// Fixed registers, these are always kept when in Jit context.
|
||||
MOVP2R(MEMBASEREG, Memory::base);
|
||||
MOVP2R(MEMBASEREG, mipsState->space->base);
|
||||
MOVP2R(CTXREG, mipsState);
|
||||
|
||||
LoadStaticRegisters();
|
||||
@@ -157,7 +157,7 @@ void ArmJitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
static_assert(Memory::BLOCK_SHADOW_ENTRY_MASK == 0x0FFFFFFC, "BICs below assume the 32-bit shadow mask");
|
||||
BIC(SCRATCH1, SCRATCH1, Operand2(0xF0, 4)); // &= 0x0FFFFFFF. Rotation is to the right, in 2-bit increments.
|
||||
BIC(SCRATCH1, SCRATCH1, Operand2(3));
|
||||
MOVP2R(SCRATCH2, Memory::blockShadow);
|
||||
MOVP2R(SCRATCH2, mipsState->space->blockShadow);
|
||||
hooks_.dispatchFetch = GetCodePtr();
|
||||
LDR(SCRATCH1, SCRATCH2, SCRATCH1);
|
||||
// The entry is the block's offset into the code space, or 0 for none.
|
||||
|
||||
@@ -51,6 +51,7 @@ static void ShowPC(void *membase, void *jitbase) {
|
||||
}
|
||||
|
||||
void Arm64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
regs_.SetMemoryBase(mipsState->space->base);
|
||||
// This will be used as a writable scratch area, always 32-bit accessible.
|
||||
const u8 *start = AlignCodePage();
|
||||
if (DebugProfilerEnabled()) {
|
||||
@@ -155,7 +156,7 @@ void Arm64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
fp_.ABI_PushRegisters(regs_to_save, regs_to_save_fp);
|
||||
|
||||
// Fixed registers, these are always kept when in Jit context.
|
||||
MOVP2R(MEMBASEREG, Memory::base);
|
||||
MOVP2R(MEMBASEREG, mipsState->space->base);
|
||||
MOVP2R(CTXREG, mipsState);
|
||||
MOVP2R(JITBASEREG, GetBasePtr());
|
||||
|
||||
@@ -205,7 +206,7 @@ void Arm64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
MovFromPC(SCRATCH1);
|
||||
WriteDebugPC(SCRATCH1);
|
||||
ANDI2R(SCRATCH1, SCRATCH1, Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
MOVP2R(SCRATCH2_64, Memory::blockShadow);
|
||||
MOVP2R(SCRATCH2_64, mipsState->space->blockShadow);
|
||||
hooks_.dispatchFetch = GetCodePtr();
|
||||
LDR(SCRATCH1, SCRATCH2_64, SCRATCH1_64);
|
||||
// The entry is the block's offset into the code space, or 0 for none.
|
||||
|
||||
@@ -60,7 +60,7 @@ void Arm64JitBackend::CompIR_Exit(IRInst inst) {
|
||||
B(hooks_.dispatcher);
|
||||
SetJumpTarget(inTime);
|
||||
ANDI2R(SCRATCH1, SCRATCH1, Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
MOVP2R(SCRATCH2_64, Memory::blockShadow);
|
||||
MOVP2R(SCRATCH2_64, mips_->space->blockShadow);
|
||||
LDR(SCRATCH1, SCRATCH2_64, SCRATCH1_64);
|
||||
FixupBranch found = CBNZ(SCRATCH1);
|
||||
B(dispatcherNoCheck_);
|
||||
|
||||
@@ -123,7 +123,7 @@ void Arm64IRRegCache::EmitLoadStaticRegisters() {
|
||||
emit_->LDR(INDEX_UNSIGNED, FromNativeReg(allocs[i].nr), CTXREG, offset);
|
||||
if (allocs[i].pointerified && jo_->enablePointerify) {
|
||||
ARM64Reg r64 = FromNativeReg64(allocs[i].nr);
|
||||
uint32_t membaseHigh = (uint32_t)((uint64_t)Memory::base >> 32);
|
||||
uint32_t membaseHigh = (uint32_t)((uint64_t)membase_ >> 32);
|
||||
emit_->MOVK(r64, membaseHigh & 0xFFFF, SHIFT_32);
|
||||
if (membaseHigh & 0xFFFF0000)
|
||||
emit_->MOVK(r64, membaseHigh >> 16, SHIFT_48);
|
||||
@@ -347,7 +347,7 @@ void Arm64IRRegCache::AdjustNativeRegAsPtr(IRNativeReg nreg, bool state) {
|
||||
#endif
|
||||
emit_->ADD(r, r, MEMBASEREG);
|
||||
} else {
|
||||
uint32_t membaseHigh = (uint32_t)((uint64_t)Memory::base >> 32);
|
||||
uint32_t membaseHigh = (uint32_t)((uint64_t)membase_ >> 32);
|
||||
emit_->MOVK(r, membaseHigh & 0xFFFF, SHIFT_32);
|
||||
if (membaseHigh & 0xFFFF0000)
|
||||
emit_->MOVK(r, membaseHigh >> 16, SHIFT_48);
|
||||
|
||||
@@ -86,9 +86,9 @@ static u32 RunKernelLoad(MIPSState *mips, u32 addr) {
|
||||
u32 value;
|
||||
if (IsValidAlignedAddress<size>(addr)) {
|
||||
switch (size) {
|
||||
case 1: value = Memory::ReadUnchecked_U8(addr); break;
|
||||
case 2: value = Memory::ReadUnchecked_U16(addr); break;
|
||||
default: value = Memory::ReadUnchecked_U32(addr); break;
|
||||
case 1: value = mips->space->ReadUnchecked_U8(addr); break;
|
||||
case 2: value = mips->space->ReadUnchecked_U16(addr); break;
|
||||
default: value = mips->space->ReadUnchecked_U32(addr); break;
|
||||
}
|
||||
} else if (Memory::IsMMIOAccess(addr)) {
|
||||
value = MMIO::Read(mips, addr, size);
|
||||
@@ -105,9 +105,9 @@ template <int size>
|
||||
static void RunKernelStore(MIPSState *mips, u32 addr, u32 value) {
|
||||
if (IsValidAlignedAddress<size>(addr)) {
|
||||
switch (size) {
|
||||
case 1: Memory::WriteUnchecked_U8((u8)value, addr); break;
|
||||
case 2: Memory::WriteUnchecked_U16((u16)value, addr); break;
|
||||
default: Memory::WriteUnchecked_U32(value, addr); break;
|
||||
case 1: mips->space->WriteUnchecked_U8((u8)value, addr); break;
|
||||
case 2: mips->space->WriteUnchecked_U16((u16)value, addr); break;
|
||||
default: mips->space->WriteUnchecked_U32(value, addr); break;
|
||||
}
|
||||
} else if (Memory::IsMMIOAccess(addr)) {
|
||||
MMIO::Write(mips, addr, size, value);
|
||||
@@ -159,6 +159,7 @@ static void RunKernelStore(MIPSState *mips, u32 addr, u32 value) {
|
||||
} while (false)
|
||||
|
||||
u32 IRInterpret(MIPSState *mips, const IRInst *inst, const IRInst *chainArena) {
|
||||
const Memory::AddressSpace &space = *mips->space;
|
||||
#if IR_THREADED_DISPATCH
|
||||
static const void *dispatch[256];
|
||||
static bool dispatchReady = false;
|
||||
@@ -423,25 +424,25 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const IRInst *chainArena) {
|
||||
IR_NEXT;
|
||||
|
||||
IR_CASE(Load8)
|
||||
mips->r[inst->dest] = Memory::ReadUnchecked_U8(mips->r[inst->src1] + inst->constant);
|
||||
mips->r[inst->dest] = space.ReadUnchecked_U8(mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
IR_CASE(Load8Ext)
|
||||
mips->r[inst->dest] = SignExtend8ToU32(Memory::ReadUnchecked_U8(mips->r[inst->src1] + inst->constant));
|
||||
mips->r[inst->dest] = SignExtend8ToU32(space.ReadUnchecked_U8(mips->r[inst->src1] + inst->constant));
|
||||
IR_NEXT;
|
||||
IR_CASE(Load16)
|
||||
mips->r[inst->dest] = Memory::ReadUnchecked_U16(mips->r[inst->src1] + inst->constant);
|
||||
mips->r[inst->dest] = space.ReadUnchecked_U16(mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
IR_CASE(Load16Ext)
|
||||
mips->r[inst->dest] = SignExtend16ToU32(Memory::ReadUnchecked_U16(mips->r[inst->src1] + inst->constant));
|
||||
mips->r[inst->dest] = SignExtend16ToU32(space.ReadUnchecked_U16(mips->r[inst->src1] + inst->constant));
|
||||
IR_NEXT;
|
||||
IR_CASE(Load32)
|
||||
mips->r[inst->dest] = Memory::ReadUnchecked_U32(mips->r[inst->src1] + inst->constant);
|
||||
mips->r[inst->dest] = space.ReadUnchecked_U32(mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
IR_CASE(Load32Left)
|
||||
{
|
||||
u32 addr = mips->r[inst->src1] + inst->constant;
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 mem = space.ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 destMask = 0x00ffffff >> shift;
|
||||
mips->r[inst->dest] = (mips->r[inst->dest] & destMask) | (mem << (24 - shift));
|
||||
IR_NEXT;
|
||||
@@ -450,52 +451,52 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const IRInst *chainArena) {
|
||||
{
|
||||
u32 addr = mips->r[inst->src1] + inst->constant;
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 mem = space.ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 destMask = 0xffffff00 << (24 - shift);
|
||||
mips->r[inst->dest] = (mips->r[inst->dest] & destMask) | (mem >> shift);
|
||||
IR_NEXT;
|
||||
}
|
||||
IR_CASE(Load32Linked)
|
||||
if (inst->dest != MIPS_REG_ZERO)
|
||||
mips->r[inst->dest] = Memory::ReadUnchecked_U32(mips->r[inst->src1] + inst->constant);
|
||||
mips->r[inst->dest] = space.ReadUnchecked_U32(mips->r[inst->src1] + inst->constant);
|
||||
mips->llBit = 1;
|
||||
IR_NEXT;
|
||||
IR_CASE(LoadFloat)
|
||||
mips->f[inst->dest] = Memory::ReadUnchecked_Float(mips->r[inst->src1] + inst->constant);
|
||||
mips->f[inst->dest] = space.ReadUnchecked_Float(mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
|
||||
IR_CASE(Store8)
|
||||
Memory::WriteUnchecked_U8(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
space.WriteUnchecked_U8(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
IR_CASE(Store16)
|
||||
Memory::WriteUnchecked_U16(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
space.WriteUnchecked_U16(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
IR_CASE(Store32)
|
||||
Memory::WriteUnchecked_U32(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
space.WriteUnchecked_U32(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
IR_CASE(Store32Left)
|
||||
{
|
||||
u32 addr = mips->r[inst->src1] + inst->constant;
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 mem = space.ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 memMask = 0xffffff00 << shift;
|
||||
u32 result = (mips->r[inst->src3] >> (24 - shift)) | (mem & memMask);
|
||||
Memory::WriteUnchecked_U32(result, addr & 0xfffffffc);
|
||||
space.WriteUnchecked_U32(result, addr & 0xfffffffc);
|
||||
IR_NEXT;
|
||||
}
|
||||
IR_CASE(Store32Right)
|
||||
{
|
||||
u32 addr = mips->r[inst->src1] + inst->constant;
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 mem = space.ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 memMask = 0x00ffffff >> (24 - shift);
|
||||
u32 result = (mips->r[inst->src3] << shift) | (mem & memMask);
|
||||
Memory::WriteUnchecked_U32(result, addr & 0xfffffffc);
|
||||
space.WriteUnchecked_U32(result, addr & 0xfffffffc);
|
||||
IR_NEXT;
|
||||
}
|
||||
IR_CASE(Store32Conditional)
|
||||
if (mips->llBit) {
|
||||
Memory::WriteUnchecked_U32(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
space.WriteUnchecked_U32(mips->r[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
if (inst->dest != MIPS_REG_ZERO) {
|
||||
mips->r[inst->dest] = 1;
|
||||
}
|
||||
@@ -504,20 +505,20 @@ u32 IRInterpret(MIPSState *mips, const IRInst *inst, const IRInst *chainArena) {
|
||||
}
|
||||
IR_NEXT;
|
||||
IR_CASE(StoreFloat)
|
||||
Memory::WriteUnchecked_Float(mips->f[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
space.WriteUnchecked_Float(mips->f[inst->src3], mips->r[inst->src1] + inst->constant);
|
||||
IR_NEXT;
|
||||
|
||||
IR_CASE(LoadVec4)
|
||||
{
|
||||
u32 base = mips->r[inst->src1] + inst->constant;
|
||||
// This compiles to a nice SSE load/store on x86, and hopefully similar on ARM.
|
||||
memcpy(&mips->f[inst->dest], Memory::GetPointerUnchecked(base), 4 * 4);
|
||||
memcpy(&mips->f[inst->dest], space.GetPointerUnchecked(base), 4 * 4);
|
||||
IR_NEXT;
|
||||
}
|
||||
IR_CASE(StoreVec4)
|
||||
{
|
||||
u32 base = mips->r[inst->src1] + inst->constant;
|
||||
memcpy((float *)Memory::GetPointerUnchecked(base), &mips->f[inst->dest], 4 * 4);
|
||||
memcpy((float *)space.GetPointerUnchecked(base), &mips->f[inst->dest], 4 * 4);
|
||||
IR_NEXT;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ IRJit::IRJit(MIPSState *mipsState, bool compileToNative) : frontend_(mipsState->
|
||||
frontend_.SetOptions(opts);
|
||||
|
||||
profiling_ = !g_Config.sJitProfileFile.empty();
|
||||
blocks_.SetAddressSpace(mipsState->space);
|
||||
}
|
||||
|
||||
IRJit::~IRJit() {
|
||||
@@ -190,7 +191,7 @@ void IRJit::InvalidateBlock(int block_num) {
|
||||
// Before Destroy, which forgets the block's address. Blocks linked to it jump straight in.
|
||||
InvalidateTargetBlock(block_num);
|
||||
blocks_.RemoveBlockFromPageLookup(block_num);
|
||||
block->Destroy();
|
||||
block->Destroy(blocks_.Space());
|
||||
}
|
||||
|
||||
void IRJit::InvalidateCacheExcept(const std::vector<std::pair<u32, u32>> &keep) {
|
||||
@@ -358,7 +359,7 @@ void IRInterpreterJit::RunBlocks() {
|
||||
while (mips->downcount >= 0) {
|
||||
// The block's offset into the IR arena, or 0 for none, or a replacement hook (handled by
|
||||
// compiling a block).
|
||||
const u32 offset = *Memory::GetBlockShadowEntry(mips->pc);
|
||||
const u32 offset = *mips->space->GetBlockShadowEntry(mips->pc);
|
||||
static_assert(Memory::BLOCK_SHADOW_HOOK_NO_JIT == 1, "IR arena reserves offsets 0 and 1");
|
||||
if (offset > Memory::BLOCK_SHADOW_HOOK_NO_JIT) {
|
||||
const IRInst *instPtr = arena_.data() + offset;
|
||||
@@ -407,7 +408,7 @@ void IRInterpreterJit::RunBlocks() {
|
||||
|
||||
void JitBlockTable::Clear() {
|
||||
for (JitBlock &block : blocks_) {
|
||||
block.Destroy();
|
||||
block.Destroy(*space_);
|
||||
}
|
||||
blocks_.clear();
|
||||
byPage_.clear();
|
||||
@@ -473,7 +474,7 @@ std::vector<int> JitBlockTable::FindInvalidatedBlockNumbers(u32 address, u32 len
|
||||
void JitBlockTable::FinalizeBlock(int blockIndex) {
|
||||
// TODO: What's different about preload blocks?
|
||||
JitBlock &block = blocks_[blockIndex];
|
||||
block.Finalize();
|
||||
block.Finalize(*space_);
|
||||
|
||||
u32 startAddr, size;
|
||||
block.GetRange(&startAddr, &size);
|
||||
@@ -551,24 +552,24 @@ int JitBlockTable::GetBlockNumberFromStartAddress(u32 em_address) const {
|
||||
return best;
|
||||
}
|
||||
|
||||
void JitBlock::Finalize() {
|
||||
void JitBlock::Finalize(const Memory::AddressSpace &space) {
|
||||
// Check it wasn't invalidated, in case this is after preload.
|
||||
// TODO: Allow reusing blocks when the code matches hash_ again, instead.
|
||||
if (origAddr_ && Memory::IsValid4AlignedAddress(origAddr_)) {
|
||||
origFirstOpcode_ = Memory::ReadUnchecked_Instruction(origAddr_);
|
||||
_dbg_assert_(entry_ != 0);
|
||||
Memory::WriteBlockShadow(origAddr_, entry_);
|
||||
space.WriteBlockShadow(origAddr_, entry_);
|
||||
} else {
|
||||
WARN_LOG(Log::JIT, "Finalizing invalid block (entry: %d)", entry_);
|
||||
}
|
||||
}
|
||||
|
||||
void JitBlock::Destroy() {
|
||||
void JitBlock::Destroy(const Memory::AddressSpace &space) {
|
||||
if (origAddr_ && Memory::IsValid4AlignedAddress(origAddr_)) {
|
||||
// A block at a mirror may have taken over the entry, leave that alone. One that never got an
|
||||
// entry (the arena or code space filled while compiling it) has nothing in the shadow.
|
||||
if (entry_ != 0)
|
||||
Memory::ClearBlockShadow(origAddr_, entry_);
|
||||
space.ClearBlockShadow(origAddr_, entry_);
|
||||
// Let's mark this invalid so we don't try to clear it again.
|
||||
origAddr_ = 0;
|
||||
}
|
||||
|
||||
+12
-2
@@ -80,8 +80,9 @@ public:
|
||||
return hash_;
|
||||
}
|
||||
|
||||
void Finalize();
|
||||
void Destroy();
|
||||
// Enter the block in the space's block shadow, and take it out.
|
||||
void Finalize(const Memory::AddressSpace &space);
|
||||
void Destroy(const Memory::AddressSpace &space);
|
||||
|
||||
// Only filled in by the IR interpreter, when profiling.
|
||||
JitBlockProfileStats profileStats_{};
|
||||
@@ -105,6 +106,14 @@ public:
|
||||
Clear();
|
||||
}
|
||||
|
||||
// Whose block shadow the blocks go in.
|
||||
void SetAddressSpace(const Memory::AddressSpace *space) {
|
||||
space_ = space;
|
||||
}
|
||||
const Memory::AddressSpace &Space() const {
|
||||
return *space_;
|
||||
}
|
||||
|
||||
void Clear();
|
||||
std::vector<int> FindInvalidatedBlockNumbers(u32 address, u32 length);
|
||||
void FinalizeBlock(int blockNum);
|
||||
@@ -142,6 +151,7 @@ private:
|
||||
u32 AddressToPage(u32 addr) const;
|
||||
std::vector<JitBlock> blocks_;
|
||||
std::unordered_map<u32, std::vector<int>> byPage_;
|
||||
const Memory::AddressSpace *space_ = nullptr;
|
||||
};
|
||||
|
||||
class IRJit;
|
||||
|
||||
@@ -163,6 +163,10 @@ public:
|
||||
virtual ~IRNativeRegCacheBase() {}
|
||||
|
||||
virtual void Start(u32 startPC, const IRInst *instructions, int count);
|
||||
// The guest memory base of the CPU the code is for, where pointerified registers point.
|
||||
void SetMemoryBase(const u8 *base) {
|
||||
membase_ = base;
|
||||
}
|
||||
void SetIRIndex(int index) {
|
||||
irIndex_ = index;
|
||||
}
|
||||
@@ -259,6 +263,7 @@ protected:
|
||||
bool IsValidFPR(IRReg r) const;
|
||||
|
||||
MIPSComp::JitOptions *jo_;
|
||||
const u8 *membase_ = nullptr;
|
||||
// The block being compiled, and its IR.
|
||||
u32 irStartPC_ = 0;
|
||||
const IRInst *irInsts_ = nullptr;
|
||||
|
||||
+18
-18
@@ -379,7 +379,7 @@ namespace MIPSInt {
|
||||
R(rt) = 0;
|
||||
}
|
||||
} else {
|
||||
R(rt) = Memory::ReadUnchecked_U32(addr);
|
||||
R(rt) = mips->space->ReadUnchecked_U32(addr);
|
||||
}
|
||||
}
|
||||
mips->llBit = 1;
|
||||
@@ -392,7 +392,7 @@ namespace MIPSInt {
|
||||
else
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sc");
|
||||
} else {
|
||||
Memory::WriteUnchecked_U32(R(rt), addr);
|
||||
mips->space->WriteUnchecked_U32(R(rt), addr);
|
||||
}
|
||||
// Report success even if the store got dropped - reporting failure just makes
|
||||
// the usual retry loop spin on the same bad address forever.
|
||||
@@ -472,7 +472,7 @@ namespace MIPSInt {
|
||||
R(rt) = 0;
|
||||
break;
|
||||
}
|
||||
R(rt) = SignExtend8ToU32(Memory::ReadUnchecked_U8(addr));
|
||||
R(rt) = SignExtend8ToU32(mips->space->ReadUnchecked_U8(addr));
|
||||
break; //lb
|
||||
case 33:
|
||||
if (!Memory::IsValid2AlignedAddress(addr)) {
|
||||
@@ -485,7 +485,7 @@ namespace MIPSInt {
|
||||
R(rt) = 0;
|
||||
break;
|
||||
}
|
||||
R(rt) = SignExtend16ToU32(Memory::ReadUnchecked_U16(addr));
|
||||
R(rt) = SignExtend16ToU32(mips->space->ReadUnchecked_U16(addr));
|
||||
break; //lh
|
||||
case 35:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
@@ -498,7 +498,7 @@ namespace MIPSInt {
|
||||
R(rt) = 0;
|
||||
break;
|
||||
}
|
||||
R(rt) = Memory::ReadUnchecked_U32(addr);
|
||||
R(rt) = mips->space->ReadUnchecked_U32(addr);
|
||||
break; //lw
|
||||
case 36:
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
@@ -511,7 +511,7 @@ namespace MIPSInt {
|
||||
R(rt) = 0;
|
||||
break;
|
||||
}
|
||||
R(rt) = Memory::ReadUnchecked_U8(addr);
|
||||
R(rt) = mips->space->ReadUnchecked_U8(addr);
|
||||
break; //lbu
|
||||
case 37:
|
||||
if (!Memory::IsValid2AlignedAddress(addr)) {
|
||||
@@ -524,7 +524,7 @@ namespace MIPSInt {
|
||||
R(rt) = 0;
|
||||
break;
|
||||
}
|
||||
R(rt) = Memory::ReadUnchecked_U16(addr);
|
||||
R(rt) = mips->space->ReadUnchecked_U16(addr);
|
||||
break; //lhu
|
||||
case 40:
|
||||
if (!Memory::IsValidAddress(addr)) {
|
||||
@@ -536,7 +536,7 @@ namespace MIPSInt {
|
||||
Core_MemoryException(addr, 1, PC, MemoryExceptionType::WRITE_WORD, "sb");
|
||||
break;
|
||||
}
|
||||
Memory::WriteUnchecked_U8(R(rt), addr);
|
||||
mips->space->WriteUnchecked_U8(R(rt), addr);
|
||||
break; //sb
|
||||
case 41:
|
||||
if (!Memory::IsValid2AlignedAddress(addr)) {
|
||||
@@ -548,7 +548,7 @@ namespace MIPSInt {
|
||||
Core_MemoryException(addr, 2, PC, MemoryExceptionType::WRITE_WORD, "sh");
|
||||
break;
|
||||
}
|
||||
Memory::WriteUnchecked_U16(R(rt), addr);
|
||||
mips->space->WriteUnchecked_U16(R(rt), addr);
|
||||
break; //sh
|
||||
case 43:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
@@ -560,7 +560,7 @@ namespace MIPSInt {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sw");
|
||||
break;
|
||||
}
|
||||
Memory::WriteUnchecked_U32(R(rt), addr);
|
||||
mips->space->WriteUnchecked_U32(R(rt), addr);
|
||||
break; //sw
|
||||
|
||||
// When there's an LWL and an LWR together, we should be able to peephole optimize that
|
||||
@@ -570,7 +570,7 @@ namespace MIPSInt {
|
||||
// Not checking for alignment here - the actual read will be aligned.
|
||||
u32 mem = 0;
|
||||
if (Memory::IsValidAddress(addr)) {
|
||||
mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
mem = mips->space->ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
} else if (Memory::IsMMIOAccess(addr)) {
|
||||
mem = ReadMMIO(mips, addr & 0xfffffffc, 4);
|
||||
} else {
|
||||
@@ -587,7 +587,7 @@ namespace MIPSInt {
|
||||
// Not checking for alignment here - the actual read will be aligned.
|
||||
u32 mem = 0;
|
||||
if (Memory::IsValidAddress(addr)) {
|
||||
mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
mem = mips->space->ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
} else if (Memory::IsMMIOAccess(addr)) {
|
||||
mem = ReadMMIO(mips, addr & 0xfffffffc, 4);
|
||||
} else {
|
||||
@@ -608,9 +608,9 @@ namespace MIPSInt {
|
||||
break;
|
||||
}
|
||||
u32 shift = (addr & 3) * 8;
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 mem = mips->space->ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 result = ( ( u32(R(rt)) >> (24 - shift) ) ) | ( mem & (0xffffff00 << shift) );
|
||||
Memory::WriteUnchecked_U32(result, (addr & 0xfffffffc));
|
||||
mips->space->WriteUnchecked_U32(result, (addr & 0xfffffffc));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -622,9 +622,9 @@ namespace MIPSInt {
|
||||
break;
|
||||
}
|
||||
u32 shift = (addr & 3) << 3;
|
||||
u32 mem = Memory::ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 mem = mips->space->ReadUnchecked_U32(addr & 0xfffffffc);
|
||||
u32 result = ( ( u32(R(rt)) << shift ) | (mem & (0x00ffffff >> (24 - shift)) ) );
|
||||
Memory::WriteUnchecked_U32(result, (addr & 0xfffffffc));
|
||||
mips->space->WriteUnchecked_U32(result, (addr & 0xfffffffc));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -652,7 +652,7 @@ namespace MIPSInt {
|
||||
FI(ft) = 0;
|
||||
break;
|
||||
}
|
||||
FI(ft) = Memory::ReadUnchecked_U32(addr);
|
||||
FI(ft) = mips->space->ReadUnchecked_U32(addr);
|
||||
break; //lwc1
|
||||
case 57:
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
@@ -663,7 +663,7 @@ namespace MIPSInt {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "swc1");
|
||||
break;
|
||||
}
|
||||
Memory::WriteUnchecked_U32(FI(ft), addr);
|
||||
mips->space->WriteUnchecked_U32(FI(ft), addr);
|
||||
break; //swc1
|
||||
default:
|
||||
_dbg_assert_msg_(false,"Trying to interpret FPULS instruction that can't be interpreted");
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace MIPSInt
|
||||
}
|
||||
// It's an LVL
|
||||
for (int i = 0; i < offset + 1; i++) {
|
||||
d[3 - i] = valid ? Memory::ReadUnchecked_Float(addr - 4 * i) : 0.0f;
|
||||
d[3 - i] = valid ? mips->space->ReadUnchecked_Float(addr - 4 * i) : 0.0f;
|
||||
}
|
||||
} else {
|
||||
if (!valid) {
|
||||
@@ -270,7 +270,7 @@ namespace MIPSInt
|
||||
}
|
||||
// It's an LVR
|
||||
for (int i = 0; i < (3 - offset) + 1; i++) {
|
||||
d[i] = valid ? Memory::ReadUnchecked_Float(addr + 4 * i) : 0.0f;
|
||||
d[i] = valid ? mips->space->ReadUnchecked_Float(addr + 4 * i) : 0.0f;
|
||||
}
|
||||
}
|
||||
WriteLoadedVector(mips, d, vt);
|
||||
@@ -288,15 +288,15 @@ namespace MIPSInt
|
||||
}
|
||||
|
||||
#ifndef COMMON_BIG_ENDIAN
|
||||
cf = reinterpret_cast<const float *>(Memory::GetPointerUnchecked(addr));
|
||||
cf = reinterpret_cast<const float *>(mips->space->GetPointerUnchecked(addr));
|
||||
WriteLoadedVector(mips, cf, vt);
|
||||
#else
|
||||
float lvqd[4];
|
||||
|
||||
lvqd[0] = Memory::ReadUnchecked_Float(addr);
|
||||
lvqd[1] = Memory::ReadUnchecked_Float(addr + 4);
|
||||
lvqd[2] = Memory::ReadUnchecked_Float(addr + 8);
|
||||
lvqd[3] = Memory::ReadUnchecked_Float(addr + 12);
|
||||
lvqd[0] = mips->space->ReadUnchecked_Float(addr);
|
||||
lvqd[1] = mips->space->ReadUnchecked_Float(addr + 4);
|
||||
lvqd[2] = mips->space->ReadUnchecked_Float(addr + 8);
|
||||
lvqd[3] = mips->space->ReadUnchecked_Float(addr + 12);
|
||||
|
||||
WriteLoadedVector(mips, lvqd, vt);
|
||||
#endif
|
||||
@@ -315,7 +315,7 @@ namespace MIPSInt
|
||||
// It's an SVL
|
||||
for (int i = 0; i < offset + 1; i++)
|
||||
{
|
||||
Memory::WriteUnchecked_Float(d[3 - i], addr - i * 4);
|
||||
mips->space->WriteUnchecked_Float(d[3 - i], addr - i * 4);
|
||||
}
|
||||
} else {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
@@ -324,7 +324,7 @@ namespace MIPSInt
|
||||
}
|
||||
// It's an SVR
|
||||
for (int i = 0; i < (3 - offset) + 1; i++) {
|
||||
Memory::WriteUnchecked_Float(d[i], addr + 4 * i);
|
||||
mips->space->WriteUnchecked_Float(d[i], addr + 4 * i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -337,7 +337,7 @@ namespace MIPSInt
|
||||
break;
|
||||
}
|
||||
#ifndef COMMON_BIG_ENDIAN
|
||||
f = reinterpret_cast<float *>(Memory::GetPointerWriteUnchecked(addr));
|
||||
f = reinterpret_cast<float *>(mips->space->GetPointerUnchecked(addr));
|
||||
if (f) {
|
||||
ReadVector(mips, f, V_Quad, vt);
|
||||
}
|
||||
@@ -345,10 +345,10 @@ namespace MIPSInt
|
||||
float svqd[4];
|
||||
ReadVector(mips, svqd, V_Quad, vt);
|
||||
|
||||
Memory::WriteUnchecked_Float(svqd[0], addr);
|
||||
Memory::WriteUnchecked_Float(svqd[1], addr + 4);
|
||||
Memory::WriteUnchecked_Float(svqd[2], addr + 8);
|
||||
Memory::WriteUnchecked_Float(svqd[3], addr + 12);
|
||||
mips->space->WriteUnchecked_Float(svqd[0], addr);
|
||||
mips->space->WriteUnchecked_Float(svqd[1], addr + 4);
|
||||
mips->space->WriteUnchecked_Float(svqd[2], addr + 8);
|
||||
mips->space->WriteUnchecked_Float(svqd[3], addr + 12);
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -1750,14 +1750,14 @@ namespace MIPSInt
|
||||
VI(vt) = 0;
|
||||
break;
|
||||
}
|
||||
VI(vt) = Memory::ReadUnchecked_U32(addr);
|
||||
VI(vt) = mips->space->ReadUnchecked_U32(addr);
|
||||
break;
|
||||
case 58: //sv.s
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
Core_MemoryException(addr, 4, PC, MemoryExceptionType::WRITE_WORD, "sv.s");
|
||||
break;
|
||||
}
|
||||
Memory::WriteUnchecked_U32(VI(vt), addr);
|
||||
mips->space->WriteUnchecked_U32(VI(vt), addr);
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted");
|
||||
|
||||
@@ -120,7 +120,7 @@ void LoongArch64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
_assert_(saveOffset <= saveSize);
|
||||
|
||||
// Fixed registers, these are always kept when in Jit context.
|
||||
LI(MEMBASEREG, Memory::base);
|
||||
LI(MEMBASEREG, mipsState->space->base);
|
||||
LI(CTXREG, mipsState);
|
||||
LI(JITBASEREG, GetBasePtr());
|
||||
|
||||
@@ -170,7 +170,7 @@ void LoongArch64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
WriteDebugPC(SCRATCH1);
|
||||
LI(SCRATCH2, (u32)Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
AND(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
LI(SCRATCH2, Memory::blockShadow);
|
||||
LI(SCRATCH2, mipsState->space->blockShadow);
|
||||
ADD_D(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
hooks_.dispatchFetch = GetCodePtr();
|
||||
LD_WU(SCRATCH1, SCRATCH1, 0);
|
||||
|
||||
@@ -57,7 +57,7 @@ void LoongArch64JitBackend::CompIR_Exit(IRInst inst) {
|
||||
SetJumpTarget(inTime);
|
||||
LI(SCRATCH2, (u32)Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
AND(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
LI(SCRATCH2, Memory::blockShadow);
|
||||
LI(SCRATCH2, mips_->space->blockShadow);
|
||||
LDX_WU(SCRATCH1, SCRATCH2, SCRATCH1);
|
||||
FixupBranch found = BNEZ(SCRATCH1);
|
||||
QuickJ(R_RA, dispatcherNoCheck_);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "Common/Serialize/SerializeFuncs.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/MIPS/Interpreter.h"
|
||||
#include "Core/MIPS/MIPSTables.h"
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
@@ -232,6 +233,8 @@ const float cst_constants[32] = {
|
||||
};
|
||||
|
||||
MIPSState::MIPSState() {
|
||||
space = &Memory::g_mainSpace;
|
||||
|
||||
// Initialize vorder
|
||||
|
||||
// This reordering of the VFPU registers in RAM means that instead of being like this:
|
||||
|
||||
@@ -34,6 +34,10 @@ namespace MIPSComp {
|
||||
class JitInterface;
|
||||
}
|
||||
|
||||
namespace Memory {
|
||||
struct AddressSpace;
|
||||
}
|
||||
|
||||
typedef Memory::Opcode MIPSOpcode;
|
||||
|
||||
// A fake opcode the CPU cores fetch in place of an instruction with a replacement function (see
|
||||
@@ -317,6 +321,8 @@ public:
|
||||
|
||||
// Owned. Null on the interpreter.
|
||||
MIPSComp::JitInterface *jit = nullptr;
|
||||
// What this CPU sees of memory. The main CPU's is Memory::g_mainSpace.
|
||||
const Memory::AddressSpace *space = nullptr;
|
||||
};
|
||||
|
||||
// Access control ('private') break standard layout. Let's not allow it, to avoid excessive
|
||||
|
||||
@@ -132,7 +132,7 @@ void RiscVJitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
_assert_(saveOffset <= saveSize);
|
||||
|
||||
// Fixed registers, these are always kept when in Jit context.
|
||||
LI(MEMBASEREG, Memory::base, SCRATCH1);
|
||||
LI(MEMBASEREG, mipsState->space->base, SCRATCH1);
|
||||
LI(CTXREG, mipsState, SCRATCH1);
|
||||
LI(JITBASEREG, GetBasePtr(), SCRATCH1);
|
||||
|
||||
@@ -182,7 +182,7 @@ void RiscVJitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
WriteDebugPC(SCRATCH1);
|
||||
LI(SCRATCH2, (u32)Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
AND(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
LI(SCRATCH2, Memory::blockShadow, X7);
|
||||
LI(SCRATCH2, mipsState->space->blockShadow, X7);
|
||||
ADD(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
hooks_.dispatchFetch = GetCodePtr();
|
||||
LWU(SCRATCH1, SCRATCH1, 0);
|
||||
|
||||
@@ -57,7 +57,7 @@ void RiscVJitBackend::CompIR_Exit(IRInst inst) {
|
||||
SetJumpTarget(inTime);
|
||||
LI(SCRATCH2, (u32)Memory::BLOCK_SHADOW_ENTRY_MASK);
|
||||
AND(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
LI(SCRATCH2, Memory::blockShadow, X7);
|
||||
LI(SCRATCH2, mips_->space->blockShadow, X7);
|
||||
ADD(SCRATCH1, SCRATCH1, SCRATCH2);
|
||||
LWU(SCRATCH1, SCRATCH1, 0);
|
||||
FixupBranch found = BNE(SCRATCH1, R_ZERO);
|
||||
|
||||
@@ -50,6 +50,7 @@ static void ShowPC(void *membase, void *jitbase) {
|
||||
}
|
||||
|
||||
void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
regs_.SetMemoryBase(mipsState->space->base);
|
||||
// This will be used as a writable scratch area, always 32-bit accessible.
|
||||
const u8 *start = AlignCodePage();
|
||||
if (DebugProfilerEnabled()) {
|
||||
@@ -150,7 +151,7 @@ void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||
#if PPSSPP_ARCH(AMD64)
|
||||
// Two x64-specific statically allocated registers.
|
||||
MOV(64, R(MEMBASEREG), ImmPtr(Memory::base));
|
||||
MOV(64, R(MEMBASEREG), ImmPtr(mipsState->space->base));
|
||||
if (jitbaseInR15)
|
||||
MOV(64, R(JITBASEREG), ImmPtr((const void *)jitbase));
|
||||
#endif
|
||||
@@ -221,7 +222,7 @@ void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
ABI_CallFunctionAC(reinterpret_cast<void *>(&ShowPC), R(MEMBASEREG), (u32)jitbase);
|
||||
}
|
||||
#else
|
||||
ABI_CallFunctionCC(reinterpret_cast<void *>(&ShowPC), (u32)Memory::base, (u32)GetBasePtr());
|
||||
ABI_CallFunctionCC(reinterpret_cast<void *>(&ShowPC), (u32)mipsState->space->base, (u32)GetBasePtr());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -230,11 +231,11 @@ void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
|
||||
// Look the block up in the shadow. Its entry is the offset into the code space, or 0 for none.
|
||||
AND(32, R(SCRATCH1), Imm32(Memory::BLOCK_SHADOW_ENTRY_MASK));
|
||||
#if PPSSPP_ARCH(X86)
|
||||
_assert_msg_(Memory::blockShadow != 0, "Block shadow bogus");
|
||||
_assert_msg_(mipsState->space->blockShadow != 0, "Block shadow bogus");
|
||||
hooks_.dispatchFetch = GetCodePtr();
|
||||
MOV(32, R(SCRATCH1), MDisp(SCRATCH1, (u32)Memory::blockShadow));
|
||||
MOV(32, R(SCRATCH1), MDisp(SCRATCH1, (u32)mipsState->space->blockShadow));
|
||||
#elif PPSSPP_ARCH(AMD64)
|
||||
MOV(64, R(RDX), ImmPtr(Memory::blockShadow));
|
||||
MOV(64, R(RDX), ImmPtr(mipsState->space->blockShadow));
|
||||
hooks_.dispatchFetch = GetCodePtr();
|
||||
MOV(32, R(SCRATCH1), MComplex(RDX, SCRATCH1, SCALE_1, 0));
|
||||
#endif
|
||||
|
||||
@@ -64,7 +64,7 @@ Gen::OpArg X64JitBackend::PrepareSrc1Address(IRInst inst) {
|
||||
#if PPSSPP_ARCH(AMD64)
|
||||
addrArg = MDisp(MEMBASEREG, disp & 0x7FFFFFFF);
|
||||
#else
|
||||
addrArg = M(Memory::base + disp);
|
||||
addrArg = M(mips_->space->base + disp);
|
||||
#endif
|
||||
} else if ((jo.cachePointers || src1IsPointer) && !readsFromSrc1 && (!clobbersSrc1 || src1IsPointer)) {
|
||||
X64Reg src1 = regs_.MapGPRAsPointer(inst.src1);
|
||||
@@ -74,12 +74,12 @@ Gen::OpArg X64JitBackend::PrepareSrc1Address(IRInst inst) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
LEA(PTRBITS, SCRATCH1, MDisp(regs_.RX(inst.src1), disp));
|
||||
AND(PTRBITS, R(SCRATCH1), Imm32(Memory::MEMVIEW32_MASK));
|
||||
addrArg = MDisp(SCRATCH1, (intptr_t)Memory::base);
|
||||
addrArg = MDisp(SCRATCH1, (intptr_t)mips_->space->base);
|
||||
#else
|
||||
#if PPSSPP_ARCH(AMD64)
|
||||
addrArg = MComplex(MEMBASEREG, regs_.RX(inst.src1), SCALE_1, disp);
|
||||
#else
|
||||
addrArg = MDisp(regs_.RX(inst.src1), Memory::base + disp);
|
||||
addrArg = MDisp(regs_.RX(inst.src1), mips_->space->base + disp);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ void X64JitBackend::CompIR_ValidateAddress(IRInst inst) {
|
||||
if (regs_.IsGPRMappedAsPointer(inst.src1)) {
|
||||
LEA(PTRBITS, SCRATCH1, MDisp(regs_.RXPtr(inst.src1), inst.constant));
|
||||
#if defined(MASKED_PSP_MEMORY)
|
||||
SUB(PTRBITS, R(SCRATCH1), ImmPtr(Memory::base));
|
||||
SUB(PTRBITS, R(SCRATCH1), ImmPtr(mips_->space->base));
|
||||
#else
|
||||
SUB(PTRBITS, R(SCRATCH1), R(MEMBASEREG));
|
||||
#endif
|
||||
|
||||
@@ -392,14 +392,14 @@ void X64IRRegCache::AdjustNativeRegAsPtr(IRNativeReg nreg, bool state) {
|
||||
// This destroys the value...
|
||||
_dbg_assert_(!nr[nreg].isDirty);
|
||||
emit_->AND(PTRBITS, ::R(r), Imm32(Memory::MEMVIEW32_MASK));
|
||||
emit_->ADD(PTRBITS, ::R(r), ImmPtr(Memory::base));
|
||||
emit_->ADD(PTRBITS, ::R(r), ImmPtr(membase_));
|
||||
#else
|
||||
emit_->ADD(PTRBITS, ::R(r), ::R(MEMBASEREG));
|
||||
#endif
|
||||
} else {
|
||||
#if defined(MASKED_PSP_MEMORY)
|
||||
_dbg_assert_(!nr[nreg].isDirty);
|
||||
emit_->SUB(PTRBITS, ::R(r), ImmPtr(Memory::base));
|
||||
emit_->SUB(PTRBITS, ::R(r), ImmPtr(membase_));
|
||||
#else
|
||||
emit_->SUB(PTRBITS, ::R(r), ::R(MEMBASEREG));
|
||||
#endif
|
||||
|
||||
+18
-2
@@ -48,6 +48,7 @@ namespace Memory {
|
||||
u8* base = nullptr;
|
||||
|
||||
u8 *blockShadow = nullptr;
|
||||
AddressSpace g_mainSpace;
|
||||
static const size_t BLOCK_SHADOW_SIZE = (size_t)BLOCK_SHADOW_MASK + 1;
|
||||
|
||||
// The MemArena class
|
||||
@@ -430,6 +431,8 @@ bool Init(MemMapSetupFlags flags) {
|
||||
INFO_LOG(Log::MemMap, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)",
|
||||
base, m_pPhysicalRAM, m_pUncachedRAM);
|
||||
|
||||
g_mainSpace.base = base;
|
||||
g_mainSpace.blockShadow = blockShadow;
|
||||
MemFault_Init();
|
||||
return true;
|
||||
}
|
||||
@@ -609,6 +612,7 @@ void Shutdown() {
|
||||
base = nullptr;
|
||||
FreeMemoryPages(blockShadow, BLOCK_SHADOW_SIZE);
|
||||
blockShadow = nullptr;
|
||||
g_mainSpace = AddressSpace();
|
||||
DEBUG_LOG(Log::MemMap, "Memory system shut down.");
|
||||
}
|
||||
|
||||
@@ -631,18 +635,30 @@ Opcode ReadUnchecked_Instruction(u32 address) {
|
||||
}
|
||||
|
||||
u32 ReadBlockShadow(u32 address) {
|
||||
return g_mainSpace.ReadBlockShadow(address);
|
||||
}
|
||||
|
||||
void WriteBlockShadow(u32 address, u32 value) {
|
||||
g_mainSpace.WriteBlockShadow(address, value);
|
||||
}
|
||||
|
||||
bool ClearBlockShadow(u32 address, u32 value) {
|
||||
return g_mainSpace.ClearBlockShadow(address, value);
|
||||
}
|
||||
|
||||
u32 AddressSpace::ReadBlockShadow(u32 address) const {
|
||||
if (!blockShadow || !IsValid4AlignedAddress(address))
|
||||
return 0;
|
||||
return *GetBlockShadowEntry(address);
|
||||
}
|
||||
|
||||
void WriteBlockShadow(u32 address, u32 value) {
|
||||
void AddressSpace::WriteBlockShadow(u32 address, u32 value) const {
|
||||
if (!blockShadow || !IsValid4AlignedAddress(address))
|
||||
return;
|
||||
*GetBlockShadowEntry(address) = value;
|
||||
}
|
||||
|
||||
bool ClearBlockShadow(u32 address, u32 value) {
|
||||
bool AddressSpace::ClearBlockShadow(u32 address, u32 value) const {
|
||||
if (!blockShadow || !IsValid4AlignedAddress(address))
|
||||
return false;
|
||||
u32 *entry = GetBlockShadowEntry(address);
|
||||
|
||||
@@ -311,6 +311,43 @@ inline void WriteUnchecked_U8(u8 data, u32 address) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// What one CPU sees of memory: where its addresses point (base) and its block shadow. The main CPU's
|
||||
// is g_mainSpace, which follows base and blockShadow above. The CPU cores go through their
|
||||
// MIPSState's, so another CPU (the Media Engine) can have its own.
|
||||
struct AddressSpace {
|
||||
u8 *base = nullptr;
|
||||
u8 *blockShadow = nullptr;
|
||||
|
||||
u8 *GetPointerUnchecked(u32 address) const {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
return base + (address & MEMVIEW32_MASK);
|
||||
#else
|
||||
return base + address;
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 ReadUnchecked_U8(u32 address) const { return *GetPointerUnchecked(address); }
|
||||
u16 ReadUnchecked_U16(u32 address) const { return *(u16_le *)GetPointerUnchecked(DepthMirrored16(address)); }
|
||||
u32 ReadUnchecked_U32(u32 address) const { return *(u32_le *)GetPointerUnchecked(address); }
|
||||
u64 ReadUnchecked_U64(u32 address) const { return *(u64_le *)GetPointerUnchecked(address); }
|
||||
float ReadUnchecked_Float(u32 address) const { return *(float_le *)GetPointerUnchecked(address); }
|
||||
void WriteUnchecked_U8(u8 data, u32 address) const { *GetPointerUnchecked(address) = data; }
|
||||
void WriteUnchecked_U16(u16 data, u32 address) const { *(u16_le *)GetPointerUnchecked(DepthMirrored16(address)) = data; }
|
||||
void WriteUnchecked_U32(u32 data, u32 address) const { *(u32_le *)GetPointerUnchecked(address) = data; }
|
||||
void WriteUnchecked_U64(u64 data, u32 address) const { *(u64_le *)GetPointerUnchecked(address) = data; }
|
||||
void WriteUnchecked_Float(float data, u32 address) const { *(float_le *)GetPointerUnchecked(address) = data; }
|
||||
|
||||
u32 *GetBlockShadowEntry(u32 address) const {
|
||||
return (u32 *)(blockShadow + (address & BLOCK_SHADOW_ENTRY_MASK));
|
||||
}
|
||||
// As the functions of the same name above, for this space's shadow.
|
||||
u32 ReadBlockShadow(u32 address) const;
|
||||
void WriteBlockShadow(u32 address, u32 value) const;
|
||||
bool ClearBlockShadow(u32 address, u32 value) const;
|
||||
};
|
||||
|
||||
extern AddressSpace g_mainSpace;
|
||||
|
||||
void WriteOrException_U8(const u8 data, const u32 address);
|
||||
void WriteOrException_U16(const u16 data, const u32 address);
|
||||
void WriteOrException_U32(const u32 data, const u32 address);
|
||||
|
||||
Reference in new issue
Block a user