Merge remote-tracking branch 'origin/master' into fh/x64-arm-jit
This commit is contained in:
commit
1b47ef0ab1
|
@ -28,7 +28,7 @@
|
||||||
#include "deps/vixl/aarch64/macro-assembler-aarch64.h"
|
#include "deps/vixl/aarch64/macro-assembler-aarch64.h"
|
||||||
using namespace vixl::aarch64;
|
using namespace vixl::aarch64;
|
||||||
|
|
||||||
static u8 *WritableCodeBuffer;
|
static u8 *pCodeBuffer;
|
||||||
|
|
||||||
class DSPAssembler : public MacroAssembler
|
class DSPAssembler : public MacroAssembler
|
||||||
{
|
{
|
||||||
|
@ -447,18 +447,18 @@ void dsp_recompile()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DSPAssembler assembler(WritableCodeBuffer, sizeof(dsp.DynCode));
|
DSPAssembler assembler(pCodeBuffer, sizeof(dsp.DynCode));
|
||||||
assembler.Compile(&dsp);
|
assembler.Compile(&dsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_rec_init()
|
void dsp_rec_init()
|
||||||
{
|
{
|
||||||
if (!vmem_platform_prepare_jit_block(dsp.DynCode, sizeof(dsp.DynCode), (void**)&WritableCodeBuffer))
|
if (!vmem_platform_prepare_jit_block(dsp.DynCode, sizeof(dsp.DynCode), (void**)&pCodeBuffer))
|
||||||
die("mprotect failed in arm64 dsp");
|
die("mprotect failed in arm64 dsp");
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_rec_step()
|
void dsp_rec_step()
|
||||||
{
|
{
|
||||||
((void (*)())dsp.DynCode)();
|
((void (*)())pCodeBuffer)();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,7 +41,7 @@ alignas(4096) static u8 CodeBuffer[32 * 1024]
|
||||||
#else
|
#else
|
||||||
#error CodeBuffer code section unknown
|
#error CodeBuffer code section unknown
|
||||||
#endif
|
#endif
|
||||||
static u8 *WritableCodeBuffer;
|
static u8 *pCodeBuffer;
|
||||||
|
|
||||||
class X64DSPAssembler : public Xbyak::CodeGenerator
|
class X64DSPAssembler : public Xbyak::CodeGenerator
|
||||||
{
|
{
|
||||||
|
@ -420,18 +420,18 @@ void dsp_recompile()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
X64DSPAssembler assembler(WritableCodeBuffer, sizeof(CodeBuffer));
|
X64DSPAssembler assembler(pCodeBuffer, sizeof(CodeBuffer));
|
||||||
assembler.Compile(&dsp);
|
assembler.Compile(&dsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_rec_init()
|
void dsp_rec_init()
|
||||||
{
|
{
|
||||||
if (!vmem_platform_prepare_jit_block(CodeBuffer, sizeof(CodeBuffer), (void**)&WritableCodeBuffer))
|
if (!vmem_platform_prepare_jit_block(CodeBuffer, sizeof(CodeBuffer), (void**)&pCodeBuffer))
|
||||||
die("mprotect failed in x64 dsp");
|
die("mprotect failed in x64 dsp");
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_rec_step()
|
void dsp_rec_step()
|
||||||
{
|
{
|
||||||
((void (*)())&CodeBuffer[0])();
|
((void (*)())&pCodeBuffer[0])();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,7 +42,7 @@ alignas(4096) static u8 CodeBuffer[32 * 1024]
|
||||||
#else
|
#else
|
||||||
#error CodeBuffer code section unknown
|
#error CodeBuffer code section unknown
|
||||||
#endif
|
#endif
|
||||||
static u8 *WritableCodeBuffer;
|
static u8 *pCodeBuffer;
|
||||||
|
|
||||||
class X86DSPAssembler : public Xbyak::CodeGenerator
|
class X86DSPAssembler : public Xbyak::CodeGenerator
|
||||||
{
|
{
|
||||||
|
@ -386,18 +386,18 @@ void dsp_recompile()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
X86DSPAssembler assembler(WritableCodeBuffer, sizeof(CodeBuffer));
|
X86DSPAssembler assembler(pCodeBuffer, sizeof(CodeBuffer));
|
||||||
assembler.Compile(&dsp);
|
assembler.Compile(&dsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_rec_init()
|
void dsp_rec_init()
|
||||||
{
|
{
|
||||||
if (!vmem_platform_prepare_jit_block(CodeBuffer, sizeof(CodeBuffer), (void**)&WritableCodeBuffer))
|
if (!vmem_platform_prepare_jit_block(CodeBuffer, sizeof(CodeBuffer), (void**)&pCodeBuffer))
|
||||||
die("mprotect failed in x86 dsp");
|
die("mprotect failed in x86 dsp");
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_rec_step()
|
void dsp_rec_step()
|
||||||
{
|
{
|
||||||
((void (*)())&CodeBuffer[0])();
|
((void (*)())&pCodeBuffer[0])();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -501,7 +501,10 @@ void dc_init()
|
||||||
set_platform(DC_PLATFORM_DREAMCAST);
|
set_platform(DC_PLATFORM_DREAMCAST);
|
||||||
|
|
||||||
plugins_Init();
|
plugins_Init();
|
||||||
|
mem_Init();
|
||||||
|
reios_init();
|
||||||
|
|
||||||
|
// the recompiler may start generating code at this point and needs a fully configured machine
|
||||||
#if FEAT_SHREC != DYNAREC_NONE
|
#if FEAT_SHREC != DYNAREC_NONE
|
||||||
Get_Sh4Recompiler(&sh4_cpu);
|
Get_Sh4Recompiler(&sh4_cpu);
|
||||||
sh4_cpu.Init(); // Also initialize the interpreter
|
sh4_cpu.Init(); // Also initialize the interpreter
|
||||||
|
@ -517,9 +520,6 @@ void dc_init()
|
||||||
INFO_LOG(INTERPRETER, "Using Interpreter");
|
INFO_LOG(INTERPRETER, "Using Interpreter");
|
||||||
}
|
}
|
||||||
|
|
||||||
mem_Init();
|
|
||||||
reios_init();
|
|
||||||
|
|
||||||
init_done = true;
|
init_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,28 +219,9 @@ u32 X86Compiler::relinkBlock(RuntimeBlockInfo* block)
|
||||||
case BET_DynamicRet:
|
case BET_DynamicRet:
|
||||||
case BET_DynamicCall:
|
case BET_DynamicCall:
|
||||||
case BET_DynamicJump:
|
case BET_DynamicJump:
|
||||||
if (block->relink_data == 0)
|
mov(ecx, dword[GetRegPtr(reg_pc_dyn)]);
|
||||||
{
|
jmp((const void *)no_update);
|
||||||
if (block->pBranchBlock)
|
|
||||||
{
|
|
||||||
cmp(dword[GetRegPtr(reg_pc_dyn)], block->pBranchBlock->addr);
|
|
||||||
je((const void *)block->pBranchBlock->code);
|
|
||||||
call(ngen_LinkBlock_Generic_stub);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// dummy cmp/je to keep same code size in both cases
|
|
||||||
cmp(dword[GetRegPtr(reg_pc_dyn)], 0xFABCDECF);
|
|
||||||
call(ngen_LinkBlock_Generic_stub);
|
|
||||||
je((const void *)ngen_LinkBlock_Generic_stub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
verify(block->pBranchBlock == nullptr);
|
|
||||||
mov(ecx, dword[GetRegPtr(reg_pc_dyn)]);
|
|
||||||
jmp((const void *)no_update);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BET_StaticCall:
|
case BET_StaticCall:
|
||||||
|
@ -398,9 +379,10 @@ void X86Compiler::genMainloop()
|
||||||
//no_update:
|
//no_update:
|
||||||
Xbyak::Label no_updateLabel;
|
Xbyak::Label no_updateLabel;
|
||||||
L(no_updateLabel);
|
L(no_updateLabel);
|
||||||
mov(esi, ecx); // save sh4 pc in ESI, used below if the jump table is still empty for this address
|
mov(esi, ecx); // save sh4 pc in ESI, used below if FPCB is still empty for this address
|
||||||
call((void *)bm_GetCodeByVAddr);
|
mov(eax, (size_t)&p_sh4rcb->fpcb[0]);
|
||||||
jmp(eax);
|
and_(ecx, RAM_SIZE_MAX - 2);
|
||||||
|
jmp(dword[eax + ecx * 2]);
|
||||||
|
|
||||||
//intc_sched:
|
//intc_sched:
|
||||||
Xbyak::Label intc_schedLabel;
|
Xbyak::Label intc_schedLabel;
|
||||||
|
@ -473,6 +455,8 @@ void X86Compiler::genMainloop()
|
||||||
call((void *)rdv_BlockCheckFail);
|
call((void *)rdv_BlockCheckFail);
|
||||||
jmp(eax);
|
jmp(eax);
|
||||||
|
|
||||||
|
genMemHandlers();
|
||||||
|
|
||||||
ready();
|
ready();
|
||||||
|
|
||||||
mainloop = (void (*)())getCode();
|
mainloop = (void (*)())getCode();
|
||||||
|
@ -599,34 +583,6 @@ bool X86Compiler::genReadMemImmediate(const shil_opcode& op, RuntimeBlockInfo* b
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool X86Compiler::genReadMemoryFast(const shil_opcode& op, RuntimeBlockInfo* block)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void X86Compiler::genReadMemorySlow(const shil_opcode& op, RuntimeBlockInfo* block)
|
|
||||||
{
|
|
||||||
u32 size = op.flags & 0x7f;
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
genCall(ReadMem8);
|
|
||||||
movsx(eax, al);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
genCall(ReadMem16);
|
|
||||||
movsx(eax, ax);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
genCall(ReadMem32);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
genCall(ReadMem64);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
die("1..8 bytes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool X86Compiler::genWriteMemImmediate(const shil_opcode& op, RuntimeBlockInfo* block)
|
bool X86Compiler::genWriteMemImmediate(const shil_opcode& op, RuntimeBlockInfo* block)
|
||||||
{
|
{
|
||||||
|
@ -721,32 +677,6 @@ bool X86Compiler::genWriteMemImmediate(const shil_opcode& op, RuntimeBlockInfo*
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X86Compiler::genWriteMemoryFast(const shil_opcode& op, RuntimeBlockInfo* block)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void X86Compiler::genWriteMemorySlow(const shil_opcode& op, RuntimeBlockInfo* block)
|
|
||||||
{
|
|
||||||
u32 size = op.flags & 0x7f;
|
|
||||||
switch (size) {
|
|
||||||
case 1:
|
|
||||||
genCall(WriteMem8);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
genCall(WriteMem16);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
genCall(WriteMem32);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
genCall(WriteMem64);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
die("1..8 bytes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void X86Compiler::checkBlock(bool smc_checks, RuntimeBlockInfo* block)
|
void X86Compiler::checkBlock(bool smc_checks, RuntimeBlockInfo* block)
|
||||||
{
|
{
|
||||||
if (!smc_checks)
|
if (!smc_checks)
|
||||||
|
@ -783,7 +713,11 @@ void ngen_ResetBlocks()
|
||||||
|
|
||||||
compiler = new X86Compiler();
|
compiler = new X86Compiler();
|
||||||
|
|
||||||
compiler->genMainloop();
|
try {
|
||||||
|
compiler->genMainloop();
|
||||||
|
} catch (const Xbyak::Error& e) {
|
||||||
|
ERROR_LOG(DYNAREC, "Fatal xbyak error: %s", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
delete compiler;
|
delete compiler;
|
||||||
compiler = nullptr;
|
compiler = nullptr;
|
||||||
|
@ -818,10 +752,13 @@ void ngen_Compile(RuntimeBlockInfo* block, bool smc_checks, bool, bool, bool opt
|
||||||
delete compiler;
|
delete compiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ngen_Rewrite(unat& host_pc, unat, unat)
|
bool ngen_Rewrite(size_t& host_pc, size_t addr, size_t acc)
|
||||||
{
|
{
|
||||||
// TODO
|
X86Compiler *compiler = new X86Compiler((u8*)(addr - 5));
|
||||||
return false;
|
bool rv = compiler->rewriteMemAccess(host_pc, addr, acc);
|
||||||
|
delete compiler;
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ngen_CC_Start(shil_opcode* op)
|
void ngen_CC_Start(shil_opcode* op)
|
||||||
|
|
|
@ -75,17 +75,22 @@ public:
|
||||||
|
|
||||||
void genMainloop();
|
void genMainloop();
|
||||||
u32 relinkBlock(RuntimeBlockInfo *block);
|
u32 relinkBlock(RuntimeBlockInfo *block);
|
||||||
|
bool rewriteMemAccess(size_t& host_pc, size_t retadr, size_t acc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void genOpcode(RuntimeBlockInfo *block, bool optimise, shil_opcode& op);
|
void genOpcode(RuntimeBlockInfo *block, bool optimise, shil_opcode& op);
|
||||||
|
|
||||||
bool genReadMemImmediate(const shil_opcode& op, RuntimeBlockInfo *block);
|
bool genReadMemImmediate(const shil_opcode& op, RuntimeBlockInfo *block);
|
||||||
bool genReadMemoryFast(const shil_opcode& op, RuntimeBlockInfo *block);
|
|
||||||
void genReadMemorySlow(const shil_opcode& op, RuntimeBlockInfo *block);
|
|
||||||
|
|
||||||
bool genWriteMemImmediate(const shil_opcode& op, RuntimeBlockInfo *block);
|
bool genWriteMemImmediate(const shil_opcode& op, RuntimeBlockInfo *block);
|
||||||
bool genWriteMemoryFast(const shil_opcode& op, RuntimeBlockInfo *block);
|
void genMemHandlers();
|
||||||
void genWriteMemorySlow(const shil_opcode& op, RuntimeBlockInfo *block);
|
void alignStack(int amount) {
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (amount > 0)
|
||||||
|
add(esp, amount);
|
||||||
|
else
|
||||||
|
sub(esp, -amount);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void checkBlock(bool smc_checks, RuntimeBlockInfo *block);
|
void checkBlock(bool smc_checks, RuntimeBlockInfo *block);
|
||||||
void freezeXMM();
|
void freezeXMM();
|
||||||
|
|
|
@ -25,16 +25,191 @@
|
||||||
#include "rec_x86.h"
|
#include "rec_x86.h"
|
||||||
#include "hw/sh4/sh4_opcode_list.h"
|
#include "hw/sh4/sh4_opcode_list.h"
|
||||||
#include "hw/sh4/sh4_core.h"
|
#include "hw/sh4/sh4_core.h"
|
||||||
|
#include "hw/mem/_vmem.h"
|
||||||
|
|
||||||
|
namespace MemOp {
|
||||||
|
enum Size {
|
||||||
|
S8,
|
||||||
|
S16,
|
||||||
|
S32,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
SizeCount
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Op {
|
||||||
|
R,
|
||||||
|
W,
|
||||||
|
OpCount
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
Fast,
|
||||||
|
Slow,
|
||||||
|
TypeCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static const void *MemHandlers[MemOp::TypeCount][MemOp::SizeCount][MemOp::OpCount];
|
||||||
|
static const u8 *MemHandlerStart, *MemHandlerEnd;
|
||||||
|
|
||||||
|
void X86Compiler::genMemHandlers()
|
||||||
|
{
|
||||||
|
// make sure the memory handlers are set
|
||||||
|
verify(ReadMem8 != nullptr);
|
||||||
|
|
||||||
|
MemHandlerStart = getCurr();
|
||||||
|
for (int type = 0; type < MemOp::TypeCount; type++)
|
||||||
|
{
|
||||||
|
for (int size = 0; size < MemOp::SizeCount; size++)
|
||||||
|
{
|
||||||
|
for (int op = 0; op < MemOp::OpCount; op++)
|
||||||
|
{
|
||||||
|
MemHandlers[type][size][op] = getCurr();
|
||||||
|
|
||||||
|
if (type == MemOp::Fast && _nvmem_enabled())
|
||||||
|
{
|
||||||
|
mov(eax, ecx);
|
||||||
|
and_(ecx, 0x1FFFFFFF);
|
||||||
|
Xbyak::Address address = dword[ecx];
|
||||||
|
Xbyak::Reg reg;
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case MemOp::S8:
|
||||||
|
address = byte[ecx + (size_t)virt_ram_base];
|
||||||
|
reg = op == MemOp::R ? (Xbyak::Reg)eax : (Xbyak::Reg)dl;
|
||||||
|
break;
|
||||||
|
case MemOp::S16:
|
||||||
|
address = word[ecx + (size_t)virt_ram_base];
|
||||||
|
reg = op == MemOp::R ? (Xbyak::Reg)eax : (Xbyak::Reg)dx;
|
||||||
|
break;
|
||||||
|
case MemOp::S32:
|
||||||
|
address = dword[ecx + (size_t)virt_ram_base];
|
||||||
|
reg = op == MemOp::R ? eax : edx;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
address = dword[ecx + (size_t)virt_ram_base];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (size >= MemOp::F32)
|
||||||
|
{
|
||||||
|
if (op == MemOp::R)
|
||||||
|
movss(xmm0, address);
|
||||||
|
else
|
||||||
|
movss(address, xmm0);
|
||||||
|
if (size == MemOp::F64)
|
||||||
|
{
|
||||||
|
address = dword[ecx + (size_t)virt_ram_base + 4];
|
||||||
|
if (op == MemOp::R)
|
||||||
|
movss(xmm1, address);
|
||||||
|
else
|
||||||
|
movss(address, xmm1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (op == MemOp::R)
|
||||||
|
{
|
||||||
|
if (size <= MemOp::S16)
|
||||||
|
movsx(reg, address);
|
||||||
|
else
|
||||||
|
mov(reg, address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mov(address, reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Slow path
|
||||||
|
if (op == MemOp::R)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case MemOp::S8:
|
||||||
|
// 16-byte alignment
|
||||||
|
alignStack(-12);
|
||||||
|
call((const void *)ReadMem8);
|
||||||
|
movsx(eax, al);
|
||||||
|
alignStack(12);
|
||||||
|
break;
|
||||||
|
case MemOp::S16:
|
||||||
|
// 16-byte alignment
|
||||||
|
alignStack(-12);
|
||||||
|
call((const void *)ReadMem16);
|
||||||
|
movsx(eax, ax);
|
||||||
|
alignStack(12);
|
||||||
|
break;
|
||||||
|
case MemOp::S32:
|
||||||
|
jmp((const void *)ReadMem32); // tail call
|
||||||
|
continue;
|
||||||
|
case MemOp::F32:
|
||||||
|
// 16-byte alignment
|
||||||
|
alignStack(-12);
|
||||||
|
call((const void *)ReadMem32);
|
||||||
|
movd(xmm0, eax);
|
||||||
|
alignStack(12);
|
||||||
|
break;
|
||||||
|
case MemOp::F64:
|
||||||
|
// 16-byte alignment
|
||||||
|
alignStack(-12);
|
||||||
|
call((const void *)ReadMem64);
|
||||||
|
movd(xmm0, eax);
|
||||||
|
movd(xmm1, edx);
|
||||||
|
alignStack(12);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
die("1..8 bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case MemOp::S8:
|
||||||
|
jmp((const void *)WriteMem8); // tail call
|
||||||
|
continue;
|
||||||
|
case MemOp::S16:
|
||||||
|
jmp((const void *)WriteMem16); // tail call
|
||||||
|
continue;
|
||||||
|
case MemOp::S32:
|
||||||
|
jmp((const void *)WriteMem32); // tail call
|
||||||
|
continue;
|
||||||
|
case MemOp::F32:
|
||||||
|
movd(edx, xmm0);
|
||||||
|
jmp((const void *)WriteMem32); // tail call
|
||||||
|
continue;
|
||||||
|
case MemOp::F64:
|
||||||
|
#ifndef _WIN32
|
||||||
|
// 16-byte alignment
|
||||||
|
alignStack(-12);
|
||||||
|
#else
|
||||||
|
sub(esp, 8);
|
||||||
|
#endif
|
||||||
|
movss(dword[esp], xmm0);
|
||||||
|
movss(dword[esp + 4], xmm1);
|
||||||
|
call((const void *)WriteMem64); // dynacall adds 8 to esp
|
||||||
|
alignStack(4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
die("1..8 bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MemHandlerEnd = getCurr();
|
||||||
|
}
|
||||||
|
|
||||||
void X86Compiler::genOpcode(RuntimeBlockInfo* block, bool optimise, shil_opcode& op)
|
void X86Compiler::genOpcode(RuntimeBlockInfo* block, bool optimise, shil_opcode& op)
|
||||||
{
|
{
|
||||||
switch (op.op)
|
switch (op.op)
|
||||||
{
|
{
|
||||||
case shop_ifb:
|
case shop_ifb:
|
||||||
if (op.rs1._imm)
|
if (op.rs1.is_imm() && op.rs1.imm_value())
|
||||||
mov(dword[&next_pc], op.rs2._imm);
|
mov(dword[&next_pc], op.rs2.imm_value());
|
||||||
mov(ecx, op.rs3._imm);
|
mov(ecx, op.rs3.imm_value());
|
||||||
genCall(OpDesc[op.rs3._imm]->oph);
|
genCall(OpDesc[op.rs3.imm_value()]->oph);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -66,25 +241,52 @@ void X86Compiler::genOpcode(RuntimeBlockInfo* block, bool optimise, shil_opcode&
|
||||||
else
|
else
|
||||||
add(ecx, dword[op.rs3.reg_ptr()]);
|
add(ecx, dword[op.rs3.reg_ptr()]);
|
||||||
}
|
}
|
||||||
if (!optimise || !genReadMemoryFast(op, block))
|
|
||||||
genReadMemorySlow(op, block);
|
|
||||||
|
|
||||||
u32 size = op.flags & 0x7f;
|
int memOpSize;
|
||||||
if (size != 8)
|
switch (op.flags & 0x7f)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
memOpSize = MemOp::S8;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
memOpSize = MemOp::S16;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
memOpSize = regalloc.IsAllocf(op.rd) ? MemOp::F32 : MemOp::S32;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
memOpSize = MemOp::F64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
freezeXMM();
|
||||||
|
const u8 *start = getCurr();
|
||||||
|
call(MemHandlers[optimise ? MemOp::Fast : MemOp::Slow][memOpSize][MemOp::R]);
|
||||||
|
verify(getCurr() - start == 5);
|
||||||
|
thawXMM();
|
||||||
|
|
||||||
|
if (memOpSize <= MemOp::S32)
|
||||||
|
{
|
||||||
host_reg_to_shil_param(op.rd, eax);
|
host_reg_to_shil_param(op.rd, eax);
|
||||||
else {
|
}
|
||||||
|
else if (memOpSize == MemOp::F32)
|
||||||
|
{
|
||||||
|
host_reg_to_shil_param(op.rd, xmm0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#ifdef EXPLODE_SPANS
|
#ifdef EXPLODE_SPANS
|
||||||
if (op.rd.count() == 2 && regalloc.IsAllocf(op.rd, 0) && regalloc.IsAllocf(op.rd, 1))
|
if (op.rd.count() == 2 && regalloc.IsAllocf(op.rd, 0) && regalloc.IsAllocf(op.rd, 1))
|
||||||
{
|
{
|
||||||
movd(regalloc.MapXRegister(op.rd, 0), eax);
|
mov(regalloc.MapXRegister(op.rd, 0), xmm0);
|
||||||
movd(regalloc.MapXRegister(op.rd, 1), edx);
|
mov(regalloc.MapXRegister(op.rd, 1), xmm1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
verify(!regalloc.IsAllocAny(op.rd));
|
verify(!regalloc.IsAllocAny(op.rd));
|
||||||
mov(dword[op.rd.reg_ptr()], eax);
|
movss(dword[op.rd.reg_ptr()], xmm0);
|
||||||
mov(dword[op.rd.reg_ptr() + 1], edx);
|
movss(dword[op.rd.reg_ptr() + 1], xmm1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,29 +306,46 @@ void X86Compiler::genOpcode(RuntimeBlockInfo* block, bool optimise, shil_opcode&
|
||||||
add(ecx, dword[op.rs3.reg_ptr()]);
|
add(ecx, dword[op.rs3.reg_ptr()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 size = op.flags & 0x7f;
|
int memOpSize;
|
||||||
if (size != 8)
|
switch (op.flags & 0x7f)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
memOpSize = MemOp::S8;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
memOpSize = MemOp::S16;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
memOpSize = regalloc.IsAllocf(op.rs2) ? MemOp::F32 : MemOp::S32;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
memOpSize = MemOp::F64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memOpSize <= MemOp::S32)
|
||||||
shil_param_to_host_reg(op.rs2, edx);
|
shil_param_to_host_reg(op.rs2, edx);
|
||||||
|
else if (memOpSize == MemOp::F32)
|
||||||
|
shil_param_to_host_reg(op.rs2, xmm0);
|
||||||
else {
|
else {
|
||||||
#ifdef EXPLODE_SPANS
|
#ifdef EXPLODE_SPANS
|
||||||
if (op.rs2.count() == 2 && regalloc.IsAllocf(op.rs2, 0) && regalloc.IsAllocf(op.rs2, 1))
|
if (op.rs2.count() == 2 && regalloc.IsAllocf(op.rs2, 0) && regalloc.IsAllocf(op.rs2, 1))
|
||||||
{
|
{
|
||||||
sub(esp, 8);
|
mov(xmm0, regalloc.MapXRegister(op.rs2, 0));
|
||||||
movsd(dword[esp + 4], regalloc.MapXRegister(op.rs2, 1));
|
mov(xmm1, regalloc.MapXRegister(op.rs2, 1));
|
||||||
movsd(dword[esp], regalloc.MapXRegister(op.rs2, 0));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
sub(esp, 8);
|
movd(xmm0, dword[op.rs2.reg_ptr()]);
|
||||||
mov(eax, dword[op.rs2.reg_ptr() + 1]);
|
movd(xmm1, dword[op.rs2.reg_ptr() + 1]);
|
||||||
mov(dword[esp + 4], eax);
|
|
||||||
mov(eax, dword[op.rs2.reg_ptr()]);
|
|
||||||
mov(dword[esp], eax);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!optimise || !genWriteMemoryFast(op, block))
|
freezeXMM();
|
||||||
genWriteMemorySlow(op, block);
|
const u8 *start = getCurr();
|
||||||
|
call(MemHandlers[optimise ? MemOp::Fast : MemOp::Slow][memOpSize][MemOp::W]);
|
||||||
|
verify(getCurr() - start == 5);
|
||||||
|
thawXMM();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -203,4 +422,36 @@ void X86Compiler::genOpcode(RuntimeBlockInfo* block, bool optimise, shil_opcode&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool X86Compiler::rewriteMemAccess(size_t& host_pc, size_t retadr, size_t acc)
|
||||||
|
{
|
||||||
|
//DEBUG_LOG(DYNAREC, "rewriteMemAccess hpc %08x retadr %08x", host_pc, retadr);
|
||||||
|
if (host_pc < (size_t)MemHandlerStart || host_pc >= (size_t)MemHandlerEnd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u32 ca = *(u32 *)(retadr - 4) + retadr;
|
||||||
|
|
||||||
|
for (int size = 0; size < MemOp::SizeCount; size++)
|
||||||
|
{
|
||||||
|
for (int op = 0; op < MemOp::OpCount; op++)
|
||||||
|
{
|
||||||
|
if ((u32)MemHandlers[MemOp::Fast][size][op] != ca)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//found !
|
||||||
|
const u8 *start = getCurr();
|
||||||
|
call(MemHandlers[MemOp::Slow][size][op]);
|
||||||
|
verify(getCurr() - start == 5);
|
||||||
|
|
||||||
|
ready();
|
||||||
|
|
||||||
|
host_pc = retadr - 5;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR_LOG(DYNAREC, "rewriteMemAccess code not found: hpc %08x retadr %08x acc %08x", host_pc, retadr, acc);
|
||||||
|
die("Failed to match the code");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -368,16 +368,6 @@ static void reios_sys_flashrom() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reios_sys_gd()
|
|
||||||
{
|
|
||||||
gdrom_hle_op();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reios_sys_gd2()
|
|
||||||
{
|
|
||||||
gdrom_hle_op();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reios_sys_misc()
|
static void reios_sys_misc()
|
||||||
{
|
{
|
||||||
INFO_LOG(REIOS, "reios_sys_misc - r7: 0x%08X, r4 0x%08X, r5 0x%08X, r6 0x%08X", r[7], r[4], r[5], r[6]);
|
INFO_LOG(REIOS, "reios_sys_misc - r7: 0x%08X, r4 0x%08X, r5 0x%08X, r6 0x%08X", r[7], r[4], r[5], r[6]);
|
||||||
|
@ -395,7 +385,6 @@ static void reios_sys_misc()
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void hook_fp();
|
typedef void hook_fp();
|
||||||
static u32 hook_addr(hook_fp* fn);
|
|
||||||
|
|
||||||
static void setup_syscall(u32 hook_addr, u32 syscall_addr) {
|
static void setup_syscall(u32 hook_addr, u32 syscall_addr) {
|
||||||
WriteMem32(syscall_addr, hook_addr);
|
WriteMem32(syscall_addr, hook_addr);
|
||||||
|
@ -615,12 +604,12 @@ static void reios_boot()
|
||||||
|
|
||||||
memset(GetMemPtr(0x8C000000, 0), 0xFF, 64 * 1024);
|
memset(GetMemPtr(0x8C000000, 0), 0xFF, 64 * 1024);
|
||||||
|
|
||||||
setup_syscall(hook_addr(&reios_sys_system), dc_bios_syscall_system);
|
setup_syscall(0x8C001000, dc_bios_syscall_system);
|
||||||
setup_syscall(hook_addr(&reios_sys_font), dc_bios_syscall_font);
|
setup_syscall(0x8C001002, dc_bios_syscall_font);
|
||||||
setup_syscall(hook_addr(&reios_sys_flashrom), dc_bios_syscall_flashrom);
|
setup_syscall(0x8C001004, dc_bios_syscall_flashrom);
|
||||||
setup_syscall(hook_addr(&reios_sys_gd), dc_bios_syscall_gd);
|
setup_syscall(0x8C001006, dc_bios_syscall_gd);
|
||||||
setup_syscall(hook_addr(&reios_sys_gd2), dc_bios_syscall_gd2);
|
setup_syscall(dc_bios_entrypoint_gd2, dc_bios_syscall_gd2);
|
||||||
setup_syscall(hook_addr(&reios_sys_misc), dc_bios_syscall_misc);
|
setup_syscall(0x8C001008, dc_bios_syscall_misc);
|
||||||
|
|
||||||
//Infinite loop for arm !
|
//Infinite loop for arm !
|
||||||
WriteMem32(0x80800000, 0xEAFFFFFE);
|
WriteMem32(0x80800000, 0xEAFFFFFE);
|
||||||
|
@ -669,13 +658,11 @@ static void reios_boot()
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<u32, hook_fp*> hooks;
|
static std::map<u32, hook_fp*> hooks;
|
||||||
static std::map<hook_fp*, u32> hooks_rev;
|
|
||||||
|
|
||||||
#define SYSCALL_ADDR_MAP(addr) (((addr) & 0x1FFFFFFF) | 0x80000000)
|
#define SYSCALL_ADDR_MAP(addr) (((addr) & 0x1FFFFFFF) | 0x80000000)
|
||||||
|
|
||||||
static void register_hook(u32 pc, hook_fp* fn) {
|
static void register_hook(u32 pc, hook_fp* fn) {
|
||||||
hooks[SYSCALL_ADDR_MAP(pc)] = fn;
|
hooks[SYSCALL_ADDR_MAP(pc)] = fn;
|
||||||
hooks_rev[fn] = pc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DYNACALL reios_trap(u32 op) {
|
void DYNACALL reios_trap(u32 op) {
|
||||||
|
@ -693,16 +680,6 @@ void DYNACALL reios_trap(u32 op) {
|
||||||
next_pc = pr;
|
next_pc = pr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 hook_addr(hook_fp* fn) {
|
|
||||||
if (hooks_rev.count(fn))
|
|
||||||
return hooks_rev[fn];
|
|
||||||
else {
|
|
||||||
ERROR_LOG(REIOS, "hook_addr: Failed to reverse lookup %p", fn);
|
|
||||||
verify(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reios_init()
|
bool reios_init()
|
||||||
{
|
{
|
||||||
INFO_LOG(REIOS, "reios: Init");
|
INFO_LOG(REIOS, "reios: Init");
|
||||||
|
@ -712,10 +689,10 @@ bool reios_init()
|
||||||
register_hook(0x8C001000, reios_sys_system);
|
register_hook(0x8C001000, reios_sys_system);
|
||||||
register_hook(0x8C001002, reios_sys_font);
|
register_hook(0x8C001002, reios_sys_font);
|
||||||
register_hook(0x8C001004, reios_sys_flashrom);
|
register_hook(0x8C001004, reios_sys_flashrom);
|
||||||
register_hook(0x8C001006, reios_sys_gd);
|
register_hook(0x8C001006, gdrom_hle_op);
|
||||||
register_hook(0x8C001008, reios_sys_misc);
|
register_hook(0x8C001008, reios_sys_misc);
|
||||||
|
|
||||||
register_hook(dc_bios_entrypoint_gd2, reios_sys_gd2);
|
register_hook(dc_bios_entrypoint_gd2, gdrom_hle_op);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue