2015-07-14 01:35:34 +00:00
|
|
|
#include "xbyak/xbyak.h"
|
2015-07-13 21:56:42 +00:00
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
|
2015-07-14 15:47:54 +00:00
|
|
|
#if HOST_CPU == CPU_X64
|
2015-07-13 21:56:42 +00:00
|
|
|
#include "hw/sh4/sh4_opcode_list.h"
|
|
|
|
#include "hw/sh4/modules/ccn.h"
|
|
|
|
#include "hw/sh4/sh4_interrupts.h"
|
|
|
|
|
|
|
|
#include "hw/sh4/sh4_core.h"
|
|
|
|
#include "hw/sh4/dyna/ngen.h"
|
|
|
|
#include "hw/sh4/sh4_mem.h"
|
|
|
|
#include "hw/sh4/dyna/regalloc.h"
|
|
|
|
#include "emitter/x86_emitter.h"
|
|
|
|
#include "profiler/profiler.h"
|
|
|
|
#include "oslib/oslib.h"
|
|
|
|
|
|
|
|
|
|
|
|
struct DynaRBI : RuntimeBlockInfo
|
|
|
|
{
|
|
|
|
virtual u32 Relink() {
|
|
|
|
//verify(false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void Relocate(void* dst) {
|
|
|
|
verify(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int cycle_counter;
|
|
|
|
|
|
|
|
void ngen_FailedToFindBlock_internal() {
|
|
|
|
rdv_FailedToFindBlock(Sh4cntx.pc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void(*ngen_FailedToFindBlock)() = &ngen_FailedToFindBlock_internal;
|
|
|
|
|
|
|
|
void ngen_mainloop(void* v_cntx)
|
|
|
|
{
|
2015-07-14 01:35:34 +00:00
|
|
|
Sh4RCB* ctx = (Sh4RCB*)((u8*)v_cntx - sizeof(Sh4RCB));
|
2015-07-13 21:56:42 +00:00
|
|
|
|
2015-07-14 15:23:02 +00:00
|
|
|
cycle_counter = 0;
|
2015-07-13 21:56:42 +00:00
|
|
|
|
|
|
|
for (;;) {
|
2015-07-14 15:23:02 +00:00
|
|
|
cycle_counter = SH4_TIMESLICE;
|
2015-07-13 21:56:42 +00:00
|
|
|
do {
|
2015-07-14 01:35:34 +00:00
|
|
|
DynarecCodeEntryPtr rcb = bm_GetCode(ctx->cntx.pc);
|
2015-07-13 21:56:42 +00:00
|
|
|
rcb();
|
|
|
|
} while (cycle_counter > 0);
|
|
|
|
|
|
|
|
if (UpdateSystem()) {
|
|
|
|
rdv_DoInterrupts_pc(ctx->cntx.pc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ngen_init()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ngen_ResetBlocks()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void ngen_GetFeatures(ngen_features* dst)
|
|
|
|
{
|
|
|
|
dst->InterpreterFallback = true;
|
|
|
|
dst->OnlyDynamicEnds = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
RuntimeBlockInfo* ngen_AllocateBlock()
|
|
|
|
{
|
|
|
|
return new DynaRBI();
|
|
|
|
}
|
|
|
|
|
|
|
|
u32* GetRegPtr(u32 reg)
|
|
|
|
{
|
|
|
|
return Sh4_int_GetRegisterPtr((Sh4RegType)reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
class BlockCompiler : Xbyak::CodeGenerator{
|
|
|
|
public:
|
|
|
|
BlockCompiler() : Xbyak::CodeGenerator(64 * 1024, emit_GetCCPtr()) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) {
|
|
|
|
mov(rax, (size_t)&cycle_counter);
|
|
|
|
|
|
|
|
sub(dword[rax], block->guest_cycles);
|
|
|
|
|
|
|
|
sub(rsp, 8);
|
|
|
|
|
2015-07-14 01:35:34 +00:00
|
|
|
for (size_t i = 0; i < block->oplist.size(); i++) {
|
|
|
|
shil_opcode& op = block->oplist[i];
|
2015-07-13 21:56:42 +00:00
|
|
|
switch (op.op) {
|
|
|
|
|
|
|
|
case shop_ifb:
|
|
|
|
if (op.rs1._imm)
|
|
|
|
{
|
|
|
|
mov(rax, (size_t)&next_pc);
|
|
|
|
mov(dword[rax], op.rs2._imm);
|
|
|
|
}
|
|
|
|
|
2015-07-14 01:35:34 +00:00
|
|
|
#if HOST_OS == OS_LINUX
|
|
|
|
mov(rdi, op.rs3._imm);
|
|
|
|
#else
|
|
|
|
mov(rcx, op.rs3._imm);
|
|
|
|
#endif
|
2015-07-13 21:56:42 +00:00
|
|
|
|
|
|
|
call(OpDesc[op.rs3._imm]->oph);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case shop_jdyn:
|
|
|
|
{
|
|
|
|
mov(rax, (size_t)op.rs1.reg_ptr());
|
|
|
|
|
|
|
|
mov(ecx, dword[rax]);
|
|
|
|
|
|
|
|
if (op.rs2.is_imm()) {
|
|
|
|
add(ecx, op.rs2._imm);
|
|
|
|
}
|
|
|
|
mov(dword[rax], ecx);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case shop_mov32:
|
|
|
|
{
|
|
|
|
verify(op.rd.is_reg());
|
|
|
|
|
|
|
|
verify(op.rs1.is_reg() || op.rs1.is_imm());
|
|
|
|
|
|
|
|
if (op.rs1.is_imm()) {
|
|
|
|
mov(ecx, op.rs1._imm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mov(rax, (size_t)op.rs1.reg_ptr());
|
|
|
|
|
|
|
|
mov(ecx, dword[rax]);
|
|
|
|
}
|
|
|
|
|
|
|
|
mov(rax, (size_t)op.rd.reg_ptr());
|
|
|
|
|
|
|
|
mov(dword[rax], ecx);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
shil_chf[op.op](&op);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
verify(block->BlockType == BET_DynamicJump);
|
|
|
|
|
|
|
|
add(rsp, 8);
|
|
|
|
ret();
|
|
|
|
|
|
|
|
ready();
|
|
|
|
|
|
|
|
block->code = (DynarecCodeEntryPtr)getCode();
|
|
|
|
|
|
|
|
emit_Skip(getSize());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
|
|
|
{
|
|
|
|
verify(emit_FreeSpace() >= 64 * 1024);
|
|
|
|
|
2015-07-14 01:35:34 +00:00
|
|
|
BlockCompiler* compiler = new BlockCompiler();
|
2015-07-13 21:56:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
compiler->compile(block, force_checks, reset, staging, optimise);
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 ngen_CC_BytesPushed;
|
|
|
|
void ngen_CC_Start(shil_opcode* op)
|
|
|
|
{
|
|
|
|
ngen_CC_BytesPushed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ngen_CC_Param(shil_opcode* op, shil_param* par, CanonicalParamType tp)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
switch (tp)
|
|
|
|
{
|
|
|
|
//push the contents
|
|
|
|
case CPT_u32:
|
|
|
|
case CPT_f32:
|
|
|
|
if (par->is_reg())
|
|
|
|
{
|
|
|
|
if (reg.IsAllocg(*par))
|
|
|
|
x86e->Emit(op_push32, reg.mapg(*par));
|
|
|
|
else if (reg.IsAllocf(*par))
|
|
|
|
{
|
|
|
|
x86e->Emit(op_sub32, ESP, 4);
|
|
|
|
x86e->Emit(op_movss, x86_mrm(ESP), reg.mapf(*par));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
die("Must not happen !\n");
|
|
|
|
x86e->Emit(op_push32, x86_ptr(par->reg_ptr()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (par->is_imm())
|
|
|
|
x86e->Emit(op_push, par->_imm);
|
|
|
|
else
|
|
|
|
die("invalid combination");
|
|
|
|
ngen_CC_BytesPushed += 4;
|
|
|
|
break;
|
|
|
|
//push the ptr itself
|
|
|
|
case CPT_ptr:
|
|
|
|
verify(par->is_reg());
|
|
|
|
|
|
|
|
die("FAIL");
|
|
|
|
x86e->Emit(op_push, (unat)par->reg_ptr());
|
|
|
|
|
|
|
|
for (u32 ri = 0; ri<(*par).count(); ri++)
|
|
|
|
{
|
|
|
|
if (reg.IsAllocf(*par, ri))
|
|
|
|
{
|
|
|
|
x86e->Emit(op_sub32, ESP, 4);
|
|
|
|
x86e->Emit(op_movss, x86_mrm(ESP), reg.mapfv(*par, ri));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
verify(!reg.IsAllocAny((Sh4RegType)(par->_reg + ri)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ngen_CC_BytesPushed += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
//store from EAX
|
|
|
|
case CPT_u64rvL:
|
|
|
|
case CPT_u32rv:
|
|
|
|
if (reg.IsAllocg(*par))
|
|
|
|
x86e->Emit(op_mov32, reg.mapg(*par), EAX);
|
|
|
|
/*else if (reg.IsAllocf(*par))
|
|
|
|
x86e->Emit(op_movd_xmm_from_r32,reg.mapf(*par),EAX);*/
|
|
|
|
else
|
|
|
|
die("Must not happen!\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CPT_u64rvH:
|
|
|
|
if (reg.IsAllocg(*par))
|
|
|
|
x86e->Emit(op_mov32, reg.mapg(*par), EDX);
|
|
|
|
else
|
|
|
|
die("Must not happen!\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
//Store from ST(0)
|
|
|
|
case CPT_f32rv:
|
|
|
|
verify(reg.IsAllocf(*par));
|
|
|
|
x86e->Emit(op_fstp32f, x86_ptr(par->reg_ptr()));
|
|
|
|
x86e->Emit(op_movss, reg.mapf(*par), x86_ptr(par->reg_ptr()));
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void ngen_CC_Call(shil_opcode*op, void* function)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
reg.FreezeXMM();
|
|
|
|
x86e->Emit(op_call, x86_ptr_imm(function));
|
|
|
|
reg.ThawXMM();
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
void ngen_CC_Finish(shil_opcode* op)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
x86e->Emit(op_add32, ESP, ngen_CC_BytesPushed);
|
|
|
|
*/
|
2015-07-14 01:35:34 +00:00
|
|
|
}
|
2015-07-14 15:47:54 +00:00
|
|
|
#endif
|