Commit f28988e7 authored by Libretro-Admin's avatar Libretro-Admin
Browse files
parent 531ad31e
Pipeline #16297 failed with stages
in 2 minutes and 50 seconds
......@@ -387,16 +387,8 @@ ifneq ($(filter $(WITH_DYNAREC), x86_64 x64),)
# Recompiler (x86 32bit)
else ifneq ($(filter $(WITH_DYNAREC), i386 i686 x86),)
DYNAREC_USED = 1
ifneq ($(filter $(platform), unix android),)
SOURCES_ASM += $(CORE_DIR)/core/rec-x86/rec_lin86_asm.S
else
SOURCES_ASM += $(CORE_DIR)/core/rec-x86/rec_win86_asm.S
#SOURCES_ASM += $(CORE_DIR)/core/hw/arm7/arm7_win86_asm.S
endif
SOURCES_CXX += $(CORE_DIR)/core/rec-x86/rec_x86_asm.cpp \
$(CORE_DIR)/core/rec-x86/rec_x86_driver.cpp \
$(CORE_DIR)/core/rec-x86/rec_x86_il.cpp \
$(CORE_DIR)/core/rec-x86/x86_emitter.cpp
SOURCES_CXX += $(CORE_DIR)/core/rec-x86/rec_x86.cpp \
$(CORE_DIR)/core/rec-x86/x86_ops.cpp
endif
......
This diff is collapsed.
......@@ -21,6 +21,7 @@
#if HOST_CPU == CPU_X64 && FEAT_DSPREC != DYNAREC_NONE
#define XBYAK_NO_OP_NAMES
#include "deps/xbyak/xbyak.h"
#include "deps/xbyak/xbyak_util.h"
#include "dsp.h"
......
......@@ -277,6 +277,7 @@ void FlushCache();
void arm_Reset()
{
DEBUG_LOG(AICA_ARM, "AICA ARM Reset");
#if FEAT_AREC != DYNAREC_NONE
FlushCache();
#endif
......@@ -354,6 +355,15 @@ void update_armintc()
}
#if FEAT_AREC != DYNAREC_NONE
//
// ARM7 Recompiler
//
#include "virt_arm.h"
#if defined(__APPLE__)
#include <sys/mman.h>
#endif
extern "C" void CompileCode();
......@@ -570,15 +580,6 @@ void InitHash()
AddDPOP(15,DP_R_OFC, DP_W_RFC);
}
/*
*
* X86 Compiler
*
*/
void armEmit32(u32 emit32);
void *armGetEmitPtr();
......@@ -638,25 +639,22 @@ void armv_prof(OpType opt,u32 op,u32 flg);
extern "C" void arm_dispatch();
extern "C" void arm_exit();
extern "C" void DYNACALL arm_mainloop(u32 cycl, void* regs, void* entrypoints);
extern "C" void DYNACALL
#ifdef __GNUC__
// Avoid inlining / duplicating / whatever
__attribute__ ((optimize(0)))
#endif
arm_mainloop(u32 cycl, void* regs, void* entrypoints);
extern "C" void DYNACALL arm_compilecode();
template <bool Load, bool Byte>
u32 DYNACALL DoMemOp(u32 addr,u32 data)
{
u32 rv=0;
#if HOST_CPU==CPU_X86
addr=virt_arm_reg(0);
data=virt_arm_reg(1);
#endif
if (Load)
{
if (Byte)
rv=arm_ReadMem8(addr);
else
rv=arm_ReadMem32(addr);
return arm_ReadMem8(addr);
return arm_ReadMem32(addr);
}
else
{
......@@ -666,11 +664,7 @@ u32 DYNACALL DoMemOp(u32 addr,u32 data)
arm_WriteMem32(addr,data);
}
#if HOST_CPU==CPU_X86
virt_arm_reg(0)=rv;
#endif
return rv;
return 0;
}
//findfirstset -- used in LDM/STM handling
......@@ -695,10 +689,6 @@ template<u32 I>
void DYNACALL DoLDM(u32 addr, u32 mask)
{
#if HOST_CPU==CPU_X86
addr=virt_arm_reg(0);
mask=virt_arm_reg(1);
#endif
//addr=(addr); //force align ?
u32 idx=-1;
......@@ -715,20 +705,16 @@ void DYNACALL DoLDM(u32 addr, u32 mask)
void* GetMemOp(bool Load, bool Byte)
{
if (Load)
{
if (Byte)
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<true,true>;
else
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<true,false>;
}
else
{
if (Byte)
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<false,true>;
else
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<false,false>;
}
if (Load)
{
if (Byte)
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<true,true>;
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<true,false>;
}
if (Byte)
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<false,true>;
return (void*)(u32(DYNACALL*)(u32,u32))&DoMemOp<false,false>;
}
//Decodes an opcode, returns type.
......@@ -1227,212 +1213,7 @@ void *armGetEmitPtr()
return NULL;
}
#if HOST_CPU == CPU_X86
/* X86 backend
* Uses a mix of
* x86 code
* Virtualised arm code (using the varm interpreter)
* Emulated arm fallbacks (using the aica arm interpreter)
*
* The goal is to run as much code possible under the varm interpreter
* so it will run on arm w/o changes. A few opcodes are missing from varm
* (MOV32 is a notable case) and as such i've added a few varm_* hooks
*
* This code also performs a LOT of compiletime and runtime state/value sanity checks.
* We don't care for speed here ...
*/
#include "../../rec-x86/x86_emitter.h"
#include "virt_arm.h"
static x86_block* x86e;
void DumpRegs(const char* output)
{
static FILE* f=fopen(output, "w");
static int id=0;
#if 0
if (490710==id)
{
__asm int 3;
}
#endif
verify(id!=137250);
#if 1
fprintf(f,"%d\n",id);
//for(int i=0;i<14;i++)
{
int i=R15_ARM_NEXT;
fprintf(f,"r%d=%08X\n",i,reg[i].I);
}
#endif
id++;
}
void DYNACALL PrintOp(u32 opcd)
{
DEBUG_LOG(AICA_ARM, "%08X", opcd);
}
void armv_imm_to_reg(u32 regn, u32 imm)
{
x86e->Emit(op_mov32,&reg[regn].I,imm);
}
void armv_MOV32(eReg regn, u32 imm)
{
x86e->Emit(op_mov32,&virt_arm_reg(regn),imm);
}
void armv_call(void* loc)
{
x86e->Emit(op_call,x86_ptr_imm(loc));
}
x86_Label* end_lbl;
void armv_setup()
{
//Setup emitter
x86e = new x86_block();
x86e->Init(0,0);
x86e->x86_buff=(u8*)EMIT_GET_PTR();
x86e->x86_size=1024*64;
x86e->do_realloc=false;
//load base reg ..
x86e->Emit(op_mov32,&virt_arm_reg(8),(u32)&arm_Reg[0]);
//the "end" label is used to exit from the block, if a code modification (expected opcode // actual opcode in ram) is detected
end_lbl=x86e->CreateLabel(false,0);
}
void armv_intpr(u32 opcd)
{
//Call interpreter
x86e->Emit(op_mov32,ECX,opcd);
x86e->Emit(op_call,x86_ptr_imm(&arm_single_op));
}
void armv_end(void* codestart, u32 cycles)
{
//Normal block end
//Move counter to EAX for return, pop ESI, ret
x86e->Emit(op_sub32,ESI,cycles);
x86e->Emit(op_jns,x86_ptr_imm(arm_dispatch));
x86e->Emit(op_jmp,x86_ptr_imm(arm_exit));
//Fluch cache, move counter to EAX, pop, ret
//this should never happen (triggers a breakpoint on x86)
x86e->MarkLabel(end_lbl);
x86e->Emit(op_int3);
x86e->Emit(op_call,x86_ptr_imm(FlushCache));
x86e->Emit(op_sub32,ESI,cycles);
x86e->Emit(op_jmp,x86_ptr_imm(arm_dispatch));
//Generate the code & apply fixups/relocations as needed
x86e->Generate();
//Use space from the dynarec buffer
icPtr+=x86e->x86_indx;
//Delete the x86 emitter ...
delete x86e;
}
//sanity check: non branch doesn't set pc
void armv_check_pc(u32 pc)
{
x86e->Emit(op_cmp32,&armNextPC,pc);
x86_Label* nof=x86e->CreateLabel(false,0);
x86e->Emit(op_je,nof);
x86e->Emit(op_int3);
x86e->MarkLabel(nof);
}
//sanity check: stale cache
void armv_check_cache(u32 opcd, u32 pc)
{
x86e->Emit(op_cmp32,&CPUReadMemoryQuick(pc),opcd);
x86_Label* nof=x86e->CreateLabel(false,0);
x86e->Emit(op_je,nof);
x86e->Emit(op_int3);
x86e->MarkLabel(nof);
}
//profiler hook
void armv_prof(OpType opt,u32 op,u32 flags)
{
if (VOT_Fallback!=opt)
x86e->Emit(op_add32,&nfb,1);
else
{
if (flags & OP_SETS_PC)
x86e->Emit(op_add32,&bfb,1);
else if (flags & OP_MFB)
x86e->Emit(op_add32,&mfb,1);
else
x86e->Emit(op_add32,&ffb,1);
}
}
#ifndef _WIN32
naked void DYNACALL arm_compilecode()
{
__asm
{
call CompileCode;
mov eax,0;
jmp arm_dispatch;
}
}
naked void DYNACALL arm_mainloop(u32 cycl, void* regs, void* entrypoints)
{
__asm
{
push esi
mov esi,ecx
add esi,reg[CYCL_CNT*4].I
mov eax,0;
jmp arm_dispatch
}
}
naked void arm_dispatch()
{
__asm
{
arm_disp:
mov eax,reg[R15_ARM_NEXT*4].I
and eax,0x7FFFFC
cmp reg[INTR_PEND*4].I,0
jne arm_dofiq
jmp [EntryPoints+eax]
arm_dofiq:
call CPUFiq
jmp arm_disp
}
}
naked void arm_exit()
{
__asm
{
arm_exit:
mov reg[CYCL_CNT*4].I,esi
pop esi
ret
}
}
#endif
#elif (HOST_CPU == CPU_ARM)
#if (HOST_CPU == CPU_ARM)
/*
*
......@@ -1518,7 +1299,7 @@ void armv_end(void* codestart, u32 cycl)
armFlushICache(codestart,(void*)EMIT_GET_PTR());
}
//Hook cus varm misses this, so x86 needs special code
//Hook cus varm misses this
void armv_MOV32(eReg regn, u32 imm)
{
MOV32(regn,imm);
......@@ -1528,9 +1309,7 @@ void armv_MOV32(eReg regn, u32 imm)
No sanity checks on arm ..
*/
#elif HOST_CPU == CPU_ARM64
#include <sys/mman.h>
#endif
#endif // HOST_CPU == CPU_ARM
//Run a timeslice for ARMREC
void arm_Run(u32 samples)
......@@ -1579,9 +1358,6 @@ void MemOperand2(eReg dst,bool I, bool U,u32 offs, u32 opcd)
template<u32 Pd>
void DYNACALL MSR_do(u32 v)
{
#if HOST_CPU==CPU_X86
v=virt_arm_reg(r0);
#endif
if (Pd)
{
if(armMode > 0x10 && armMode < 0x1f) /* !=0x10 ?*/
......@@ -1645,11 +1421,6 @@ extern "C" void CompileCode()
//Read opcode ...
u32 opcd=CPUReadMemoryQuick(pc);
#if HOST_CPU==CPU_X86
//Sanity check: Stale cache
armv_check_cache(opcd,pc);
#endif
u32 op_flags;
//Decode & handle opcode
......@@ -1668,15 +1439,9 @@ extern "C" void CompileCode()
armv_imm_to_reg(15,pc+8);
else*/
#if HOST_CPU==CPU_X86
armv_imm_to_reg(15,rand());
#endif
VirtualizeOpcode(opcd,op_flags,pc);
#if HOST_CPU==CPU_X86
armv_imm_to_reg(15,rand());
#endif
}
break;
......@@ -1694,11 +1459,7 @@ extern "C" void CompileCode()
}
LoadReg(r0,opcd&0xF);
#if HOST_CPU==CPU_X86
x86e->Emit(op_and32, &virt_arm_reg(0), 0xfffffffc);
#else
armv_bic(r0, r0, 3);
#endif
void *ref = armv_start_conditional(cc);
StoreReg(r0,R15_ARM_NEXT,cc);
armv_end_conditional(ref);
......@@ -1946,24 +1707,8 @@ extern "C" void CompileCode()
if (op_flags & OP_SETS_PC)
armv_imm_to_reg(R15_ARM_NEXT,pc+4);
#if HOST_CPU==CPU_X86
if ( !(op_flags & OP_SETS_PC) )
armv_imm_to_reg(R15_ARM_NEXT,pc+4);
#endif
armv_intpr(opcd);
#if HOST_CPU==CPU_X86
if ( !(op_flags & OP_SETS_PC) )
{
//Sanity check: next pc
armv_check_pc(pc+4);
#if 0
x86e->Emit(op_mov32,ECX,opcd);
x86e->Emit(op_call,x86_ptr_imm(PrintOp));
#endif
}
#endif
}
break;
......@@ -1971,26 +1716,11 @@ extern "C" void CompileCode()
die("can't happen\n");
}
#if HOST_CPU==CPU_X86
armv_imm_to_reg(15,0xF87641FF);
armv_prof(opt,opcd,op_flags);
#endif
//Branch ?
if (op_flags & OP_SETS_PC)
{
//x86e->Emit(op_call,x86_ptr_imm(DumpRegs)); // great debugging tool
arm_printf("ARM: %06X: Block End %d\n",pc,ops);
#if HOST_CPU==CPU_X86 && 0
//Great fallback finder, also spams console
if (opt==VOT_Fallback)
{
x86e->Emit(op_mov32,ECX,opcd);
x86e->Emit(op_call,x86_ptr_imm(PrintOp));
}
#endif
break;
}
......@@ -2010,8 +1740,6 @@ extern "C" void CompileCode()
armv_end((void*)rv,Cycles);
}
void FlushCache()
{
icPtr=ICache;
......@@ -2019,37 +1747,6 @@ void FlushCache()
EntryPoints[i]=(void*)&arm_compilecode;
}
#if HOST_CPU==CPU_X86 && HOST_OS == OS_WINDOWS
#include <windows.h>
// These have to be declared somewhere or linker dies
u8* ARM::emit_opt=0;
eReg ARM::reg_addr;
eReg ARM::reg_dst;
s32 ARM::imma;
void armEmit32(u32 emit32)
{
if (icPtr >= (ICache + ICacheSize - 64*1024)) {
die("ICache is full, invalidate old entries ..."); //ifdebug
}
x86e->Emit(op_mov32,ECX,emit32);
x86e->Emit(op_call,x86_ptr_imm(virt_arm_op));
}
void *armGetEmitPtr()
{
return icPtr;
}
#endif
void armt_init()
{
InitHash();
......@@ -2057,11 +1754,11 @@ void armt_init()
//align to next page ..
ICache = (u8*)(((unat)ARM7_TCB+4095)& ~4095);
#ifdef __MACH__
//Can't just mprotect on iOS
munmap(ICache, ICacheSize);
ICache = (u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
#endif
#ifdef TARGET_IPHONE
//Can't just mprotect on iOS
munmap(ICache, ICacheSize);
ICache = (u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
#endif
mem_region_set_exec(ICache, ICacheSize);
......@@ -2074,5 +1771,4 @@ void armt_init()
icPtr=ICache;
}
#endif
#endif // FEAT_AREC != DYNAREC_NONE
......@@ -133,7 +133,7 @@ RuntimeBlockInfoPtr bm_GetBlock2(void* dynarec_code)
iter--; // Need to go back to find the potential candidate
// However it might be out of bounds, check for that
if ((u8*)iter->second->code + iter->second->host_code_size < (u8*)dynarecrw)
if ((u8*)iter->second->code + iter->second->host_code_size <= (u8*)dynarec_code)
return NULL;
verify(iter->second->contains_code((u8*)dynarecrw));
......@@ -155,7 +155,7 @@ RuntimeBlockInfoPtr bm_GetStaleBlock(void* dynarec_code)
auto it = del_blocks.end();
do
{
it--;
--it;
if ((*it)->contains_code((u8*)dynarecrw))
return *it;
} while (it != del_blocks.begin());
......@@ -365,7 +365,6 @@ void bm_ResetTempCache(bool full)
void bm_Init()
{
#ifdef DYNA_OPROF
oprofHandle=op_open_agent();
if (oprofHandle==0)
......@@ -373,7 +372,6 @@ void bm_Init()
else
INFO_LOG(DYNAREC, "bm: Oprofile integration enabled !");
#endif
bm_Reset();
}
void bm_Term()
......@@ -547,10 +545,10 @@ void RuntimeBlockInfo::Discard()
// Update references
for (RuntimeBlockInfoPtr& ref : pre_refs)
{
if (ref->NextBlock == vaddr)
ref->pNextBlock = NULL;
if (ref->BranchBlock == vaddr)
ref->pBranchBlock = NULL;
if (ref->pNextBlock == this)
ref->pNextBlock = nullptr;
if (ref->pBranchBlock == this)
ref->pBranchBlock = nullptr;
ref->relink_data = 0;
ref->Relink();
}
......
......@@ -138,7 +138,7 @@ const char* RuntimeBlockInfo::hash()
{
u16 data=ptr[i];
//Do not count PC relative loads (relocated code)
if ((ptr[i]>>12)==0xD)
if ((data >> 12) == 0xD)
data=0xD000;
XXH32_update(state, &data, 2);
......@@ -254,7 +254,7 @@ DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock_pc()
DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc)
{
//printf("rdv_FailedToFindBlock ~ %08X\n",pc);
//DEBUG_LOG(DYNAREC, "rdv_FailedToFindBlock %08x", pc);
next_pc=pc;
DynarecCodeEntryPtr code = rdv_CompilePC(0);
if (code == NULL)
......@@ -319,6 +319,7 @@ DynarecCodeEntryPtr rdv_FindOrCompile()
void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc)
{
// code is the RX addr to return after, however bm_GetBlock returns RW
//DEBUG_LOG(DYNAREC, "rdv_LinkBlock %p pc %08x", code, dpc);
RuntimeBlockInfoPtr rbi=bm_GetBlock2((void*)code);
bool stale_block = false;
if (!rbi)
......