flycast/core/rec-x64/rec_x64.cpp

282 lines
4.9 KiB
C++
Raw Normal View History

2015-07-14 01:35:34 +00:00
#include "xbyak/xbyak.h"
2015-07-13 21:56:42 +00:00
#include "types.h"
#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
}