From ae4420e6046d4ad3c5790f396c88ea4184b5ebd5 Mon Sep 17 00:00:00 2001 From: Andrew Church Date: Sun, 18 Jan 2015 07:00:58 +0900 Subject: [PATCH] Implement missing PPU instructions. --- rpcs3/Emu/Cell/PPUDisAsm.h | 4 + rpcs3/Emu/Cell/PPUInstrTable.h | 48 +++++--- rpcs3/Emu/Cell/PPUInterpreter.h | 169 +++++++++++++++++---------- rpcs3/Emu/Cell/PPULLVMRecompiler.cpp | 10 ++ rpcs3/Emu/Cell/PPULLVMRecompiler.h | 1 + rpcs3/Emu/Cell/PPUOpcodes.h | 19 +++ rpcs3/Emu/Cell/PPUThread.h | 8 +- 7 files changed, 179 insertions(+), 80 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 531b21bc37..228c9edd4e 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -1675,6 +1675,10 @@ private: { DisAsm_V1_R2("stvlx", vs, ra, rb); } + void STDBRX(u32 rs, u32 ra, u32 rb) + { + DisAsm_R3("stdbrx", rs, ra, rb); + } void STSWX(u32 rs, u32 ra, u32 rb) { DisAsm_R3("swswx", rs, ra, rb); diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h index c9f03c789d..a22627f2ae 100644 --- a/rpcs3/Emu/Cell/PPUInstrTable.h +++ b/rpcs3/Emu/Cell/PPUInstrTable.h @@ -226,6 +226,9 @@ namespace PPU_instr #define bind_instr(list, name, ...) \ static const auto& name = make_instr(list, #name, &PPUOpcodes::name, ##__VA_ARGS__) +#define bind_instr_oe(list, name, ...) \ + bind_instr(list, name, ##__VA_ARGS__); \ + static const auto& name##O = make_instr(list, #name "O", &PPUOpcodes::name, ##__VA_ARGS__) bind_instr(main_list, TDI, TO, RA, simm16); bind_instr(main_list, TWI, TO, RA, simm16); @@ -456,9 +459,9 @@ namespace PPU_instr /*0x004*/bind_instr(g1f_list, TW, TO, RA, RB); /*0x006*/bind_instr(g1f_list, LVSL, VD, RA, RB); /*0x007*/bind_instr(g1f_list, LVEBX, VD, RA, RB); - /*0x008*/bind_instr(g1f_list, SUBFC, RD, RA, RB, OE, RC); + /*0x008*/bind_instr_oe(g1f_list, SUBFC, RD, RA, RB, OE, RC); /*0x009*/bind_instr(g1f_list, MULHDU, RD, RA, RB, RC); - /*0x00a*/bind_instr(g1f_list, ADDC, RD, RA, RB, OE, RC); + /*0x00a*/bind_instr_oe(g1f_list, ADDC, RD, RA, RB, OE, RC); /*0x00b*/bind_instr(g1f_list, MULHWU, RD, RA, RB, RC); /*0x013*/bind_instr(g1f_list, MFOCRF, L_11, RD, CRM); /*0x014*/bind_instr(g1f_list, LWARX, RD, RA, RB); @@ -471,7 +474,7 @@ namespace PPU_instr /*0x020*/bind_instr(g1f_list, CMPL, CRFD, L_10, RA, RB); /*0x026*/bind_instr(g1f_list, LVSR, VD, RA, RB); /*0x027*/bind_instr(g1f_list, LVEHX, VD, RA, RB); - /*0x028*/bind_instr(g1f_list, SUBF, RD, RA, RB, OE, RC); + /*0x028*/bind_instr_oe(g1f_list, SUBF, RD, RA, RB, OE, RC); /*0x035*/bind_instr(g1f_list, LDUX, RD, RA, RB); /*0x036*/bind_instr(g1f_list, DCBST, RA, RB); /*0x037*/bind_instr(g1f_list, LWZUX, RD, RA, RB); @@ -485,12 +488,12 @@ namespace PPU_instr /*0x056*/bind_instr(g1f_list, DCBF, RA, RB); /*0x057*/bind_instr(g1f_list, LBZX, RD, RA, RB); /*0x067*/bind_instr(g1f_list, LVX, VD, RA, RB); - /*0x068*/bind_instr(g1f_list, NEG, RD, RA, OE, RC); + /*0x068*/bind_instr_oe(g1f_list, NEG, RD, RA, OE, RC); /*0x077*/bind_instr(g1f_list, LBZUX, RD, RA, RB); /*0x07c*/bind_instr(g1f_list, NOR, RA, RS, RB, RC); /*0x087*/bind_instr(g1f_list, STVEBX, VS, RA, RB); - /*0x088*/bind_instr(g1f_list, SUBFE, RD, RA, RB, OE, RC); - /*0x08a*/bind_instr(g1f_list, ADDE, RD, RA, RB, OE, RC); + /*0x088*/bind_instr_oe(g1f_list, SUBFE, RD, RA, RB, OE, RC); + /*0x08a*/bind_instr_oe(g1f_list, ADDE, RD, RA, RB, OE, RC); /*0x090*/bind_instr(g1f_list, MTOCRF, L_11, CRM, RS); /*0x095*/bind_instr(g1f_list, STDX, RS, RA, RB); /*0x096*/bind_instr(g1f_list, STWCX_, RS, RA, RB); @@ -499,18 +502,18 @@ namespace PPU_instr /*0x0b5*/bind_instr(g1f_list, STDUX, RS, RA, RB); /*0x0b7*/bind_instr(g1f_list, STWUX, RS, RA, RB); /*0x0c7*/bind_instr(g1f_list, STVEWX, VS, RA, RB); - /*0x0c8*/bind_instr(g1f_list, SUBFZE, RD, RA, OE, RC); - /*0x0ca*/bind_instr(g1f_list, ADDZE, RD, RA, OE, RC); + /*0x0c8*/bind_instr_oe(g1f_list, SUBFZE, RD, RA, OE, RC); + /*0x0ca*/bind_instr_oe(g1f_list, ADDZE, RD, RA, OE, RC); /*0x0d6*/bind_instr(g1f_list, STDCX_, RS, RA, RB); /*0x0d7*/bind_instr(g1f_list, STBX, RS, RA, RB); /*0x0e7*/bind_instr(g1f_list, STVX, VS, RA, RB); - /*0x0e8*/bind_instr(g1f_list, SUBFME, RD, RA, OE, RC); - /*0x0e9*/bind_instr(g1f_list, MULLD, RD, RA, RB, OE, RC); - /*0x0ea*/bind_instr(g1f_list, ADDME, RD, RA, OE, RC); - /*0x0eb*/bind_instr(g1f_list, MULLW, RD, RA, RB, OE, RC); + /*0x0e8*/bind_instr_oe(g1f_list, SUBFME, RD, RA, OE, RC); + /*0x0e9*/bind_instr_oe(g1f_list, MULLD, RD, RA, RB, OE, RC); + /*0x0ea*/bind_instr_oe(g1f_list, ADDME, RD, RA, OE, RC); + /*0x0eb*/bind_instr_oe(g1f_list, MULLW, RD, RA, RB, OE, RC); /*0x0f6*/bind_instr(g1f_list, DCBTST, RA, RB, TH); /*0x0f7*/bind_instr(g1f_list, STBUX, RS, RA, RB); - /*0x10a*/bind_instr(g1f_list, ADD, RD, RA, RB, OE, RC); + /*0x10a*/bind_instr_oe(g1f_list, ADD, RD, RA, RB, OE, RC); /*0x116*/bind_instr(g1f_list, DCBT, RA, RB, TH); /*0x117*/bind_instr(g1f_list, LHZX, RD, RA, RB); /*0x11c*/bind_instr(g1f_list, EQV, RA, RS, RB, RC); @@ -531,15 +534,21 @@ namespace PPU_instr /*0x1b6*/bind_instr(g1f_list, ECOWX, RS, RA, RB); /*0x1b7*/bind_instr(g1f_list, STHUX, RS, RA, RB); /*0x1bc*/bind_instr(g1f_list, OR, RA, RS, RB, RC); - /*0x1c9*/bind_instr(g1f_list, DIVDU, RD, RA, RB, OE, RC); - /*0x1cb*/bind_instr(g1f_list, DIVWU, RD, RA, RB, OE, RC); + /*0x1c9*/bind_instr_oe(g1f_list, DIVDU, RD, RA, RB, OE, RC); + /*0x1cb*/bind_instr_oe(g1f_list, DIVWU, RD, RA, RB, OE, RC); /*0x1d3*/bind_instr(g1f_list, MTSPR, SPR, RS); /*0x1d6*///DCBI /*0x1dc*/bind_instr(g1f_list, NAND, RA, RS, RB, RC); /*0x1e7*/bind_instr(g1f_list, STVXL, VS, RA, RB); - /*0x1e9*/bind_instr(g1f_list, DIVD, RD, RA, RB, OE, RC); - /*0x1eb*/bind_instr(g1f_list, DIVW, RD, RA, RB, OE, RC); + /*0x1e9*/bind_instr_oe(g1f_list, DIVD, RD, RA, RB, OE, RC); + /*0x1eb*/bind_instr_oe(g1f_list, DIVW, RD, RA, RB, OE, RC); /*0x207*/bind_instr(g1f_list, LVLX, VD, RA, RB); + // MULH{D|DU|W|WU} don't use OE, but a real Cell accepts + // opcodes with OE=1 and Rc=0, behaving as if OE was not set. + // OE=1 and Rc=1 causes an invalid instruction exception, but + // we don't worry about that. + static const auto& MULHDUO = make_instr<0x209>(g1f_list, "MULHDUO", &PPUOpcodes::MULHDU, RD, RA, RB, RC); + static const auto& MULHWUO = make_instr<0x20b>(g1f_list, "MULHWUO", &PPUOpcodes::MULHWU, RD, RA, RB, RC); /*0x214*/bind_instr(g1f_list, LDBRX, RD, RA, RB); /*0x215*/bind_instr(g1f_list, LSWX, RD, RA, RB); /*0x216*/bind_instr(g1f_list, LWBRX, RD, RA, RB); @@ -548,11 +557,14 @@ namespace PPU_instr /*0x21b*/bind_instr(g1f_list, SRD, RA, RS, RB, RC); /*0x227*/bind_instr(g1f_list, LVRX, VD, RA, RB); /*0x237*/bind_instr(g1f_list, LFSUX, FRD, RA, RB); + static const auto& MULHDO = make_instr<0x249>(g1f_list, "MULHDO", &PPUOpcodes::MULHD, RD, RA, RB, RC); + static const auto& MULHWO = make_instr<0x24b>(g1f_list, "MULHWO", &PPUOpcodes::MULHW, RD, RA, RB, RC); /*0x255*/bind_instr(g1f_list, LSWI, RD, RA, NB); /*0x256*/bind_instr(g1f_list, SYNC, L_9_10); /*0x257*/bind_instr(g1f_list, LFDX, FRD, RA, RB); /*0x277*/bind_instr(g1f_list, LFDUX, FRD, RA, RB); /*0x287*/bind_instr(g1f_list, STVLX, VS, RA, RB); + /*0x294*/bind_instr(g1f_list, STDBRX, RD, RA, RB); /*0x296*/bind_instr(g1f_list, STSWX, RS, RA, RB); /*0x296*/bind_instr(g1f_list, STWBRX, RS, RA, RB); /*0x297*/bind_instr(g1f_list, STFSX, FRS, RA, RB); @@ -657,4 +669,4 @@ namespace PPU_instr using namespace lists; using namespace implicts; #undef bind_instr -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index ba6ad22b1e..460cf632a3 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -2381,16 +2381,16 @@ private: const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = ~RA + RB + 1; CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if(oe) throw "SUBFC(): subfco"; + if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; + const u64 RA = CPU.GPR[ra]; + const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = RA + RB; CPU.XER.CA = CPU.IsCarry(RA, RB); - if(oe) throw "ADDC(): addco"; + if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void MULHDU(u32 rd, u32 ra, u32 rb, bool rc) @@ -2526,8 +2526,10 @@ private: } void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { - CPU.GPR[rd] = CPU.GPR[rb] - CPU.GPR[ra]; - if(oe) throw "SUBF(): subfo"; + const u64 RA = CPU.GPR[ra]; + const u64 RB = CPU.GPR[rb]; + CPU.GPR[rd] = RB - RA; + if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void LDUX(u32 rd, u32 ra, u32 rb) @@ -2605,8 +2607,9 @@ private: } void NEG(u32 rd, u32 ra, u32 oe, bool rc) { - CPU.GPR[rd] = 0-CPU.GPR[ra]; - if(oe) throw "NEG(): nego"; + const u64 RA = CPU.GPR[ra]; + CPU.GPR[rd] = 0 - RA; + if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void LBZUX(u32 rd, u32 ra, u32 rb) @@ -2634,8 +2637,8 @@ private: const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = ~RA + RB + CPU.XER.CA; CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); + if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) throw "SUBFE(): subfeo"; } void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { @@ -2659,8 +2662,8 @@ private: CPU.GPR[rd] = RA + RB; CPU.XER.CA = CPU.IsCarry(RA, RB); } + if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) throw "ADDE(): addeo"; } void MTOCRF(u32 l, u32 crm, u32 rs) { @@ -2748,7 +2751,7 @@ private: const u64 RA = CPU.GPR[ra]; CPU.GPR[rd] = RA + CPU.XER.CA; CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if(oe) LOG_WARNING(PPU, "addzeo"); + if(oe) CPU.SetOV((RA>>63 == 0) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void SUBFZE(u32 rd, u32 ra, u32 oe, bool rc) @@ -2756,8 +2759,8 @@ private: const u64 RA = CPU.GPR[ra]; CPU.GPR[rd] = ~RA + CPU.XER.CA; CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if (oe) LOG_WARNING(PPU, "subfzeo"); - if (rc) CPU.UpdateCR0(CPU.GPR[rd]); + if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); + if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void STDCX_(u32 rs, u32 ra, u32 rb) { @@ -2787,14 +2790,20 @@ private: const u64 RA = CPU.GPR[ra]; CPU.GPR[rd] = ~RA + CPU.XER.CA + ~0ULL; CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if (oe) LOG_WARNING(PPU, "subfmeo"); - if (rc) CPU.UpdateCR0(CPU.GPR[rd]); + if(oe) CPU.SetOV((~RA>>63 == 1) && (~RA>>63 != CPU.GPR[rd]>>63)); + if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { - CPU.GPR[rd] = (s64)((s64)CPU.GPR[ra] * (s64)CPU.GPR[rb]); + const s64 RA = CPU.GPR[ra]; + const s64 RB = CPU.GPR[rb]; + CPU.GPR[rd] = (s64)(RA * RB); + if(oe) + { + const s64 high = __mulh(RA, RB); + CPU.SetOV(high != s64(CPU.GPR[rd]) >> 63); + } if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) throw "MULLD(): mulldo"; } void ADDME(u32 rd, u32 ra, u32 oe, bool rc) { @@ -2802,14 +2811,14 @@ private: CPU.GPR[rd] = RA + CPU.XER.CA - 1; CPU.XER.CA |= RA != 0; - if(oe) throw "ADDME(): addmeo"; + if(oe) CPU.SetOV((u64(RA)>>63 == 1) && (u64(RA)>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { CPU.GPR[rd] = (s64)((s64)(s32)CPU.GPR[ra] * (s64)(s32)CPU.GPR[rb]); + if(oe) CPU.SetOV(s64(CPU.GPR[rd]) < s64(-1)<<31 || s64(CPU.GPR[rd]) >= s64(1)<<31); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) throw "MULLW(): mullwo"; } void DCBTST(u32 ra, u32 rb, u32 th) { @@ -2825,7 +2834,7 @@ private: const u64 RA = CPU.GPR[ra]; const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = RA + RB; - if(oe) throw "ADD(): addo"; + if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void DCBT(u32 ra, u32 rb, u32 th) @@ -2940,11 +2949,12 @@ private: if(RB == 0) { - if(oe) throw "DIVDU(): divduo"; + if(oe) CPU.SetOV(true); CPU.GPR[rd] = 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = RA / RB; } @@ -2957,11 +2967,12 @@ private: if(RB == 0) { - if(oe) throw "DIVWU(): divwuo"; + if(oe) CPU.SetOV(true); CPU.GPR[rd] = 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = RA / RB; } @@ -2991,11 +3002,12 @@ private: if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) { - if(oe) throw "DIVD(): divdo"; + if(oe) CPU.SetOV(true); CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = RA / RB; } @@ -3008,11 +3020,12 @@ private: if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) { - if(oe) throw "DIVW(): divwo"; + if(oe) CPU.SetOV(true); CPU.GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = (u32)(RA / RB); } @@ -3033,7 +3046,22 @@ private: } void LSWX(u32 rd, u32 ra, u32 rb) { - throw "LSWX()"; + u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + u32 count = CPU.XER.XER & 0x7F; + for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31) + { + CPU.GPR[rd] = vm::get_ref>(vm::cast(addr)); + } + if (count) + { + u32 value = 0; + for (u32 byte = 0; byte < count; byte++) + { + u32 byte_value = vm::get_ref(vm::cast(addr+byte)); + value |= byte_value << ((3^byte)*8); + } + CPU.GPR[rd] = value; + } } void LWBRX(u32 rd, u32 ra, u32 rb) { @@ -3129,9 +3157,28 @@ private: for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i), CPU.VPR[vs]._u8[15 - i]); } + void STDBRX(u32 rs, u32 ra, u32 rb) + { + const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + vm::get_ref(vm::cast(addr)) = CPU.GPR[rs]; + } void STSWX(u32 rs, u32 ra, u32 rb) { - throw "STSWX()"; + u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + u32 count = CPU.XER.XER & 0x7F; + for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31) + { + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); + } + if (count) + { + u32 value = (u32)CPU.GPR[rs]; + for (u32 byte = 0; byte < count; byte++) + { + u32 byte_value = (u8)(value >> ((3^byte)*8)); + vm::write8(vm::cast(addr+byte), byte_value); + } + } } void STWBRX(u32 rs, u32 ra, u32 rb) { @@ -3520,25 +3567,25 @@ private: } CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FDIVS(): fdivs.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FSUBS(u32 frd, u32 fra, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(CPU.FPR[fra] - CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FSUBS(): fsubs.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FADDS(u32 frd, u32 fra, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(CPU.FPR[fra] + CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FADDS(): fadds.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FSQRTS(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(sqrt(CPU.FPR[frb])); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FSQRTS(): fsqrts.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FRES(u32 frd, u32 frb, bool rc) { @@ -3547,7 +3594,7 @@ private: CPU.SetFPSCRException(FPSCR_ZX); } CPU.FPR[frd] = static_cast(1.0 / CPU.FPR[frb]); - if(rc) throw "FRES(): fres.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMULS(u32 frd, u32 fra, u32 frc, bool rc) { @@ -3555,31 +3602,31 @@ private: CPU.FPSCR.FI = 0; CPU.FPSCR.FR = 0; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FMULS(): fmuls.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FMADDS(): fmadds.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FMSUBS(): fmsubs.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(-(CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb])); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FNMSUBS(): fnmsubs.";////CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = static_cast(-(CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb])); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FNMADDS(): fnmadds.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void STD(u32 rs, u32 ra, s32 d) { @@ -3599,7 +3646,7 @@ private: if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); CPU.FPSCR.FPSCR |= mask; - if(rc) throw "MTFSB1(): mtfsb1."; + if(rc) CPU.UpdateCR1(); } void MCRFS(u32 crbd, u32 crbs) { @@ -3632,7 +3679,7 @@ private: if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); CPU.FPSCR.FPSCR &= ~mask; - if(rc) throw "MTFSB0(): mtfsb0."; + if(rc) CPU.UpdateCR1(); } void MTFSFI(u32 crfd, u32 i, bool rc) { @@ -3650,12 +3697,12 @@ private: LOG_WARNING(PPU, "Non-IEEE mode enabled"); } - if(rc) throw "MTFSFI(): mtfsfi."; + if(rc) CPU.UpdateCR1(); } void MFFS(u32 frd, bool rc) { (u64&)CPU.FPR[frd] = CPU.FPSCR.FPSCR; - if(rc) throw "MFFS(): mffs."; + if(rc) CPU.UpdateCR1(); } void MTFSF(u32 flm, u32 frb, bool rc) { @@ -3674,7 +3721,7 @@ private: else LOG_WARNING(PPU, "Non-IEEE mode enabled"); } - if(rc) throw "MTFSF(): mtfsf."; + if(rc) CPU.UpdateCR1(); } void FCMPU(u32 crfd, u32 fra, u32 frb) { @@ -3762,7 +3809,7 @@ private: } (u64&)CPU.FPR[frd] = r; - if(rc) throw "FCTIW(): fctiw."; + if(rc) CPU.UpdateCR1(); } void FCTIWZ(u32 frd, u32 frb, bool rc) { @@ -3800,7 +3847,7 @@ private: } (u64&)CPU.FPR[frd] = (u64)value; - if(rc) throw "FCTIWZ(): fctiwz."; + if(rc) CPU.UpdateCR1(); } void FDIV(u32 frd, u32 fra, u32 frb, bool rc) { @@ -3843,30 +3890,30 @@ private: CPU.FPR[frd] = res; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FDIV(): fdiv.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FSUB(u32 frd, u32 fra, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[fra] - CPU.FPR[frb]; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FSUB(): fsub.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FADD(u32 frd, u32 fra, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[fra] + CPU.FPR[frb]; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FASS(): fadd.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FSQRT(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = sqrt(CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FSQRT(): fsqrt.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[fra] >= 0.0 ? CPU.FPR[frc] : CPU.FPR[frb]; - if(rc) throw "FSEL(): fsel.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMUL(u32 frd, u32 fra, u32 frc, bool rc) { @@ -3889,7 +3936,7 @@ private: CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); } - if(rc) throw "FMUL(): fmul.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FRSQRTE(u32 frd, u32 frb, bool rc) { @@ -3898,31 +3945,31 @@ private: CPU.SetFPSCRException(FPSCR_ZX); } CPU.FPR[frd] = 1.0 / sqrt(CPU.FPR[frb]); - if(rc) throw "FRSQRTE(): frsqrte.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb]; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FMSUB(): fmsub.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb]; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FMADD(): fmadd.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = -(CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FNMSUB(): fnmsub.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = -(CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb]); CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FNMADD(): fnmadd.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FCMPO(u32 crfd, u32 fra, u32 frb) { @@ -3949,22 +3996,22 @@ private: void FNEG(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = -CPU.FPR[frb]; - if(rc) throw "FNEG(): fneg.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMR(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[frb]; - if(rc) throw "FMR(): fmr.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FNABS(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = -fabs(CPU.FPR[frb]); - if(rc) throw "FNABS(): fnabs.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FABS(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = fabs(CPU.FPR[frb]); - if(rc) throw "FABS(): fabs.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FCTID(u32 frd, u32 frb, bool rc) { @@ -4023,7 +4070,7 @@ private: } (u64&)CPU.FPR[frd] = r; - if(rc) throw "FCTID(): fctid."; + if(rc) CPU.UpdateCR1(); } void FCTIDZ(u32 frd, u32 frb, bool rc) { @@ -4061,7 +4108,7 @@ private: } (u64&)CPU.FPR[frd] = r; - if(rc) throw "FCTIDZ(): fctidz."; + if(rc) CPU.UpdateCR1(); } void FCFID(u32 frd, u32 frb, bool rc) { @@ -4083,7 +4130,7 @@ private: CPU.FPR[frd] = bf; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) throw "FCFID(): fcfid.";//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void UNK(const u32 code, const u32 opcode, const u32 gcode) diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 1451a80c27..8442c33d6d 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -3746,6 +3746,16 @@ void Compiler::STVLX(u32 vs, u32 ra, u32 rb) { addr_i8_ptr, vs_i8_ptr, size_i64, m_ir_builder->getInt32(1), m_ir_builder->getInt1(false)); } +void Compiler::STDBRX(u32 rs, u32 ra, u32 rb) { + auto addr_i64 = GetGpr(rb); + if (ra) { + auto ra_i64 = GetGpr(ra); + addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + } + + WriteMemory(addr_i64, GetGpr(rs), 0, false); +} + void Compiler::STSWX(u32 rs, u32 ra, u32 rb) { CompilationError("STSWX"); } diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index 1d656cc4a1..c4bdeb6b6b 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -598,6 +598,7 @@ namespace ppu_recompiler_llvm { void LFDX(u32 frd, u32 ra, u32 rb) override; void LFDUX(u32 frd, u32 ra, u32 rb) override; void STVLX(u32 vs, u32 ra, u32 rb) override; + void STDBRX(u32 rd, u32 ra, u32 rb) override; void STSWX(u32 rs, u32 ra, u32 rb) override; void STWBRX(u32 rs, u32 ra, u32 rb) override; void STFSX(u32 frs, u32 ra, u32 rb) override; diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 39b9e08aa9..aee76ba295 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -344,6 +344,8 @@ namespace PPU_opcodes DIVD = 0x1e9, DIVW = 0x1eb, LVLX = 0x207, //Load Vector Left Indexed + SUBFCO = 0x208, + ADDCO = 0x20a, LDBRX = 0x214, LSWX = 0x215, LWBRX = 0x216, @@ -351,21 +353,33 @@ namespace PPU_opcodes SRW = 0x218, SRD = 0x21b, LVRX = 0x227, //Load Vector Right Indexed + SUBFO = 0x228, LFSUX = 0x237, LSWI = 0x255, SYNC = 0x256, LFDX = 0x257, + NEGO = 0x268, LFDUX = 0x277, STVLX = 0x287, //Store Vector Left Indexed + SUBFEO = 0x288, + ADDEO = 0x28a, + STDBRX = 0x294, STSWX = 0x295, STWBRX = 0x296, STFSX = 0x297, STVRX = 0x2a7, //Store Vector Right Indexed STFSUX = 0x2b7, + SUBFZEO= 0x2c8, + ADDZEO = 0x2ca, STSWI = 0x2d5, STFDX = 0x2d7, //Store Floating-Point Double Indexed + SUBFMEO= 0x2e8, + MULLDO = 0x2e9, + ADDMEO = 0x2ea, + MULLWO = 0x2eb, STFDUX = 0x2f7, LVLXL = 0x307, //Load Vector Left Indexed Last + ADDO = 0x30a, LHBRX = 0x316, SRAW = 0x318, SRAD = 0x31a, @@ -380,9 +394,13 @@ namespace PPU_opcodes EXTSH = 0x39a, STVRXL = 0x3a7, //Store Vector Right Indexed Last EXTSB = 0x3ba, + DIVDUO = 0x3c9, + DIVWUO = 0x3cb, STFIWX = 0x3d7, EXTSW = 0x3da, ICBI = 0x3d6, //Instruction Cache Block Invalidate + DIVDO = 0x3e9, + DIVWO = 0x3eb, DCBZ = 0x3f6, //Data Cache Block Set to Zero }; @@ -759,6 +777,7 @@ public: virtual void LFDX(u32 frd, u32 ra, u32 rb) = 0; virtual void LFDUX(u32 frd, u32 ra, u32 rb) = 0; virtual void STVLX(u32 vs, u32 ra, u32 rb) = 0; + virtual void STDBRX(u32 rs, u32 ra, u32 rb) = 0; virtual void STSWX(u32 rs, u32 ra, u32 rb) = 0; virtual void STWBRX(u32 rs, u32 ra, u32 rb) = 0; virtual void STFSX(u32 frs, u32 ra, u32 rb) = 0; diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index c0d5eda43c..659b81443e 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -652,7 +652,7 @@ public: UpdateCRn(0, val, 0); } - template void UpdateCR1() + void UpdateCR1() { SetCR_LT(1, FPSCR.FX); SetCR_GT(1, FPSCR.FEX); @@ -670,6 +670,12 @@ public: bool IsCarry(const u64 a, const u64 b) { return (a + b) < a; } bool IsCarry(const u64 a, const u64 b, const u64 c) { return IsCarry(a, b) || IsCarry(a + b, c); } + void SetOV(const bool set) + { + XER.OV = set; + XER.SO |= set; + } + void SetFPSCRException(const FPSCR_EXP mask) { if ((FPSCR.FPSCR & mask) != mask) FPSCR.FX = 1;