First block compiled with new JIT

This commit is contained in:
google0101-ryan 2023-11-01 18:42:46 -04:00
parent e15268d451
commit 12aeadd143
25 changed files with 41329 additions and 8488 deletions

View file

@ -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()

40376
file Normal file

File diff suppressed because it is too large Load diff

View file

@ -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
View 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
View 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

View file

@ -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)

View file

@ -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
}

View file

@ -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));
}

View file

@ -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
}

View file

@ -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
View 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;
};

View file

@ -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());
}

View file

@ -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);

View file

@ -0,0 +1 @@
#define MOV(a, b) generator->mov(a, b)

View 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();
}

View 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();
}

View 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,
};

View 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;
}

View 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

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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);
};

View file

@ -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)
{