diff --git a/src/core/cpu_core_private.h b/src/core/cpu_core_private.h index 2b7da61ef..7e8ecd15f 100644 --- a/src/core/cpu_core_private.h +++ b/src/core/cpu_core_private.h @@ -64,7 +64,41 @@ TickCount GetICacheFillTicks(VirtualMemoryAddress address); u32 FillICache(VirtualMemoryAddress address); void CheckAndUpdateICacheTags(u32 line_count, TickCount uncached_ticks); -// defined in cpu_memory.cpp - memory access functions which return false if an exception was thrown. +ALWAYS_INLINE Segment GetSegmentForAddress(VirtualMemoryAddress address) +{ + switch ((address >> 29)) + { + case 0x00: // KUSEG 0M-512M + case 0x01: // KUSEG 512M-1024M + case 0x02: // KUSEG 1024M-1536M + case 0x03: // KUSEG 1536M-2048M + return Segment::KUSEG; + + case 0x04: // KSEG0 - physical memory cached + return Segment::KSEG0; + + case 0x05: // KSEG1 - physical memory uncached + return Segment::KSEG1; + + case 0x06: // KSEG2 + case 0x07: // KSEG2 + default: + return Segment::KSEG2; + } +} + +ALWAYS_INLINE PhysicalMemoryAddress VirtualAddressToPhysical(VirtualMemoryAddress address) +{ + return (address & PHYSICAL_MEMORY_ADDRESS_MASK); +} + +ALWAYS_INLINE VirtualMemoryAddress PhysicalAddressToVirtual(PhysicalMemoryAddress address, Segment segment) +{ + static constexpr std::array bases = {{0x00000000, 0x80000000, 0xA0000000, 0xE0000000}}; + return bases[static_cast(segment)] | address; +} + +// defined in bus.cpp - memory access functions which return false if an exception was thrown. bool FetchInstruction(); bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value); bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value); diff --git a/src/core/cpu_types.cpp b/src/core/cpu_types.cpp index 1d4436686..db9960e45 100644 --- a/src/core/cpu_types.cpp +++ b/src/core/cpu_types.cpp @@ -119,6 +119,24 @@ u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_p } } +bool IsCallInstruction(const Instruction& instruction) +{ + return (instruction.op == InstructionOp::funct && instruction.r.funct == InstructionFunct::jalr) || + (instruction.op == InstructionOp::jal); +} + +bool IsReturnInstruction(const Instruction& instruction) +{ + if (instruction.op != InstructionOp::funct) + return false; + + // j(al)r ra + if (instruction.r.funct == InstructionFunct::jr || instruction.r.funct == InstructionFunct::jalr) + return (instruction.r.rs == Reg::ra); + + return false; +} + bool IsMemoryLoadInstruction(const Instruction& instruction) { switch (instruction.op) @@ -159,6 +177,33 @@ bool IsMemoryStoreInstruction(const Instruction& instruction) } } +std::optional GetLoadStoreEffectiveAddress(const Instruction& instruction, const Registers* regs) +{ + switch (instruction.op) + { + case InstructionOp::lb: + case InstructionOp::lh: + case InstructionOp::lw: + case InstructionOp::lbu: + case InstructionOp::lhu: + case InstructionOp::lwc2: + case InstructionOp::sb: + case InstructionOp::sh: + case InstructionOp::sw: + case InstructionOp::swc2: + return (regs->r[static_cast(instruction.i.rs.GetValue())] + instruction.i.imm_sext32()); + + case InstructionOp::lwl: + case InstructionOp::lwr: + case InstructionOp::swl: + case InstructionOp::swr: + return (regs->r[static_cast(instruction.i.rs.GetValue())] + instruction.i.imm_sext32()) & ~UINT32_C(3); + + default: + return std::nullopt; + } +} + bool InstructionHasLoadDelay(const Instruction& instruction) { switch (instruction.op) diff --git a/src/core/cpu_types.h b/src/core/cpu_types.h index 874bb6f91..9fbb0b12c 100644 --- a/src/core/cpu_types.h +++ b/src/core/cpu_types.h @@ -1,6 +1,7 @@ #pragma once #include "common/bitfield.h" #include "types.h" +#include namespace CPU { @@ -14,6 +15,14 @@ enum : u32 INSTRUCTION_SIZE = sizeof(u32) }; +enum class Segment +{ + KUSEG, // virtual memory + KSEG0, // physical memory cached + KSEG1, // physical memory uncached + KSEG2 +}; + enum class Reg : u8 { zero, @@ -215,6 +224,8 @@ bool IsBranchInstruction(const Instruction& instruction); bool IsUnconditionalBranchInstruction(const Instruction& instruction); bool IsDirectBranchInstruction(const Instruction& instruction); u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_pc); +bool IsCallInstruction(const Instruction& instruction); +bool IsReturnInstruction(const Instruction& instruction); bool IsMemoryLoadInstruction(const Instruction& instruction); bool IsMemoryStoreInstruction(const Instruction& instruction); bool InstructionHasLoadDelay(const Instruction& instruction); @@ -272,6 +283,9 @@ struct Registers }; }; +std::optional GetLoadStoreEffectiveAddress(const Instruction& instruction, + const Registers* regs); + enum class Cop0Reg : u8 { BPC = 3,