diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h new file mode 100644 index 0000000000..b7b18ac650 --- /dev/null +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -0,0 +1,397 @@ +#pragma once + +// PPU Instruction Type +struct ppu_itype +{ + enum type + { + UNK = 0, + + MFVSCR, + MTVSCR, + VADDCUW, + VADDFP, + VADDSBS, + VADDSHS, + VADDSWS, + VADDUBM, + VADDUBS, + VADDUHM, + VADDUHS, + VADDUWM, + VADDUWS, + VAND, + VANDC, + VAVGSB, + VAVGSH, + VAVGSW, + VAVGUB, + VAVGUH, + VAVGUW, + VCFSX, + VCFUX, + VCMPBFP, + VCMPEQFP, + VCMPEQUB, + VCMPEQUH, + VCMPEQUW, + VCMPGEFP, + VCMPGTFP, + VCMPGTSB, + VCMPGTSH, + VCMPGTSW, + VCMPGTUB, + VCMPGTUH, + VCMPGTUW, + VCTSXS, + VCTUXS, + VEXPTEFP, + VLOGEFP, + VMADDFP, + VMAXFP, + VMAXSB, + VMAXSH, + VMAXSW, + VMAXUB, + VMAXUH, + VMAXUW, + VMHADDSHS, + VMHRADDSHS, + VMINFP, + VMINSB, + VMINSH, + VMINSW, + VMINUB, + VMINUH, + VMINUW, + VMLADDUHM, + VMRGHB, + VMRGHH, + VMRGHW, + VMRGLB, + VMRGLH, + VMRGLW, + VMSUMMBM, + VMSUMSHM, + VMSUMSHS, + VMSUMUBM, + VMSUMUHM, + VMSUMUHS, + VMULESB, + VMULESH, + VMULEUB, + VMULEUH, + VMULOSB, + VMULOSH, + VMULOUB, + VMULOUH, + VNMSUBFP, + VNOR, + VOR, + VPERM, + VPKPX, + VPKSHSS, + VPKSHUS, + VPKSWSS, + VPKSWUS, + VPKUHUM, + VPKUHUS, + VPKUWUM, + VPKUWUS, + VREFP, + VRFIM, + VRFIN, + VRFIP, + VRFIZ, + VRLB, + VRLH, + VRLW, + VRSQRTEFP, + VSEL, + VSL, + VSLB, + VSLDOI, + VSLH, + VSLO, + VSLW, + VSPLTB, + VSPLTH, + VSPLTISB, + VSPLTISH, + VSPLTISW, + VSPLTW, + VSR, + VSRAB, + VSRAH, + VSRAW, + VSRB, + VSRH, + VSRO, + VSRW, + VSUBCUW, + VSUBFP, + VSUBSBS, + VSUBSHS, + VSUBSWS, + VSUBUBM, + VSUBUBS, + VSUBUHM, + VSUBUHS, + VSUBUWM, + VSUBUWS, + VSUMSWS, + VSUM2SWS, + VSUM4SBS, + VSUM4SHS, + VSUM4UBS, + VUPKHPX, + VUPKHSB, + VUPKHSH, + VUPKLPX, + VUPKLSB, + VUPKLSH, + VXOR, + TDI, + TWI, + MULLI, + SUBFIC, + CMPLI, + CMPI, + ADDIC, + ADDI, + ADDIS, + BC, + HACK, + SC, + B, + MCRF, + BCLR, + CRNOR, + CRANDC, + ISYNC, + CRXOR, + CRNAND, + CRAND, + CREQV, + CRORC, + CROR, + BCCTR, + RLWIMI, + RLWINM, + RLWNM, + ORI, + ORIS, + XORI, + XORIS, + ANDI, + ANDIS, + RLDICL, + RLDICR, + RLDIC, + RLDIMI, + RLDCL, + RLDCR, + CMP, + TW, + LVSL, + LVEBX, + SUBFC, + ADDC, + MULHDU, + MULHWU, + MFOCRF, + LWARX, + LDX, + LWZX, + SLW, + CNTLZW, + SLD, + AND, + CMPL, + LVSR, + LVEHX, + SUBF, + LDUX, + DCBST, + LWZUX, + CNTLZD, + ANDC, + TD, + LVEWX, + MULHD, + MULHW, + LDARX, + DCBF, + LBZX, + LVX, + NEG, + LBZUX, + NOR, + STVEBX, + SUBFE, + ADDE, + MTOCRF, + STDX, + STWCX, + STWX, + STVEHX, + STDUX, + STWUX, + STVEWX, + SUBFZE, + ADDZE, + STDCX, + STBX, + STVX, + SUBFME, + MULLD, + ADDME, + MULLW, + DCBTST, + STBUX, + ADD, + DCBT, + LHZX, + EQV, + ECIWX, + LHZUX, + XOR, + MFSPR, + LWAX, + DST, + LHAX, + LVXL, + MFTB, + LWAUX, + DSTST, + LHAUX, + STHX, + ORC, + ECOWX, + STHUX, + OR, + DIVDU, + DIVWU, + MTSPR, + DCBI, + NAND, + STVXL, + DIVD, + DIVW, + LVLX, + LDBRX, + LSWX, + LWBRX, + LFSX, + SRW, + SRD, + LVRX, + LSWI, + LFSUX, + SYNC, + LFDX, + LFDUX, + STVLX, + STDBRX, + STSWX, + STWBRX, + STFSX, + STVRX, + STFSUX, + STSWI, + STFDX, + STFDUX, + LVLXL, + LHBRX, + SRAW, + SRAD, + LVRXL, + DSS, + SRAWI, + SRADI, + EIEIO, + STVLXL, + STHBRX, + EXTSH, + STVRXL, + EXTSB, + STFIWX, + EXTSW, + ICBI, + DCBZ, + LWZ, + LWZU, + LBZ, + LBZU, + STW, + STWU, + STB, + STBU, + LHZ, + LHZU, + LHA, + LHAU, + STH, + STHU, + LMW, + STMW, + LFS, + LFSU, + LFD, + LFDU, + STFS, + STFSU, + STFD, + STFDU, + LD, + LDU, + LWA, + STD, + STDU, + FDIVS, + FSUBS, + FADDS, + FSQRTS, + FRES, + FMULS, + FMADDS, + FMSUBS, + FNMSUBS, + FNMADDS, + MTFSB1, + MCRFS, + MTFSB0, + MTFSFI, + MFFS, + MTFSF, + FCMPU, + FRSP, + FCTIW, + FCTIWZ, + FDIV, + FSUB, + FADD, + FSQRT, + FSEL, + FMUL, + FRSQRTE, + FMSUB, + FMADD, + FNMSUB, + FNMADD, + FCMPO, + FNEG, + FMR, + FNABS, + FABS, + FCTID, + FCTIDZ, + FCFID, + }; + + // Enable address-of operator for ppu_decoder<> + friend constexpr type operator &(type value) + { + return value; + } +}; diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 8bb313482a..81942d22e2 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -8,11 +8,14 @@ #include "Emu/Cell/PPUOpcodes.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/PPUAnalyser.h" #include "Emu/Cell/lv2/sys_prx.h" #include +const ppu_decoder s_ppu_itype; + LOG_CHANNEL(cellAdec); LOG_CHANNEL(cellAtrac); LOG_CHANNEL(cellAtracMulti); diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 35dec7108a..ecef1e01c6 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -209,7 +209,7 @@ void spu_recompiler::compile(spu_function_t& f) compiler.endFunc(); // Compile and store function address - f.compiled = asmjit_cast(compiler.make()); + f.compiled = asmjit_cast(compiler.make()); // Add ASMJIT logs log += logger.getString(); diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index 6a616519c2..3a47e28863 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -1,24 +1,20 @@ #include "stdafx.h" - -#include "Crypto/sha1.h" -#include "SPURecompiler.h" #include "SPUAnalyser.h" +#include "SPURecompiler.h" +#include "SPUOpcodes.h" -const spu_decoder s_spu_itype; +const spu_decoder s_spu_itype; std::shared_ptr SPUDatabase::find(const be_t* data, u64 key, u32 max_size) { - for (auto found = m_db.find(key); found != m_db.end() && found->first == key; found++) + for (auto found = m_db.equal_range(key); found.first != found.second; found.first++) { - if (found->second->size > max_size) - { - continue; - } + const auto& func = found.first->second; // Compare binary data explicitly (TODO: optimize) - if (std::equal(found->second->data.begin(), found->second->data.end(), data)) + if (LIKELY(func->size <= max_size) && std::memcmp(func->data.data(), data, func->size) == 0) { - return found->second; + return func; } } @@ -85,8 +81,6 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en const auto type = s_spu_itype.decode(op.opcode); - using namespace spu_itype; - // Find existing function if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos)) { @@ -97,8 +91,8 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Additional analysis at the beginning of the block if (start != entry && start == pos) { - // Possible jump table - std::vector jt_abs, jt_rel; + std::vector jt_abs; + std::vector jt_rel; for (; pos < limit; pos += 4) { @@ -106,7 +100,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en if (target % 4) { - // Misaligned address: abort analysis + // Address cannot be misaligned: abort jt scan break; } @@ -172,15 +166,16 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en break; } - if (type == &type::BI || type == &type::IRET) // Branch Indirect + if (type == BI || type == IRET) // Branch Indirect { - if (type == &type::IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); + if (type == IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); - blocks.emplace(start); start = pos + 4; + blocks.emplace(start); + start = pos + 4; } - else if (type == &type::BR || type == &type::BRA) // Branch Relative/Absolute + else if (type == BR || type == BRA) // Branch Relative/Absolute { - const u32 target = spu_branch_target(type == &type::BR ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == BR ? pos : 0, op.i16); // Add adjacent function because it always could be adjacent.emplace(target); @@ -190,11 +185,12 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(target); } - blocks.emplace(start); start = pos + 4; + blocks.emplace(start); + start = pos + 4; } - else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link + else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); if (target == pos + 4) { @@ -215,11 +211,11 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Function call without $LR", pos); } } - else if (type == &type::BISL || type == &type::BISLED) // Branch Indirect and Set Link + else if (type == BISL || type == BISLED) // Branch Indirect and Set Link { if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Indirect function call without $LR", pos); } - else if (type == &type::BRNZ || type == &type::BRZ || type == &type::BRHNZ || type == &type::BRHZ) // Branch Relative if (Not) Zero (Half)word + else if (type == BRNZ || type == BRZ || type == BRHNZ || type == BRHZ) // Branch Relative if (Not) Zero (Half)word { const u32 target = spu_branch_target(pos, op.i16); @@ -231,24 +227,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(target); } } - else if (type == &type::BINZ || type == &type::BIZ || type == &type::BIHNZ || type == &type::BIHZ) // Branch Indirect if (Not) Zero (Half)word - { - } - else if (type == &type::HBR || type == &type::HBRA || type == &type::HBRR) // Hint for Branch - { - } - else if (type == &type::STQA || type == &type::STQD || type == &type::STQR || type == &type::STQX || type == &type::FSCRWR || type == &type::MTSPR || type == &type::WRCH) // Store - { - } - else if (type == &type::HEQ || type == &type::HEQI || type == &type::HGT || type == &type::HGTI || type == &type::HLGT || type == &type::HLGTI) // Halt - { - } - else if (type == &type::STOP || type == &type::STOPD || type == &type::NOP || type == &type::LNOP || type == &type::SYNC || type == &type::DSYNC) // Miscellaneous - { - } else // Other instructions (writing rt reg) { - const u32 rt = type == &type::SELB || type == &type::SHUFB || type == &type::MPYA || type == &type::FNMS || type == &type::FMA || type == &type::FMS ? +op.rc : +op.rt; + const u32 rt = type & spu_itype::_quadrop ? +op.rt4 : +op.rt; // Analyse link register access if (rt == 0) @@ -258,7 +239,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Analyse stack pointer access if (rt == 1) { - if (type == &type::ILA && pos < ila_sp_pos) + if (type == ILA && pos < ila_sp_pos) { // set minimal ila $SP,* instruction position ila_sp_pos = pos; @@ -274,15 +255,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en const auto type = s_spu_itype.decode(op.opcode); - using namespace spu_itype; - - if (!type) // Invalid instruction + if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link { - break; - } - else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link - { - const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); if (target != pos + 4 && target > entry && limit > target) { @@ -290,6 +265,10 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en limit = target; } } + else if (!type) // Invalid instruction + { + break; + } } if (limit <= entry) diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index 1588d31c8a..25f23c593a 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -1,223 +1,251 @@ #pragma once -#include "Emu/Cell/SPUOpcodes.h" #include "Utilities/SharedMutex.h" #include -class SPUThread; - -// Type of the runtime functions generated by SPU recompiler -using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t* _ls); - -// SPU Instruction Classifier -namespace spu_itype +// SPU Instruction Type +struct spu_itype { - struct type + enum { - u32 UNK; - u32 STOP; - u32 LNOP; - u32 SYNC; - u32 DSYNC; - u32 MFSPR; - u32 RDCH; - u32 RCHCNT; - u32 SF; - u32 OR; - u32 BG; - u32 SFH; - u32 NOR; - u32 ABSDB; - u32 ROT; - u32 ROTM; - u32 ROTMA; - u32 SHL; - u32 ROTH; - u32 ROTHM; - u32 ROTMAH; - u32 SHLH; - u32 ROTI; - u32 ROTMI; - u32 ROTMAI; - u32 SHLI; - u32 ROTHI; - u32 ROTHMI; - u32 ROTMAHI; - u32 SHLHI; - u32 A; - u32 AND; - u32 CG; - u32 AH; - u32 NAND; - u32 AVGB; - u32 MTSPR; - u32 WRCH; - u32 BIZ; - u32 BINZ; - u32 BIHZ; - u32 BIHNZ; - u32 STOPD; - u32 STQX; - u32 BI; - u32 BISL; - u32 IRET; - u32 BISLED; - u32 HBR; - u32 GB; - u32 GBH; - u32 GBB; - u32 FSM; - u32 FSMH; - u32 FSMB; - u32 FREST; - u32 FRSQEST; - u32 LQX; - u32 ROTQBYBI; - u32 ROTQMBYBI; - u32 SHLQBYBI; - u32 CBX; - u32 CHX; - u32 CWX; - u32 CDX; - u32 ROTQBI; - u32 ROTQMBI; - u32 SHLQBI; - u32 ROTQBY; - u32 ROTQMBY; - u32 SHLQBY; - u32 ORX; - u32 CBD; - u32 CHD; - u32 CWD; - u32 CDD; - u32 ROTQBII; - u32 ROTQMBII; - u32 SHLQBII; - u32 ROTQBYI; - u32 ROTQMBYI; - u32 SHLQBYI; - u32 NOP; - u32 CGT; - u32 XOR; - u32 CGTH; - u32 EQV; - u32 CGTB; - u32 SUMB; - u32 HGT; - u32 CLZ; - u32 XSWD; - u32 XSHW; - u32 CNTB; - u32 XSBH; - u32 CLGT; - u32 ANDC; - u32 FCGT; - u32 DFCGT; - u32 FA; - u32 FS; - u32 FM; - u32 CLGTH; - u32 ORC; - u32 FCMGT; - u32 DFCMGT; - u32 DFA; - u32 DFS; - u32 DFM; - u32 CLGTB; - u32 HLGT; - u32 DFMA; - u32 DFMS; - u32 DFNMS; - u32 DFNMA; - u32 CEQ; - u32 MPYHHU; - u32 ADDX; - u32 SFX; - u32 CGX; - u32 BGX; - u32 MPYHHA; - u32 MPYHHAU; - u32 FSCRRD; - u32 FESD; - u32 FRDS; - u32 FSCRWR; - u32 DFTSV; - u32 FCEQ; - u32 DFCEQ; - u32 MPY; - u32 MPYH; - u32 MPYHH; - u32 MPYS; - u32 CEQH; - u32 FCMEQ; - u32 DFCMEQ; - u32 MPYU; - u32 CEQB; - u32 FI; - u32 HEQ; - u32 CFLTS; - u32 CFLTU; - u32 CSFLT; - u32 CUFLT; - u32 BRZ; - u32 STQA; - u32 BRNZ; - u32 BRHZ; - u32 BRHNZ; - u32 STQR; - u32 BRA; - u32 LQA; - u32 BRASL; - u32 BR; - u32 FSMBI; - u32 BRSL; - u32 LQR; - u32 IL; - u32 ILHU; - u32 ILH; - u32 IOHL; - u32 ORI; - u32 ORHI; - u32 ORBI; - u32 SFI; - u32 SFHI; - u32 ANDI; - u32 ANDHI; - u32 ANDBI; - u32 AI; - u32 AHI; - u32 STQD; - u32 LQD; - u32 XORI; - u32 XORHI; - u32 XORBI; - u32 CGTI; - u32 CGTHI; - u32 CGTBI; - u32 HGTI; - u32 CLGTI; - u32 CLGTHI; - u32 CLGTBI; - u32 HLGTI; - u32 MPYI; - u32 MPYUI; - u32 CEQI; - u32 CEQHI; - u32 CEQBI; - u32 HEQI; - u32 HBRA; - u32 HBRR; - u32 ILA; - u32 SELB; - u32 SHUFB; - u32 MPYA; - u32 FNMS; - u32 FMA; - u32 FMS; + memory = 1 << 8, // Memory Load/Store Instructions + constant = 1 << 9, // Constant Formation Instructions + integer = 1 << 10, // Integer and Logical Instructions + shiftrot = 1 << 11, // Shift and Rotate Instructions + compare = 1 << 12, // Compare Instructions + branch = 1 << 13, // Branch Instructions + floating = 1 << 14, // Floating-Point Instructions + + _quadrop = 1 << 15, // 4-op Instructions }; + + enum type + { + UNK = 0, + + HEQ, + HEQI, + HGT, + HGTI, + HLGT, + HLGTI, + + HBR, + HBRA, + HBRR, + + STOP, + STOPD, + LNOP, + NOP, + SYNC, + DSYNC, + MFSPR, + MTSPR, + RDCH, + RCHCNT, + WRCH, + + LQD = memory, + LQX, + LQA, + LQR, + STQD, + STQX, + STQA, + STQR, + + CBD = constant, + CBX, + CHD, + CHX, + CWD, + CWX, + CDD, + CDX, + ILH, + ILHU, + IL, + ILA, + IOHL, + FSMBI, + + AH = integer, + AHI, + A, + AI, + SFH, + SFHI, + SF, + SFI, + ADDX, + CG, + CGX, + SFX, + BG, + BGX, + MPY, + MPYU, + MPYI, + MPYUI, + MPYH, + MPYS, + MPYHH, + MPYHHA, + MPYHHU, + MPYHHAU, + CLZ, + CNTB, + FSMB, + FSMH, + FSM, + GBB, + GBH, + GB, + AVGB, + ABSDB, + SUMB, + XSBH, + XSHW, + XSWD, + AND, + ANDC, + ANDBI, + ANDHI, + ANDI, + OR, + ORC, + ORBI, + ORHI, + ORI, + ORX, + XOR, + XORBI, + XORHI, + XORI, + NAND, + NOR, + EQV, + + MPYA = integer | _quadrop, + SELB, + SHUFB, + + SHLH = shiftrot, + SHLHI, + SHL, + SHLI, + SHLQBI, + SHLQBII, + SHLQBY, + SHLQBYI, + SHLQBYBI, + ROTH, + ROTHI, + ROT, + ROTI, + ROTQBY, + ROTQBYI, + ROTQBYBI, + ROTQBI, + ROTQBII, + ROTHM, + ROTHMI, + ROTM, + ROTMI, + ROTQMBY, + ROTQMBYI, + ROTQMBYBI, + ROTQMBI, + ROTQMBII, + ROTMAH, + ROTMAHI, + ROTMA, + ROTMAI, + + CEQB = compare, + CEQBI, + CEQH, + CEQHI, + CEQ, + CEQI, + CGTB, + CGTBI, + CGTH, + CGTHI, + CGT, + CGTI, + CLGTB, + CLGTBI, + CLGTH, + CLGTHI, + CLGT, + CLGTI, + + BR = branch, + BRA, + BRSL, + BRASL, + BI, + IRET, + BISLED, + BISL, + BRNZ, + BRZ, + BRHNZ, + BRHZ, + BIZ, + BINZ, + BIHZ, + BIHNZ, + + FA = floating, + DFA, + FS, + DFS, + FM, + DFM, + DFMA, + DFNMS, + DFMS, + DFNMA, + FREST, + FRSQEST, + FI, + CSFLT, + CFLTS, + CUFLT, + CFLTU, + FRDS, + FESD, + FCEQ, + FCMEQ, + FCGT, + FCMGT, + FSCRWR, + FSCRRD, + + DFCEQ, + DFCMEQ, + DFCGT, + DFCMGT, + DFTSV, + + FMA = floating | _quadrop, + FNMS, + FMS, + }; + + // Enable address-of operator for spu_decoder<> + friend constexpr type operator &(type value) + { + return value; + } }; +class SPUThread; + // SPU basic function information structure struct spu_function_t { @@ -243,7 +271,7 @@ struct spu_function_t bool does_reset_stack; // Pointer to the compiled function - spu_jit_func_t compiled = nullptr; + u32(*compiled)(SPUThread* _spu, be_t* _ls) = nullptr; spu_function_t(u32 addr, u32 size) : addr(addr) @@ -253,7 +281,7 @@ struct spu_function_t }; // SPU Function Database (must be global or PS3 process-local) -class SPUDatabase final +class SPUDatabase final : spu_itype { shared_mutex m_mutex; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 5486f84215..9976034e61 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -424,6 +424,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 6b845772c8..8dbc1cf8dd 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1396,6 +1396,9 @@ Emu\Cell + + Emu\Cell + Header Files