mirror of
https://github.com/google0101-ryan/Emotional.git
synced 2024-05-11 09:05:28 -04:00
First block compiled with new JIT
This commit is contained in:
parent
e15268d451
commit
12aeadd143
|
@ -9,11 +9,12 @@ set(SOURCES src/main.cpp
|
|||
src/emu/memory/Bus.cpp
|
||||
src/emu/System.cpp
|
||||
src/emu/cpu/ee/EmotionEngine.cpp
|
||||
src/emu/cpu/ee/EEJit.cpp
|
||||
src/emu/cpu/ee/x64/EEJitx64.cpp
|
||||
src/emu/cpu/ee/x64/RegAllocator.cpp
|
||||
src/emu/cpu/ee/dmac.cpp
|
||||
src/emu/cpu/ee/vu.cpp
|
||||
src/emu/cpu/ee/vif.cpp
|
||||
src/emu/cpu/ee/x64/reg_alloc.cpp
|
||||
src/emu/cpu/ee/x64/emit.cpp
|
||||
src/emu/cpu/iop/cpu.cpp
|
||||
src/emu/cpu/iop/opcodes.cpp
|
||||
src/emu/cpu/iop/dma.cpp
|
||||
|
@ -22,14 +23,14 @@ set(SOURCES src/main.cpp
|
|||
src/emu/gpu/gs.cpp
|
||||
src/emu/dev/sif.cpp
|
||||
src/emu/dev/cdvd.cpp
|
||||
src/emu/dev/sio2.cpp
|
||||
src/emu/cpu/ee/ee_interpret.cpp
|
||||
src/emu/cpu/ee/ee_opcode.cpp)
|
||||
src/emu/dev/sio2.cpp)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
add_definitions(-DEE_JIT=64)
|
||||
|
||||
add_executable(ps2 ${SOURCES})
|
||||
set(TARGET_NAME ps2)
|
||||
|
||||
|
@ -41,7 +42,7 @@ target_link_libraries(ps2 ${SDL2_LIBRARIES})
|
|||
if(MSVC)
|
||||
target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX)
|
||||
else()
|
||||
target_compile_options(${TARGET_NAME} PRIVATE -pg -O0 -mincoming-stack-boundary=3)
|
||||
target_compile_options(${TARGET_NAME} PRIVATE -pg -O3 -mincoming-stack-boundary=3)
|
||||
target_link_options(${TARGET_NAME} PRIVATE -pg)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "System.h"
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
#include <emu/cpu/ee/ee_interpret.h>
|
||||
#include <emu/sched/scheduler.h>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
#include <emu/cpu/iop/cpu.h>
|
||||
|
@ -106,11 +105,7 @@ void System::LoadBios(std::string biosName)
|
|||
void System::Reset()
|
||||
{
|
||||
Scheduler::InitScheduler();
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::Reset();
|
||||
#else
|
||||
EEInterpreter::Reset();
|
||||
#endif
|
||||
|
||||
IOP_MANAGEMENT::Reset();
|
||||
|
||||
|
@ -131,27 +126,20 @@ void System::Reset()
|
|||
|
||||
void System::Run()
|
||||
{
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::Clock();
|
||||
#else
|
||||
while (1)
|
||||
{
|
||||
size_t cycles = Scheduler::GetNextTimestamp();
|
||||
// size_t cycles = Scheduler::GetNextTimestamp();
|
||||
|
||||
EEInterpreter::Clock(cycles);
|
||||
int true_cycles = EmotionEngine::Clock(32);
|
||||
IOP_MANAGEMENT::Clock(true_cycles / 2);
|
||||
|
||||
Scheduler::CheckScheduler(cycles);
|
||||
Scheduler::CheckScheduler(true_cycles);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void System::Dump()
|
||||
{
|
||||
#ifdef EE_JIT
|
||||
EmotionEngine::Dump();
|
||||
#else
|
||||
EEInterpreter::Dump();
|
||||
#endif
|
||||
Bus::Dump();
|
||||
VectorUnit::Dump();
|
||||
IOP_MANAGEMENT::Dump();
|
||||
|
|
226
src/emu/cpu/ee/EEJit.cpp
Normal file
226
src/emu/cpu/ee/EEJit.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
#include "EEJit.h"
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
|
||||
#if (EE_JIT == 64)
|
||||
#include <emu/cpu/ee/x64/EEJitx64.h>
|
||||
#endif
|
||||
|
||||
#include <emu/cpu/iop/opcode.h>
|
||||
|
||||
float convert(uint32_t value)
|
||||
{
|
||||
switch(value & 0x7F800000)
|
||||
{
|
||||
case 0x0:
|
||||
value &= 0x80000000;
|
||||
return *(float*)&value;
|
||||
case 0x7F800000:
|
||||
value = (value & 0x80000000)|0x7F7FFFFF;
|
||||
return *(float*)&value;
|
||||
default:
|
||||
return *(float*)&value;
|
||||
}
|
||||
}
|
||||
|
||||
Block *curBlock;
|
||||
|
||||
std::unordered_map<uint32_t, Block*> blocks;
|
||||
|
||||
void EmitPrologue()
|
||||
{
|
||||
IRInstruction instr = IRInstruction::Build({}, IRInstrs::PROLOGUE);
|
||||
curBlock->instructions.push_back(instr);
|
||||
}
|
||||
|
||||
// 0x05
|
||||
void EmitBEQ(Opcode op)
|
||||
{
|
||||
IRValue imm(IRValue::Imm);
|
||||
imm.SetImm32(op.i_type.imm << 2);
|
||||
|
||||
IRValue rt(IRValue::Reg);
|
||||
rt.SetReg(op.r_type.rt);
|
||||
|
||||
IRValue rs(IRValue::Reg);
|
||||
rs.SetReg(op.r_type.rs);
|
||||
|
||||
auto instr = IRInstruction::Build({rs, rt, imm}, IRInstrs::BRANCH);
|
||||
instr.b_type = IRInstruction::BranchType::EQ;
|
||||
curBlock->instructions.push_back(instr);
|
||||
|
||||
printf("beq %s,%s,pc+%d\n", EmotionEngine::Reg(op.i_type.rs), EmotionEngine::Reg(op.i_type.rt), (int32_t)imm.GetImm());
|
||||
}
|
||||
|
||||
// 0x0A
|
||||
void EmitSLTI(Opcode op)
|
||||
{
|
||||
IRValue imm(IRValue::Imm);
|
||||
imm.SetImm64(op.i_type.imm);
|
||||
|
||||
IRValue src(IRValue::Reg);
|
||||
src.SetReg(op.i_type.rs);
|
||||
|
||||
IRValue dst(IRValue::Reg);
|
||||
dst.SetReg(op.i_type.rt);
|
||||
|
||||
auto instr = IRInstruction::Build({dst, src, imm}, IRInstrs::SLT);
|
||||
instr.is_unsigned = false;
|
||||
curBlock->instructions.push_back(instr);
|
||||
|
||||
printf("slti %s,%s,0x%08lx\n", EmotionEngine::Reg(op.i_type.rt), EmotionEngine::Reg(op.i_type.rs), (int64_t)(int16_t)op.i_type.imm);
|
||||
}
|
||||
|
||||
// 0x0F
|
||||
void EmitLUI(Opcode op)
|
||||
{
|
||||
IRValue rt(IRValue::Reg);
|
||||
rt.SetReg(op.i_type.rt);
|
||||
|
||||
IRValue imm(IRValue::Imm);
|
||||
imm.SetImm64From32(op.i_type.imm << 16);
|
||||
|
||||
auto instr = IRInstruction::Build({rt, imm}, IRInstrs::MOVE);
|
||||
curBlock->instructions.push_back(instr);
|
||||
|
||||
printf("lui %s,0x%08lx\n", EmotionEngine::Reg(rt.GetReg()), imm.GetImm64());
|
||||
}
|
||||
|
||||
// 0x10 0x00
|
||||
void EmitMFC0(Opcode op)
|
||||
{
|
||||
int dest = op.r_type.rt;
|
||||
int src = op.r_type.rd;
|
||||
|
||||
IRValue dst_val(IRValue::Cop0Reg);
|
||||
dst_val.SetReg(dest);
|
||||
|
||||
IRValue src_val(IRValue::Reg);
|
||||
src_val.SetReg(src);
|
||||
|
||||
auto instr = IRInstruction::Build({src_val, dst_val}, IRInstrs::MOVE);
|
||||
curBlock->instructions.push_back(instr);
|
||||
|
||||
printf("mfc0 %s,r%d\n", EmotionEngine::Reg(dest), src);
|
||||
}
|
||||
|
||||
// 0x10
|
||||
void EmitCOP0(Opcode op)
|
||||
{
|
||||
switch (op.r_type.func)
|
||||
{
|
||||
case 0x00:
|
||||
EmitMFC0(op);
|
||||
break;
|
||||
default:
|
||||
printf("[EEJIT]: Cannot emit unknown cop0 opcode 0x%08x\n", op.r_type.func);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsBranch(Opcode op)
|
||||
{
|
||||
switch (op.opcode)
|
||||
{
|
||||
case 0x05:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool branchDelayed = false;
|
||||
|
||||
// Compile and dispatch `cycles` instructions
|
||||
// If we encounter a branch, return that as the true number of cycles
|
||||
int EEJit::Clock(int cycles)
|
||||
{
|
||||
// Create a new block
|
||||
curBlock = new Block();
|
||||
curBlock->addr = EmotionEngine::GetState()->pc;
|
||||
curBlock->instructions.clear();
|
||||
|
||||
uint32_t start = curBlock->addr;
|
||||
|
||||
EmitPrologue();
|
||||
|
||||
int cycle = 0;
|
||||
for (; cycle < cycles; cycle++)
|
||||
{
|
||||
printf("0x%08x:\t", start);
|
||||
// TODO: Move this into its own assembly routine
|
||||
uint32_t instr = Bus::Read32(start);
|
||||
start += 4;
|
||||
|
||||
Opcode op;
|
||||
op.full = instr;
|
||||
|
||||
if (!instr)
|
||||
{
|
||||
printf("nop\n");
|
||||
if (branchDelayed)
|
||||
{
|
||||
branchDelayed = false;
|
||||
cycle++;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (op.opcode)
|
||||
{
|
||||
case 0x05:
|
||||
EmitBEQ(op);
|
||||
break;
|
||||
case 0x0A:
|
||||
EmitSLTI(op);
|
||||
break;
|
||||
case 0x0F:
|
||||
EmitLUI(op);
|
||||
break;
|
||||
case 0x10:
|
||||
EmitCOP0(op);
|
||||
break;
|
||||
default:
|
||||
printf("[EEJIT]: Cannot emit unknown opcode 0x%02x (0x%08x)\n", op.opcode, op.full);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (branchDelayed)
|
||||
{
|
||||
branchDelayed = false;
|
||||
cycle++;
|
||||
break;
|
||||
}
|
||||
|
||||
branchDelayed = IsBranch(op);
|
||||
}
|
||||
|
||||
// Emit epilogue
|
||||
curBlock->instructions.push_back(IRInstruction::Build({}, IRInstrs::EPILOGUE));
|
||||
// JIT the block into host code
|
||||
#if EE_JIT == 64
|
||||
EEJitX64::TranslateBlock(curBlock);
|
||||
#endif
|
||||
// Cache the block
|
||||
// Run it
|
||||
curBlock->entryPoint(EmotionEngine::GetState(), start);
|
||||
|
||||
return cycle;
|
||||
}
|
||||
|
||||
void EEJit::Initialize()
|
||||
{
|
||||
#if EE_JIT == 64
|
||||
EEJitX64::Initialize();
|
||||
#else
|
||||
#error Please use x64! x86/AARCH64 currently unsupported!
|
||||
#endif
|
||||
}
|
||||
|
||||
void EEJit::Dump()
|
||||
{
|
||||
#if EE_JIT == 64
|
||||
EEJitX64::Dump();
|
||||
#endif
|
||||
}
|
143
src/emu/cpu/ee/EEJit.h
Normal file
143
src/emu/cpu/ee/EEJit.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
enum IRInstrs
|
||||
{
|
||||
PROLOGUE,
|
||||
EPILOGUE,
|
||||
MOVE, // General purpose move (COP0, r<-imm, etc)
|
||||
SLT, // Compare and set register (can be immediate or reg, signed or unsigned)
|
||||
BRANCH, // PC-Relative branch on condition = true
|
||||
};
|
||||
|
||||
struct IRValue
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Imm,
|
||||
Reg,
|
||||
Cop0Reg,
|
||||
Cop1Reg,
|
||||
Float
|
||||
};
|
||||
private:
|
||||
union
|
||||
{
|
||||
uint64_t imm;
|
||||
int register_num;
|
||||
float fp_value;
|
||||
int cop_regnum;
|
||||
} value;
|
||||
|
||||
Type type;
|
||||
public:
|
||||
IRValue(Type type)
|
||||
: type(type) {}
|
||||
|
||||
bool IsImm() {return type == Imm;}
|
||||
bool IsCop0() {return type == Cop0Reg;}
|
||||
bool IsCop1() {return type == Cop1Reg;}
|
||||
bool IsReg() {return type == Reg;}
|
||||
bool IsFloat() {return type == Float;}
|
||||
// Can be used for guest, COP0, and COP1 registers
|
||||
void SetReg(uint32_t reg) {value.register_num = reg;}
|
||||
void SetImm(uint16_t imm) {value.imm = (int32_t)(int16_t)imm;}
|
||||
void SetImm64(uint16_t imm) {value.imm = (int64_t)(int16_t)imm;}
|
||||
void SetImm64From32(uint32_t imm) {value.imm = (int64_t)(int32_t)imm;}
|
||||
void SetImm32(uint32_t imm) {value.imm = imm;}
|
||||
void SetImmUnsigned(uint16_t imm) {value.imm = (uint32_t)imm;}
|
||||
void SetImm32Unsigned(uint32_t imm) {value.imm = imm;}
|
||||
|
||||
|
||||
uint32_t GetImm() {return value.imm;}
|
||||
uint64_t GetImm64() {return value.imm;}
|
||||
uint32_t GetReg() {return value.register_num;}
|
||||
};
|
||||
|
||||
struct IRInstruction
|
||||
{
|
||||
// The IR instruction
|
||||
uint8_t instr;
|
||||
// Arguments are left -> right
|
||||
std::vector<IRValue> args;
|
||||
|
||||
bool should_link = false;
|
||||
bool is_logical = false;
|
||||
bool is_unsigned = false;
|
||||
bool is_likely = false;
|
||||
bool is_mmi_divmul = false;
|
||||
|
||||
// Shift direction
|
||||
enum Direction
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
} direction;
|
||||
|
||||
// Branch condition
|
||||
enum BranchType
|
||||
{
|
||||
NE = 0,
|
||||
EQ = 1,
|
||||
GE = 2,
|
||||
LE = 3,
|
||||
GT = 4,
|
||||
LT = 5,
|
||||
} b_type;
|
||||
|
||||
// MOVN, MOVZ
|
||||
enum class MovCond : int
|
||||
{
|
||||
N = 1,
|
||||
Z = 2,
|
||||
} mov_cond;
|
||||
|
||||
// Memory access sizes
|
||||
enum AccessSize
|
||||
{
|
||||
U64 = 0,
|
||||
U32 = 1,
|
||||
U16 = 2,
|
||||
U8 = 3,
|
||||
U128 = 4,
|
||||
} access_size;
|
||||
|
||||
enum InstrSize // ADDIU vs DADDIU, etc
|
||||
{
|
||||
Size64,
|
||||
Size32
|
||||
} size = Size32;
|
||||
|
||||
static IRInstruction Build(std::vector<IRValue> args, uint8_t i_type)
|
||||
{
|
||||
IRInstruction i;
|
||||
i.instr = i_type;
|
||||
i.args = args;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
uint32_t opcode;
|
||||
};
|
||||
|
||||
typedef void (*blockEntry)(void* statePtr, uint32_t blockPC);
|
||||
|
||||
struct Block
|
||||
{
|
||||
uint32_t addr;
|
||||
std::vector<IRInstruction> instructions;
|
||||
blockEntry entryPoint;
|
||||
};
|
||||
|
||||
namespace EEJit
|
||||
{
|
||||
|
||||
int Clock(int cycles);
|
||||
|
||||
void Initialize();
|
||||
void Dump();
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -9,407 +9,6 @@
|
|||
#include <util/uint128.h>
|
||||
#include <3party/robin_hood.h>
|
||||
|
||||
namespace EE_JIT
|
||||
{
|
||||
|
||||
enum IRInstrs
|
||||
{
|
||||
MOV = 0,
|
||||
NOP = 1,
|
||||
SLTI = 2,
|
||||
SaveHostRegs = 3,
|
||||
RestoreHostRegs = 4,
|
||||
BranchConditional = 5,
|
||||
IncPC = 6,
|
||||
OR = 7,
|
||||
JumpAlways = 8,
|
||||
Add = 9,
|
||||
MemoryStore = 10,
|
||||
JumpImm = 11, // We have to do some fancy or'ing for JAL, J so it can't share an op with JR, JALR
|
||||
AND = 12,
|
||||
Shift = 13,
|
||||
Mult = 14,
|
||||
Div = 15,
|
||||
UhOh = 16,
|
||||
MemoryLoad = 17,
|
||||
MoveFromLo = 18,
|
||||
BranchRegImm = 19,
|
||||
MoveFromHi = 20,
|
||||
Sub = 21,
|
||||
MovCond = 22,
|
||||
Div1 = 23,
|
||||
Shift64 = 24,
|
||||
XOR = 25,
|
||||
UpdateCopCount = 26,
|
||||
POR = 27,
|
||||
NOR = 28,
|
||||
LDL = 29,
|
||||
LDR = 30,
|
||||
SDL = 31,
|
||||
SDR = 32,
|
||||
PADDUSW = 33,
|
||||
DI = 34,
|
||||
ERET = 35,
|
||||
SYSCALL = 36,
|
||||
EI = 37,
|
||||
PLZCW = 38,
|
||||
PMFHI = 39,
|
||||
PMFLO = 40,
|
||||
MTHI = 41,
|
||||
MTLO = 42,
|
||||
PCPYLD = 43,
|
||||
PSUBB = 44,
|
||||
PNOR = 45,
|
||||
PAND = 46,
|
||||
PCPYUD = 47,
|
||||
BC0T = 48,
|
||||
BC0F = 49,
|
||||
PCPYH = 50,
|
||||
CFC2 = 51,
|
||||
CTC2 = 52,
|
||||
VISWR = 53,
|
||||
QMFC2 = 54,
|
||||
QMTC2 = 55,
|
||||
VSUB = 56,
|
||||
VSQI = 57,
|
||||
VIADD = 58,
|
||||
ADDAS = 59,
|
||||
PADDSB = 60,
|
||||
MADD = 61,
|
||||
MADDS = 62,
|
||||
CVTS = 63,
|
||||
MULS = 64,
|
||||
CVTW = 65,
|
||||
DIVS = 66,
|
||||
MOVS = 67,
|
||||
ADDS = 68,
|
||||
SUBS = 69,
|
||||
NEGS = 70,
|
||||
LQC2 = 71,
|
||||
VMULAX = 72,
|
||||
VMADDAZ = 73,
|
||||
VMADDAY = 74,
|
||||
VMADDW = 75,
|
||||
SQC2 = 76,
|
||||
VMADDZ = 77,
|
||||
VMADDAX = 78,
|
||||
VMULAW = 79,
|
||||
VCLIPW = 80,
|
||||
CLES = 81,
|
||||
BC1F = 82,
|
||||
CEQS = 83,
|
||||
BC1T = 84,
|
||||
};
|
||||
|
||||
struct IRValue
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Imm,
|
||||
Reg,
|
||||
Cop0Reg,
|
||||
Cop1Reg,
|
||||
Float
|
||||
};
|
||||
private:
|
||||
union
|
||||
{
|
||||
uint64_t imm;
|
||||
int register_num;
|
||||
float fp_value;
|
||||
int cop_regnum;
|
||||
} value;
|
||||
|
||||
Type type;
|
||||
public:
|
||||
IRValue(Type type)
|
||||
: type(type) {}
|
||||
|
||||
bool IsImm() {return type == Imm;}
|
||||
bool IsCop0() {return type == Cop0Reg;}
|
||||
bool IsCop1() {return type == Cop1Reg;}
|
||||
bool IsReg() {return type == Reg;}
|
||||
bool IsFloat() {return type == Float;}
|
||||
// Can be used for guest, COP0, and COP1 registers
|
||||
void SetReg(uint32_t reg) {value.register_num = reg;}
|
||||
void SetImm(uint16_t imm) {value.imm = (int32_t)(int16_t)imm;}
|
||||
void SetImm32(uint32_t imm) {value.imm = imm;}
|
||||
void SetImmUnsigned(uint16_t imm) {value.imm = (uint32_t)imm;}
|
||||
void SetImm32Unsigned(uint32_t imm) {value.imm = imm;}
|
||||
|
||||
|
||||
uint32_t GetImm() {return value.imm;}
|
||||
uint32_t GetReg() {return value.register_num;}
|
||||
};
|
||||
|
||||
struct IRInstruction
|
||||
{
|
||||
// The IR instruction
|
||||
uint8_t instr;
|
||||
// Arguments are left -> right
|
||||
std::vector<IRValue> args;
|
||||
|
||||
bool should_link = false;
|
||||
bool is_logical = false;
|
||||
bool is_unsigned = false;
|
||||
bool is_likely = false;
|
||||
bool is_mmi_divmul = false;
|
||||
|
||||
// Shift direction
|
||||
enum Direction
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
} direction;
|
||||
|
||||
// Branch condition
|
||||
enum BranchType
|
||||
{
|
||||
NE = 0,
|
||||
EQ = 1,
|
||||
GE = 2,
|
||||
LE = 3,
|
||||
GT = 4,
|
||||
LT = 5,
|
||||
} b_type;
|
||||
|
||||
// MOVN, MOVZ
|
||||
enum class MovCond : int
|
||||
{
|
||||
N = 1,
|
||||
Z = 2,
|
||||
} mov_cond;
|
||||
|
||||
// Memory access sizes
|
||||
enum AccessSize
|
||||
{
|
||||
U64 = 0,
|
||||
U32 = 1,
|
||||
U16 = 2,
|
||||
U8 = 3,
|
||||
U128 = 4,
|
||||
} access_size;
|
||||
|
||||
enum InstrSize // ADDIU vs DADDIU, etc
|
||||
{
|
||||
Size64,
|
||||
Size32
|
||||
} size = Size32;
|
||||
|
||||
static IRInstruction Build(std::vector<IRValue> args, uint8_t i_type)
|
||||
{
|
||||
IRInstruction i;
|
||||
i.instr = i_type;
|
||||
i.args = args;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
uint32_t opcode;
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
uint8_t* entry;
|
||||
uint32_t guest_addr;
|
||||
std::vector<IRInstruction> ir;
|
||||
size_t cycles;
|
||||
};
|
||||
|
||||
class JIT
|
||||
{
|
||||
private:
|
||||
Block* cur_block;
|
||||
robin_hood::unordered_flat_map<uint32_t, Block*> blockCache;
|
||||
|
||||
void EmitJ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitJAL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
void EmitBEQ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
void EmitBNE(uint32_t instr, EE_JIT::IRInstruction& i); // 0x05
|
||||
void EmitBLEZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitBGTZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitADDI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x08
|
||||
void EmitADDIU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
void EmitSLTI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0A
|
||||
void EmitSLTIU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0B
|
||||
void EmitANDI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0C
|
||||
void EmitORI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0D
|
||||
void EmitXORI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0E
|
||||
void EmitLUI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0F
|
||||
void EmitCOP0(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
void EmitBEQL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x14
|
||||
void EmitBNEL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x15
|
||||
void EmitDADDIU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x19
|
||||
void EmitLDL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1a
|
||||
void EmitLDR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1b
|
||||
void EmitLQ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1f
|
||||
void EmitSQ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1f
|
||||
void EmitLB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x20
|
||||
void EmitLH(uint32_t instr, EE_JIT::IRInstruction& i); // 0x21
|
||||
void EmitLW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x23
|
||||
void EmitLBU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x24
|
||||
void EmitLHU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x25
|
||||
void EmitLWU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x27
|
||||
void EmitSB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x28
|
||||
void EmitSH(uint32_t instr, EE_JIT::IRInstruction& i); // 0x29
|
||||
void EmitSW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2B
|
||||
void EmitSDL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2C
|
||||
void EmitSDR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2D
|
||||
void EmitLWC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x31
|
||||
void EmitLQC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x36
|
||||
void EmitLD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x37
|
||||
void EmitSWC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x39
|
||||
void EmitSQC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3e
|
||||
void EmitSD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3f
|
||||
|
||||
void EmitSLL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitSRL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitSRA(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
void EmitSLLV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
void EmitSRLV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitSRAV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x07
|
||||
void EmitJR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x08
|
||||
void EmitJALR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
void EmitMOVZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0A
|
||||
void EmitMOVN(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0B
|
||||
void EmitSyscall(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0C
|
||||
void EmitBreak(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0D
|
||||
void EmitMFHI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
void EmitMTHI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x11
|
||||
void EmitMFLO(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitMTLO(uint32_t instr, EE_JIT::IRInstruction& i); // 0x13
|
||||
void EmitDSLLV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x14
|
||||
void EmitDSRLV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x16
|
||||
void EmitDSRAV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x17
|
||||
void EmitMULT(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitMULTU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x19
|
||||
void EmitDIV(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1a
|
||||
void EmitDIVU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1b
|
||||
void EmitADD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x20
|
||||
void EmitADDU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x21
|
||||
void EmitSUB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x22
|
||||
void EmitSUBU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x23
|
||||
void EmitAND(uint32_t instr, EE_JIT::IRInstruction& i); // 0x24
|
||||
void EmitOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x25
|
||||
void EmitXOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x25
|
||||
void EmitNOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x27
|
||||
void EmitSLT(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2A
|
||||
void EmitSLTU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2B
|
||||
void EmitDADDU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2D
|
||||
void EmitDSUBU(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2F
|
||||
void EmitDSLL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x38
|
||||
void EmitDSRL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3A
|
||||
void EmitDSLL32(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3C
|
||||
void EmitDSRL32(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3E
|
||||
void EmitDSRA32(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3F
|
||||
|
||||
void EmitBLTZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitBGEZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitBLTZL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitBGEZL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
void EmitBGEZAL(uint32_t instr, EE_JIT::IRInstruction& i); // 0x11
|
||||
|
||||
// MMI
|
||||
void EmitMADD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitPLZCW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
void EmitMFHI1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
void EmitMTHI1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x11
|
||||
void EmitMFLO1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitMTLO1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x13
|
||||
void EmitMULT1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitDIVU1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1B
|
||||
void EmitPADDSB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x30
|
||||
|
||||
void EmitPSUBB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
|
||||
// MMI2
|
||||
void EmitPMFHI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x08
|
||||
void EmitPMFLO(uint32_t instr, EE_JIT::IRInstruction& i); // 0x09
|
||||
void EmitPCPYLD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0e
|
||||
void EmitPAND(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
|
||||
// MMI3
|
||||
void EmitPCPYUD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0E
|
||||
void EmitPOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x12
|
||||
void EmitPNOR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x13
|
||||
void EmitPCPYH(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1B
|
||||
|
||||
void EmitPADDUW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
|
||||
|
||||
// COP0
|
||||
void EmitMFC0(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitMTC0(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
void EmitERET(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
|
||||
// COP1
|
||||
void EmitMFC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitMTC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x04
|
||||
|
||||
// COP1 BC
|
||||
void EmitBC1F(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitBC1T(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
|
||||
// COP1.S
|
||||
void EmitADDS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitSUBS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitMULS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitDIVS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x03
|
||||
void EmitMOVS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
void EmitNEGS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x07
|
||||
void EmitADDAS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitMADDS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1c
|
||||
void EmitCVTW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x24
|
||||
void EmitCEQS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x32
|
||||
void EmitCLES(uint32_t instr, EE_JIT::IRInstruction& i); // 0x36
|
||||
|
||||
// COP1.W
|
||||
void EmitCVTS(uint32_t instr, EE_JIT::IRInstruction& i); // 0x30
|
||||
|
||||
// COP2
|
||||
void EmitQMFC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
void EmitCFC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x02
|
||||
void EmitQMTC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x05
|
||||
void EmitCTC2(uint32_t instr, EE_JIT::IRInstruction& i); // 0x06
|
||||
|
||||
// COP2 special1
|
||||
void EmitVMADDZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0a
|
||||
void EmitVMADDW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0b
|
||||
void EmitVSUB(uint32_t instr, EE_JIT::IRInstruction& i); // 0x2c
|
||||
void EmitVIADD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x30
|
||||
|
||||
// COP2 special2
|
||||
void EmitVMADDAX(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0a
|
||||
void EmitVMADDAY(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0b
|
||||
void EmitVMADDAZ(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0b
|
||||
void EmitVMULAX(uint32_t instr, EE_JIT::IRInstruction& i); // 0x18
|
||||
void EmitVMULAW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1B
|
||||
void EmitVCLIPW(uint32_t instr, EE_JIT::IRInstruction& i); // 0x1F
|
||||
void EmitVSQI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x35
|
||||
void EmitVISWR(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3f
|
||||
|
||||
// BC0
|
||||
void EmitBC0F(uint32_t instr, EE_JIT::IRInstruction& i); // 0x00
|
||||
void EmitBC0T(uint32_t instr, EE_JIT::IRInstruction& i); // 0x01
|
||||
|
||||
void EmitIncPC(EE_JIT::IRInstruction& i);
|
||||
public:
|
||||
using EntryFunc = void(*)();
|
||||
|
||||
void EmitIR(uint32_t instr);
|
||||
|
||||
void EmitPrequel(uint32_t guest_start);
|
||||
EntryFunc EmitDone(size_t cycles_taken);
|
||||
Block* GetExistingBlock(uint32_t start);
|
||||
|
||||
bool DoesBlockExist(uint32_t addr);
|
||||
void CheckCacheFull();
|
||||
|
||||
void MarkDirty(uint32_t address, uint32_t size);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace EmotionEngine
|
||||
{
|
||||
|
||||
|
@ -440,7 +39,7 @@ struct ProcessorState
|
|||
extern bool can_disassemble;
|
||||
|
||||
void Reset();
|
||||
int Clock();
|
||||
int Clock(int cycles);
|
||||
void Dump();
|
||||
ProcessorState* GetState();
|
||||
void MarkDirty(uint32_t address, uint32_t size);
|
||||
|
@ -458,8 +57,6 @@ void CheckCacheFull();
|
|||
bool DoesBlockExit(uint32_t addr);
|
||||
void EmitIR(uint32_t instr);
|
||||
bool IsBranch(uint32_t instr);
|
||||
EE_JIT::JIT::EntryFunc EmitDone(uint64_t cycles_taken);
|
||||
EE_JIT::JIT::EntryFunc GetExistingBlockFunc(uint32_t addr);
|
||||
uint64_t GetExistingBlockCycles(uint32_t addr);
|
||||
|
||||
inline const char* Reg(int index)
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
#include <emu/sched/scheduler.h>
|
||||
#include <emu/dev/sif.h>
|
||||
#include <emu/gpu/gif.hpp>
|
||||
#ifdef EE_JIT
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
#else
|
||||
#include <emu/cpu/ee/ee_interpret.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
@ -190,6 +194,9 @@ void DoGIFTransfer()
|
|||
#ifdef EE_JIT
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
EmotionEngine::SetIp1Pending();
|
||||
#else
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
EEInterpreter::SetIP1Pending();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -546,6 +553,7 @@ void HandleSIF0Transfer()
|
|||
#ifdef EE_JIT
|
||||
EmotionEngine::SetIp1Pending();
|
||||
#else
|
||||
EEInterpreter::SetIP1Pending();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -936,6 +944,11 @@ void WriteDSTAT(uint32_t data)
|
|||
EmotionEngine::SetIp1Pending();
|
||||
else
|
||||
EmotionEngine::ClearIp1Pending();
|
||||
#else
|
||||
if (stat.channel_irq & stat.channel_irq_mask)
|
||||
EEInterpreter::SetIP1Pending();
|
||||
else
|
||||
EEInterpreter::ClearIP1Pending();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,746 +0,0 @@
|
|||
#include "ee_interpret.h"
|
||||
#include <util/uint128.h>
|
||||
#include <string.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
|
||||
uint128_t regs[32];
|
||||
uint32_t pc, next_pc;
|
||||
uint32_t hi, lo;
|
||||
uint32_t hi1, lo1;
|
||||
EEInterpreter::COP0 EEInterpreter::cop0;
|
||||
extern EEInterpreter::Cop1Reg cop1_regs[32];
|
||||
|
||||
void EEInterpreter::Reset()
|
||||
{
|
||||
memset(regs, 0, sizeof(regs));
|
||||
|
||||
pc = 0xbfc00000;
|
||||
next_pc = pc + 4;
|
||||
|
||||
cop0.prid = 0x2E20;
|
||||
|
||||
if (!tlb)
|
||||
tlb = new EETLB();
|
||||
}
|
||||
|
||||
void EEInterpreter::Write8(uint32_t addr, uint8_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint8_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write8(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write16(uint32_t addr, uint16_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint16_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write16(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint32_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write32(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write64(uint32_t addr, uint64_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(uint64_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write64(addr, data); // Slow
|
||||
}
|
||||
|
||||
void EEInterpreter::Write128(uint32_t addr, __uint128_t data)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->wrTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
*(__uint128_t*)(ptr + offs) = data;
|
||||
else
|
||||
return Bus::Write128(addr, {data}); // Slow
|
||||
}
|
||||
|
||||
uint8_t EEInterpreter::Read8(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint8_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read8(addr); // Slow
|
||||
}
|
||||
|
||||
uint16_t EEInterpreter::Read16(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint16_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read16(addr); // Slow
|
||||
}
|
||||
|
||||
uint32_t EEInterpreter::Read32(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint32_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read32(addr); // Slow
|
||||
}
|
||||
|
||||
uint64_t EEInterpreter::Read64(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(uint64_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read64(addr); // Slow
|
||||
}
|
||||
|
||||
__uint128_t EEInterpreter::Read128(uint32_t addr)
|
||||
{
|
||||
const auto page = addr >> 12;
|
||||
const auto offs = addr & 0xfff;
|
||||
const auto ptr = tlb->rdTable[page];
|
||||
|
||||
if (ptr != 0)
|
||||
return *(__uint128_t*)(ptr + offs);
|
||||
else
|
||||
return Bus::Read128(addr).u128; // Slow
|
||||
}
|
||||
|
||||
void EETLB::Unmap(TlbEntry& entry)
|
||||
{
|
||||
uint32_t real_vpn = entry.entry.vpn2 * 2;
|
||||
real_vpn >>= entry.pageShift;
|
||||
|
||||
uint32_t even_page = (real_vpn * entry.pageSize) / 4096;
|
||||
uint32_t odd_page = ((real_vpn + 1) * entry.pageSize) / 4096;
|
||||
|
||||
if (entry.entry.s)
|
||||
{
|
||||
if (entry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < 1024*16; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[even_page + index] = 0;
|
||||
wrTable[even_page + index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < entry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[even_page + index] = 0;
|
||||
wrTable[even_page + index] = 0;
|
||||
rdTable[odd_page + index] = 0;
|
||||
wrTable[odd_page + index] = 0;
|
||||
}
|
||||
}
|
||||
if (entry.entry.v1)
|
||||
{
|
||||
for (uint32_t i = 0; i < entry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[odd_page + index] = 0;
|
||||
wrTable[odd_page + index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EETLB::DoRemap(int index)
|
||||
{
|
||||
auto& tlbEntry = tlb[index];
|
||||
|
||||
uint32_t entryLo0 = EEInterpreter::cop0.regs[2];
|
||||
uint32_t entryLo1 = EEInterpreter::cop0.regs[3];
|
||||
uint32_t pageMask = EEInterpreter::cop0.regs[5];
|
||||
uint32_t entryHi = EEInterpreter::cop0.regs[10];
|
||||
|
||||
Unmap(tlbEntry);
|
||||
|
||||
switch (pageMask >> 13)
|
||||
{
|
||||
case 0:
|
||||
tlbEntry.pageSize = 4*1024;
|
||||
tlbEntry.pageShift = 0;
|
||||
break;
|
||||
case 3:
|
||||
tlbEntry.pageSize = 16*1024;
|
||||
tlbEntry.pageShift = 2;
|
||||
break;
|
||||
case 0xf:
|
||||
tlbEntry.pageSize = 64*1024;
|
||||
tlbEntry.pageShift = 4;
|
||||
break;
|
||||
case 0x3f:
|
||||
tlbEntry.pageSize = 256*1024;
|
||||
tlbEntry.pageShift = 6;
|
||||
break;
|
||||
case 0xff:
|
||||
tlbEntry.pageSize = 1024*1024;
|
||||
tlbEntry.pageShift = 8;
|
||||
break;
|
||||
case 0x3ff:
|
||||
tlbEntry.pageSize = 4*1024*1024;
|
||||
tlbEntry.pageShift = 10;
|
||||
break;
|
||||
case 0xfff:
|
||||
tlbEntry.pageSize = 16*1024*1024;
|
||||
tlbEntry.pageShift = 12;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown page size 0x%08x\n", pageMask >> 13);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32_t pfn0 = (entryLo0 >> 6) & 0xFFFFF;
|
||||
uint32_t pfn1 = (entryLo1 >> 6) & 0xFFFFF;
|
||||
uint32_t vpn2 = (entryHi >> 13) & 0x7FFFF;
|
||||
|
||||
tlbEntry.entry.g = (entryLo0 & 1) & (entryLo1 & 1);
|
||||
tlbEntry.entry.v0 = (entryLo0 >> 1) & 1;
|
||||
tlbEntry.entry.d0 = (entryLo0 >> 2) & 1;
|
||||
tlbEntry.entry.c0 = (entryLo0 >> 3) & 0x7;
|
||||
tlbEntry.entry.pfn0 = (entryLo0 >> 6) & 0xFFFFF;
|
||||
tlbEntry.entry.v1 = (entryLo1 >> 1) & 1;
|
||||
tlbEntry.entry.d1 = (entryLo1 >> 2) & 1;
|
||||
tlbEntry.entry.c1 = (entryLo1 >> 3) & 0x7;
|
||||
tlbEntry.entry.pfn1 = (entryLo1 >> 6) & 0xFFFFF;
|
||||
|
||||
tlbEntry.entry.vpn2 = entryHi >> 13;
|
||||
tlbEntry.entry.asid = entryHi & 0xff;
|
||||
|
||||
uint32_t real_virt = vpn2 * 2;
|
||||
real_virt >>= tlbEntry.pageShift;
|
||||
real_virt *= tlbEntry.pageSize;
|
||||
|
||||
uint32_t real_phy = pfn0 >> tlbEntry.pageShift;
|
||||
real_phy *= tlbEntry.pageSize;
|
||||
uint32_t real_phy_1 = pfn1 >> tlbEntry.pageShift;
|
||||
real_phy_1 *= tlbEntry.pageSize;
|
||||
|
||||
uint32_t real_vpn = (vpn2 * 2) >> tlbEntry.pageShift;
|
||||
|
||||
uint32_t even_virt_page = (real_vpn * tlbEntry.pageSize) / 4096;
|
||||
uint32_t even_virt_addr = even_virt_page * 4096;
|
||||
uint32_t even_phy_addr = (pfn0 >> tlbEntry.pageShift) * tlbEntry.pageSize;
|
||||
uint32_t odd_virt_page = ((real_vpn+1) * tlbEntry.pageSize) / 4096;
|
||||
uint32_t odd_virt_addr = odd_virt_page * 4096;
|
||||
uint32_t odd_phy_addr = (pfn1 >> tlbEntry.pageShift) * tlbEntry.pageSize;
|
||||
|
||||
if (tlbEntry.entry.s)
|
||||
{
|
||||
if (tlbEntry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < 1024*16; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
rdTable[even_virt_page + index] = (uintptr_t)(Bus::GetSprPtr()+i);
|
||||
wrTable[even_virt_page + index] = (uintptr_t)(Bus::GetSprPtr()+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tlbEntry.entry.v0)
|
||||
{
|
||||
for (uint32_t i = 0; i < tlbEntry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
uintptr_t mem = (uintptr_t)Bus::GetPtrForAddress(even_phy_addr+i);
|
||||
rdTable[even_virt_page + index] = mem;
|
||||
wrTable[even_virt_page + index] = mem;
|
||||
}
|
||||
}
|
||||
if (tlbEntry.entry.v1)
|
||||
{
|
||||
for (uint32_t i = 0; i < tlbEntry.pageSize; i += 4096)
|
||||
{
|
||||
int index = i / 4096;
|
||||
uintptr_t mem = (uintptr_t)Bus::GetPtrForAddress(odd_phy_addr+i);
|
||||
rdTable[odd_virt_page + index] = mem;
|
||||
wrTable[odd_virt_page + index] = mem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EEInterpreter::Clock(int cycles)
|
||||
{
|
||||
for (int cycle = 0; cycle < cycles; cycle++)
|
||||
{
|
||||
uint32_t instr = Read32(pc);
|
||||
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
|
||||
if (instr == 0)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: nop\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t opcode = (instr >> 26) & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
Sll(instr);
|
||||
break;
|
||||
case 0x02:
|
||||
Srl(instr);
|
||||
break;
|
||||
case 0x03:
|
||||
Sra(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
Sllv(instr);
|
||||
break;
|
||||
case 0x07:
|
||||
Srav(instr);
|
||||
break;
|
||||
case 0x08:
|
||||
Jr(instr);
|
||||
break;
|
||||
case 0x09:
|
||||
Jalr(instr);
|
||||
break;
|
||||
case 0x0a:
|
||||
Movz(instr);
|
||||
break;
|
||||
case 0x0b:
|
||||
Movn(instr);
|
||||
break;
|
||||
case 0x0f:
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sync.p\n");
|
||||
break;
|
||||
case 0x10:
|
||||
Mfhi(instr);
|
||||
break;
|
||||
case 0x12:
|
||||
Mflo(instr);
|
||||
break;
|
||||
case 0x14:
|
||||
Dsllv(instr);
|
||||
break;
|
||||
case 0x17:
|
||||
Dsrav(instr);
|
||||
break;
|
||||
case 0x18:
|
||||
Mult(instr);
|
||||
break;
|
||||
case 0x19:
|
||||
Multu(instr);
|
||||
break;
|
||||
case 0x1a:
|
||||
Div(instr);
|
||||
break;
|
||||
case 0x1b:
|
||||
Divu(instr);
|
||||
break;
|
||||
case 0x21:
|
||||
Addu(instr);
|
||||
break;
|
||||
case 0x23:
|
||||
Subu(instr);
|
||||
break;
|
||||
case 0x24:
|
||||
And(instr);
|
||||
break;
|
||||
case 0x25:
|
||||
Or(instr);
|
||||
break;
|
||||
case 0x27:
|
||||
Nor(instr);
|
||||
break;
|
||||
case 0x2a:
|
||||
Slt(instr);
|
||||
break;
|
||||
case 0x2b:
|
||||
Sltu(instr);
|
||||
break;
|
||||
case 0x2d:
|
||||
Daddu(instr);
|
||||
break;
|
||||
case 0x38:
|
||||
Dsll(instr);
|
||||
break;
|
||||
case 0x3c:
|
||||
Dsll32(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
Dsra32(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown special instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01:
|
||||
{
|
||||
opcode = (instr >> 16) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
Bltz(instr);
|
||||
break;
|
||||
case 0x01:
|
||||
Bgez(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown regimm instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x02:
|
||||
J(instr);
|
||||
break;
|
||||
case 0x03:
|
||||
Jal(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
Beq(instr);
|
||||
break;
|
||||
case 0x05:
|
||||
Bne(instr);
|
||||
break;
|
||||
case 0x06:
|
||||
Blez(instr);
|
||||
break;
|
||||
case 0x07:
|
||||
Bgtz(instr);
|
||||
break;
|
||||
case 0x09:
|
||||
Addiu(instr);
|
||||
break;
|
||||
case 0x0a:
|
||||
Slti(instr);
|
||||
break;
|
||||
case 0x0b:
|
||||
Sltiu(instr);
|
||||
break;
|
||||
case 0x0c:
|
||||
Andi(instr);
|
||||
break;
|
||||
case 0x0d:
|
||||
Ori(instr);
|
||||
break;
|
||||
case 0x0e:
|
||||
Xori(instr);
|
||||
break;
|
||||
case 0x0f:
|
||||
Lui(instr);
|
||||
break;
|
||||
case 0x10:
|
||||
{
|
||||
opcode = (instr >> 21) & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
Mfc0(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
Mtc0(instr);
|
||||
break;
|
||||
case 0x10:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x02:
|
||||
Tlbwi(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop0 tlb instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop0 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x11:
|
||||
{
|
||||
opcode = (instr >> 21) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x04:
|
||||
Mtc1(instr);
|
||||
break;
|
||||
case 0x06:
|
||||
break;
|
||||
case 0x10:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x18:
|
||||
Addas(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop1.s instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop1 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x12:
|
||||
{
|
||||
opcode = (instr >> 21) & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x01:
|
||||
Qmfc2(instr);
|
||||
break;
|
||||
case 0x02:
|
||||
Cfc2(instr);
|
||||
break;
|
||||
case 0x05:
|
||||
Qmtc2(instr);
|
||||
break;
|
||||
case 0x06:
|
||||
Ctc2(instr);
|
||||
break;
|
||||
case 0x10 ... 0x1F:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x2c:
|
||||
VectorUnit::VU0::Vsub(instr);
|
||||
break;
|
||||
case 0x30:
|
||||
VectorUnit::VU0::Viadd(instr);
|
||||
break;
|
||||
case 0x3C ... 0x3F:
|
||||
{
|
||||
opcode = (instr & 0x3) | ((instr >> 6) & 0x1F) << 2;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x35:
|
||||
VectorUnit::VU0::Vsqi(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
VectorUnit::VU0::Viswr(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop2 special2 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop2 special1 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown cop2 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x14:
|
||||
Beql(instr);
|
||||
break;
|
||||
case 0x15:
|
||||
Bnel(instr);
|
||||
break;
|
||||
case 0x19:
|
||||
Daddiu(instr);
|
||||
break;
|
||||
case 0x1C:
|
||||
{
|
||||
opcode = instr & 0x3F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x12:
|
||||
Mflo1(instr);
|
||||
break;
|
||||
case 0x18:
|
||||
Mult1(instr);
|
||||
break;
|
||||
case 0x1b:
|
||||
Divu1(instr);
|
||||
break;
|
||||
case 0x29:
|
||||
{
|
||||
opcode = (instr >> 6) & 0x1F;
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x12:
|
||||
Por(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown mmi3 instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("[emu/EE]: Unknown mmi instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x1e:
|
||||
Lq(instr);
|
||||
break;
|
||||
case 0x1f:
|
||||
Sq(instr);
|
||||
break;
|
||||
case 0x20:
|
||||
Lb(instr);
|
||||
break;
|
||||
case 0x21:
|
||||
Lh(instr);
|
||||
break;
|
||||
case 0x23:
|
||||
Lw(instr);
|
||||
break;
|
||||
case 0x24:
|
||||
Lbu(instr);
|
||||
break;
|
||||
case 0x25:
|
||||
Lhu(instr);
|
||||
break;
|
||||
case 0x27:
|
||||
Lwu(instr);
|
||||
break;
|
||||
case 0x28:
|
||||
Sb(instr);
|
||||
break;
|
||||
case 0x29:
|
||||
Sh(instr);
|
||||
break;
|
||||
case 0x2b:
|
||||
Sw(instr);
|
||||
break;
|
||||
case 0x2f:
|
||||
if constexpr (CanDisassamble)
|
||||
printf("cache\n");
|
||||
break;
|
||||
case 0x37:
|
||||
Ld(instr);
|
||||
break;
|
||||
case 0x39:
|
||||
Swc1(instr);
|
||||
break;
|
||||
case 0x3f:
|
||||
Sd(instr);
|
||||
break;
|
||||
default:
|
||||
printf("[emu/EE]: Unknown instruction 0x%02x\n", opcode);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cop0.count++;
|
||||
}
|
||||
}
|
||||
|
||||
extern float convert(uint32_t);
|
||||
|
||||
void EEInterpreter::Dump()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/EE]: %s\t->\t%s\n", Reg(i), print_128(regs[i]));
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("[emu/EE]: f%d\t->\t%f\n", i, convert(cop1_regs[i].u));
|
||||
printf("pc\t->\t0x%08x\n", pc);
|
||||
printf("next pc\t->\t0x%08x\n", next_pc);
|
||||
printf("hi\t->\t0x%08x\n", hi);
|
||||
printf("lo\t->\t0x%08x\n", lo);
|
||||
printf("hi1\t->\t0x%08x\n", hi1);
|
||||
printf("lo1\t->\t0x%08x\n", lo1);
|
||||
}
|
||||
|
||||
const uint32_t PAGE_SIZE = 4 * 1024;
|
||||
|
||||
EETLB::EETLB()
|
||||
{
|
||||
wrTable = new uintptr_t[0x100000];
|
||||
rdTable = new uintptr_t[0x100000];
|
||||
|
||||
memset(wrTable, 0, sizeof(uintptr_t)*0x100000);
|
||||
memset(rdTable, 0, sizeof(uintptr_t)*0x100000);
|
||||
|
||||
for (auto pageIndex = 0; pageIndex < 8192; pageIndex++)
|
||||
{
|
||||
const auto ptr = (uintptr_t)(&(Bus::GetRamPtr()[(pageIndex * PAGE_SIZE) & 0x1FFFFFF]));
|
||||
rdTable[pageIndex + 0x00000] = ptr;
|
||||
rdTable[pageIndex + 0x80000] = ptr;
|
||||
rdTable[pageIndex + 0xA0000] = ptr;
|
||||
wrTable[pageIndex + 0x00000] = ptr;
|
||||
wrTable[pageIndex + 0x80000] = ptr;
|
||||
wrTable[pageIndex + 0xA0000] = ptr;
|
||||
}
|
||||
|
||||
for (auto pageIndex = 0; pageIndex < 1024; pageIndex++)
|
||||
{
|
||||
const auto ptr = (uintptr_t)(&BiosRom[(pageIndex * PAGE_SIZE) & 0x1FFFFFF]);
|
||||
rdTable[pageIndex + 0x1FC00] = ptr;
|
||||
rdTable[pageIndex + 0x9FC00] = ptr;
|
||||
rdTable[pageIndex + 0xBFC00] = ptr;
|
||||
}
|
||||
|
||||
memset(tlb, 0, sizeof(tlb));
|
||||
}
|
|
@ -1,333 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class EETLB
|
||||
{
|
||||
public:
|
||||
uintptr_t* rdTable;
|
||||
uintptr_t* wrTable;
|
||||
|
||||
struct TlbEntry
|
||||
{
|
||||
union Entry
|
||||
{
|
||||
__uint128_t data;
|
||||
struct
|
||||
{
|
||||
__uint128_t v0 : 1,
|
||||
d0 : 1,
|
||||
c0 : 3,
|
||||
pfn0 : 20,
|
||||
v1 : 1,
|
||||
d1 : 1,
|
||||
c1 : 3,
|
||||
pfn1 : 20,
|
||||
s : 1,
|
||||
asid : 8,
|
||||
g : 1,
|
||||
vpn2 : 19,
|
||||
mask : 12;
|
||||
};
|
||||
} entry;
|
||||
uint32_t pageSize;
|
||||
uint32_t pageShift;
|
||||
} tlb[48];
|
||||
public:
|
||||
EETLB();
|
||||
|
||||
void Unmap(TlbEntry& entry);
|
||||
void DoRemap(int index);
|
||||
};
|
||||
|
||||
namespace EEInterpreter
|
||||
{
|
||||
|
||||
inline const char* Reg(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return "$zero";
|
||||
case 1:
|
||||
return "$at";
|
||||
case 2:
|
||||
return "$v0";
|
||||
case 3:
|
||||
return "$v1";
|
||||
case 4:
|
||||
return "$a0";
|
||||
case 5:
|
||||
return "$a1";
|
||||
case 6:
|
||||
return "$a2";
|
||||
case 7:
|
||||
return "$a3";
|
||||
case 8:
|
||||
return "$t0";
|
||||
case 9:
|
||||
return "$t1";
|
||||
case 10:
|
||||
return "$t2";
|
||||
case 11:
|
||||
return "$t3";
|
||||
case 12:
|
||||
return "$t4";
|
||||
case 13:
|
||||
return "$t5";
|
||||
case 14:
|
||||
return "$t6";
|
||||
case 15:
|
||||
return "$t7";
|
||||
case 16:
|
||||
return "$s0";
|
||||
case 17:
|
||||
return "$s1";
|
||||
case 18:
|
||||
return "$s2";
|
||||
case 19:
|
||||
return "$s3";
|
||||
case 20:
|
||||
return "$s4";
|
||||
case 21:
|
||||
return "$s5";
|
||||
case 22:
|
||||
return "$s6";
|
||||
case 23:
|
||||
return "$s7";
|
||||
case 24:
|
||||
return "$t8";
|
||||
case 25:
|
||||
return "$t9";
|
||||
case 26:
|
||||
return "$k0";
|
||||
case 27:
|
||||
return "$k1";
|
||||
case 28:
|
||||
return "$gp";
|
||||
case 29:
|
||||
return "$sp";
|
||||
case 30:
|
||||
return "$fp";
|
||||
case 31:
|
||||
return "$ra";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
union COP0Status
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t ie : 1; /* Interrupt Enable */
|
||||
uint32_t exl : 1; /* Exception Level */
|
||||
uint32_t erl : 1; /* Error Level */
|
||||
uint32_t ksu : 2; /* Kernel/Supervisor/User Mode bits */
|
||||
uint32_t : 5;
|
||||
uint32_t im0 : 1; /* Int[1:0] signals */
|
||||
uint32_t im1 : 1;
|
||||
uint32_t bem : 1; /* Bus Error Mask */
|
||||
uint32_t : 2;
|
||||
uint32_t im7 : 1; /* Internal timer interrupt */
|
||||
uint32_t eie : 1; /* Enable IE */
|
||||
uint32_t edi : 1; /* EI/DI instruction Enable */
|
||||
uint32_t ch : 1; /* Cache Hit */
|
||||
uint32_t : 3;
|
||||
uint32_t bev : 1; /* Location of TLB refill */
|
||||
uint32_t dev : 1; /* Location of Performance counter */
|
||||
uint32_t : 2;
|
||||
uint32_t fr : 1; /* Additional floating point registers */
|
||||
uint32_t : 1;
|
||||
uint32_t cu : 4; /* Usability of each of the four coprocessors */
|
||||
};
|
||||
};
|
||||
|
||||
union COP0Cause
|
||||
{
|
||||
uint32_t value;
|
||||
struct
|
||||
{
|
||||
uint32_t : 2;
|
||||
uint32_t exccode : 5;
|
||||
uint32_t : 3;
|
||||
uint32_t ip0_pending : 1;
|
||||
uint32_t ip1_pending : 1;
|
||||
uint32_t siop : 1;
|
||||
uint32_t : 2;
|
||||
uint32_t timer_ip_pending : 1;
|
||||
uint32_t exc2 : 3;
|
||||
uint32_t : 9;
|
||||
uint32_t ce : 2;
|
||||
uint32_t bd2 : 1;
|
||||
uint32_t bd : 1;
|
||||
};
|
||||
};
|
||||
|
||||
enum OperatingMode
|
||||
{
|
||||
USER_MODE = 0b10,
|
||||
SUPERVISOR_MODE = 0b01,
|
||||
KERNEL_MODE = 0b00
|
||||
};
|
||||
|
||||
/* The COP0 registers */
|
||||
union COP0
|
||||
{
|
||||
uint32_t regs[32] = {};
|
||||
struct
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t random;
|
||||
uint32_t entry_lo0;
|
||||
uint32_t entry_lo1;
|
||||
uint32_t context;
|
||||
uint32_t page_mask;
|
||||
uint32_t wired;
|
||||
uint32_t reserved0[1];
|
||||
uint32_t bad_vaddr;
|
||||
uint32_t count;
|
||||
uint32_t entryhi;
|
||||
uint32_t compare;
|
||||
COP0Status status;
|
||||
COP0Cause cause;
|
||||
uint32_t epc;
|
||||
uint32_t prid;
|
||||
uint32_t config;
|
||||
uint32_t reserved1[6];
|
||||
uint32_t bad_paddr;
|
||||
uint32_t debug;
|
||||
uint32_t perf;
|
||||
uint32_t reserved2[2];
|
||||
uint32_t tag_lo;
|
||||
uint32_t tag_hi;
|
||||
uint32_t error_epc;
|
||||
uint32_t reserved3[1];
|
||||
};
|
||||
};
|
||||
|
||||
extern COP0 cop0;
|
||||
static constexpr bool CanDisassamble = false;
|
||||
|
||||
extern EETLB* tlb;
|
||||
|
||||
|
||||
union Cop1Reg
|
||||
{
|
||||
float f;
|
||||
uint32_t u;
|
||||
int32_t s;
|
||||
};
|
||||
|
||||
uint8_t Read8(uint32_t addr);
|
||||
uint16_t Read16(uint32_t addr);
|
||||
uint32_t Read32(uint32_t addr);
|
||||
uint64_t Read64(uint32_t addr);
|
||||
__uint128_t Read128(uint32_t addr);
|
||||
|
||||
void Write8(uint32_t addr, uint8_t data);
|
||||
void Write16(uint32_t addr, uint16_t data);
|
||||
void Write32(uint32_t addr, uint32_t data);
|
||||
void Write64(uint32_t addr, uint64_t data);
|
||||
void Write128(uint32_t addr, __uint128_t data);
|
||||
|
||||
void Reset();
|
||||
|
||||
void Clock(int cycles);
|
||||
void Dump();
|
||||
|
||||
// Normal
|
||||
void J(uint32_t instr); // 0x02
|
||||
void Jal(uint32_t instr); // 0x03
|
||||
void Beq(uint32_t instr); // 0x04
|
||||
void Bne(uint32_t instr); // 0x05
|
||||
void Blez(uint32_t instr); // 0x06
|
||||
void Bgtz(uint32_t instr); // 0x07
|
||||
void Addiu(uint32_t instr); // 0x09
|
||||
void Slti(uint32_t instr); // 0x0A
|
||||
void Sltiu(uint32_t instr); // 0x0B
|
||||
void Andi(uint32_t instr); // 0x0C
|
||||
void Ori(uint32_t instr); // 0x0D
|
||||
void Xori(uint32_t instr); // 0x0E
|
||||
void Lui(uint32_t instr); // 0x0F
|
||||
void Beql(uint32_t instr); // 0x14
|
||||
void Bnel(uint32_t instr); // 0x15
|
||||
void Daddiu(uint32_t instr); // 0x19
|
||||
void Lq(uint32_t instr); // 0x1e
|
||||
void Sq(uint32_t instr); // 0x1f
|
||||
void Lb(uint32_t instr); // 0x20
|
||||
void Lh(uint32_t instr); // 0x21
|
||||
void Lw(uint32_t instr); // 0x23
|
||||
void Lbu(uint32_t instr); // 0x24
|
||||
void Lhu(uint32_t instr); // 0x25
|
||||
void Lwu(uint32_t instr); // 0x27
|
||||
void Sb(uint32_t instr); // 0x28
|
||||
void Sh(uint32_t instr); // 0x29
|
||||
void Sw(uint32_t instr); // 0x2B
|
||||
void Swc1(uint32_t instr); // 0x31
|
||||
void Ld(uint32_t instr); // 0x37
|
||||
void Sd(uint32_t instr); // 0x3F
|
||||
|
||||
// Special
|
||||
void Sll(uint32_t instr); // 0x00
|
||||
void Srl(uint32_t instr); // 0x02
|
||||
void Sra(uint32_t instr); // 0x03
|
||||
void Sllv(uint32_t instr); // 0x04
|
||||
void Srav(uint32_t instr); // 0x07
|
||||
void Jr(uint32_t instr); // 0x08
|
||||
void Jalr(uint32_t instr); // 0x09
|
||||
void Movz(uint32_t instr); // 0x0a
|
||||
void Movn(uint32_t instr); // 0x0b
|
||||
void Mfhi(uint32_t instr); // 0x10
|
||||
void Mflo(uint32_t instr); // 0x12
|
||||
void Dsllv(uint32_t instr); // 0x14
|
||||
void Dsrav(uint32_t instr); // 0x17
|
||||
void Mult(uint32_t instr); // 0x18
|
||||
void Multu(uint32_t instr); // 0x19
|
||||
void Div(uint32_t instr); // 0x1A
|
||||
void Divu(uint32_t instr); // 0x1B
|
||||
void Addu(uint32_t instr); // 0x21
|
||||
void Subu(uint32_t instr); // 0x23
|
||||
void And(uint32_t instr); // 0x24
|
||||
void Or(uint32_t instr); // 0x25
|
||||
void Nor(uint32_t instr); // 0x27
|
||||
void Slt(uint32_t instr); // 0x2a
|
||||
void Sltu(uint32_t instr); // 0x2b
|
||||
void Daddu(uint32_t instr); // 0x2d
|
||||
void Dsll(uint32_t instr); // 0x38
|
||||
void Dsll32(uint32_t instr); // 0x3c
|
||||
void Dsra32(uint32_t instr); // 0x3f
|
||||
|
||||
// Regimm
|
||||
void Bltz(uint32_t instr); // 0x00
|
||||
void Bgez(uint32_t instr); // 0x01
|
||||
|
||||
// Cop0
|
||||
void Mfc0(uint32_t instr); // 0x00
|
||||
void Mtc0(uint32_t instr); // 0x04
|
||||
|
||||
// Cop0 TLB
|
||||
void Tlbwi(uint32_t instr); // 0x02
|
||||
|
||||
// MMI
|
||||
void Mflo1(uint32_t instr); // 0x12
|
||||
void Mult1(uint32_t instr); // 0x18
|
||||
void Divu1(uint32_t instr); // 0x1B
|
||||
|
||||
// MMI3
|
||||
void Por(uint32_t instr);
|
||||
|
||||
// COP2
|
||||
void Qmfc2(uint32_t instr); // 0x01
|
||||
void Cfc2(uint32_t instr); // 0x02
|
||||
void Qmtc2(uint32_t instr); // 0x05
|
||||
void Ctc2(uint32_t instr); // 0x06
|
||||
|
||||
// COP1
|
||||
void Mtc1(uint32_t instr); // 0x04
|
||||
|
||||
// COP1.S
|
||||
void Addas(uint32_t instr); // 0x18
|
||||
|
||||
}
|
|
@ -1,675 +0,0 @@
|
|||
#include "ee_interpret.h"
|
||||
|
||||
#include <util/uint128.h>
|
||||
#include <emu/memory/Bus.h>
|
||||
#include <emu/cpu/ee/vu.h>
|
||||
|
||||
#define _rs_ ((instr >> 21) & 0x1F)
|
||||
#define _rt_ ((instr >> 16) & 0x1F)
|
||||
#define _rd_ ((instr >> 11) & 0x1F)
|
||||
#define _sa_ ((instr >> 6) & 0x1F)
|
||||
|
||||
#define _ft_ ((instr >> 16) & 0x1F)
|
||||
#define _fs_ ((instr >> 11) & 0x1F)
|
||||
|
||||
#define _imm16_ (instr & 0xffff)
|
||||
#define _simm64_ ((int64_t)(int16_t)(instr & 0xffff))
|
||||
#define _simm32_ ((int32_t)(int16_t)(instr & 0xffff))
|
||||
#define _imm26_ (instr & 0x3ffffff)
|
||||
|
||||
extern float convert(uint32_t);
|
||||
|
||||
extern uint128_t regs[32];
|
||||
extern uint32_t pc, next_pc;
|
||||
extern uint32_t hi, lo;
|
||||
extern uint32_t hi1, lo1;
|
||||
EEInterpreter::Cop1Reg cop1_regs[32], accumulator;
|
||||
|
||||
EETLB *EEInterpreter::tlb;
|
||||
|
||||
void EEInterpreter::Mfc0(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u32[0] = cop0.regs[_rd_];
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mfc0 %s, r%d\n", Reg(_rt_), _rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mtc0(uint32_t instr)
|
||||
{
|
||||
cop0.regs[_rd_] = regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mtc0 %s, r%d\n", Reg(_rt_), _rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Tlbwi(uint32_t)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: tlbwi\n");
|
||||
|
||||
tlb->DoRemap(cop0.regs[0]);
|
||||
}
|
||||
|
||||
void EEInterpreter::Slti(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = ((int64_t)regs[_rs_].u64[0] < _simm64_);
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: slti %s, %s, 0x%04lx\n", Reg(_rt_), Reg(_rs_), _simm64_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Andi(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] & _imm16_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: andi %s, %s, 0x%04x\n", Reg(_rt_), Reg(_rs_), _imm16_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Ori(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] | _imm16_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: ori %s, %s, 0x%04x\n", Reg(_rt_), Reg(_rs_), _imm16_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Xori(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] ^ _imm16_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: xori %s, %s, 0x%04x\n", Reg(_rt_), Reg(_rs_), _imm16_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Lui(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (_simm64_ << 16);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lui %s, 0x%08lx\n", Reg(_rt_), (_simm64_ << 16));
|
||||
}
|
||||
|
||||
void EEInterpreter::Beql(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: beql %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), next_pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] == regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
else
|
||||
{
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void EEInterpreter::Bnel(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bnel %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), next_pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] != regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
else
|
||||
{
|
||||
pc = next_pc;
|
||||
next_pc += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void EEInterpreter::Daddiu(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = regs[_rs_].u64[0] + _simm64_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: daddiu %s, %s, 0x%08lx\n", Reg(_rt_), Reg(_rs_), _simm64_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Lq(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u128 = Read128(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lq %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sq(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
Write128(addr, regs[_rt_].u128);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sq %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lb(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = (int8_t)Read8(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lb %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lh(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = (int16_t)Read16(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lh %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lw(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = (int32_t)Read32(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lw %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
|
||||
void EEInterpreter::Lbu(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read8(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lbu %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lhu(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read16(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lhu %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Lwu(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read32(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: lwu %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sb(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
Write8(addr, regs[_rt_].u8[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sb %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sh(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
Write16(addr, regs[_rt_].u8[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sh %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sw(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
Write32(addr, regs[_rt_].u32[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sw %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Swc1(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
Write32(addr, cop1_regs[_rt_].u);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: swc1 f%d, 0x%08x(%s)\n", _rt_, _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Ld(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
regs[_rt_].u64[0] = Read64(addr);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: ld %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sd(uint32_t instr)
|
||||
{
|
||||
uint32_t addr = regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
Write64(addr, regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sd %s, 0x%08x(%s)\n", Reg(_rt_), _simm32_, Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sll(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(int32_t)(regs[_rt_].u32[0] << _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sll %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Srl(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(regs[_rt_].u32[0] >> _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: srl %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Sra(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)((int32_t)regs[_rt_].u32[0] >> _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sra %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Sllv(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (regs[_rt_].u32[0] << (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sllv %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Srav(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)((int32_t)regs[_rt_].u32[0] >> (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: srav %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Jr(uint32_t instr)
|
||||
{
|
||||
next_pc = regs[_rs_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: jr %s\n", Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Jalr(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u32[0] = next_pc;
|
||||
next_pc = regs[_rs_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: jalr %s, %s\n", Reg(_rd_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Movz(uint32_t instr)
|
||||
{
|
||||
if (regs[_rt_].u64[0] == 0) regs[_rd_].u64[0] = regs[_rs_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: movz %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Movn(uint32_t instr)
|
||||
{
|
||||
if (regs[_rt_].u64[0] != 0) regs[_rd_].u64[0] = regs[_rs_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: movn %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sltiu(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (regs[_rs_].u64[0] < _imm16_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sltiu %s, %s, 0x%08lx\n", Reg(_rt_), Reg(_rs_), (uint64_t)_simm64_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mfhi(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = hi;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mfhi %s\n", Reg(_rd_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Mflo(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = lo;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mflo %s\n", Reg(_rd_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsllv(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (regs[_rt_].u64[0] << (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsllv %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsrav(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ((int64_t)regs[_rt_].u64[0] >> (regs[_rs_].u32[0] & 0x3F));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsrav %s, %s, %s\n", Reg(_rd_), Reg(_rt_), Reg(_rs_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Mult(uint32_t instr)
|
||||
{
|
||||
uint64_t result = (int32_t)regs[_rs_].u32[0] * (int32_t)regs[_rt_].u32[0];
|
||||
|
||||
lo = regs[_rd_].u64[0] = (int64_t)(int32_t)result;
|
||||
hi = (int32_t)(result >> 32);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mult %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Multu(uint32_t instr)
|
||||
{
|
||||
uint64_t result = regs[_rs_].u32[0] * regs[_rt_].u32[0];
|
||||
|
||||
lo = regs[_rd_].u64[0] = (int64_t)(int32_t)result;
|
||||
hi = (int32_t)(result >> 32);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: multu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Div(uint32_t instr)
|
||||
{
|
||||
int64_t numerator = regs[_rs_].u64[0];
|
||||
int64_t denominator = regs[_rt_].u64[0];
|
||||
|
||||
if (numerator == (int64_t)0x80000000 && denominator == -1)
|
||||
{
|
||||
lo = 0x80000000;
|
||||
hi = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = numerator / denominator;
|
||||
hi = numerator % denominator;
|
||||
}
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: div %s, %s\n", Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Divu(uint32_t instr)
|
||||
{
|
||||
if (regs[_rt_].u32[0] == 0)
|
||||
{
|
||||
lo = 0xffffffff;
|
||||
hi = regs[_rs_].u32[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = regs[_rs_].u32[0] / regs[_rt_].u32[0];
|
||||
hi = regs[_rs_].u32[0] % regs[_rt_].u32[0];
|
||||
}
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: divu %s, %s\n", Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Addu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int32_t)regs[_rs_].u32[0] + (int32_t)regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: addu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Subu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)regs[_rs_].u64[0] - (int64_t)regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: subu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::And(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = regs[_rs_].u64[0] & regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: and %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Or(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = regs[_rs_].u64[0] | regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: or %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Nor(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ~(regs[_rs_].u64[0] | regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: nor %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Daddu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = regs[_rs_].u64[0] + regs[_rt_].u64[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: daddu %s, %s, %s (0x%08lx)\n", Reg(_rd_), Reg(_rs_), Reg(_rt_), regs[_rd_].u64[0]);
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsll(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(regs[_rt_].u64[0] << _sa_);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsll %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsll32(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (int64_t)(regs[_rt_].u64[0] << (_sa_ + 32));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsll32 %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Dsra32(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ((int64_t)regs[_rt_].u64[0] >> (_sa_ + 32));
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: dsra32 %s, %s, %d\n", Reg(_rd_), Reg(_rt_), _sa_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Slt(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = ((int64_t)regs[_rs_].u64[0] < (int64_t)regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: slt %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Sltu(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = (regs[_rs_].u64[0] < regs[_rt_].u64[0]);
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: sltu %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Bltz(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bltz %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] < 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Bgez(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bgez %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] >= 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
|
||||
void EEInterpreter::J(uint32_t instr)
|
||||
{
|
||||
next_pc = (next_pc & 0xf0000000) | _imm26_ << 2;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: j 0x%08x\n", next_pc);
|
||||
}
|
||||
|
||||
void EEInterpreter::Jal(uint32_t instr)
|
||||
{
|
||||
regs[31].u32[0] = next_pc;
|
||||
next_pc = (next_pc & 0xf0000000) | _imm26_ << 2;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: jal 0x%08x\n", next_pc);
|
||||
}
|
||||
|
||||
void EEInterpreter::Beq(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: beq %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), next_pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] == regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Bne(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bne %s, %s, 0x%08lx\n", Reg(_rs_), Reg(_rt_), pc + (_simm64_ << 2));
|
||||
|
||||
if (regs[_rs_].u64[0] != regs[_rt_].u64[0])
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Blez(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: blez %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] <= 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Bgtz(uint32_t instr)
|
||||
{
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: bgtz %s, 0x%08lx\n", Reg(_rs_), pc + (_simm64_ << 2));
|
||||
|
||||
if ((int64_t)regs[_rs_].u64[0] > 0)
|
||||
next_pc = pc + (_simm64_ << 2);
|
||||
}
|
||||
|
||||
void EEInterpreter::Addiu(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (int32_t)regs[_rs_].u32[0] + _simm32_;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: addiu %s, %s, 0x%08x\n", Reg(_rt_), Reg(_rs_), _simm32_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mflo1(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u64[0] = lo1;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mflo1 %s\n", Reg(_rd_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Divu1(uint32_t instr)
|
||||
{
|
||||
lo1 = regs[_rs_].u32[0] / regs[_rt_].u32[0];
|
||||
hi1 = regs[_rs_].u32[0] % regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: divu1 %s, %s\n", Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Mult1(uint32_t instr)
|
||||
{
|
||||
uint64_t result = (int32_t)regs[_rs_].u32[0] * (int32_t)regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mult1 %s, %s, %s (0x%08x, 0x%08x)\n", Reg(_rd_), Reg(_rs_), Reg(_rt_), (int32_t)regs[_rs_].u32[0], (int32_t)regs[_rt_].u32[0]);
|
||||
|
||||
lo1 = regs[_rd_].u64[0] = (int64_t)(int32_t)result;
|
||||
hi1 = (int32_t)(result >> 32);
|
||||
}
|
||||
|
||||
void EEInterpreter::Por(uint32_t instr)
|
||||
{
|
||||
regs[_rd_].u128 = regs[_rs_].u128 | regs[_rt_].u128;
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: por %s, %s, %s\n", Reg(_rd_), Reg(_rs_), Reg(_rt_));
|
||||
}
|
||||
|
||||
void EEInterpreter::Qmfc2(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u128 = VectorUnit::VU0::ReadReg(_rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Cfc2(uint32_t instr)
|
||||
{
|
||||
regs[_rt_].u64[0] = (int64_t)(int32_t)VectorUnit::VU0::ReadControl(_rd_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Qmtc2(uint32_t instr)
|
||||
{
|
||||
VectorUnit::VU0::WriteReg(_rd_, regs[_rt_].u128);
|
||||
}
|
||||
|
||||
void EEInterpreter::Ctc2(uint32_t instr)
|
||||
{
|
||||
VectorUnit::VU0::WriteControl(_rd_, regs[_rt_].u32[0]);
|
||||
}
|
||||
|
||||
void EEInterpreter::Mtc1(uint32_t instr)
|
||||
{
|
||||
cop1_regs[_rs_].u = regs[_rt_].u32[0];
|
||||
|
||||
if constexpr (CanDisassamble)
|
||||
printf("[emu/EE]: mtc1 %s, f%d\n", Reg(_rt_), _rs_);
|
||||
}
|
||||
|
||||
void EEInterpreter::Addas(uint32_t instr)
|
||||
{
|
||||
float op1 = convert(cop1_regs[_fs_].u);
|
||||
float op2 = convert(cop1_regs[_ft_].u);
|
||||
accumulator.f = op1 + op2;
|
||||
}
|
41
src/emu/cpu/ee/opcode.h
Normal file
41
src/emu/cpu/ee/opcode.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct EEOpcode
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t full;
|
||||
struct
|
||||
{ /* Used when polling for the opcode */
|
||||
uint32_t : 26;
|
||||
uint32_t opcode : 6;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t imm : 16;
|
||||
uint32_t rt : 5;
|
||||
uint32_t rs : 5;
|
||||
uint32_t opcode : 6;
|
||||
} i_type;
|
||||
struct
|
||||
{
|
||||
uint32_t target : 26;
|
||||
uint32_t opcode : 6;
|
||||
} j_type;
|
||||
struct
|
||||
{
|
||||
uint32_t func : 6;
|
||||
uint32_t sa : 5;
|
||||
uint32_t rd : 5;
|
||||
uint32_t rt : 5;
|
||||
uint32_t rs : 5;
|
||||
uint32_t opcode : 6;
|
||||
} r_type;
|
||||
};
|
||||
|
||||
uint32_t pc;
|
||||
bool is_delay_slot = false;
|
||||
bool branch_taken = false;
|
||||
};
|
|
@ -130,6 +130,7 @@ void WriteControl(int index, uint32_t data)
|
|||
switch (index)
|
||||
{
|
||||
case 1 ... 15:
|
||||
printf("Writing 0x%08x to vi%02d\n", data, index);
|
||||
vu0_state.vi[index] = data;
|
||||
break;
|
||||
case 16:
|
||||
|
@ -166,6 +167,7 @@ __uint128_t ReadReg(int index)
|
|||
|
||||
void WriteReg(int index, __uint128_t val)
|
||||
{
|
||||
printf("VU0: Writing %s to vf%02d\n", print_128({val}), index);
|
||||
vu0_state.vf[index].u128.u128 = val;
|
||||
}
|
||||
|
||||
|
@ -586,15 +588,15 @@ void Vsqi(uint32_t instr)
|
|||
auto& f = vu0_state.vf[fs];
|
||||
|
||||
if (x)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0x0, f.x);
|
||||
WriteDataMem32(0, vu0_state.vi[it]*16+0x0, f.x);
|
||||
if (y)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0x4, f.y);
|
||||
WriteDataMem32(0, vu0_state.vi[it]*16+0x4, f.y);
|
||||
if (z)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0x8, f.z);
|
||||
WriteDataMem32(0, vu0_state.vi[it]*16+0x8, f.z);
|
||||
if (w)
|
||||
WriteDataMem32(0, vu0_state.vi[it]+0xc, f.w);
|
||||
WriteDataMem32(0, vu0_state.vi[it]*16+0xc, f.w);
|
||||
|
||||
vu0_state.vi[it] += 0x10;
|
||||
VU0::vu0_state.vi[it]++;
|
||||
|
||||
printf("sqi.%s vf%02d, (vi%02d++).%s\n", dest_.c_str(), fs, it, dest_.c_str());
|
||||
}
|
||||
|
|
|
@ -67,6 +67,12 @@ struct VectorState
|
|||
|
||||
extern VectorState vu0_state;
|
||||
|
||||
|
||||
inline void Init()
|
||||
{
|
||||
vu0_state.vf[0].w = 1.0f;
|
||||
}
|
||||
|
||||
// VU0 specific stuff, like COP2 opcodes
|
||||
uint32_t ReadControl(int index);
|
||||
void WriteControl(int index, uint32_t data);
|
||||
|
|
1
src/emu/cpu/ee/x64/EEJitX64_Aliases.inl
Normal file
1
src/emu/cpu/ee/x64/EEJitX64_Aliases.inl
Normal file
|
@ -0,0 +1 @@
|
|||
#define MOV(a, b) generator->mov(a, b)
|
202
src/emu/cpu/ee/x64/EEJitx64.cpp
Normal file
202
src/emu/cpu/ee/x64/EEJitx64.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
#include "EEJitx64.h"
|
||||
#include "RegAllocator.h"
|
||||
#include <emu/cpu/ee/EEJit.h>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <3rdparty/xbyak/xbyak.h>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
Xbyak::CodeGenerator* generator;
|
||||
uint8_t* base;
|
||||
RegAllocatorX64 reg_alloc;
|
||||
|
||||
#include "EEJitX64_Aliases.inl"
|
||||
|
||||
void EEJitX64::JitStoreReg(GuestRegister reg)
|
||||
{
|
||||
auto offs = reg_alloc.GetRegOffset(reg);
|
||||
|
||||
generator->mov(generator->qword[generator->rbp + offs], Xbyak::Reg64(reg_alloc.GetHostReg(reg)));
|
||||
}
|
||||
|
||||
void EEJitX64::JitLoadReg(GuestRegister reg, int hostReg)
|
||||
{
|
||||
generator->mov(Xbyak::Reg64(hostReg), generator->qword[generator->rbp + reg_alloc.GetRegOffset(reg)]);
|
||||
}
|
||||
|
||||
void JitPrologue()
|
||||
{
|
||||
// Load RBP with the state pointer, passed in RDI
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (i != 4)
|
||||
generator->push(Xbyak::Reg64(i));
|
||||
MOV(generator->rbp, generator->rdi);
|
||||
MOV(generator->r8, generator->rsi);
|
||||
}
|
||||
|
||||
void JitEpilogue()
|
||||
{
|
||||
// First, we need to writeback all registers to memory
|
||||
reg_alloc.DoWriteback();
|
||||
|
||||
// Write R8 back to pc
|
||||
generator->mov(generator->qword[generator->rbp + offsetof(EmotionEngine::ProcessorState, pc)], generator->r8);
|
||||
generator->mov(generator->qword[generator->rbp + offsetof(EmotionEngine::ProcessorState, next_pc)], generator->r8);
|
||||
generator->add(generator->qword[generator->rbp + offsetof(EmotionEngine::ProcessorState, next_pc)], 4);
|
||||
|
||||
// Now restore all host registers
|
||||
for (int i = 15; i >= 0; i--)
|
||||
if (i != 4)
|
||||
generator->pop(Xbyak::Reg64(i));
|
||||
generator->ret();
|
||||
}
|
||||
|
||||
void JitMov(IRInstruction& i)
|
||||
{
|
||||
if (i.args[0].IsReg() && i.args[1].IsCop0())
|
||||
{
|
||||
if (i.args[1].GetReg() == 0)
|
||||
{
|
||||
printf("WARNING: Mov cop0 -> $zero\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto src = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)(i.args[0].GetReg()+COP0_OFFS)));
|
||||
auto dst = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg(), true));
|
||||
generator->mov(dst, src);
|
||||
}
|
||||
}
|
||||
else if (i.args[0].IsReg() && i.args[1].IsImm())
|
||||
{
|
||||
if (i.args[1].GetReg() == 0)
|
||||
{
|
||||
printf("WARNING: Mov imm -> $zero\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dst = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)(i.args[0].GetReg()), true));
|
||||
generator->mov(dst, i.args[1].GetImm64());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[EEJIT_X64]: Unknown src/dst combo for move\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void JitSlt(IRInstruction& i)
|
||||
{
|
||||
// Args[0] = dst, Args[1] = op1, Args[2] = op2
|
||||
if (i.args[2].IsImm())
|
||||
{
|
||||
if (i.is_unsigned)
|
||||
{
|
||||
printf("TODO: SLTIU\n");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dst = Xbyak::Reg8(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true));
|
||||
auto src = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg()));
|
||||
int32_t imm = i.args[2].GetImm();
|
||||
|
||||
generator->cmp(src, imm);
|
||||
generator->setl(dst);
|
||||
generator->movzx(Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg(), true)), dst);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unhandled SLT/SLTU\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void JitBranch(IRInstruction& i)
|
||||
{
|
||||
auto op1 = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[0].GetReg()));
|
||||
|
||||
Xbyak::Label cond_failed;
|
||||
|
||||
switch (i.b_type)
|
||||
{
|
||||
case IRInstruction::BranchType::EQ:
|
||||
{
|
||||
auto op2 = Xbyak::Reg64(reg_alloc.GetHostReg((GuestRegister)i.args[1].GetReg()));
|
||||
generator->cmp(op1, op2);
|
||||
generator->jne(cond_failed);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("Unknown branch condition %d\n", i.b_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
generator->add(generator->r8, i.args[2].GetImm());
|
||||
generator->L(cond_failed);
|
||||
}
|
||||
|
||||
void JitIncPC()
|
||||
{
|
||||
generator->add(generator->r8, 4);
|
||||
}
|
||||
|
||||
void EEJitX64::TranslateBlock(Block *block)
|
||||
{
|
||||
block->entryPoint = (blockEntry)generator->getCurr();
|
||||
|
||||
for (auto& i : block->instructions)
|
||||
{
|
||||
if (i.instr != 0x00)
|
||||
JitIncPC();
|
||||
|
||||
switch (i.instr)
|
||||
{
|
||||
case 0x00:
|
||||
JitPrologue();
|
||||
break;
|
||||
case 0x01:
|
||||
JitEpilogue();
|
||||
break;
|
||||
case 0x02:
|
||||
JitMov(i);
|
||||
break;
|
||||
case 0x03:
|
||||
JitSlt(i);
|
||||
break;
|
||||
case 0x04:
|
||||
JitBranch(i);
|
||||
break;
|
||||
default:
|
||||
printf("[EEJIT_X64]: Cannot emit unknown IR instruction 0x%02x\n", i.instr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EEJitX64::Initialize()
|
||||
{
|
||||
base = (uint8_t*)mmap(nullptr, 0xffffffff, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
|
||||
if (base == MAP_FAILED)
|
||||
{
|
||||
printf("[EEJIT_X64]: Failed to map base! %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
generator = new Xbyak::CodeGenerator(0xffffffff, (void*)base);
|
||||
}
|
||||
|
||||
void EEJitX64::Dump()
|
||||
{
|
||||
std::ofstream file("code.out", std::ios::binary);
|
||||
file.write((char*)base, generator->getSize());
|
||||
file.close();
|
||||
}
|
21
src/emu/cpu/ee/x64/EEJitx64.h
Normal file
21
src/emu/cpu/ee/x64/EEJitx64.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "GuestRegister.h"
|
||||
|
||||
struct Block;
|
||||
|
||||
namespace EEJitX64
|
||||
{
|
||||
|
||||
void JitStoreReg(GuestRegister reg);
|
||||
void JitLoadReg(GuestRegister reg, int hostReg);
|
||||
|
||||
// Translate a JIT block from IR to host code
|
||||
// Modifies the `entry` pointer in the block
|
||||
void TranslateBlock(Block* block);
|
||||
|
||||
void Initialize();
|
||||
|
||||
void Dump();
|
||||
|
||||
}
|
55
src/emu/cpu/ee/x64/GuestRegister.h
Normal file
55
src/emu/cpu/ee/x64/GuestRegister.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
|
||||
enum GuestRegister
|
||||
{
|
||||
NONE,
|
||||
REG_AT,
|
||||
REG_V0,
|
||||
REG_V1,
|
||||
REG_A0,
|
||||
REG_A1,
|
||||
REG_A2,
|
||||
REG_A3,
|
||||
REG_T0,
|
||||
REG_T1,
|
||||
REG_T2,
|
||||
REG_T3,
|
||||
REG_T4,
|
||||
REG_T5,
|
||||
REG_T6,
|
||||
REG_T7,
|
||||
REG_S0,
|
||||
REG_S1,
|
||||
REG_S2,
|
||||
REG_S3,
|
||||
REG_S4,
|
||||
REG_S5,
|
||||
REG_S6,
|
||||
REG_S7,
|
||||
REG_T8,
|
||||
REG_T9,
|
||||
REG_K0,
|
||||
REG_K1,
|
||||
REG_GP,
|
||||
REG_SP,
|
||||
REG_FP,
|
||||
REG_RA,
|
||||
COP0_OFFS = REG_RA,
|
||||
REG_COP0_INDEX,
|
||||
REG_COP0_RANDOM,
|
||||
REG_COP0_ENTRYLO0,
|
||||
REG_COP0_ENTRYLO1,
|
||||
REG_COP0_CONTEXT,
|
||||
REG_COP0_PAGEMASK,
|
||||
REG_COP0_WIRED,
|
||||
REG_COP0_BADVADDR,
|
||||
REG_COP0_COUNT,
|
||||
REG_COP0_ENTRYHI,
|
||||
REG_COP0_COMPARE,
|
||||
REG_COP0_STATUS,
|
||||
REG_COP0_CAUSE,
|
||||
REG_COP0_EPC,
|
||||
REG_COP0_PRID,
|
||||
};
|
177
src/emu/cpu/ee/x64/RegAllocator.cpp
Normal file
177
src/emu/cpu/ee/x64/RegAllocator.cpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
#include "RegAllocator.h"
|
||||
#include "EEJitx64.h"
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
|
||||
enum HostRegisters
|
||||
{
|
||||
RAX,
|
||||
RCX,
|
||||
RDX,
|
||||
RBX,
|
||||
RSP,
|
||||
RBP,
|
||||
RSI,
|
||||
RDI,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15
|
||||
};
|
||||
|
||||
struct HostRegister
|
||||
{
|
||||
bool allocated;
|
||||
GuestRegister mapping;
|
||||
int used = 0;
|
||||
} regs[16];
|
||||
|
||||
size_t RegAllocatorX64::GetRegOffset(GuestRegister reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case GuestRegister::REG_AT: return offsetof(EmotionEngine::ProcessorState, regs[1]);
|
||||
case GuestRegister::REG_V0: return offsetof(EmotionEngine::ProcessorState, regs[2]);
|
||||
case GuestRegister::REG_V1: return offsetof(EmotionEngine::ProcessorState, regs[3]);
|
||||
case GuestRegister::REG_A0: return offsetof(EmotionEngine::ProcessorState, regs[4]);
|
||||
case GuestRegister::REG_A1: return offsetof(EmotionEngine::ProcessorState, regs[5]);
|
||||
case GuestRegister::REG_A2: return offsetof(EmotionEngine::ProcessorState, regs[6]);
|
||||
case GuestRegister::REG_A3: return offsetof(EmotionEngine::ProcessorState, regs[7]);
|
||||
case GuestRegister::REG_T0: return offsetof(EmotionEngine::ProcessorState, regs[8]);
|
||||
case GuestRegister::REG_T1: return offsetof(EmotionEngine::ProcessorState, regs[9]);
|
||||
case GuestRegister::REG_T2: return offsetof(EmotionEngine::ProcessorState, regs[10]);
|
||||
case GuestRegister::REG_T3: return offsetof(EmotionEngine::ProcessorState, regs[11]);
|
||||
case GuestRegister::REG_T4: return offsetof(EmotionEngine::ProcessorState, regs[12]);
|
||||
case GuestRegister::REG_T5: return offsetof(EmotionEngine::ProcessorState, regs[13]);
|
||||
case GuestRegister::REG_T6: return offsetof(EmotionEngine::ProcessorState, regs[14]);
|
||||
case GuestRegister::REG_T7: return offsetof(EmotionEngine::ProcessorState, regs[15]);
|
||||
case GuestRegister::REG_S0: return offsetof(EmotionEngine::ProcessorState, regs[16]);
|
||||
case GuestRegister::REG_S1: return offsetof(EmotionEngine::ProcessorState, regs[17]);
|
||||
case GuestRegister::REG_S2: return offsetof(EmotionEngine::ProcessorState, regs[18]);
|
||||
case GuestRegister::REG_S3: return offsetof(EmotionEngine::ProcessorState, regs[19]);
|
||||
case GuestRegister::REG_S4: return offsetof(EmotionEngine::ProcessorState, regs[20]);
|
||||
case GuestRegister::REG_S5: return offsetof(EmotionEngine::ProcessorState, regs[21]);
|
||||
case GuestRegister::REG_S6: return offsetof(EmotionEngine::ProcessorState, regs[22]);
|
||||
case GuestRegister::REG_S7: return offsetof(EmotionEngine::ProcessorState, regs[23]);
|
||||
case GuestRegister::REG_T8: return offsetof(EmotionEngine::ProcessorState, regs[24]);
|
||||
case GuestRegister::REG_T9: return offsetof(EmotionEngine::ProcessorState, regs[25]);
|
||||
case GuestRegister::REG_K0: return offsetof(EmotionEngine::ProcessorState, regs[26]);
|
||||
case GuestRegister::REG_K1: return offsetof(EmotionEngine::ProcessorState, regs[27]);
|
||||
case GuestRegister::REG_GP: return offsetof(EmotionEngine::ProcessorState, regs[28]);
|
||||
case GuestRegister::REG_SP: return offsetof(EmotionEngine::ProcessorState, regs[29]);
|
||||
case GuestRegister::REG_FP: return offsetof(EmotionEngine::ProcessorState, regs[30]);
|
||||
case GuestRegister::REG_RA: return offsetof(EmotionEngine::ProcessorState, regs[31]);
|
||||
case GuestRegister::REG_COP0_PRID: return offsetof(EmotionEngine::ProcessorState, cop0_regs[15]);
|
||||
default:
|
||||
printf("[REGALLOC_X64]: Couldn't find offset of unknown guest register %d\n", (int)reg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int RegAllocatorX64::GetHostReg(GuestRegister reg, bool dest)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (regs[i].mapping == reg)
|
||||
{
|
||||
regs[i].used++;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// No reg found, replacement time
|
||||
|
||||
// First look for unallocated registers
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (!regs[i].allocated)
|
||||
{
|
||||
regs[i].allocated = true;
|
||||
regs[i].mapping = reg;
|
||||
regs[i].used = 1;
|
||||
if (!dest)
|
||||
EEJitX64::JitLoadReg(reg, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
int hitsLeast = -1;
|
||||
|
||||
// Find the least used register
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
printf("%d\n", regs[i].used);
|
||||
if (regs[i].used > hitsLeast)
|
||||
{
|
||||
hitsLeast = regs[i].used;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Write back the register
|
||||
EEJitX64::JitStoreReg(regs[index].mapping);
|
||||
|
||||
regs[index].mapping = reg;
|
||||
regs[index].used = 1;
|
||||
if (!dest)
|
||||
EEJitX64::JitLoadReg(reg, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
void RegAllocatorX64::DoWriteback()
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (regs[i].allocated && regs[i].mapping != GuestRegister::NONE)
|
||||
{
|
||||
EEJitX64::JitStoreReg(regs[i].mapping);
|
||||
regs[i].allocated = false;
|
||||
regs[i].mapping = GuestRegister::NONE;
|
||||
regs[i].used = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegAllocatorX64::RegAllocatorX64()
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
regs[i].allocated = false;
|
||||
regs[i].mapping = GuestRegister::NONE;
|
||||
regs[i].used = 0;
|
||||
}
|
||||
|
||||
// Mark RSP, RBP, RAX, RDI, RSI, and R8 as used
|
||||
// RSP is used for the stack (and it should never be overwritten)
|
||||
// RBP is used to point to the processor state
|
||||
// RAX is used for return values
|
||||
// RDI and RSI are used for passing values to functions
|
||||
// R8 holds the current value of pc
|
||||
regs[RSP].allocated = true;
|
||||
regs[RSP].mapping = GuestRegister::NONE;
|
||||
regs[RSP].used = -1;
|
||||
|
||||
regs[RBP].allocated = true;
|
||||
regs[RBP].mapping = GuestRegister::NONE;
|
||||
regs[RBP].used = -1;
|
||||
|
||||
regs[RAX].allocated = true;
|
||||
regs[RAX].mapping = GuestRegister::NONE;
|
||||
regs[RAX].used = -1;
|
||||
|
||||
regs[RDI].allocated = true;
|
||||
regs[RDI].mapping = GuestRegister::NONE;
|
||||
regs[RDI].used = -1;
|
||||
|
||||
regs[RSI].allocated = true;
|
||||
regs[RSI].mapping = GuestRegister::NONE;
|
||||
regs[RSI].used = -1;
|
||||
|
||||
regs[R8].allocated = true;
|
||||
regs[R8].mapping = GuestRegister::NONE;
|
||||
regs[R8].used = -1;
|
||||
}
|
16
src/emu/cpu/ee/x64/RegAllocator.h
Normal file
16
src/emu/cpu/ee/x64/RegAllocator.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "GuestRegister.h"
|
||||
|
||||
class RegAllocatorX64
|
||||
{
|
||||
public:
|
||||
RegAllocatorX64();
|
||||
|
||||
int GetHostReg(GuestRegister reg, bool dest = false);
|
||||
size_t GetRegOffset(GuestRegister reg);
|
||||
void DoWriteback();
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -1,132 +0,0 @@
|
|||
// (c) Copyright 2022-2023 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <emu/cpu/ee/x64/reg_alloc.h>
|
||||
#include <3rdparty/xbyak/xbyak.h>
|
||||
#include <emu/cpu/ee/EmotionEngine.h>
|
||||
#include <vector>
|
||||
|
||||
namespace EE_JIT
|
||||
{
|
||||
|
||||
struct Block;
|
||||
struct IRInstruction;
|
||||
|
||||
class Emitter
|
||||
{
|
||||
private:
|
||||
Xbyak::CodeGenerator* cg;
|
||||
uint8_t* base;
|
||||
uint8_t* free_base;
|
||||
RegisterAllocator* reg_alloc;
|
||||
size_t sizeWithoutCurBlock = 0;
|
||||
|
||||
void EmitSaveHostRegs();
|
||||
void EmitRestoreHostRegs();
|
||||
void EmitMov(IRInstruction i);
|
||||
void EmitPMFLO(IRInstruction i);
|
||||
void EmitPMFHI(IRInstruction i);
|
||||
void EmitMovCond(IRInstruction i);
|
||||
void EmitSLTI(IRInstruction i);
|
||||
void EmitBC(IRInstruction i);
|
||||
void EmitIncPC(IRInstruction i);
|
||||
void EmitOR(IRInstruction i);
|
||||
void EmitNOR(IRInstruction i);
|
||||
void EmitXOR(IRInstruction i);
|
||||
void EmitAND(IRInstruction i);
|
||||
void EmitJA(IRInstruction i);
|
||||
void EmitJumpImm(IRInstruction i);
|
||||
void EmitAdd(IRInstruction i);
|
||||
void EmitSub(IRInstruction i);
|
||||
void EmitMemoryStore(IRInstruction i);
|
||||
void EmitMemoryLoad(IRInstruction i);
|
||||
void EmitLDL(IRInstruction i);
|
||||
void EmitLDR(IRInstruction i);
|
||||
void EmitSDL(IRInstruction i);
|
||||
void EmitSDR(IRInstruction i);
|
||||
void EmitShift(IRInstruction i);
|
||||
void EmitShift64(IRInstruction i);
|
||||
void EmitMULT(IRInstruction i);
|
||||
void EmitDIV(IRInstruction i);
|
||||
void EmitUhOh(IRInstruction i);
|
||||
void EmitIR(IRInstruction i);
|
||||
void EmitMoveFromLo(IRInstruction i);
|
||||
void EmitMoveFromHi(IRInstruction i);
|
||||
void EmitBranchRegImm(IRInstruction i);
|
||||
void EmitUpdateCopCount(IRInstruction i);
|
||||
void EmitPOR(IRInstruction i);
|
||||
void EmitPADDUSW(IRInstruction i);
|
||||
void EmitDI(IRInstruction i);
|
||||
void EmitERET(IRInstruction i);
|
||||
void EmitSyscall(IRInstruction i);
|
||||
void EmitEI(IRInstruction i);
|
||||
void EmitPLZCW(IRInstruction i);
|
||||
void EmitMTLO(IRInstruction i);
|
||||
void EmitMTHI(IRInstruction i);
|
||||
void EmitPCPYLD(IRInstruction i);
|
||||
void EmitPSUBB(IRInstruction i);
|
||||
void EmitPADDSB(IRInstruction i);
|
||||
void EmitPNOR(IRInstruction i);
|
||||
void EmitPAND(IRInstruction i);
|
||||
void EmitPCPYUD(IRInstruction i);
|
||||
void EmitBC0T(IRInstruction i);
|
||||
void EmitBC0F(IRInstruction i);
|
||||
void EmitPCPYH(IRInstruction i);
|
||||
void EmitCFC2(IRInstruction i);
|
||||
void EmitCTC2(IRInstruction i);
|
||||
void EmitVISWR(IRInstruction i);
|
||||
void EmitQMFC2(IRInstruction i);
|
||||
void EmitQMTC2(IRInstruction i);
|
||||
void EmitVSUB(IRInstruction i);
|
||||
void EmitVSQI(IRInstruction i);
|
||||
void EmitVIADD(IRInstruction i);
|
||||
void EmitADDA(IRInstruction i);
|
||||
void EmitMADD(IRInstruction i);
|
||||
void EmitMADDS(IRInstruction i);
|
||||
void EmitCVTS(IRInstruction i);
|
||||
void EmitMULS(IRInstruction i);
|
||||
void EmitCVTW(IRInstruction i);
|
||||
void EmitDIVS(IRInstruction i);
|
||||
void EmitMOVS(IRInstruction i);
|
||||
void EmitADDS(IRInstruction i);
|
||||
void EmitSUBS(IRInstruction i);
|
||||
void EmitNEGS(IRInstruction i);
|
||||
void EmitLQC2(IRInstruction i);
|
||||
void EmitSQC2(IRInstruction i);
|
||||
void EmitVMULAX(IRInstruction i);
|
||||
void EmitVMADDAX(IRInstruction i);
|
||||
void EmitVMADDAY(IRInstruction i);
|
||||
void EmitVMADDAZ(IRInstruction i);
|
||||
void EmitVMADDW(IRInstruction i);
|
||||
void EmitVMADDZ(IRInstruction i);
|
||||
void EmitVMULAW(IRInstruction i);
|
||||
void EmitVCLIPW(IRInstruction i);
|
||||
void EmitCLES(IRInstruction i);
|
||||
void EmitCEQS(IRInstruction i);
|
||||
void EmitBC1F(IRInstruction i);
|
||||
void EmitBC1T(IRInstruction i);
|
||||
|
||||
EE_JIT::JIT::EntryFunc dispatcher_entry;
|
||||
public:
|
||||
Emitter();
|
||||
void Dump();
|
||||
void TranslateBlock(Block* block);
|
||||
|
||||
void EnterDispatcher();
|
||||
|
||||
void ResetFreeBase()
|
||||
{
|
||||
free_base = base;
|
||||
delete cg;
|
||||
cg = new Xbyak::CodeGenerator(0xffffffff, base);
|
||||
}
|
||||
|
||||
uint8_t* GetFreeBase();
|
||||
};
|
||||
|
||||
extern Emitter* emit;
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
// (c) Copyright 2022 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#include "reg_alloc.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
RegisterAllocator::RegisterAllocator()
|
||||
{
|
||||
Reset();
|
||||
// Here just in case I have to do any initialization in the future
|
||||
}
|
||||
|
||||
void RegisterAllocator::Reset()
|
||||
{
|
||||
used_xmm_registers.fill(false);
|
||||
used_registers.fill(false);
|
||||
used_registers_8.fill(false);
|
||||
MarkRegUsed(RBP);
|
||||
MarkRegUsed(RSP);
|
||||
}
|
||||
|
||||
int RegisterAllocator::AllocHostRegister()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (!used_registers[i])
|
||||
{
|
||||
used_registers[i] = true;
|
||||
if (i < 4)
|
||||
{
|
||||
int ind = i * 2;
|
||||
used_registers_8[ind] = true;
|
||||
used_registers_8[ind+1] = true;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[JIT/RegAlloc]: Ran out of host registers!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int RegisterAllocator::AllocHostXMMRegister()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (!used_xmm_registers[i])
|
||||
{
|
||||
used_xmm_registers[i] = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[JIT/RegAlloc]: Ran out of host xmm registers!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void RegisterAllocator::MarkRegUsed(int reg)
|
||||
{
|
||||
used_registers[reg] = true;
|
||||
if (reg < 4)
|
||||
{
|
||||
int ind = reg * 2;
|
||||
used_registers_8[ind] = true;
|
||||
used_registers_8[ind+1] = true;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// (c) Copyright 2022 Ryan Ilari
|
||||
// This code is licensed under MIT license (see LICENSE for details)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
class RegisterAllocator
|
||||
{
|
||||
private:
|
||||
std::array<bool, 8> used_registers;
|
||||
// Due to how 8-bit registers map, we have a seperate array
|
||||
std::array<bool, 8> used_registers_8;
|
||||
std::array<bool, 8> used_xmm_registers;
|
||||
|
||||
public:
|
||||
enum HostRegisters64
|
||||
{
|
||||
RAX,
|
||||
RCX,
|
||||
RDX,
|
||||
RBX,
|
||||
RSP,
|
||||
RBP,
|
||||
RSI,
|
||||
RDI
|
||||
};
|
||||
|
||||
RegisterAllocator();
|
||||
void Reset();
|
||||
|
||||
int AllocHostRegister();
|
||||
int AllocHostXMMRegister();
|
||||
void MarkRegUsed(int reg);
|
||||
};
|
|
@ -32,7 +32,7 @@ uint32_t Bus::spu2_stat = 0;
|
|||
|
||||
uint32_t Translate(uint32_t addr)
|
||||
{
|
||||
constexpr uint32_t KUSEG_MASKS[8] =
|
||||
constexpr uint32_t KUSEG_MASKS[8] =
|
||||
{
|
||||
/* KUSEG: Don't touch the address, it's fine */
|
||||
0xffffffff, 0xfffffff, 0xfffffff, 0xffffffff,
|
||||
|
@ -44,12 +44,8 @@ uint32_t Translate(uint32_t addr)
|
|||
0xffffffff, 0x1fffffff,
|
||||
};
|
||||
|
||||
if (addr >= 0xFFFF8000) [[unlikely]]
|
||||
{
|
||||
return (addr - 0xFFFF8000) + 0x78000;
|
||||
}
|
||||
|
||||
addr &= KUSEG_MASKS[addr >> 29];
|
||||
if ((addr & 0xF0000000) != 0x70000000)
|
||||
addr &= 0x1FFFFFFF;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
@ -65,6 +61,7 @@ void Bus::LoadBios(uint8_t *data)
|
|||
console.open("console.txt");
|
||||
|
||||
GS::Initialize();
|
||||
VectorUnit::VU0::Init();
|
||||
}
|
||||
|
||||
void Bus::Dump()
|
||||
|
@ -436,17 +433,22 @@ void Bus::Write64(uint32_t addr, uint64_t data)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
bool firstTime = true;
|
||||
|
||||
void Bus::Write32(uint32_t addr, uint32_t data)
|
||||
{
|
||||
EmotionEngine::MarkDirty(addr, sizeof(data));
|
||||
|
||||
if (addr == 0x8001e140)
|
||||
{
|
||||
printf("Writing 0x%08x to GIFTAG stuff\n", data);
|
||||
}
|
||||
|
||||
addr = Translate(addr);
|
||||
|
||||
if (addr == 0x10c0 && data == 0 && !firstTime)
|
||||
{
|
||||
printf("Writing 0 to 0x10c0\n");
|
||||
exit(1);
|
||||
}
|
||||
else if (addr == 0x10c0 && data == 0)
|
||||
firstTime = false;
|
||||
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
{
|
||||
*reinterpret_cast<uint32_t*>(&spr[addr - 0x70000000]) = data;
|
||||
|
@ -778,6 +780,8 @@ uint32_t Bus::LoadElf(std::string name)
|
|||
{
|
||||
auto pheader = *(Elf32_Phdr*)&buffer[i];
|
||||
|
||||
printf("Phdr: Load: 0x%08x\n", pheader.p_vaddr);
|
||||
|
||||
int mem_w = pheader.p_paddr;
|
||||
for (auto file_w = pheader.p_offset; file_w < pheader.p_offset+pheader.p_filesz; file_w += 4)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue