Added first instruction

This commit is contained in:
Your Name 2023-01-03 03:48:00 -05:00
parent 1bbe22910c
commit cb5ecc4b2a
14 changed files with 6910 additions and 66 deletions

View file

@ -19,7 +19,9 @@ set(SOURCES src/main.cpp
src/app/Application.cpp
src/emu/memory/Bus.cpp
src/emu/System.cpp
src/emu/cpu/ee/EmotionEngine.cpp)
src/emu/cpu/ee/EmotionEngine.cpp
src/emu/cpu/ee/x64/reg_alloc.cpp
src/emu/cpu/ee/x64/emit.cpp)
set(CMAKE_BUILD_TYPE Debug)

2951
src/3rdparty/xbyak/xbyak.h vendored Normal file

File diff suppressed because it is too large Load diff

258
src/3rdparty/xbyak/xbyak_bin2hex.h vendored Normal file
View file

@ -0,0 +1,258 @@
enum {
B00000000= 0,
B00000001= 1,
B00000010= 2,
B00000011= 3,
B00000100= 4,
B00000101= 5,
B00000110= 6,
B00000111= 7,
B00001000= 8,
B00001001= 9,
B00001010= 10,
B00001011= 11,
B00001100= 12,
B00001101= 13,
B00001110= 14,
B00001111= 15,
B00010000= 16,
B00010001= 17,
B00010010= 18,
B00010011= 19,
B00010100= 20,
B00010101= 21,
B00010110= 22,
B00010111= 23,
B00011000= 24,
B00011001= 25,
B00011010= 26,
B00011011= 27,
B00011100= 28,
B00011101= 29,
B00011110= 30,
B00011111= 31,
B00100000= 32,
B00100001= 33,
B00100010= 34,
B00100011= 35,
B00100100= 36,
B00100101= 37,
B00100110= 38,
B00100111= 39,
B00101000= 40,
B00101001= 41,
B00101010= 42,
B00101011= 43,
B00101100= 44,
B00101101= 45,
B00101110= 46,
B00101111= 47,
B00110000= 48,
B00110001= 49,
B00110010= 50,
B00110011= 51,
B00110100= 52,
B00110101= 53,
B00110110= 54,
B00110111= 55,
B00111000= 56,
B00111001= 57,
B00111010= 58,
B00111011= 59,
B00111100= 60,
B00111101= 61,
B00111110= 62,
B00111111= 63,
B01000000= 64,
B01000001= 65,
B01000010= 66,
B01000011= 67,
B01000100= 68,
B01000101= 69,
B01000110= 70,
B01000111= 71,
B01001000= 72,
B01001001= 73,
B01001010= 74,
B01001011= 75,
B01001100= 76,
B01001101= 77,
B01001110= 78,
B01001111= 79,
B01010000= 80,
B01010001= 81,
B01010010= 82,
B01010011= 83,
B01010100= 84,
B01010101= 85,
B01010110= 86,
B01010111= 87,
B01011000= 88,
B01011001= 89,
B01011010= 90,
B01011011= 91,
B01011100= 92,
B01011101= 93,
B01011110= 94,
B01011111= 95,
B01100000= 96,
B01100001= 97,
B01100010= 98,
B01100011= 99,
B01100100= 100,
B01100101= 101,
B01100110= 102,
B01100111= 103,
B01101000= 104,
B01101001= 105,
B01101010= 106,
B01101011= 107,
B01101100= 108,
B01101101= 109,
B01101110= 110,
B01101111= 111,
B01110000= 112,
B01110001= 113,
B01110010= 114,
B01110011= 115,
B01110100= 116,
B01110101= 117,
B01110110= 118,
B01110111= 119,
B01111000= 120,
B01111001= 121,
B01111010= 122,
B01111011= 123,
B01111100= 124,
B01111101= 125,
B01111110= 126,
B01111111= 127,
B10000000= 128,
B10000001= 129,
B10000010= 130,
B10000011= 131,
B10000100= 132,
B10000101= 133,
B10000110= 134,
B10000111= 135,
B10001000= 136,
B10001001= 137,
B10001010= 138,
B10001011= 139,
B10001100= 140,
B10001101= 141,
B10001110= 142,
B10001111= 143,
B10010000= 144,
B10010001= 145,
B10010010= 146,
B10010011= 147,
B10010100= 148,
B10010101= 149,
B10010110= 150,
B10010111= 151,
B10011000= 152,
B10011001= 153,
B10011010= 154,
B10011011= 155,
B10011100= 156,
B10011101= 157,
B10011110= 158,
B10011111= 159,
B10100000= 160,
B10100001= 161,
B10100010= 162,
B10100011= 163,
B10100100= 164,
B10100101= 165,
B10100110= 166,
B10100111= 167,
B10101000= 168,
B10101001= 169,
B10101010= 170,
B10101011= 171,
B10101100= 172,
B10101101= 173,
B10101110= 174,
B10101111= 175,
B10110000= 176,
B10110001= 177,
B10110010= 178,
B10110011= 179,
B10110100= 180,
B10110101= 181,
B10110110= 182,
B10110111= 183,
B10111000= 184,
B10111001= 185,
B10111010= 186,
B10111011= 187,
B10111100= 188,
B10111101= 189,
B10111110= 190,
B10111111= 191,
B11000000= 192,
B11000001= 193,
B11000010= 194,
B11000011= 195,
B11000100= 196,
B11000101= 197,
B11000110= 198,
B11000111= 199,
B11001000= 200,
B11001001= 201,
B11001010= 202,
B11001011= 203,
B11001100= 204,
B11001101= 205,
B11001110= 206,
B11001111= 207,
B11010000= 208,
B11010001= 209,
B11010010= 210,
B11010011= 211,
B11010100= 212,
B11010101= 213,
B11010110= 214,
B11010111= 215,
B11011000= 216,
B11011001= 217,
B11011010= 218,
B11011011= 219,
B11011100= 220,
B11011101= 221,
B11011110= 222,
B11011111= 223,
B11100000= 224,
B11100001= 225,
B11100010= 226,
B11100011= 227,
B11100100= 228,
B11100101= 229,
B11100110= 230,
B11100111= 231,
B11101000= 232,
B11101001= 233,
B11101010= 234,
B11101011= 235,
B11101100= 236,
B11101101= 237,
B11101110= 238,
B11101111= 239,
B11110000= 240,
B11110001= 241,
B11110010= 242,
B11110011= 243,
B11110100= 244,
B11110101= 245,
B11110110= 246,
B11110111= 247,
B11111000= 248,
B11111001= 249,
B11111010= 250,
B11111011= 251,
B11111100= 252,
B11111101= 253,
B11111110= 254,
B11111111= 255
};

2331
src/3rdparty/xbyak/xbyak_mnemonic.h vendored Normal file

File diff suppressed because it is too large Load diff

1000
src/3rdparty/xbyak/xbyak_util.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -48,4 +48,6 @@ void Application::Exit(int code)
}
void Application::Exit()
{}
{
System::Dump();
}

View file

@ -35,4 +35,9 @@ void System::Run()
{
while (1)
EmotionEngine::Clock();
}
}
void System::Dump()
{
EmotionEngine::Dump();
}

View file

@ -11,5 +11,6 @@ void LoadBios(std::string biosName);
void Reset();
void Run();
void Dump();
}

View file

@ -1,55 +1,34 @@
#include "EmotionEngine.h"
#include <emu/memory/Bus.h>
#include <emu/cpu/ee/x64/emit.h>
namespace EE_JIT
{
enum IRInstrs
void JIT::EmitBNE(uint32_t instr, EE_JIT::IRInstruction &i)
{
MOV = 0,
NOP = 0,
SLTI = 0,
};
printf("bne\n");
struct IRValue
{
public:
enum Type
{
Imm,
Reg,
Cop0Reg,
FP
};
private:
union
{
uint32_t imm;
int register_num;
float fp_value;
int cop_regnum;
} value;
int rt = (instr >> 16) & 0x1F;
int rs = (instr >> 21) & 0x1F;
Type type;
public:
IRValue(Type type)
: type(type) {}
IRValue dest = IRValue(IRValue::Reg);
IRValue source = IRValue(IRValue::Reg);
IRValue imm = IRValue(IRValue::Imm);
bool IsImm() {return type == Imm;}
// Can be used for guest and COP0 registers
void SetReg(uint32_t reg) {value.register_num = reg;}
void SetImm(uint16_t imm) {value.imm = (int32_t)(int16_t)imm;}
};
source.SetReg(rs);
dest.SetReg(rt);
imm.SetImm(instr & 0xffff);
struct IRInstruction
{
uint8_t instr;
// Arguments are right -> left
std::vector<IRValue> args;
};
i = IRInstruction::Build({dest, source, imm}, IRInstrs::BranchConditional);
i.b_type = IRInstruction::BranchType::NE;
cur_block->ir.push_back(i);
}
void JIT::EmitSLTI(uint32_t instr, EE_JIT::IRInstruction &i)
{
printf("slti\n");
int rt = (instr >> 16) & 0x1F;
int rs = (instr >> 21) & 0x1F;
@ -60,10 +39,7 @@ void JIT::EmitSLTI(uint32_t instr, EE_JIT::IRInstruction &i)
dest.SetReg(rt);
imm.SetImm(instr & 0xffff);
i.instr = IRInstrs::SLTI;
i.args.push_back(imm);
i.args.push_back(source);
i.args.push_back(dest);
i = IRInstruction::Build({dest, source, imm}, IRInstrs::SLTI);
cur_block->ir.push_back(i);
}
@ -87,6 +63,8 @@ void JIT::EmitCOP0(uint32_t instr, EE_JIT::IRInstruction &i)
void JIT::EmitMFC0(uint32_t instr, EE_JIT::IRInstruction& i)
{
printf("mfc0\n");
int rd = (instr >> 11) & 0x1F;
int rt = (instr >> 16) & 0x1F;
@ -95,25 +73,19 @@ void JIT::EmitMFC0(uint32_t instr, EE_JIT::IRInstruction& i)
dest.SetReg(rd);
src.SetReg(rt);
i.instr = IRInstrs::MOV;
i.args.push_back(src);
i.args.push_back(dest);
i = IRInstruction::Build({dest, src}, IRInstrs::MOV);
cur_block->ir.push_back(i);
}
void JIT::EmitIR(uint32_t instr)
{
if (!cur_block)
{
cur_block = new Block;
}
EE_JIT::IRInstruction current_instruction;
if (instr == 0)
{
printf("nop\n");
current_instruction.instr = NOP;
cur_block->ir.push_back(current_instruction);
return;
@ -123,6 +95,9 @@ void JIT::EmitIR(uint32_t instr)
switch (opcode)
{
case 0x05:
EmitBNE(instr, current_instruction);
break;
case 0x0A:
EmitSLTI(instr, current_instruction);
break;
@ -135,6 +110,26 @@ void JIT::EmitIR(uint32_t instr)
}
}
void JIT::EmitPrequel()
{
if (!cur_block)
{
cur_block = new Block;
}
auto i = IRInstruction::Build({}, IRInstrs::SaveHostRegs);
cur_block->ir.push_back(i);
}
void JIT::EmitDone()
{
auto i = IRInstruction::Build({}, IRInstrs::RestoreHostRegs);
cur_block->ir.push_back(i);
blockCache.push_back(cur_block);
EE_JIT::emit->TranslateBlock(cur_block);
}
}
EE_JIT::JIT jit;
@ -149,15 +144,53 @@ void Reset()
state.pc = 0xBFC00000;
state.next_pc = 0xBFC00004;
EE_JIT::emit = new EE_JIT::Emitter();
}
bool IsBranch(uint32_t instr)
{
uint8_t opcode = (instr >> 26) & 0x3F;
switch (opcode)
{
case 0x05:
return true;
default:
return false;
}
}
void Clock()
{
uint32_t instr = Bus::Read32(state.pc);
state.pc = state.next_pc;
state.next_pc += 4;
jit.EmitPrequel();
jit.EmitIR(instr);
bool isBranch = false;
bool isBranchDelayed = false;
do
{
uint32_t instr = Bus::Read32(state.pc);
state.pc = state.next_pc;
state.next_pc += 4;
jit.EmitIR(instr);
isBranch = isBranchDelayed;
isBranchDelayed = IsBranch(instr);
} while (!isBranch);
jit.EmitDone();
exit(1);
}
void Dump()
{
EE_JIT::emit->Dump();
}
ProcessorState* GetState()
{
return &state;
}
}

View file

@ -7,26 +7,95 @@
namespace EE_JIT
{
struct IRInstruction;
enum IRInstrs
{
MOV = 0,
NOP = 1,
SLTI = 2,
SaveHostRegs = 3,
RestoreHostRegs = 4,
BranchConditional = 5,
};
struct IRValue
{
public:
enum Type
{
Imm,
Reg,
Cop0Reg,
FP
};
private:
union
{
uint32_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;}
// Can be used for guest and COP0 registers
void SetReg(uint32_t reg) {value.register_num = reg;}
void SetImm(uint16_t imm) {value.imm = (int32_t)(int16_t)imm;}
uint32_t GetImm() {return value.imm;}
uint32_t GetReg() {return value.register_num;}
};
struct IRInstruction
{
uint8_t instr;
// Arguments are right -> left
std::vector<IRValue> args;
enum BranchType
{
NE = 0,
} b_type;
static IRInstruction Build(std::vector<IRValue> args, uint8_t i_type)
{
IRInstruction i;
i.instr = i_type;
i.args = args;
return i;
}
};
struct Block
{
uint32_t guest_start;
std::vector<IRInstruction> ir;
};
class JIT
{
private:
struct Block
{
uint32_t guest_start;
std::vector<IRInstruction> ir;
};
Block* cur_block;
std::vector<Block*> blockCache;
void EmitSLTI(uint32_t instr, EE_JIT::IRInstruction& i);
void EmitCOP0(uint32_t instr, EE_JIT::IRInstruction& i);
void EmitBNE(uint32_t instr, EE_JIT::IRInstruction& i); // 0x05
void EmitSLTI(uint32_t instr, EE_JIT::IRInstruction& i); // 0x0A
void EmitCOP0(uint32_t instr, EE_JIT::IRInstruction& i); // 0x10
void EmitMFC0(uint32_t instr, EE_JIT::IRInstruction& i);
public:
void EmitIR(uint32_t instr);
void EmitPrequel();
void EmitDone();
};
}
@ -37,10 +106,13 @@ namespace EmotionEngine
struct ProcessorState
{
uint128_t regs[32];
uint32_t cop0_regs[32];
uint32_t pc, next_pc;
};
void Reset();
void Clock();
void Dump();
ProcessorState* GetState();
}

View file

@ -0,0 +1,98 @@
#include "emit.h"
#include <sys/mman.h>
#include <emu/cpu/ee/EmotionEngine.h>
#include <fstream>
EE_JIT::Emitter* EE_JIT::emit;
void EE_JIT::Emitter::EmitMov(IRInstruction i)
{
if (i.args[1].IsImm()) // Lui
{
Xbyak::Reg64 reg_ptr = Xbyak::Reg64(reg_alloc->AllocHostRegister());
auto offset = ((offsetof(EmotionEngine::ProcessorState, regs)) + (i.args[1].GetReg() * sizeof(uint128_t) + offsetof(uint128_t, u32)));
cg->lea(reg_ptr, cg->ptr[cg->rax + offset]);
cg->mov(cg->dword[reg_ptr], i.args[0].GetImm());
}
else if (i.args[1].IsCop0()) // Mfc0
{
Xbyak::Reg64 ee_reg_ptr = Xbyak::Reg64(reg_alloc->AllocHostRegister());
Xbyak::Reg64 cop_reg_ptr = Xbyak::Reg64(reg_alloc->AllocHostRegister());
Xbyak::Reg64 ee_reg_value = Xbyak::Reg64(reg_alloc->AllocHostRegister());
auto dest_offset = ((offsetof(EmotionEngine::ProcessorState, regs)) + (i.args[0].GetReg() * sizeof(uint128_t) + offsetof(uint128_t, u32)));
auto src_offset = ((offsetof(EmotionEngine::ProcessorState, cop0_regs)) + (i.args[1].GetReg() * sizeof(uint32_t)));
cg->lea(cop_reg_ptr, cg->ptr[cg->rax + src_offset]);
cg->mov(ee_reg_value, cg->dword[cop_reg_ptr]);
cg->lea(ee_reg_ptr, cg->ptr[cg->rax + dest_offset]);
cg->mov(cg->dword[ee_reg_ptr], ee_reg_value);
}
else
{
printf("[emu/JIT]: Unknown MOV format\n");
exit(1);
}
}
void EE_JIT::Emitter::EmitSaveHostRegs()
{
for (int i = 0; i < 8; i++)
if (i != 4)
cg->push(Xbyak::Reg64(i));
cg->mov(cg->rbp, reinterpret_cast<uint64_t>(EmotionEngine::GetState()));
}
void EE_JIT::Emitter::EmitIR(IRInstruction i)
{
reg_alloc->Reset();
switch (i.instr)
{
case SaveHostRegs:
EmitSaveHostRegs();
break;
case MOV:
EmitMov(i);
break;
default:
printf("[JIT/Emit]: Unknown IR instruction 0x%02x\n", i.instr);
exit(1);
}
}
EE_JIT::Emitter::Emitter()
{
base = (uint8_t*)mmap(nullptr, 0xffffffff, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED)
{
printf("[JIT/Emit]: Failed to map base! %s\n", strerror(errno));
exit(1);
}
cg = new Xbyak::CodeGenerator(0xffffff, (void*)base);
reg_alloc = new RegisterAllocator();
reg_alloc->Reset();
}
void EE_JIT::Emitter::Dump()
{
std::ofstream dump("out.bin");
for (size_t i = 0; i < cg->getSize(); i++)
{
dump << cg->getCode()[i];
}
dump.flush();
dump.close();
munmap(base, 0xffffffff);
}
void EE_JIT::Emitter::TranslateBlock(Block *block)
{
for (auto& i : block->ir)
{
EmitIR(i);
}
}

