CPU: Add additional instruction decoder helpers
This commit is contained in:
parent
9fd1d606d7
commit
e044858953
|
@ -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<VirtualMemoryAddress, 4> bases = {{0x00000000, 0x80000000, 0xA0000000, 0xE0000000}};
|
||||
return bases[static_cast<u32>(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);
|
||||
|
|
|
@ -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<VirtualMemoryAddress> 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<u32>(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<u32>(instruction.i.rs.GetValue())] + instruction.i.imm_sext32()) & ~UINT32_C(3);
|
||||
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool InstructionHasLoadDelay(const Instruction& instruction)
|
||||
{
|
||||
switch (instruction.op)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "common/bitfield.h"
|
||||
#include "types.h"
|
||||
#include <optional>
|
||||
|
||||
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<VirtualMemoryAddress> GetLoadStoreEffectiveAddress(const Instruction& instruction,
|
||||
const Registers* regs);
|
||||
|
||||
enum class Cop0Reg : u8
|
||||
{
|
||||
BPC = 3,
|
||||
|
|
Loading…
Reference in New Issue