Added all-asm JIT dispatcher, runs at ~140fps now

This commit is contained in:
Your Name 2023-01-16 06:26:59 -05:00
parent eece745982
commit a20304b733
11 changed files with 704 additions and 64 deletions

View file

@ -11,6 +11,7 @@ set(SOURCES src/main.cpp
src/emu/cpu/ee/EmotionEngine.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/sched/scheduler.cpp
@ -27,7 +28,7 @@ set(TARGET_NAME ps2)
if(MSVC)
target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX)
else()
target_compile_options(${TARGET_NAME} PRIVATE -pg)
target_compile_options(${TARGET_NAME} PRIVATE -pg -O0 -mincoming-stack-boundary=3)
target_link_options(${TARGET_NAME} PRIVATE -pg)
endif()

View file

@ -5,13 +5,39 @@
#include <emu/memory/Bus.h>
#include <emu/cpu/ee/EmotionEngine.h>
#include <emu/sched/scheduler.h>
#include <emu/cpu/ee/vu.h>
Scheduler::Event vsync_event;
#include <chrono>
#include <iostream>
std::chrono::steady_clock::time_point first_tp;
unsigned long frame_count = 0;
std::chrono::duration<double> uptime()
{
if (first_tp == std::chrono::steady_clock::time_point{})
return std::chrono::duration<double>{0};
return std::chrono::steady_clock::now() - first_tp;
}
double fps()
{
const double uptime_sec = uptime().count();
if (uptime_sec == 0)
return 0;
return frame_count / uptime_sec;
}
void HandleVsync()
{
printf("Vsync\n");
// printf("FPS: %f\n", fps());
Scheduler::ScheduleEvent(vsync_event);
frame_count++;
}
void System::LoadBios(std::string biosName)
@ -47,19 +73,18 @@ void System::Reset()
vsync_event.name = "VSYNC handler";
vsync_event.cycles_from_now = 4920115;
Scheduler::ScheduleEvent(vsync_event);
first_tp = std::chrono::steady_clock::now();
}
void System::Run()
{
while (1)
{
int cycles = EmotionEngine::Clock();
Scheduler::CheckScheduler(cycles);
}
EmotionEngine::Clock();
}
void System::Dump()
{
EmotionEngine::Dump();
Bus::Dump();
VectorUnit::Dump();
}

View file

@ -282,7 +282,7 @@ void JIT::EmitCOP0(uint32_t instr, EE_JIT::IRInstruction &i)
// printf("tlbwi\n");
break;
default:
printf("[emu/CPU]: Cannot emit unknown cop0 instruction 0x%02x\n", op);
// printf("[emu/CPU]: Cannot emit unknown cop0 instruction 0x%02x\n", op);
exit(1);
}
}
@ -353,6 +353,48 @@ void JIT::EmitDADDIU(uint32_t instr, EE_JIT::IRInstruction &i)
cur_block->ir.push_back(i);
}
void JIT::EmitLDL(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
int _base = (instr >> 21) & 0x1F;
int32_t _offset = (int16_t)(instr & 0xffff);
// printf("ldl %s, %d(%s)\n", EmotionEngine::Reg(_rt), _offset, EmotionEngine::Reg(_base));
IRValue base = IRValue(IRValue::Reg);
IRValue rt = IRValue(IRValue::Reg);
IRValue offset = IRValue(IRValue::Imm);
base.SetReg(_base);
rt.SetReg(_rt);
offset.SetImm(_offset);
i = IRInstruction::Build({rt, offset, base}, IRInstrs::LDL);
cur_block->ir.push_back(i);
}
void JIT::EmitLDR(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
int _base = (instr >> 21) & 0x1F;
int32_t _offset = (int16_t)(instr & 0xffff);
// printf("ldr %s, %d(%s)\n", EmotionEngine::Reg(_rt), _offset, EmotionEngine::Reg(_base));
IRValue base = IRValue(IRValue::Reg);
IRValue rt = IRValue(IRValue::Reg);
IRValue offset = IRValue(IRValue::Imm);
base.SetReg(_base);
rt.SetReg(_rt);
offset.SetImm(_offset);
i = IRInstruction::Build({rt, offset, base}, IRInstrs::LDR);
cur_block->ir.push_back(i);
}
void JIT::EmitLQ(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
@ -513,6 +555,29 @@ void JIT::EmitLHU(uint32_t instr, EE_JIT::IRInstruction &i)
cur_block->ir.push_back(i);
}
void JIT::EmitLWU(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
int _base = (instr >> 21) & 0x1F;
int32_t _offset = (int16_t)(instr & 0xffff);
// printf("lwu %s, %d(%s)\n", EmotionEngine::Reg(_rt), _offset, EmotionEngine::Reg(_base));
IRValue base = IRValue(IRValue::Reg);
IRValue rt = IRValue(IRValue::Reg);
IRValue offset = IRValue(IRValue::Imm);
base.SetReg(_base);
rt.SetReg(_rt);
offset.SetImm(_offset);
i = IRInstruction::Build({rt, offset, base}, IRInstrs::MemoryLoad);
i.access_size = IRInstruction::U32;
i.is_unsigned = true;
cur_block->ir.push_back(i);
}
void JIT::EmitSB(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
@ -575,10 +640,53 @@ void JIT::EmitSW(uint32_t instr, EE_JIT::IRInstruction &i)
i = IRInstruction::Build({rt, offset, base}, IRInstrs::MemoryStore);
i.access_size = IRInstruction::U32;
i.is_unsigned = false;
cur_block->ir.push_back(i);
}
void JIT::EmitSDL(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
int _base = (instr >> 21) & 0x1F;
int32_t _offset = (int16_t)(instr & 0xffff);
// printf("sdl %s, %d(%s)\n", EmotionEngine::Reg(_rt), _offset, EmotionEngine::Reg(_base));
IRValue base = IRValue(IRValue::Reg);
IRValue rt = IRValue(IRValue::Reg);
IRValue offset = IRValue(IRValue::Imm);
base.SetReg(_base);
rt.SetReg(_rt);
offset.SetImm(_offset);
i = IRInstruction::Build({rt, offset, base}, IRInstrs::SDL);
cur_block->ir.push_back(i);
}
void JIT::EmitSDR(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
int _base = (instr >> 21) & 0x1F;
int32_t _offset = (int16_t)(instr & 0xffff);
// printf("sdr %s, %d(%s)\n", EmotionEngine::Reg(_rt), _offset, EmotionEngine::Reg(_base));
IRValue base = IRValue(IRValue::Reg);
IRValue rt = IRValue(IRValue::Reg);
IRValue offset = IRValue(IRValue::Imm);
base.SetReg(_base);
rt.SetReg(_rt);
offset.SetImm(_offset);
i = IRInstruction::Build({rt, offset, base}, IRInstrs::SDR);
cur_block->ir.push_back(i);
}
void JIT::EmitLD(uint32_t instr, EE_JIT::IRInstruction &i)
{
int _rt = (instr >> 16) & 0x1F;
@ -1487,7 +1595,7 @@ void JIT::EmitIR(uint32_t instr)
EmitDSRA32(instr, current_instruction);
break;
default:
printf("[emu/CPU]: Cannot emit unknown special instruction 0x%02x\n", opcode);
// printf("[emu/CPU]: Cannot emit unknown special instruction 0x%02x\n", opcode);
cur_block->ir.clear();
delete cur_block;
exit(1);
@ -1506,7 +1614,7 @@ void JIT::EmitIR(uint32_t instr)
EmitBGEZ(instr, current_instruction);
break;
default:
printf("Unknown regimm opcode 0x%02x\n", opcode);
// printf("Unknown regimm opcode 0x%02x\n", opcode);
exit(1);
}
break;
@ -1553,6 +1661,17 @@ void JIT::EmitIR(uint32_t instr)
case 0x10:
EmitCOP0(instr, current_instruction);
break;
case 0x11:
{
opcode = (instr >> 21) & 0x1F;
switch (opcode)
{
default:
printf("[emu/EE]: Ignoring COP1 command 0x%08x\n", instr);
break;
}
break;
}
case 0x12:
{
opcode = (instr >> 21) & 0x1F;
@ -1600,6 +1719,12 @@ void JIT::EmitIR(uint32_t instr)
case 0x19:
EmitDADDIU(instr, current_instruction);
break;
case 0x1A:
EmitLDL(instr, current_instruction);
break;
case 0x1B:
EmitLDR(instr, current_instruction);
break;
case 0x1C:
{
opcode = instr & 0x3F;
@ -1658,6 +1783,9 @@ void JIT::EmitIR(uint32_t instr)
case 0x25:
EmitLHU(instr, current_instruction);
break;
case 0x27:
EmitLWU(instr, current_instruction);
break;
case 0x28:
EmitSB(instr, current_instruction);
break;
@ -1667,6 +1795,12 @@ void JIT::EmitIR(uint32_t instr)
case 0x2b:
EmitSW(instr, current_instruction);
break;
case 0x2c:
EmitSDL(instr, current_instruction);
break;
case 0x2d:
EmitSDR(instr, current_instruction);
break;
case 0x2f:
// printf("cache\n");
break;
@ -1692,22 +1826,18 @@ void JIT::EmitPrequel(uint32_t guest_start)
cur_block = new Block;
cur_block->guest_addr = guest_start;
cur_block->entry = (uint8_t*)emit->GetFreeBase();
auto i = IRInstruction::Build({}, IRInstrs::SaveHostRegs);
cur_block->ir.push_back(i);
}
JIT::EntryFunc JIT::EmitDone(size_t cycles_taken)
{
// printf("Done.\n");
IRValue cycles = IRValue(IRValue::Imm);
cycles.SetImm32Unsigned(cycles_taken);
auto i = IRInstruction::Build({cycles}, IRInstrs::UpdateCopCount);
cur_block->ir.push_back(i);
i = IRInstruction::Build({}, IRInstrs::RestoreHostRegs);
cur_block->ir.push_back(i);
blockCache[cur_block->guest_addr] = cur_block;
EE_JIT::emit->TranslateBlock(cur_block);
@ -1718,6 +1848,12 @@ JIT::EntryFunc JIT::EmitDone(size_t cycles_taken)
Block* JIT::GetExistingBlock(uint32_t start)
{
if (!blockCache[start])
{
// printf("ERROR: Block doesn't exist at 0x%08x\n", start);
exit(1);
}
return blockCache[start];
}
@ -1741,7 +1877,7 @@ void JIT::MarkDirty(uint32_t address, uint32_t size)
{
for (auto i = address; i < address+size; i++)
{
if (blockCache[i])
if (blockCache.find(size) != blockCache.end())
{
delete blockCache[i];
blockCache[i] = nullptr;
@ -1799,73 +1935,92 @@ bool IsBranch(uint32_t instr)
default:
return false;
}
return false;
}
EE_JIT::JIT::EntryFunc EmitDone(int cycles_taken)
{
return jit.EmitDone(cycles_taken);
}
EE_JIT::JIT::EntryFunc GetExistingBlockFunc(uint32_t addr)
{
return (EE_JIT::JIT::EntryFunc)jit.GetExistingBlock(addr)->entry;
}
uint64_t GetExistingBlockCycles(uint32_t addr)
{
return jit.GetExistingBlock(addr)->cycles;
}
#define BLOCKCACHE_ENABLE
int Clock()
{
jit.CheckCacheFull();
// jit.CheckCacheFull();
#ifdef BLOCKCACHE_ENABLE
if (!jit.DoesBlockExist(state.pc))
{
#endif
jit.EmitPrequel(state.pc);
// #ifdef BLOCKCACHE_ENABLE
// if (!jit.DoesBlockExist(state.pc))
// {
// #endif
// jit.EmitPrequel(state.pc);
bool isBranch = false;
bool isBranchDelayed = false;
// bool isBranch = false;
// bool isBranchDelayed = false;
uint32_t pc = state.pc;
uint32_t next_pc = state.next_pc;
// uint32_t pc = state.pc;
// uint32_t next_pc = state.next_pc;
int cycles = 0;
int instrs_emitted = 0;
// int cycles = 0;
// int instrs_emitted = 0;
do
{
instrs_emitted++;
uint32_t instr = Bus::Read32(pc);
pc = next_pc;
next_pc += 4;
// do
// {
// instrs_emitted++;
// uint32_t instr = Bus::Read32(pc);
// pc = next_pc;
// next_pc += 4;
state.pc_at = pc - 4;
// state.pc_at = pc - 4;
// printf("0x%08x (0x%08x): ", pc - 4, instr);
// // printf("0x%08x (0x%08x): ", pc - 4, instr);
jit.EmitIR(instr);
// jit.EmitIR(instr);
isBranch = isBranchDelayed;
isBranchDelayed = IsBranch(instr);
// isBranch = isBranchDelayed;
// isBranchDelayed = IsBranch(instr);
if (instrs_emitted == 20 && !isBranchDelayed)
break;
// if (instrs_emitted == 20 && !isBranchDelayed)
// break;
cycles += 2;
} while (!isBranch);
// cycles += 1;
// } while (!isBranch);
auto func = jit.EmitDone(cycles);
func();
// auto func = jit.EmitDone(cycles);
// func();
return cycles;
#ifdef BLOCKCACHE_ENABLE
}
else
{
auto b = jit.GetExistingBlock(state.pc);
// return cycles;
// #ifdef BLOCKCACHE_ENABLE
// }
// else
// {
// auto b = jit.GetExistingBlock(state.pc);
if (!b)
{
printf("Something has gone seriously wrong!\n");
exit(1);
}
// if (!b)
// {
// // printf("Something has gone seriously wrong!\n");
// exit(1);
// }
auto func = (EE_JIT::JIT::EntryFunc)b->entry;
func();
// auto func = (EE_JIT::JIT::EntryFunc)b->entry;
// func();
return b->cycles;
}
#endif
// return b->cycles;
// }
// #endif
EE_JIT::emit->EnterDispatcher();
}
void Dump()
@ -1890,4 +2045,21 @@ void MarkDirty(uint32_t address, uint32_t size)
jit.MarkDirty(address, size);
}
void EmitPrequel()
{
jit.EmitPrequel(state.pc);
}
void CheckCacheFull()
{
jit.CheckCacheFull();
}
bool DoesBlockExit(uint32_t addr)
{
return jit.DoesBlockExist(addr);
}
void EmitIR(uint32_t instr)
{
jit.EmitIR(instr);
}
}

View file

@ -42,6 +42,10 @@ enum IRInstrs
UpdateCopCount = 26,
POR = 27,
NOR = 28,
LDL = 29,
LDR = 30,
SDL = 31,
SDR = 32,
};
struct IRValue
@ -179,6 +183,8 @@ private:
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
@ -186,9 +192,12 @@ private:
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 EmitLD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x37
void EmitSWC1(uint32_t instr, EE_JIT::IRInstruction& i); // 0x39
void EmitSD(uint32_t instr, EE_JIT::IRInstruction& i); // 0x3f
@ -280,6 +289,15 @@ int Clock();
void Dump();
ProcessorState* GetState();
void MarkDirty(uint32_t address, uint32_t size);
void EmitPrequel();
void CheckCacheFull();
bool DoesBlockExit(uint32_t addr);
void EmitIR(uint32_t instr);
bool IsBranch(uint32_t instr);
EE_JIT::JIT::EntryFunc EmitDone(int cycles_taken);
EE_JIT::JIT::EntryFunc GetExistingBlockFunc(uint32_t addr);
uint64_t GetExistingBlockCycles(uint32_t addr);
inline const char* Reg(int index)
{

153
src/emu/cpu/ee/vif.cpp Normal file
View file

@ -0,0 +1,153 @@
#include "vif.h"
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <emu/sched/scheduler.h>
bool vif1_event_scheduled = false;
bool vif0_event_scheduled = false;
void VIF::WriteFBRST(int vif_num, uint32_t data)
{
if (data & 1)
{
printf("[emu/VIF%d]: Reset\n", vif_num);
}
}
void VIF::WriteMASK(int vif_num, uint32_t data)
{
}
std::queue<uint32_t> vif1_fifo, vif0_fifo;
struct VIF_DATA
{
uint16_t cycle;
uint16_t mask;
uint16_t mode;
uint16_t itop;
} vif1, vif0;
void HandleVIF1Data()
{
uint32_t data = vif1_fifo.front();
vif1_fifo.pop();
uint8_t cmd = (data >> 24) & 0xff;
uint16_t imm = data & 0xffff;
switch (cmd)
{
case 0x01:
printf("[emu/VIF1]: STCYCL 0x%04x\n", imm);
vif1.cycle = imm;
break;
default:
printf("[emu/VIF1]: Unknown CMD 0x%02x\n", cmd);
exit(1);
}
if (!vif1_fifo.empty())
{
Scheduler::Event event;
event.cycles_from_now = 2;
event.func = HandleVIF1Data;
event.name = "VIF1 Data Handler";
}
else
vif1_event_scheduled = false;
}
void VIF::WriteVIF1FIFO(uint128_t data)
{
for (int i = 0; i < 4; i++)
{
vif1_fifo.push(data.u32[i]);
}
if (!vif1_event_scheduled)
{
Scheduler::Event event;
// Most of these events should be handled ASAP
event.cycles_from_now = 0;
event.func = HandleVIF1Data;
event.name = "VIF1 Data Handler";
Scheduler::ScheduleEvent(event);
vif1_event_scheduled = true;
}
}
void HandleVIF0Data()
{
uint32_t data = vif0_fifo.front();
vif0_fifo.pop();
uint8_t cmd = (data >> 24) & 0xff;
uint16_t imm = data & 0xffff;
switch (cmd)
{
case 0x00:
printf("[emu/VIF0]: NOP\n");
break;
case 0x01:
printf("[emu/VIF0]: STCYCL 0x%04x\n", imm);
vif0.cycle = imm;
break;
case 0x04:
printf("[emu/VIF0]: ITOP 0x%04x\n", imm);
vif0.itop = imm;
break;
case 0x05:
printf("[emu/VIF0]: STMOD 0x%04x\n", imm);
vif0.mode = imm;
break;
case 0x20:
printf("[emu/VIF0]: STMASK 0x%04x\n", imm);
vif0.mask = imm;
break;
default:
printf("[emu/VIF0]: Unknown CMD 0x%02x\n", cmd);
exit(1);
}
if (!vif0_fifo.empty())
{
Scheduler::Event event;
event.cycles_from_now = 2;
event.func = HandleVIF0Data;
event.name = "VIF0 Data Handler";
Scheduler::ScheduleEvent(event);
vif0_event_scheduled = true;
}
else
{
vif0_event_scheduled = false;
}
}
void VIF::WriteVIF0FIFO(uint128_t data)
{
for (int i = 0; i < 4; i++)
{
printf("[emu/VIF0]: Adding 0x%08x to VIF0 FIFO\n", data.u32[i]);
vif0_fifo.push(data.u32[i]);
}
if (!vif0_event_scheduled)
{
Scheduler::Event event;
// Most of these events should be handled ASAP
event.cycles_from_now = 0;
event.func = HandleVIF0Data;
event.name = "VIF0 Data Handler";
Scheduler::ScheduleEvent(event);
vif0_event_scheduled = true;
}
}

15
src/emu/cpu/ee/vif.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <cstdint>
#include <util/uint128.h>
namespace VIF
{
void WriteFBRST(int vif_num, uint32_t data);
void WriteMASK(int vif_num, uint32_t data);
void WriteVIF1FIFO(uint128_t data);
void WriteVIF0FIFO(uint128_t data);
}

View file

@ -1,4 +1,5 @@
#include "vu.h"
#include <fstream>
namespace VectorUnit
{
@ -9,7 +10,7 @@ uint32_t code_address_mask[2] = {0xfff, 0x3fff};
uint8_t data[2][0x4000];
uint8_t code[2][0x4000];
void WriteDataMem128(int vector, uint32_t addr, uint128_t data)
void WriteDataMem128(int vector, uint32_t addr, uint128_t _data)
{
if (vector == 1)
addr = (addr - 0x1100C000);
@ -18,7 +19,47 @@ void WriteDataMem128(int vector, uint32_t addr, uint128_t data)
addr &= data_address_mask[vector];
*(uint128_t*)&data[vector][addr] = _data;
}
void WriteCodeMem128(int vector, uint32_t addr, uint128_t data)
{
if (vector == 1)
addr = (addr - 0x11008000);
else
addr = (addr - 0x11000000);
addr &= code_address_mask[vector];
*(uint128_t*)&code[vector][addr] = data;
}
void WriteCodeMem64(int vector, uint32_t addr, uint64_t data)
{
if (vector == 1)
addr = (addr - 0x11008000);
else
addr = (addr - 0x11000000);
addr &= code_address_mask[vector];
*(uint64_t*)&code[vector][addr] = data;
}
void Dump()
{
std::ofstream out_file("vu0_code.bin");
for (int i = 0; i < 0x4000; i++)
{
out_file << code[0][i];
}
out_file.close();
out_file.open("vu1_code.bin");
for (int i = 0; i < 0x4000; i++)
{
out_file << code[1][i];
}
}
}

View file

@ -8,4 +8,16 @@ namespace VectorUnit
void WriteDataMem128(int vector, uint32_t addr, uint128_t data);
void WriteCodeMem128(int vector, uint32_t addr, uint128_t data);
void WriteCodeMem64(int vector, uint32_t addr, uint64_t data);
void Dump();
namespace VU0
{
// VU0 specific stuff, like COP2 opcodes
}
}

View file

@ -5,6 +5,7 @@
#include <sys/mman.h>
#include <emu/cpu/ee/EmotionEngine.h>
#include <emu/memory/Bus.h>
#include <emu/sched/scheduler.h>
#include <fstream>
#include <cassert>
@ -202,7 +203,7 @@ void EE_JIT::Emitter::EmitBC(IRInstruction i)
// cg->add(cg->dword[next_pc], 4);
reg_alloc->Reset();
EmitIncPC(i);
EmitRestoreHostRegs();
cg->ret();
}
cg->L(end);
@ -1183,6 +1184,136 @@ EE_JIT::Emitter::Emitter()
cg = new Xbyak::CodeGenerator(0xffffff, (void*)base);
reg_alloc = new RegisterAllocator();
reg_alloc->Reset();
reg_alloc->MarkRegUsed(RegisterAllocator::RDI);
reg_alloc->MarkRegUsed(RegisterAllocator::RAX);
Xbyak::Reg64 func_ptr = Xbyak::Reg64(reg_alloc->AllocHostRegister());
Xbyak::Reg32 next_pc = Xbyak::Reg32(reg_alloc->AllocHostRegister());
Xbyak::Reg32 pc = Xbyak::Reg32(reg_alloc->AllocHostRegister());
Xbyak::Reg32 isBranchDelayed = Xbyak::Reg32(reg_alloc->AllocHostRegister());
cg->endbr64();
EmitSaveHostRegs();
// RSP + 0: pc
// RSP + 4: next_pc
// RSP + 8: isBranch
// RSP + 16: isBranchDelayed
// RSP + 20: instrs_emitted
// RSP + 24 .. RSP + 32: Wasted space for alignment reasons
cg->sub(cg->rsp, 32);
cg->mov(cg->dword[cg->rsp + 0], 0);
cg->mov(cg->dword[cg->rsp + 4], 0);
cg->mov(cg->dword[cg->rsp + 8], 0);
cg->mov(cg->dword[cg->rsp + 16], 0);
cg->mov(cg->dword[cg->rsp + 20], 0);
cg->mov(cg->dword[cg->rsp + 24], 0);
Xbyak::Label begin;
cg->L(begin);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::CheckCacheFull));
cg->call(func_ptr);
auto next_pc_off = (offsetof(EmotionEngine::ProcessorState, next_pc));
auto pc_off = (offsetof(EmotionEngine::ProcessorState, pc));
cg->mov(next_pc, cg->dword[cg->rbp + next_pc_off]);
cg->mov(pc, cg->dword[cg->rbp + pc_off]);
cg->mov(cg->dword[cg->rsp], pc);
cg->mov(cg->dword[cg->rsp + 4], next_pc);
cg->mov(cg->edi, cg->dword[cg->rsp]);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::DoesBlockExit));
cg->call(func_ptr);
cg->test(cg->al, cg->al);
Xbyak::Label block;
cg->jne(block, Xbyak::CodeGenerator::T_NEAR);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::EmitPrequel));
cg->call(func_ptr);
Xbyak::Label compile_instr;
cg->L(compile_instr);
cg->add(cg->dword[cg->rsp + 20], 1);
cg->mov(cg->edi, cg->dword[cg->rsp]);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(Bus::Read32));
cg->call(func_ptr);
cg->mov(next_pc, cg->dword[cg->rsp + 4]);
cg->mov(cg->dword[cg->rsp], next_pc);
cg->add(cg->dword[cg->rsp + 4], 4);
cg->mov(cg->rdi, cg->rax);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::EmitIR));
cg->call(func_ptr);
cg->mov(isBranchDelayed, cg->dword[cg->rsp + 16]);
cg->mov(cg->dword[cg->rsp + 8], isBranchDelayed);
cg->mov(cg->edi, cg->dword[cg->rsp]);
cg->sub(cg->edi, 4);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(Bus::Read32));
cg->call(func_ptr);
cg->mov(cg->edi, cg->eax);
cg->mov(cg->eax, 0);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::IsBranch));
cg->call(func_ptr);
cg->mov(cg->dword[cg->rsp + 16], cg->eax);
Xbyak::Label block_compiled;
cg->cmp(cg->dword[cg->rsp + 20], 20);
cg->je(block_compiled);
cg->mov(isBranchDelayed, cg->dword[cg->rsp + 8]);
cg->cmp(isBranchDelayed, 1);
cg->jge(block_compiled);
cg->jmp(compile_instr);
cg->L(block_compiled);
cg->mov(cg->edi, cg->dword[cg->rsp + 20]);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::EmitDone));
cg->call(func_ptr);
cg->call(cg->rax);
cg->mov(cg->rdi, cg->dword[cg->rsp + 20]);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(Scheduler::CheckScheduler));
cg->call(func_ptr);
cg->jmp(begin);
cg->L(block);
cg->mov(cg->rdi, cg->dword[cg->rsp]);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::GetExistingBlockFunc));
cg->call(func_ptr);
cg->call(cg->rax);
cg->mov(cg->rdi, cg->dword[cg->rsp]);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(EmotionEngine::GetExistingBlockCycles));
cg->call(func_ptr);
cg->mov(cg->rdi, cg->rax);
cg->mov(func_ptr, reinterpret_cast<uint64_t>(Scheduler::CheckScheduler));
cg->call(func_ptr);
cg->jmp(begin);
cg->add(cg->rsp, 32);
EmitRestoreHostRegs();
dispatcher_entry = (EE_JIT::JIT::EntryFunc)base;
base += cg->getSize();
Dump();
}
void EE_JIT::Emitter::Dump()
@ -1206,6 +1337,13 @@ void EE_JIT::Emitter::TranslateBlock(Block *block)
{
EmitIR(i);
}
cg->ret();
}
void EE_JIT::Emitter::EnterDispatcher()
{
dispatcher_entry();
}
const uint8_t *EE_JIT::Emitter::GetFreeBase()

