| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
| #include "../../HW/Memmap.h" | ||
|
|
||
| #include "../PowerPC.h" | ||
| #include "../../CoreTiming.h" | ||
| #include "MemoryUtil.h" | ||
|
|
||
| #include "JitIL.h" | ||
| #include "../JitCommon/JitCache.h" | ||
|
|
||
| #include "../../HW/GPFifo.h" | ||
| #include "../../Core.h" | ||
|
|
||
| #include "JitILAsm.h" | ||
| #include "ArmEmitter.h" | ||
|
|
||
| JitArmILAsmRoutineManager armil_asm_routines; | ||
| void JitArmILAsmRoutineManager::Generate() | ||
| { | ||
| enterCode = GetCodePtr(); | ||
| PUSH(9, R4, R5, R6, R7, R8, R9, R10, R11, _LR); | ||
| // Take care to 8-byte align stack for function calls. | ||
| // We are misaligned here because of an odd number of args for PUSH. | ||
| // It's not like x86 where you need to account for an extra 4 bytes | ||
| // consumed by CALL. | ||
| SUB(_SP, _SP, 4); | ||
|
|
||
| MOVI2R(R0, (u32)&CoreTiming::downcount); | ||
| MOVI2R(R9, (u32)&PowerPC::ppcState.spr[0]); | ||
|
|
||
| FixupBranch skipToRealDispatcher = B(); | ||
| dispatcher = GetCodePtr(); | ||
| printf("ILDispatcher is %p\n", dispatcher); | ||
|
|
||
| // Downcount Check | ||
| // The result of slice decrementation should be in flags if somebody jumped here | ||
| // IMPORTANT - We jump on negative, not carry!!! | ||
| FixupBranch bail = B_CC(CC_MI); | ||
|
|
||
| SetJumpTarget(skipToRealDispatcher); | ||
| dispatcherNoCheck = GetCodePtr(); | ||
|
|
||
| // This block of code gets the address of the compiled block of code | ||
| // It runs though to the compiling portion if it isn't found | ||
| LDR(R12, R9, PPCSTATE_OFF(pc));// Load the current PC into R12 | ||
|
|
||
| Operand2 iCacheMask = Operand2(0xE, 2); // JIT_ICACHE_MASK | ||
| BIC(R12, R12, iCacheMask); // R12 contains PC & JIT_ICACHE_MASK here. | ||
|
|
||
| MOVI2R(R14, (u32)jit->GetBlockCache()->iCache); | ||
|
|
||
| LDR(R12, R14, R12); // R12 contains iCache[PC & JIT_ICACHE_MASK] here | ||
| // R12 Confirmed this is the correct iCache Location loaded. | ||
| TST(R12, 0x80); // Test to see if it is a JIT block. | ||
|
|
||
| SetCC(CC_EQ); | ||
| // Success, it is our Jitblock. | ||
| MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers()); | ||
| // LDR R14 right here to get CodePointers()[0] pointer. | ||
| LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size | ||
| LDR(R14, R14, R12); // Load the block address in to R14 | ||
|
|
||
| B(R14); | ||
| // No need to jump anywhere after here, the block will go back to dispatcher start | ||
| SetCC(); | ||
|
|
||
| // If we get to this point, that means that we don't have the block cached to execute | ||
| // So call ArmJit to compile the block and then execute it. | ||
| MOVI2R(R14, (u32)&Jit); | ||
| BL(R14); | ||
|
|
||
| B(dispatcherNoCheck); | ||
|
|
||
| // fpException() | ||
| // Floating Point Exception Check, Jumped to if false | ||
| fpException = GetCodePtr(); | ||
| LDR(R0, R9, PPCSTATE_OFF(Exceptions)); | ||
| ORR(R0, R0, EXCEPTION_FPU_UNAVAILABLE); | ||
| STR(R0, R9, PPCSTATE_OFF(Exceptions)); | ||
| QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions); | ||
| LDR(R0, R9, PPCSTATE_OFF(npc)); | ||
| STR(R0, R9, PPCSTATE_OFF(pc)); | ||
| B(dispatcher); | ||
|
|
||
| SetJumpTarget(bail); | ||
| doTiming = GetCodePtr(); | ||
| // XXX: In JIT64, Advance() gets called /after/ the exception checking | ||
| // once it jumps back to the start of outerLoop | ||
| QuickCallFunction(R14, (void*)&CoreTiming::Advance); | ||
|
|
||
| // Does exception checking | ||
| testExceptions = GetCodePtr(); | ||
| LDR(R0, R9, PPCSTATE_OFF(pc)); | ||
| STR(R0, R9, PPCSTATE_OFF(npc)); | ||
| QuickCallFunction(R14, (void*)&PowerPC::CheckExceptions); | ||
| LDR(R0, R9, PPCSTATE_OFF(npc)); | ||
| STR(R0, R9, PPCSTATE_OFF(pc)); | ||
| // Check the state pointer to see if we are exiting | ||
| // Gets checked on every exception check | ||
| MOVI2R(R0, (u32)PowerPC::GetStatePtr()); | ||
| MVN(R1, 0); | ||
| LDR(R0, R0); | ||
| TST(R0, R1); | ||
| FixupBranch Exit = B_CC(CC_NEQ); | ||
|
|
||
| B(dispatcher); | ||
|
|
||
| SetJumpTarget(Exit); | ||
|
|
||
| ADD(_SP, _SP, 4); | ||
|
|
||
| POP(9, R4, R5, R6, R7, R8, R9, R10, R11, _PC); // Returns | ||
|
|
||
| GenerateCommon(); | ||
|
|
||
| FlushIcache(); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #ifndef _JITARMILASM_H | ||
| #define _JITARMILASM_H | ||
| #include "ArmEmitter.h" | ||
| #include "../JitCommon/JitAsmCommon.h" | ||
| using namespace ArmGen; | ||
| class JitArmILAsmRoutineManager : public CommonAsmRoutinesBase, public ARMXCodeBlock | ||
| { | ||
| private: | ||
| void Generate(); | ||
| void GenerateCommon() {} | ||
|
|
||
| public: | ||
| void Init() { | ||
| AllocCodeSpace(8192); | ||
| Generate(); | ||
| WriteProtect(); | ||
| } | ||
|
|
||
| void Shutdown() { | ||
| FreeCodeSpace(); | ||
| } | ||
| }; | ||
|
|
||
| extern JitArmILAsmRoutineManager armil_asm_routines; | ||
|
|
||
| #endif | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
|
|
||
| #include "../../ConfigManager.h" | ||
| #include "../PowerPC.h" | ||
| #include "../PPCTables.h" | ||
|
|
||
| #include "JitIL.h" | ||
|
|
||
| #include "../../HW/Memmap.h" | ||
|
|
||
| #define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return; | ||
| //#define NORMALBRANCH_START | ||
|
|
||
| void JitArmIL::bx(UGeckoInstruction inst) | ||
| { | ||
| //NORMALBRANCH_START | ||
| INSTRUCTION_START; | ||
|
|
||
| // We must always process the following sentence | ||
| // even if the blocks are merged by PPCAnalyst::Flatten(). | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| // If this is not the last instruction of a block, | ||
| // we will skip the rest process. | ||
| // Because PPCAnalyst::Flatten() merged the blocks. | ||
| if (!js.isLastInstruction) { | ||
| return; | ||
| } | ||
|
|
||
| u32 destination; | ||
| if (inst.AA) | ||
| destination = SignExt26(inst.LI << 2); | ||
| else | ||
| destination = js.compilerPC + SignExt26(inst.LI << 2); | ||
|
|
||
| if (destination == js.compilerPC) { | ||
| ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC)); | ||
| return; | ||
| } | ||
|
|
||
| ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination)); | ||
| } | ||
| static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) { | ||
| IREmitter::InstLoc CRTest = 0, CTRTest = 0; | ||
| if ((inst.BO & 16) == 0) // Test a CR bit | ||
| { | ||
| IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2); | ||
| IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3)); | ||
| CRTest = ibuild.EmitAnd(CRReg, CRCmp); | ||
| if (!(inst.BO & 8)) | ||
| CRTest = ibuild.EmitXor(CRCmp, CRTest); | ||
| } | ||
|
|
||
| if ((inst.BO & 4) == 0) { | ||
| IREmitter::InstLoc c = ibuild.EmitLoadCTR(); | ||
| c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); | ||
| ibuild.EmitStoreCTR(c); | ||
| if (inst.BO & 2) { | ||
| CTRTest = ibuild.EmitICmpEq(c, | ||
| ibuild.EmitIntConst(0)); | ||
| } else { | ||
| CTRTest = c; | ||
| } | ||
| } | ||
|
|
||
| IREmitter::InstLoc Test = CRTest; | ||
| if (CTRTest) { | ||
| if (Test) | ||
| Test = ibuild.EmitAnd(Test, CTRTest); | ||
| else | ||
| Test = CTRTest; | ||
| } | ||
|
|
||
| if (!Test) { | ||
| Test = ibuild.EmitIntConst(1); | ||
| } | ||
| return Test; | ||
| } | ||
|
|
||
| void JitArmIL::bclrx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
|
|
||
| if (!js.isLastInstruction && | ||
| (inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) { | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| return; | ||
| } | ||
|
|
||
| if (inst.hex == 0x4e800020) { | ||
| ibuild.EmitBranchUncond(ibuild.EmitLoadLink()); | ||
| return; | ||
| } | ||
| IREmitter::InstLoc test = TestBranch(ibuild, inst); | ||
| test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); | ||
| ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| IREmitter::InstLoc destination = ibuild.EmitLoadLink(); | ||
| destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| ibuild.EmitBranchUncond(destination); | ||
| } | ||
| void JitArmIL::bcx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink( | ||
| ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| IREmitter::InstLoc Test = TestBranch(ibuild, inst); | ||
|
|
||
| u32 destination; | ||
| if(inst.AA) | ||
| destination = SignExt16(inst.BD << 2); | ||
| else | ||
| destination = js.compilerPC + SignExt16(inst.BD << 2); | ||
|
|
||
| if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle && | ||
| inst.hex == 0x4182fff8 && | ||
| (Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 && | ||
| (Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 || | ||
| (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000)) | ||
| ) | ||
| { | ||
| ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination)); | ||
| } | ||
| else | ||
| { | ||
| ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination)); | ||
| } | ||
| ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| } | ||
|
|
||
| void JitArmIL::bcctrx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
| if ((inst.BO & 4) == 0) { | ||
| IREmitter::InstLoc c = ibuild.EmitLoadCTR(); | ||
| c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); | ||
| ibuild.EmitStoreCTR(c); | ||
| } | ||
| IREmitter::InstLoc test; | ||
| if ((inst.BO & 16) == 0) // Test a CR bit | ||
| { | ||
| IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2); | ||
| IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3)); | ||
| test = ibuild.EmitAnd(CRReg, CRCmp); | ||
| if (!(inst.BO & 8)) | ||
| test = ibuild.EmitXor(test, CRCmp); | ||
| } else { | ||
| test = ibuild.EmitIntConst(1); | ||
| } | ||
| test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); | ||
| ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| IREmitter::InstLoc destination = ibuild.EmitLoadCTR(); | ||
| destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| ibuild.EmitBranchUncond(destination); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #ifndef JITARMIL_TABLES_H | ||
| #define JITARMIL_TABLES_H | ||
|
|
||
| #include "../Gekko.h" | ||
| #include "../PPCTables.h" | ||
|
|
||
| namespace JitArmILTables | ||
| { | ||
| void CompileInstruction(PPCAnalyst::CodeOp & op); | ||
| void InitTables(); | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #ifndef _JITILBASE_H | ||
| #define _JITILBASE_H | ||
|
|
||
| #include "IR.h" | ||
| #include "../PowerPC.h" | ||
| #include "../PPCAnalyst.h" | ||
| #include "../PPCTables.h" | ||
| #include "../JitCommon/JitBase.h" | ||
| #include "../../ConfigManager.h" | ||
| #include "../../Core.h" | ||
| #include "../../CoreTiming.h" | ||
| #include "../../HW/GPFifo.h" | ||
| #include "../../HW/Memmap.h" | ||
|
|
||
| #define INSTRUCTION_START | ||
|
|
||
| #define JITDISABLE(setting) \ | ||
| if (Core::g_CoreStartupParameter.bJITOff || \ | ||
| Core::g_CoreStartupParameter.setting) \ | ||
| {Default(inst); return;} | ||
|
|
||
| class JitILBase : public JitBase | ||
| { | ||
| protected: | ||
| // The default code buffer. We keep it around to not have to alloc/dealloc a | ||
| // large chunk of memory for each recompiled block. | ||
| PPCAnalyst::CodeBuffer code_buffer; | ||
| public: | ||
| JitILBase() : code_buffer(32000) {} | ||
| ~JitILBase() {} | ||
|
|
||
| IREmitter::IRBuilder ibuild; | ||
|
|
||
| virtual JitBaseBlockCache *GetBlockCache() = 0; | ||
|
|
||
| virtual void Jit(u32 em_address) = 0; | ||
|
|
||
| virtual const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) = 0; | ||
|
|
||
| virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0; | ||
|
|
||
| virtual bool IsInCodeSpace(u8 *ptr) = 0; | ||
|
|
||
| // OPCODES | ||
| virtual void unknown_instruction(UGeckoInstruction inst) = 0; | ||
| virtual void Default(UGeckoInstruction inst) = 0; | ||
| virtual void DoNothing(UGeckoInstruction inst) = 0; | ||
| virtual void HLEFunction(UGeckoInstruction inst) = 0; | ||
|
|
||
| virtual void DynaRunTable4(UGeckoInstruction _inst) = 0; | ||
| virtual void DynaRunTable19(UGeckoInstruction _inst) = 0; | ||
| virtual void DynaRunTable31(UGeckoInstruction _inst) = 0; | ||
| virtual void DynaRunTable59(UGeckoInstruction _inst) = 0; | ||
| virtual void DynaRunTable63(UGeckoInstruction _inst) = 0; | ||
|
|
||
| // Branches | ||
| void sc(UGeckoInstruction inst); | ||
| void rfi(UGeckoInstruction inst); | ||
| void bx(UGeckoInstruction inst); | ||
| void bcx(UGeckoInstruction inst); | ||
| void bcctrx(UGeckoInstruction inst); | ||
| void bclrx(UGeckoInstruction inst); | ||
|
|
||
| // LoadStore | ||
| void lXzx(UGeckoInstruction inst); | ||
| void lhax(UGeckoInstruction inst); | ||
| void stXx(UGeckoInstruction inst); | ||
| void lmw(UGeckoInstruction inst); | ||
| void stmw(UGeckoInstruction inst); | ||
| void stX(UGeckoInstruction inst); //stw sth stb | ||
| void lXz(UGeckoInstruction inst); | ||
| void lbzu(UGeckoInstruction inst); | ||
| void lha(UGeckoInstruction inst); | ||
|
|
||
| // System Registers | ||
| void mtspr(UGeckoInstruction inst); | ||
| void mfspr(UGeckoInstruction inst); | ||
| void mtmsr(UGeckoInstruction inst); | ||
| void mfmsr(UGeckoInstruction inst); | ||
| void mftb(UGeckoInstruction inst); | ||
| void mtcrf(UGeckoInstruction inst); | ||
| void mfcr(UGeckoInstruction inst); | ||
| void mcrf(UGeckoInstruction inst); | ||
| void crXX(UGeckoInstruction inst); | ||
|
|
||
| void dcbst(UGeckoInstruction inst); | ||
| void dcbz(UGeckoInstruction inst); | ||
| void icbi(UGeckoInstruction inst); | ||
|
|
||
| void addx(UGeckoInstruction inst); | ||
| void boolX(UGeckoInstruction inst); | ||
| void mulli(UGeckoInstruction inst); | ||
| void mulhwux(UGeckoInstruction inst); | ||
| void mullwx(UGeckoInstruction inst); | ||
| void divwux(UGeckoInstruction inst); | ||
| void srawix(UGeckoInstruction inst); | ||
| void srawx(UGeckoInstruction inst); | ||
| void addex(UGeckoInstruction inst); | ||
| void addzex(UGeckoInstruction inst); | ||
|
|
||
| void extsbx(UGeckoInstruction inst); | ||
| void extshx(UGeckoInstruction inst); | ||
|
|
||
| void reg_imm(UGeckoInstruction inst); | ||
|
|
||
| void ps_sel(UGeckoInstruction inst); | ||
| void ps_mr(UGeckoInstruction inst); | ||
| void ps_sign(UGeckoInstruction inst); //aggregate | ||
| void ps_arith(UGeckoInstruction inst); //aggregate | ||
| void ps_mergeXX(UGeckoInstruction inst); | ||
| void ps_maddXX(UGeckoInstruction inst); | ||
| void ps_rsqrte(UGeckoInstruction inst); | ||
| void ps_sum(UGeckoInstruction inst); | ||
| void ps_muls(UGeckoInstruction inst); | ||
|
|
||
| void fp_arith_s(UGeckoInstruction inst); | ||
|
|
||
| void fcmpx(UGeckoInstruction inst); | ||
| void fmrx(UGeckoInstruction inst); | ||
|
|
||
| void cmpXX(UGeckoInstruction inst); | ||
|
|
||
| void cntlzwx(UGeckoInstruction inst); | ||
|
|
||
| void lfs(UGeckoInstruction inst); | ||
| void lfd(UGeckoInstruction inst); | ||
| void stfd(UGeckoInstruction inst); | ||
| void stfs(UGeckoInstruction inst); | ||
| void stfsx(UGeckoInstruction inst); | ||
| void psq_l(UGeckoInstruction inst); | ||
| void psq_st(UGeckoInstruction inst); | ||
|
|
||
| void fmaddXX(UGeckoInstruction inst); | ||
| void fsign(UGeckoInstruction inst); | ||
| void rlwinmx(UGeckoInstruction inst); | ||
| void rlwimix(UGeckoInstruction inst); | ||
| void rlwnmx(UGeckoInstruction inst); | ||
| void negx(UGeckoInstruction inst); | ||
| void slwx(UGeckoInstruction inst); | ||
| void srwx(UGeckoInstruction inst); | ||
| void lfsx(UGeckoInstruction inst); | ||
|
|
||
| void subfic(UGeckoInstruction inst); | ||
| void subfcx(UGeckoInstruction inst); | ||
| void subfx(UGeckoInstruction inst); | ||
| void subfex(UGeckoInstruction inst); | ||
|
|
||
| }; | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
|
|
||
| // The branches are known good, or at least reasonably good. | ||
| // No need for a disable-mechanism. | ||
|
|
||
| // If defined, clears CR0 at blr and bl-s. If the assumption that | ||
| // flags never carry over between functions holds, then the task for | ||
| // an optimizer becomes much easier. | ||
|
|
||
| // #define ACID_TEST | ||
|
|
||
| // Zelda and many more games seem to pass the Acid Test. | ||
|
|
||
| //#define NORMALBRANCH_START Default(inst); ibuild.EmitInterpreterBranch(); return; | ||
| #define NORMALBRANCH_START | ||
|
|
||
| void JitILBase::sc(UGeckoInstruction inst) | ||
| { | ||
| ibuild.EmitSystemCall(ibuild.EmitIntConst(js.compilerPC)); | ||
| } | ||
|
|
||
| void JitILBase::rfi(UGeckoInstruction inst) | ||
| { | ||
| ibuild.EmitRFIExit(); | ||
| } | ||
|
|
||
| void JitILBase::bx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
| INSTRUCTION_START; | ||
|
|
||
| // We must always process the following sentence | ||
| // even if the blocks are merged by PPCAnalyst::Flatten(). | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| // If this is not the last instruction of a block, | ||
| // we will skip the rest process. | ||
| // Because PPCAnalyst::Flatten() merged the blocks. | ||
| if (!js.isLastInstruction) { | ||
| return; | ||
| } | ||
|
|
||
| u32 destination; | ||
| if (inst.AA) | ||
| destination = SignExt26(inst.LI << 2); | ||
| else | ||
| destination = js.compilerPC + SignExt26(inst.LI << 2); | ||
|
|
||
| if (destination == js.compilerPC) { | ||
| ibuild.EmitShortIdleLoop(ibuild.EmitIntConst(js.compilerPC)); | ||
| return; | ||
| } | ||
|
|
||
| ibuild.EmitBranchUncond(ibuild.EmitIntConst(destination)); | ||
| } | ||
|
|
||
| static IREmitter::InstLoc TestBranch(IREmitter::IRBuilder& ibuild, UGeckoInstruction inst) { | ||
| IREmitter::InstLoc CRTest = 0, CTRTest = 0; | ||
| if ((inst.BO & 16) == 0) // Test a CR bit | ||
| { | ||
| IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2); | ||
| IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3)); | ||
| CRTest = ibuild.EmitAnd(CRReg, CRCmp); | ||
| if (!(inst.BO & 8)) | ||
| CRTest = ibuild.EmitXor(CRCmp, CRTest); | ||
| } | ||
|
|
||
| if ((inst.BO & 4) == 0) { | ||
| IREmitter::InstLoc c = ibuild.EmitLoadCTR(); | ||
| c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); | ||
| ibuild.EmitStoreCTR(c); | ||
| if (inst.BO & 2) { | ||
| CTRTest = ibuild.EmitICmpEq(c, | ||
| ibuild.EmitIntConst(0)); | ||
| } else { | ||
| CTRTest = c; | ||
| } | ||
| } | ||
|
|
||
| IREmitter::InstLoc Test = CRTest; | ||
| if (CTRTest) { | ||
| if (Test) | ||
| Test = ibuild.EmitAnd(Test, CTRTest); | ||
| else | ||
| Test = CTRTest; | ||
| } | ||
|
|
||
| if (!Test) { | ||
| Test = ibuild.EmitIntConst(1); | ||
| } | ||
| return Test; | ||
| } | ||
|
|
||
| void JitILBase::bcx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink( | ||
| ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| IREmitter::InstLoc Test = TestBranch(ibuild, inst); | ||
|
|
||
| u32 destination; | ||
| if(inst.AA) | ||
| destination = SignExt16(inst.BD << 2); | ||
| else | ||
| destination = js.compilerPC + SignExt16(inst.BD << 2); | ||
|
|
||
| if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle && | ||
| inst.hex == 0x4182fff8 && | ||
| (Memory::ReadUnchecked_U32(js.compilerPC - 8) & 0xFFFF0000) == 0x800D0000 && | ||
| (Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x28000000 || | ||
| (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC - 4) == 0x2C000000)) | ||
| ) | ||
| { | ||
| ibuild.EmitIdleBranch(Test, ibuild.EmitIntConst(destination)); | ||
| } | ||
| else | ||
| { | ||
| ibuild.EmitBranchCond(Test, ibuild.EmitIntConst(destination)); | ||
| } | ||
| ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| } | ||
|
|
||
| void JitILBase::bcctrx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
| if ((inst.BO & 4) == 0) { | ||
| IREmitter::InstLoc c = ibuild.EmitLoadCTR(); | ||
| c = ibuild.EmitSub(c, ibuild.EmitIntConst(1)); | ||
| ibuild.EmitStoreCTR(c); | ||
| } | ||
| IREmitter::InstLoc test; | ||
| if ((inst.BO & 16) == 0) // Test a CR bit | ||
| { | ||
| IREmitter::InstLoc CRReg = ibuild.EmitLoadCR(inst.BI >> 2); | ||
| IREmitter::InstLoc CRCmp = ibuild.EmitIntConst(8 >> (inst.BI & 3)); | ||
| test = ibuild.EmitAnd(CRReg, CRCmp); | ||
| if (!(inst.BO & 8)) | ||
| test = ibuild.EmitXor(test, CRCmp); | ||
| } else { | ||
| test = ibuild.EmitIntConst(1); | ||
| } | ||
| test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); | ||
| ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| IREmitter::InstLoc destination = ibuild.EmitLoadCTR(); | ||
| destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| ibuild.EmitBranchUncond(destination); | ||
| } | ||
|
|
||
| void JitILBase::bclrx(UGeckoInstruction inst) | ||
| { | ||
| NORMALBRANCH_START | ||
|
|
||
| if (!js.isLastInstruction && | ||
| (inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) { | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| return; | ||
| } | ||
|
|
||
| if (inst.hex == 0x4e800020) { | ||
| ibuild.EmitBranchUncond(ibuild.EmitLoadLink()); | ||
| return; | ||
| } | ||
| IREmitter::InstLoc test = TestBranch(ibuild, inst); | ||
| test = ibuild.EmitICmpEq(test, ibuild.EmitIntConst(0)); | ||
| ibuild.EmitBranchCond(test, ibuild.EmitIntConst(js.compilerPC + 4)); | ||
|
|
||
| IREmitter::InstLoc destination = ibuild.EmitLoadLink(); | ||
| destination = ibuild.EmitAnd(destination, ibuild.EmitIntConst(-4)); | ||
| if (inst.LK) | ||
| ibuild.EmitStoreLink(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| ibuild.EmitBranchUncond(destination); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
| void JitILBase::fp_arith_s(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITFloatingPointOff) | ||
| if (inst.Rc || (inst.SUBOP5 != 25 && inst.SUBOP5 != 20 && | ||
| inst.SUBOP5 != 21 && inst.SUBOP5 != 26)) { | ||
| Default(inst); return; | ||
| } | ||
| // Only the interpreter has "proper" support for (some) FP flags | ||
| if (inst.SUBOP5 == 25 && Core::g_CoreStartupParameter.bEnableFPRF) { | ||
| Default(inst); return; | ||
| } | ||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); | ||
| switch (inst.SUBOP5) | ||
| { | ||
| case 20: //sub | ||
| val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB)); | ||
| break; | ||
| case 21: //add | ||
| val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB)); | ||
| break; | ||
| case 25: //mul | ||
| val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC)); | ||
| break; | ||
| case 26: //rsqrte | ||
| val = ibuild.EmitLoadFReg(inst.FB); | ||
| val = ibuild.EmitDoubleToSingle(val); | ||
| val = ibuild.EmitFSRSqrt(val); | ||
| val = ibuild.EmitDupSingleToMReg(val); | ||
| break; | ||
| default: | ||
| _assert_msg_(DYNA_REC, 0, "fp_arith_s WTF!!!"); | ||
| } | ||
|
|
||
| if (inst.OPCD == 59) { | ||
| val = ibuild.EmitDoubleToSingle(val); | ||
| val = ibuild.EmitDupSingleToMReg(val); | ||
| } else { | ||
| val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); | ||
| } | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
| void JitILBase::fmaddXX(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITFloatingPointOff) | ||
| if (inst.Rc) { | ||
| Default(inst); return; | ||
| } | ||
| // Only the interpreter has "proper" support for (some) FP flags | ||
| if (inst.SUBOP5 == 29 && Core::g_CoreStartupParameter.bEnableFPRF) { | ||
| Default(inst); return; | ||
| } | ||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA); | ||
| val = ibuild.EmitFDMul(val, ibuild.EmitLoadFReg(inst.FC)); | ||
| if (inst.SUBOP5 & 1) | ||
| val = ibuild.EmitFDAdd(val, ibuild.EmitLoadFReg(inst.FB)); | ||
| else | ||
| val = ibuild.EmitFDSub(val, ibuild.EmitLoadFReg(inst.FB)); | ||
| if (inst.SUBOP5 & 2) | ||
| val = ibuild.EmitFDNeg(val); | ||
| if (inst.OPCD == 59) { | ||
| val = ibuild.EmitDoubleToSingle(val); | ||
| val = ibuild.EmitDupSingleToMReg(val); | ||
| } else { | ||
| val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); | ||
| } | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
| void JitILBase::fmrx(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITFloatingPointOff) | ||
| if (inst.Rc) { | ||
| Default(inst); return; | ||
| } | ||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FB); | ||
| val = ibuild.EmitInsertDoubleInMReg(val, ibuild.EmitLoadFReg(inst.FD)); | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
| void JitILBase::fcmpx(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITFloatingPointOff) | ||
| IREmitter::InstLoc lhs, rhs, res; | ||
| lhs = ibuild.EmitLoadFReg(inst.FA); | ||
| rhs = ibuild.EmitLoadFReg(inst.FB); | ||
| int ordered = (inst.SUBOP10 == 32) ? 1 : 0; | ||
| res = ibuild.EmitFDCmpCR(lhs, rhs, ordered); | ||
| ibuild.EmitStoreFPRF(res); | ||
| ibuild.EmitStoreCR(res, inst.CRFD); | ||
| } | ||
|
|
||
| void JitILBase::fsign(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITFloatingPointOff) | ||
| Default(inst); | ||
| return; | ||
|
|
||
| // TODO | ||
| switch (inst.SUBOP10) { | ||
| case 40: // fnegx | ||
| break; | ||
| case 264: // fabsx | ||
| break; | ||
| case 136: // fnabs | ||
| break; | ||
| default: | ||
| PanicAlert("fsign bleh"); | ||
| break; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
| void JitILBase::lhax(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| IREmitter::InstLoc val = ibuild.EmitLoad16(addr); | ||
| val = ibuild.EmitSExt16(val); | ||
| ibuild.EmitStoreGReg(val, inst.RD); | ||
| } | ||
|
|
||
| void JitILBase::lXz(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.OPCD & 1) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| IREmitter::InstLoc val; | ||
| switch (inst.OPCD & ~0x1) | ||
| { | ||
| case 32: val = ibuild.EmitLoad32(addr); break; //lwz | ||
| case 40: val = ibuild.EmitLoad16(addr); break; //lhz | ||
| case 34: val = ibuild.EmitLoad8(addr); break; //lbz | ||
| default: PanicAlert("lXz: invalid access size"); val = 0; break; | ||
| } | ||
| ibuild.EmitStoreGReg(val, inst.RD); | ||
| } | ||
|
|
||
| void JitILBase::lbzu(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| const IREmitter::InstLoc uAddress = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), ibuild.EmitIntConst((int)inst.SIMM_16)); | ||
| const IREmitter::InstLoc temp = ibuild.EmitLoad8(uAddress); | ||
| ibuild.EmitStoreGReg(temp, inst.RD); | ||
| ibuild.EmitStoreGReg(uAddress, inst.RA); | ||
| } | ||
|
|
||
| void JitILBase::lha(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = | ||
| ibuild.EmitIntConst((s32)(s16)inst.SIMM_16); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| IREmitter::InstLoc val = ibuild.EmitLoad16(addr); | ||
| val = ibuild.EmitSExt16(val); | ||
| ibuild.EmitStoreGReg(val, inst.RD); | ||
| } | ||
|
|
||
| void JitILBase::lXzx(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB); | ||
|
|
||
| if (inst.RA) | ||
| { | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.SUBOP10 & 32) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| } | ||
|
|
||
| IREmitter::InstLoc val; | ||
| switch (inst.SUBOP10 & ~32) | ||
| { | ||
| default: PanicAlert("lXzx: invalid access size"); | ||
| case 23: val = ibuild.EmitLoad32(addr); break; //lwzx | ||
| case 279: val = ibuild.EmitLoad16(addr); break; //lhzx | ||
| case 87: val = ibuild.EmitLoad8(addr); break; //lbzx | ||
| } | ||
| ibuild.EmitStoreGReg(val, inst.RD); | ||
| } | ||
|
|
||
| void JitILBase::dcbst(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
|
|
||
| // If the dcbst instruction is preceded by dcbt, it is flushing a prefetched | ||
| // memory location. Do not invalidate the JIT cache in this case as the memory | ||
| // will be the same. | ||
| // dcbt = 0x7c00022c | ||
| if ((Memory::ReadUnchecked_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c) | ||
| { | ||
| Default(inst); return; | ||
| } | ||
| } | ||
|
|
||
| // Zero cache line. | ||
| void JitILBase::dcbz(UGeckoInstruction inst) | ||
| { | ||
| Default(inst); return; | ||
|
|
||
| // TODO! | ||
| #if 0 | ||
| if(Core::g_CoreStartupParameter.bJITOff || Core::g_CoreStartupParameter.bJITLoadStoreOff) | ||
| {Default(inst); return;} // turn off from debugger | ||
| INSTRUCTION_START; | ||
| MOV(32, R(EAX), gpr.R(inst.RB)); | ||
| if (inst.RA) | ||
| ADD(32, R(EAX), gpr.R(inst.RA)); | ||
| AND(32, R(EAX), Imm32(~31)); | ||
| XORPD(XMM0, R(XMM0)); | ||
| #ifdef _M_X64 | ||
| MOVAPS(MComplex(EBX, EAX, SCALE_1, 0), XMM0); | ||
| MOVAPS(MComplex(EBX, EAX, SCALE_1, 16), XMM0); | ||
| #else | ||
| AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); | ||
| MOVAPS(MDisp(EAX, (u32)Memory::base), XMM0); | ||
| MOVAPS(MDisp(EAX, (u32)Memory::base + 16), XMM0); | ||
| #endif | ||
| #endif | ||
| } | ||
|
|
||
| void JitILBase::stX(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), | ||
| value = ibuild.EmitLoadGReg(inst.RS); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), addr); | ||
| if (inst.OPCD & 1) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| switch (inst.OPCD & ~1) | ||
| { | ||
| case 36: ibuild.EmitStore32(value, addr); break; //stw | ||
| case 44: ibuild.EmitStore16(value, addr); break; //sth | ||
| case 38: ibuild.EmitStore8(value, addr); break; //stb | ||
| default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return; | ||
| } | ||
| } | ||
|
|
||
| void JitILBase::stXx(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), | ||
| value = ibuild.EmitLoadGReg(inst.RS); | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.SUBOP10 & 32) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| switch (inst.SUBOP10 & ~32) | ||
| { | ||
| case 151: ibuild.EmitStore32(value, addr); break; //stw | ||
| case 407: ibuild.EmitStore16(value, addr); break; //sth | ||
| case 215: ibuild.EmitStore8(value, addr); break; //stb | ||
| default: _assert_msg_(DYNA_REC, 0, "AWETKLJASDLKF"); return; | ||
| } | ||
| } | ||
|
|
||
| // A few games use these heavily in video codecs. (GFZP01 @ 0x80020E18) | ||
| void JitILBase::lmw(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| for (int i = inst.RD; i < 32; i++) | ||
| { | ||
| IREmitter::InstLoc val = ibuild.EmitLoad32(addr); | ||
| ibuild.EmitStoreGReg(val, i); | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4)); | ||
| } | ||
| } | ||
|
|
||
| void JitILBase::stmw(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| for (int i = inst.RD; i < 32; i++) | ||
| { | ||
| IREmitter::InstLoc val = ibuild.EmitLoadGReg(i); | ||
| ibuild.EmitStore32(val, addr); | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4)); | ||
| } | ||
| } | ||
|
|
||
| void JitILBase::icbi(UGeckoInstruction inst) | ||
| { | ||
| Default(inst); | ||
| ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
| // TODO: Add peephole optimizations for multiple consecutive lfd/lfs/stfd/stfs since they are so common, | ||
| // and pshufb could help a lot. | ||
| // Also add hacks for things like lfs/stfs the same reg consecutively, that is, simple memory moves. | ||
|
|
||
| void JitILBase::lfs(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreFloatingOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val; | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); | ||
| ibuild.EmitStoreFReg(val, inst.RD); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::lfd(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreFloatingOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), val; | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| val = ibuild.EmitLoadFReg(inst.RD); | ||
| val = ibuild.EmitInsertDoubleInMReg(ibuild.EmitLoadDouble(addr), val); | ||
| ibuild.EmitStoreFReg(val, inst.RD); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::stfd(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreFloatingOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), | ||
| val = ibuild.EmitLoadFReg(inst.RS); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.OPCD & 1) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| ibuild.EmitStoreDouble(val, addr); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::stfs(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreFloatingOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_16), | ||
| val = ibuild.EmitLoadFReg(inst.RS); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.OPCD & 1) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| val = ibuild.EmitDoubleToSingle(val); | ||
| ibuild.EmitStoreSingle(val, addr); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::stfsx(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreFloatingOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), | ||
| val = ibuild.EmitLoadFReg(inst.RS); | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| val = ibuild.EmitDoubleToSingle(val); | ||
| ibuild.EmitStoreSingle(val, addr); | ||
| return; | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::lfsx(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStoreFloatingOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| IREmitter::InstLoc addr = ibuild.EmitLoadGReg(inst.RB), val; | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| val = ibuild.EmitDupSingleToMReg(ibuild.EmitLoadSingle(addr)); | ||
| ibuild.EmitStoreFReg(val, inst.RD); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
| void JitILBase::psq_st(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStorePairedOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| if (inst.W) {Default(inst); return;} | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val; | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.OPCD == 61) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| val = ibuild.EmitLoadFReg(inst.RS); | ||
| val = ibuild.EmitCompactMRegToPacked(val); | ||
| ibuild.EmitStorePaired(val, addr, inst.I); | ||
| } | ||
|
|
||
| void JitILBase::psq_l(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITLoadStorePairedOff) | ||
| if (js.memcheck) { Default(inst); return; } | ||
| if (inst.W) {Default(inst); return;} | ||
| IREmitter::InstLoc addr = ibuild.EmitIntConst(inst.SIMM_12), val; | ||
| if (inst.RA) | ||
| addr = ibuild.EmitAdd(addr, ibuild.EmitLoadGReg(inst.RA)); | ||
| if (inst.OPCD == 57) | ||
| ibuild.EmitStoreGReg(addr, inst.RA); | ||
| val = ibuild.EmitLoadPaired(addr, inst.I | (inst.W << 3)); // The lower 3 bits is for GQR index. The next 1 bit is for inst.W | ||
| val = ibuild.EmitExpandPackedToMReg(val); | ||
| ibuild.EmitStoreFReg(val, inst.RD); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
| void JitILBase::ps_mr(UGeckoInstruction inst) | ||
| { | ||
| Default(inst); return; | ||
| } | ||
|
|
||
| void JitILBase::ps_sel(UGeckoInstruction inst) | ||
| { | ||
| Default(inst); return; | ||
| } | ||
|
|
||
| void JitILBase::ps_sign(UGeckoInstruction inst) | ||
| { | ||
| Default(inst); return; | ||
| } | ||
|
|
||
| void JitILBase::ps_rsqrte(UGeckoInstruction inst) | ||
| { | ||
| Default(inst); return; | ||
| } | ||
|
|
||
| void JitILBase::ps_arith(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITPairedOff) | ||
| if (inst.Rc || (inst.SUBOP5 != 21 && inst.SUBOP5 != 20 && inst.SUBOP5 != 25)) { | ||
| Default(inst); return; | ||
| } | ||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), rhs; | ||
| if (inst.SUBOP5 == 25) | ||
| rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| else | ||
| rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitCompactMRegToPacked(val); | ||
|
|
||
| switch (inst.SUBOP5) | ||
| { | ||
| case 20: | ||
| val = ibuild.EmitFPSub(val, rhs); | ||
| break; | ||
| case 21: | ||
| val = ibuild.EmitFPAdd(val, rhs); | ||
| break; | ||
| case 25: | ||
| val = ibuild.EmitFPMul(val, rhs); | ||
| } | ||
| val = ibuild.EmitExpandPackedToMReg(val); | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
| void JitILBase::ps_sum(UGeckoInstruction inst) | ||
| { | ||
| // TODO: This operation strikes me as a bit strange... | ||
| // perhaps we can optimize it depending on the users? | ||
| // TODO: ps_sum breaks Sonic Colours (black screen) | ||
| Default(inst); return; | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITPairedOff) | ||
| if (inst.Rc || inst.SUBOP5 != 10) { | ||
| Default(inst); return; | ||
| } | ||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), temp; | ||
| val = ibuild.EmitCompactMRegToPacked(val); | ||
| val = ibuild.EmitFPDup0(val); | ||
| temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPAdd(val, temp); | ||
| temp = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| val = ibuild.EmitFPMerge11(val, temp); | ||
| val = ibuild.EmitExpandPackedToMReg(val); | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::ps_muls(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITPairedOff) | ||
| if (inst.Rc) { | ||
| Default(inst); return; | ||
| } | ||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), | ||
| rhs = ibuild.EmitLoadFReg(inst.FC); | ||
|
|
||
| val = ibuild.EmitCompactMRegToPacked(val); | ||
| rhs = ibuild.EmitCompactMRegToPacked(rhs); | ||
|
|
||
| if (inst.SUBOP5 == 12) | ||
| rhs = ibuild.EmitFPDup0(rhs); | ||
| else | ||
| rhs = ibuild.EmitFPDup1(rhs); | ||
|
|
||
| val = ibuild.EmitFPMul(val, rhs); | ||
| val = ibuild.EmitExpandPackedToMReg(val); | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
|
|
||
| //TODO: find easy cases and optimize them, do a breakout like ps_arith | ||
| void JitILBase::ps_mergeXX(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITPairedOff) | ||
| if (inst.Rc) { | ||
| Default(inst); return; | ||
| } | ||
|
|
||
| IREmitter::InstLoc val = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FA)), | ||
| rhs = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
|
|
||
| switch (inst.SUBOP10) | ||
| { | ||
| case 528: | ||
| val = ibuild.EmitFPMerge00(val, rhs); | ||
| break; //00 | ||
| case 560: | ||
| val = ibuild.EmitFPMerge01(val, rhs); | ||
| break; //01 | ||
| case 592: | ||
| val = ibuild.EmitFPMerge10(val, rhs); | ||
| break; //10 | ||
| case 624: | ||
| val = ibuild.EmitFPMerge11(val, rhs); | ||
| break; //11 | ||
| default: | ||
| _assert_msg_(DYNA_REC, 0, "ps_merge - invalid op"); | ||
| } | ||
| val = ibuild.EmitExpandPackedToMReg(val); | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } | ||
|
|
||
|
|
||
| void JitILBase::ps_maddXX(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITPairedOff) | ||
| if (inst.Rc) { | ||
| Default(inst); return; | ||
| } | ||
|
|
||
| IREmitter::InstLoc val = ibuild.EmitLoadFReg(inst.FA), op2, op3; | ||
| val = ibuild.EmitCompactMRegToPacked(val); | ||
| switch (inst.SUBOP5) | ||
| { | ||
| case 14: {//madds0 | ||
| op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| op2 = ibuild.EmitFPDup0(op2); | ||
| val = ibuild.EmitFPMul(val, op2); | ||
| op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPAdd(val, op3); | ||
| break; | ||
| } | ||
| case 15: {//madds1 | ||
| op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| op2 = ibuild.EmitFPDup1(op2); | ||
| val = ibuild.EmitFPMul(val, op2); | ||
| op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPAdd(val, op3); | ||
| break; | ||
| } | ||
| case 28: {//msub | ||
| op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| val = ibuild.EmitFPMul(val, op2); | ||
| op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPSub(val, op3); | ||
| break; | ||
| } | ||
| case 29: {//madd | ||
| op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| val = ibuild.EmitFPMul(val, op2); | ||
| op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPAdd(val, op3); | ||
| break; | ||
| } | ||
| case 30: {//nmsub | ||
| op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| val = ibuild.EmitFPMul(val, op2); | ||
| op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPSub(val, op3); | ||
| val = ibuild.EmitFPNeg(val); | ||
| break; | ||
| } | ||
| case 31: {//nmadd | ||
| op2 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FC)); | ||
| val = ibuild.EmitFPMul(val, op2); | ||
| op3 = ibuild.EmitCompactMRegToPacked(ibuild.EmitLoadFReg(inst.FB)); | ||
| val = ibuild.EmitFPAdd(val, op3); | ||
| val = ibuild.EmitFPNeg(val); | ||
| break; | ||
| } | ||
| } | ||
| val = ibuild.EmitExpandPackedToMReg(val); | ||
| ibuild.EmitStoreFReg(val, inst.FD); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,220 @@ | ||
| // Copyright 2013 Dolphin Emulator Project | ||
| // Licensed under GPLv2 | ||
| // Refer to the license.txt file included. | ||
|
|
||
| #include "Common.h" | ||
| #include "JitILBase.h" | ||
|
|
||
| #include "../../HW/SystemTimers.h" | ||
|
|
||
|
|
||
| void JitILBase::mtspr(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
| u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); | ||
| switch(iIndex) { | ||
| case SPR_TL: | ||
| case SPR_TU: | ||
| Default(inst); | ||
| return; | ||
| case SPR_LR: | ||
| ibuild.EmitStoreLink(ibuild.EmitLoadGReg(inst.RD)); | ||
| return; | ||
| case SPR_CTR: | ||
| ibuild.EmitStoreCTR(ibuild.EmitLoadGReg(inst.RD)); | ||
| return; | ||
| case SPR_GQR0: | ||
| case SPR_GQR0 + 1: | ||
| case SPR_GQR0 + 2: | ||
| case SPR_GQR0 + 3: | ||
| case SPR_GQR0 + 4: | ||
| case SPR_GQR0 + 5: | ||
| case SPR_GQR0 + 6: | ||
| case SPR_GQR0 + 7: | ||
| ibuild.EmitStoreGQR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_GQR0); | ||
| return; | ||
| case SPR_SRR0: | ||
| case SPR_SRR1: | ||
| ibuild.EmitStoreSRR(ibuild.EmitLoadGReg(inst.RD), iIndex - SPR_SRR0); | ||
| return; | ||
| default: | ||
| Default(inst); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| void JitILBase::mfspr(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
| u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); | ||
| switch (iIndex) | ||
| { | ||
| case SPR_TL: | ||
| case SPR_TU: | ||
| Default(inst); | ||
| return; | ||
| case SPR_LR: | ||
| ibuild.EmitStoreGReg(ibuild.EmitLoadLink(), inst.RD); | ||
| return; | ||
| case SPR_CTR: | ||
| ibuild.EmitStoreGReg(ibuild.EmitLoadCTR(), inst.RD); | ||
| return; | ||
| case SPR_GQR0: | ||
| case SPR_GQR0 + 1: | ||
| case SPR_GQR0 + 2: | ||
| case SPR_GQR0 + 3: | ||
| case SPR_GQR0 + 4: | ||
| case SPR_GQR0 + 5: | ||
| case SPR_GQR0 + 6: | ||
| case SPR_GQR0 + 7: | ||
| ibuild.EmitStoreGReg(ibuild.EmitLoadGQR(iIndex - SPR_GQR0), inst.RD); | ||
| return; | ||
| default: | ||
| Default(inst); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| // ======================================================================================= | ||
| // Don't interpret this, if we do we get thrown out | ||
| // -------------- | ||
| void JitILBase::mtmsr(UGeckoInstruction inst) | ||
| { | ||
| ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC)); | ||
| ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); | ||
| } | ||
| // ============== | ||
|
|
||
|
|
||
| void JitILBase::mfmsr(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
| ibuild.EmitStoreGReg(ibuild.EmitLoadMSR(), inst.RD); | ||
| } | ||
|
|
||
| void JitILBase::mftb(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START; | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
| mfspr(inst); | ||
| } | ||
|
|
||
| void JitILBase::mfcr(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START; | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
|
|
||
| IREmitter::InstLoc d = ibuild.EmitIntConst(0); | ||
| for (int i = 0; i < 8; ++i) | ||
| { | ||
| d = ibuild.EmitShl(d, ibuild.EmitIntConst(4)); | ||
| d = ibuild.EmitOr(d, ibuild.EmitLoadCR(i)); | ||
| } | ||
| ibuild.EmitStoreGReg(d, inst.RD); | ||
| } | ||
|
|
||
| void JitILBase::mtcrf(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START; | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
|
|
||
| IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS); | ||
| for (int i = 0; i < 8; ++i) | ||
| { | ||
| if (inst.CRM & (0x80 >> i)) | ||
| { | ||
| IREmitter::InstLoc value; | ||
| value = ibuild.EmitShrl(s, ibuild.EmitIntConst(28 - i * 4)); | ||
| value = ibuild.EmitAnd(value, ibuild.EmitIntConst(0xF)); | ||
| ibuild.EmitStoreCR(value, i); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void JitILBase::mcrf(UGeckoInstruction inst) | ||
| { | ||
| INSTRUCTION_START | ||
| JITDISABLE(bJITSystemRegistersOff) | ||
|
|
||
| if (inst.CRFS != inst.CRFD) | ||
| { | ||
| ibuild.EmitStoreCR(ibuild.EmitLoadCR(inst.CRFS), inst.CRFD); | ||
| } | ||
| } | ||
|
|
||
| void JitILBase::crXX(UGeckoInstruction inst) | ||
| { | ||
| // Ported from Jit_SystemRegister.cpp | ||
|
|
||
| // Get bit CRBA in EAX aligned with bit CRBD | ||
| const int shiftA = (inst.CRBD & 3) - (inst.CRBA & 3); | ||
| IREmitter::InstLoc eax = ibuild.EmitLoadCR(inst.CRBA >> 2); | ||
| if (shiftA < 0) | ||
| eax = ibuild.EmitShl(eax, ibuild.EmitIntConst(-shiftA)); | ||
| else if (shiftA > 0) | ||
| eax = ibuild.EmitShrl(eax, ibuild.EmitIntConst(shiftA)); | ||
|
|
||
| // Get bit CRBB in ECX aligned with bit CRBD | ||
| const int shiftB = (inst.CRBD & 3) - (inst.CRBB & 3); | ||
| IREmitter::InstLoc ecx = ibuild.EmitLoadCR(inst.CRBB >> 2); | ||
| if (shiftB < 0) | ||
| ecx = ibuild.EmitShl(ecx, ibuild.EmitIntConst(-shiftB)); | ||
| else if (shiftB > 0) | ||
| ecx = ibuild.EmitShrl(ecx, ibuild.EmitIntConst(shiftB)); | ||
|
|
||
| // Compute combined bit | ||
| const unsigned subop = inst.SUBOP10; | ||
| switch (subop) { | ||
| case 257: | ||
| // crand | ||
| eax = ibuild.EmitAnd(eax, ecx); | ||
| break; | ||
| case 129: | ||
| // crandc | ||
| ecx = ibuild.EmitNot(ecx); | ||
| eax = ibuild.EmitAnd(eax, ecx); | ||
| break; | ||
| case 289: | ||
| // creqv | ||
| eax = ibuild.EmitXor(eax, ecx); | ||
| eax = ibuild.EmitNot(eax); | ||
| break; | ||
| case 225: | ||
| // crnand | ||
| eax = ibuild.EmitAnd(eax, ecx); | ||
| eax = ibuild.EmitNot(eax); | ||
| break; | ||
| case 33: | ||
| // crnor | ||
| eax = ibuild.EmitOr(eax, ecx); | ||
| eax = ibuild.EmitNot(eax); | ||
| break; | ||
| case 449: | ||
| // cror | ||
| eax = ibuild.EmitOr(eax, ecx); | ||
| break; | ||
| case 417: | ||
| // crorc | ||
| ecx = ibuild.EmitNot(ecx); | ||
| eax = ibuild.EmitOr(eax, ecx); | ||
| break; | ||
| case 193: | ||
| // crxor | ||
| eax = ibuild.EmitXor(eax, ecx); | ||
| break; | ||
| default: | ||
| PanicAlert("crXX: invalid instruction"); | ||
| break; | ||
| } | ||
|
|
||
| // Store result bit in CRBD | ||
| eax = ibuild.EmitAnd(eax, ibuild.EmitIntConst(0x8 >> (inst.CRBD & 3))); | ||
| IREmitter::InstLoc bd = ibuild.EmitLoadCR(inst.CRBD >> 2); | ||
| bd = ibuild.EmitAnd(bd, ibuild.EmitIntConst(~(0x8 >> (inst.CRBD & 3)))); | ||
| bd = ibuild.EmitOr(bd, eax); | ||
| ibuild.EmitStoreCR(bd, inst.CRBD >> 2); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ | |
| #ifndef _PPCCACHE_H | ||
| #define _PPCCACHE_H | ||
|
|
||
| #include "CommonTypes.h" | ||
|
|
||
| #define FAST_ICACHE | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,5 +21,4 @@ set(SRCS Src/BannerLoader.cpp | |
| Src/VolumeWiiCrypted.cpp | ||
| Src/WiiWad.cpp) | ||
|
|
||
| add_dolphin_library(discio "${SRCS}" "") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,7 +14,7 @@ | |
| #ifndef DISC_SCRUBBER_H | ||
| #define DISC_SCRUBBER_H | ||
|
|
||
| #include "CommonTypes.h" | ||
| #include "Blob.h" | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ | |
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "CommonTypes.h" | ||
| #include "Filesystem.h" | ||
|
|
||
| namespace DiscIO | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,7 @@ | |
| #include <vector> | ||
| #include <map> | ||
|
|
||
| #include "CommonTypes.h" | ||
| #include "Blob.h" | ||
| #include "Volume.h" | ||
|
|
||
|
|
||