31
src/emu/cpu/ee/x64/emit.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <emu/cpu/ee/x64/reg_alloc.h>
#include <3rdparty/xbyak/xbyak.h>
namespace EE_JIT
{
struct Block;
struct IRInstruction;
class Emitter
{
private:
Xbyak::CodeGenerator* cg;
uint8_t* base;
RegisterAllocator* reg_alloc;
void EmitSaveHostRegs();
void EmitMov(IRInstruction i);
void EmitIR(IRInstruction i);
public:
Emitter();
void Dump();
void TranslateBlock(Block* block);
};
extern Emitter* emit;
}

View file

@ -0,0 +1,31 @@
#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_registers.fill(false);
used_registers_8.fill(false);
used_registers[RBP] = true;
}
int RegisterAllocator::AllocHostRegister()
{
for (int i = 0; i < 8; i++)
{
if (!used_registers[i])
{
used_registers[i] = true;
return i;
}
}
printf("[JIT/RegAlloc]: Ran out of host registers!\n");
exit(1);
}

View file

@ -0,0 +1,29 @@
#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;
enum HostRegisters64
{
RAX,
RCX,
RDX,
RBX,
RSP,
RBP,
RSI,
RDI
};
public:
RegisterAllocator();
void Reset();
int AllocHostRegister();
};