View file

@ -6,6 +6,7 @@
#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
@ -51,11 +52,15 @@ private:
void EmitBranchRegImm(IRInstruction i);
void EmitUpdateCopCount(IRInstruction i);
void EmitPOR(IRInstruction i);
EE_JIT::JIT::EntryFunc dispatcher_entry;
public:
Emitter();
void Dump();
void TranslateBlock(Block* block);
void EnterDispatcher();
void ResetFreeBase()
{
free_base = base;

View file

@ -11,6 +11,7 @@
#include <emu/gpu/gs.h>
#include <emu/cpu/ee/dmac.hpp>
#include <emu/cpu/ee/vu.h>
#include <emu/cpu/ee/vif.h>
uint8_t BiosRom[0x400000];
uint8_t spr[0x4000];
@ -157,6 +158,8 @@ uint32_t Bus::Read32(uint32_t addr)
return DMAC::ReadDSTAT();
case 0x1000E020:
return DMAC::ReadDPCR();
case 0x10002010:
return 0;
}
printf("Read32 from unknown address 0x%08x\n", addr);
@ -171,6 +174,14 @@ uint16_t Bus::Read16(uint32_t addr)
return *(uint16_t*)&BiosRom[addr - 0x1fc00000];
if (addr >= 0x70000000 && addr < 0x70004000)
return *(uint16_t*)&spr[addr - 0x70000000];
if (addr < 0x2000000)
return *(uint16_t*)&ram[addr];
switch (addr)
{
case 0x1f803800:
return 0;
}
printf("Read16 from unknown address 0x%08x\n", addr);
exit(1);
@ -209,7 +220,22 @@ void Bus::Write128(uint32_t addr, uint128_t data)
*(__uint128_t*)&ram[addr] = data.u128;
return;
}
if (addr >= 0x70000000 && addr < 0x70004000)
{
*(__uint128_t*)&spr[addr - 0x70000000] = data.u128;
return;
}
if (addr >= 0x11000000 && addr < 0x11004000)
{
VectorUnit::WriteDataMem128(0, addr, data);
return;
}
if (addr >= 0x11004000 && addr < 0x11008000)
{
VectorUnit::WriteDataMem128(0, addr, data);
return;
}
if (addr >= 0x1100C000 && addr < 0x11010000)
{
VectorUnit::WriteDataMem128(1, addr, data);
@ -218,9 +244,17 @@ void Bus::Write128(uint32_t addr, uint128_t data)
switch (addr)
{
case 0x10004000:
VIF::WriteVIF0FIFO(data);
return;
case 0x10005000:
VIF::WriteVIF1FIFO(data);
return;
case 0x10006000:
GIF::WriteFIFO(data);
return;
case 0x10007010:
return;
}
printf("Write128 0x%lx%016lx to unknown address 0x%08x\n", data.u64[1], data.u64[0], addr);
@ -243,6 +277,11 @@ void Bus::Write64(uint32_t addr, uint64_t data)
*(uint64_t*)&ram[addr] = data;
return;
}
if (addr >= 0x11008000 && addr < 0x1100C000)
{
VectorUnit::WriteCodeMem64(1, addr, data);
return;
}
switch (addr)
{
@ -348,6 +387,7 @@ void Bus::Write32(uint32_t addr, uint32_t data)
case 0x10001810:
case 0x10001820:
case 0x10001830:
case 0x1000f510:
return;
case 0x10008000:
case 0x10008010:
@ -427,6 +467,21 @@ void Bus::Write32(uint32_t addr, uint32_t data)
case 0x1000E040:
case 0x1000E050:
return;
case 0x10003810:
VIF::WriteFBRST(0, data);
return;
case 0x10003820:
case 0x10003830:
VIF::WriteMASK(0, data);
return;
case 0x10003c00:
return;
case 0x10003c10:
VIF::WriteFBRST(1, data);
return;
case 0x10002000:
case 0x10002010:
return;
}
printf("Write32 0x%08x to unknown address 0x%08x\n", data, addr);
@ -444,6 +499,11 @@ void Bus::Write16(uint32_t addr, uint16_t data)
*(uint16_t*)&spr[addr - 0x70000000] = data;
return;
}
if (addr < 0x2000000)
{
*(uint16_t*)&ram[addr] = data;
return;
}
if (((addr & 0xFF000000) == 0x1A000000) || ((addr & 0xFFF00000) == 0x1F800000))
return;