From a54e0cf2445a461df173137ca26df84ab6c80d98 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 16 Dec 2014 21:58:38 +0100 Subject: [PATCH] Goodbye PowerPC, you can always be resurrected when the time comes --- Common/ppcEmitter.cpp | 927 ------------------- Common/ppcEmitter.h | 518 ----------- Core/HLE/ReplaceTables.cpp | 2 - Core/MIPS/JitCommon/JitBlockCache.cpp | 20 +- Core/MIPS/JitCommon/JitBlockCache.h | 4 - Core/MIPS/JitCommon/NativeJit.h | 5 +- Core/MIPS/MIPSTables.cpp | 4 +- Core/MIPS/PPC/PpcAsm.cpp | 285 ------ Core/MIPS/PPC/PpcCompAlu.cpp | 562 ------------ Core/MIPS/PPC/PpcCompBranch.cpp | 435 --------- Core/MIPS/PPC/PpcCompFpu.cpp | 463 ---------- Core/MIPS/PPC/PpcCompLoadStore.cpp | 152 --- Core/MIPS/PPC/PpcCompReplace.cpp | 39 - Core/MIPS/PPC/PpcCompVFPU.cpp | 1219 ------------------------- Core/MIPS/PPC/PpcJit.cpp | 288 ------ Core/MIPS/PPC/PpcJit.h | 335 ------- Core/MIPS/PPC/PpcRegCache.cpp | 313 ------- Core/MIPS/PPC/PpcRegCache.h | 156 ---- Core/MIPS/PPC/PpcRegCacheFPU.cpp | 388 -------- Core/MIPS/PPC/PpcRegCacheFPU.h | 140 --- Core/MIPS/PPC/PpcRegCacheVPU.cpp | 313 ------- Core/MIPS/PPC/PpcRegCacheVPU.h | 106 --- 22 files changed, 7 insertions(+), 6667 deletions(-) delete mode 100644 Common/ppcEmitter.cpp delete mode 100644 Common/ppcEmitter.h delete mode 100644 Core/MIPS/PPC/PpcAsm.cpp delete mode 100644 Core/MIPS/PPC/PpcCompAlu.cpp delete mode 100644 Core/MIPS/PPC/PpcCompBranch.cpp delete mode 100644 Core/MIPS/PPC/PpcCompFpu.cpp delete mode 100644 Core/MIPS/PPC/PpcCompLoadStore.cpp delete mode 100644 Core/MIPS/PPC/PpcCompReplace.cpp delete mode 100644 Core/MIPS/PPC/PpcCompVFPU.cpp delete mode 100644 Core/MIPS/PPC/PpcJit.cpp delete mode 100644 Core/MIPS/PPC/PpcJit.h delete mode 100644 Core/MIPS/PPC/PpcRegCache.cpp delete mode 100644 Core/MIPS/PPC/PpcRegCache.h delete mode 100644 Core/MIPS/PPC/PpcRegCacheFPU.cpp delete mode 100644 Core/MIPS/PPC/PpcRegCacheFPU.h delete mode 100644 Core/MIPS/PPC/PpcRegCacheVPU.cpp delete mode 100644 Core/MIPS/PPC/PpcRegCacheVPU.h diff --git a/Common/ppcEmitter.cpp b/Common/ppcEmitter.cpp deleted file mode 100644 index 8bcb7bcaa7..0000000000 --- a/Common/ppcEmitter.cpp +++ /dev/null @@ -1,927 +0,0 @@ -#include -#include "ppcEmitter.h" - -// Helper - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | D | A | B | XO |Rc| -#define X_FORM(OPCD, D, A, B, XO, Rc) { \ - int a = (A), b = (B), d = (D); \ - Write32((OPCD << 26) | (d << 21) | (a << 16) | (b << 11) | (((XO) & 0x3ff) << 1) | (Rc)); \ -} - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | D | A | B |OE| XO |Rc| -#define XO_FORM(OPCD, D, A, B, OE, XO, Rc) { \ - int a = (A), b = (B), d = (D); \ - Write32((OPCD << 26) | (d << 21) | (a << 16) | (b << 11) | (OE << 10) | (((XO) & 0x1ff) << 1) | (Rc)); \ -} - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | D | A | B | C | XO |Rc| -#define A_FORM(OPCD, D, A, B, C, XO, Rc) { \ - int a = (A), b = (B), c = (C), d = (D); \ - Write32((OPCD << 26) | (d << 21) | (a << 16) | (b << 11) | (c << 6) | (XO << 1) | (Rc)); \ -} - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | D | A | d/UIMM/SIMM | -#define D_FORM(OPCD, RD, RA, IMM) { \ - int _ra = (RA), _rd = (RD); \ - Write32((OPCD << 26) | (_rd << 21) | (_ra << 16) | ((IMM) & 0xffff)); \ -} - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | D | A | B | C | XO |Rc| -#define A_FORM(OPCD, D, A, B, C, XO, Rc) { \ - int a = (A), b = (B), c = (C), d = (D); \ - Write32((OPCD << 26) | (d << 21) | (a << 16) | (b << 11) | (c << 6) | (XO << 1) | (Rc)); \ -} - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | BO/crbD | BI/crbA | crbB | XO |LK| -#define XL_FORM(OPCD, crbD, crbA, crbB, XO, LK) { \ - X_FORM(OPCD, crbD, crbA, crbB, XO, LK); \ -} - -// 0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 -// | OPCD | S | A | SH | MB | ME |Rc| -#define M_FORM(OPCD, RS, RA, SH, MB, ME, Rc) { \ - int rs = (RS), ra = (RA), sh = (SH); \ - Write32((OPCD << 26) | (rs << 21) | (ra << 16) | (sh << 11) | ((MB) << 6) | ((ME) << 1) | (Rc)); \ -} - -namespace PpcGen { - - // Mul stuff - - void PPCXEmitter::DIVW (PPCReg Rt, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rt, Ra, Rb, 0, 491, 0); - } - void PPCXEmitter::DIVWU (PPCReg Rt, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rt, Ra, Rb, 0, 459, 0); - } - void PPCXEmitter::MULLW (PPCReg Rt, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rt, Ra, Rb, 0, 235, 0); - } - void PPCXEmitter::MULHW (PPCReg Rt, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rt, Ra, Rb, 0, 75, 0); - } - void PPCXEmitter::MULHWU(PPCReg Rt, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rt, Ra, Rb, 0, 11, 0); - } - - // Arithmetics ops - void PPCXEmitter::ADDZE (PPCReg Rd, PPCReg Ra) { - XO_FORM(31, Rd, Ra, 0, 0, 202, 0); - } - - void PPCXEmitter::ADD (PPCReg Rd, PPCReg Ra, PPCReg Rb) { - u32 instr = (0x7C000214 | (Rd << 21) | (Ra << 16) | (Rb << 11)); - Write32(instr); - } - - void PPCXEmitter::ADDI (PPCReg Rd, PPCReg Ra, short imm) { - u32 instr = (0x38000000 | (Rd << 21) | (Ra << 16) | ((imm) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::ADDIS (PPCReg Rd, PPCReg Ra, short imm) { - u32 instr = (0x3C000000 | (Rd << 21) | (Ra << 16) | ((imm) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::AND (PPCReg Rs, PPCReg Ra, PPCReg Rb) { - u32 instr = (0x7C000038 | (Ra << 21) | (Rs << 16) | (Rb << 11)); - Write32(instr); - } - - void PPCXEmitter::ANDI (PPCReg Rdest, PPCReg Ra, unsigned short imm) { - u32 instr = (0x70000000 | (Ra << 21) | (Rdest << 16) | ((imm) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::ANDIS (PPCReg Rdest, PPCReg Ra, unsigned short imm) { - u32 instr = (0x74000000 | (Ra << 21) | (Rdest << 16) | ((imm) & 0xffff)); - Write32(instr); - } - - // Memory load/store operations - void PPCXEmitter::LI(PPCReg dest, unsigned short imm) { - u32 instr = (0x38000000 | (dest << 21) | ((imm) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::LIS(PPCReg dest, unsigned short imm) { - u32 instr = (0x3C000000 | (dest << 21) | ((imm) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::LBZ (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0x88000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::LBZX (PPCReg dest, PPCReg a, PPCReg b) { - u32 instr = ((31<<26) | (dest << 21) | (a << 16) | (b << 11) | (87<<1)); - Write32(instr); - } - - void PPCXEmitter::LHZ (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0xA0000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::LHBRX (PPCReg dest, PPCReg src, PPCReg offset) { - u32 instr = (0x7C00062C | (dest << 21) | (src << 16) | (offset << 11)); - Write32(instr); - } - - void PPCXEmitter::LWZ (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0x80000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::LWBRX (PPCReg dest, PPCReg src, PPCReg offset) { - u32 instr = (0x7C00042C | (dest << 21) | (src << 16) | (offset << 11)); - Write32(instr); - } - - void PPCXEmitter::STB (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0x98000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::STBX (PPCReg dest, PPCReg a, PPCReg b) { - u32 instr = ((31<<26) | (dest << 21) | (a << 16) | (b << 11) | (215 << 1)); - Write32(instr); - } - - void PPCXEmitter::STH (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0xB0000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::STHBRX (PPCReg dest, PPCReg src, PPCReg offset) { - u32 instr = (0x7C00072C | (dest << 21) | (src << 16) | (offset << 11)); - Write32(instr); - } - - void PPCXEmitter::STW (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0x90000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::STWU (PPCReg dest, PPCReg src, int offset) { - u32 instr = (0x94000000 | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::STWBRX (PPCReg dest, PPCReg src, PPCReg offset) { - u32 instr = (0x7C00052C | (dest << 21) | (src << 16) | (offset << 11)); - Write32(instr); - } - - void PPCXEmitter::LD (PPCReg dest, PPCReg src, int offset) { - u32 instr = ((58 << 26) | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - void PPCXEmitter::STD (PPCReg dest, PPCReg src, int offset) { - u32 instr = ((62 << 26) | (dest << 21) | (src << 16) | ((offset) & 0xffff)); - Write32(instr); - } - - // Branch operations - void PPCXEmitter::B (const void *fnptr) { - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x48000000 | ((s32)((func) & 0x3fffffc))); - Write32(instr); - } - - void PPCXEmitter::BL(const void *fnptr) { - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x48000001 | ((s32)((func) & 0x3fffffc))); - Write32(instr); - } - - void PPCXEmitter::BA (const void *fnptr) { - s32 func = (s32)fnptr; - u32 instr = (0x48000002 | ((s32)((func) & 0x3fffffc))); - Write32(instr); - } - - void PPCXEmitter::BLA (const void *fnptr) { - s32 func = (s32)fnptr; - u32 instr = (0x48000003 | ((s32)((func) & 0x3fffffc))); - Write32(instr); - } - - -#define IS_SMALL_JUMP (((u32)code - (u32)fnptr)>=-32767 && ((u32)code - (u32)fnptr)<=-32767) -#define CHECK_SMALL_JUMP { if(IS_SMALL_JUMP) { DebugBreak(); } } - - void PPCXEmitter::BEQ (const void *fnptr) { - CHECK_SMALL_JUMP - - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x41820000 | ( func & 0xfffc)); - Write32(instr); - } - - void PPCXEmitter::BNE (const void *fnptr) { - CHECK_SMALL_JUMP - - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x40820000 | ( func & 0xfffc)); - Write32(instr); - } - - void PPCXEmitter::BGT(const void *fnptr) { - CHECK_SMALL_JUMP - - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x41810000 | (((s16)(((func)+1))) & 0xfffc)); - Write32(instr); - } - - - void PPCXEmitter::BLTCTR() { - Write32((19 << 26) | (12 << 21) | (528 <<1)); - // Break(); - } - - void PPCXEmitter::BLT (const void *fnptr) { - //CHECK_JUMP - if (!IS_SMALL_JUMP) { - u32 func_addr = (u32) fnptr; - // Load func address - MOVI2R(R0, func_addr); - // Set it to link register - MTCTR(R0); - // Branch - BLTCTR(); - return; - } - - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x41800000 | (((s16)(((func)+1))) & 0xfffc)); - Write32(instr); - } - - void PPCXEmitter::BLE (const void *fnptr) { - CHECK_SMALL_JUMP - - s32 func = (s32)fnptr - s32(code); - u32 instr = (0x40810000 | (((s16)(((func)+1))) & 0xfffc)); - Write32(instr); - } - - void PPCXEmitter::BCTRL() { - Write32(0x4E800421); - } - - void PPCXEmitter::BCTR() { - Write32(0x4E800420); - } - - // Link Register - void PPCXEmitter::MFLR(PPCReg r) { - Write32(0x7C0802A6 | r << 21); - } - - void PPCXEmitter::MTLR(PPCReg r) { - Write32(0x7C0803A6 | r << 21); - } - - void PPCXEmitter::MTCTR(PPCReg r) { - Write32(0x7C0903A6 | r << 21); - } - - void PPCXEmitter::BLR() { - Write32(0x4E800020); - } - - void PPCXEmitter::BGTLR() { - Write32(0x4D810020); - } - - // Fixup - FixupBranch PPCXEmitter::B() - { - FixupBranch branch; - branch.type = _B; - branch.ptr = code; - branch.condition = condition; - //We'll write NOP here for now. - Write32(0x60000000); - return branch; - } - - FixupBranch PPCXEmitter::BL() - { - FixupBranch branch; - branch.type = _BL; - branch.ptr = code; - branch.condition = condition; - //We'll write NOP here for now. - Write32(0x60000000); - return branch; - } - - - FixupBranch PPCXEmitter::BNE() { - FixupBranch branch; - branch.type = _BNE; - branch.ptr = code; - branch.condition = condition; - //We'll write NOP here for now. - Write32(0x60000000); - return branch; - } - - FixupBranch PPCXEmitter::BLT() { - FixupBranch branch; - branch.type = _BLT; - branch.ptr = code; - branch.condition = condition; - //We'll write NOP here for now. - Write32(0x60000000); - return branch; - } - - FixupBranch PPCXEmitter::BLE() { - FixupBranch branch; - branch.type = _BLE; - branch.ptr = code; - branch.condition = condition; - //We'll write NOP here for now. - Write32(0x60000000); - return branch; - } - - FixupBranch PPCXEmitter::B_Cond(FixupBranchType type) { - FixupBranch branch; - branch.type = type; - branch.ptr = code; - branch.condition = condition; - //We'll write NOP here for now. - Write32(0x60000000); - return branch; - } - - void PPCXEmitter::SetJumpTarget(FixupBranch const &branch) - { - s32 distance = s32(code) - (s32)branch.ptr; - _assert_msg_(DYNA_REC, distance > -32767 - && distance <= 32767, - "SetJumpTarget out of range (%p calls %p)", code, - branch.ptr); - - switch(branch.type) { - case _B: - *(u32*)branch.ptr = (0x48000000 | ((s32)((distance) & 0x3fffffc))); - break; - case _BL: - *(u32*)branch.ptr = (0x48000001 | ((s32)((distance) & 0x3fffffc))); - break; - case _BEQ: - *(u32*)branch.ptr = (0x41820000 | ((s16)(((distance)+1)) & 0xfffc)); - break; - case _BNE: - *(u32*)branch.ptr = (0x40820000 | ((s16)(((distance)+1)) & 0xfffc)); - break; - case _BLT: - *(u32*)branch.ptr = (0x41800000 | ((s16)(((distance)+1)) & 0xfffc)); - break; - case _BLE: - *(u32*)branch.ptr = (0x40810000 | ((s16)(((distance)+1)) & 0xfffc)); - break; - case _BGT: - *(u32*)branch.ptr = (0x41810000 | ((s16)(((distance)+1)) & 0xfffc)); - break; - case _BGE: - *(u32*)branch.ptr = (0x40800000 | ((s16)(((distance)+1)) & 0xfffc)); - break; - default: - // Error !!! - _assert_msg_(DYNA_REC, 0, "SetJumpTarget unknow branch type: %d", branch.type); - break; - } - } - - // Compare (Only use CR0 atm...) - void PPCXEmitter::CMPI(PPCReg dest, unsigned short imm) { - Write32((11<<26) | (dest << 16) | ((imm) & 0xffff)); - } - - void PPCXEmitter::CMPLI(PPCReg dest, unsigned short imm) { - Write32((10<<26) | (dest << 16) | ((imm) & 0xffff)); - } - - void PPCXEmitter::CMP(PPCReg a, PPCReg b, CONDITION_REGISTER cr) { - Write32((31 << 26) | (a << 16) | (b << 11)); - } - void PPCXEmitter::CMPL(PPCReg a, PPCReg b, CONDITION_REGISTER cr) { - Write32((31 << 26) | (a << 16) | (b << 11) | (1<<6)); - } - void PPCXEmitter::MFCR (PPCReg dest) { - Write32(0x7C000026 | (dest << 21)); - } - void PPCXEmitter::MTCR (PPCReg dest) { - Write32(0x7C000120 | (dest << 21) | (0xff<<12)); - } - - void PPCXEmitter::CROR (int bt, int ba, int bb) { - XL_FORM(19, bt, ba, bb, 449, 0); - } - - void PPCXEmitter::ISEL (PPCReg Rt, PPCReg Ra, PPCReg Rb, CONDITION_REGISTER cr) { - // Not working !! - A_FORM(31, Rt, Ra, Rb, cr, 15, 0); - Break(); - } - - // Others operation - void PPCXEmitter::ORI(PPCReg Rd, PPCReg Ra, unsigned short imm) { - u32 instr = (0x60000000 | (Ra << 21) | (Rd << 16) | (imm & 0xffff)); - Write32(instr); - } - void PPCXEmitter::XORI (PPCReg Rdest, PPCReg Ra, unsigned short imm) { - u32 instr = (0x68000000 | (Ra << 21) | (Rdest << 16) | (imm & 0xffff)); - Write32(instr); - } - - void PPCXEmitter::OR(PPCReg Rdest, PPCReg Ra, PPCReg Rb) { - u32 instr = (0x7C000378 | (Ra << 21) | (Rdest << 16) | (Rb << 11)); - Write32(instr); - } - - void PPCXEmitter::XOR(PPCReg Rd, PPCReg Ra, PPCReg Rb) { - u32 instr = (0x7C000278 | (Ra << 21) | (Rd << 16) | (Rb << 11)); - Write32(instr); - } - - void PPCXEmitter::NEG(PPCReg Rd, PPCReg Ra) { - XO_FORM(31, Rd, Ra, 0, 0, 104, 0); - } - - - void PPCXEmitter::NOR(PPCReg Rd, PPCReg Ra, PPCReg Rb) { - u32 instr = (0x7C0000f8 | (Ra << 21) | (Rd << 16) | (Rb << 11)); - Write32(instr); - } - - void PPCXEmitter::SUBF(PPCReg Rd, PPCReg Ra, PPCReg Rb, int RCFlags) { - u32 instr = (0x7C000050 | (Rd << 21) | (Ra << 16) | (Rb << 11) | (RCFlags & 1)); - Write32(instr); - } - - void PPCXEmitter::SUBFC (PPCReg Rd, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rd, Ra, Rb, 0, 8, 0); - } - void PPCXEmitter::SUBFIC(PPCReg Rt, PPCReg Ra, short imm) { - D_FORM(8, Rt, Ra, imm); - } - - - void PPCXEmitter::SUBFE(PPCReg Rd, PPCReg Ra, PPCReg Rb) { - XO_FORM(31, Rd, Ra, Rb, 0, 136, 0); - } - - // Quick Call - // dest = LIS(imm) + ORI(+imm) - void PPCXEmitter::MOVI2R(PPCReg dest, unsigned int imm) { - if ((s32) (s16) (imm) == (s32) (imm)) { - // 16bit - LI(dest, imm & 0xFFFF); - } else { - // HI 16bit - LIS(dest, imm>>16); - if ((imm & 0xFFFF) != 0) { - // LO 16bit - ORI(dest, dest, imm & 0xFFFF); - } - } - } - - void PPCXEmitter::QuickCallFunction(void *func) { - /** TODO : can use simple jump **/ - - u32 func_addr = (u32) func; - // Load func address - MOVI2R(R0, func_addr); - // Set it to link register - MTCTR(R0); - // Branch - BCTRL(); - } - - // sign - void PPCXEmitter::EXTSB (PPCReg dest, PPCReg src) { - Write32((0x7C000774 | (src << 21) | (dest << 16))); - } - - void PPCXEmitter::EXTSH (PPCReg dest, PPCReg src) { - Write32(0x7C000734 | (src << 21) | (dest << 16)); - } - - void PPCXEmitter::EXTSW (PPCReg Rt, PPCReg Ra) { - X_FORM(31, Rt, Ra, 0, 986, 0); - } - - void PPCXEmitter::EQV (PPCReg Ra, PPCReg Rs, PPCReg Rb) { - X_FORM(31, Rs, Ra, Rb, 284, 0); - } - - void PPCXEmitter::RLWINM (PPCReg dest, PPCReg src, int shift, int start, int end) { - Write32((21<<26) | (src << 21) | (dest << 16) | (shift << 11) | (start << 6) | (end << 1)); - } - - void PPCXEmitter::RLDICL (PPCReg Rs, PPCReg Ra, int sh, int mb) { - Write32((30 << 26) | (Rs << 21) | (Ra << 16) | (sh << 11) | ((mb) << 6) | ((sh) << 1) | (0)); - } - - // Shift Instructions - void PPCXEmitter::SRAW (PPCReg dest, PPCReg src, PPCReg shift) { - X_FORM(31, src, dest, shift, 792, 0); - } - void PPCXEmitter::SRAWI (PPCReg dest, PPCReg src, unsigned short imm) { - X_FORM(31, src, dest, imm, 824, 0); - } - - void PPCXEmitter::SLW (PPCReg dest, PPCReg src, PPCReg shift) { - X_FORM(31, src, dest, shift, 24, 0); - } - - void PPCXEmitter::SLWI (PPCReg dest, PPCReg src, unsigned short imm) { - RLWINM(dest, src, imm, 0, (31-imm)); - } - - void PPCXEmitter::SRW (PPCReg dest, PPCReg src, PPCReg shift) { - X_FORM(31, src, dest, shift, 536, 0); - } - - void PPCXEmitter::SRWI (PPCReg dest, PPCReg src, unsigned short imm) { - RLWINM(dest, src, (32-imm), imm, 31); - } - - void PPCXEmitter::ROTRW (PPCReg dest, PPCReg src, PPCReg shift) { - - } - - void PPCXEmitter::ROTRWI(PPCReg dest, PPCReg src, unsigned short imm) { - RLWINM(dest, src, (32-imm), 0, 31); - } - - void PPCXEmitter::ROTLW (PPCReg dest, PPCReg src, PPCReg shift) { - } - - void PPCXEmitter::ROTLWI (PPCReg dest, PPCReg src, unsigned short imm) { - } - - // Fpu - void PPCXEmitter::LFS (PPCReg FRt, PPCReg Ra, unsigned short offset) { - D_FORM(48, FRt, Ra, offset); - } - void PPCXEmitter::LFD (PPCReg FRt, PPCReg Ra, unsigned short offset) { - D_FORM(50, FRt, Ra, offset); - } - void PPCXEmitter::SFS (PPCReg FRt, PPCReg Ra, unsigned short offset) { - D_FORM(52, FRt, Ra, offset); - } - void PPCXEmitter::SFD (PPCReg FRt, PPCReg Ra, unsigned short offset) { - D_FORM(54, FRt, Ra, offset); - } - - - void PPCXEmitter::MOVI2F (PPCReg dest, float imm, bool negate) { - u32 tmp; - - union convert { - unsigned int i; - float f; - } fc; - - fc.f = imm; - - MOVI2R(R6, fc.i); - - // R7 = imm - MOVI2R(R7, (u32)&tmp); - STW(R6, R7); - - // dest = R7 - LFS(dest, R7, 0); - - if (negate == true) { - FNEG(dest, dest); - } - } - - void PPCXEmitter::SaveFloatSwap(PPCReg FRt, PPCReg Base, PPCReg offset) { - // used for swapping float ... - u32 tmp; - - // Save Value in tmp - MOVI2R(R7, (u32)&tmp); - SFS(FRt, R7, 0); - - // Load the value in R6 - LWZ(R6, R7); - - // Save the final value - STWBRX(R6, Base, offset); - } - - void PPCXEmitter::LoadFloatSwap(PPCReg FRt, PPCReg Base, PPCReg offset) { - // used for swapping float ... - u32 tmp; - - // Load Value into a temp REG - LWBRX(R6, Base, offset); - - // Save it in tmp - MOVI2R(R7, (u32)&tmp); - STW(R6, R7); - - // Load the final value - LFS(FRt, R7, 0); - } - void PPCXEmitter::MTFSB0(int bt) { - X_FORM(63, bt, 0, 0, 70, 0); - } - void PPCXEmitter::FCTID (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 846, 0); - } - void PPCXEmitter::FCFID (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 846, 0); - } - void PPCXEmitter::FRSP (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 12, 0); - } - void PPCXEmitter::FCTIW (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 14, 0); - } - void PPCXEmitter::STFIWX(PPCReg FRt, PPCReg FRa, PPCReg FRb) { - X_FORM(31, FRt, FRa, FRb, 983, 0); - } - - // Fpu move instruction - void PPCXEmitter::FMR (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 72, 0); - } - void PPCXEmitter::FNEG (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 40, 0); - } - void PPCXEmitter::FABS (PPCReg FRt, PPCReg FRb) { - X_FORM(63, FRt, 0, FRb, 264, 0); - } - void PPCXEmitter::FNABS (PPCReg FRt, PPCReg FRb) { - Break(); - X_FORM(63, FRt, 0, FRb, 136, 0); - } - void PPCXEmitter::FCPSGN (PPCReg FRt, PPCReg FRb) { - Break(); - X_FORM(63, FRt, 0, FRb, 8, 0); - } - - // Fpu arith - void PPCXEmitter::FADDS (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - A_FORM(59, FRt, FRa, FRb, 0, 21, 0); - } - void PPCXEmitter::FSUBS (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - A_FORM(59, FRt, FRa, FRb, 0, 20, 0); - } - void PPCXEmitter::FADD (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - A_FORM(63, FRt, FRa, FRb, 0, 21, 0); - } - void PPCXEmitter::FSUB (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - A_FORM(63, FRt, FRa, FRb, 0, 20, 0); - } - void PPCXEmitter::FMUL (PPCReg FRt, PPCReg FRa, PPCReg FRc) { - A_FORM(63, FRt, FRa, 0, FRc, 25, 0); - } - void PPCXEmitter::FMULS (PPCReg FRt, PPCReg FRa, PPCReg FRc) { - A_FORM(59, FRt, FRa, 0, FRc, 25, 0); - } - void PPCXEmitter::FDIV (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - A_FORM(63, FRt, FRa, FRb, 0, 18, 0); - } - void PPCXEmitter::FDIVS (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - A_FORM(59, FRt, FRa, FRb, 0, 18, 0); - } - void PPCXEmitter::FSQRT (PPCReg FRt, PPCReg FRb) { - A_FORM(63, FRt, 0, FRb, 0, 22, 0); - } - void PPCXEmitter::FSQRTS (PPCReg FRt, PPCReg FRb) { - A_FORM(59, FRt, 0, FRb, 0, 22, 0); - } - void PPCXEmitter::FSQRTE (PPCReg FRt, PPCReg FRb) { - Break(); - } - void PPCXEmitter::FSQRTES(PPCReg FRt, PPCReg FRb) { - Break(); - } - void PPCXEmitter::FRE (PPCReg FRt, PPCReg FRb) { - Break(); - } - void PPCXEmitter::FRES (PPCReg FRt, PPCReg FRb) { - Break(); - } - - // Fpu mul add - void PPCXEmitter::FMADD (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb) { - A_FORM(63, FRt, FRa, FRb, FRc, 29, 0); - } - void PPCXEmitter::FMSUB (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb) { - A_FORM(63, FRt, FRa, FRb, FRc, 28, 0); - } - void PPCXEmitter::FMADDS (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb) { - A_FORM(59, FRt, FRa, FRb, FRc, 29, 0); - } - void PPCXEmitter::FMSUBS (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb) { - A_FORM(59, FRt, FRa, FRb, FRc, 28, 0); - } - - // Fpu sel - void PPCXEmitter::FSEL (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb) { - A_FORM(63, FRt, FRa, FRb, FRc, 23, 0); - } - // #define fpmin(a,b) __fsel((a)-(b), b,a) - void PPCXEmitter::FMIN (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - PPCReg safe = FPR3; // hope it's safe !! - FSUBS(safe, FRa, FRb); - FSEL(FRt, safe, FRb, FRa); - //Break(); - } - // #define fpmax(a,b) __fsel((a)-(b), a,b) - void PPCXEmitter::FMAX (PPCReg FRt, PPCReg FRa, PPCReg FRb) { - PPCReg safe = FPR3; // hope it's safe !! - FSUBS(safe, FRa, FRb); - FSEL(FRt, safe, FRa, FRb); - //Break(); - } - - - - void PPCXEmitter::FCMPU (int Bf, PPCReg FRa, PPCReg FRb) { // unordered - X_FORM(63, Bf, FRa, FRb, 0, 0); - } - - void PPCXEmitter::FCMPO (int Bf, PPCReg FRa, PPCReg FRb) { // ordered - X_FORM(63, Bf, FRa, FRb, 32, 0); - } - - // fpu convert - void PPCXEmitter::FRIN (PPCReg FRt, PPCReg FRb) { // round - X_FORM(63, FRt, 0, FRb, 392, 0); - } - void PPCXEmitter::FRIZ (PPCReg FRt, PPCReg FRb) { // trunc - X_FORM(63, FRt, 0, FRb, 456, 0); - } - void PPCXEmitter::FRIP (PPCReg FRt, PPCReg FRb) { // ceil - X_FORM(63, FRt, 0, FRb, 424, 0); - } - void PPCXEmitter::FRIM (PPCReg FRt, PPCReg FRb) { // floor - X_FORM(63, FRt, 0, FRb, 488, 0); - } - - // Prologue / epilogue - - /** save/load fpr in a static buffer ... **/ - static double _fprTmp[32]; - - void PPCXEmitter::Prologue() { - // Save regs - u32 regSize = 8; // 4 in 32bit system - u32 stackFrameSize = 0x1F0; - - // Write Prologue (setup stack frame etc ...) - // Save Lr - MFLR(R12); - - // Save gpr - for(int i = 14; i < 32; i ++) { - STD((PPCReg)i, R1, -((33 - i) * regSize)); - } - - // Save r12 - STW(R12, R1, -0x8); -#if 0 - // add fpr frame - ADDI(R12, R1, -0x98); - - // Load fpr - for(int i = 14; i < 32; i ++) { - SFD((PPCReg)i, R1, -((32 - i) * regSize)); - } -#endif - // allocate stack - STWU(R1, R1, -stackFrameSize); - -#if 1 - // load fpr buff - MOVI2R(R5, (u32)&_fprTmp); - - // Save fpr - for(int i = 14; i < 32; i ++) { - SFD((PPCReg)i, R5, i * regSize); - } -#endif - } - - void PPCXEmitter::Epilogue() { - u32 regSize = 8; // 4 in 32bit system - u32 stackFrameSize = 0x1F0; - - //Break(); - - // Write Epilogue (restore stack frame, return) - // free stack - ADDI(R1, R1, stackFrameSize); -#if 0 - ADDI(R12, R1, -0x98); - - // Restore fpr - for(int i = 14; i < 32; i ++) { - LFD((PPCReg)i, R1, -((32 - i) * regSize)); - } -#endif - // Restore gpr - for(int i = 14; i < 32; i ++) { - LD((PPCReg)i, R1, -((33 - i) * regSize)); - } - - // recover r12 (LR saved register) - LWZ (R12, R1, -0x8); - - // Restore Lr - MTLR(R12); - -#if 1 - // load fpr buff - MOVI2R(R5, (u32)&_fprTmp); - - // Load fpr - for(int i = 14; i < 32; i ++) { - LFD((PPCReg)i, R5, i * regSize); - } -#endif - } - - // Others ... - void PPCXEmitter::SetCodePtr(u8 *ptr) - { - code = ptr; - startcode = code; - lastCacheFlushEnd = ptr; - } - - const u8 *PPCXEmitter::GetCodePtr() const - { - return code; - } - - u8 *PPCXEmitter::GetWritableCodePtr() - { - return code; - } - - void PPCXEmitter::ReserveCodeSpace(u32 bytes) - { - for (u32 i = 0; i < bytes/4; i++) - Write32(0x60000000); //nop - } - - const u8 *PPCXEmitter::AlignCode16() - { - ReserveCodeSpace((-(s32)code) & 15); - return code; - } - - const u8 *PPCXEmitter::AlignCodePage() - { - ReserveCodeSpace((-(s32)code) & 4095); - return code; - } - - void PPCXEmitter::FlushIcache() - { - FlushIcacheSection(lastCacheFlushEnd, code); - lastCacheFlushEnd = code; - } - - void PPCXEmitter::FlushIcacheSection(u8 *start, u8 *end) - { - u8 * addr = start; - while(addr < end) { - __asm dcbst r0, addr - __asm icbi r0, addr - addr += 4; - } - __emit(0x7c0004ac);//sync - __emit(0x4C00012C);//isync - } - - -} // namespace \ No newline at end of file diff --git a/Common/ppcEmitter.h b/Common/ppcEmitter.h deleted file mode 100644 index 7f3bef67a0..0000000000 --- a/Common/ppcEmitter.h +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// http://www.csd.uwo.ca/~mburrel/stuff/ppc-asm.html -// http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.aixassem/doc/alangref/linkage_convent.htm -// http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.aixassem/doc/alangref/instruction_set.htm - -#pragma once - -#include "Common.h" -#include "MemoryUtil.h" -#include - -#undef _IP -#undef R0 -#undef _SP -#undef _LR -#undef _PC -#undef CALL - -namespace PpcGen -{ - enum PPCReg - { - // GPRs (32) - // Behaves as zero does in some instructions - R0 = 0, - // Stack pointer (SP) - R1, - // Reserved - R2, - // Used to pass integer function parameters and return values - R3, R4, - // Used to pass integer function parameters - R5, R6, R7, R8, R9, R10, - // General purpose - R11, - // Scratch - R12, - // Unused by the compiler reserved - R13, - // General purpose - R14, R15, R16, R17, R18, R19, - R20, R21, R22, R23, R24, R25, - R26, R27, R28, R29, R30, R31, - - // CRs (7) - CR0 = 0, - - // FPRs (32) - // Scratch - FPR0 = 0, - // Used to pass double word function parameters and return values - FPR1, FPR2, FPR3, FPR4, - FPR5, FPR6, FPR7, FPR8, - FPR9, FPR10, FPR11, FPR12, - FPR13, - // General purpose - FPR14, FPR15, FPR16, FPR17, - FPR18, FPR19, FPR20, FPR21, - FPR22, FPR23, FPR24, FPR25, - FPR26, FPR27, FPR28, FPR29, - FPR30, FPR31, - - - // Vmx (128) - VR0 = 0, VR1, VR2, VR3, VR4, - VR5, VR6, VR7, VR8, VR9, - VR10, VR11, VR12, VR13, VR14, - VR15, VR16, VR17, VR18, VR19, - VR20, VR21, VR22, VR23, VR24, - VR25, VR26, VR27, VR28, VR29, - VR30, VR31, VR32, VR33, VR34, - VR35, VR36, VR37, VR38, VR39, - VR40, VR41, VR42, VR43, VR44, - VR45, VR46, VR47, VR48, VR49, - VR50, VR51, VR52, VR53, VR54, - VR55, VR56, VR57, VR58, VR59, - VR60, VR61, VR62, VR63, VR64, - VR65, VR66, VR67, VR68, VR69, - VR70, VR71, VR72, VR73, VR74, - VR75, VR76, VR77, VR78, VR79, - VR80, VR81, VR82, VR83, VR84, - VR85, VR86, VR87, VR88, VR89, - VR90, VR91, VR92, VR93, VR94, - VR95, VR96, VR97, VR98, VR99, //... - - // Others regs - LR, CTR, XER, FPSCR, - - // End - - INVALID_REG = 0xFFFFFFFF - }; - enum IntegerSize - { - I_I8 = 0, - I_I16, - I_I32, - I_I64 - }; - - enum - { - NUMGPRs = 31, - }; - - typedef const u8* JumpTarget; - - - enum FixupBranchType { - _B, - _BEQ, - _BNE, - _BLT, - _BLE, - _BGT, - _BGE, - // Link register - _BL - }; - - struct FixupBranch - { - u8 *ptr; - u32 condition; // Remembers our codition at the time - FixupBranchType type; //0 = B 1 = BL - }; - - class PPCXEmitter - { - private: - u8 *code, *startcode; - u8 *lastCacheFlushEnd; - u32 condition; - - protected: - // Write opcode - inline void Write32(u32 value) {*(u32*)code = value; code+=4;} - public: - PPCXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) { - } - PPCXEmitter(u8 *code_ptr) { - code = code_ptr; - lastCacheFlushEnd = code_ptr; - startcode = code_ptr; - } - virtual ~PPCXEmitter() {} - - void SetCodePtr(u8 *ptr); - void ReserveCodeSpace(u32 bytes); - const u8 *AlignCode16(); - const u8 *AlignCodePage(); - const u8 *GetCodePtr() const; - void FlushIcache(); - void FlushIcacheSection(u8 *start, u8 *end); - u8 *GetWritableCodePtr(); - - - // Special purpose instructions - - // Debug Breakpoint - void BKPT(u16 arg); - - // Hint instruction - void YIELD(); - - // Do nothing - void NOP(int count = 1); //nop padding - TODO: fast nop slides, for amd and intel (check their manuals) - - // FixupBranch ops - FixupBranch B(); - FixupBranch BL(); - FixupBranch BNE(); - FixupBranch BLT(); - FixupBranch BLE(); - - FixupBranch B_Cond(FixupBranchType type); - - void SetJumpTarget(FixupBranch const &branch); - - // Branch ops - void B (const void *fnptr); - void BL(const void *fnptr); - void BA (const void *fnptr); - void BLA(const void *fnptr); - void BEQ(const void *fnptr); - void BNE(const void *fnptr); - void BLE(const void *fnptr); - void BLT(const void *fnptr); - void BGT(const void *fnptr); - void BEQ (PPCReg r); - - void BLR(); - void BGTLR(); // ??? used ? - void BLTCTR(); - void BGTCTR(); - void BLECTR(); - void BGECTR(); - void BCTRL (); - void BCTR(); - - // Link Register - void MFLR(PPCReg r); - void MTLR(PPCReg r); - void MTCTR(PPCReg r); - - - // Logical Ops - void AND (PPCReg Rs, PPCReg Ra, PPCReg Rb); - void ANDI (PPCReg Rdest, PPCReg Ra, unsigned short imm); - void ANDIS(PPCReg Rdest, PPCReg Ra, unsigned short imm); - void NAND (PPCReg Rs, PPCReg Ra, PPCReg Rb); - void OR (PPCReg Rs, PPCReg Ra, PPCReg Rb); - void ORI (PPCReg Rdest, PPCReg Ra, unsigned short imm); - void NOR (PPCReg Rs, PPCReg Ra, PPCReg Rb); - void XOR (PPCReg Rs, PPCReg Ra, PPCReg Rb); - void XORI (PPCReg Rdest, PPCReg Ra, unsigned short imm); - void NEG (PPCReg Rs, PPCReg Ra); - void EQV (PPCReg a, PPCReg b, PPCReg c); - - // Arithmetics ops - void ADD (PPCReg Rd, PPCReg Ra, PPCReg Rb); - void ADDI (PPCReg Rd, PPCReg Ra, short imm); - void ADDIS (PPCReg Rd, PPCReg Ra, short imm); - void ADDC (PPCReg Rd, PPCReg Ra, PPCReg Rb); - void ADDZE (PPCReg Rd, PPCReg Ra); - void SUB (PPCReg Rd, PPCReg Ra, PPCReg Rb) { - // reverse ? - SUBF(Rd, Rb, Ra); - } - // if RCFlags update CR0 - void SUBF (PPCReg Rd, PPCReg Ra, PPCReg Rb, int RCFlags = 0); - void SUBFIC (PPCReg Rt, PPCReg Ra, short imm); - void SUBFC (PPCReg Rd, PPCReg Ra, PPCReg Rb); - void SUBFE (PPCReg Rd, PPCReg Ra, PPCReg Rb); - - // integer multiplication ops - void DIVW (PPCReg Rt, PPCReg Ra, PPCReg Rb); - void DIVWU (PPCReg Rt, PPCReg Ra, PPCReg Rb); - void MULLW (PPCReg Rt, PPCReg Ra, PPCReg Rb); - void MULHW (PPCReg Rt, PPCReg Ra, PPCReg Rb); - void MULHWU (PPCReg Rt, PPCReg Ra, PPCReg Rb); - - // Memory load/store operations - void LI (PPCReg dest, unsigned short imm); - void LIS (PPCReg dest, unsigned short imm); - // dest = LIS(imm) + ORI(+imm) - void MOVI2R (PPCReg dest, unsigned int imm); - - // 8bit - void LBZ (PPCReg dest, PPCReg src, int offset = 0); - void LBZX (PPCReg dest, PPCReg a, PPCReg b); - - // 16bit - void LHZ (PPCReg dest, PPCReg src, int offset = 0); - void LHBRX (PPCReg dest, PPCReg src, PPCReg offset); - // 32 bit - void LWZ (PPCReg dest, PPCReg src, int offset = 0); - void LWBRX (PPCReg dest, PPCReg src, PPCReg offset); - // 64 bit - void LD (PPCReg dest, PPCReg src, int offset = 0); - - // 8 bit - void STB (PPCReg dest, PPCReg src, int offset = 0); - void STBX (PPCReg dest, PPCReg a, PPCReg b); - // 16 bit - void STH (PPCReg dest, PPCReg src, int offset = 0); - void STHBRX (PPCReg dest, PPCReg src, PPCReg offset); - // 32 bit - void STW (PPCReg dest, PPCReg src, int offset = 0); - void STWU (PPCReg dest, PPCReg src, int offset = 0); - void STWBRX (PPCReg dest, PPCReg src, PPCReg offset); - // 64 bit - void STD (PPCReg dest, PPCReg src, int offset = 0); - - // sign - void EXTSB (PPCReg dest, PPCReg src); - void EXTSH (PPCReg dest, PPCReg src); - void EXTSW (PPCReg dest, PPCReg src); - - // - void RLWINM (PPCReg dest, PPCReg src, int shift, int start, int end); - - void RLDICL (PPCReg Rt, PPCReg Rs, int sh, int mb); - - // Shift Instructions - void SRAW (PPCReg dest, PPCReg src, PPCReg shift); - void SRAWI (PPCReg dest, PPCReg src, unsigned short imm); - - void SLW (PPCReg dest, PPCReg src, PPCReg shift); - void SLWI (PPCReg dest, PPCReg src, unsigned short imm); - - void SRW (PPCReg dest, PPCReg src, PPCReg shift); - void SRWI (PPCReg dest, PPCReg src, unsigned short imm); - - void ROTRW (PPCReg dest, PPCReg src, PPCReg shift); - void ROTRWI (PPCReg dest, PPCReg src, unsigned short imm); - - void ROTLW (PPCReg dest, PPCReg src, PPCReg shift); - void ROTLWI (PPCReg dest, PPCReg src, unsigned short imm); - - // Compare - enum CONDITION_REGISTER{ - CR0, - CR1, - CR2, - CR3, - CR4, - CR5, - CR6, - CR7 - }; - - void CROR (int bt, int ba, int bb); - void CMPLI (PPCReg dest, unsigned short imm); - void CMPI (PPCReg dest, unsigned short imm); - void CMPL (PPCReg a, PPCReg b, CONDITION_REGISTER cr = CR0); - void CMP (PPCReg a, PPCReg b, CONDITION_REGISTER cr = CR0); - void MFCR (PPCReg dest); - void MTCR (PPCReg dest); - - void ISEL (PPCReg Rt, PPCReg Ra, PPCReg Rb, CONDITION_REGISTER cr = CR0); - - void Prologue(); - void Epilogue(); - - // Debug ! - void Break() { - Write32(0x0FE00016); - } - - void MR (PPCReg to, PPCReg from) { - OR(to, from, from); - } - - // Fpu - void LFS (PPCReg FRt, PPCReg Ra, unsigned short offset = 0); - void LFD (PPCReg FRt, PPCReg Ra, unsigned short offset = 0); - void SFS (PPCReg FRt, PPCReg Ra, unsigned short offset = 0); - void SFD (PPCReg FRt, PPCReg Ra, unsigned short offset = 0); - void SaveFloatSwap(PPCReg FRt, PPCReg Ra, PPCReg offset); - void LoadFloatSwap(PPCReg FRt, PPCReg Ra, PPCReg offset); - // dest = LIS(imm) + ORI(+imm) - void MOVI2F (PPCReg dest, float imm, bool negate = false); - - // Fpu move instruction - void FMR (PPCReg FRt, PPCReg FRb); - - // fpu - void MTFSB0 (int bt); - void FCFID (PPCReg FRt, PPCReg FRb); - void FCTID (PPCReg FRt, PPCReg FRb); - void FRSP (PPCReg FRt, PPCReg FRb); - void FCTIW (PPCReg FRt, PPCReg FRb); - void STFIWX (PPCReg FRt, PPCReg FRa, PPCReg FRb); - - // Fpu - void FNEG (PPCReg FRt, PPCReg FRb); - void FABS (PPCReg FRt, PPCReg FRb); - void FNABS (PPCReg FRt, PPCReg FRb); - void FCPSGN (PPCReg FRt, PPCReg FRb); - - // Fpu arith - void FADD (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FSUB (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FADDS (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FSUBS (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FMUL (PPCReg FRt, PPCReg FRa, PPCReg FRc); - void FMULS (PPCReg FRt, PPCReg FRa, PPCReg FRc); - void FDIV (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FDIVS (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FSQRT (PPCReg FRt, PPCReg FRb); - void FSQRTS (PPCReg FRt, PPCReg FRb); - void FSQRTE (PPCReg FRt, PPCReg FRb); - void FSQRTES(PPCReg FRt, PPCReg FRb); - void FRE (PPCReg FRt, PPCReg FRb); - void FRES (PPCReg FRt, PPCReg FRb); - - // FSEL ... - void FSEL (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb); - void FMIN (PPCReg FRt, PPCReg FRa, PPCReg FRb); - void FMAX (PPCReg FRt, PPCReg FRa, PPCReg FRb); - - // Fpu mul add - void FMADD (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb); - void FMSUB (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb); - void FMADDS (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb); - void FMSUBS (PPCReg FRt, PPCReg FRa, PPCReg FRc, PPCReg FRb); - - // Fpu compare - void FCMPU (int Bf, PPCReg FRa, PPCReg FRb); // unordered - void FCMPO (int Bf, PPCReg FRa, PPCReg FRb); // ordered - - // Fpu convert - void FRIN (PPCReg FRt, PPCReg FRb); // round - void FRIZ (PPCReg FRt, PPCReg FRb); // trunc - void FRIP (PPCReg FRt, PPCReg FRb); // ceil - void FRIM (PPCReg FRt, PPCReg FRb); // floor - - - // VPU - lvx128 - void LoadVector(PPCReg Rd, PPCReg Ra, PPCReg Rb); - void SaveVector(PPCReg Rd, PPCReg Ra, PPCReg Rb); - void LoadVectorSwap(PPCReg Rd, PPCReg Ra, PPCReg Rb); - void SaveVectorSwap(PPCReg Rd, PPCReg Ra, PPCReg Rb); - - void MOVI2V (PPCReg dest, float imm); - - void VADDFP (PPCReg Rd, PPCReg Ra); // Vector Add Floating Point - void VMADDFP (PPCReg Rd, PPCReg Ra, PPCReg Rb); // Vector Multiply Add Floating Point - void VMAXFP (PPCReg Rd, PPCReg Ra); // Vector Maximum Floating Point - void VMINFP (PPCReg Rd, PPCReg Ra); // Vector Minimum Floating Point - void VMSUM3FP (PPCReg Rd, PPCReg Ra); // 3-operand Dot Product - void VMSUM4FP (PPCReg Rd, PPCReg Ra); // 4-operand Dot Product - void VMULFP (PPCReg Rd, PPCReg Ra); // Vector Multiply Floating Point - void VNMSUBFP (PPCReg Rd, PPCReg Ra, PPCReg Rb); // Vector Negate Multiply-Subtract Floating Point - void VSUBFP (PPCReg Rd, PPCReg Ra); // Vector Subtract Floating Point - - void VCMPBFP (PPCReg Rd, PPCReg Ra); // Vector Compare Bounds Floating Point - void VCMPEQFP (PPCReg Rd, PPCReg Ra); // Vector Compare Equal-to-Floating Point - void VCMPGEFP (PPCReg Rd, PPCReg Ra); // Vector Compare Greater-Than-or-Equal-to Floating Point - void VCMPGTFP (PPCReg Rd, PPCReg Ra); // Vector Compare Greater-Than Floating Point - - - - void QuickCallFunction(void *func); - protected: - - }; // class PPCXEmitter - - - // You get memory management for free, plus, you can use all the MOV etc functions without - // having to prefix them with gen-> or something similar. - class PPCXCodeBlock : public PPCXEmitter - { - protected: - u8 *region; - size_t region_size; - - public: - PPCXCodeBlock() : region(NULL), region_size(0) {} - virtual ~PPCXCodeBlock() { if (region) FreeCodeSpace(); } - - // Call this before you generate any code. - void AllocCodeSpace(int size) - { - region_size = size; - region = (u8*)AllocateExecutableMemory(region_size); - SetCodePtr(region); - } - - // Always clear code space with breakpoints, so that if someone accidentally executes - // uninitialized, it just breaks into the debugger. - void ClearCodeSpace() - { - // x86/64: 0xCC = breakpoint - memset(region, 0xCC, region_size); - ResetCodePtr(); - } - - // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. - void FreeCodeSpace() - { - region = NULL; - region_size = 0; - } - - bool IsInSpace(const u8 *ptr) const - { - return ptr >= region && ptr < region + region_size; - } - - // Cannot currently be undone. Will write protect the entire code region. - // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). - void WriteProtect() - { - //WriteProtectMemory(region, region_size, true); - } - void UnWriteProtect() - { - //UnWriteProtectMemory(region, region_size, false); - } - - void ResetCodePtr() - { - SetCodePtr(region); - } - - size_t GetSpaceLeft() const - { - return region_size - (GetCodePtr() - region); - } - - u8 *GetBasePtr() { - return region; - } - - size_t GetOffset(const u8 *ptr) const { - return ptr - region; - } - }; - -} // namespace diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 25bdcf7f2b..33696580ce 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -807,8 +807,6 @@ static int Hook_kankabanchoutbr_download_frame() { #define JITFUNC(f) (&MIPSComp::Jit::f) #elif defined(MIPS) #define JITFUNC(f) (&MIPSComp::Jit::f) -#elif defined(PPC) -#define JITFUNC(f) (&MIPSComp::Jit::f) #endif // Can either replace with C functions or functions emitted in Asm/ArmAsm. diff --git a/Core/MIPS/JitCommon/JitBlockCache.cpp b/Core/MIPS/JitCommon/JitBlockCache.cpp index 8082263d07..01b3ba06a3 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.cpp +++ b/Core/MIPS/JitCommon/JitBlockCache.cpp @@ -49,8 +49,6 @@ #elif defined(_M_IX86) || defined(_M_X64) #include "Common/x64Analyzer.h" #include "Core/MIPS/x86/Asm.h" -#elif defined(PPC) -#include "Core/MIPS/MIPS.h" #else #warning "Unsupported arch!" #include "Core/MIPS/MIPS.h" @@ -425,7 +423,7 @@ void JitBlockCache::LinkBlockExits(int i) { } while ((op & 0xFF000000) != 0xEA000000); emit.BKPT(1); emit.FlushIcache(); - + b.linkStatus[e] = true; #elif defined(_M_IX86) || defined(_M_X64) XEmitter emit(b.exitPtrs[e]); // Okay, this is a bit ugly, but we check here if it already has a JMP. @@ -440,12 +438,8 @@ void JitBlockCache::LinkBlockExits(int i) { emit.INT3(); } } -#elif defined(PPC) - PPCXEmitter emit(b.exitPtrs[e]); - emit.B(blocks_[destinationBlock].checkedEntry); - emit.FlushIcache(); -#endif b.linkStatus[e] = true; +#endif } } } @@ -590,12 +584,6 @@ void JitBlockCache::DestroyBlock(int block_num, bool invalidate) { XEmitter emit((u8 *)b->checkedEntry); emit.MOV(32, M(&mips_->pc), Imm32(b->originalAddress)); emit.JMP(MIPSComp::jit->Asm().dispatcher, true); -#elif defined(PPC) - PPCXEmitter emit((u8 *)b->checkedEntry); - emit.MOVI2R(R3, b->originalAddress); - emit.STW(R0, CTXREG, offsetof(MIPSState, pc)); - emit.B(MIPSComp::jit->dispatcher); - emit.FlushIcache(); #endif } @@ -631,8 +619,8 @@ int JitBlockCache::GetBlockExitSize() { return 0; #elif defined(_M_IX86) || defined(_M_X64) return 15; -#elif defined(PPC) - // TODO +#else +#warning GetBlockExitSize unimplemented return 0; #endif } diff --git a/Core/MIPS/JitCommon/JitBlockCache.h b/Core/MIPS/JitCommon/JitBlockCache.h index 937874cd13..ae2db1e304 100644 --- a/Core/MIPS/JitCommon/JitBlockCache.h +++ b/Core/MIPS/JitCommon/JitBlockCache.h @@ -42,10 +42,6 @@ typedef ArmGen::ARMXCodeBlock NativeCodeBlock; #include "Common/x64Emitter.h" namespace Gen { class XEmitter; } typedef Gen::XCodeBlock NativeCodeBlock; -#elif defined(PPC) -#include "Common/ppcEmitter.h" -namespace PpcGen { class PPCXEmitter; } -typedef PpcGen::PPCXCodeBlock NativeCodeBlock; #elif defined(MIPS) #include "Common/MipsEmitter.h" namespace MIPSGen { class MIPSEmitter; } diff --git a/Core/MIPS/JitCommon/NativeJit.h b/Core/MIPS/JitCommon/NativeJit.h index d87e0ddab2..bcc611957c 100644 --- a/Core/MIPS/JitCommon/NativeJit.h +++ b/Core/MIPS/JitCommon/NativeJit.h @@ -23,10 +23,7 @@ struct JitBlock; #undef emit #endif -#if defined(PPC) -#include "../PPC/PpcJit.h" -typedef MIPSComp::Jit NativeJit; -#elif defined(ARM) +#if defined(ARM) #include "../ARM/ArmJit.h" typedef MIPSComp::ArmJit NativeJit; #elif defined(_M_IX86) || defined(_M_X64) diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index c6a61fbb3a..10599a8b8f 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -94,8 +94,8 @@ struct MIPSInstruction { #define JITFUNC(f) (&Jit::f) #elif defined(MIPS) #define JITFUNC(f) (&Jit::f) -#elif defined(PPC) -#define JITFUNC(f) (&Jit::f) +#else +#error Unknown architecture #endif using namespace MIPSDis; diff --git a/Core/MIPS/PPC/PpcAsm.cpp b/Core/MIPS/PPC/PpcAsm.cpp deleted file mode 100644 index 7660f68b22..0000000000 --- a/Core/MIPS/PPC/PpcAsm.cpp +++ /dev/null @@ -1,285 +0,0 @@ -#include "Common/ChunkFile.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - -#include - -using namespace PpcGen; - -extern volatile CoreState coreState; - -static void JitAt() -{ - MIPSComp::jit->Compile(currentMIPS->pc); -} - -namespace MIPSComp -{ -static int dontLogBlocks = 20; -static int logBlocks = 40; - -const u8 *Jit::DoJit(u32 em_address, JitBlock *b) -{ - js.cancel = false; - js.blockStart = js.compilerPC = mips_->pc; - js.downcountAmount = 0; - js.curBlock = b; - js.compiling = true; - js.inDelaySlot = false; - js.PrefixStart(); - - // We add a check before the block, used when entering from a linked block. - b->checkedEntry = GetCodePtr(); - // Downcount flag check. The last block decremented downcounter, and the flag should still be available. - - MOVI2R(SREG, js.blockStart); - - // if (currentMIPS->downcount<0) - CMPI(DCNTREG, 0); - BLT((const void *)outerLoopPCInR0); - - b->normalEntry = GetCodePtr(); - // TODO: this needs work - MIPSAnalyst::AnalysisResults analysis; // = MIPSAnalyst::Analyze(em_address); - - gpr.Start(analysis); - fpr.Start(analysis); - - int numInstructions = 0; - int cycles = 0; - int partialFlushOffset = 0; - if (logBlocks > 0) logBlocks--; - if (dontLogBlocks > 0) dontLogBlocks--; - -// #define LOGASM -#ifdef LOGASM - char temp[256]; -#endif - while (js.compiling) - { - gpr.SetCompilerPC(js.compilerPC); // Let it know for log messages - fpr.SetCompilerPC(js.compilerPC); - MIPSOpcode inst = Memory::Read_Instruction(js.compilerPC); - js.downcountAmount += MIPSGetInstructionCycleEstimate(inst); - - MIPSCompileOp(inst); - - js.compilerPC += 4; - numInstructions++; - } -#ifdef LOGASM - if (logBlocks > 0 && dontLogBlocks == 0) { - for (u32 cpc = em_address; cpc != js.compilerPC + 4; cpc += 4) { - MIPSDisAsm(Memory::Read_Instruction(cpc), cpc, temp, true); - INFO_LOG(JIT, "M: %08x %s", cpc, temp); - } - } -#endif - - b->codeSize = GetCodePtr() - b->normalEntry; - -#ifdef LOGASM - if (logBlocks > 0 && dontLogBlocks == 0) { - INFO_LOG(JIT, "=============== ARM ==============="); - DisassembleArm(b->normalEntry, GetCodePtr() - b->normalEntry); - } -#endif - //DumpJit(); - - AlignCode16(); - - // Don't forget to zap the instruction cache! - FlushIcache(); - - b->originalSize = numInstructions; - return b->normalEntry; -} - -void Jit::DumpJit() { -#ifdef _XBOX - u32 len = (u32)GetCodePtr() - (u32)GetBasePtr(); - FILE * fd; - fd = fopen("game:\\jit.bin", "wb"); - fwrite(GetBasePtr(), len, 1, fd); - fclose(fd); -#endif -} - -void Jit::GenerateFixedCode() { - enterCode = AlignCode16(); - - INFO_LOG(JIT, "Base: %08x", (u32)Memory::base); - INFO_LOG(JIT, "enterCode: 0x%08p", enterCode); - INFO_LOG(JIT, "GetBasePtr: 0x%08p", GetBasePtr()); - - Prologue(); - - // Map fixed register - MOVI2R(BASEREG, (u32)Memory::base); - MOVI2R(CTXREG, (u32)mips_); - MOVI2R(CODEREG, (u32)GetBasePtr()); - - // Update downcount reg value from memory - RestoreDowncount(DCNTREG); - - // SREG = mips->pc - MovFromPC(SREG); - - // Keep current location, TODO rename it, outerLoopPCInR0 to outerLoopPCInR3 ?? - outerLoopPCInR0 = GetCodePtr(); - - // mips->pc = SREG - MovToPC(SREG); - - // Keep current location - outerLoop = GetCodePtr(); - - // Jit loop - // { - // Save downcount reg value to memory - SaveDowncount(DCNTREG); - // Call CoreTiming::Advance() => update donwcount - QuickCallFunction((void *)&CoreTiming::Advance); - // Update downcount reg value from memory - RestoreDowncount(DCNTREG); - - // branch to skipToRealDispatch - FixupBranch skipToRealDispatch = B(); //skip the sync and compare first time - - // Keep current location dispatcherCheckCoreState: - dispatcherCheckCoreState = GetCodePtr(); - - // The result of slice decrementation should be in flags if somebody jumped here - // IMPORTANT - We jump on negative, not carry!!! - // branch to bailCoreState: (jump if(what ??) negative ) - FixupBranch bailCoreState = BLT(); // BLT ??? - - // SREG = coreState - MOVI2R(SREG, (u32)&coreState); - // Compare coreState and CORE_RUNNING - LWZ(SREG, SREG); // SREG = *SREG - CMPI(SREG, 0); // compare 0(CORE_RUNNING) and CR0 - - // branch to badCoreState: (jump if coreState != CORE_RUNNING) - FixupBranch badCoreState = BNE(); - - // branch to skipToRealDispatch2: - FixupBranch skipToRealDispatch2 = B(); //skip the sync and compare first time - - // Keep current location, TODO rename it, outerLoopPCInR0 to outerLoopPCInSREG ?? - dispatcherPCInR0 = GetCodePtr(); - - // mips->pc = SREG - MovToPC(SREG); - - // At this point : flags = EQ. Fine for the next check, no need to jump over it. - // label dispatcher: - dispatcher = GetCodePtr(); - - // { - // The result of slice decrementation should be in flags if somebody jumped here - // IMPORTANT - We jump on negative, not carry!!! - // label bail: - // arm B_CC(CC_MI); - FixupBranch bail = BLT(); - - // label skipToRealDispatch: - SetJumpTarget(skipToRealDispatch); - - // label skipToRealDispatch2: - SetJumpTarget(skipToRealDispatch2); - - // Keep current location - dispatcherNoCheck = GetCodePtr(); - - // read op - // R3 = mips->pc & Memory::MEMVIEW32_MASK - LWZ(R3, CTXREG, offsetof(MIPSState, pc)); - // & Memory::MEMVIEW32_MASK - RLWINM(R3, R3, 0, 2, 31); - - // R3 = memory::base[r3]; - ADD(R3, BASEREG, R3); - MOVI2R(R0, 0); - LWBRX(R3, R3, R0); - - // R4 = R3 & MIPS_EMUHACK_VALUE_MASK - RLWINM(R4, R3, 0, 6, 31); - - // R3 = R3 & MIPS_EMUHACK_MASK - RLWINM(R3, R3, 0, 0, 6); - - // compare, op == MIPS_EMUHACK_OPCODE - MOVI2R(SREG, MIPS_EMUHACK_OPCODE); - CMPL(R3, SREG); - - // Branch if func block not found - FixupBranch notfound = BNE(); - - // { - // R3 = R4 + GetBasePtr() - ADD(R3, R4, CODEREG); - - MTCTR(R3); - BCTR(); - // } - - // label notfound: - SetJumpTarget(notfound); - - //Ok, no block, let's jit - // Save downcount reg value to memory - SaveDowncount(DCNTREG); - - // Exec JitAt => Compile block ! - QuickCallFunction((void *)&JitAt); - - // Update downcount reg value from memory - RestoreDowncount(DCNTREG); - - // branch to dispatcherNoCheck: - B(dispatcherNoCheck); // no point in special casing this - // } - - // label bail: - SetJumpTarget(bail); - - // label bailCoreState: - SetJumpTarget(bailCoreState); - - // Compare coreState and CORE_RUNNING - MOVI2R(SREG, (u32)&coreState); - LWZ(SREG, SREG); // SREG = *SREG => SREG = coreState - CMPLI(SREG, 0); // compare 0(CORE_RUNNING) and corestate - - BEQ(outerLoop); - // } - - // badCoreState label: - SetJumpTarget(badCoreState); - - // Keep current location - breakpointBailout = GetCodePtr(); - - // mips->downcount = DCNTREG - SaveDowncount(DCNTREG); - - Epilogue(); - - // Go back to caller - BLR(); - - // Don't forget to zap the instruction cache! - FlushIcache(); -} - -} - diff --git a/Core/MIPS/PPC/PpcCompAlu.cpp b/Core/MIPS/PPC/PpcCompAlu.cpp deleted file mode 100644 index 4ddcc26a45..0000000000 --- a/Core/MIPS/PPC/PpcCompAlu.cpp +++ /dev/null @@ -1,562 +0,0 @@ -#include "Common/ChunkFile.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - -/*************************************************************************************************** -* Current issues: -* Comp_RType3(min/max): Can't select start in disgaea -* Comp_ShiftType(srl/srlv?): Crash ridge racer 2 -***************************************************************************************************/ - - -using namespace MIPSAnalyst; -#define _RS MIPS_GET_RS(op) -#define _RT MIPS_GET_RT(op) -#define _RD MIPS_GET_RD(op) -#define _FS MIPS_GET_FS(op) -#define _FT MIPS_GET_FT(op) -#define _FD MIPS_GET_FD(op) -#define _SA MIPS_GET_SA(op) -#define _POS ((op>> 6) & 0x1F) -#define _SIZE ((op>>11) & 0x1F) -#define _IMM16 (signed short)(op & 0xFFFF) -#define _IMM26 (op & 0x03FFFFFF) - -// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. -// Currently known non working ones should have DISABLE. - -//#define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; -#define DISABLE { Comp_Generic(op); return; } - -namespace MIPSComp -{ - - static u32 EvalOr(u32 a, u32 b) { return a | b; } - static u32 EvalXor(u32 a, u32 b) { return a ^ b; } - static u32 EvalAnd(u32 a, u32 b) { return a & b; } - static u32 EvalAdd(u32 a, u32 b) { return a + b; } - static u32 EvalSub(u32 a, u32 b) { return a - b; } - static u32 EvalNor(u32 a, u32 b) { return ~(a | b); } - - // Utilities to reduce duplicated code - void Jit::CompType3(int rd, int rs, int rt, void (PPCXEmitter::*arith)(PPCReg Rd, PPCReg Ra, PPCReg Rb), u32 (*eval)(u32 a, u32 b), bool isSub) { - if (gpr.IsImm(rs) && gpr.IsImm(rt)) { - gpr.SetImm(rd, (*eval)(gpr.GetImm(rs), gpr.GetImm(rt))); - } else if (gpr.IsImm(rt)) { - u32 rtImm = gpr.GetImm(rt); - gpr.MapDirtyIn(rd, rs); - MOVI2R(SREG, rtImm); - (this->*arith)(gpr.R(rd), gpr.R(rs), SREG); - } else if (gpr.IsImm(rs)) { - u32 rsImm = gpr.GetImm(rs); - gpr.MapDirtyIn(rd, rt); - // TODO: Special case when rsImm can be represented as an Operand2 - MOVI2R(SREG, rsImm); - (this->*arith)(gpr.R(rd), SREG, gpr.R(rt)); - } else { - // Generic solution - gpr.MapDirtyInIn(rd, rs, rt); - (this->*arith)(gpr.R(rd), gpr.R(rs), gpr.R(rt)); - } - } - - void Jit::CompImmLogic(int rs, int rt, u32 uimm, void (PPCXEmitter::*arith)(PPCReg Rd, PPCReg Ra, unsigned short imm), u32 (*eval)(u32 a, u32 b)) - { - if (gpr.IsImm(rs)) { - gpr.SetImm(rt, (*eval)(gpr.GetImm(rs), uimm)); - } else { - gpr.MapDirtyIn(rt, rs); - (this->*arith)(gpr.R(rt), gpr.R(rs), uimm); - } - } - - void Jit::Comp_IType(MIPSOpcode op) - { - CONDITIONAL_DISABLE; - s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension - u32 uimm = op & 0xFFFF; - u32 suimm = (u32)(s32)simm; - - int rt = _RT; - int rs = _RS; - - int o = op>>26; - - // noop, won't write to ZERO. - if (rt == 0) - return; - - switch (op >> 26) - { - - case 8: // same as addiu? - case 9: // R(rt) = R(rs) + simm; break; //addiu - { - if (gpr.IsImm(rs)) { - gpr.SetImm(rt, gpr.GetImm(rs) + simm); - } else { - gpr.MapDirtyIn(rt, rs); - ADDI(gpr.R(rt), gpr.R(rs), simm); - } - break; - } - - // Use with caution can change CR0 ! - case 12: CompImmLogic(rs, rt, uimm, &PPCXEmitter::ANDI, &EvalAnd); break; - // Safe - case 13: CompImmLogic(rs, rt, uimm, &PPCXEmitter::ORI, &EvalOr); break; - case 14: CompImmLogic(rs, rt, uimm, &PPCXEmitter::XORI, &EvalXor); break; - case 15: // R(rt) = uimm << 16; //lui - gpr.SetImm(rt, uimm << 16); - break; - - case 10: // slti - R(rt) = (s32)R(rs) < simm - if (gpr.IsImm(rs)) - { - gpr.SetImm(rt, (s32)gpr.GetImm(rs) < simm); - break; - } else { - //DISABLE; - gpr.MapDirtyIn(rt, rs); - - PPCReg ppc_rt = gpr.R(rt); - PPCReg ppc_rs = gpr.R(rs); - - MOVI2R(R0, 0); - ADDI(SREG, R0, uimm); - - SUBFC(R0, SREG, ppc_rs); - EQV(ppc_rt, SREG, ppc_rs); - SRWI(ppc_rt, ppc_rt, 31); - ADDZE(ppc_rt, ppc_rt); - RLWINM(ppc_rt, ppc_rt, 0, 31, 31); - //Break(); - break; - } - - case 11: //sltiu - if (gpr.IsImm(rs)) - { - gpr.SetImm(rt, gpr.GetImm(rs) < suimm); - break; - } else { - //DISABLE; - gpr.MapDirtyIn(rt, rs); - - PPCReg ppc_rt = gpr.R(rt); - - ADDI(SREG, R0, suimm); - SUBFC(ppc_rt, SREG, gpr.R(rs)); - SUBFE(ppc_rt, ppc_rt, ppc_rt); - NEG(ppc_rt, ppc_rt); - - break; - } - - default: - Comp_Generic(op); - break; - } - } - - void Jit::Comp_RType2(MIPSOpcode op) { - Comp_Generic(op); - } - - - void Jit::Comp_RType3(MIPSOpcode op) { - CONDITIONAL_DISABLE; - int rt = _RT; - int rs = _RS; - int rd = _RD; - - // noop, won't write to ZERO. - if (rd == 0) - return; - - u8 o = op & 63; - - switch (op & 63) - { - case 10: // if (R(rt) == 0) R(rd) = R(rs); break; //movz - if (rd == rs) - break; - if (!gpr.IsImm(rt)) - { - gpr.MapDirtyInIn(rd, rt, rs, false); - CMPI(gpr.R(rt), 0); - PpcGen::FixupBranch ptr; - - ptr = B_Cond(_BNE); - - MR(gpr.R(rd), gpr.R(rs)); - - SetJumpTarget(ptr); - - } - else if (gpr.GetImm(rt) == 0) - { - // Yes, this actually happens. - if (gpr.IsImm(rs)) - gpr.SetImm(rd, gpr.GetImm(rs)); - else - { - gpr.MapDirtyIn(rd, rs); - MR(gpr.R(rd), gpr.R(rs)); - } - } - break; - - case 11:// if (R(rt) != 0) R(rd) = R(rs); break; //movn - if (rd == rs) - break; - if (!gpr.IsImm(rt)) - { - gpr.MapDirtyInIn(rd, rt, rs, false); - CMPI(gpr.R(rt), 0); - - PpcGen::FixupBranch ptr; - - ptr = B_Cond(_BEQ); - - MR(gpr.R(rd), gpr.R(rs)); - - SetJumpTarget(ptr); - } - else if (gpr.GetImm(rt) != 0) - { - // Yes, this actually happens. - if (gpr.IsImm(rs)) - gpr.SetImm(rd, gpr.GetImm(rs)); - else - { - gpr.MapDirtyIn(rd, rs); - MR(gpr.R(rd), gpr.R(rs)); - } - } - break; - - case 32: //R(rd) = R(rs) + R(rt); break; //add - case 33: //R(rd) = R(rs) + R(rt); break; //addu - // Some optimized special cases - if (gpr.IsImm(rs) && gpr.GetImm(rs) == 0) { - gpr.MapDirtyIn(rd, rt); - MR(gpr.R(rd), gpr.R(rt)); - } else if (gpr.IsImm(rt) && gpr.GetImm(rt) == 0) { - gpr.MapDirtyIn(rd, rs); - MR(gpr.R(rd), gpr.R(rs)); - } else { - CompType3(rd, rs, rt, &PPCXEmitter::ADD, &EvalAdd); - } - break; - case 34: //R(rd) = R(rs) - R(rt); break; //sub - case 35: //R(rd) = R(rs) - R(rt); break; //subu - CompType3(rd, rs, rt, &PPCXEmitter::SUB, &EvalSub, true); - break; - case 36: //R(rd) = R(rs) & R(rt); break; //and - CompType3(rd, rs, rt, &PPCXEmitter::AND, &EvalAnd); - break; - case 37: //R(rd) = R(rs) | R(rt); break; //or - CompType3(rd, rs, rt, &PPCXEmitter::OR, &EvalOr); - break; - case 38: //R(rd) = R(rs) ^ R(rt); break; //xor/eor - CompType3(rd, rs, rt, &PPCXEmitter::XOR, &EvalXor); - break; - // Not tested ! - case 39: // R(rd) = ~(R(rs) | R(rt)); break; //nor - CompType3(rd, rs, rt, &PPCXEmitter::NOR, &EvalNor); - break; - - case 42: //R(rd) = (int)R(rs) < (int)R(rt); break; //slt - if (gpr.IsImm(rs) && gpr.IsImm(rt)) { - gpr.SetImm(rd, (s32)gpr.GetImm(rs) < (s32)gpr.GetImm(rt)); - } else { - gpr.MapDirtyInIn(rd, rs, rt); - - PPCReg ppc_rd = gpr.R(rd); - PPCReg ppc_rs = gpr.R(rs); - PPCReg ppc_rt = gpr.R(rt); - - SUBFC(R0, ppc_rt, ppc_rs); - EQV(ppc_rd, ppc_rt, ppc_rs); - SRWI(ppc_rd, ppc_rd, 31); - ADDZE(ppc_rd, ppc_rd); - RLWINM(ppc_rd, ppc_rd, 0, 31, 31); - } - - break; - - case 43: //R(rd) = R(rs) < R(rt); break; //sltu - if (gpr.IsImm(rs) && gpr.IsImm(rt)) { - gpr.SetImm(rd, gpr.GetImm(rs) < gpr.GetImm(rt)); - } else { - gpr.MapDirtyInIn(rd, rs, rt); - - PPCReg ppc_rd = gpr.R(rd); - - SUBFC(ppc_rd, gpr.R(rt), gpr.R(rs)); - SUBFE(ppc_rd, ppc_rd, ppc_rd); - NEG(ppc_rd, ppc_rd); - } - break; - - - case 44:// R(rd) = ((s32)R(rs) > (s32)R(rt)) ? R(rs) : R(rt); break; //max - DISABLE; - if (gpr.IsImm(rs) && gpr.IsImm(rt)) - gpr.SetImm(rd, std::max((s32)gpr.GetImm(rs), (s32)gpr.GetImm(rt))); - else - { - gpr.MapDirtyInIn(rd, rs, rt); - PpcGen::FixupBranch end; - - // by default rd = rt - MR(gpr.R(rd), gpr.R(rt)); - - // if rs > rt => end - CMP(gpr.R(rs), gpr.R(rt)); - end = B_Cond(_BLE); - - // rd = rs - MR(gpr.R(rd), gpr.R(rs)); - - SetJumpTarget(end); - } - break; - - case 45: //min - DISABLE; - if (gpr.IsImm(rs) && gpr.IsImm(rt)) - gpr.SetImm(rd, std::min((s32)gpr.GetImm(rs), (s32)gpr.GetImm(rt))); - else - { - gpr.MapDirtyInIn(rd, rs, rt); - PpcGen::FixupBranch end; - - // by default rd = rt - MR(gpr.R(rd), gpr.R(rt)); - - // if rs < rt => end - CMP(gpr.R(rs), gpr.R(rt)); - end = B_Cond(_BGE); - - // rd = rs - MR(gpr.R(rd), gpr.R(rs)); - - SetJumpTarget(end); - } - break; - - - default: - Comp_Generic(op); - break; - } - } - - /** - * srl/srlv are disabled because they crash rr2 - **/ - void Jit::Comp_ShiftType(MIPSOpcode op) { - CONDITIONAL_DISABLE; - int rs = _RS; - int rd = _RD; - int fd = _FD; - int rt = _RT; - int sa = _SA; - - // noop, won't write to ZERO. - if (rd == 0) - return; - - // WARNING : ROTR - switch (op & 0x3f) - { - case 0: //sll - gpr.MapDirtyIn(rd, rt); - SLWI(gpr.R(rd), gpr.R(rt), sa); - break; - - case 2: - DISABLE; - if (rs == 0) // srl - { - gpr.MapDirtyIn(rd, rt); - SRWI(gpr.R(rd), gpr.R(rt), sa); - //Break(); - break; - } - else // rotr - { - gpr.MapDirtyIn(rd, rt); - ROTRWI(gpr.R(rd), gpr.R(rt), sa); - Break(); - break; - } - - case 3: //sra - gpr.MapDirtyIn(rd, rt); - SRAWI(gpr.R(rd), gpr.R(rt), sa); - break; - - case 4: //sllv - if (gpr.IsImm(rs)) - { - int sa = gpr.GetImm(rs) & 0x1F; - gpr.MapDirtyIn(rd, rt); - SLWI(gpr.R(rd), gpr.R(rt), sa); - break; - } - gpr.MapDirtyInIn(rd, rs, rt); - ANDI(SREG, gpr.R(rs), 0x1F); - SLW(gpr.R(rd), gpr.R(rt), SREG); - break; - - case 6: - DISABLE; - if ( fd == 0) { //srlv - if (gpr.IsImm(rs)) - { - int sa = gpr.GetImm(rs) & 0x1F; - gpr.MapDirtyIn(rd, rt); - SRWI(gpr.R(rd), gpr.R(rt), sa); - break; - } else { - gpr.MapDirtyInIn(rd, rs, rt); - ANDI(SREG, gpr.R(rs), 0x1F); - SRW(gpr.R(rd), gpr.R(rt), SREG); - break; - } - } else { // rotrv - if (gpr.IsImm(rs)) - { - int sa = gpr.GetImm(rs) & 0x1F; - gpr.MapDirtyIn(rd, rt); - ROTRWI(gpr.R(rd), gpr.R(rt), sa); - break; - } - // Not made - DISABLE; - } - break; - - case 7: //srav - if (gpr.IsImm(rs)) - { - int sa = gpr.GetImm(rs) & 0x1F; - gpr.MapDirtyIn(rd, rt); - SRAWI(gpr.R(rd), gpr.R(rt), sa); - break; - } - gpr.MapDirtyInIn(rd, rs, rt); - ANDI(SREG, gpr.R(rs), 0x1F); - SRAW(gpr.R(rd), gpr.R(rt), SREG); - break; - - default: - Comp_Generic(op); - break; - } - } - - void Jit::Comp_Allegrex(MIPSOpcode op) { - Comp_Generic(op); - } - - void Jit::Comp_Allegrex2(MIPSOpcode op) { - Comp_Generic(op); - } - - void Jit::Comp_MulDivType(MIPSOpcode op) { - CONDITIONAL_DISABLE; - MIPSGPReg rt = _RT; - MIPSGPReg rs = _RS; - int rd = _RD; - - switch (op & 63) - { - case 16: // R(rd) = HI; //mfhi - gpr.MapDirtyIn(rd, MIPSREG_HI); - MR(gpr.R(rd), gpr.R(MIPSREG_HI)); - break; - - case 17: // HI = R(rs); //mthi - gpr.MapDirtyIn(MIPSREG_HI, rs); - MR(gpr.R(MIPSREG_HI), gpr.R(rs)); - break; - - case 18: // R(rd) = LO; break; //mflo - gpr.MapDirtyIn(rd, MIPSREG_LO); - MR(gpr.R(rd), gpr.R(MIPSREG_LO)); - break; - - case 19: // LO = R(rs); break; //mtlo - gpr.MapDirtyIn(MIPSREG_LO, rs); - MR(gpr.R(MIPSREG_LO), gpr.R(rs)); - break; - - case 24: //mult (the most popular one). lo,hi = signed mul (rs * rt) - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); - MULLW(gpr.R(MIPSREG_LO), gpr.R(rs), gpr.R(rt)); - MULHW(gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); - break; - - case 25: //multu (2nd) lo,hi = unsigned mul (rs * rt) - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); - MULLW(gpr.R(MIPSREG_LO), gpr.R(rs), gpr.R(rt)); - MULHWU(gpr.R(MIPSREG_HI), gpr.R(rs), gpr.R(rt)); - break; - - case 26: //div - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); - DIVW(gpr.R(MIPSREG_LO), gpr.R(rs), gpr.R(rt)); - MULLW(SREG, gpr.R(rt), gpr.R(MIPSREG_LO)); - SUB(gpr.R(MIPSREG_HI), gpr.R(rs), SREG); - break; - - case 27: //divu - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt); - DIVWU(gpr.R(MIPSREG_LO), gpr.R(rs), gpr.R(rt)); - MULLW(SREG, gpr.R(rt), gpr.R(MIPSREG_LO)); - SUB(gpr.R(MIPSREG_HI), gpr.R(rs), SREG); - break; - - case 28: //madd - DISABLE; - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt, false); - break; - - case 29: //maddu - DISABLE; - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt, false); - break; - - case 46: // msub - DISABLE; - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt, false); - break; - - case 47: // msubu - DISABLE; - gpr.MapDirtyDirtyInIn(MIPSREG_LO, MIPSREG_HI, rs, rt, false); - break; - - default: - DISABLE; - } - } - - void Jit::Comp_Special3(MIPSOpcode op) { - Comp_Generic(op); - } - -} \ No newline at end of file diff --git a/Core/MIPS/PPC/PpcCompBranch.cpp b/Core/MIPS/PPC/PpcCompBranch.cpp deleted file mode 100644 index c46e67fef9..0000000000 --- a/Core/MIPS/PPC/PpcCompBranch.cpp +++ /dev/null @@ -1,435 +0,0 @@ -#include "Common/ChunkFile.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MemMap.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "Core/Reporting.h" -#include "Core/HLE/HLE.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - -#include - - -#define _RS MIPS_GET_RS(op) -#define _RT MIPS_GET_RT(op) -#define _RD MIPS_GET_RD(op) -#define _FS MIPS_GET_FS(op) -#define _FT MIPS_GET_FT(op) -#define _FD MIPS_GET_FD(op) -#define _SA MIPS_GET_SA(op) -#define _POS ((op>> 6) & 0x1F) -#define _SIZE ((op>>11) & 0x1F) -#define _IMM16 (signed short)(op & 0xFFFF) -#define _IMM26 (op & 0x03FFFFFF) - -#define LOOPOPTIMIZATION 0 - -// We can disable nice delay slots. -#define CONDITIONAL_NICE_DELAYSLOT delaySlotIsNice = false; -// #define CONDITIONAL_NICE_DELAYSLOT ; - -#define SHOW_JS_COMPILER_PC { printf("js.compilerPC: %08x\n", js.compilerPC); } - -#define BRANCH_COMPILE_LOG { printf("JIT(%8x): %s => %d - %08x\n", (u32)GetCodePtr() ,__FUNCTION__, cc, js.compilerPC); } - -using namespace MIPSAnalyst; - -using namespace PpcGen; - -namespace MIPSComp -{ - -void Jit::BranchRSRTComp(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely) -{ - if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSRTComp delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart); - return; - } - int offset = (signed short)(op&0xFFFF)<<2; - MIPSGPReg rt = _RT; - MIPSGPReg rs = _RS; - u32 targetAddr = js.compilerPC + offset + 4; - - MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC+4); - bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rt, rs); - CONDITIONAL_NICE_DELAYSLOT; - if (!likely && delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_NICE); - - - if (gpr.IsImm(rt) && gpr.GetImm(rt) == 0) - { - gpr.MapReg(rs); - CMPLI(gpr.R(rs), 0); - } - else if (gpr.IsImm(rs) && gpr.GetImm(rs) == 0) // only these are easily 'flippable' - { - gpr.MapReg(rt); - CMPLI(gpr.R(rt), 0); - } - else - { - gpr.MapInIn(rs, rt); - CMPL(gpr.R(rs), gpr.R(rt)); - } - - PpcGen::FixupBranch ptr; - if (!likely) - { - if (!delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_SAFE_FLUSH); - else - FlushAll(); - ptr = B_Cond(cc); - } - else - { - FlushAll(); - ptr = B_Cond(cc); - CompileDelaySlot(DELAYSLOT_FLUSH); - } - - // Take the branch - WriteExit(targetAddr, 0); - - SetJumpTarget(ptr); - - // Not taken - WriteExit(js.compilerPC+8, 1); - - js.compiling = false; -} - - -void Jit::BranchRSZeroComp(MIPSOpcode op, PpcGen::FixupBranchType cc, bool andLink, bool likely) -{ - if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in RSZeroComp delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart); - return; - } - int offset = (signed short)(op&0xFFFF)<<2; - MIPSGPReg rs = _RS; - u32 targetAddr = js.compilerPC + offset + 4; - - MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); - bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs); - CONDITIONAL_NICE_DELAYSLOT; - if (!likely && delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_NICE); - - gpr.MapReg(rs); - CMPI(gpr.R(rs), 0); - - PpcGen::FixupBranch ptr; - if (!likely) - { - if (!delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_SAFE_FLUSH); - else - FlushAll(); - ptr = B_Cond(cc); - } - else - { - FlushAll(); - ptr = B_Cond(cc); - CompileDelaySlot(DELAYSLOT_FLUSH); - } - - // Take the branch - if (andLink) - { - MOVI2R(SREG, js.compilerPC + 8); - STW(SREG, CTXREG, MIPS_REG_RA * 4); - } - - WriteExit(targetAddr, 0); - - SetJumpTarget(ptr); - - // Not taken - WriteExit(js.compilerPC + 8, 1); - - js.compiling = false; -} - -void Jit::Comp_RelBranch(MIPSOpcode op) { - // The CC flags here should be opposite of the actual branch becuase they skip the branching action. - switch (op>>26) - { - case 4: BranchRSRTComp(op, _BNE, false); break;//beq - case 5: BranchRSRTComp(op, _BEQ, false); break;//bne - - case 6: BranchRSZeroComp(op, _BGT, false, false); break;//blez - case 7: BranchRSZeroComp(op, _BLE, false, false); break;//bgtz - - case 20: BranchRSRTComp(op, _BNE, true); break;//beql - case 21: BranchRSRTComp(op, _BEQ, true); break;//bnel - - case 22: BranchRSZeroComp(op, _BGT, false, true); break;//blezl - case 23: BranchRSZeroComp(op, _BLE, false, true); break;//bgtzl - - default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); - break; - } - js.compiling = false; -} - -void Jit::Comp_RelBranchRI(MIPSOpcode op) { - switch ((op >> 16) & 0x1F) - { - case 0: BranchRSZeroComp(op, _BGE, false, false); break; //if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 4; break;//bltz - case 1: BranchRSZeroComp(op, _BLT, false, false); break; //if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 4; break;//bgez - case 2: BranchRSZeroComp(op, _BGE, false, true); break; //if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 8; break;//bltzl - case 3: BranchRSZeroComp(op, _BLT, false, true); break; //if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 8; break;//bgezl - case 16: BranchRSZeroComp(op, _BGE, true, false); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else PC += 4; break;//bltzal - case 17: BranchRSZeroComp(op, _BLT, true, false); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else PC += 4; break;//bgezal - case 18: BranchRSZeroComp(op, _BGE, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) < 0) DelayBranchTo(addr); else SkipLikely(); break;//bltzall - case 19: BranchRSZeroComp(op, _BLT, true, true); break; //R(MIPS_REG_RA) = PC + 8; if ((s32)R(rs) >= 0) DelayBranchTo(addr); else SkipLikely(); break;//bgezall - default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); - break; - } - js.compiling = false; -} - - -// If likely is set, discard the branch slot if NOT taken. -void Jit::BranchFPFlag(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely) -{ - if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in FPFlag delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart); - return; - } - int offset = (signed short)(op & 0xFFFF) << 2; - u32 targetAddr = js.compilerPC + offset + 4; - - MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); - bool delaySlotIsNice = IsDelaySlotNiceFPU(op, delaySlotOp); - CONDITIONAL_NICE_DELAYSLOT; - if (!likely && delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_NICE); - - FlushAll(); - - LWZ(SREG, CTXREG, offsetof(MIPSState, fpcond)); - // change CR0 - ANDI(SREG, SREG, 1); - - PpcGen::FixupBranch ptr; - if (!likely) - { - if (!delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_SAFE_FLUSH); - ptr = B_Cond(cc); - } - else - { - ptr = B_Cond(cc); - CompileDelaySlot(DELAYSLOT_FLUSH); - } - - // Take the branch - WriteExit(targetAddr, 0); - - SetJumpTarget(ptr); - // Not taken - WriteExit(js.compilerPC + 8, 1); - js.compiling = false; -} - -void Jit::Comp_FPUBranch(MIPSOpcode op) { - switch((op >> 16) & 0x1f) - { - case 0: BranchFPFlag(op, _BNE, false); break; // bc1f - case 1: BranchFPFlag(op, _BEQ, false); break; // bc1t - case 2: BranchFPFlag(op, _BNE, true); break; // bc1fl - case 3: BranchFPFlag(op, _BEQ, true); break; // bc1tl - default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); - break; - } - js.compiling = false; -} - - -// If likely is set, discard the branch slot if NOT taken. -void Jit::BranchVFPUFlag(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely) -{ - if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in VFPU delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart); - return; - } - int offset = (signed short)(op & 0xFFFF) << 2; - u32 targetAddr = js.compilerPC + offset + 4; - - MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); - - bool delaySlotIsNice = IsDelaySlotNiceVFPU(op, delaySlotOp); - CONDITIONAL_NICE_DELAYSLOT; - if (!likely && delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_NICE); - - FlushAll(); - - int imm3 = (op >> 18) & 7; - - - MOVI2R(SREG, (u32)&(mips_->vfpuCtrl[VFPU_CTRL_CC])); - LWZ(SREG, SREG, 0); - // change CR0 - ANDI(SREG, SREG, 1 << imm3); - - PpcGen::FixupBranch ptr; - js.inDelaySlot = true; - if (!likely) - { - if (!delaySlotIsNice) - CompileDelaySlot(DELAYSLOT_SAFE_FLUSH); - ptr = B_Cond(cc); - } - else - { - ptr = B_Cond(cc); - CompileDelaySlot(DELAYSLOT_FLUSH); - } - js.inDelaySlot = false; - - // Take the branch - WriteExit(targetAddr, 0); - - SetJumpTarget(ptr); - - // Not taken - WriteExit(js.compilerPC + 8, 1); - js.compiling = false; -} - -void Jit::Comp_VBranch(MIPSOpcode op) { - switch ((op >> 16) & 3) - { - case 0: BranchVFPUFlag(op, _BNE, false); break; // bvf - case 1: BranchVFPUFlag(op, _BEQ, false); break; // bvt - case 2: BranchVFPUFlag(op, _BNE, true); break; // bvfl - case 3: BranchVFPUFlag(op, _BEQ, true); break; // bvtl - } - js.compiling = false; -} - -void Jit::Comp_Jump(MIPSOpcode op) { - if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in Jump delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart); - return; - } - u32 off = ((op & 0x03FFFFFF) << 2); - u32 targetAddr = (js.compilerPC & 0xF0000000) | off; - - switch (op >> 26) - { - case 2: //j - CompileDelaySlot(DELAYSLOT_NICE); - FlushAll(); - WriteExit(targetAddr, 0); - break; - - case 3: //jal - gpr.MapReg(MIPS_REG_RA, MAP_NOINIT | MAP_DIRTY); - MOVI2R(gpr.R(MIPS_REG_RA), js.compilerPC + 8); - CompileDelaySlot(DELAYSLOT_NICE); - FlushAll(); - WriteExit(targetAddr, 0); - break; - - default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); - break; - } - js.compiling = false; -} - -void Jit::Comp_JumpReg(MIPSOpcode op) { - if (js.inDelaySlot) { - ERROR_LOG_REPORT(JIT, "Branch in JumpReg delay slot at %08x in block starting at %08x", js.compilerPC, js.blockStart); - return; - } - MIPSGPReg rs = _RS; - MIPSGPReg rd = _RD; - - MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4); - bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs); - CONDITIONAL_NICE_DELAYSLOT; - - if (IsSyscall(delaySlotOp)) { - gpr.MapReg(rs); - PPCReg mRs = gpr.R(rs); - MR(FLAGREG, mRs); - MovToPC(FLAGREG); // For syscall to be able to return. - CompileDelaySlot(DELAYSLOT_FLUSH); - return; // Syscall wrote exit code. - } else if (delaySlotIsNice) { - CompileDelaySlot(DELAYSLOT_NICE); - gpr.MapReg(rs); - PPCReg mRs = gpr.R(rs); - MR(FLAGREG, mRs); // Save the destination address through the delay slot. Could use isNice to avoid when the jit is fully implemented - FlushAll(); - } else { - // Delay slot - gpr.MapReg(rs); - PPCReg mRs = gpr.R(rs); - MR(FLAGREG, mRs); // Save the destination address through the delay slot. Could use isNice to avoid when the jit is fully implemented - CompileDelaySlot(DELAYSLOT_NICE); - FlushAll(); - } - - switch (op & 0x3f) - { - case 8: //jr - break; - case 9: //jalr - // mips->reg = js.compilerPC + 8; - MOVI2R(SREG, js.compilerPC + 8); - STW(SREG, CTXREG, (int)rd * 4); - break; - default: - _dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled"); - break; - } - - WriteExitDestInR(FLAGREG); - js.compiling = false; -} - -void Jit::Comp_Syscall(MIPSOpcode op) { - FlushAll(); - - // If we're in a delay slot, this is off by one. - const int offset = js.inDelaySlot ? -1 : 0; - WriteDownCount(offset); - js.downcountAmount = -offset; - - // CallSyscall(op); - MOVI2R(R3, op.encoding); - SaveDowncount(DCNTREG); - QuickCallFunction((void *)&CallSyscall); - RestoreDowncount(DCNTREG); - - WriteSyscallExit(); - js.compiling = false; -} - -void Jit::Comp_Break(MIPSOpcode op) { - Comp_Generic(op); - WriteSyscallExit(); - js.compiling = false; -} - - -} \ No newline at end of file diff --git a/Core/MIPS/PPC/PpcCompFpu.cpp b/Core/MIPS/PPC/PpcCompFpu.cpp deleted file mode 100644 index 7c8bee7cc5..0000000000 --- a/Core/MIPS/PPC/PpcCompFpu.cpp +++ /dev/null @@ -1,463 +0,0 @@ -#include "Common/ChunkFile.h" -#include "Core/Config.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MemMap.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - -#define _RS MIPS_GET_RS(op) -#define _RT MIPS_GET_RT(op) -#define _RD MIPS_GET_RD(op) -#define _FS MIPS_GET_FS(op) -#define _FT MIPS_GET_FT(op) -#define _FD MIPS_GET_FD(op) -#define _SA MIPS_GET_SA(op) -#define _POS ((op>> 6) & 0x1F) -#define _SIZE ((op>>11) & 0x1F) -#define _IMM16 (signed short)(op & 0xFFFF) -#define _IMM26 (op & 0x03FFFFFF) - -// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. -// Currently known non working ones should have DISABLE. - -//#define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; -#define DISABLE { Comp_Generic(op); return; } - -using namespace PpcGen; - -namespace MIPSComp -{ - -void Jit::Comp_FPU3op(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int ft = _FT; - int fs = _FS; - int fd = _FD; - - fpr.MapDirtyInIn(fd, fs, ft); - switch (op & 0x3f) - { - case 0: FADDS(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) + F(ft); //add - case 1: FSUBS(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) - F(ft); //sub - case 2: { //F(fd) = F(fs) * F(ft); //mul - FMULS(fpr.R(fd), fpr.R(fs), fpr.R(ft)); - break; - } - case 3: FDIVS(fpr.R(fd), fpr.R(fs), fpr.R(ft)); break; //F(fd) = F(fs) / F(ft); //div - default: - DISABLE; - return; - } -} - -void Jit::Comp_FPULS(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - s32 offset = (s16)(op & 0xFFFF); - int ft = _FT; - int rs = _RS; - // u32 addr = R(rs) + offset; - // logBlocks = 1; - bool doCheck = false; - - if (!g_Config.bFastMemory) { - DISABLE; - } - - switch(op >> 26) - { - case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1 - fpr.SpillLock(ft); - fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY); - if (gpr.IsImm(rs)) { - u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF; - MOVI2R(SREG, addr); - } else { - gpr.MapReg(rs); - SetRegToEffectiveAddress(SREG, rs, offset); - } - - LoadFloatSwap(fpr.R(ft), BASEREG, SREG); - - fpr.ReleaseSpillLocksAndDiscardTemps(); - break; - - case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1 - fpr.MapReg(ft); - if (gpr.IsImm(rs)) { - u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF; - MOVI2R(SREG, addr); - } else { - gpr.MapReg(rs); - SetRegToEffectiveAddress(SREG, rs, offset); - } - - SaveFloatSwap(fpr.R(ft), BASEREG, SREG); - break; - - default: - Comp_Generic(op); - return; - } -} - -#if 0 -/** -This can be made with branch, but i'm trying to do it branch free, not working correctly yet ... -**/ -void Jit::Comp_FPUComp(MIPSOpcode op) { - DISABLE; - CONDITIONAL_DISABLE; - - - int opc = op & 0xF; - if (opc >= 8) opc -= 8; // alias - if (opc == 0) { // f, sf (signalling false) - MOVI2R(SREG, 0); - STW(SREG, CTXREG, offsetof(MIPSState, fpcond)); - return; - } - - int fs = _FS; - int ft = _FT; - fpr.MapInIn(fs, ft); - - PPCReg _tmp = FPR8; - PPCReg _zero = FPR6; - PPCReg _one = FPR7; - - //VCMP(fpr.R(fs), fpr.R(ft)); - //VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags). - - /** - Condition-Register Field and Floating-Point Condition Code Interpretation - Bit Name Description - 1000 FL (FRA) < (FRB) - 0100 FG (FRA) > (FRB) - 0010 FE (FRA) = (FRB) - 0001 FU (FRA) ? (FRB) (unordered) - **/ - - switch(opc) - { - // OK - case 1: // un, ngle (unordered) - FCMPU(0, fpr.R(fs), fpr.R(ft)); - MFCR(SREG); - SRAWI(SREG, SREG, 28); - ANDI(SREG, SREG, 0x1); - break; - // FAIL - case 2: //eq, seq (equal, ordered) - DISABLE; - //Break(); - FCMPO(0, fpr.R(fs), fpr.R(ft)); - MFCR(SREG); - SRAWI(SREG, SREG, 28); - SRAWI(SREG, SREG, 2); - ANDI(SREG, SREG, 0x1); - break; - // FAIL - case 3: // ueq, ngl (equal, unordered) - DISABLE; - //Break(); - FCMPU(0, fpr.R(fs), fpr.R(ft)); - MFCR(R7); - SRAWI(R7, R7, 28); - - SRAWI(SREG, R7, 2); - ANDI(SREG, SREG, 0x1); - - // check unordered - ANDI(R7, R7, 0x1); - // SREG = ((R7 >> 2) & 1) || ((R8 >> 3) & 1) - OR(SREG, R7, SREG); - return; - // OK - case 4: // olt, lt (less than, ordered) - //DISABLE; - //Break(); - FCMPO(0, fpr.R(fs), fpr.R(ft)); - MFCR(SREG); - - SRAWI(SREG, SREG, 28); - SRAWI(SREG, SREG, 3); - - // SREG = SREG & 1 - ANDI(SREG, SREG, 0x1); - break; - // OK - case 5: // ult, nge (less than, unordered) - //DISABLE; - //Break(); - FCMPO(0, fpr.R(fs), fpr.R(ft)); - MFCR(R7); - SRAWI(R7, R7, 28); - - // SREG = SREG & 1 - SRAWI(SREG, R7, 3); - ANDI(SREG, SREG, 0x1); - - // check unordered - ANDI(R7, R7, 0x1); - - // final - OR(SREG, R7, SREG); - break; - // FAIL - case 6: // ole, le (less equal, ordered) - DISABLE; - //Break(); - FCMPO(0, fpr.R(ft), fpr.R(fs)); - MFCR(SREG); - SRAWI(SREG, SREG, 28); - - // SREG = (SREG >> 1) & 1 - SRAWI(SREG, SREG, 3); - ANDI(SREG, SREG, 0x1); - break; - // FAIL - case 7: // ule, ngt (less equal, unordered) - DISABLE; - //Break(); - FCMPO(0, fpr.R(ft), fpr.R(fs)); - MFCR(R7); - SRAWI(R7, R7, 28); - - // SREG = (SREG >> 1) & 1 - SRAWI(SREG, R7, 1); - ANDI(SREG, SREG, 0x1); - // check unordered - // R8 = (R7 >> 3) & 1 - SRAWI(R8, R7, 3); - ANDI(R8, R8, 0x1); - // SREG = (R7 & 1) || ((R8 >> 3) & 1) - OR(SREG, R7, R8); - break; - default: - Comp_Generic(op); - return; - } - STW(SREG, CTXREG, offsetof(MIPSState, fpcond)); -} -#else -/** -* 2nd attempt -**/ -void Jit::FPUComp(int fs, int ft, PpcGen::FixupBranchType cond, bool unorderer, int bf) { - PpcGen::FixupBranch ptr; - - // Default result - MOVI2R(SREG, 1); - - // Compare - FCMPU(0, fpr.R(fs), fpr.R(ft)); - - if (unorderer) { - // 3 = UN - CROR(bf, bf, 3); - } - - // If result is good jump - ptr = B_Cond(cond); - - MOVI2R(SREG, 0); - - SetJumpTarget(ptr); -} - -/** https://github.com/gligli/mupen64-360/blob/42bf04f370f00f16be17f3ba9f74b420a7d86422/source/r4300/ppc/MIPS-to-PPC.c#L2916 **/ -/** -Condition-Register Field and Floating-Point Condition Code Interpretation -Bit Name Description -0 FL (FRA) < (FRB) -1 FG (FRA) > (FRB) -2 FE (FRA) = (FRB) -3 FU (FRA) ? (FRB) (unordered) -**/ -void Jit::Comp_FPUComp(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int opc = op & 0xF; - if (opc >= 8) opc -= 8; // alias - if (opc == 0) { // f, sf (signalling false) - MOVI2R(SREG, 0); - STW(SREG, CTXREG, offsetof(MIPSState, fpcond)); - return; - } - - int fs = _FS; - int ft = _FT; - fpr.MapInIn(fs, ft); - - switch(opc) - { - // FAIL - case 1: // un, ngle (unordered) - DISABLE; - break; - // OK - case 2: //eq, seq (equal, ordered) - FPUComp(fs, ft, _BEQ); - break; - // FAIL - case 3: // ueq, ngl (equal, unordered) - FPUComp(fs, ft, _BEQ, true, 2); - break; - // OK - case 4: // olt, lt (less than, ordered) - FPUComp(fs, ft, _BLT); - break; - // FAIL - case 5: // ult, nge (less than, unordered) - FPUComp(fs, ft, _BLT, true, 0); - break; - // OK - case 6: // ole, le (less equal, ordered) - FPUComp(fs, ft, _BLE, true, 1); - break; - // FAIL - case 7: // ule, ngt (less equal, unordered) - FPUComp(fs, ft, _BLE); - break; - default: - Comp_Generic(op); - return; - } - STW(SREG, CTXREG, offsetof(MIPSState, fpcond)); -} - -#endif - -void Jit::Comp_FPU2op(MIPSOpcode op) { - DISABLE - CONDITIONAL_DISABLE; - - int fs = _FS; - int fd = _FD; - - switch (op & 0x3f) - { - case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt - fpr.MapDirtyIn(fd, fs); - FSQRTS(fpr.R(fd), fpr.R(fs)); - break; - case 5: //F(fd) = fabsf(F(fs)); break; //abs - fpr.MapDirtyIn(fd, fs); - FABS(fpr.R(fd), fpr.R(fs)); - break; - case 6: //F(fd) = F(fs); break; //mov - fpr.MapDirtyIn(fd, fs); - FMR(fpr.R(fd), fpr.R(fs)); - break; - case 7: //F(fd) = -F(fs); break; //neg - fpr.MapDirtyIn(fd, fs); - FNEG(fpr.R(fd), fpr.R(fs)); - break; - - case 13: // FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break; //trunc.w.s - fpr.MapDirtyIn(fd, fs); - FRIZ(fpr.R(fd), fpr.R(fs)); - break; - /* - case 12: // FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s - case 14: // FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s - case 15: // FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s - case 32: // F(fd) = (float)FsI(fs); break; //cvt.s.w - - case 36: - //switch (currentMIPS->fcr31 & 3) - //{ - //case 0: FsI(fd) = (int)round_ieee_754(F(fs)); break; // RINT_0 - //case 1: FsI(fd) = (int)F(fs); break; // CAST_1 - //case 2: FsI(fd) = (int)ceilf(F(fs)); break; // CEIL_2 - //case 3: FsI(fd) = (int)floorf(F(fs)); break; // FLOOR_3 - //} - //break; //cvt.w.s - */ - default: - Comp_Generic(op); - break; - } -} - -/** -Seem to work -**/ -void Jit::Comp_mxc1(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int fs = _FS; - MIPSGPReg rt = _RT; - - switch ((op >> 21) & 0x1f) - { - case 0: // R(rt) = FI(fs); break; //mfc1 - // Let's just go through RAM for now. - fpr.FlushR(fs); - gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); - LWZ(gpr.R(rt), CTXREG, fpr.GetMipsRegOffset(fs)); - return; - - case 2: //cfc1 - if (fs == 31) - { - /* Todo Lazy code ! */ - gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT); - PPCReg _rt = gpr.R(rt); - - // SREG = fpcond & 1; - LWZ(SREG, CTXREG, offsetof(MIPSState, fpcond)); - ANDI(SREG, SREG, 1); // Just in case - // SREG << 23 - SLWI(SREG, SREG, 23); - - // RT = fcr31 & ~(1<<23) - LWZ(_rt, CTXREG, offsetof(MIPSState, fcr31)); - RLWINM(_rt, _rt, 0, 9, 7); - - // RT = RT | SREG - OR(_rt, _rt, SREG); - } else if (fs == 0) { - gpr.SetImm(rt, MIPSState::FCR0_VALUE); - } else { - // Unsupported regs are always 0. - gpr.SetImm(rt, 0); - } - return; - - case 4: //FI(fs) = R(rt); break; //mtc1 - // Let's just go through RAM for now. - gpr.FlushR(rt); - fpr.MapReg(fs, MAP_DIRTY | MAP_NOINIT); - LFS(fpr.R(fs), CTXREG, gpr.GetMipsRegOffset(rt)); - return; - - case 6: //ctc1 - if (fs == 31) - { - gpr.MapReg(rt, 0); - - // Update MIPS state - // fcr31 = rt - STW(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31)); - - // fpcond = (rt >> 23) & 1; - SRWI(SREG, gpr.R(rt), 23); - ANDI(SREG, SREG, 1); - STW(SREG, CTXREG, offsetof(MIPSState, fpcond)); - } - return; - } -} - -} \ No newline at end of file diff --git a/Core/MIPS/PPC/PpcCompLoadStore.cpp b/Core/MIPS/PPC/PpcCompLoadStore.cpp deleted file mode 100644 index 1b02ea8c5d..0000000000 --- a/Core/MIPS/PPC/PpcCompLoadStore.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "Common/ChunkFile.h" -#include "Core/Config.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - - -#define _RS ((op>>21) & 0x1F) -#define _RT ((op>>16) & 0x1F) -#define _RD ((op>>11) & 0x1F) -#define _FS ((op>>11) & 0x1F) -#define _FT ((op>>16) & 0x1F) -#define _FD ((op>>6 ) & 0x1F) -#define _POS ((op>>6 ) & 0x1F) -#define _SIZE ((op>>11) & 0x1F) - -// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. -// Currently known non working ones should have DISABLE. - -//#define CONDITIONAL_DISABLE { Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; -#define DISABLE { Comp_Generic(op); return; } - -using namespace PpcGen; - -namespace MIPSComp -{ - -void Jit::SetRegToEffectiveAddress(PpcGen::PPCReg r, int rs, s16 offset) { - if (offset) { - ADDI(SREG, gpr.R(rs), offset); - RLWINM(SREG, SREG, 0, 2, 31); // &= 0x3FFFFFFF - } else { - RLWINM(SREG, gpr.R(rs), 0, 2, 31); // &= 0x3FFFFFFF - } - -} -void Jit::Comp_ITypeMem(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int offset = (signed short)(op&0xFFFF); - bool load = false; - int rt = _RT; - int rs = _RS; - int o = op>>26; - if (((op >> 29) & 1) == 0 && rt == 0) { - // Don't load anything into $zr - return; - } - - if (!g_Config.bFastMemory) { - DISABLE; - } - - u32 iaddr = gpr.IsImm(rs) ? offset + gpr.GetImm(rs) : 0xFFFFFFFF; - bool doCheck = false; - - switch (o) - { - case 32: //lb - case 33: //lh - case 35: //lw - case 36: //lbu - case 37: //lhu - load = true; - case 40: //sb - case 41: //sh - case 43: //sw - - if (gpr.IsImm(rs) && Memory::IsValidAddress(iaddr)) { - // We can compute the full address at compile time. Kickass. - u32 addr = iaddr & 0x3FFFFFFF; - // Must be OK even if rs == rt since we have the value from imm already. - gpr.MapReg(rt, load ? MAP_NOINIT | MAP_DIRTY : 0); - MOVI2R(SREG, addr); - } else { - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address? CPU bug?"); - load ? gpr.MapDirtyIn(rt, rs) : gpr.MapInIn(rt, rs); - - SetRegToEffectiveAddress(SREG, rs, offset); - } - switch (o) - { - // Load - case 32: //lb - LBZX(gpr.R(rt), BASEREG, SREG); - EXTSB(gpr.R(rt), gpr.R(rt)); - break; - case 33: //lh - LHBRX(gpr.R(rt), BASEREG, SREG); - EXTSH(gpr.R(rt), gpr.R(rt)); - break; - case 35: //lw - LWBRX(gpr.R(rt), BASEREG, SREG); - break; - case 36: //lbu - LBZX (gpr.R(rt), BASEREG, SREG); - break; - case 37: //lhu - LHBRX (gpr.R(rt), BASEREG, SREG); - break; - // Store - case 40: //sb - STBX (gpr.R(rt), BASEREG, SREG); - break; - case 41: //sh - STHBRX(gpr.R(rt), BASEREG, SREG); - break; - case 43: //sw - STWBRX(gpr.R(rt), BASEREG, SREG); - break; - } - break; - case 34: //lwl - case 38: //lwr - load = true; - case 42: //swl - case 46: //swr - if (!js.inDelaySlot) { - // Optimisation: Combine to single unaligned load/store - bool isLeft = (o == 34 || o == 42); - MIPSOpcode nextOp = Memory::Read_Instruction(js.compilerPC + 4); - // Find a matching shift in opposite direction with opposite offset. - if (nextOp == (isLeft ? (op.encoding + (4<<26) - 3) - : (op.encoding - (4<<26) + 3))) - { - EatInstruction(nextOp); - nextOp = MIPSOpcode(((load ? 35 : 43) << 26) | ((isLeft ? nextOp : op) & 0x03FFFFFF)); //lw, sw - Comp_ITypeMem(nextOp); - return; - } - } - - DISABLE; // Disabled until crashes are resolved. - break; - default: - Comp_Generic(op); - return ; - } - } - - void Jit::Comp_Cache(MIPSOpcode op) { - DISABLE; - } -} diff --git a/Core/MIPS/PPC/PpcCompReplace.cpp b/Core/MIPS/PPC/PpcCompReplace.cpp deleted file mode 100644 index a000093a85..0000000000 --- a/Core/MIPS/PPC/PpcCompReplace.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include -#include "math/math_util.h" - -#include "Core/MemMap.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSAnalyst.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Common/CPUDetect.h" -#include "Core/Config.h" -#include "Core/Reporting.h" -#include "Core/MIPS/JitCommon/JitCommon.h" - -namespace MIPSComp { - -int Jit::Replace_fabsf() { - return -1; - // fpr.MapDirtyIn(0, 13); - // VABS(fpr.R(0), fpr.R(13)); - // return 6; // Number of instructions in the MIPS function -} - -} \ No newline at end of file diff --git a/Core/MIPS/PPC/PpcCompVFPU.cpp b/Core/MIPS/PPC/PpcCompVFPU.cpp deleted file mode 100644 index d9ce40baa1..0000000000 --- a/Core/MIPS/PPC/PpcCompVFPU.cpp +++ /dev/null @@ -1,1219 +0,0 @@ - -#include "math/math_util.h" - -#include "Common/ChunkFile.h" -#include "Core/Config.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - -const bool disablePrefixes = false; - -// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. -// Currently known non working ones should have DISABLE. - -// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocks(); Comp_Generic(op); return; } -#define CONDITIONAL_DISABLE ; -#define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; } - -#define _RS MIPS_GET_RS(op) -#define _RT MIPS_GET_RT(op) -#define _RD MIPS_GET_RD(op) -#define _FS MIPS_GET_FS(op) -#define _FT MIPS_GET_FT(op) -#define _FD MIPS_GET_FD(op) -#define _SA MIPS_GET_SA(op) -#define _POS ((op>> 6) & 0x1F) -#define _SIZE ((op>>11) & 0x1F) -#define _IMM16 (signed short)(op & 0xFFFF) -#define _IMM26 (op & 0x03FFFFFF) - -using namespace PpcGen; - -// #define USE_VMX128 - -namespace MIPSComp -{ - // Vector regs can overlap in all sorts of swizzled ways. - // This does allow a single overlap in sregs[i]. - static bool IsOverlapSafeAllowS(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) - { - for (int i = 0; i < sn; ++i) - { - if (sregs[i] == dreg && i != di) - return false; - } - for (int i = 0; i < tn; ++i) - { - if (tregs[i] == dreg) - return false; - } - - // Hurray, no overlap, we can write directly. - return true; - } - - static bool IsOverlapSafe(int dreg, int di, int sn, u8 sregs[], int tn = 0, u8 tregs[] = NULL) - { - return IsOverlapSafeAllowS(dreg, di, sn, sregs, tn, tregs) && sregs[di] != dreg; - } - - void Jit::ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz) { - if (prefix == 0xE4) return; - - int n = GetNumVectorElements(sz); - u8 origV[4]; - static const float constantArray[8] = {0.f, 1.f, 2.f, 0.5f, 3.f, 1.f/3.f, 0.25f, 1.f/6.f}; - - for (int i = 0; i < n; i++) - origV[i] = vregs[i]; - - for (int i = 0; i < n; i++) - { - int regnum = (prefix >> (i*2)) & 3; - int abs = (prefix >> (8+i)) & 1; - int negate = (prefix >> (16+i)) & 1; - int constants = (prefix >> (12+i)) & 1; - - // Unchanged, hurray. - if (!constants && regnum == i && !abs && !negate) - continue; - - // This puts the value into a temp reg, so we won't write the modified value back. - vregs[i] = fpr.GetTempV(); - if (!constants) { - fpr.MapDirtyInV(vregs[i], origV[regnum]); - fpr.SpillLockV(vregs[i]); - - // Prefix may say "z, z, z, z" but if this is a pair, we force to x. - // TODO: But some ops seem to use const 0 instead? - if (regnum >= n) { - WARN_LOG(CPU, "JIT: Invalid VFPU swizzle: %08x : %d / %d at PC = %08x (%s)", prefix, regnum, n, js.compilerPC, currentMIPS->DisasmAt(js.compilerPC)); - regnum = 0; - } - - if (abs) { - FABS(fpr.V(vregs[i]), fpr.V(origV[regnum])); - if (negate) - FNEG(fpr.V(vregs[i]), fpr.V(vregs[i])); - } else { - if (negate) - FNEG(fpr.V(vregs[i]), fpr.V(origV[regnum])); - else - FMR(fpr.V(vregs[i]), fpr.V(origV[regnum])); - } - } else { - fpr.MapRegV(vregs[i], MAP_DIRTY | MAP_NOINIT); - fpr.SpillLockV(vregs[i]); - MOVI2F(fpr.V(vregs[i]), constantArray[regnum + (abs<<2)], negate); - } - } - } - - void Jit::GetVectorRegsPrefixD(u8 *regs, VectorSize sz, int vectorReg) { - _assert_(js.prefixDFlag & PpcJitState::PREFIX_KNOWN); - - GetVectorRegs(regs, sz, vectorReg); - if (js.prefixD == 0) - return; - - int n = GetNumVectorElements(sz); - for (int i = 0; i < n; i++) { - // Hopefully this is rare, we'll just write it into a reg we drop. - if (js.VfpuWriteMask(i)) - regs[i] = fpr.GetTempV(); - } - } - - void Jit::ApplyPrefixD(const u8 *vregs, VectorSize sz) { - _assert_(js.prefixDFlag & PpcJitState::PREFIX_KNOWN); - if (!js.prefixD) return; - - int n = GetNumVectorElements(sz); - for (int i = 0; i < n; i++) { - if (js.VfpuWriteMask(i)) - continue; - - // TODO: These clampers are wrong - put this into google - // and look at the plot: abs(x) - abs(x-0.5) + 0.5 - // It's too steep. - - // Also, they mishandle NaN and Inf. - int sat = (js.prefixD >> (i * 2)) & 3; - if (sat == 1) { - fpr.MapRegV(vregs[i], MAP_DIRTY); - - MOVI2F(FPR6, 0.0f); - MOVI2F(FPR7, 1.0f); - - FMAX(fpr.V(vregs[i]), fpr.V(vregs[i]), FPR6); - FMIN(fpr.V(vregs[i]), fpr.V(vregs[i]), FPR7); - } else if (sat == 3) { - fpr.MapRegV(vregs[i], MAP_DIRTY); - - MOVI2F(FPR6, -1.0f); - MOVI2F(FPR7, 1.0f); - - FMAX(fpr.V(vregs[i]), fpr.V(vregs[i]), FPR6); - FMIN(fpr.V(vregs[i]), fpr.V(vregs[i]), FPR7); - } - } - } - - void Jit::Comp_SV(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - s32 imm = (signed short)(op&0xFFFC); - int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5); - int rs = _RS; - - if (!g_Config.bFastMemory) { - DISABLE; - } - - bool doCheck = false; - switch (op >> 26) - { - case 50: //lv.s // VI(vt) = Memory::Read_U32(addr); - { - // CC might be set by slow path below, so load regs first. - fpr.MapRegV(vt, MAP_DIRTY | MAP_NOINIT); - if (gpr.IsImm(rs)) { - u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; - MOVI2R(SREG, addr); - } else { - gpr.MapReg(rs); - SetRegToEffectiveAddress(SREG, rs, imm); - } - - LoadFloatSwap(fpr.V(vt), BASEREG, SREG); - } - break; - - case 58: //sv.s // Memory::Write_U32(VI(vt), addr); - { - // CC might be set by slow path below, so load regs first. - fpr.MapRegV(vt); - if (gpr.IsImm(rs)) { - u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; - MOVI2R(SREG, addr); - } else { - gpr.MapReg(rs); - SetRegToEffectiveAddress(SREG, rs, imm); - } - SaveFloatSwap(fpr.V(vt), BASEREG, SREG); - } - break; - - - default: - DISABLE; - } - } - - void Jit::Comp_SVQ(MIPSOpcode op) { - // Comp_Generic(op); - CONDITIONAL_DISABLE; - - int imm = (signed short)(op&0xFFFC); - int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5); - int rs = _RS; - - if (!g_Config.bFastMemory) { - DISABLE; - } - - bool doCheck = false; - switch (op >> 26) - { - case 54: //lv.q - { - u8 vregs[4]; - GetVectorRegs(vregs, V_Quad, vt); - fpr.MapRegsAndSpillLockV(vregs, V_Quad, MAP_DIRTY | MAP_NOINIT); - - if (gpr.IsImm(rs)) { - u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; - MOVI2R(SREG, addr + (u32)Memory::base); - } else { - gpr.MapReg(rs); - SetRegToEffectiveAddress(SREG, rs, imm); - ADD(SREG, SREG, BASEREG); - } - - for (int i = 0; i < 4; i++) { - MOVI2R(R9, i * 4); - LoadFloatSwap(fpr.V(vregs[i]), SREG, R9); - } - } - break; - - case 62: //sv.q - { - // CC might be set by slow path below, so load regs first. - u8 vregs[4]; - GetVectorRegs(vregs, V_Quad, vt); - fpr.MapRegsAndSpillLockV(vregs, V_Quad, 0); - - if (gpr.IsImm(rs)) { - u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF; - MOVI2R(SREG, addr + (u32)Memory::base); - } else { - gpr.MapReg(rs); - SetRegToEffectiveAddress(SREG, rs, imm); - ADD(SREG, SREG, BASEREG); - } - - for (int i = 0; i < 4; i++) { - MOVI2R(R9, i * 4); - SaveFloatSwap(fpr.V(vregs[i]), SREG, R9); - } - } - break; - - default: - DISABLE; - break; - } - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VPFX(MIPSOpcode op) { - CONDITIONAL_DISABLE; - int data = op & 0xFFFFF; - int regnum = (op >> 24) & 3; - switch (regnum) { - case 0: // S - js.prefixS = data; - js.prefixSFlag = PpcJitState::PREFIX_KNOWN_DIRTY; - break; - case 1: // T - js.prefixT = data; - js.prefixTFlag = PpcJitState::PREFIX_KNOWN_DIRTY; - break; - case 2: // D - js.prefixD = data; - js.prefixDFlag = PpcJitState::PREFIX_KNOWN_DIRTY; - break; - default: - ERROR_LOG(CPU, "VPFX - bad regnum %i : data=%08x", regnum, data); - break; - } - } - - void Jit::Comp_VVectorInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - // WARNING: No prefix support! - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - switch ((op >> 16) & 0xF) - { - case 6: // v=zeros; break; //vzero - MOVI2F(FPR5, 0.0f); - break; - case 7: // v=ones; break; //vone - MOVI2F(FPR5, 1.0f); - break; - default: - DISABLE; - break; - } - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - u8 dregs[4]; - GetVectorRegsPrefixD(dregs, sz, _VD); - fpr.MapRegsAndSpillLockV(dregs, sz, MAP_NOINIT | MAP_DIRTY); - - for (int i = 0; i < n; ++i) - FMR(fpr.V(dregs[i]), FPR5); - - ApplyPrefixD(dregs, sz); - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VMatrixInit(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - MatrixSize sz = GetMtxSize(op); - int n = GetMatrixSide(sz); - - u8 dregs[16]; - GetMatrixRegs(dregs, sz, _VD); - - switch ((op >> 16) & 0xF) { - case 3: // vmidt - MOVI2F(FPR6, 0.0f); - MOVI2F(FPR7, 1.0f); - for (int a = 0; a < n; a++) { - for (int b = 0; b < n; b++) { - fpr.MapRegV(dregs[a * 4 + b], MAP_DIRTY | MAP_NOINIT); - FMR(fpr.V(dregs[a * 4 + b]), a == b ? FPR7 : FPR6); - } - } - break; - case 6: // vmzero - MOVI2F(FPR6, 0.0f); - for (int a = 0; a < n; a++) { - for (int b = 0; b < n; b++) { - fpr.MapRegV(dregs[a * 4 + b], MAP_DIRTY | MAP_NOINIT); - FMR(fpr.V(dregs[a * 4 + b]), FPR6); - } - } - break; - case 7: // vmone - MOVI2F(FPR7, 1.0f); - for (int a = 0; a < n; a++) { - for (int b = 0; b < n; b++) { - fpr.MapRegV(dregs[a * 4 + b], MAP_DIRTY | MAP_NOINIT); - FMR(fpr.V(dregs[a * 4 + b]), FPR7); - } - } - break; - } - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VDot(MIPSOpcode op) { - CONDITIONAL_DISABLE; - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - int vd = _VD; - int vs = _VS; - int vt = _VT; - VectorSize sz = GetVecSize(op); - - // TODO: Force read one of them into regs? probably not. - u8 sregs[4], tregs[4], dregs[1]; - GetVectorRegsPrefixS(sregs, sz, vs); - GetVectorRegsPrefixT(tregs, sz, vt); - GetVectorRegsPrefixD(dregs, V_Single, vd); - - // TODO: applyprefixST here somehow (shuffle, etc...) - fpr.MapRegsAndSpillLockV(sregs, sz, 0); - fpr.MapRegsAndSpillLockV(tregs, sz, 0); - FMULS(FPR6, fpr.V(sregs[0]), fpr.V(tregs[0])); - - int n = GetNumVectorElements(sz); - for (int i = 1; i < n; i++) { - // sum += s[i]*t[i]; - FMADDS(FPR6, fpr.V(sregs[i]), fpr.V(tregs[i]), FPR6); - } - fpr.ReleaseSpillLocksAndDiscardTemps(); - - fpr.MapRegV(dregs[0], MAP_NOINIT | MAP_DIRTY); - - // TODO: applyprefixD here somehow (write mask etc..) - FMR(fpr.V(dregs[0]), FPR6); - ApplyPrefixD(dregs, V_Single); - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VecDo3(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - int vd = _VD; - int vs = _VS; - int vt = _VT; - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - u8 sregs[4], tregs[4], dregs[4]; - GetVectorRegsPrefixS(sregs, sz, _VS); - GetVectorRegsPrefixT(tregs, sz, _VT); - GetVectorRegsPrefixD(dregs, sz, _VD); - - MIPSReg tempregs[4]; - for (int i = 0; i < n; i++) { - if (!IsOverlapSafe(dregs[i], i, n, sregs, n, tregs)) { - tempregs[i] = fpr.GetTempV(); - } else { - tempregs[i] = dregs[i]; - } - } - - for (int i = 0; i < n; i++) { - fpr.MapDirtyInInV(tempregs[i], sregs[i], tregs[i]); - switch (op >> 26) { - case 24: //VFPU0 - switch ((op >> 23)&7) { - case 0: // d[i] = s[i] + t[i]; break; //vadd - FADDS(fpr.V(tempregs[i]), fpr.V(sregs[i]), fpr.V(tregs[i])); - break; - case 1: // d[i] = s[i] - t[i]; break; //vsub - FSUBS(fpr.V(tempregs[i]), fpr.V(sregs[i]), fpr.V(tregs[i])); - break; - case 7: // d[i] = s[i] / t[i]; break; //vdiv - FDIVS(fpr.V(tempregs[i]), fpr.V(sregs[i]), fpr.V(tregs[i])); - break; - default: - DISABLE; - } - break; - case 25: //VFPU1 - switch ((op >> 23) & 7) { - case 0: // d[i] = s[i] * t[i]; break; //vmul - FMULS(fpr.V(tempregs[i]), fpr.V(sregs[i]), fpr.V(tregs[i])); - break; - default: - DISABLE; - } - break; - case 27: //VFPU3 - // DISABLE - - switch ((op >> 23) & 7) { - case 2: // vmin - FMIN(fpr.V(tempregs[i]), fpr.V(sregs[i]), fpr.V(tregs[i])); - break; - case 3: // vmax - FMAX(fpr.V(tempregs[i]), fpr.V(sregs[i]), fpr.V(tregs[i])); - break; - case 6: // vsge - // DISABLE; // pending testing - MOVI2F(FPR6, 1.0f); - MOVI2F(FPR7, 0.0f); - FSUBS(FPR8, fpr.V(sregs[i]), fpr.V(tregs[i])); - FSEL(fpr.V(tempregs[i]), FPR8, FPR6, FPR7); - break; - case 7: // vslt - // DISABLE; // pending testing - MOVI2F(FPR6, 1.0f); - MOVI2F(FPR7, 0.0f); - FSUBS(FPR8, fpr.V(sregs[i]), fpr.V(tregs[i])); - FSEL(fpr.V(tempregs[i]), FPR8, FPR7, FPR6); - break; - } - break; - - default: - DISABLE; - } - } - - for (int i = 0; i < n; i++) { - if (dregs[i] != tempregs[i]) { - fpr.MapDirtyInV(dregs[i], tempregs[i]); - FMR(fpr.V(dregs[i]), fpr.V(tempregs[i])); - } - } - ApplyPrefixD(dregs, sz); - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VV2Op(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - // Pre-processing: Eliminate silly no-op VMOVs, common in Wipeout Pure - if (((op >> 16) & 0x1f) == 0 && _VS == _VD && js.HasNoPrefix()) { - return; - } - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - u8 sregs[4], dregs[4]; - GetVectorRegsPrefixS(sregs, sz, _VS); - GetVectorRegsPrefixD(dregs, sz, _VD); - - MIPSReg tempregs[4]; - for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], i, n, sregs)) { - tempregs[i] = fpr.GetTempV(); - } else { - tempregs[i] = dregs[i]; - } - } - - // Warning: sregs[i] and tempxregs[i] may be the same reg. - // Helps for vmov, hurts for vrcp, etc. - for (int i = 0; i < n; ++i) { - switch ((op >> 16) & 0x1f) { - case 0: // d[i] = s[i]; break; //vmov - // Probably for swizzle. - fpr.MapDirtyInV(tempregs[i], sregs[i]); - FMR(fpr.V(tempregs[i]), fpr.V(sregs[i])); - break; - case 1: // d[i] = fabsf(s[i]); break; //vabs - fpr.MapDirtyInV(tempregs[i], sregs[i]); - FABS(fpr.V(tempregs[i]), fpr.V(sregs[i])); - break; - case 2: // d[i] = -s[i]; break; //vneg - fpr.MapDirtyInV(tempregs[i], sregs[i]); - FNEG(fpr.V(tempregs[i]), fpr.V(sregs[i])); - break; - - /* These are probably just as broken as the prefix. - case 4: // if (s[i] < 0) d[i] = 0; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat0 - fpr.MapDirtyInV(tempregs[i], sregs[i]); - MOVI2F(S0, 0.5f, R0); - VABS(S1, fpr.V(sregs[i])); // S1 = fabs(x) - VSUB(fpr.V(tempregs[i]), fpr.V(sregs[i]), S0); // S2 = fabs(x-0.5f) {VABD} - VABS(fpr.V(tempregs[i]), fpr.V(tempregs[i])); - VSUB(fpr.V(tempregs[i]), S1, fpr.V(tempregs[i])); // v[i] = S1 - S2 + 0.5f - VADD(fpr.V(tempregs[i]), fpr.V(tempregs[i]), S0); - break; - case 5: // if (s[i] < -1.0f) d[i] = -1.0f; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat1 - fpr.MapDirtyInV(tempregs[i], sregs[i]); - MOVI2F(S0, 1.0f, R0); - VABS(S1, fpr.V(sregs[i])); // S1 = fabs(x) - VSUB(fpr.V(tempregs[i]), fpr.V(sregs[i]), S0); // S2 = fabs(x-1.0f) {VABD} - VABS(fpr.V(tempregs[i]), fpr.V(tempregs[i])); - VSUB(fpr.V(tempregs[i]), S1, fpr.V(tempregs[i])); // v[i] = S1 - S2 - break; - */ - - case 16: // d[i] = 1.0f / s[i]; break; //vrcp - fpr.MapDirtyInV(tempregs[i], sregs[i]); - MOVI2F(FPR6, 1.0f); - FDIVS(fpr.V(tempregs[i]), FPR6, fpr.V(sregs[i])); - break; - case 17: // d[i] = 1.0f / sqrtf(s[i]); break; //vrsq - fpr.MapDirtyInV(tempregs[i], sregs[i]); - MOVI2F(FPR6, 1.0f); - FSQRTS(FPR7, fpr.V(sregs[i])); - FDIVS(fpr.V(tempregs[i]), FPR6, FPR7); - break; - case 18: // d[i] = sinf((float)M_PI_2 * s[i]); break; //vsin - DISABLE; - break; - case 19: // d[i] = cosf((float)M_PI_2 * s[i]); break; //vcos - DISABLE; - break; - case 20: // d[i] = powf(2.0f, s[i]); break; //vexp2 - DISABLE; - break; - case 21: // d[i] = logf(s[i])/log(2.0f); break; //vlog2 - DISABLE; - break; - case 22: // d[i] = sqrtf(s[i]); break; //vsqrt - fpr.MapDirtyInV(tempregs[i], sregs[i]); - FSQRTS(fpr.V(tempregs[i]), fpr.V(sregs[i])); - FABS(fpr.V(tempregs[i]), fpr.V(tempregs[i])); - break; - case 23: // d[i] = asinf(s[i] * (float)M_2_PI); break; //vasin - DISABLE; - break; - case 24: // d[i] = -1.0f / s[i]; break; // vnrcp - fpr.MapDirtyInV(tempregs[i], sregs[i]); - MOVI2F(FPR6, -1.0f); - FDIVS(fpr.V(tempregs[i]), FPR6, fpr.V(sregs[i])); - break; - case 26: // d[i] = -sinf((float)M_PI_2 * s[i]); break; // vnsin - DISABLE; - break; - case 28: // d[i] = 1.0f / expf(s[i] * (float)M_LOG2E); break; // vrexp2 - DISABLE; - break; - default: - DISABLE; - break; - } - } - - for (int i = 0; i < n; ++i) { - if (dregs[i] != tempregs[i]) { - fpr.MapDirtyInV(dregs[i], tempregs[i]); - FMR(fpr.V(dregs[i]), fpr.V(tempregs[i])); - } - } - - ApplyPrefixD(dregs, sz); - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Mftv(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int imm = op & 0xFF; - MIPSGPReg rt = _RT; - switch ((op >> 21) & 0x1f) - { - case 3: //mfv / mfvc - // rt = 0, imm = 255 appears to be used as a CPU interlock by some games. - if (rt != 0) { - if (imm < 128) { //R(rt) = VI(imm); - fpr.FlushV(imm); - gpr.MapReg(rt, MAP_NOINIT | MAP_DIRTY); - LWZ(gpr.R(rt), CTXREG, fpr.GetMipsRegOffsetV(imm)); - } else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc - DISABLE; - // In case we have a saved prefix. - //FlushPrefixV(); - //gpr.BindToRegister(rt, false, true); - //MOV(32, gpr.R(rt), M(&mips_->vfpuCtrl[imm - 128])); - } else { - //ERROR - maybe need to make this value too an "interlock" value? - ERROR_LOG(CPU, "mfv - invalid register %i", imm); - } - } - break; - - case 7: // mtv - if (imm < 128) { - gpr.FlushR(rt); - fpr.MapRegV(imm, MAP_DIRTY | MAP_NOINIT); - LFS(fpr.V(imm), CTXREG, gpr.GetMipsRegOffset(rt)); - } else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc //currentMIPS->vfpuCtrl[imm - 128] = R(rt); - gpr.MapReg(rt); - STW(gpr.R(rt), CTXREG, offsetof(MIPSState, vfpuCtrl) + 4 * (imm - 128)); - //gpr.BindToRegister(rt, true, false); - //MOV(32, M(&mips_->vfpuCtrl[imm - 128]), gpr.R(rt)); - - // TODO: Optimization if rt is Imm? - // Set these BEFORE disable! - if (imm - 128 == VFPU_CTRL_SPREFIX) { - js.prefixSFlag = PpcJitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_TPREFIX) { - js.prefixTFlag = PpcJitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_DPREFIX) { - js.prefixDFlag = PpcJitState::PREFIX_UNKNOWN; - } - } else { - //ERROR - _dbg_assert_msg_(CPU,0,"mtv - invalid register"); - } - break; - - default: - DISABLE; - } - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Vmfvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int vs = _VS; - int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { - fpr.MapRegV(vs); - ADDI(SREG, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4); - LFS(fpr.V(vs), SREG, 0); - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - } - - void Jit::Comp_Vmtvc(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - int vs = _VS; - int imm = op & 0xFF; - if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) { - fpr.MapRegV(vs); - ADDI(SREG, CTXREG, offsetof(MIPSState, vfpuCtrl[0]) + (imm - 128) * 4); - SFS(fpr.V(vs), SREG, 0); - fpr.ReleaseSpillLocksAndDiscardTemps(); - - if (imm - 128 == VFPU_CTRL_SPREFIX) { - js.prefixSFlag = PpcJitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_TPREFIX) { - js.prefixTFlag = PpcJitState::PREFIX_UNKNOWN; - } else if (imm - 128 == VFPU_CTRL_DPREFIX) { - js.prefixDFlag = PpcJitState::PREFIX_UNKNOWN; - } - } - } - - void Jit::Comp_Vmmov(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - // TODO: This probably ignores prefixes? - //if (js.MayHavePrefix()) { - // DISABLE; - //} - - if (_VS == _VD) { - // A lot of these in Wipeout... Just drop the instruction entirely. - return; - } - - MatrixSize sz = GetMtxSize(op); - int n = GetMatrixSide(sz); - - u8 sregs[16], dregs[16]; - GetMatrixRegs(sregs, sz, _VS); - GetMatrixRegs(dregs, sz, _VD); - - // Rough overlap check. - bool overlap = false; - if (GetMtx(_VS) == GetMtx(_VD)) { - // Potential overlap (guaranteed for 3x3 or more). - overlap = true; - } - - if (overlap) { - // Not so common, fallback. - DISABLE; - } else { - for (int a = 0; a < n; a++) { - for (int b = 0; b < n; b++) { - fpr.MapDirtyInV(dregs[a * 4 + b], sregs[a * 4 + b]); - FMR(fpr.V(dregs[a * 4 + b]), fpr.V(sregs[a * 4 + b])); - } - } - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - } - - void Jit::Comp_VScl(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - u8 sregs[4], dregs[4], treg; - GetVectorRegsPrefixS(sregs, sz, _VS); - GetVectorRegs(&treg, V_Single, _VT); - GetVectorRegsPrefixD(dregs, sz, _VD); - - // Move to S0 early, so we don't have to worry about overlap with scale. - fpr.LoadToRegV(FPR6, treg); - - // For prefixes to work, we just have to ensure that none of the output registers spill - // and that there's no overlap. - MIPSReg tempregs[4]; - for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], i, n, sregs)) { - // Need to use temp regs - tempregs[i] = fpr.GetTempV(); - } else { - tempregs[i] = dregs[i]; - } - } - - // The meat of the function! - for (int i = 0; i < n; i++) { - fpr.MapDirtyInV(tempregs[i], sregs[i]); - FMULS(fpr.V(tempregs[i]), fpr.V(sregs[i]), FPR6); - } - - for (int i = 0; i < n; i++) { - // All must be mapped for prefixes to work. - if (dregs[i] != tempregs[i]) { - fpr.MapDirtyInV(dregs[i], tempregs[i]); - FMR(fpr.V(dregs[i]), fpr.V(tempregs[i])); - } - } - - ApplyPrefixD(dregs, sz); - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Vmmul(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - // TODO: This probably ignores prefixes? - if (js.MayHavePrefix() || disablePrefixes) { - DISABLE; - } - - MatrixSize sz = GetMtxSize(op); - int n = GetMatrixSide(sz); - - u8 sregs[16], tregs[16], dregs[16]; - GetMatrixRegs(sregs, sz, _VS); - GetMatrixRegs(tregs, sz, _VT); - GetMatrixRegs(dregs, sz, _VD); - - // Rough overlap check. - bool overlap = false; - if (GetMtx(_VS) == GetMtx(_VD) || GetMtx(_VT) == GetMtx(_VD)) { - // Potential overlap (guaranteed for 3x3 or more). - overlap = true; - } - - if (overlap) { - DISABLE; - } else { - for (int a = 0; a < n; a++) { - for (int b = 0; b < n; b++) { - fpr.MapInInV(sregs[b * 4], tregs[a * 4]); - FMULS(FPR6, fpr.V(sregs[b * 4]), fpr.V(tregs[a * 4])); - for (int c = 1; c < n; c++) { - fpr.MapInInV(sregs[b * 4 + c], tregs[a * 4 + c]); - FMADDS(FPR6, fpr.V(sregs[b * 4 + c]), fpr.V(tregs[a * 4 + c]), FPR6); - } - fpr.MapRegV(dregs[a * 4 + b], MAP_DIRTY | MAP_NOINIT); - FMR(fpr.V(dregs[a * 4 + b]), FPR6); - } - } - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - } - - void Jit::Comp_Vmscl(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vtfm(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - // TODO: This probably ignores prefixes? Or maybe uses D? - if (js.MayHavePrefix() || disablePrefixes) { - DISABLE; - } - - VectorSize sz = GetVecSize(op); - MatrixSize msz = GetMtxSize(op); - int n = GetNumVectorElements(sz); - int ins = (op >> 23) & 7; - - bool homogenous = false; - if (n == ins) { - n++; - sz = (VectorSize)((int)(sz) + 1); - msz = (MatrixSize)((int)(msz) + 1); - homogenous = true; - } - // Otherwise, n should already be ins + 1. - else if (n != ins + 1) { - DISABLE; - } - - u8 sregs[16], dregs[4], tregs[4]; - GetMatrixRegs(sregs, msz, _VS); - GetVectorRegs(tregs, sz, _VT); - GetVectorRegs(dregs, sz, _VD); - - // TODO: test overlap, optimize. - int tempregs[4]; - for (int i = 0; i < n; i++) { - fpr.MapInInV(sregs[i * 4], tregs[0]); - FMULS(FPR6, fpr.V(sregs[i * 4]), fpr.V(tregs[0])); - for (int k = 1; k < n; k++) { - if (!homogenous || k != n - 1) { - fpr.MapInInV(sregs[i * 4 + k], tregs[k]); - FMADDS(FPR6, fpr.V(sregs[i * 4 + k]), fpr.V(tregs[k]), FPR6); - } else { - fpr.MapRegV(sregs[i * 4 + k]); - FADDS(FPR6, FPR6, fpr.V(sregs[i * 4 + k])); - } - } - - int temp = fpr.GetTempV(); - fpr.MapRegV(temp, MAP_NOINIT | MAP_DIRTY); - fpr.SpillLockV(temp); - FMR(fpr.V(temp), FPR6); - tempregs[i] = temp; - } - for (int i = 0; i < n; i++) { - u8 temp = tempregs[i]; - fpr.MapRegV(dregs[i], MAP_NOINIT | MAP_DIRTY); - FMR(fpr.V(dregs[i]), fpr.V(temp)); - } - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VHdp(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_VCrs(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_VDet(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vi2x(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vx2i(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vf2i(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vi2f(MIPSOpcode op) { - //DISABLE; - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) - DISABLE; - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - int imm = (op >> 16) & 0x1f; - const float mult = 1.0f / (float)(1UL << imm); - - u8 sregs[4], dregs[4]; - GetVectorRegsPrefixS(sregs, sz, _VS); - GetVectorRegsPrefixD(dregs, sz, _VD); - - MIPSReg tempregs[4]; - for (int i = 0; i < n; ++i) { - if (!IsOverlapSafe(dregs[i], i, n, sregs)) { - tempregs[i] = fpr.GetTempV(); - } else { - tempregs[i] = dregs[i]; - } - } - - if (mult != 1.0f) - MOVI2F(FPR5, mult, false); - - u64 tmp = 0; - MOVI2R(SREG, (u32)&tmp); - - //Break(); - - for (int i = 0; i < n; i++) { - // Crappy code !! - fpr.MapDirtyInV(tempregs[i], sregs[i]); - - // float => mem - SFS(fpr.V(sregs[i]), SREG, 0); - - // int <= mem - LWZ(R6, SREG, 0); - //RLDICL(R6, R6, 0, 23); - EXTSW(R6, R6); - - // int => mem - STD(R6, SREG, 0); - - // float <= mem - LFD(fpr.V(tempregs[i]), SREG, 0); - - FCFID(fpr.V(tempregs[i]), fpr.V(tempregs[i])); - FRSP(fpr.V(tempregs[i]), fpr.V(tempregs[i])); - - if (mult != 1.0f) - FMULS(fpr.V(tempregs[i]), fpr.V(tempregs[i]), FPR5); - } - - //Break(); - - for (int i = 0; i < n; ++i) { - if (dregs[i] != tempregs[i]) { - fpr.MapDirtyInV(dregs[i], tempregs[i]); - FMR(fpr.V(dregs[i]), fpr.V(tempregs[i])); - } - } - - ApplyPrefixD(dregs, sz); - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Vh2f(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vcst(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - int conNum = (op >> 16) & 0x1f; - int vd = _VD; - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - u8 dregs[4]; - GetVectorRegsPrefixD(dregs, sz, _VD); - fpr.MapRegsAndSpillLockV(dregs, sz, MAP_NOINIT | MAP_DIRTY); - - MOVI2R(SREG, (u32)(void *)&cst_constants[conNum]); - LFS(FPR6, SREG, 0); - for (int i = 0; i < n; ++i) - FMR(fpr.V(dregs[i]), FPR6); - - ApplyPrefixD(dregs, sz); - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Vhoriz(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_VRot(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_VIdt(MIPSOpcode op) { - CONDITIONAL_DISABLE - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - int vd = _VD; - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - MOVI2F(FPR6, 0.0f); - MOVI2F(FPR7, 1.0f); - u8 dregs[4]; - GetVectorRegsPrefixD(dregs, sz, _VD); - fpr.MapRegsAndSpillLockV(dregs, sz, MAP_NOINIT | MAP_DIRTY); - switch (sz) - { - case V_Pair: - FMR(fpr.V(dregs[0]), (vd&1)==0 ? FPR7 : FPR6); - FMR(fpr.V(dregs[1]), (vd&1)==1 ? FPR7 : FPR6); - break; - case V_Quad: - FMR(fpr.V(dregs[0]), (vd&3)==0 ? FPR7 : FPR6); - FMR(fpr.V(dregs[1]), (vd&3)==1 ? FPR7 : FPR6); - FMR(fpr.V(dregs[2]), (vd&3)==2 ? FPR7 : FPR6); - FMR(fpr.V(dregs[3]), (vd&3)==3 ? FPR7 : FPR6); - break; - default: - _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted"); - break; - } - - ApplyPrefixD(dregs, sz); - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Vcmp(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Vcmov(MIPSOpcode op) { - DISABLE; - } - - void Jit::Comp_Viim(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - u8 dreg; - GetVectorRegs(&dreg, V_Single, _VT); - - s32 imm = (s32)(s16)(u16)(op & 0xFFFF); - fpr.MapRegV(dreg, MAP_DIRTY | MAP_NOINIT); - MOVI2F(fpr.V(dreg), (float)imm); - - ApplyPrefixD(&dreg, V_Single); - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_Vfim(MIPSOpcode op) { - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - u8 dreg; - GetVectorRegs(&dreg, V_Single, _VT); - - FP16 half; - half.u = op & 0xFFFF; - FP32 fval = half_to_float_fast5(half); - fpr.MapRegV(dreg, MAP_DIRTY | MAP_NOINIT); - MOVI2F(fpr.V(dreg), fval.f); - - ApplyPrefixD(&dreg, V_Single); - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - - void Jit::Comp_VCrossQuat(MIPSOpcode op) { - DISABLE; - CONDITIONAL_DISABLE; - - if (js.HasUnknownPrefix() || disablePrefixes) { - DISABLE; - } - - VectorSize sz = GetVecSize(op); - int n = GetNumVectorElements(sz); - - u8 sregs[4], tregs[4], dregs[4]; - GetVectorRegs(sregs, sz, _VS); - GetVectorRegs(tregs, sz, _VT); - GetVectorRegs(dregs, sz, _VD); - - // Map everything into registers. - fpr.MapRegsAndSpillLockV(sregs, sz, 0); - fpr.MapRegsAndSpillLockV(tregs, sz, 0); - - if (sz == V_Triple) { - int temp3 = fpr.GetTempV(); - fpr.MapRegV(temp3, MAP_DIRTY | MAP_NOINIT); - // Cross product vcrsp.t - - // Compute X - FMULS(FPR6, fpr.V(sregs[1]), fpr.V(tregs[2])); - FMSUBS(FPR6, fpr.V(sregs[2]), fpr.V(tregs[1]), FPR6); - - // Compute Y - FMULS(FPR7, fpr.V(sregs[2]), fpr.V(tregs[0])); - FMSUBS(FPR7, fpr.V(sregs[0]), fpr.V(tregs[2]), FPR7); - - // Compute Z - FMULS(fpr.V(temp3), fpr.V(sregs[0]), fpr.V(tregs[1])); - FMSUBS(fpr.V(temp3), fpr.V(sregs[1]), fpr.V(tregs[0]), fpr.V(temp3)); - - fpr.MapRegsAndSpillLockV(dregs, V_Triple, MAP_DIRTY | MAP_NOINIT); - FMR(fpr.V(dregs[0]), FPR6); - FMR(fpr.V(dregs[1]), FPR7); - FMR(fpr.V(dregs[2]), fpr.V(temp3)); - } else if (sz == V_Quad) { - // Quaternion product vqmul.q untested - DISABLE; - } - - fpr.ReleaseSpillLocksAndDiscardTemps(); - } - void Jit::Comp_Vsgn(MIPSOpcode op) { - DISABLE; - } - void Jit::Comp_Vocp(MIPSOpcode op) { - DISABLE; - } - void Jit::Comp_ColorConv(MIPSOpcode op) { - DISABLE; - } - void Jit::Comp_Vbfy(MIPSOpcode op) { - DISABLE; - } -} - diff --git a/Core/MIPS/PPC/PpcJit.cpp b/Core/MIPS/PPC/PpcJit.cpp deleted file mode 100644 index 583de42661..0000000000 --- a/Core/MIPS/PPC/PpcJit.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "Common/ChunkFile.h" -#include "Core/Core.h" -#include "Core/CoreTiming.h" -#include "Core/MemMap.h" -#include "Core/MIPS/MIPS.h" -#include "Core/MIPS/MIPSCodeUtils.h" -#include "Core/MIPS/MIPSInt.h" -#include "Core/MIPS/MIPSTables.h" - -#include "PpcRegCache.h" -#include "ppcEmitter.h" -#include "PpcJit.h" - -#include -#include - -using namespace PpcGen; - -extern volatile CoreState coreState; - -namespace MIPSComp -{ - -static u32 delaySlotFlagsValue; - -void Jit::CompileDelaySlot(int flags) -{ - // preserve flag around the delay slot! Maybe this is not always necessary on ARM where - // we can (mostly) control whether we set the flag or not. Of course, if someone puts an slt in to the - // delay slot, we're screwed. - if (flags & DELAYSLOT_SAFE) { - // Save flags register - MOVI2R(SREG, (u32)&delaySlotFlagsValue); - STW(FLAGREG, SREG); - MFCR(R19); - } - - js.inDelaySlot = true; - MIPSOpcode op = Memory::Read_Instruction(js.compilerPC + 4); - MIPSCompileOp(op); - js.inDelaySlot = false; - - if (flags & DELAYSLOT_FLUSH) - FlushAll(); - - if (flags & DELAYSLOT_SAFE) { - // Restore flags register - MOVI2R(SREG, (u32)&delaySlotFlagsValue); - LWZ(FLAGREG, SREG); - MTCR(R19); - } -} - -void Jit::Compile(u32 em_address) -{ - if (GetSpaceLeft() < 0x10000 || blocks.IsFull()) - { - ClearCache(); - } - - int block_num = blocks.AllocateBlock(em_address); - JitBlock *b = blocks.GetBlock(block_num); - DoJit(em_address, b); - blocks.FinalizeBlock(block_num, jo.enableBlocklink); - - // Drat. The VFPU hit an uneaten prefix at the end of a block. - if (js.startDefaultPrefix && js.MayHavePrefix()) - { - js.startDefaultPrefix = false; - // Our assumptions are all wrong so it's clean-slate time. - ClearCache(); - - // Let's try that one more time. We won't get back here because we toggled the value. - Compile(em_address); - } -} - -bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) -{ - // TODO: Not used by anything yet. - return false; -} - -void Jit::MovFromPC(PPCReg r) { - LWZ(r, CTXREG, offsetof(MIPSState, pc)); -} - -void Jit::MovToPC(PPCReg r) { - STW(r, CTXREG, offsetof(MIPSState, pc)); -} - -void Jit::SaveDowncount(PPCReg r) { - STW(r, CTXREG, offsetof(MIPSState, downcount)); -} - -void Jit::RestoreDowncount(PPCReg r) { - LWZ(r, CTXREG, offsetof(MIPSState, downcount)); -} - -static void ShowDownCount() { - if (currentMIPS->downcount<0) { - //ERROR_LOG(DYNA_REC, "MIPSState, downcount %08x", currentMIPS->downcount); - Crash(); - } -} - -void Jit::WriteDownCount(int offset) -{ - // don't know if the result is correct - int theDowncount = js.downcountAmount + offset; - if (jo.downcountInRegister) { - // DCNTREG = DCNTREG - theDowncount; - MOVI2R(SREG, theDowncount); - SUBF(DCNTREG, SREG, DCNTREG, 1); - STW(DCNTREG, CTXREG, offsetof(MIPSState, downcount)); - } else { - // DCNTREG = MIPSState->downcount - theDowncount; - MOVI2R(SREG, theDowncount); - LWZ(DCNTREG, CTXREG, offsetof(MIPSState, downcount)); - SUBF(DCNTREG, SREG, DCNTREG, 1); - STW(DCNTREG, CTXREG, offsetof(MIPSState, downcount)); - } - - //QuickCallFunction(ShowDownCount); - - CMPI(DCNTREG, 0); -} - -void Jit::Comp_Generic(MIPSOpcode op) { - FlushAll(); - - // basic jit !! - MIPSInterpretFunc func = MIPSGetInterpretFunc(op); - if (func) - { - // Save mips PC and cycles - SaveDowncount(DCNTREG); - MOVI2R(SREG, js.compilerPC); - MovToPC(SREG); - - // call interpreted function - MOVI2R(R3, op.encoding); - QuickCallFunction((void *)func); - - // restore pc and cycles - RestoreDowncount(DCNTREG); - } - const MIPSInfo info = MIPSGetInfo(op); - if ((info & IS_VFPU) != 0 && (info & VFPU_NO_PREFIX) == 0) - { - // If it does eat them, it'll happen in MIPSCompileOp(). - if ((info & OUT_EAT_PREFIX) == 0) - js.PrefixUnknown(); - } -} - -void Jit::EatInstruction(MIPSOpcode op) { - MIPSInfo info = MIPSGetInfo(op); - _dbg_assert_msg_(JIT, !(info & DELAYSLOT), "Never eat a branch op."); - _dbg_assert_msg_(JIT, !js.inDelaySlot, "Never eat an instruction inside a delayslot."); - - js.compilerPC += 4; - js.downcountAmount += MIPSGetInstructionCycleEstimate(op); -} - -void Jit::Comp_RunBlock(MIPSOpcode op) { - // This shouldn't be necessary, the dispatcher should catch us before we get here. - ERROR_LOG(JIT, "Comp_RunBlock should never be reached!"); -} - -void Jit::Comp_ReplacementFunc(MIPSOpcode op) -{ - // None of the code of this function is relevant so we'll just - // call the replacement and move RA to PC. - int replacementFunc = op & 0xFFFFFFF; - - - // We could even do this in the jal that is branching to the function - // but having the op is necessary for the interpreter anyway. -} - -void Jit::Comp_DoNothing(MIPSOpcode op) { - -} - -void Jit::FlushAll() -{ - gpr.FlushAll(); - fpr.FlushAll(); - FlushPrefixV(); -} - -void Jit::FlushPrefixV() -{ - if ((js.prefixSFlag & PpcJitState::PREFIX_DIRTY) != 0) { - MOVI2R(SREG, js.prefixS); - STW(SREG, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_SPREFIX])); - js.prefixSFlag = (PpcJitState::PrefixState) (js.prefixSFlag & ~PpcJitState::PREFIX_DIRTY); - } - - if ((js.prefixTFlag & PpcJitState::PREFIX_DIRTY) != 0) { - MOVI2R(SREG, js.prefixT); - STW(SREG, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_TPREFIX])); - js.prefixTFlag = (PpcJitState::PrefixState) (js.prefixTFlag & ~PpcJitState::PREFIX_DIRTY); - } - - if ((js.prefixDFlag & PpcJitState::PREFIX_DIRTY) != 0) { - MOVI2R(SREG, js.prefixD); - STW(SREG, CTXREG, offsetof(MIPSState, vfpuCtrl[VFPU_CTRL_DPREFIX])); - js.prefixDFlag = (PpcJitState::PrefixState) (js.prefixDFlag & ~PpcJitState::PREFIX_DIRTY); - } -} - -void Jit::ClearCache() { - blocks.Clear(); - ClearCodeSpace(); - GenerateFixedCode(); -} - -void Jit::InvalidateCache() { - blocks.Clear(); -} - -void Jit::InvalidateCacheAt(u32 em_address, int length) { - blocks.InvalidateICache(em_address, length); -} - -Jit::Jit(MIPSState *mips) : blocks(mips, this), gpr(mips, &jo),fpr(mips),mips_(mips) -{ - blocks.Init(); - gpr.SetEmitter(this); - fpr.SetEmitter(this); - AllocCodeSpace(1024 * 1024 * 16); // 32MB is the absolute max because that's what an ARM branch instruction can reach, backwards and forwards. - GenerateFixedCode(); - - js.startDefaultPrefix = true; -} - -void Jit::RunLoopUntil(u64 globalticks) { -#ifdef _XBOX - // force stack alinement - //_alloca(16*1024); -#endif - - // Run the compiled code - ((void (*)())enterCode)(); -} - - -// IDEA - could have a WriteDualExit that takes two destinations and two condition flags, -// and just have conditional that set PC "twice". This only works when we fall back to dispatcher -// though, as we need to have the SUBS flag set in the end. So with block linking in the mix, -// I don't think this gives us that much benefit. -void Jit::WriteExit(u32 destination, int exit_num) -{ - WriteDownCount(); - //If nobody has taken care of this yet (this can be removed when all branches are done) - JitBlock *b = js.curBlock; - b->exitAddress[exit_num] = destination; - b->exitPtrs[exit_num] = GetWritableCodePtr(); - - // Link opportunity! - int block = blocks.GetBlockNumberFromStartAddress(destination); - if (block >= 0 && jo.enableBlocklink) { - // It exists! Joy of joy! - B(blocks.GetBlock(block)->checkedEntry); - b->linkStatus[exit_num] = true; - } else { - MOVI2R(SREG, destination); - B((const void *)dispatcherPCInR0); - } -} - -void Jit::WriteExitDestInR(PPCReg Reg) -{ - //Break(); - MovToPC(Reg); - WriteDownCount(); - // TODO: shouldn't need an indirect branch here... - B((const void *)dispatcher); -} - -void Jit::WriteSyscallExit() -{ - WriteDownCount(); - B((const void *)dispatcherCheckCoreState); -} -} \ No newline at end of file diff --git a/Core/MIPS/PPC/PpcJit.h b/Core/MIPS/PPC/PpcJit.h deleted file mode 100644 index e5931b4636..0000000000 --- a/Core/MIPS/PPC/PpcJit.h +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#include "Common/CommonTypes.h" - -#include "Core/MIPS/JitCommon/JitBlockCache.h" -#include "Core/MIPS/PPC/PpcRegCache.h" -#include "Core/MIPS/PPC/PpcRegCacheFpu.h" - -#include "Core/MIPS/MIPS.h" - -#include - -namespace MIPSComp -{ - - struct PpcJitOptions - { - PpcJitOptions() - { - enableBlocklink = true; - downcountInRegister = true; - } - - bool enableBlocklink; - bool downcountInRegister; - }; - - struct PpcJitState - { - enum PrefixState - { - PREFIX_UNKNOWN = 0x00, - PREFIX_KNOWN = 0x01, - PREFIX_DIRTY = 0x10, - PREFIX_KNOWN_DIRTY = 0x11, - }; - - PpcJitState() - : prefixSFlag(PREFIX_UNKNOWN), - prefixTFlag(PREFIX_UNKNOWN), - prefixDFlag(PREFIX_UNKNOWN) {} - - u32 compilerPC; - u32 blockStart; - bool cancel; - bool inDelaySlot; - int downcountAmount; - bool compiling; // TODO: get rid of this in favor of using analysis results to determine end of block - JitBlock *curBlock; - - // VFPU prefix magic - bool startDefaultPrefix; - u32 prefixS; - u32 prefixT; - u32 prefixD; - PrefixState prefixSFlag; - PrefixState prefixTFlag; - PrefixState prefixDFlag; - void PrefixStart() { - if (startDefaultPrefix) { - EatPrefix(); - } else { - PrefixUnknown(); - } - } - void PrefixUnknown() { - prefixSFlag = PREFIX_UNKNOWN; - prefixTFlag = PREFIX_UNKNOWN; - prefixDFlag = PREFIX_UNKNOWN; - } - bool MayHavePrefix() const { - if (HasUnknownPrefix()) { - return true; - } else if (prefixS != 0xE4 || prefixT != 0xE4 || prefixD != 0) { - return true; - } else if (VfpuWriteMask() != 0) { - return true; - } - - return false; - } - bool HasUnknownPrefix() const { - if (!(prefixSFlag & PREFIX_KNOWN) || !(prefixTFlag & PREFIX_KNOWN) || !(prefixDFlag & PREFIX_KNOWN)) { - return true; - } - return false; - } - bool HasNoPrefix() const { - return (prefixDFlag & PREFIX_KNOWN) && (prefixSFlag & PREFIX_KNOWN) && (prefixTFlag & PREFIX_KNOWN) && (prefixS == 0xE4 && prefixT == 0xE4 && prefixD == 0); - } - - void EatPrefix() { - if ((prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4) { - prefixSFlag = PREFIX_KNOWN_DIRTY; - prefixS = 0xE4; - } - if ((prefixTFlag & PREFIX_KNOWN) == 0 || prefixT != 0xE4) { - prefixTFlag = PREFIX_KNOWN_DIRTY; - prefixT = 0xE4; - } - if ((prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0 || VfpuWriteMask() != 0) { - prefixDFlag = PREFIX_KNOWN_DIRTY; - prefixD = 0x0; - } - } - u8 VfpuWriteMask() const { - _assert_(prefixDFlag & PREFIX_KNOWN); - return (prefixD >> 8) & 0xF; - } - bool VfpuWriteMask(int i) const { - _assert_(prefixDFlag & PREFIX_KNOWN); - return (prefixD >> (8 + i)) & 1; - } - }; - - - enum CompileDelaySlotFlags - { - // Easy, nothing extra. - DELAYSLOT_NICE = 0, - // Flush registers after delay slot. - DELAYSLOT_FLUSH = 1, - // Preserve flags. - DELAYSLOT_SAFE = 2, - // Flush registers after and preserve flags. - DELAYSLOT_SAFE_FLUSH = DELAYSLOT_FLUSH | DELAYSLOT_SAFE, - }; - - class Jit: public PpcGen::PPCXCodeBlock - { - protected: - JitBlockCache blocks; - public: - Jit(MIPSState *mips); - void DoState(PointerWrap &p) { - auto s = p.Section("Jit", 1); - if (!s) - return; - - // Do nothing - } - static void DoDummyState(PointerWrap &p) { - auto s = p.Section("Jit", 1); - if (!s) - return; - - // Do nothing - } - - // Compiled ops should ignore delay slots - // the compiler will take care of them by itself - // OR NOT - void Comp_Generic(MIPSOpcode op); - - void EatInstruction(MIPSOpcode op); - void Comp_RunBlock(MIPSOpcode op); - void Comp_ReplacementFunc(MIPSOpcode op); - - // TODO: Eat VFPU prefixes here. - void EatPrefix() { js.EatPrefix(); } - - // Ops - void Comp_ITypeMem(MIPSOpcode op); - void Comp_Cache(MIPSOpcode op); - - void Comp_RelBranch(MIPSOpcode op); - void Comp_RelBranchRI(MIPSOpcode op); - void Comp_FPUBranch(MIPSOpcode op); - void Comp_FPULS(MIPSOpcode op); - void Comp_FPUComp(MIPSOpcode op); - void Comp_Jump(MIPSOpcode op); - void Comp_JumpReg(MIPSOpcode op); - void Comp_Syscall(MIPSOpcode op); - void Comp_Break(MIPSOpcode op); - - void Comp_IType(MIPSOpcode op); - void Comp_RType2(MIPSOpcode op); - void Comp_RType3(MIPSOpcode op); - void Comp_ShiftType(MIPSOpcode op); - void Comp_Allegrex(MIPSOpcode op); - void Comp_Allegrex2(MIPSOpcode op); - void Comp_VBranch(MIPSOpcode op); - void Comp_MulDivType(MIPSOpcode op); - void Comp_Special3(MIPSOpcode op); - - void Comp_FPU3op(MIPSOpcode op); - void Comp_FPU2op(MIPSOpcode op); - void Comp_mxc1(MIPSOpcode op); - - void Comp_DoNothing(MIPSOpcode op); - - void Comp_SV(MIPSOpcode op); - void Comp_SVQ(MIPSOpcode op); - void Comp_VPFX(MIPSOpcode op); - void Comp_VVectorInit(MIPSOpcode op); - void Comp_VMatrixInit(MIPSOpcode op); - void Comp_VDot(MIPSOpcode op); - void Comp_VecDo3(MIPSOpcode op); - void Comp_VV2Op(MIPSOpcode op); - void Comp_Mftv(MIPSOpcode op); - void Comp_Vmfvc(MIPSOpcode op); - void Comp_Vmtvc(MIPSOpcode op); - void Comp_Vmmov(MIPSOpcode op); - void Comp_VScl(MIPSOpcode op); - void Comp_Vmmul(MIPSOpcode op); - void Comp_Vmscl(MIPSOpcode op); - void Comp_Vtfm(MIPSOpcode op); - void Comp_VHdp(MIPSOpcode op); - void Comp_VCrs(MIPSOpcode op); - void Comp_VDet(MIPSOpcode op); - void Comp_Vi2x(MIPSOpcode op); - void Comp_Vx2i(MIPSOpcode op); - void Comp_Vf2i(MIPSOpcode op); - void Comp_Vi2f(MIPSOpcode op); - void Comp_Vh2f(MIPSOpcode op); - void Comp_Vcst(MIPSOpcode op); - void Comp_Vhoriz(MIPSOpcode op); - void Comp_VRot(MIPSOpcode op); - void Comp_VIdt(MIPSOpcode op); - void Comp_Vcmp(MIPSOpcode op); - void Comp_Vcmov(MIPSOpcode op); - void Comp_Viim(MIPSOpcode op); - void Comp_Vfim(MIPSOpcode op); - void Comp_VCrossQuat(MIPSOpcode op); - void Comp_Vsgn(MIPSOpcode op); - void Comp_Vocp(MIPSOpcode op); - void Comp_ColorConv(MIPSOpcode op); - void Comp_Vbfy(MIPSOpcode op); - - int Replace_fabsf(); - - // Utility compilation functions - void BranchFPFlag(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely); - void BranchVFPUFlag(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely); - void BranchRSZeroComp(MIPSOpcode op, PpcGen::FixupBranchType cc, bool andLink, bool likely); - void BranchRSRTComp(MIPSOpcode op, PpcGen::FixupBranchType cc, bool likely); - - void SetRegToEffectiveAddress(PpcGen::PPCReg r, int rs, s16 offset); - - // Utilities to reduce duplicated code - void CompImmLogic(int rs, int rt, u32 uimm, void (PPCXEmitter::*arith)(PPCReg Rd, PPCReg Ra, unsigned short imm), u32 (*eval)(u32 a, u32 b)); - void CompType3(int rd, int rs, int rt, void (PPCXEmitter::*arithOp2)(PPCReg Rd, PPCReg Ra, PPCReg Rb), u32 (*eval)(u32 a, u32 b), bool isSub = false); - void FPUComp(int fs, int ft, PpcGen::FixupBranchType cond, bool unorderer = false, int bf = 0); - - void ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz); - void ApplyPrefixD(const u8 *vregs, VectorSize sz); - void GetVectorRegsPrefixS(u8 *regs, VectorSize sz, int vectorReg) { - _assert_(js.prefixSFlag & PpcJitState::PREFIX_KNOWN); - GetVectorRegs(regs, sz, vectorReg); - ApplyPrefixST(regs, js.prefixS, sz); - } - void GetVectorRegsPrefixT(u8 *regs, VectorSize sz, int vectorReg) { - _assert_(js.prefixTFlag & PpcJitState::PREFIX_KNOWN); - GetVectorRegs(regs, sz, vectorReg); - ApplyPrefixST(regs, js.prefixT, sz); - } - void GetVectorRegsPrefixD(u8 *regs, VectorSize sz, int vectorReg); - - // flush regs - void FlushAll(); - void FlushPrefixV(); - - void WriteDownCount(int offset = 0); - void MovFromPC(PpcGen::PPCReg r); - void MovToPC(PpcGen::PPCReg r); - - void SaveDowncount(PpcGen::PPCReg r); - void RestoreDowncount(PpcGen::PPCReg r); - - void WriteExit(u32 destination, int exit_num); - void WriteExitDestInR(PPCReg Reg); - void WriteSyscallExit(); - - void ClearCache(); - void InvalidateCache(); - void InvalidateCacheAt(u32 em_address, int length = 4); - - void RunLoopUntil(u64 globalticks); - void GenerateFixedCode(); - - void DumpJit(); - - void CompileDelaySlot(int flags); - void Compile(u32 em_address); // Compiles a block at current MIPS PC - const u8 *DoJit(u32 em_address, JitBlock *b); - - bool DescribeCodePtr(const u8 *ptr, std::string &name); - - PpcJitOptions jo; - PpcJitState js; - - PpcRegCache gpr; - PpcRegCacheFPU fpr; - - MIPSState *mips_; - - JitBlockCache *GetBlockCache() { return &blocks; } - - public: - // Code pointers - const u8 *enterCode; - - const u8 *outerLoop; - const u8 *outerLoopPCInR0; - const u8 *dispatcherCheckCoreState; - const u8 *dispatcherPCInR0; - const u8 *dispatcher; - const u8 *dispatcherNoCheck; - - const u8 *breakpointBailout; - - }; - - typedef void (Jit::*MIPSCompileFunc)(MIPSOpcode opcode); - typedef int (Jit::*MIPSReplaceFunc)(); - -} // namespace MIPSComp - diff --git a/Core/MIPS/PPC/PpcRegCache.cpp b/Core/MIPS/PPC/PpcRegCache.cpp deleted file mode 100644 index b44e463cf3..0000000000 --- a/Core/MIPS/PPC/PpcRegCache.cpp +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include -#include "PpcRegCache.h" -#include "PpcJit.h" - -using namespace PpcGen; - -PpcRegCache::PpcRegCache(MIPSState *mips, MIPSComp::PpcJitOptions *options) : mips_(mips), options_(options) { -} - -void PpcRegCache::Init(PPCXEmitter *emitter) { - emit_ = emitter; -} - -void PpcRegCache::Start(MIPSAnalyst::AnalysisResults &stats) { - for (int i = 0; i < NUM_PPCREG; i++) { - ar[i].mipsReg = -1; - ar[i].isDirty = false; - } - for (int i = 0; i < NUM_MIPSREG; i++) { - mr[i].loc = ML_MEM; - mr[i].reg = INVALID_REG; - mr[i].imm = -1; - mr[i].spillLock = false; - } -} - -const PPCReg *PpcRegCache::GetMIPSAllocationOrder(int &count) const { - // Note that R0 is reserved as scratch for now. - // R1 could be used as it's only used for scratch outside "regalloc space" now. - // R12 is also potentially usable. - // R4-R7 are registers we could use for static allocation or downcount. - // R8 is used to preserve flags in nasty branches. - // R9 and upwards are reserved for jit basics. - if (options_->downcountInRegister) { - static const PPCReg allocationOrder[] = { - /*R14, R15, R16, R17, R18, R19,*/ - R20, R21, R22, R23, R24, R25, - R26, R27, R28, R29, R30, R31, - }; - count = sizeof(allocationOrder) / sizeof(const int); - return allocationOrder; - } else { - static const PPCReg allocationOrder2[] = { - /*R14, R15, R16, R17, R18, R19,*/ - R20, R21, R22, R23, R24, R25, - R26, R27, R28, R29, R30, R31, - }; - count = sizeof(allocationOrder2) / sizeof(const int); - return allocationOrder2; - } -} - -void PpcRegCache::FlushBeforeCall() { - // R4-R11 are preserved. Others need flushing. - /* - FlushPpcReg(R2); - FlushPpcReg(R3); - FlushPpcReg(R12); - */ -} - -// TODO: Somewhat smarter spilling - currently simply spills the first available, should do -// round robin or FIFO or something. -PPCReg PpcRegCache::MapReg(MIPSReg mipsReg, int mapFlags) { - // Let's see if it's already mapped. If so we just need to update the dirty flag. - // We don't need to check for ML_NOINIT because we assume that anyone who maps - // with that flag immediately writes a "known" value to the register. - if (mr[mipsReg].loc == ML_PPCREG) { - if (ar[mr[mipsReg].reg].mipsReg != mipsReg) { - ERROR_LOG(JIT, "Register mapping out of sync! %i", mipsReg); - } - if (mapFlags & MAP_DIRTY) { - ar[mr[mipsReg].reg].isDirty = true; - } - return (PPCReg)mr[mipsReg].reg; - } - - // Okay, not mapped, so we need to allocate an ARM register. - - int allocCount; - const PPCReg *allocOrder = GetMIPSAllocationOrder(allocCount); - -allocate: - for (int i = 0; i < allocCount; i++) { - int reg = allocOrder[i]; - - if (ar[reg].mipsReg == -1) { - // That means it's free. Grab it, and load the value into it (if requested). - ar[reg].isDirty = (mapFlags & MAP_DIRTY) ? true : false; - if ((mapFlags & MAP_NOINIT) != MAP_NOINIT) { - if (mr[mipsReg].loc == ML_MEM) { - if (mipsReg != 0) { - emit_->LWZ((PPCReg)reg, CTXREG, GetMipsRegOffset(mipsReg)); - } else { - // If we get a request to load the zero register, at least we won't spend - // time on a memory access... - emit_->MOVI2R((PPCReg)reg, 0); - } - } else if (mr[mipsReg].loc == ML_IMM) { - emit_->MOVI2R((PPCReg)reg, mr[mipsReg].imm); - ar[reg].isDirty = true; // IMM is always dirty. - } - } - ar[reg].mipsReg = mipsReg; - mr[mipsReg].loc = ML_PPCREG; - mr[mipsReg].reg = (PPCReg)reg; - return (PPCReg)reg; - } - } - - // Still nothing. Let's spill a reg and goto 10. - // TODO: Use age or something to choose which register to spill? - // TODO: Spill dirty regs first? or opposite? - int bestToSpill = -1; - for (int i = 0; i < allocCount; i++) { - int reg = allocOrder[i]; - if (ar[reg].mipsReg != -1 && mr[ar[reg].mipsReg].spillLock) - continue; - bestToSpill = reg; - break; - } - - if (bestToSpill != -1) { - // ERROR_LOG(JIT, "Out of registers at PC %08x - spills register %i.", mips_->pc, bestToSpill); - FlushPpcReg((PPCReg)bestToSpill); - goto allocate; - } - - // Uh oh, we have all them spilllocked.... - ERROR_LOG(JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); - return INVALID_REG; -} - -void PpcRegCache::MapInIn(MIPSReg rd, MIPSReg rs) { - SpillLock(rd, rs); - MapReg(rd); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCache::MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad) { - SpillLock(rd, rs); - bool load = !avoidLoad || rd == rs; - MapReg(rd, load ? MAP_DIRTY : MAP_NOINIT); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCache::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad) { - SpillLock(rd, rs, rt); - bool load = !avoidLoad || (rd == rs || rd == rt); - MapReg(rd, load ? MAP_DIRTY : MAP_NOINIT); - MapReg(rt); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCache::MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad) { - SpillLock(rd1, rd2, rs, rt); - bool load1 = !avoidLoad || (rd1 == rs || rd1 == rt); - bool load2 = !avoidLoad || (rd2 == rs || rd2 == rt); - MapReg(rd1, load1 ? MAP_DIRTY : MAP_NOINIT); - MapReg(rd2, load2 ? MAP_DIRTY : MAP_NOINIT); - MapReg(rt); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCache::FlushPpcReg(PPCReg r) { - if (ar[r].mipsReg == -1) { - // Nothing to do, reg not mapped. - return; - } - if (ar[r].mipsReg != -1) { - if (ar[r].isDirty && mr[ar[r].mipsReg].loc == ML_PPCREG) - emit_->STW(r, CTXREG, GetMipsRegOffset(ar[r].mipsReg)); - // IMMs won't be in an ARM reg. - mr[ar[r].mipsReg].loc = ML_MEM; - mr[ar[r].mipsReg].reg = INVALID_REG; - mr[ar[r].mipsReg].imm = 0; - } else { - ERROR_LOG(JIT, "Dirty but no mipsreg?"); - } - ar[r].isDirty = false; - ar[r].mipsReg = -1; -} - -void PpcRegCache::FlushR(MIPSReg r) { - switch (mr[r].loc) { - case ML_IMM: - // IMM is always "dirty". - emit_->MOVI2R(SREG, mr[r].imm); - emit_->STW(SREG, CTXREG, GetMipsRegOffset(r)); - break; - - case ML_PPCREG: - if (mr[r].reg == INVALID_REG) { - ERROR_LOG(JIT, "FlushMipsReg: MipsReg had bad PpcReg"); - } - if (ar[mr[r].reg].isDirty) { - emit_->STW((PPCReg)mr[r].reg, CTXREG, GetMipsRegOffset(r)); - ar[mr[r].reg].isDirty = false; - } - ar[mr[r].reg].mipsReg = -1; - break; - - case ML_MEM: - // Already there, nothing to do. - break; - - default: - //BAD - break; - } - mr[r].loc = ML_MEM; - mr[r].reg = INVALID_REG; - mr[r].imm = 0; -} - -void PpcRegCache::FlushAll() { - for (int i = 0; i < NUM_MIPSREG; i++) { - FlushR(i); - } - // Sanity check - for (int i = 0; i < NUM_PPCREG; i++) { - if (ar[i].mipsReg != -1) { - ERROR_LOG(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); - } - } -} - -void PpcRegCache::SetImm(MIPSReg r, u32 immVal) { - if (r == 0) - ERROR_LOG(JIT, "Trying to set immediate %08x to r0", immVal); - - // Zap existing value if cached in a reg - if (mr[r].loc == ML_PPCREG) { - ar[mr[r].reg].mipsReg = -1; - ar[mr[r].reg].isDirty = false; - } - mr[r].loc = ML_IMM; - mr[r].imm = immVal; - mr[r].reg = INVALID_REG; -} - -bool PpcRegCache::IsImm(MIPSReg r) const { - if (r == 0) return true; - return mr[r].loc == ML_IMM; -} - -u32 PpcRegCache::GetImm(MIPSReg r) const { - if (r == 0) return 0; - if (mr[r].loc != ML_IMM) { - ERROR_LOG(JIT, "Trying to get imm from non-imm register %i", r); - } - return mr[r].imm; -} - -int PpcRegCache::GetMipsRegOffset(MIPSReg r) { - if (r < 32) - return r * 4; - switch (r) { - case MIPSREG_HI: - return offsetof(MIPSState, hi); - case MIPSREG_LO: - return offsetof(MIPSState, lo); - } - ERROR_LOG(JIT, "bad mips register %i", r); - return 0; // or what? -} - -void PpcRegCache::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) { - mr[r1].spillLock = true; - if (r2 != -1) mr[r2].spillLock = true; - if (r3 != -1) mr[r3].spillLock = true; - if (r4 != -1) mr[r4].spillLock = true; -} - -void PpcRegCache::ReleaseSpillLocks() { - for (int i = 0; i < NUM_MIPSREG; i++) { - mr[i].spillLock = false; - } -} - -void PpcRegCache::ReleaseSpillLock(MIPSReg reg) { - mr[reg].spillLock = false; -} - -PPCReg PpcRegCache::R(int mipsReg) { - if (mr[mipsReg].loc == ML_PPCREG) { - return (PPCReg)mr[mipsReg].reg; - } else { - ERROR_LOG(JIT, "Reg %i not in ppc reg. compilerPC = %08x", mipsReg, compilerPC_); - return INVALID_REG; // BAAAD - } -} diff --git a/Core/MIPS/PPC/PpcRegCache.h b/Core/MIPS/PPC/PpcRegCache.h deleted file mode 100644 index 5f982bbe7f..0000000000 --- a/Core/MIPS/PPC/PpcRegCache.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - - -/** -PPC reg cache based on arm version -**/ - -#pragma once - -#include "../MIPS.h" -#include "../MIPSAnalyst.h" -#include "ppcEmitter.h" - -using namespace PpcGen; - -// R2 to R8: mapped MIPS regs -// R9 = code pointers -// R10 = MIPS context -// R11 = base pointer - - -// R18 to R31: mapped MIPS regs -// R14 = MIPS context -// R15 = downcount register -// R16 = code pointer -// R17 = base pointer - -#if 1 -#define CTXREG (R14) -#define DCNTREG (R15) -#define CODEREG (R16) -#define BASEREG (R17) -#else -#define CTXREG (R6) -#define DCNTREG (R7) -#define CODEREG (R8) -#define BASEREG (R9) -#endif - - -// Safe to use this as scratch regs ? -#define SREG (R5) -#define FLAGREG (R18) - -// Special MIPS registers: -enum { - MIPSREG_HI = 32, - MIPSREG_LO = 33, - TOTAL_MAPPABLE_MIPSREGS = 34, -}; - -typedef int MIPSReg; - -struct RegPPC { - int mipsReg; // if -1, no mipsreg attached. - bool isDirty; // Should the register be written back? -}; - -enum RegMIPSLoc { - ML_IMM, - ML_PPCREG, - ML_MEM, -}; - -struct RegMIPS { - // Where is this MIPS register? - RegMIPSLoc loc; - // Data (only one of these is used, depending on loc. Could make a union). - u32 imm; - PPCReg reg; // reg index - bool spillLock; // if true, this register cannot be spilled. - // If loc == ML_MEM, it's back in its location in the CPU context struct. -}; - -#undef MAP_DIRTY -#undef MAP_NOINIT -// Initing is the default so the flag is reversed. -enum { - MAP_DIRTY = 1, - MAP_NOINIT = 2 | MAP_DIRTY, -}; - -namespace MIPSComp { - struct PpcJitOptions; -} - -class PpcRegCache -{ -public: - PpcRegCache(MIPSState *mips, MIPSComp::PpcJitOptions *options); - ~PpcRegCache() {} - - void Init(PPCXEmitter *emitter); - void Start(MIPSAnalyst::AnalysisResults &stats); - - // Protect the arm register containing a MIPS register from spilling, to ensure that - // it's being kept allocated. - void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1, MIPSReg reg4 = -1); - void ReleaseSpillLock(MIPSReg reg); - void ReleaseSpillLocks(); - - void SetImm(MIPSReg reg, u32 immVal); - bool IsImm(MIPSReg reg) const; - u32 GetImm(MIPSReg reg) const; - - // Returns an ARM register containing the requested MIPS register. - PPCReg MapReg(MIPSReg reg, int mapFlags = 0); - void MapInIn(MIPSReg rd, MIPSReg rs); - void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true); - void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); - void MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); - void FlushPpcReg(PPCReg r); - void FlushR(MIPSReg r); - void FlushBeforeCall(); - void FlushAll(); - - PPCReg R(int preg); // Returns a cached register - - void SetEmitter(PPCXEmitter *emitter) { emit_ = emitter; } - - // For better log output only. - void SetCompilerPC(u32 compilerPC) { compilerPC_ = compilerPC; } - - int GetMipsRegOffset(MIPSReg r); - -private: - const PPCReg *GetMIPSAllocationOrder(int &count) const; - - MIPSState *mips_; - MIPSComp::PpcJitOptions *options_; - PPCXEmitter *emit_; - u32 compilerPC_; - - enum { - NUM_PPCREG = 32, - NUM_MIPSREG = TOTAL_MAPPABLE_MIPSREGS, - }; - - RegPPC ar[NUM_MIPSREG]; - RegMIPS mr[NUM_MIPSREG]; -}; diff --git a/Core/MIPS/PPC/PpcRegCacheFPU.cpp b/Core/MIPS/PPC/PpcRegCacheFPU.cpp deleted file mode 100644 index dd2e53322a..0000000000 --- a/Core/MIPS/PPC/PpcRegCacheFPU.cpp +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "base/logging.h" -#include "Common/PpcEmitter.h" -#include "Common/CPUDetect.h" -#include "Core/MIPS/PPC/PpcRegCacheFPU.h" - - -using namespace PpcGen; - - -PpcRegCacheFPU::PpcRegCacheFPU(MIPSState *mips) : mips_(mips), vr(mr + 32) { -} - -void PpcRegCacheFPU::Init(PPCXEmitter *emitter) { - emit_ = emitter; -} - -void PpcRegCacheFPU::Start(MIPSAnalyst::AnalysisResults &stats) { - for (int i = 0; i < NUM_PPCFPUREG; i++) { - ar[i].mipsReg = -1; - ar[i].isDirty = false; - } - for (int i = 0; i < NUM_MIPSFPUREG; i++) { - mr[i].loc = ML_MEM; - mr[i].reg = INVALID_REG; - mr[i].spillLock = false; - mr[i].tempLock = false; - } -} - -static const PPCReg *GetMIPSAllocationOrder(int &count) { - // We reserve S0-S1 as scratch. Can afford two registers. Maybe even four, which could simplify some things. - static const PPCReg allocationOrder[] = { - FPR14, FPR15, FPR16, FPR17, - FPR18, FPR19, FPR20, FPR21, - FPR22, FPR23, FPR24, FPR25, - FPR26, FPR27, FPR28, FPR29, - FPR30, FPR31 - }; - - count = sizeof(allocationOrder) / sizeof(const int); - return allocationOrder; -} - -PPCReg PpcRegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) { - // Let's see if it's already mapped. If so we just need to update the dirty flag. - // We don't need to check for ML_NOINIT because we assume that anyone who maps - // with that flag immediately writes a "known" value to the register. - if (mr[mipsReg].loc == ML_PPCREG) { - if (ar[mr[mipsReg].reg].mipsReg != mipsReg) { - ERROR_LOG(HLE, "Register mapping out of sync! %i", mipsReg); - } - if (mapFlags & MAP_DIRTY) { - ar[mr[mipsReg].reg].isDirty = true; - } - //INFO_LOG(HLE, "Already mapped %i to %i", mipsReg, mr[mipsReg].reg); - return (PPCReg)(mr[mipsReg].reg + FPR0); - } - - // Okay, not mapped, so we need to allocate an PPC register. - - int allocCount; - const PPCReg *allocOrder = GetMIPSAllocationOrder(allocCount); - -allocate: - for (int i = 0; i < allocCount; i++) { - int reg = allocOrder[i] - FPR0; - - if (ar[reg].mipsReg == -1) { - // That means it's free. Grab it, and load the value into it (if requested). - ar[reg].isDirty = (mapFlags & MAP_DIRTY) ? true : false; - if (!(mapFlags & MAP_NOINIT)) { - if (mr[mipsReg].loc == ML_MEM && mipsReg < TEMP0) { - emit_->LFS((PPCReg)(reg + FPR0), CTXREG, GetMipsRegOffset(mipsReg)); - } - } - ar[reg].mipsReg = mipsReg; - mr[mipsReg].loc = ML_PPCREG; - mr[mipsReg].reg = reg; - //INFO_LOG(HLE, "Mapped %i to %i", mipsReg, mr[mipsReg].reg); - return (PPCReg)(reg + FPR0); - } - } - - - // Still nothing. Let's spill a reg and goto 10. - // TODO: Use age or something to choose which register to spill? - // TODO: Spill dirty regs first? or opposite? - int bestToSpill = -1; - for (int i = 0; i < allocCount; i++) { - int reg = allocOrder[i] - FPR0; - if (ar[reg].mipsReg != -1 && (mr[ar[reg].mipsReg].spillLock || mr[ar[reg].mipsReg].tempLock)) - continue; - bestToSpill = reg; - break; - } - - if (bestToSpill != -1) { - FlushPpcReg((PPCReg)(FPR0 + bestToSpill)); - goto allocate; - } - - // Uh oh, we have all them spilllocked.... - ERROR_LOG(JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); - return INVALID_REG; -} - -void PpcRegCacheFPU::MapInIn(MIPSReg rd, MIPSReg rs) { - SpillLock(rd, rs); - MapReg(rd); - MapReg(rs); - ReleaseSpillLock(rd); - ReleaseSpillLock(rs); -} - -void PpcRegCacheFPU::MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad) { - SpillLock(rd, rs); - bool overlap = avoidLoad && rd == rs; - MapReg(rd, MAP_DIRTY | (overlap ? 0 : MAP_NOINIT)); - MapReg(rs); - ReleaseSpillLock(rd); - ReleaseSpillLock(rs); -} - -void PpcRegCacheFPU::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad) { - SpillLock(rd, rs, rt); - bool overlap = avoidLoad && (rd == rs || rd == rt); - MapReg(rd, MAP_DIRTY | (overlap ? 0 : MAP_NOINIT)); - MapReg(rt); - MapReg(rs); - ReleaseSpillLock(rd); - ReleaseSpillLock(rs); - ReleaseSpillLock(rt); -} - -void PpcRegCacheFPU::SpillLockV(const u8 *v, VectorSize sz) { - for (int i = 0; i < GetNumVectorElements(sz); i++) { - vr[v[i]].spillLock = true; - } -} - -void PpcRegCacheFPU::SpillLockV(int vec, VectorSize sz) { - u8 v[4]; - GetVectorRegs(v, sz, vec); - SpillLockV(v, sz); -} - -void PpcRegCacheFPU::MapRegV(int vreg, int flags) { - MapReg(vreg + 32, flags); -} - -void PpcRegCacheFPU::LoadToRegV(PPCReg ppcReg, int vreg) { - if (vr[vreg].loc == ML_PPCREG) { - emit_->FMR(ppcReg, (PPCReg)(FPR0 + vr[vreg].reg)); - } else { - MapRegV(vreg); - emit_->FMR(ppcReg, V(vreg)); - } -} - -void PpcRegCacheFPU::MapRegsAndSpillLockV(int vec, VectorSize sz, int flags) { - u8 v[4]; - GetVectorRegs(v, sz, vec); - SpillLockV(v, sz); - for (int i = 0; i < GetNumVectorElements(sz); i++) { - MapRegV(v[i], flags); - } -} - -void PpcRegCacheFPU::MapRegsAndSpillLockV(const u8 *v, VectorSize sz, int flags) { - SpillLockV(v, sz); - for (int i = 0; i < GetNumVectorElements(sz); i++) { - MapRegV(v[i], flags); - } -} - -void PpcRegCacheFPU::MapInInV(int vs, int vt) { - SpillLockV(vs); - SpillLockV(vt); - MapRegV(vs); - MapRegV(vt); - ReleaseSpillLockV(vs); - ReleaseSpillLockV(vt); -} - -void PpcRegCacheFPU::MapDirtyInV(int vd, int vs, bool avoidLoad) { - bool overlap = avoidLoad && (vd == vs); - SpillLockV(vd); - SpillLockV(vs); - MapRegV(vd, MAP_DIRTY | (overlap ? 0 : MAP_NOINIT)); - MapRegV(vs); - ReleaseSpillLockV(vd); - ReleaseSpillLockV(vs); -} - -void PpcRegCacheFPU::MapDirtyInInV(int vd, int vs, int vt, bool avoidLoad) { - bool overlap = avoidLoad && ((vd == vs) || (vd == vt)); - SpillLockV(vd); - SpillLockV(vs); - SpillLockV(vt); - MapRegV(vd, MAP_DIRTY | (overlap ? 0 : MAP_NOINIT)); - MapRegV(vs); - MapRegV(vt); - ReleaseSpillLockV(vd); - ReleaseSpillLockV(vs); - ReleaseSpillLockV(vt); -} - -void PpcRegCacheFPU::FlushPpcReg(PPCReg r) { - int reg = r - FPR0; - if (ar[reg].mipsReg == -1) { - // Nothing to do, reg not mapped. - return; - } - if (ar[reg].mipsReg != -1) { - if (ar[reg].isDirty && mr[ar[reg].mipsReg].loc == ML_PPCREG) - { - //INFO_LOG(HLE, "Flushing PPC reg %i", reg); - emit_->SFS(r, CTXREG, GetMipsRegOffset(ar[reg].mipsReg)); - } - // IMMs won't be in an PPC reg. - mr[ar[reg].mipsReg].loc = ML_MEM; - mr[ar[reg].mipsReg].reg = INVALID_REG; - } else { - ERROR_LOG(HLE, "Dirty but no mipsreg?"); - } - ar[reg].isDirty = false; - ar[reg].mipsReg = -1; -} - -void PpcRegCacheFPU::FlushR(MIPSReg r) { - switch (mr[r].loc) { - case ML_IMM: - // IMM is always "dirty". - // IMM is not allowed for FP (yet). - ERROR_LOG(HLE, "Imm in FP register?"); - break; - - case ML_PPCREG: - if (mr[r].reg == (int)INVALID_REG) { - ERROR_LOG(HLE, "FlushR: MipsReg had bad PpcReg"); - } - if (ar[mr[r].reg].isDirty) { - //INFO_LOG(HLE, "Flushing dirty reg %i", mr[r].reg); - emit_->SFS((PPCReg)(mr[r].reg + FPR0), CTXREG, GetMipsRegOffset(r)); - ar[mr[r].reg].isDirty = false; - } - ar[mr[r].reg].mipsReg = -1; - break; - - case ML_MEM: - // Already there, nothing to do. - break; - - default: - //BAD - break; - } - mr[r].loc = ML_MEM; - mr[r].reg = (int)INVALID_REG; -} - -void PpcRegCacheFPU::DiscardR(MIPSReg r) { - switch (mr[r].loc) { - case ML_IMM: - // IMM is always "dirty". - // IMM is not allowed for FP (yet). - ERROR_LOG(HLE, "Imm in FP register?"); - break; - - case ML_PPCREG: - if (mr[r].reg == (int)INVALID_REG) { - ERROR_LOG(HLE, "DiscardR: MipsReg had bad PpcReg"); - } - // Note that we DO NOT write it back here. That's the whole point of Discard. - ar[mr[r].reg].isDirty = false; - ar[mr[r].reg].mipsReg = -1; - break; - - case ML_MEM: - // Already there, nothing to do. - break; - - default: - //BAD - break; - } - mr[r].loc = ML_MEM; - mr[r].reg = (int)INVALID_REG; - mr[r].tempLock = false; - mr[r].spillLock = false; -} - - -bool PpcRegCacheFPU::IsTempX(PPCReg r) const { - return ar[r - FPR0].mipsReg >= TEMP0; -} - -int PpcRegCacheFPU::GetTempR() { - for (int r = TEMP0; r < TEMP0 + NUM_TEMPS; ++r) { - if (mr[r].loc == ML_MEM && !mr[r].tempLock) { - mr[r].tempLock = true; - return r; - } - } - - ERROR_LOG(CPU, "Out of temp regs! Might need to DiscardR() some"); - _assert_msg_(DYNA_REC, 0, "Regcache ran out of temp regs, might need to DiscardR() some."); - return -1; -} - - -void PpcRegCacheFPU::FlushAll() { - // Discard temps! - for (int i = TEMP0; i < TEMP0 + NUM_TEMPS; i++) { - DiscardR(i); - } - for (int i = 0; i < NUM_MIPSFPUREG; i++) { - FlushR(i); - } - // Sanity check - for (int i = 0; i < NUM_PPCFPUREG; i++) { - if (ar[i].mipsReg != -1) { - ERROR_LOG(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); - } - } -} - -int PpcRegCacheFPU::GetMipsRegOffset(MIPSReg r) { - // These are offsets within the MIPSState structure. First there are the GPRS, then FPRS, then the "VFPURs", then the VFPU ctrls. - if (r < 0 || r > 32 + 128 + NUM_TEMPS) { - ERROR_LOG(JIT, "bad mips register %i, out of range", r); - return 0; // or what? - } - - if (r < 32 || r > 32 + 128) { - return (32 + r) << 2; - } else { - // r is between 32 and 128 + 32 - return (32 + 32 + voffset[r - 32]) << 2; - } -} - -void PpcRegCacheFPU::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) { - mr[r1].spillLock = true; - if (r2 != -1) mr[r2].spillLock = true; - if (r3 != -1) mr[r3].spillLock = true; - if (r4 != -1) mr[r4].spillLock = true; -} - -// This is actually pretty slow with all the 160 regs... -void PpcRegCacheFPU::ReleaseSpillLocksAndDiscardTemps() { - for (int i = 0; i < NUM_MIPSFPUREG; i++) - mr[i].spillLock = false; - for (int i = TEMP0; i < TEMP0 + NUM_TEMPS; ++i) - DiscardR(i); -} - -PPCReg PpcRegCacheFPU::R(int mipsReg) { - if (mr[mipsReg].loc == ML_PPCREG) { - return (PPCReg)(mr[mipsReg].reg + FPR0); - } else { - if (mipsReg < 32) { - ERROR_LOG(JIT, "FReg %i not in PPC reg. compilerPC = %08x : %s", mipsReg, compilerPC_, currentMIPS->DisasmAt(compilerPC_)); - } else if (mipsReg < 32 + 128) { - ERROR_LOG(JIT, "VReg %i not in PPC reg. compilerPC = %08x : %s", mipsReg - 32, compilerPC_, currentMIPS->DisasmAt(compilerPC_)); - } else { - ERROR_LOG(JIT, "Tempreg %i not in PPC reg. compilerPC = %08x : %s", mipsReg - 128 - 32, compilerPC_, currentMIPS->DisasmAt(compilerPC_)); - } - return INVALID_REG; // BAAAD - } -} diff --git a/Core/MIPS/PPC/PpcRegCacheFPU.h b/Core/MIPS/PPC/PpcRegCacheFPU.h deleted file mode 100644 index 960e8e5dfa..0000000000 --- a/Core/MIPS/PPC/PpcRegCacheFPU.h +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#pragma once - -#pragma once - -#include "../MIPS.h" -#include "../MIPSAnalyst.h" -#include "Common/PpcEmitter.h" -#include "Core/MIPS/PPC/PpcRegCache.h" -#include "Core/MIPS/MIPSVFPUUtils.h" - -using namespace PpcGen; - -enum { - NUM_TEMPS = 16, - TEMP0 = 32 + 128, - TOTAL_MAPPABLE_MIPSFPUREGS = 32 + 128 + NUM_TEMPS, -}; - -struct FPURegPPC { - int mipsReg; // if -1, no mipsreg attached. - bool isDirty; // Should the register be written back? -}; - -struct FPURegMIPS { - // Where is this MIPS register? - RegMIPSLoc loc; - // Data (only one of these is used, depending on loc. Could make a union). - int reg; - bool spillLock; // if true, this register cannot be spilled. - bool tempLock; - // If loc == ML_MEM, it's back in its location in the CPU context struct. -}; - - -class PpcRegCacheFPU -{ -public: - PpcRegCacheFPU(MIPSState *mips); - ~PpcRegCacheFPU() {} - - void Init(PPCXEmitter *emitter); - void Start(MIPSAnalyst::AnalysisResults &stats); - - // Protect the ppc register containing a MIPS register from spilling, to ensure that - // it's being kept allocated. - void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1, MIPSReg reg4 = -1); - void SpillLockV(MIPSReg r) { SpillLock(r + 32); } - - void ReleaseSpillLocksAndDiscardTemps(); - void ReleaseSpillLock(int mipsreg) - { - mr[mipsreg].spillLock = false; - } - void ReleaseSpillLockV(int mipsreg) { - ReleaseSpillLock(mipsreg + 32); - } - - void SetImm(MIPSReg reg, u32 immVal); - bool IsImm(MIPSReg reg) const; - u32 GetImm(MIPSReg reg) const; - - // Returns an PPC register containing the requested MIPS register. - PPCReg MapReg(MIPSReg reg, int mapFlags = 0); - void MapInIn(MIPSReg rd, MIPSReg rs); - void MapInInV(int rt, int rs); - void MapDirtyInV(int rd, int rs, bool avoidLoad = true); - void MapDirtyInInV(int rd, int rs, int rt, bool avoidLoad = true); - void MapDirty(MIPSReg rd); - void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true); - void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); - void FlushPpcReg(PPCReg r); - void FlushR(MIPSReg r); - void FlushV(MIPSReg r) { FlushR(r + 32); } - void DiscardR(MIPSReg r); - void DiscardV(MIPSReg r) { DiscardR(r + 32);} - bool IsTempX(PPCReg r) const; - - MIPSReg GetTempR(); - MIPSReg GetTempV() { return GetTempR() - 32; } - - void FlushAll(); - - PPCReg R(int preg); // Returns a cached register - - // VFPU registers - - PPCReg V(int vreg) { return R(vreg + 32); } - - void MapRegV(int vreg, int flags = 0); - - void LoadToRegV(PPCReg ppcReg, int vreg); - - // NOTE: These require you to release spill locks manually! - void MapRegsAndSpillLockV(int vec, VectorSize vsz, int flags); - void MapRegsAndSpillLockV(const u8 *v, VectorSize vsz, int flags); - - void SpillLockV(const u8 *v, VectorSize vsz); - void SpillLockV(int vec, VectorSize vsz); - - void SetEmitter(PPCXEmitter *emitter) { emit_ = emitter; } - - // For better log output only. - void SetCompilerPC(u32 compilerPC) { compilerPC_ = compilerPC; } - - int GetMipsRegOffset(MIPSReg r); - int GetMipsRegOffsetV(MIPSReg r) { - return GetMipsRegOffset(r + 32); - } - -private: - MIPSState *mips_; - PPCXEmitter *emit_; - u32 compilerPC_; - - enum { - NUM_PPCFPUREG = 32, - NUM_MIPSFPUREG = TOTAL_MAPPABLE_MIPSFPUREGS, - }; - - RegPPC ar[NUM_PPCFPUREG]; - FPURegMIPS mr[NUM_MIPSFPUREG]; - FPURegMIPS *vr; -}; diff --git a/Core/MIPS/PPC/PpcRegCacheVPU.cpp b/Core/MIPS/PPC/PpcRegCacheVPU.cpp deleted file mode 100644 index 59faa11a62..0000000000 --- a/Core/MIPS/PPC/PpcRegCacheVPU.cpp +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include -#include "PpcRegCacheVPU.h" -#include "PpcJit.h" - -using namespace PpcGen; - -PpcRegCacheVPU::PpcRegCacheVPU(MIPSState *mips, MIPSComp::PpcJitOptions *options) : mips_(mips), options_(options) { -} - -void PpcRegCacheVPU::Init(PPCXEmitter *emitter) { - emit_ = emitter; -} - -void PpcRegCacheVPU::Start(MIPSAnalyst::AnalysisResults &stats) { - for (int i = 0; i < NUM_PPCVPUREG; i++) { - ar[i].mipsReg = -1; - ar[i].isDirty = false; - } - for (int i = 0; i < NUM_MIPSVPUREG; i++) { - mr[i].loc = ML_MEM; - mr[i].reg = INVALID_REG; - mr[i].imm = -1; - mr[i].spillLock = false; - } -} - -const PPCReg *PpcRegCacheVPU::GetMIPSAllocationOrder(int &count) const { - // Note that R0 is reserved as scratch for now. - // R1 could be used as it's only used for scratch outside "regalloc space" now. - // R12 is also potentially usable. - // R4-R7 are registers we could use for static allocation or downcount. - // R8 is used to preserve flags in nasty branches. - // R9 and upwards are reserved for jit basics. - if (options_->downcountInRegister) { - static const PPCReg allocationOrder[] = { - /*R14, R15, R16, R17, R18, R19,*/ - R20, R21, R22, R23, R24, R25, - R26, R27, R28, R29, R30, R31, - }; - count = sizeof(allocationOrder) / sizeof(const int); - return allocationOrder; - } else { - static const PPCReg allocationOrder2[] = { - /*R14, R15, R16, R17, R18, R19,*/ - R20, R21, R22, R23, R24, R25, - R26, R27, R28, R29, R30, R31, - }; - count = sizeof(allocationOrder2) / sizeof(const int); - return allocationOrder2; - } -} - -void PpcRegCacheVPU::FlushBeforeCall() { - // R4-R11 are preserved. Others need flushing. - /* - FlushPpcReg(R2); - FlushPpcReg(R3); - FlushPpcReg(R12); - */ -} - -// TODO: Somewhat smarter spilling - currently simply spills the first available, should do -// round robin or FIFO or something. -PPCReg PpcRegCacheVPU::MapReg(MIPSReg mipsReg, int mapFlags) { - // Let's see if it's already mapped. If so we just need to update the dirty flag. - // We don't need to check for ML_NOINIT because we assume that anyone who maps - // with that flag immediately writes a "known" value to the register. - if (mr[mipsReg].loc == ML_PPCREG) { - if (ar[mr[mipsReg].reg].mipsReg != mipsReg) { - ERROR_LOG(HLE, "Register mapping out of sync! %i", mipsReg); - } - if (mapFlags & MAP_DIRTY) { - ar[mr[mipsReg].reg].isDirty = true; - } - return (PPCReg)mr[mipsReg].reg; - } - - // Okay, not mapped, so we need to allocate an ARM register. - - int allocCount; - const PPCReg *allocOrder = GetMIPSAllocationOrder(allocCount); - -allocate: - for (int i = 0; i < allocCount; i++) { - int reg = allocOrder[i]; - - if (ar[reg].mipsReg == -1) { - // That means it's free. Grab it, and load the value into it (if requested). - ar[reg].isDirty = (mapFlags & MAP_DIRTY) ? true : false; - if (!(mapFlags & MAP_NOINIT)) { - if (mr[mipsReg].loc == ML_MEM) { - if (mipsReg != 0) { - emit_->LWZ((PPCReg)reg, CTXREG, GetMipsRegOffset(mipsReg)); - } else { - // If we get a request to load the zero register, at least we won't spend - // time on a memory access... - emit_->MOVI2R((PPCReg)reg, 0); - } - } else if (mr[mipsReg].loc == ML_IMM) { - emit_->MOVI2R((PPCReg)reg, mr[mipsReg].imm); - ar[reg].isDirty = true; // IMM is always dirty. - } - } - ar[reg].mipsReg = mipsReg; - mr[mipsReg].loc = ML_PPCREG; - mr[mipsReg].reg = (PPCReg)reg; - return (PPCReg)reg; - } - } - - // Still nothing. Let's spill a reg and goto 10. - // TODO: Use age or something to choose which register to spill? - // TODO: Spill dirty regs first? or opposite? - int bestToSpill = -1; - for (int i = 0; i < allocCount; i++) { - int reg = allocOrder[i]; - if (ar[reg].mipsReg != -1 && mr[ar[reg].mipsReg].spillLock) - continue; - bestToSpill = reg; - break; - } - - if (bestToSpill != -1) { - // ERROR_LOG(JIT, "Out of registers at PC %08x - spills register %i.", mips_->pc, bestToSpill); - FlushPpcReg((PPCReg)bestToSpill); - goto allocate; - } - - // Uh oh, we have all them spilllocked.... - ERROR_LOG(JIT, "Out of spillable registers at PC %08x!!!", mips_->pc); - return INVALID_REG; -} - -void PpcRegCacheVPU::MapInIn(MIPSReg rd, MIPSReg rs) { - SpillLock(rd, rs); - MapReg(rd); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCacheVPU::MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad) { - SpillLock(rd, rs); - bool load = !avoidLoad || rd == rs; - MapReg(rd, MAP_DIRTY | (load ? 0 : MAP_NOINIT)); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCacheVPU::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad) { - SpillLock(rd, rs, rt); - bool load = !avoidLoad || (rd == rs || rd == rt); - MapReg(rd, MAP_DIRTY | (load ? 0 : MAP_NOINIT)); - MapReg(rt); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCacheVPU::MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad) { - SpillLock(rd1, rd2, rs, rt); - bool load1 = !avoidLoad || (rd1 == rs || rd1 == rt); - bool load2 = !avoidLoad || (rd2 == rs || rd2 == rt); - MapReg(rd1, MAP_DIRTY | (load1 ? 0 : MAP_NOINIT)); - MapReg(rd2, MAP_DIRTY | (load2 ? 0 : MAP_NOINIT)); - MapReg(rt); - MapReg(rs); - ReleaseSpillLocks(); -} - -void PpcRegCacheVPU::FlushPpcReg(PPCReg r) { - if (ar[r].mipsReg == -1) { - // Nothing to do, reg not mapped. - return; - } - if (ar[r].mipsReg != -1) { - if (ar[r].isDirty && mr[ar[r].mipsReg].loc == ML_PPCREG) - emit_->STW(r, CTXREG, GetMipsRegOffset(ar[r].mipsReg)); - // IMMs won't be in an ARM reg. - mr[ar[r].mipsReg].loc = ML_MEM; - mr[ar[r].mipsReg].reg = INVALID_REG; - mr[ar[r].mipsReg].imm = 0; - } else { - ERROR_LOG(HLE, "Dirty but no mipsreg?"); - } - ar[r].isDirty = false; - ar[r].mipsReg = -1; -} - -void PpcRegCacheVPU::FlushR(MIPSReg r) { - switch (mr[r].loc) { - case ML_IMM: - // IMM is always "dirty". - emit_->MOVI2R(SREG, mr[r].imm); - emit_->STW(SREG, CTXREG, GetMipsRegOffset(r)); - break; - - case ML_PPCREG: - if (mr[r].reg == INVALID_REG) { - ERROR_LOG(HLE, "FlushMipsReg: MipsReg had bad PpcReg"); - } - if (ar[mr[r].reg].isDirty) { - emit_->STW((PPCReg)mr[r].reg, CTXREG, GetMipsRegOffset(r)); - ar[mr[r].reg].isDirty = false; - } - ar[mr[r].reg].mipsReg = -1; - break; - - case ML_MEM: - // Already there, nothing to do. - break; - - default: - //BAD - break; - } - mr[r].loc = ML_MEM; - mr[r].reg = INVALID_REG; - mr[r].imm = 0; -} - -void PpcRegCacheVPU::FlushAll() { - for (int i = 0; i < NUM_MIPSVPUREG; i++) { - FlushR(i); - } - // Sanity check - for (int i = 0; i < NUM_PPCVPUREG; i++) { - if (ar[i].mipsReg != -1) { - ERROR_LOG(JIT, "Flush fail: ar[%i].mipsReg=%i", i, ar[i].mipsReg); - } - } -} - -void PpcRegCacheVPU::SetImm(MIPSReg r, u32 immVal) { - if (r == 0) - ERROR_LOG(JIT, "Trying to set immediate %08x to r0", immVal); - - // Zap existing value if cached in a reg - if (mr[r].loc == ML_PPCREG) { - ar[mr[r].reg].mipsReg = -1; - ar[mr[r].reg].isDirty = false; - } - mr[r].loc = ML_IMM; - mr[r].imm = immVal; - mr[r].reg = INVALID_REG; -} - -bool PpcRegCacheVPU::IsImm(MIPSReg r) const { - if (r == 0) return true; - return mr[r].loc == ML_IMM; -} - -u32 PpcRegCacheVPU::GetImm(MIPSReg r) const { - if (r == 0) return 0; - if (mr[r].loc != ML_IMM) { - ERROR_LOG(JIT, "Trying to get imm from non-imm register %i", r); - } - return mr[r].imm; -} - -int PpcRegCacheVPU::GetMipsRegOffset(MIPSReg r) { - if (r < 32) - return r * 4; - switch (r) { - case MIPSREG_HI: - return offsetof(MIPSState, hi); - case MIPSREG_LO: - return offsetof(MIPSState, lo); - } - ERROR_LOG(JIT, "bad mips register %i", r); - return 0; // or what? -} - -void PpcRegCacheVPU::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) { - mr[r1].spillLock = true; - if (r2 != -1) mr[r2].spillLock = true; - if (r3 != -1) mr[r3].spillLock = true; - if (r4 != -1) mr[r4].spillLock = true; -} - -void PpcRegCacheVPU::ReleaseSpillLocks() { - for (int i = 0; i < NUM_MIPSVPUREG; i++) { - mr[i].spillLock = false; - } -} - -void PpcRegCacheVPU::ReleaseSpillLock(MIPSReg reg) { - mr[reg].spillLock = false; -} - -PPCReg PpcRegCacheVPU::R(int mipsReg) { - if (mr[mipsReg].loc == ML_PPCREG) { - return (PPCReg)mr[mipsReg].reg; - } else { - ERROR_LOG(JIT, "Reg %i not in ppc reg. compilerPC = %08x", mipsReg, compilerPC_); - return INVALID_REG; // BAAAD - } -} diff --git a/Core/MIPS/PPC/PpcRegCacheVPU.h b/Core/MIPS/PPC/PpcRegCacheVPU.h deleted file mode 100644 index eaf836eec8..0000000000 --- a/Core/MIPS/PPC/PpcRegCacheVPU.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2012- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - - -/** -PPC reg cache based on arm version -**/ - -#pragma once - -#include "../MIPS.h" -#include "../MIPSAnalyst.h" -#include "ppcEmitter.h" -#include "Core/MIPS/PPC/PpcRegCache.h" - -using namespace PpcGen; - -typedef int MIPSReg; - -struct VPURegPPC { - int mipsReg; // if -1, no mipsreg attached. - bool isDirty; // Should the register be written back? -}; - -struct VPURegMIPS { - // Where is this MIPS register? - RegMIPSLoc loc; - // Data (only one of these is used, depending on loc. Could make a union). - u32 imm; - PPCReg reg; // reg index - bool spillLock; // if true, this register cannot be spilled. - // If loc == ML_MEM, it's back in its location in the CPU context struct. -}; -namespace MIPSComp { - struct PpcJitOptions; -} - -class PpcRegCacheVPU -{ -public: - PpcRegCacheVPU(MIPSState *mips, MIPSComp::PpcJitOptions *options); - ~PpcRegCacheVPU() {} - - void Init(PPCXEmitter *emitter); - void Start(MIPSAnalyst::AnalysisResults &stats); - - // Protect the arm register containing a MIPS register from spilling, to ensure that - // it's being kept allocated. - void SpillLock(MIPSReg reg, MIPSReg reg2 = -1, MIPSReg reg3 = -1, MIPSReg reg4 = -1); - void ReleaseSpillLock(MIPSReg reg); - void ReleaseSpillLocks(); - - void SetImm(MIPSReg reg, u32 immVal); - bool IsImm(MIPSReg reg) const; - u32 GetImm(MIPSReg reg) const; - - // Returns an ARM register containing the requested MIPS register. - PPCReg MapReg(MIPSReg reg, int mapFlags = 0); - void MapInIn(MIPSReg rd, MIPSReg rs); - void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true); - void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); - void MapDirtyDirtyInIn(MIPSReg rd1, MIPSReg rd2, MIPSReg rs, MIPSReg rt, bool avoidLoad = true); - void FlushPpcReg(PPCReg r); - void FlushR(MIPSReg r); - void FlushBeforeCall(); - void FlushAll(); - - PPCReg R(int preg); // Returns a cached register - - void SetEmitter(PPCXEmitter *emitter) { emit_ = emitter; } - - // For better log output only. - void SetCompilerPC(u32 compilerPC) { compilerPC_ = compilerPC; } - - int GetMipsRegOffset(MIPSReg r); - -private: - const PPCReg *GetMIPSAllocationOrder(int &count) const; - - MIPSState *mips_; - MIPSComp::PpcJitOptions *options_; - PPCXEmitter *emit_; - u32 compilerPC_; - - enum { - NUM_PPCVPUREG = 128, - NUM_MIPSVPUREG = 32, - }; - - VPURegPPC ar[NUM_PPCVPUREG]; - VPURegMIPS mr[NUM_MIPSVPUREG]; -};