CPU: Add additional instruction decoder helpers

This commit is contained in:
Connor McLaughlin 2020-12-17 01:11:50 +10:00
parent 9fd1d606d7
commit e044858953
3 changed files with 94 additions and 1 deletions

View File

@ -64,7 +64,41 @@ TickCount GetICacheFillTicks(VirtualMemoryAddress address);
u32 FillICache(VirtualMemoryAddress address); u32 FillICache(VirtualMemoryAddress address);
void CheckAndUpdateICacheTags(u32 line_count, TickCount uncached_ticks); 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 FetchInstruction();
bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value); bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value);
bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value); bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value);

View File

@ -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) bool IsMemoryLoadInstruction(const Instruction& instruction)
{ {
switch (instruction.op) 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) bool InstructionHasLoadDelay(const Instruction& instruction)
{ {
switch (instruction.op) switch (instruction.op)

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common/bitfield.h" #include "common/bitfield.h"
#include "types.h" #include "types.h"
#include <optional>
namespace CPU { namespace CPU {
@ -14,6 +15,14 @@ enum : u32
INSTRUCTION_SIZE = sizeof(u32) INSTRUCTION_SIZE = sizeof(u32)
}; };
enum class Segment
{
KUSEG, // virtual memory
KSEG0, // physical memory cached
KSEG1, // physical memory uncached
KSEG2
};
enum class Reg : u8 enum class Reg : u8
{ {
zero, zero,
@ -215,6 +224,8 @@ bool IsBranchInstruction(const Instruction& instruction);
bool IsUnconditionalBranchInstruction(const Instruction& instruction); bool IsUnconditionalBranchInstruction(const Instruction& instruction);
bool IsDirectBranchInstruction(const Instruction& instruction); bool IsDirectBranchInstruction(const Instruction& instruction);
u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_pc); u32 GetBranchInstructionTarget(const Instruction& instruction, u32 instruction_pc);
bool IsCallInstruction(const Instruction& instruction);
bool IsReturnInstruction(const Instruction& instruction);
bool IsMemoryLoadInstruction(const Instruction& instruction); bool IsMemoryLoadInstruction(const Instruction& instruction);
bool IsMemoryStoreInstruction(const Instruction& instruction); bool IsMemoryStoreInstruction(const Instruction& instruction);
bool InstructionHasLoadDelay(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 enum class Cop0Reg : u8
{ {
BPC = 3, BPC = 3,