diff --git a/Utilities/types.h b/Utilities/types.h index 3b96863146..acfd3bdf1d 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -534,6 +534,26 @@ inline u64 cntlz64(u64 arg, bool nonzero = false) #endif } +inline u32 cnttz32(u32 arg, bool nonzero = false) +{ +#ifdef _MSC_VER + ulong res; + return _BitScanForward(&res, arg) || nonzero ? res : 32; +#else + return arg || nonzero ? __builtin_ctzll(arg) : 32; +#endif +} + +inline u64 cnttz64(u64 arg, bool nonzero = false) +{ +#ifdef _MSC_VER + ulong res; + return _BitScanForward64(&res, arg) || nonzero ? res : 64; +#else + return arg || nonzero ? __builtin_ctzll(arg) : 64; +#endif +} + // Helper function, used by ""_u16, ""_u32, ""_u64 constexpr u8 to_u8(char c) { diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 0cff30ec89..232d1918ac 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -1433,3 +1433,1957 @@ void ppu_module::analyse(u32 lib_toc, u32 entry) LOG_NOTICE(PPU, "Function analysis: %zu functions (%zu enqueued)", funcs.size(), func_queue.size()); } + +void ppu_acontext::UNK(ppu_opcode_t op) +{ + std::fill_n(gpr, 32, spec_gpr{}); + LOG_ERROR(PPU, "Unknown/Illegal opcode: 0x%08x at 0x%x" HERE, op.opcode, cia); +} + +void ppu_acontext::MFVSCR(ppu_opcode_t op) +{ +} + +void ppu_acontext::MTVSCR(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDCUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDSBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDSHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDSWS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDUBM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDUBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDUHM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDUHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDUWM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VADDUWS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAND(ppu_opcode_t op) +{ +} + +void ppu_acontext::VANDC(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAVGSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAVGSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAVGSW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAVGUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAVGUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VAVGUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCFSX(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCFUX(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPBFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPEQFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPEQUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPEQUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPEQUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGEFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTSW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCMPGTUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCTSXS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VCTUXS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VEXPTEFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VLOGEFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMADDFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXSW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMAXUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMHADDSHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMHRADDSHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINSW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMINUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMLADDUHM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMRGHB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMRGHH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMRGHW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMRGLB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMRGLH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMRGLW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMSUMMBM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMSUMSHM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMSUMSHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMSUMUBM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMSUMUHM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMSUMUHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULESB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULESH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULEUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULEUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULOSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULOSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULOUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VMULOUH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VNMSUBFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VNOR(ppu_opcode_t op) +{ +} + +void ppu_acontext::VOR(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPERM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKPX(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKSHSS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKSHUS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKSWSS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKSWUS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKUHUM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKUHUS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKUWUM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VPKUWUS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VREFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRFIM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRFIN(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRFIP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRFIZ(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRLB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRLH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRLW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VRSQRTEFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSEL(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSL(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSLB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSLDOI(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSLH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSLO(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSLW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSPLTB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSPLTH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSPLTISB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSPLTISH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSPLTISW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSPLTW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSR(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRAB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRAH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRAW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRO(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSRW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBCUW(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBFP(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBSBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBSHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBSWS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBUBM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBUBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBUHM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBUHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBUWM(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUBUWS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUMSWS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUM2SWS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUM4SBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUM4SHS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VSUM4UBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::VUPKHPX(ppu_opcode_t op) +{ +} + +void ppu_acontext::VUPKHSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VUPKHSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VUPKLPX(ppu_opcode_t op) +{ +} + +void ppu_acontext::VUPKLSB(ppu_opcode_t op) +{ +} + +void ppu_acontext::VUPKLSH(ppu_opcode_t op) +{ +} + +void ppu_acontext::VXOR(ppu_opcode_t op) +{ +} + +void ppu_acontext::TDI(ppu_opcode_t op) +{ +} + +void ppu_acontext::TWI(ppu_opcode_t op) +{ +} + +void ppu_acontext::MULLI(ppu_opcode_t op) +{ + const s64 amin = gpr[op.ra].imin; + const s64 amax = gpr[op.ra].imax; + + // Undef or mixed range (default) + s64 min = 0; + s64 max = -1; + + // Special cases like powers of 2 and their negations are not handled + if (amin <= amax) + { + min = amin * op.simm16; + max = amax * op.simm16; + + // Check overflow + if (min >> 63 != ::mulh64(amin, op.simm16) || max >> 63 != ::mulh64(amax, op.simm16)) + { + min = 0; + max = -1; + } + else if (min > max) + { + std::swap(min, max); + } + } + + gpr[op.rd] = spec_gpr::range(min, max, gpr[op.ra].tz() + ::cnttz64(op.simm16)); +} + +void ppu_acontext::SUBFIC(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + spec_gpr::fixed(op.simm16) + spec_gpr::fixed(1); +} + +void ppu_acontext::CMPLI(ppu_opcode_t op) +{ +} + +void ppu_acontext::CMPI(ppu_opcode_t op) +{ +} + +void ppu_acontext::ADDIC(ppu_opcode_t op) +{ + gpr[op.rd] = gpr[op.ra] + spec_gpr::fixed(op.simm16); +} + +void ppu_acontext::ADDI(ppu_opcode_t op) +{ + gpr[op.rd] = op.ra ? gpr[op.ra] + spec_gpr::fixed(op.simm16) : spec_gpr::fixed(op.simm16); +} + +void ppu_acontext::ADDIS(ppu_opcode_t op) +{ + gpr[op.rd] = op.ra ? gpr[op.ra] + spec_gpr::fixed((u64)op.simm16 << 16) : spec_gpr::fixed((u64)op.simm16 << 16); +} + +void ppu_acontext::BC(ppu_opcode_t op) +{ +} + +void ppu_acontext::SC(ppu_opcode_t op) +{ +} + +void ppu_acontext::B(ppu_opcode_t op) +{ +} + +void ppu_acontext::MCRF(ppu_opcode_t op) +{ +} + +void ppu_acontext::BCLR(ppu_opcode_t op) +{ +} + +void ppu_acontext::CRNOR(ppu_opcode_t op) +{ +} + +void ppu_acontext::CRANDC(ppu_opcode_t op) +{ +} + +void ppu_acontext::ISYNC(ppu_opcode_t op) +{ +} + +void ppu_acontext::CRXOR(ppu_opcode_t op) +{ +} + +void ppu_acontext::CRNAND(ppu_opcode_t op) +{ +} + +void ppu_acontext::CRAND(ppu_opcode_t op) +{ +} + +void ppu_acontext::CREQV(ppu_opcode_t op) +{ +} + +void ppu_acontext::CRORC(ppu_opcode_t op) +{ +} + +void ppu_acontext::CROR(ppu_opcode_t op) +{ +} + +void ppu_acontext::BCCTR(ppu_opcode_t op) +{ +} + +void ppu_acontext::RLWIMI(ppu_opcode_t op) +{ + const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (op.mb32 <= op.me32) + { + // 32-bit op, including mnemonics: INSLWI, INSRWI (TODO) + min = ::rol32((u32)min, op.sh32) & mask; + max = ::rol32((u32)max, op.sh32) & mask; + } + else + { + // Full 64-bit op with duplication + min = ::rol64((u32)min | min << 32, op.sh32) & mask; + max = ::rol64((u32)max | max << 32, op.sh32) & mask; + } + + if (mask != -1) + { + // Insertion + min |= gpr[op.ra].bmin & ~mask; + max |= gpr[op.ra].bmax & ~mask; + } + + gpr[op.rs] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLWINM(ppu_opcode_t op) +{ + const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (op.mb32 <= op.me32) + { + if (op.sh32 == 0) + { + // CLRLWI, CLRRWI mnemonics + gpr[op.ra] = gpr[op.ra] & spec_gpr::fixed(mask); + return; + } + else if (op.mb32 == 0 && op.me32 == 31) + { + // ROTLWI, ROTRWI mnemonics + } + else if (op.mb32 == 0 && op.sh32 == 31 - op.me32) + { + // SLWI mnemonic + } + else if (op.me32 == 31 && op.sh32 == 32 - op.mb32) + { + // SRWI mnemonic + } + else if (op.mb32 == 0 && op.sh32 < 31 - op.me32) + { + // EXTLWI and other possible mnemonics + } + else if (op.me32 == 31 && 32 - op.sh32 < op.mb32) + { + // EXTRWI and other possible mnemonics + } + + min = ::rol32((u32)min, op.sh32) & mask; + max = ::rol32((u32)max, op.sh32) & mask; + } + else + { + // Full 64-bit op with duplication + min = ::rol64((u32)min | min << 32, op.sh32) & mask; + max = ::rol64((u32)max | max << 32, op.sh32) & mask; + } + + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLWNM(ppu_opcode_t op) +{ + const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (op.mb32 <= op.me32) + { + if (op.mb32 == 0 && op.me32 == 31) + { + // ROTLW mnemonic + } + + // TODO + min = 0; + max = mask; + } + else + { + // Full 64-bit op with duplication + min = 0; + max = mask; + } + + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::ORI(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] | spec_gpr::fixed(op.uimm16); +} + +void ppu_acontext::ORIS(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] | spec_gpr::fixed(op.uimm16 << 16); +} + +void ppu_acontext::XORI(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] ^ spec_gpr::fixed(op.uimm16); +} + +void ppu_acontext::XORIS(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] ^ spec_gpr::fixed(op.uimm16 << 16); +} + +void ppu_acontext::ANDI(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] & spec_gpr::fixed(op.uimm16); +} + +void ppu_acontext::ANDIS(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] & spec_gpr::fixed(op.uimm16 << 16); +} + +void ppu_acontext::RLDICL(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + const u64 mask = ~0ull >> mb; + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (64 - sh < mb) + { + // EXTRDI mnemonic + } + else if (64 - sh == mb) + { + // SRDI mnemonic + } + else if (sh == 0) + { + // CLRLDI mnemonic + gpr[op.ra] = gpr[op.rs] & spec_gpr::fixed(mask); + return; + } + + min = ::rol64(min, sh) & mask; + max = ::rol64(max, sh) & mask; + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLDICR(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 me = op.mbe64; + const u64 mask = ~0ull << (63 - me); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (sh < 63 - me) + { + // EXTLDI mnemonic + } + else if (sh == 63 - me) + { + // SLDI mnemonic + } + else if (sh == 0) + { + // CLRRDI mnemonic + gpr[op.ra] = gpr[op.rs] & spec_gpr::fixed(mask); + return; + } + + min = ::rol64(min, sh) & mask; + max = ::rol64(max, sh) & mask; + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLDIC(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + const u64 mask = ppu_rotate_mask(mb, 63 - sh); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (mb == 0 && sh == 0) + { + gpr[op.ra] = gpr[op.rs]; + return; + } + else if (mb <= 63 - sh) + { + // CLRLSLDI + gpr[op.ra] = (gpr[op.rs] & spec_gpr::fixed(ppu_rotate_mask(0, sh + mb))) << spec_gpr::fixed(sh); + return; + } + + min = ::rol64(min, sh) & mask; + max = ::rol64(max, sh) & mask; + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLDIMI(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + const u64 mask = ppu_rotate_mask(mb, 63 - sh); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + if (mb == 0 && sh == 0) + { + // Copy + } + else if (mb <= 63 - sh) + { + // INSRDI mnemonic + } + + min = ::rol64(min, sh) & mask; + max = ::rol64(max, sh) & mask; + + if (mask != -1) + { + // Insertion + min |= gpr[op.ra].bmin & ~mask; + max |= gpr[op.ra].bmax & ~mask; + } + + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLDCL(ppu_opcode_t op) +{ + const u32 mb = op.mbe64; + const u64 mask = ~0ull >> mb; + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + // TODO + min = 0; + max = mask; + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::RLDCR(ppu_opcode_t op) +{ + const u32 me = op.mbe64; + const u64 mask = ~0ull << (63 - me); + + u64 min = gpr[op.rs].bmin; + u64 max = gpr[op.rs].bmax; + + // TODO + min = 0; + max = mask; + gpr[op.ra] = spec_gpr::approx(min, max); +} + +void ppu_acontext::CMP(ppu_opcode_t op) +{ +} + +void ppu_acontext::TW(ppu_opcode_t op) +{ +} + +void ppu_acontext::LVSL(ppu_opcode_t op) +{ +} + +void ppu_acontext::LVEBX(ppu_opcode_t op) +{ +} + +void ppu_acontext::SUBFC(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + gpr[op.rb] + spec_gpr::fixed(1); +} + +void ppu_acontext::ADDC(ppu_opcode_t op) +{ + gpr[op.rd] = gpr[op.ra] + gpr[op.rb]; +} + +void ppu_acontext::MULHDU(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::MULHWU(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::MFOCRF(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LWARX(ppu_opcode_t op) +{ + gpr[op.rd] = spec_gpr::range(0, UINT32_MAX); +} + +void ppu_acontext::LDX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LWZX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::SLW(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::CNTLZW(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::SLD(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::AND(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] & gpr[op.rb]; +} + +void ppu_acontext::CMPL(ppu_opcode_t op) +{ +} + +void ppu_acontext::LVSR(ppu_opcode_t op) +{ +} + +void ppu_acontext::LVEHX(ppu_opcode_t op) +{ +} + +void ppu_acontext::SUBF(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + gpr[op.rb] + spec_gpr::fixed(1); +} + +void ppu_acontext::LDUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::DCBST(ppu_opcode_t op) +{ +} + +void ppu_acontext::LWZUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::CNTLZD(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::ANDC(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] & ~gpr[op.rb]; +} + +void ppu_acontext::TD(ppu_opcode_t op) +{ +} + +void ppu_acontext::LVEWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::MULHD(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::MULHW(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LDARX(ppu_opcode_t op) +{ + gpr[op.rd] = {}; +} + +void ppu_acontext::DCBF(ppu_opcode_t op) +{ +} + +void ppu_acontext::LBZX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LVX(ppu_opcode_t op) +{ +} + +void ppu_acontext::NEG(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + spec_gpr::fixed(1); +} + +void ppu_acontext::LBZUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::NOR(ppu_opcode_t op) +{ + gpr[op.ra] = ~(gpr[op.rs] | gpr[op.rb]); +} + +void ppu_acontext::STVEBX(ppu_opcode_t op) +{ +} + +void ppu_acontext::SUBFE(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + gpr[op.rb] + spec_gpr::range(0, 1); +} + +void ppu_acontext::ADDE(ppu_opcode_t op) +{ + gpr[op.rd] = gpr[op.ra] + gpr[op.rb] + spec_gpr::range(0, 1); +} + +void ppu_acontext::MTOCRF(ppu_opcode_t op) +{ +} + +void ppu_acontext::STDX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STWCX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STVEHX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STDUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STWUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STVEWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::SUBFZE(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + spec_gpr::range(0, 1); +} + +void ppu_acontext::ADDZE(ppu_opcode_t op) +{ + gpr[op.rd] = gpr[op.ra] + spec_gpr::range(0, 1); +} + +void ppu_acontext::STDCX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STBX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STVX(ppu_opcode_t op) +{ +} + +void ppu_acontext::SUBFME(ppu_opcode_t op) +{ + gpr[op.rd] = ~gpr[op.ra] + spec_gpr::fixed(-1) + spec_gpr::range(0, 1); +} + +void ppu_acontext::MULLD(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::ADDME(ppu_opcode_t op) +{ + gpr[op.rd] = gpr[op.ra] + spec_gpr::fixed(-1) + spec_gpr::range(0, 1); +} + +void ppu_acontext::MULLW(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::DCBTST(ppu_opcode_t op) +{ +} + +void ppu_acontext::STBUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::ADD(ppu_opcode_t op) +{ + gpr[op.rd] = gpr[op.ra] + gpr[op.rd]; +} + +void ppu_acontext::DCBT(ppu_opcode_t op) +{ +} + +void ppu_acontext::LHZX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::EQV(ppu_opcode_t op) +{ + gpr[op.ra] = ~(gpr[op.rs] ^ gpr[op.rb]); +} + +void ppu_acontext::ECIWX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LHZUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::XOR(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] ^ gpr[op.rb]; +} + +void ppu_acontext::MFSPR(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LWAX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::DST(ppu_opcode_t op) +{ +} + +void ppu_acontext::LHAX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LVXL(ppu_opcode_t op) +{ +} + +void ppu_acontext::MFTB(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LWAUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::DSTST(ppu_opcode_t op) +{ +} + +void ppu_acontext::LHAUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::STHX(ppu_opcode_t op) +{ +} + +void ppu_acontext::ORC(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] | ~gpr[op.rb]; +} + +void ppu_acontext::ECOWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STHUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::OR(ppu_opcode_t op) +{ + gpr[op.ra] = gpr[op.rs] | gpr[op.rb]; +} + +void ppu_acontext::DIVDU(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::DIVWU(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::MTSPR(ppu_opcode_t op) +{ +} + +void ppu_acontext::DCBI(ppu_opcode_t op) +{ +} + +void ppu_acontext::NAND(ppu_opcode_t op) +{ + gpr[op.ra] = ~(gpr[op.rs] & gpr[op.rb]); +} + +void ppu_acontext::STVXL(ppu_opcode_t op) +{ +} + +void ppu_acontext::DIVD(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::DIVW(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LVLX(ppu_opcode_t op) +{ +} + +void ppu_acontext::LDBRX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LSWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::LWBRX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LFSX(ppu_opcode_t op) +{ +} + +void ppu_acontext::SRW(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::SRD(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::LVRX(ppu_opcode_t op) +{ +} + +void ppu_acontext::LSWI(ppu_opcode_t op) +{ + std::fill_n(gpr, 32, spec_gpr{}); +} + +void ppu_acontext::LFSUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::SYNC(ppu_opcode_t op) +{ +} + +void ppu_acontext::LFDX(ppu_opcode_t op) +{ +} + +void ppu_acontext::LFDUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STVLX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STDBRX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STSWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STWBRX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STFSX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STVRX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STFSUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STSWI(ppu_opcode_t op) +{ +} + +void ppu_acontext::STFDX(ppu_opcode_t op) +{ +} + +void ppu_acontext::STFDUX(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::LVLXL(ppu_opcode_t op) +{ +} + +void ppu_acontext::LHBRX(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::SRAW(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::SRAD(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::LVRXL(ppu_opcode_t op) +{ +} + +void ppu_acontext::DSS(ppu_opcode_t op) +{ +} + +void ppu_acontext::SRAWI(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::SRADI(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::EIEIO(ppu_opcode_t op) +{ +} + +void ppu_acontext::STVLXL(ppu_opcode_t op) +{ +} + +void ppu_acontext::STHBRX(ppu_opcode_t op) +{ +} + +void ppu_acontext::EXTSH(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::STVRXL(ppu_opcode_t op) +{ +} + +void ppu_acontext::EXTSB(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::STFIWX(ppu_opcode_t op) +{ +} + +void ppu_acontext::EXTSW(ppu_opcode_t op) +{ + gpr[op.ra].set_undef(); +} + +void ppu_acontext::ICBI(ppu_opcode_t op) +{ +} + +void ppu_acontext::DCBZ(ppu_opcode_t op) +{ +} + +void ppu_acontext::LWZ(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LWZU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::LBZ(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LBZU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::STW(ppu_opcode_t op) +{ +} + +void ppu_acontext::STWU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STB(ppu_opcode_t op) +{ +} + +void ppu_acontext::STBU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::LHZ(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LHZU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::LHA(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LHAU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::STH(ppu_opcode_t op) +{ +} + +void ppu_acontext::STHU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::LMW(ppu_opcode_t op) +{ + std::fill_n(gpr, 32, spec_gpr{}); +} + +void ppu_acontext::STMW(ppu_opcode_t op) +{ +} + +void ppu_acontext::LFS(ppu_opcode_t op) +{ +} + +void ppu_acontext::LFSU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::LFD(ppu_opcode_t op) +{ +} + +void ppu_acontext::LFDU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STFS(ppu_opcode_t op) +{ +} + +void ppu_acontext::STFSU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::STFD(ppu_opcode_t op) +{ +} + +void ppu_acontext::STFDU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::LD(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::LDU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.rd].set_undef(); + gpr[op.ra] = addr; +} + +void ppu_acontext::LWA(ppu_opcode_t op) +{ + gpr[op.rd].set_undef(); +} + +void ppu_acontext::STD(ppu_opcode_t op) +{ +} + +void ppu_acontext::STDU(ppu_opcode_t op) +{ + const auto addr = gpr[op.ra] + gpr[op.rb]; + gpr[op.ra] = addr; +} + +void ppu_acontext::FDIVS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FSUBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FADDS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FSQRTS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FRES(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMULS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMADDS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMSUBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FNMSUBS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FNMADDS(ppu_opcode_t op) +{ +} + +void ppu_acontext::MTFSB1(ppu_opcode_t op) +{ +} + +void ppu_acontext::MCRFS(ppu_opcode_t op) +{ +} + +void ppu_acontext::MTFSB0(ppu_opcode_t op) +{ +} + +void ppu_acontext::MTFSFI(ppu_opcode_t op) +{ +} + +void ppu_acontext::MFFS(ppu_opcode_t op) +{ +} + +void ppu_acontext::MTFSF(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCMPU(ppu_opcode_t op) +{ +} + +void ppu_acontext::FRSP(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCTIW(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCTIWZ(ppu_opcode_t op) +{ +} + +void ppu_acontext::FDIV(ppu_opcode_t op) +{ +} + +void ppu_acontext::FSUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::FADD(ppu_opcode_t op) +{ +} + +void ppu_acontext::FSQRT(ppu_opcode_t op) +{ +} + +void ppu_acontext::FSEL(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMUL(ppu_opcode_t op) +{ +} + +void ppu_acontext::FRSQRTE(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMSUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMADD(ppu_opcode_t op) +{ +} + +void ppu_acontext::FNMSUB(ppu_opcode_t op) +{ +} + +void ppu_acontext::FNMADD(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCMPO(ppu_opcode_t op) +{ +} + +void ppu_acontext::FNEG(ppu_opcode_t op) +{ +} + +void ppu_acontext::FMR(ppu_opcode_t op) +{ +} + +void ppu_acontext::FNABS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FABS(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCTID(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCTIDZ(ppu_opcode_t op) +{ +} + +void ppu_acontext::FCFID(ppu_opcode_t op) +{ +} + +#include + +const bool s_tes = []() +{ + return true; + + std::mt19937_64 rnd{123}; + + for (u32 i = 0; i < 10000; i++) + { + ppu_acontext::spec_gpr r1, r2, r3; + r1 = ppu_acontext::spec_gpr::approx(rnd(), rnd()); + r2 = ppu_acontext::spec_gpr::range(rnd(), rnd()); + r3 = r1 | r2; + + for (u32 j = 0; j < 10000; j++) + { + u64 v1 = rnd(), v2 = rnd(); + v1 &= r1.mask(); + v1 |= r1.ones(); + if (!r2.test(v2)) + { + v2 = r2.imin; + } + + if (r1.test(v1) && r2.test(v2)) + { + if (!r3.test(v1 | v2)) + { + auto exp = ppu_acontext::spec_gpr::approx(r1.ones() & r2.ones(), r1.mask() & r2.mask()); + + LOG_ERROR(PPU, "ppu_acontext failure:" + "\n\tr1 = 0x%016x..0x%016x, 0x%016x:0x%016x" + "\n\tr2 = 0x%016x..0x%016x, 0x%016x:0x%016x" + "\n\tr3 = 0x%016x..0x%016x, 0x%016x:0x%016x" + "\n\tex = 0x%016x..0x%016x" + "\n\tv1 = 0x%016x, v2 = 0x%016x, v3 = 0x%016x", + r1.imin, r1.imax, r1.bmin, r1.bmax, r2.imin, r2.imax, r2.bmin, r2.bmax, r3.imin, r3.imax, r3.bmin, r3.bmax, exp.imin, exp.imax, v1, v2, v1 | v2); + break; + } + } + } + } + + ppu_acontext::spec_gpr r1; + r1 = ppu_acontext::spec_gpr::range(0x13311, 0x1fe22); + r1 = r1 ^ ppu_acontext::spec_gpr::approx(0x000, 0xf00); + LOG_SUCCESS(PPU, "0x%x..0x%x", r1.imin, r1.imax); + + return true; +}(); diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index 229f89455e..e2bc5eedd2 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -6,6 +6,7 @@ #include "Utilities/bit_set.h" #include "Utilities/BEType.h" +#include "PPUOpcodes.h" // PPU Function Attributes enum class ppu_attr : u32 @@ -941,3 +942,738 @@ struct ppu_iname return value; } }; + +// PPU Analyser Context +struct ppu_acontext +{ + // General-purpose register range + struct spec_gpr + { + // Integral range: normalized undef = (0;UINT64_MAX), unnormalized undefs are possible (when max = min - 1) + // Bit range: constant 0 = (0;0), constant 1 = (1;1), normalized undef = (0;1), unnormalized undef = (1;0) + + u64 imin = 0; // Integral range begin + u64 imax = -1; // Integral range end + u64 bmin = 0; // Bit range begin + u64 bmax = -1; // Bit range end + + void set_undef() + { + imin = 0; + imax = -1; + bmin = 0; + bmax = -1; + } + + // (Number of possible values - 1), 0 = const + u64 div() const + { + return imax - imin; + } + + // Return zero bits for zeros, ones for ones or undefs + u64 mask() const + { + return bmin | bmax; + } + + // Return one bits for ones, zeros for zeros or undefs + u64 ones() const + { + return bmin & bmax; + } + + // Return one bits for undefs + u64 undefs() const + { + return bmin ^ bmax; + } + + // Return number of trailing zero bits + u64 tz() const + { + return ::cnttz64(mask()); + } + + // Range NOT + spec_gpr operator ~() const + { + spec_gpr r; + r.imin = ~imax; + r.imax = ~imin; + r.bmin = ~bmax; + r.bmax = ~bmin; + return r; + } + + // Range ADD + spec_gpr operator +(const spec_gpr& rhs) const + { + spec_gpr r{}; + + const u64 adiv = div(); + const u64 bdiv = rhs.div(); + + // Check overflow, generate normalized range + if (adiv != -1 && bdiv != -1 && adiv <= adiv + bdiv) + { + r = range(imin + rhs.imin, imax + rhs.imax); + } + + // Carry for bitrange computation + u64 cmin = 0; + u64 cmax = 0; + + const u64 amask = mask(); + const u64 bmask = rhs.mask(); + const u64 aones = ones(); + const u64 bones = rhs.ones(); + + for (u32 i = 0; i < 64; i++) + { + cmin += ((amask >> i) & 1) + ((bmask >> i) & 1); + cmax += ((aones >> i) & 1) + ((bones >> i) & 1); + + // Discover some constant bits + if (cmin == cmax) + { + r.bmin |= (cmin & 1) << i; + r.bmax &= ~((~cmin & 1) << i); + } + + cmin >>= 1; + cmax >>= 1; + } + + return r; + } + + // Range AND + spec_gpr operator &(const spec_gpr& rhs) const + { + // Ignore inverted ranges (TODO) + if (imin > imax || rhs.imin > rhs.imax) + { + return approx(ones() & rhs.ones(), mask() & rhs.mask()); + } + + // Const (TODO: remove when unnecessary) + if (imin == imax && rhs.imin == rhs.imax) + { + return fixed(imin & rhs.imin); + } + + // Swap (TODO: remove when unnecessary) + if (imin == imax || rhs.undefs() > undefs()) + { + return rhs & *this; + } + + // Copy and attempt to partially preserve integral range + spec_gpr r = *this; + + for (u32 i = 63; ~i; i--) + { + const u64 m = 1ull << i; + + if (!(rhs.mask() & m)) + { + if (r.undefs() & m) + { + // undef -> 0 + r.imin &= ~(m - 1); + r.imax |= (m - 1); + r.imin &= ~m; + r.imax &= ~m; + } + else if (r.ones() & m) + { + // 1 -> 0 + if ((r.imin ^ r.imax) > (m - 1)) + { + r.imin &= ~(m - 1); + r.imax |= (m - 1); + } + + r.imin &= ~m; + r.imax &= ~m; + } + } + else if (rhs.undefs() & m) + { + // -> undef + r.imin &= ~(m - 1); + r.imax |= (m - 1); + r.imin &= ~m; + r.imax |= m; + } + } + + r.bmin = ones() & rhs.ones(); + r.bmax = mask() & rhs.mask(); + return r; + } + + // Range OR + spec_gpr operator |(const spec_gpr& rhs) const + { + // Ignore inverted ranges (TODO) + if (imin > imax || rhs.imin > rhs.imax) + { + return approx(ones() | rhs.ones(), mask() | rhs.mask()); + } + + // Const (TODO: remove when unnecessary) + if (imin == imax && rhs.imin == rhs.imax) + { + return fixed(imin | rhs.imin); + } + + // Swap (TODO: remove when unnecessary) + if (imin == imax || rhs.undefs() > undefs()) + { + return rhs | *this; + } + + // Copy and attempt to partially preserve integral range + spec_gpr r = *this; + + for (u32 i = 63; ~i; i--) + { + const u64 m = 1ull << i; + + if (rhs.ones() & m) + { + if (r.undefs() & m) + { + // undef -> 1 + r.imin &= ~(m - 1); + r.imax |= (m - 1); + r.imin |= m; + r.imax |= m; + } + else if (!(r.mask() & m)) + { + // 0 -> 1 + if ((r.imin ^ r.imax) > (m - 1)) + { + r.imin &= ~(m - 1); + r.imax |= (m - 1); + } + + r.imin |= m; + r.imax |= m; + } + } + else if (rhs.undefs() & m) + { + // -> undef + r.imin &= ~(m - 1); + r.imax |= (m - 1); + r.imin &= ~m; + r.imax |= m; + } + } + + r.bmin = ones() | rhs.ones(); + r.bmax = mask() | rhs.mask(); + return r; + } + + // Range XOR + spec_gpr operator ^(const spec_gpr& rhs) + { + return (~*this & rhs) | (*this & ~rhs); + } + + // Check whether the value is in range + bool test(u64 value) const + { + if (imin <= imax) + { + if (value < imin || value > imax) + { + return false; + } + } + else + { + if (value < imin && value > imax) + { + return false; + } + } + + if ((value & mask()) != value) + { + return false; + } + + if ((value | ones()) != value) + { + return false; + } + + return true; + } + + // Constant value + static spec_gpr fixed(u64 value) + { + spec_gpr r; + r.imin = value; + r.imax = value; + r.bmin = value; + r.bmax = value; + return r; + } + + // Range (tz = number of constant trailing zeros) + static spec_gpr range(u64 min, u64 max, u64 tz = 0) + { + const u64 mask = tz < 64 ? ~0ull << tz : 0ull; + + spec_gpr r; + r.bmin = 0; + r.bmax = mask; + + // Normalize min/max for tz (TODO) + if (min < max) + { + // Inverted constant MSB mask + const u64 mix = ~0ull >> ::cntlz64(min ^ max, true); + r.bmin |= min & ~mix; + r.bmax &= max | mix; + + r.imin = (min + ~mask) & mask; + r.imax = max & mask; + verify("Impossible range" HERE), r.imin <= r.imax; + } + else + { + r.imin = min & mask; + r.imax = (max + ~mask) & mask; + verify("Impossible range" HERE), r.imin >= r.imax; + } + + // Fix const values + if (r.imin == r.imax) + { + r.bmin = r.imin; + r.bmax = r.imax; + } + + return r; + } + + // Make from bitrange (normalize, approximate range values) + static spec_gpr approx(u64 bmin, u64 bmax) + { + spec_gpr r; + r.imin = bmin & ~(bmin ^ bmax); + r.imax = bmax | (bmin ^ bmax); + r.bmin = bmin & ~(bmin ^ bmax); + r.bmax = bmax | (bmin ^ bmax); + return r; + } + } gpr[32]{}; + + // Vector registers (draft) + struct spec_vec + { + u8 imin8[16]{}; + u8 imax8[16]{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + u16 imin16[8]{}; + u16 imax16[8]{0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; + u32 imin32[4]{}; + u32 imax32[4]{0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu}; + u64 bmin64[2]{}; + u64 bmax64[2]{0xffffffffffffffffull, 0xffffffffffffffffull}; + }; + + // Info + u32 cia; + + // Analyser step + void UNK(ppu_opcode_t); + + void MFVSCR(ppu_opcode_t); + void MTVSCR(ppu_opcode_t); + void VADDCUW(ppu_opcode_t); + void VADDFP(ppu_opcode_t); + void VADDSBS(ppu_opcode_t); + void VADDSHS(ppu_opcode_t); + void VADDSWS(ppu_opcode_t); + void VADDUBM(ppu_opcode_t); + void VADDUBS(ppu_opcode_t); + void VADDUHM(ppu_opcode_t); + void VADDUHS(ppu_opcode_t); + void VADDUWM(ppu_opcode_t); + void VADDUWS(ppu_opcode_t); + void VAND(ppu_opcode_t); + void VANDC(ppu_opcode_t); + void VAVGSB(ppu_opcode_t); + void VAVGSH(ppu_opcode_t); + void VAVGSW(ppu_opcode_t); + void VAVGUB(ppu_opcode_t); + void VAVGUH(ppu_opcode_t); + void VAVGUW(ppu_opcode_t); + void VCFSX(ppu_opcode_t); + void VCFUX(ppu_opcode_t); + void VCMPBFP(ppu_opcode_t); + void VCMPEQFP(ppu_opcode_t); + void VCMPEQUB(ppu_opcode_t); + void VCMPEQUH(ppu_opcode_t); + void VCMPEQUW(ppu_opcode_t); + void VCMPGEFP(ppu_opcode_t); + void VCMPGTFP(ppu_opcode_t); + void VCMPGTSB(ppu_opcode_t); + void VCMPGTSH(ppu_opcode_t); + void VCMPGTSW(ppu_opcode_t); + void VCMPGTUB(ppu_opcode_t); + void VCMPGTUH(ppu_opcode_t); + void VCMPGTUW(ppu_opcode_t); + void VCTSXS(ppu_opcode_t); + void VCTUXS(ppu_opcode_t); + void VEXPTEFP(ppu_opcode_t); + void VLOGEFP(ppu_opcode_t); + void VMADDFP(ppu_opcode_t); + void VMAXFP(ppu_opcode_t); + void VMAXSB(ppu_opcode_t); + void VMAXSH(ppu_opcode_t); + void VMAXSW(ppu_opcode_t); + void VMAXUB(ppu_opcode_t); + void VMAXUH(ppu_opcode_t); + void VMAXUW(ppu_opcode_t); + void VMHADDSHS(ppu_opcode_t); + void VMHRADDSHS(ppu_opcode_t); + void VMINFP(ppu_opcode_t); + void VMINSB(ppu_opcode_t); + void VMINSH(ppu_opcode_t); + void VMINSW(ppu_opcode_t); + void VMINUB(ppu_opcode_t); + void VMINUH(ppu_opcode_t); + void VMINUW(ppu_opcode_t); + void VMLADDUHM(ppu_opcode_t); + void VMRGHB(ppu_opcode_t); + void VMRGHH(ppu_opcode_t); + void VMRGHW(ppu_opcode_t); + void VMRGLB(ppu_opcode_t); + void VMRGLH(ppu_opcode_t); + void VMRGLW(ppu_opcode_t); + void VMSUMMBM(ppu_opcode_t); + void VMSUMSHM(ppu_opcode_t); + void VMSUMSHS(ppu_opcode_t); + void VMSUMUBM(ppu_opcode_t); + void VMSUMUHM(ppu_opcode_t); + void VMSUMUHS(ppu_opcode_t); + void VMULESB(ppu_opcode_t); + void VMULESH(ppu_opcode_t); + void VMULEUB(ppu_opcode_t); + void VMULEUH(ppu_opcode_t); + void VMULOSB(ppu_opcode_t); + void VMULOSH(ppu_opcode_t); + void VMULOUB(ppu_opcode_t); + void VMULOUH(ppu_opcode_t); + void VNMSUBFP(ppu_opcode_t); + void VNOR(ppu_opcode_t); + void VOR(ppu_opcode_t); + void VPERM(ppu_opcode_t); + void VPKPX(ppu_opcode_t); + void VPKSHSS(ppu_opcode_t); + void VPKSHUS(ppu_opcode_t); + void VPKSWSS(ppu_opcode_t); + void VPKSWUS(ppu_opcode_t); + void VPKUHUM(ppu_opcode_t); + void VPKUHUS(ppu_opcode_t); + void VPKUWUM(ppu_opcode_t); + void VPKUWUS(ppu_opcode_t); + void VREFP(ppu_opcode_t); + void VRFIM(ppu_opcode_t); + void VRFIN(ppu_opcode_t); + void VRFIP(ppu_opcode_t); + void VRFIZ(ppu_opcode_t); + void VRLB(ppu_opcode_t); + void VRLH(ppu_opcode_t); + void VRLW(ppu_opcode_t); + void VRSQRTEFP(ppu_opcode_t); + void VSEL(ppu_opcode_t); + void VSL(ppu_opcode_t); + void VSLB(ppu_opcode_t); + void VSLDOI(ppu_opcode_t); + void VSLH(ppu_opcode_t); + void VSLO(ppu_opcode_t); + void VSLW(ppu_opcode_t); + void VSPLTB(ppu_opcode_t); + void VSPLTH(ppu_opcode_t); + void VSPLTISB(ppu_opcode_t); + void VSPLTISH(ppu_opcode_t); + void VSPLTISW(ppu_opcode_t); + void VSPLTW(ppu_opcode_t); + void VSR(ppu_opcode_t); + void VSRAB(ppu_opcode_t); + void VSRAH(ppu_opcode_t); + void VSRAW(ppu_opcode_t); + void VSRB(ppu_opcode_t); + void VSRH(ppu_opcode_t); + void VSRO(ppu_opcode_t); + void VSRW(ppu_opcode_t); + void VSUBCUW(ppu_opcode_t); + void VSUBFP(ppu_opcode_t); + void VSUBSBS(ppu_opcode_t); + void VSUBSHS(ppu_opcode_t); + void VSUBSWS(ppu_opcode_t); + void VSUBUBM(ppu_opcode_t); + void VSUBUBS(ppu_opcode_t); + void VSUBUHM(ppu_opcode_t); + void VSUBUHS(ppu_opcode_t); + void VSUBUWM(ppu_opcode_t); + void VSUBUWS(ppu_opcode_t); + void VSUMSWS(ppu_opcode_t); + void VSUM2SWS(ppu_opcode_t); + void VSUM4SBS(ppu_opcode_t); + void VSUM4SHS(ppu_opcode_t); + void VSUM4UBS(ppu_opcode_t); + void VUPKHPX(ppu_opcode_t); + void VUPKHSB(ppu_opcode_t); + void VUPKHSH(ppu_opcode_t); + void VUPKLPX(ppu_opcode_t); + void VUPKLSB(ppu_opcode_t); + void VUPKLSH(ppu_opcode_t); + void VXOR(ppu_opcode_t); + void TDI(ppu_opcode_t); + void TWI(ppu_opcode_t); + void MULLI(ppu_opcode_t); + void SUBFIC(ppu_opcode_t); + void CMPLI(ppu_opcode_t); + void CMPI(ppu_opcode_t); + void ADDIC(ppu_opcode_t); + void ADDI(ppu_opcode_t); + void ADDIS(ppu_opcode_t); + void BC(ppu_opcode_t); + void SC(ppu_opcode_t); + void B(ppu_opcode_t); + void MCRF(ppu_opcode_t); + void BCLR(ppu_opcode_t); + void CRNOR(ppu_opcode_t); + void CRANDC(ppu_opcode_t); + void ISYNC(ppu_opcode_t); + void CRXOR(ppu_opcode_t); + void CRNAND(ppu_opcode_t); + void CRAND(ppu_opcode_t); + void CREQV(ppu_opcode_t); + void CRORC(ppu_opcode_t); + void CROR(ppu_opcode_t); + void BCCTR(ppu_opcode_t); + void RLWIMI(ppu_opcode_t); + void RLWINM(ppu_opcode_t); + void RLWNM(ppu_opcode_t); + void ORI(ppu_opcode_t); + void ORIS(ppu_opcode_t); + void XORI(ppu_opcode_t); + void XORIS(ppu_opcode_t); + void ANDI(ppu_opcode_t); + void ANDIS(ppu_opcode_t); + void RLDICL(ppu_opcode_t); + void RLDICR(ppu_opcode_t); + void RLDIC(ppu_opcode_t); + void RLDIMI(ppu_opcode_t); + void RLDCL(ppu_opcode_t); + void RLDCR(ppu_opcode_t); + void CMP(ppu_opcode_t); + void TW(ppu_opcode_t); + void LVSL(ppu_opcode_t); + void LVEBX(ppu_opcode_t); + void SUBFC(ppu_opcode_t); + void ADDC(ppu_opcode_t); + void MULHDU(ppu_opcode_t); + void MULHWU(ppu_opcode_t); + void MFOCRF(ppu_opcode_t); + void LWARX(ppu_opcode_t); + void LDX(ppu_opcode_t); + void LWZX(ppu_opcode_t); + void SLW(ppu_opcode_t); + void CNTLZW(ppu_opcode_t); + void SLD(ppu_opcode_t); + void AND(ppu_opcode_t); + void CMPL(ppu_opcode_t); + void LVSR(ppu_opcode_t); + void LVEHX(ppu_opcode_t); + void SUBF(ppu_opcode_t); + void LDUX(ppu_opcode_t); + void DCBST(ppu_opcode_t); + void LWZUX(ppu_opcode_t); + void CNTLZD(ppu_opcode_t); + void ANDC(ppu_opcode_t); + void TD(ppu_opcode_t); + void LVEWX(ppu_opcode_t); + void MULHD(ppu_opcode_t); + void MULHW(ppu_opcode_t); + void LDARX(ppu_opcode_t); + void DCBF(ppu_opcode_t); + void LBZX(ppu_opcode_t); + void LVX(ppu_opcode_t); + void NEG(ppu_opcode_t); + void LBZUX(ppu_opcode_t); + void NOR(ppu_opcode_t); + void STVEBX(ppu_opcode_t); + void SUBFE(ppu_opcode_t); + void ADDE(ppu_opcode_t); + void MTOCRF(ppu_opcode_t); + void STDX(ppu_opcode_t); + void STWCX(ppu_opcode_t); + void STWX(ppu_opcode_t); + void STVEHX(ppu_opcode_t); + void STDUX(ppu_opcode_t); + void STWUX(ppu_opcode_t); + void STVEWX(ppu_opcode_t); + void SUBFZE(ppu_opcode_t); + void ADDZE(ppu_opcode_t); + void STDCX(ppu_opcode_t); + void STBX(ppu_opcode_t); + void STVX(ppu_opcode_t); + void SUBFME(ppu_opcode_t); + void MULLD(ppu_opcode_t); + void ADDME(ppu_opcode_t); + void MULLW(ppu_opcode_t); + void DCBTST(ppu_opcode_t); + void STBUX(ppu_opcode_t); + void ADD(ppu_opcode_t); + void DCBT(ppu_opcode_t); + void LHZX(ppu_opcode_t); + void EQV(ppu_opcode_t); + void ECIWX(ppu_opcode_t); + void LHZUX(ppu_opcode_t); + void XOR(ppu_opcode_t); + void MFSPR(ppu_opcode_t); + void LWAX(ppu_opcode_t); + void DST(ppu_opcode_t); + void LHAX(ppu_opcode_t); + void LVXL(ppu_opcode_t); + void MFTB(ppu_opcode_t); + void LWAUX(ppu_opcode_t); + void DSTST(ppu_opcode_t); + void LHAUX(ppu_opcode_t); + void STHX(ppu_opcode_t); + void ORC(ppu_opcode_t); + void ECOWX(ppu_opcode_t); + void STHUX(ppu_opcode_t); + void OR(ppu_opcode_t); + void DIVDU(ppu_opcode_t); + void DIVWU(ppu_opcode_t); + void MTSPR(ppu_opcode_t); + void DCBI(ppu_opcode_t); + void NAND(ppu_opcode_t); + void STVXL(ppu_opcode_t); + void DIVD(ppu_opcode_t); + void DIVW(ppu_opcode_t); + void LVLX(ppu_opcode_t); + void LDBRX(ppu_opcode_t); + void LSWX(ppu_opcode_t); + void LWBRX(ppu_opcode_t); + void LFSX(ppu_opcode_t); + void SRW(ppu_opcode_t); + void SRD(ppu_opcode_t); + void LVRX(ppu_opcode_t); + void LSWI(ppu_opcode_t); + void LFSUX(ppu_opcode_t); + void SYNC(ppu_opcode_t); + void LFDX(ppu_opcode_t); + void LFDUX(ppu_opcode_t); + void STVLX(ppu_opcode_t); + void STDBRX(ppu_opcode_t); + void STSWX(ppu_opcode_t); + void STWBRX(ppu_opcode_t); + void STFSX(ppu_opcode_t); + void STVRX(ppu_opcode_t); + void STFSUX(ppu_opcode_t); + void STSWI(ppu_opcode_t); + void STFDX(ppu_opcode_t); + void STFDUX(ppu_opcode_t); + void LVLXL(ppu_opcode_t); + void LHBRX(ppu_opcode_t); + void SRAW(ppu_opcode_t); + void SRAD(ppu_opcode_t); + void LVRXL(ppu_opcode_t); + void DSS(ppu_opcode_t); + void SRAWI(ppu_opcode_t); + void SRADI(ppu_opcode_t); + void EIEIO(ppu_opcode_t); + void STVLXL(ppu_opcode_t); + void STHBRX(ppu_opcode_t); + void EXTSH(ppu_opcode_t); + void STVRXL(ppu_opcode_t); + void EXTSB(ppu_opcode_t); + void STFIWX(ppu_opcode_t); + void EXTSW(ppu_opcode_t); + void ICBI(ppu_opcode_t); + void DCBZ(ppu_opcode_t); + void LWZ(ppu_opcode_t); + void LWZU(ppu_opcode_t); + void LBZ(ppu_opcode_t); + void LBZU(ppu_opcode_t); + void STW(ppu_opcode_t); + void STWU(ppu_opcode_t); + void STB(ppu_opcode_t); + void STBU(ppu_opcode_t); + void LHZ(ppu_opcode_t); + void LHZU(ppu_opcode_t); + void LHA(ppu_opcode_t); + void LHAU(ppu_opcode_t); + void STH(ppu_opcode_t); + void STHU(ppu_opcode_t); + void LMW(ppu_opcode_t); + void STMW(ppu_opcode_t); + void LFS(ppu_opcode_t); + void LFSU(ppu_opcode_t); + void LFD(ppu_opcode_t); + void LFDU(ppu_opcode_t); + void STFS(ppu_opcode_t); + void STFSU(ppu_opcode_t); + void STFD(ppu_opcode_t); + void STFDU(ppu_opcode_t); + void LD(ppu_opcode_t); + void LDU(ppu_opcode_t); + void LWA(ppu_opcode_t); + void STD(ppu_opcode_t); + void STDU(ppu_opcode_t); + void FDIVS(ppu_opcode_t); + void FSUBS(ppu_opcode_t); + void FADDS(ppu_opcode_t); + void FSQRTS(ppu_opcode_t); + void FRES(ppu_opcode_t); + void FMULS(ppu_opcode_t); + void FMADDS(ppu_opcode_t); + void FMSUBS(ppu_opcode_t); + void FNMSUBS(ppu_opcode_t); + void FNMADDS(ppu_opcode_t); + void MTFSB1(ppu_opcode_t); + void MCRFS(ppu_opcode_t); + void MTFSB0(ppu_opcode_t); + void MTFSFI(ppu_opcode_t); + void MFFS(ppu_opcode_t); + void MTFSF(ppu_opcode_t); + void FCMPU(ppu_opcode_t); + void FRSP(ppu_opcode_t); + void FCTIW(ppu_opcode_t); + void FCTIWZ(ppu_opcode_t); + void FDIV(ppu_opcode_t); + void FSUB(ppu_opcode_t); + void FADD(ppu_opcode_t); + void FSQRT(ppu_opcode_t); + void FSEL(ppu_opcode_t); + void FMUL(ppu_opcode_t); + void FRSQRTE(ppu_opcode_t); + void FMSUB(ppu_opcode_t); + void FMADD(ppu_opcode_t); + void FNMSUB(ppu_opcode_t); + void FNMADD(ppu_opcode_t); + void FCMPO(ppu_opcode_t); + void FNEG(ppu_opcode_t); + void FMR(ppu_opcode_t); + void FNABS(ppu_opcode_t); + void FABS(ppu_opcode_t); + void FCTID(ppu_opcode_t); + void FCTIDZ(ppu_opcode_t); + void FCFID(ppu_opcode_t); +};