dynarec: Refactor smc-option a bit

This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2019-03-30 06:33:52 +01:00
parent 8e9b1306e1
commit af6993a819
10 changed files with 245 additions and 177 deletions

View File

@ -304,6 +304,8 @@ void bm_Rebuild()
{
return;
die("this is broken in multiple levels, including compile options");
void RASDASD();
RASDASD();
@ -321,7 +323,7 @@ void bm_Rebuild()
//constprop(all_blocks[i]);
//#endif
}
ngen_Compile(all_blocks[i],false,false,all_blocks[i]->staging_runs>0,do_opts);
ngen_Compile(all_blocks[i],NoCheck,false,all_blocks[i]->staging_runs>0,do_opts);
blkmap.insert(all_blocks[i]);
verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]);

View File

@ -86,10 +86,13 @@ void recSh4_Run()
sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx);
printf("cntx // fpcb offset: %td // pc offset: %td // pc %08X\n",(u8*)&sh4rcb.fpcb - sh4_dyna_rcb, (u8*)&sh4rcb.cntx.pc - sh4_dyna_rcb,sh4rcb.cntx.pc);
if (!settings.dynarec.safemode)
printf("Warning: Dynarec safe mode is off\n");
if (settings.dynarec.unstable_opt)
printf("Warning: Unstable optimizations is on\n");
if (settings.dynarec.SmcCheckLevel != FullCheck)
printf("Warning: SMC check mode is %d\n", settings.dynarec.SmcCheckLevel);
@ -125,34 +128,51 @@ u32 emit_FreeSpace()
}
bool DoCheck(u32 pc)
SmcCheckEnum DoCheck(u32 pc)
{
if (IsOnRam(pc))
{
if (!settings.dynarec.unstable_opt)
return true;
pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
switch (settings.dynarec.SmcCheckLevel) {
//Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
// Heuristic-elimintaed FastChecks
case NoCheck: {
if (IsOnRam(pc))
{
pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
return true;
//Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
default:
return false;
return FastCheck;
default:
return NoCheck;
}
}
return NoCheck;
}
break;
// Fast Check everything
case FastCheck:
return FastCheck;
// Full Check everything
case FullCheck:
return FastCheck;
default:
die("Unhandled settings.dynarec.SmcCheckLevel");
}
return false;
}
void AnalyseBlock(RuntimeBlockInfo* blk);

View File

@ -85,7 +85,7 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc);
void ngen_init();
//Called to compile a block
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise);
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise);
//Called when blocks are reseted
void ngen_ResetBlocks();

View File

@ -12,6 +12,8 @@
//Types
#define printf_smc(...) // printf
u32 CCN_QACR_TR[2];
@ -72,13 +74,18 @@ void CCN_CCR_write(u32 addr, u32 value)
temp.reg_data=value;
//what is 0xAC13DBF8 from ?
if (temp.ICI && curr_pc!=0xAC13DBF8)
{
//printf("Sh4: i-cache invalidation %08X\n",curr_pc);
// Shikigami No Shiro II sets ICI frequently
// Any reason to flush the dynarec cache for this?
//sh4_cpu.ResetCache();
if (temp.ICI) {
printf_smc("Sh4: i-cache invalidation %08X\n",curr_pc);
if (settings.dynarec.SmcCheckLevel != FullCheck) {
//TODO: Add skip/check vectors for Shikigami No Shiro II (uses ICI frequently)
//which game is 0xAC13DBF8 from ?
if (curr_pc != 0xAC13DBF8)
{
printf("Sh4: code cache clear (ICI) pc: %08X\n",curr_pc);
sh4_cpu.ResetCache();
}
}
}
temp.ICI=0;

View File

@ -2082,7 +2082,7 @@ __default:
}
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
{
//printf("Compile: %08X, %d, %d\n",block->addr,staging,optimise);
block->code=(DynarecCodeEntryPtr)EMIT_GET_PTR();
@ -2114,10 +2114,11 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
reg.OpBegin(&block->oplist[0],0);
//scheduler
if (force_checks && settings.dynarec.SmcCheckLevel != NoCheck)
{
if (settings.dynarec.SmcCheckLevel == FastCheck)
{
switch (smc_checks) {
case NoCheck:
break;
case FastCheck: {
MOV32(r0,block->addr);
u32* ptr=(u32*)GetMemPtr(block->addr,4);
MOV32(r2,(u32)ptr);
@ -2126,8 +2127,9 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
}
else // FullCheck
{
break;
case FullCheck: {
s32 sz = block->sh4_code_size;
u32 addr = block->addr;
MOV32(r0,addr);
@ -2160,6 +2162,11 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
}
}
}
break;
default: {
die("unhandled smc_checks");
}
}
u32 cyc=block->guest_cycles;

View File

@ -348,15 +348,15 @@ public:
return *ret_reg;
}
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
//printf("REC-ARM64 compiling %08x\n", block->addr);
#ifdef PROFILING
SaveFramePointer();
#endif
this->block = block;
if (force_checks)
CheckBlock(block);
CheckBlock(smc_checks, block);
// run register allocator
regalloc.DoAlloc(block);
@ -1292,65 +1292,73 @@ private:
verify (GetCursorAddress<Instruction *>() - start_instruction == code_size * kInstructionSize);
}
void CheckBlock(RuntimeBlockInfo* block)
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
{
if (settings.dynarec.SmcCheckLevel == NoCheck)
return;
Label blockcheck_fail;
Label blockcheck_success;
if (settings.dynarec.SmcCheckLevel == FastCheck)
{
u8* ptr = GetMemPtr(block->addr, 4);
if (ptr == NULL)
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
Ldr(w10, MemOperand(x9));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
B(eq, &blockcheck_success);
}
else // FullCheck
{
s32 sz = block->sh4_code_size;
u8* ptr = GetMemPtr(block->addr, sz);
if (ptr == NULL)
switch (smc_checks) {
case NoCheck:
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
while (sz > 0)
{
if (sz >= 8)
{
Ldr(x10, MemOperand(x9, 8, PostIndex));
Ldr(x11, *(u64*)ptr);
Cmp(x10, x11);
sz -= 8;
ptr += 8;
}
else if (sz >= 4)
{
Ldr(w10, MemOperand(x9, 4, PostIndex));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
sz -= 4;
ptr += 4;
}
else
{
Ldrh(w10, MemOperand(x9, 2, PostIndex));
Mov(w11, *(u16*)ptr);
Cmp(w10, w11);
sz -= 2;
ptr += 2;
}
B(ne, &blockcheck_fail);
case FastCheck: {
u8* ptr = GetMemPtr(block->addr, 4);
if (ptr == NULL)
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
Ldr(w10, MemOperand(x9));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
B(eq, &blockcheck_success);
}
B(&blockcheck_success);
break;
case FullCheck: {
s32 sz = block->sh4_code_size;
u8* ptr = GetMemPtr(block->addr, sz);
if (ptr == NULL)
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
while (sz > 0)
{
if (sz >= 8)
{
Ldr(x10, MemOperand(x9, 8, PostIndex));
Ldr(x11, *(u64*)ptr);
Cmp(x10, x11);
sz -= 8;
ptr += 8;
}
else if (sz >= 4)
{
Ldr(w10, MemOperand(x9, 4, PostIndex));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
sz -= 4;
ptr += 4;
}
else
{
Ldrh(w10, MemOperand(x9, 2, PostIndex));
Mov(w11, *(u16*)ptr);
Cmp(w10, w11);
sz -= 2;
ptr += 2;
}
B(ne, &blockcheck_fail);
}
B(&blockcheck_success);
}
break;
default:
die("unhandled smc_checks");
}
Bind(&blockcheck_fail);
Ldr(w0, block->addr);
TailCallRuntime(ngen_blockcheckfail);
@ -1419,13 +1427,13 @@ private:
static Arm64Assembler* compiler;
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new Arm64Assembler();
compiler->ngen_Compile(block, force_checks, reset, staging, optimise);
compiler->ngen_Compile(block, smc_checks, reset, staging, optimise);
delete compiler;
compiler = NULL;

View File

@ -1190,10 +1190,10 @@ public:
size_t opcode_index;
opcodeExec** ptrsg;
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) {
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise) {
//we need an extra one for the end opcode and optionally one more for block check
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (force_checks ? 1 : 0))(block->guest_cycles);
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (smc_checks != NoCheck ? 1 : 0))(block->guest_cycles);
ptrsg = ptrs.ptrs;
@ -1207,9 +1207,16 @@ public:
}
size_t i = 0;
if (force_checks)
if (smc_checks != NoCheck)
{
verify (smc_checks == FastCheck || smc_checks == FullCheck)
opcodeExec* op;
int check_size = block->sh4_code_size;
if (smc_checks == FastCheck) {
check_size = 4;
}
switch (block->sh4_code_size)
{
case 4:
@ -1227,6 +1234,7 @@ public:
}
ptrs.ptrs[i++] = op;
}
for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) {
opcode_index = i;
shil_opcode& op = block->oplist[opnum];
@ -1551,14 +1559,14 @@ public:
BlockCompiler* compiler;
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler();
compiler->compile(block, force_checks, reset, staging, optimise);
compiler->compile(block, smc_checks, reset, staging, optimise);
delete compiler;
}

View File

@ -239,12 +239,11 @@ public:
call_regsxmm.push_back(xmm3);
}
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
//printf("X86_64 compiling %08x to %p\n", block->addr, emit_GetCCPtr());
if (force_checks) {
CheckBlock(block);
}
CheckBlock(smc_checks, block);
regalloc.DoAlloc(block);
sub(dword[rip + &cycle_counter], block->guest_cycles);
@ -1086,55 +1085,64 @@ private:
typedef void (BlockCompiler::*X64BinaryOp)(const Xbyak::Operand&, const Xbyak::Operand&);
typedef void (BlockCompiler::*X64BinaryFOp)(const Xbyak::Xmm&, const Xbyak::Operand&);
void CheckBlock(RuntimeBlockInfo* block) {
if (settings.dynarec.SmcCheckLevel == NoCheck)
return;
mov(call_regs[0], block->addr);
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block) {
if (settings.dynarec.SmcCheckLevel == FastCheck)
{
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
mov(rax, reinterpret_cast<uintptr_t>(ptr));
mov(edx, *(u32*)ptr);
cmp(dword[rax], edx);
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
}
}
else
{
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
switch (smc_checks) {
case NoCheck:
return;
while (sz > 0)
{
void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
if (ptr)
case FastCheck: {
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
mov(call_regs[0], block->addr);
mov(rax, reinterpret_cast<uintptr_t>(ptr));
if (sz >= 8) {
mov(rdx, *(u64*)ptr);
cmp(qword[rax], rdx);
sz -= 8;
sa += 8;
}
else if (sz >= 4) {
mov(edx, *(u32*)ptr);
cmp(dword[rax], edx);
sz -= 4;
sa += 4;
}
else {
mov(edx, *(u16*)ptr);
cmp(word[rax],dx);
sz -= 2;
sa += 2;
}
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
mov(edx, *(u32*)ptr);
cmp(dword[rax], edx);
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
}
}
}
break;
case FullCheck: {
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
mov(call_regs[0], block->addr);
while (sz > 0)
{
void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
if (ptr)
{
mov(rax, reinterpret_cast<uintptr_t>(ptr));
if (sz >= 8) {
mov(rdx, *(u64*)ptr);
cmp(qword[rax], rdx);
sz -= 8;
sa += 8;
}
else if (sz >= 4) {
mov(edx, *(u32*)ptr);
cmp(dword[rax], edx);
sz -= 4;
sa += 4;
}
else {
mov(edx, *(u16*)ptr);
cmp(word[rax],dx);
sz -= 2;
sa += 2;
}
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
}
}
}
break;
default:
die("unhandled smc_checks");
}
}
@ -1277,13 +1285,13 @@ void X64RegAlloc::Writeback_FPU(u32 reg, s8 nreg)
static BlockCompiler* compiler;
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler();
compiler->compile(block, force_checks, reset, staging, optimise);
compiler->compile(block, smc_checks, reset, staging, optimise);
delete compiler;
}

View File

@ -229,42 +229,50 @@ u32 rdmt[6];
extern u32 memops_t,memops_l;
extern int mips_counter;
void CheckBlock(RuntimeBlockInfo* block,x86_ptr_imm place)
//TODO: Get back validating mode for this
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
{
if (settings.dynarec.SmcCheckLevel == NoCheck)
return;
if (settings.dynarec.SmcCheckLevel == FastCheck)
{
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
x86e->Emit(op_cmp32, ptr, *(u32*)ptr);
x86e->Emit(op_jne, place);
}
}
else // FullCheck
{
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
while(sz>0)
{
void* ptr=(void*)GetMemPtr(sa,4);
switch (smc_checks) {
case NoCheck:
break;
case FastCheck: {
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
if (sz==2)
x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
else
x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
x86e->Emit(op_jne,place);
x86e->Emit(op_cmp32, ptr, *(u32*)ptr);
x86e->Emit(op_jne, x86_ptr_imm(ngen_blockcheckfail));
}
sz-=4;
sa+=4;
}
break;
case FullCheck: {
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
while(sz>0)
{
void* ptr=(void*)GetMemPtr(sa,4);
if (ptr)
{
if (sz==2)
x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
else
x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
x86e->Emit(op_jne,x86_ptr_imm(ngen_blockcheckfail));
}
sz-=4;
sa+=4;
}
}
break;
default:
die("unhandled smc_checks");
}
}
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
{
//initialise stuff
DetectCpuFeatures();
@ -295,7 +303,7 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
//block invl. checks
x86e->Emit(op_mov32,ECX,block->addr);
CheckBlock(block,force_checks?x86_ptr_imm(ngen_blockcheckfail):x86_ptr_imm(ngen_blockcheckfail2));
CheckBlock(smc_checks, block);
//Scheduler
x86_Label* no_up=x86e->CreateLabel(false,8);

View File

@ -1015,11 +1015,11 @@ static void gui_display_settings()
ImGui::SameLine();
ShowHelpMarker("Skip wait loops. Recommended");
ImGui::PushItemWidth(ImGui::CalcTextSize("Largeenough").x);
const char *preview = settings.dynarec.SmcCheckLevel == NoCheck ? "None" : settings.dynarec.SmcCheckLevel == FastCheck ? "Fast" : "Full";
const char *preview = settings.dynarec.SmcCheckLevel == NoCheck ? "Faster" : settings.dynarec.SmcCheckLevel == FastCheck ? "Fast" : "Full";
if (ImGui::BeginCombo("SMC Checks", preview , ImGuiComboFlags_None))
{
bool is_selected = settings.dynarec.SmcCheckLevel == NoCheck;
if (ImGui::Selectable("None", &is_selected))
if (ImGui::Selectable("Faster", &is_selected))
settings.dynarec.SmcCheckLevel = NoCheck;
if (is_selected)
ImGui::SetItemDefaultFocus();