From af6993a81912d048aca53d9179843e19a42ffbee Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Mitsis Poiitidis Date: Sat, 30 Mar 2019 06:33:52 +0100 Subject: [PATCH] dynarec: Refactor smc-option a bit --- core/hw/sh4/dyna/blockmanager.cpp | 4 +- core/hw/sh4/dyna/driver.cpp | 62 ++++++++++------ core/hw/sh4/dyna/ngen.h | 2 +- core/hw/sh4/modules/ccn.cpp | 21 ++++-- core/rec-ARM/rec_arm.cpp | 21 ++++-- core/rec-ARM64/rec_arm64.cpp | 118 ++++++++++++++++-------------- core/rec-cpp/rec_cpp.cpp | 18 +++-- core/rec-x64/rec_x64.cpp | 108 ++++++++++++++------------- core/rec-x86/rec_x86_driver.cpp | 64 +++++++++------- core/rend/gui.cpp | 4 +- 10 files changed, 245 insertions(+), 177 deletions(-) diff --git a/core/hw/sh4/dyna/blockmanager.cpp b/core/hw/sh4/dyna/blockmanager.cpp index dd0a3b818..e64cd0d60 100644 --- a/core/hw/sh4/dyna/blockmanager.cpp +++ b/core/hw/sh4/dyna/blockmanager.cpp @@ -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]); diff --git a/core/hw/sh4/dyna/driver.cpp b/core/hw/sh4/dyna/driver.cpp index dcb74ec4c..8f66a4258 100644 --- a/core/hw/sh4/dyna/driver.cpp +++ b/core/hw/sh4/dyna/driver.cpp @@ -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); diff --git a/core/hw/sh4/dyna/ngen.h b/core/hw/sh4/dyna/ngen.h index 0e7d9cd3b..e7d2aff35 100644 --- a/core/hw/sh4/dyna/ngen.h +++ b/core/hw/sh4/dyna/ngen.h @@ -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(); diff --git a/core/hw/sh4/modules/ccn.cpp b/core/hw/sh4/modules/ccn.cpp index 49b7c574f..99d694c8d 100644 --- a/core/hw/sh4/modules/ccn.cpp +++ b/core/hw/sh4/modules/ccn.cpp @@ -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; diff --git a/core/rec-ARM/rec_arm.cpp b/core/rec-ARM/rec_arm.cpp index 9fdf8ea58..78f8f9249 100644 --- a/core/rec-ARM/rec_arm.cpp +++ b/core/rec-ARM/rec_arm.cpp @@ -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; diff --git a/core/rec-ARM64/rec_arm64.cpp b/core/rec-ARM64/rec_arm64.cpp index a4b7803fb..b30720796 100644 --- a/core/rec-ARM64/rec_arm64.cpp +++ b/core/rec-ARM64/rec_arm64.cpp @@ -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() - 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(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(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(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(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; diff --git a/core/rec-cpp/rec_cpp.cpp b/core/rec-cpp/rec_cpp.cpp index a3d155679..caa403bdd 100644 --- a/core/rec-cpp/rec_cpp.cpp +++ b/core/rec-cpp/rec_cpp.cpp @@ -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; } diff --git a/core/rec-x64/rec_x64.cpp b/core/rec-x64/rec_x64.cpp index 286fefc82..f3a23bdc3 100644 --- a/core/rec-x64/rec_x64.cpp +++ b/core/rec-x64/rec_x64.cpp @@ -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(ptr)); - mov(edx, *(u32*)ptr); - cmp(dword[rax], edx); - jne(reinterpret_cast(&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(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(&ngen_blockcheckfail)); + mov(edx, *(u32*)ptr); + cmp(dword[rax], edx); + jne(reinterpret_cast(&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(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(&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; } diff --git a/core/rec-x86/rec_x86_driver.cpp b/core/rec-x86/rec_x86_driver.cpp index e95cd9494..1d19a46fa 100644 --- a/core/rec-x86/rec_x86_driver.cpp +++ b/core/rec-x86/rec_x86_driver.cpp @@ -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); diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 8514ddd31..27e676307 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -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();