diff options
| author | Matthew Parlane <parlane@gmail.com> | 2013-08-23 00:51:12 +1200 |
|---|---|---|
| committer | Matthew Parlane <parlane@gmail.com> | 2013-08-23 00:51:12 +1200 |
| commit | b6e054a2beef3236822e27d95dfe38a4ccee2eb1 (patch) | |
| tree | 6f744593b14def9c2fbc7be9e509df5507835cc4 /Source/Core/Common | |
| parent | f274b3b074fb8bb0477b0e9f4e88db0e08bf4f2c (diff) | |
| parent | 41c25d0c90a2461c3e34bf9659dcf1da5e1e8580 (diff) | |
Merge branch 'master' into wii-network
Conflicts:
Source/Core/Core/Core.vcxproj
Source/Core/Core/Core.vcxproj.filters
Source/Core/Core/Src/CoreParameter.cpp
Source/Core/DolphinWX/Dolphin.vcxproj
Source/Core/DolphinWX/Dolphin.vcxproj.filters
Diffstat (limited to 'Source/Core/Common')
| -rw-r--r-- | Source/Core/Common/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | Source/Core/Common/Common.vcxproj | 4 | ||||
| -rw-r--r-- | Source/Core/Common/Common.vcxproj.filters | 4 | ||||
| -rw-r--r-- | Source/Core/Common/Src/ArmCPUDetect.cpp | 95 | ||||
| -rw-r--r-- | Source/Core/Common/Src/ArmEmitter.cpp | 241 | ||||
| -rw-r--r-- | Source/Core/Common/Src/ArmEmitter.h | 36 | ||||
| -rw-r--r-- | Source/Core/Common/Src/ExtendedTrace.cpp | 3 | ||||
| -rw-r--r-- | Source/Core/Common/Src/IniFile.cpp | 54 | ||||
| -rw-r--r-- | Source/Core/Common/Src/IniFile.h | 3 | ||||
| -rw-r--r-- | Source/Core/Common/Src/MemArena.cpp | 50 | ||||
| -rw-r--r-- | Source/Core/Common/Src/StringUtil.cpp | 37 | ||||
| -rw-r--r-- | Source/Core/Common/Src/VideoBackendBase.cpp | 80 | ||||
| -rw-r--r-- | Source/Core/Common/Src/VideoBackendBase.h | 185 | ||||
| -rw-r--r-- | Source/Core/Common/Src/x64CPUDetect.cpp | 19 | ||||
| -rw-r--r-- | Source/Core/Common/make_scmrev.h.js | 4 |
15 files changed, 374 insertions, 442 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 4891f3c090..6e230c7fa7 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -21,7 +21,6 @@ set(SRCS Src/BreakPoints.cpp Src/Thread.cpp Src/Timer.cpp Src/Version.cpp - Src/VideoBackendBase.cpp Src/x64ABI.cpp Src/x64Analyzer.cpp Src/x64Emitter.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 9c21b2a992..4066febcca 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -212,7 +212,6 @@ <ClCompile Include="Src\Thread.cpp" /> <ClCompile Include="Src\Timer.cpp" /> <ClCompile Include="Src\Version.cpp" /> - <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\x64ABI.cpp" /> <ClCompile Include="Src\x64Analyzer.cpp" /> <ClCompile Include="Src\x64CPUDetect.cpp" /> @@ -266,7 +265,6 @@ <ClInclude Include="Src\Thread.h" /> <ClInclude Include="Src\Thunk.h" /> <ClInclude Include="Src\Timer.h" /> - <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\x64ABI.h" /> <ClInclude Include="Src\x64Analyzer.h" /> <ClInclude Include="Src\x64Emitter.h" /> @@ -277,4 +275,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index f16b437f54..a912cc3d8a 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -23,7 +23,6 @@ <ClCompile Include="Src\Thread.cpp" /> <ClCompile Include="Src\Timer.cpp" /> <ClCompile Include="Src\Version.cpp" /> - <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\x64Analyzer.cpp" /> <ClCompile Include="Src\x64Emitter.cpp" /> <ClCompile Include="Src\LogManager.cpp"> @@ -87,7 +86,6 @@ <ClInclude Include="Src\Thread.h" /> <ClInclude Include="Src\Thunk.h" /> <ClInclude Include="Src\Timer.h" /> - <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\x64Analyzer.h" /> <ClInclude Include="Src\x64Emitter.h" /> <ClInclude Include="Src\Log.h"> @@ -124,4 +122,4 @@ <UniqueIdentifier>{f078f36e-a0ff-4cd0-95f8-476100d68e68}</UniqueIdentifier> </Filter> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/Common/Src/ArmCPUDetect.cpp b/Source/Core/Common/Src/ArmCPUDetect.cpp index ca277ade02..ef49d6efb1 100644 --- a/Source/Core/Common/Src/ArmCPUDetect.cpp +++ b/Source/Core/Common/Src/ArmCPUDetect.cpp @@ -17,9 +17,10 @@ #include "Common.h" #include "CPUDetect.h" -#include "StringUtil.h" #include "FileUtil.h" +// Only Linux platforms have /proc/cpuinfo +#if !defined(BLACKBERRY) && !defined(IOS) && !defined(__SYMBIAN32__) const char procfile[] = "/proc/cpuinfo"; char *GetCPUString() @@ -33,7 +34,7 @@ char *GetCPUString() auto const fp = file.GetHandle(); if (!fp) return 0; - + while (fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, marker, sizeof(marker) - 1)) @@ -42,6 +43,7 @@ char *GetCPUString() cpu_string = strndup(cpu_string, strlen(cpu_string) - 1); // Strip the newline break; } + return cpu_string; } @@ -66,6 +68,9 @@ unsigned char GetCPUImplementer() sscanf(implementer_string, "0x%02hhx", &implementer); break; } + + free(implementer_string); + return implementer; } @@ -90,15 +95,17 @@ unsigned short GetCPUPart() sscanf(part_string, "0x%03hx", &part); break; } - return part; + free(part_string); + + return part; } bool CheckCPUFeature(const char *feature) { const char marker[] = "Features\t: "; char buf[1024]; - + File::IOFile file(procfile, "r"); auto const fp = file.GetHandle(); if (!fp) @@ -117,10 +124,18 @@ bool CheckCPUFeature(const char *feature) token = strtok(NULL, " "); } } + return false; } +#endif + int GetCoreCount() { +#ifdef __SYMBIAN32__ + return 1; +#elif defined(BLACKBERRY) || defined(IOS) + return 2; +#else const char marker[] = "processor\t: "; int cores = 0; char buf[1024]; @@ -129,14 +144,16 @@ int GetCoreCount() auto const fp = file.GetHandle(); if (!fp) return 0; - + while (fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, marker, sizeof(marker) - 1)) continue; ++cores; } + return cores; +#endif } CPUInfo cpu_info; @@ -153,12 +170,58 @@ void CPUInfo::Detect() HTT = false; OS64bit = false; CPU64bit = false; - Mode64bit = false; + Mode64bit = false; vendor = VENDOR_ARM; - + // Get the information about the CPU - strncpy(cpu_string, GetCPUString(), sizeof(cpu_string)); num_cores = GetCoreCount(); +#if defined(__SYMBIAN32__) || defined(BLACKBERRY) || defined(IOS) + bool isVFP3 = false; + bool isVFP4 = false; +#ifdef IOS + isVFP3 = true; + // Check for swift arch (VFP4`) + #ifdef __ARM_ARCH_7S__ + isVFP4 = true; + #endif // #ifdef __ARM_ARCH_7S__ +#elif defined(BLACKBERRY) + isVFP3 = true; + const char cpuInfoPath[] = "/pps/services/hw_info/inventory"; + const char marker[] = "Processor_Name::"; + const char qcCPU[] = "MSM"; + char buf[1024]; + FILE* fp; + if (fp = fopen(cpuInfoPath, "r")) + { + while (fgets(buf, sizeof(buf), fp)) + { + if (strncmp(buf, marker, sizeof(marker) - 1)) + continue; + if (strncmp(buf + sizeof(marker) - 1, qcCPU, sizeof(qcCPU) - 1) == 0) + isVFP4 = true; + break; + } + fclose(fp); + } +#endif + // Hardcode this for now + bSwp = true; + bHalf = true; + bThumb = false; + bFastMult = true; + bVFP = true; + bEDSP = true; + bThumbEE = isVFP3; + bNEON = isVFP3; + bVFPv3 = isVFP3; + bTLS = true; + bVFPv4 = isVFP4; + bIDIVa = isVFP4; + bIDIVt = isVFP4; + bFP = false; + bASIMD = false; +#else + strncpy(cpu_string, GetCPUString(), sizeof(cpu_string)); bSwp = CheckCPUFeature("swp"); bHalf = CheckCPUFeature("half"); bThumb = CheckCPUFeature("thumb"); @@ -172,16 +235,15 @@ void CPUInfo::Detect() bVFPv4 = CheckCPUFeature("vfpv4"); bIDIVa = CheckCPUFeature("idiva"); bIDIVt = CheckCPUFeature("idivt"); - // Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait. if (GetCPUImplementer() == 0x51 && GetCPUPart() == 0x6F) // Krait(300) is 0x6F, Scorpion is 0x4D - bIDIVa = bIDIVt = true; - - // These two are ARMv8 specific. + bIDIVa = bIDIVt = true; + // These two require ARMv8 or higher bFP = CheckCPUFeature("fp"); bASIMD = CheckCPUFeature("asimd"); - - +#endif +// On android, we build a separate library for ARMv7 so this is fine. +// TODO: Check for ARMv7 on other platforms. #if defined(__ARM_ARCH_7A__) bArmV7 = true; #else @@ -193,11 +255,14 @@ void CPUInfo::Detect() std::string CPUInfo::Summarize() { std::string sum; +#if defined(BLACKBERRY) || defined(IOS) || defined(__SYMBIAN32__) + sum = StringFromFormat("%i cores", num_cores); +#else if (num_cores == 1) sum = StringFromFormat("%s, %i core", cpu_string, num_cores); else sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); - +#endif if (bSwp) sum += ", SWP"; if (bHalf) sum += ", Half"; if (bThumb) sum += ", Thumb"; diff --git a/Source/Core/Common/Src/ArmEmitter.cpp b/Source/Core/Common/Src/ArmEmitter.cpp index 1b20a1784e..2788760c6d 100644 --- a/Source/Core/Common/Src/ArmEmitter.cpp +++ b/Source/Core/Common/Src/ArmEmitter.cpp @@ -86,7 +86,7 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated) Operand2 AssumeMakeOperand2(u32 imm) { Operand2 op2; bool result = TryMakeOperand2(imm, op2); - _assert_msg_(DYNA_REC, result, "Could not make assumed Operand2."); + _dbg_assert_msg_(DYNA_REC, result, "Could not make assumed Operand2."); return op2; } @@ -117,14 +117,33 @@ bool ARMXEmitter::TrySetValue_TwoOp(ARMReg reg, u32 val) return true; } -void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg) +void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate) { union {float f; u32 u;} conv; - conv.f = val; + conv.f = negate ? -val : val; + // Try moving directly first if mantisse is empty + if (cpu_info.bVFPv3 && ((conv.u & 0x7FFFF) == 0)) + { + // VFP Encoding for Imms: <7> Not(<6>) Repeat(<6>,5) <5:0> Zeros(19) + bool bit6 = (conv.u & 0x40000000) == 0x40000000; + bool canEncode = true; + for (u32 mask = 0x20000000; mask >= 0x2000000; mask >>= 1) + { + if (((conv.u & mask) == mask) == bit6) + canEncode = false; + } + if (canEncode) + { + u32 imm8 = (conv.u & 0x80000000) >> 24; // sign bit + imm8 |= (!bit6 << 6); + imm8 |= (conv.u & 0x1F80000) >> 19; + VMOV(dest, IMM(imm8)); + return; + } + } MOVI2R(tempReg, conv.u); VMOV(dest, tempReg); - // TODO: VMOV an IMM directly if possible - // Otherwise, use a literal pool and VLDR directly (+- 1020) + // Otherwise, possible to use a literal pool and VLDR directly (+- 1020) } void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) @@ -246,8 +265,12 @@ void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize) } void ARMXEmitter::QuickCallFunction(ARMReg reg, void *func) { - MOVI2R(reg, (u32)(func)); - BL(reg); + if (BLInRange(func)) { + BL(func); + } else { + MOVI2R(reg, (u32)(func)); + BL(reg); + } } void ARMXEmitter::SetCodePtr(u8 *ptr) @@ -369,7 +392,7 @@ FixupBranch ARMXEmitter::B_CC(CCFlags Cond) void ARMXEmitter::B_CC(CCFlags Cond, const void *fnptr) { s32 distance = (s32)fnptr - (s32(code) + 8); - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "B_CC out of range (%p calls %p)", code, fnptr); @@ -388,7 +411,7 @@ FixupBranch ARMXEmitter::BL_CC(CCFlags Cond) void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) { s32 distance = (s32(code) - 8) - (s32)branch.ptr; - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "SetJumpTarget out of range (%p calls %p)", code, branch.ptr); @@ -402,7 +425,7 @@ void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) void ARMXEmitter::B (const void *fnptr) { s32 distance = (s32)fnptr - (s32(code) + 8); - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "B out of range (%p calls %p)", code, fnptr); @@ -414,10 +437,18 @@ void ARMXEmitter::B(ARMReg src) Write32(condition | 0x12FFF10 | src); } +bool ARMXEmitter::BLInRange(const void *fnptr) { + s32 distance = (s32)fnptr - (s32(code) + 8); + if (distance <= -33554432 || distance > 33554432) + return false; + else + return true; +} + void ARMXEmitter::BL(const void *fnptr) { s32 distance = (s32)fnptr - (s32(code) + 8); - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "BL out of range (%p calls %p)", code, fnptr); Write32(condition | 0x0B000000 | ((distance >> 2) & 0x00FFFFFF)); @@ -555,7 +586,7 @@ void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, b } } if (op == -1) - _assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType()); + _dbg_assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType()); Write32(condition | (op << 21) | (SetFlags ? (1 << 20) : 0) | Rn << 16 | Rd << 12 | Data); } @@ -581,6 +612,8 @@ void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedData void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);} void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);} void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(3, false, dest, src, op2);} +void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, false, dest, src, op2);} +void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, true, dest, src, op2);} void ARMXEmitter::MUL (ARMReg dest, ARMReg src, ARMReg op2) { Write32(condition | (dest << 16) | (src << 8) | (9 << 4) | op2); @@ -599,6 +632,11 @@ void ARMXEmitter::UMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) Write4OpMultiply(0x8, destLo, destHi, rn, rm); } +void ARMXEmitter::UMULLS(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0x9, destLo, destHi, rn, rm); +} + void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) { Write4OpMultiply(0xC, destLo, destHi, rn, rm); @@ -652,11 +690,11 @@ void ARMXEmitter::RBIT(ARMReg dest, ARMReg src) } void ARMXEmitter::REV (ARMReg dest, ARMReg src) { - Write32(condition | (0x6B << 20) | (0xF << 16) | (dest << 12) | (0xF3 << 4) | src); + Write32(condition | (0x6BF << 16) | (dest << 12) | (0xF3 << 4) | src); } void ARMXEmitter::REV16(ARMReg dest, ARMReg src) { - Write32(condition | (0x3DF << 16) | (dest << 12) | (0xFD << 4) | src); + Write32(condition | (0x6BF << 16) | (dest << 12) | (0xFB << 4) | src); } void ARMXEmitter::_MSR (bool write_nzcvq, bool write_g, Operand2 op2) @@ -677,7 +715,7 @@ void ARMXEmitter::LDREX(ARMReg dest, ARMReg base) } void ARMXEmitter::STREX(ARMReg result, ARMReg base, ARMReg op) { - _assert_msg_(DYNA_REC, (result != base && result != op), "STREX dest can't be other two registers"); + _dbg_assert_msg_(DYNA_REC, (result != base && result != op), "STREX dest can't be other two registers"); Write32(condition | (24 << 20) | (base << 16) | (result << 12) | (0xF9 << 4) | op); } void ARMXEmitter::DMB () @@ -730,7 +768,7 @@ void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool R bool SignedLoad = false; if (op == -1) - _assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); + _dbg_assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); switch (Op) { @@ -854,10 +892,25 @@ ARMReg ARMXEmitter::SubBase(ARMReg Reg) } // NEON Specific +void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) +{ + _dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VABD(float)"); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it"); + bool register_quad = Vd >= Q0; + + // Gets encoded as a double register + Vd = SubBase(Vd); + Vn = SubBase(Vn); + Vm = SubBase(Vm); + + Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \ + | ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \ + | ((Vm & 0x10) << 2) | (Vm & 0xF)); +} void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)"); - _assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); + _dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)"); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); bool register_quad = Vd >= Q0; @@ -868,13 +921,13 @@ void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \ | ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \ - | ((Vm & 0x10) << 1) | (Vm & 0xF)); + | ((Vm & 0x10) << 1) | (Vm & 0xF)); } void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)"); - _assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); + _dbg_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)"); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); // Gets encoded as a double register Vd = SubBase(Vd); @@ -883,36 +936,37 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \ | ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \ - | ((Vm & 0x10) << 2) | (Vm & 0xF)); + | ((Vm & 0x10) << 2) | (Vm & 0xF)); } -// VFP Specific -struct VFPEnc -{ - s16 opc1; - s16 opc2; -}; // Double/single, Neon -const VFPEnc VFPOps[][2] = { +extern const VFPEnc VFPOps[16][2] = { {{0xE0, 0xA0}, {0x20, 0xD1}}, // 0: VMLA - {{0xE0, 0xA4}, {0x22, 0xD1}}, // 1: VMLS - {{0xE3, 0xA0}, {0x20, 0xD0}}, // 2: VADD - {{0xE3, 0xA4}, {0x22, 0xD0}}, // 3: VSUB - {{0xE2, 0xA0}, {0x30, 0xD1}}, // 4: VMUL - {{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 5: VABS(Vn(0x0) used for encoding) - {{0xE8, 0xA0}, { -1, -1}}, // 6: VDIV - {{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 7: VNEG(Vn(0x1) used for encoding) - {{0xEB, 0xAC}, { -1, -1}}, // 8: VSQRT (Vn(0x1) used for encoding) - {{0xEB, 0xA4}, { -1, -1}}, // 9: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding) - {{0xEB, 0xAC}, { -1, -1}}, // 10: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding) - {{ -1, -1}, {0x3B, 0x30}}, // 11: VABSi + {{0xE1, 0xA4}, { -1, -1}}, // 1: VNMLA + {{0xE0, 0xA4}, {0x22, 0xD1}}, // 2: VMLS + {{0xE1, 0xA0}, { -1, -1}}, // 3: VNMLS + {{0xE3, 0xA0}, {0x20, 0xD0}}, // 4: VADD + {{0xE3, 0xA4}, {0x22, 0xD0}}, // 5: VSUB + {{0xE2, 0xA0}, {0x30, 0xD1}}, // 6: VMUL + {{0xE2, 0xA4}, { -1, -1}}, // 7: VNMUL + {{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 8: VABS(Vn(0x0) used for encoding) + {{0xE8, 0xA0}, { -1, -1}}, // 9: VDIV + {{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 10: VNEG(Vn(0x1) used for encoding) + {{0xEB, 0xAC}, { -1, -1}}, // 11: VSQRT (Vn(0x1) used for encoding) + {{0xEB, 0xA4}, { -1, -1}}, // 12: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding) + {{0xEB, 0xAC}, { -1, -1}}, // 13: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding) + {{ -1, -1}, {0x3B, 0x30}}, // 14: VABSi }; -const char *VFPOpNames[] = { + +extern const char *VFPOpNames[16] = { "VMLA", + "VNMLA", "VMLS", + "VNMLS", "VADD", "VSUB", "VMUL", + "VNMUL", "VABS", "VDIV", "VNEG", @@ -966,6 +1020,7 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm) else return ((Reg & 0x1) << 5) | (Reg >> 1); } + void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm) { bool quad_reg = Vd >= Q0; @@ -973,39 +1028,42 @@ void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm) VFPEnc enc = VFPOps[Op][quad_reg]; if (enc.opc1 == -1 && enc.opc2 == -1) - _assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP"); + _dbg_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP"); u32 VdEnc = EncodeVd(Vd); u32 VnEnc = EncodeVn(Vn); u32 VmEnc = EncodeVm(Vm); u32 cond = quad_reg ? (0xF << 28) : condition; - + Write32(cond | (enc.opc1 << 20) | VnEnc | VdEnc | (enc.opc2 << 4) | (quad_reg << 6) | (double_reg << 8) | VmEnc); } void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(0, Vd, Vn, Vm); } -void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); } -void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); } -void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); } -void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); } -void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(5, Vd, D0, Vm); } -void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); } -void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(7, Vd, D1, Vm); } -void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D1, Vm); } -void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(9, Vd, D4, Vm); } -void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D4, Vm); } -void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(9, Vd, D5, D0); } -void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(10, Vd, D5, D0); } +void ARMXEmitter::VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); } +void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); } +void ARMXEmitter::VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); } +void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); } +void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(5, Vd, Vn, Vm); } +void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); } +void ARMXEmitter::VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(7, Vd, Vn, Vm); } +void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D0, Vm); } +void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(9, Vd, Vn, Vm); } +void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D1, Vm); } +void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(11, Vd, D1, Vm); } +void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(12, Vd, D4, Vm); } +void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(13, Vd, D4, Vm); } +void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(12, Vd, D5, D0); } +void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(13, Vd, D5, D0); } void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) { - _assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); - _assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR"); + _dbg_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); + _dbg_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR"); bool Add = offset >= 0 ? true : false; u32 imm = abs(offset); - _assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); + _dbg_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); - if (imm & 0xC03) + if (imm & 0xC03) ERROR_LOG(DYNA_REC, "VLDR: Bad offset %08x", imm); bool single_reg = Dest < D0; @@ -1015,25 +1073,25 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) if (single_reg) { Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \ - | ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2)); + | ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2)); } else { Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \ - | ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2)); + | ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2)); } } void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset) { - _assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR"); - _assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR"); + _dbg_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR"); + _dbg_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR"); bool Add = offset >= 0 ? true : false; u32 imm = abs(offset); - _assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); + _dbg_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); - if (imm & 0xC03) + if (imm & 0xC03) ERROR_LOG(DYNA_REC, "VSTR: Bad offset %08x", imm); bool single_reg = Src < D0; @@ -1043,12 +1101,12 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset) if (single_reg) { Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x1) << 22) | (Base << 16) \ - | ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2)); + | ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2)); } else { Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x10) << 18) | (Base << 16) \ - | ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2)); + | ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2)); } } @@ -1063,15 +1121,20 @@ void ARMXEmitter::VMSR(ARMReg Rt) { } // VFP and ASIMD +void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2) +{ + _dbg_assert_msg_(DYNA_REC, cpu_info.bVFPv3, "VMOV #imm requires VFPv3"); + Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (0xA << 8) | op2.Imm8VFP()); +} void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high) { - _assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg"); - _assert_msg_(DYNA_REC, Dest >= D0, "This VMOV doesn't support DEST other than VFP"); + _dbg_assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg"); + _dbg_assert_msg_(DYNA_REC, Dest >= D0, "This VMOV doesn't support DEST other than VFP"); Dest = SubBase(Dest); Write32(condition | (0xE << 24) | (high << 21) | ((Dest & 0xF) << 16) | (Src << 12) \ - | (11 << 8) | ((Dest & 0x10) << 3) | (1 << 4)); + | (0xB << 8) | ((Dest & 0x10) << 3) | (1 << 4)); } void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) @@ -1091,7 +1154,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) else { // Move 64bit from Arm reg - _assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON"); + _dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON"); return; } } @@ -1111,14 +1174,14 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) else { // Move 64bit To Arm reg - _assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON"); + _dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON"); return; } } else { // Move Arm reg to Arm reg - _assert_msg_(DYNA_REC, false, "VMOV doesn't support moving ARM registers"); + _dbg_assert_msg_(DYNA_REC, false, "VMOV doesn't support moving ARM registers"); } } // Moving NEON registers @@ -1127,7 +1190,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) bool Single = DestSize == 1; bool Quad = DestSize == 4; - _assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); + _dbg_assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); Dest = SubBase(Dest); Src = SubBase(Src); @@ -1142,7 +1205,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) // Double and quad if (Quad) { - _assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); // Gets encoded as a Double register Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \ | ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \ @@ -1160,13 +1223,39 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags) { bool single_reg = (Dest < D0) && (Source < D0); + bool single_double = !single_reg && (Source < D0 || Dest < D0); + bool single_to_double = Source < D0; int op = ((flags & TO_INT) ? (flags & ROUND_TO_ZERO) : (flags & IS_SIGNED)) ? 1 : 0; int op2 = ((flags & TO_INT) ? (flags & IS_SIGNED) : 0) ? 1 : 0; Dest = SubBase(Dest); Source = SubBase(Source); - if (single_reg) + if (single_double) { + // S32<->F64 + if ((flags & TO_INT) || (flags & TO_FLOAT)) + { + if (single_to_double) + { + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) \ + | ((Dest & 0xF) << 12) | (op << 7) | (0x2D << 6) | ((Source & 0x1) << 5) | (Source >> 1)); + } else { + Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ + | ((Dest & 0x1E) << 11) | (op << 7) | (0x2D << 6) | ((Source & 0x10) << 1) | (Source & 0xF)); + } + } + // F32<->F64 + else { + if (single_to_double) + { + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | (0x7 << 16) \ + | ((Dest & 0xF) << 12) | (0x2B << 6) | ((Source & 0x1) << 5) | (Source >> 1)); + } else { + Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | (0x7 << 16) \ + | ((Dest & 0x1E) << 11) | (0x2F << 6) | ((Source & 0x10) << 1) | (Source & 0xF)); + } + } + } else if (single_reg) { Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ | ((Dest & 0x1E) << 11) | (op << 7) | (0x29 << 6) | ((Source & 0x1) << 5) | (Source >> 1)); } else { diff --git a/Source/Core/Common/Src/ArmEmitter.h b/Source/Core/Common/Src/ArmEmitter.h index b3fab39c40..1592da7d4f 100644 --- a/Source/Core/Common/Src/ArmEmitter.h +++ b/Source/Core/Common/Src/ArmEmitter.h @@ -365,7 +365,7 @@ private: u32 EncodeVn(ARMReg Vn); u32 EncodeVm(ARMReg Vm); void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm); - + void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); // New Ops @@ -431,6 +431,7 @@ public: void B (ARMReg src); void BL(const void *fnptr); void BL(ARMReg src); + bool BLInRange(const void *fnptr); void PUSH(const int num, ...); void POP(const int num, ...); @@ -453,6 +454,8 @@ public: void LSLS(ARMReg dest, ARMReg src, Operand2 op2); void LSLS(ARMReg dest, ARMReg src, ARMReg op2); void LSR (ARMReg dest, ARMReg src, Operand2 op2); + void ASR (ARMReg dest, ARMReg src, Operand2 op2); + void ASRS(ARMReg dest, ARMReg src, Operand2 op2); void SBC (ARMReg dest, ARMReg src, Operand2 op2); void SBCS(ARMReg dest, ARMReg src, Operand2 op2); void RBIT(ARMReg dest, ARMReg src); @@ -484,6 +487,7 @@ public: void MULS(ARMReg dest, ARMReg src, ARMReg op2); void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void UMULLS(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); void UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); @@ -530,6 +534,7 @@ public: // Subtracts the base from the register to give us the real one ARMReg SubBase(ARMReg Reg); // NEON Only + void VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); @@ -541,6 +546,10 @@ public: // Compares against zero void VCMP(ARMReg Vd); void VCMPE(ARMReg Vd); + + void VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VSQRT(ARMReg Vd, ARMReg Vm); @@ -552,6 +561,7 @@ public: void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VMOV(ARMReg Dest, Operand2 op2); void VMOV(ARMReg Dest, ARMReg Src, bool high); void VMOV(ARMReg Dest, ARMReg Src); void VCVT(ARMReg Dest, ARMReg Src, int flags); @@ -564,7 +574,7 @@ public: // Wrapper around MOVT/MOVW with fallbacks. void MOVI2R(ARMReg reg, u32 val, bool optimize = true); - void MOVI2F(ARMReg dest, float val, ARMReg tempReg); + void MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate = false); void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); @@ -624,7 +634,11 @@ public: // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). void WriteProtect() { - WriteProtectMemory(region, region_size, true); + WriteProtectMemory(region, region_size, true); + } + void UnWriteProtect() + { + UnWriteProtectMemory(region, region_size, false); } void ResetCodePtr() @@ -636,7 +650,23 @@ public: { return region_size - (GetCodePtr() - region); } + + u8 *GetBasePtr() { + return region; + } + + size_t GetOffset(u8 *ptr) { + return ptr - region; + } +}; + +// VFP Specific +struct VFPEnc { + s16 opc1; + s16 opc2; }; +extern const VFPEnc VFPOps[16][2]; +extern const char *VFPOpNames[16]; } // namespace diff --git a/Source/Core/Common/Src/ExtendedTrace.cpp b/Source/Core/Common/Src/ExtendedTrace.cpp index 85057639a5..08740c3c95 100644 --- a/Source/Core/Common/Src/ExtendedTrace.cpp +++ b/Source/Core/Common/Src/ExtendedTrace.cpp @@ -136,7 +136,6 @@ static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ) { BOOL ret = FALSE; - DWORD dwDisp = 0; DWORD dwSymSize = 10000; TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; @@ -153,9 +152,11 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L // Get symbol info for IP #ifndef _M_X64 + DWORD dwDisp = 0; if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) #else //makes it compile but hell im not sure if this works... + DWORD64 dwDisp = 0; if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) #endif { diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp index 0b265543de..2eca8df929 100644 --- a/Source/Core/Common/Src/IniFile.cpp +++ b/Source/Core/Common/Src/IniFile.cpp @@ -20,45 +20,30 @@ namespace { -static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) +static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut) { - int FirstEquals = (int)line.find("=", 0); - int FirstCommentChar = -1; - - // Comments - if (FirstCommentChar < 0) - FirstCommentChar = - (int)line.find("#", FirstEquals > 0 ? FirstEquals : 0); - if (FirstCommentChar < 0 && line[0] == ';') - FirstCommentChar = 0; + if (line[0] == '#') + return; - // Allow preservation of spacing before comment - if (FirstCommentChar > 0) - { - while (line[FirstCommentChar - 1] == ' ' || line[FirstCommentChar - 1] == 9) // 9 == tab - { - FirstCommentChar--; - } - } + int FirstEquals = (int)line.find("=", 0); - if ((FirstEquals >= 0) && ((FirstCommentChar < 0) || (FirstEquals < FirstCommentChar))) + if (FirstEquals >= 0) { // Yes, a valid line! *keyOut = StripSpaces(line.substr(0, FirstEquals)); - if (commentOut) *commentOut = FirstCommentChar > 0 ? line.substr(FirstCommentChar) : std::string(""); - if (valueOut) *valueOut = StripQuotes(StripSpaces(line.substr(FirstEquals + 1, FirstCommentChar - FirstEquals - 1))); + if (valueOut) *valueOut = StripQuotes(StripSpaces(line.substr(FirstEquals + 1, std::string::npos))); } } } -std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) +std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut) { for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter) { std::string& line = *iter; std::string lineKey; - ParseLine(line, &lineKey, valueOut, commentOut); + ParseLine(line, &lineKey, valueOut); if (!strcasecmp(lineKey.c_str(), key)) return &line; } @@ -67,12 +52,12 @@ std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, s void IniFile::Section::Set(const char* key, const char* newValue) { - std::string value, commented; - std::string* line = GetLine(key, &value, &commented); + std::string value; + std::string* line = GetLine(key, &value); if (line) { // Change the value - keep the key and comment - *line = StripSpaces(key) + " = " + newValue + commented; + *line = StripSpaces(key) + " = " + newValue; } else { @@ -91,7 +76,7 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue) { - std::string* line = GetLine(key, value, 0); + std::string* line = GetLine(key, value); if (!line) { if (defaultValue) @@ -224,7 +209,7 @@ bool IniFile::Section::Exists(const char *key) const for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) { std::string lineKey; - ParseLine(*iter, &lineKey, NULL, NULL); + ParseLine(*iter, &lineKey, NULL); if (!strcasecmp(lineKey.c_str(), key)) return true; } @@ -233,7 +218,7 @@ bool IniFile::Section::Exists(const char *key) const bool IniFile::Section::Delete(const char *key) { - std::string* line = GetLine(key, 0, 0); + std::string* line = GetLine(key, 0); for (std::vector<std::string>::iterator liter = lines.begin(); liter != lines.end(); ++liter) { if (line == &*liter) @@ -313,7 +298,7 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key) Section* section = GetSection(sectionName); if (!section) return false; - std::string* line = section->GetLine(key, 0, 0); + std::string* line = section->GetLine(key, 0); for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) { if (line == &(*liter)) @@ -335,7 +320,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) { std::string key; - ParseLine(*liter, &key, 0, 0); + ParseLine(*liter, &key, 0); keys.push_back(key); } return true; @@ -421,11 +406,6 @@ bool IniFile::Load(const char* filename) // New section! std::string sub = line.substr(1, endpos - 1); sections.push_back(Section(sub)); - - if (endpos + 1 < line.size()) - { - sections[sections.size() - 1].comment = line.substr(endpos + 1); - } } } else @@ -459,7 +439,7 @@ bool IniFile::Save(const char* filename) if (section.name != "") { - out << "[" << section.name << "]" << section.comment << std::endl; + out << "[" << section.name << "]" << std::endl; } for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter) diff --git a/Source/Core/Common/Src/IniFile.h b/Source/Core/Common/Src/IniFile.h index 10e1cfdbb9..bad26ca090 100644 --- a/Source/Core/Common/Src/IniFile.h +++ b/Source/Core/Common/Src/IniFile.h @@ -25,7 +25,7 @@ public: bool Exists(const char *key) const; bool Delete(const char *key); - std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); + std::string* GetLine(const char* key, std::string* valueOut); void Set(const char* key, const char* newValue); void Set(const char* key, const std::string& newValue, const std::string& defaultValue); @@ -70,7 +70,6 @@ public: protected: std::vector<std::string> lines; std::string name; - std::string comment; }; bool Load(const char* filename); diff --git a/Source/Core/Common/Src/MemArena.cpp b/Source/Core/Common/Src/MemArena.cpp index 487788dc45..b7400a978e 100644 --- a/Source/Core/Common/Src/MemArena.cpp +++ b/Source/Core/Common/Src/MemArena.cpp @@ -20,6 +20,7 @@ #include <linux/ashmem.h> #endif #endif +#include <set> #if defined(__APPLE__) static const char* ram_temp_file = "/tmp/gc_mem.tmp"; @@ -151,7 +152,11 @@ u8* MemArena::Find4GBBase() PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno)); return 0; } - munmap(base, 0x31000000); +#ifndef ANDROID + // Android 4.3 changes how munmap works which causes crashes. + // Keep the memory space after allocating it... + munmap(base, MemSize); +#endif return static_cast<u8*>(base); #endif #endif @@ -214,27 +219,7 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 bail: // Argh! ERROR! Free what we grabbed so far so we can try again. - for (int j = 0; j <= i; j++) - { - SKIP(flags, views[i].flags); - if (views[j].out_ptr_low && *views[j].out_ptr_low) - { - arena->ReleaseView(*views[j].out_ptr_low, views[j].size); - *views[j].out_ptr_low = NULL; - } - if (*views[j].out_ptr) - { -#ifdef _M_X64 - arena->ReleaseView(*views[j].out_ptr, views[j].size); -#else - if (!(views[j].flags & MV_MIRROR_PREVIOUS)) - { - arena->ReleaseView(*views[j].out_ptr, views[j].size); - } -#endif - *views[j].out_ptr = NULL; - } - } + MemoryMap_Shutdown(views, i+1, flags, arena); return false; } @@ -300,15 +285,20 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) { + std::set<void*> freeset; for (int i = 0; i < num_views; i++) { - SKIP(flags, views[i].flags); - if (views[i].out_ptr_low && *views[i].out_ptr_low) - arena->ReleaseView(*views[i].out_ptr_low, views[i].size); - if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low)) - arena->ReleaseView(*views[i].out_ptr, views[i].size); - *views[i].out_ptr = NULL; - if (views[i].out_ptr_low) - *views[i].out_ptr_low = NULL; + const MemoryView* view = &views[i]; + u8** outptrs[2] = {view->out_ptr_low, view->out_ptr}; + for (int j = 0; j < 2; j++) + { + u8** outptr = outptrs[j]; + if (outptr && *outptr && !freeset.count(*outptr)) + { + arena->ReleaseView(*outptr, view->size); + freeset.insert(*outptr); + *outptr = NULL; + } + } } } diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index 99bc2ae6ca..25885552ef 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -34,7 +34,39 @@ bool AsciiToHex(const char* _szValue, u32& result) bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { - int writtenCount = vsnprintf(out, outsize, format, args); + int writtenCount; + +#ifdef _WIN32 + // You would think *printf are simple, right? Iterate on each character, + // if it's a format specifier handle it properly, etc. + // + // Nooooo. Not according to the C standard. + // + // According to the C99 standard (7.19.6.1 "The fprintf function") + // The format shall be a multibyte character sequence + // + // Because some character encodings might have '%' signs in the middle of + // a multibyte sequence (SJIS for example only specifies that the first + // byte of a 2 byte sequence is "high", the second byte can be anything), + // printf functions have to decode the multibyte sequences and try their + // best to not screw up. + // + // Unfortunately, on Windows, the locale for most languages is not UTF-8 + // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the + // locale, and completely fails when trying to decode UTF-8 as EUC-CN. + // + // On the other hand, the fix is simple: because we use UTF-8, no such + // multibyte handling is required as we can simply assume that no '%' char + // will be present in the middle of a multibyte sequence. + // + // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. + static locale_t c_locale = NULL; + if (!c_locale) + c_locale = _create_locale(LC_ALL, ".1252"); + writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); +#else + writtenCount = vsnprintf(out, outsize, format, args); +#endif if (writtenCount > 0 && writtenCount < outsize) { @@ -58,10 +90,9 @@ std::string StringFromFormat(const char* format, ...) va_start(args, format); required = _vscprintf(format, args); buf = new char[required + 1]; - vsnprintf(buf, required, format, args); + CharArrayFromFormatV(buf, required + 1, format, args); va_end(args); - buf[required] = '\0'; std::string temp = buf; delete[] buf; #else diff --git a/Source/Core/Common/Src/VideoBackendBase.cpp b/Source/Core/Common/Src/VideoBackendBase.cpp deleted file mode 100644 index 99bce01156..0000000000 --- a/Source/Core/Common/Src/VideoBackendBase.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "VideoBackendBase.h" - -// TODO: ugly -#ifdef _WIN32 -#include "../../../Plugins/Plugin_VideoDX9/Src/VideoBackend.h" -#include "../../../Plugins/Plugin_VideoDX11/Src/VideoBackend.h" -#endif -#if !defined(USE_GLES) || USE_GLES3 -#include "../../../Plugins/Plugin_VideoOGL/Src/VideoBackend.h" -#endif -#include "../../../Plugins/Plugin_VideoSoftware/Src/VideoBackend.h" - -std::vector<VideoBackend*> g_available_video_backends; -VideoBackend* g_video_backend = NULL; -static VideoBackend* s_default_backend = NULL; - -#ifdef _WIN32 -// http://msdn.microsoft.com/en-us/library/ms725491.aspx -static bool IsGteVista() -{ - OSVERSIONINFOEX osvi; - DWORDLONG dwlConditionMask = 0; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - osvi.dwMajorVersion = 6; - - VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); - - return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask) != FALSE; -} -#endif - -void VideoBackend::PopulateList() -{ - VideoBackend* backends[4] = { NULL }; - - // D3D11 > OGL > D3D9 > SW -#ifdef _WIN32 - g_available_video_backends.push_back(backends[2] = new DX9::VideoBackend); - if (IsGteVista()) - g_available_video_backends.push_back(backends[0] = new DX11::VideoBackend); -#endif -#if !defined(USE_GLES) || USE_GLES3 - g_available_video_backends.push_back(backends[1] = new OGL::VideoBackend); -#endif - g_available_video_backends.push_back(backends[3] = new SW::VideoSoftware); - - for (int i = 0; i < 4; ++i) - { - if (backends[i]) - { - s_default_backend = g_video_backend = backends[i]; - break; - } - } -} - -void VideoBackend::ClearList() -{ - while (!g_available_video_backends.empty()) - { - delete g_available_video_backends.back(); - g_available_video_backends.pop_back(); - } -} - -void VideoBackend::ActivateBackend(const std::string& name) -{ - if (name.length() == 0) // If NULL, set it to the default backend (expected behavior) - g_video_backend = s_default_backend; - - for (std::vector<VideoBackend*>::const_iterator it = g_available_video_backends.begin(); it != g_available_video_backends.end(); ++it) - if (name == (*it)->GetName()) - g_video_backend = *it; -} diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h deleted file mode 100644 index 9c591d05a5..0000000000 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef VIDEO_BACKEND_H_ -#define VIDEO_BACKEND_H_ - -#include <string> -#include <vector> - -#include "ChunkFile.h" -#include "../../VideoCommon/Src/PerfQueryBase.h" - -typedef void (*writeFn16)(const u16,const u32); -typedef void (*writeFn32)(const u32,const u32); -typedef void (*readFn16)(u16&, const u32); - - -enum FieldType -{ - FIELD_PROGRESSIVE = 0, - FIELD_UPPER, - FIELD_LOWER -}; - -enum EFBAccessType -{ - PEEK_Z = 0, - POKE_Z, - PEEK_COLOR, - POKE_COLOR -}; - -struct SCPFifoStruct -{ - // fifo registers - volatile u32 CPBase; - volatile u32 CPEnd; - u32 CPHiWatermark; - u32 CPLoWatermark; - volatile u32 CPReadWriteDistance; - volatile u32 CPWritePointer; - volatile u32 CPReadPointer; - volatile u32 CPBreakpoint; - volatile u32 SafeCPReadPointer; - // Super Monkey Ball Adventure require this. - // Because the read&check-PEToken-loop stays in its JITed block I suppose. - // So no possiblity to ack the Token irq by the scheduler until some sort of PPC watchdog do its mess. - volatile u16 PEToken; - - volatile u32 bFF_GPLinkEnable; - volatile u32 bFF_GPReadEnable; - volatile u32 bFF_BPEnable; - volatile u32 bFF_BPInt; - volatile u32 bFF_Breakpoint; - - volatile u32 CPCmdIdle; - volatile u32 CPReadIdle; - - volatile u32 bFF_LoWatermarkInt; - volatile u32 bFF_HiWatermarkInt; - - volatile u32 bFF_LoWatermark; - volatile u32 bFF_HiWatermark; - - // for GP watchdog hack - volatile u32 Fake_GPWDToken; // cicular incrementer - volatile u32 isGpuReadingData; -}; - -class VideoBackend -{ -public: - virtual ~VideoBackend() {} - - virtual void EmuStateChange(EMUSTATE_CHANGE) = 0; - - virtual void UpdateFPSDisplay(const char*) = 0; - - virtual unsigned int PeekMessages() = 0; - - virtual bool Initialize(void *&) = 0; - virtual void Shutdown() = 0; - virtual void RunLoop(bool enable) = 0; - - virtual std::string GetName() = 0; - virtual std::string GetDisplayName() { return GetName(); } - - virtual void ShowConfig(void*) {} - - virtual void Video_Prepare() = 0; - virtual void Video_EnterLoop() = 0; - virtual void Video_ExitLoop() = 0; - virtual void Video_Cleanup() = 0; // called from gl/d3d thread - - virtual void Video_BeginField(u32, FieldType, u32, u32) = 0; - virtual void Video_EndField() = 0; - - virtual u32 Video_AccessEFB(EFBAccessType, u32, u32, u32) = 0; - virtual u32 Video_GetQueryResult(PerfQueryType type) = 0; - - virtual void Video_AddMessage(const char* pstr, unsigned int milliseconds) = 0; - virtual void Video_ClearMessages() = 0; - virtual bool Video_Screenshot(const char* filename) = 0; - - virtual void Video_SetRendering(bool bEnabled) = 0; - - virtual void Video_GatherPipeBursted() = 0; - - virtual bool Video_IsPossibleWaitingSetDrawDone() = 0; - virtual bool Video_IsHiWatermarkActive() = 0; - virtual void Video_AbortFrame() = 0; - - virtual readFn16 Video_CPRead16() = 0; - virtual writeFn16 Video_CPWrite16() = 0; - virtual readFn16 Video_PERead16() = 0; - virtual writeFn16 Video_PEWrite16() = 0; - virtual writeFn32 Video_PEWrite32() = 0; - - static void PopulateList(); - static void ClearList(); - static void ActivateBackend(const std::string& name); - - // waits until is paused and fully idle, and acquires a lock on that state. - // or, if doLock is false, releases a lock on that state and optionally unpauses. - // calls must be balanced and non-recursive (once with doLock true, then once with doLock false). - virtual void PauseAndLock(bool doLock, bool unpauseOnUnlock=true) = 0; - - // the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now - virtual void DoState(PointerWrap &p) = 0; - - virtual void CheckInvalidState() = 0; -}; - -extern std::vector<VideoBackend*> g_available_video_backends; -extern VideoBackend* g_video_backend; - -// inherited by dx9/dx11/ogl backends -class VideoBackendHardware : public VideoBackend -{ - void RunLoop(bool enable); - bool Initialize(void *&) { InitializeShared(); return true; } - - void EmuStateChange(EMUSTATE_CHANGE); - - void Video_EnterLoop(); - void Video_ExitLoop(); - void Video_BeginField(u32, FieldType, u32, u32); - void Video_EndField(); - - u32 Video_AccessEFB(EFBAccessType, u32, u32, u32); - u32 Video_GetQueryResult(PerfQueryType type); - - void Video_AddMessage(const char* pstr, unsigned int milliseconds); - void Video_ClearMessages(); - bool Video_Screenshot(const char* filename); - - void Video_SetRendering(bool bEnabled); - - void Video_GatherPipeBursted(); - - bool Video_IsPossibleWaitingSetDrawDone(); - bool Video_IsHiWatermarkActive(); - void Video_AbortFrame(); - - readFn16 Video_CPRead16(); - writeFn16 Video_CPWrite16(); - readFn16 Video_PERead16(); - writeFn16 Video_PEWrite16(); - writeFn32 Video_PEWrite32(); - - void PauseAndLock(bool doLock, bool unpauseOnUnlock=true); - void DoState(PointerWrap &p); - - bool m_invalid; - -public: - void CheckInvalidState(); - -protected: - void InitializeShared(); - void InvalidState(); -}; - -#endif diff --git a/Source/Core/Common/Src/x64CPUDetect.cpp b/Source/Core/Common/Src/x64CPUDetect.cpp index d225262f81..e4eac54ef1 100644 --- a/Source/Core/Common/Src/x64CPUDetect.cpp +++ b/Source/Core/Common/Src/x64CPUDetect.cpp @@ -72,6 +72,14 @@ static void __cpuid(int info[4], int x) #endif } +#define _XCR_XFEATURE_ENABLED_MASK 0 +static unsigned long long _xgetbv(unsigned int index) +{ + unsigned int eax, edx; + __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); + return ((unsigned long long)edx << 32) | eax; +} + #endif #include "Common.h" @@ -149,8 +157,17 @@ void CPUInfo::Detect() if ((cpu_id[2] >> 9) & 1) bSSSE3 = true; if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true; if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true; - if ((cpu_id[2] >> 28) & 1) bAVX = true; if ((cpu_id[2] >> 25) & 1) bAES = true; + + // AVX support requires 3 separate checks: + // - Is the AVX bit set in CPUID? + // - Is the XSAVE bit set in CPUID? + // - XGETBV result has the XCR bit set. + if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) + { + if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) + bAVX = true; + } } if (max_ex_fn >= 0x80000004) { // Extract brand string diff --git a/Source/Core/Common/make_scmrev.h.js b/Source/Core/Common/make_scmrev.h.js index 82f6394c2b..f2978987dc 100644 --- a/Source/Core/Common/make_scmrev.h.js +++ b/Source/Core/Common/make_scmrev.h.js @@ -58,8 +58,8 @@ var describe = GetFirstStdOutLine(gitexe + cmd_describe); var branch = GetFirstStdOutLine(gitexe + cmd_branch); var isMaster = +("master" == branch); -// remove hash from description -describe = describe.replace(/-[^-]+(-dirty)?$/, '$1'); +// remove hash (and trailing "-0" if needed) from description +describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2'); var out_contents = "#define SCM_REV_STR \"" + revision + "\"\n" + |
