diff options
Diffstat (limited to 'Source/Core/Common')
55 files changed, 3175 insertions, 723 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 122f681085..361337e421 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -1,9 +1,7 @@ -set(SRCS Src/ABI.cpp - Src/BreakPoints.cpp +set(SRCS Src/BreakPoints.cpp Src/CDUtils.cpp Src/ColorUtil.cpp Src/ConsoleListener.cpp - Src/CPUDetect.cpp Src/FileSearch.cpp Src/FileUtil.cpp Src/Hash.cpp @@ -21,10 +19,10 @@ set(SRCS Src/ABI.cpp Src/SymbolDB.cpp Src/SysConf.cpp Src/Thread.cpp - Src/Thunk.cpp Src/Timer.cpp Src/Version.cpp Src/VideoBackendBase.cpp + Src/x64ABI.cpp Src/x64Analyzer.cpp Src/x64Emitter.cpp Src/Crypto/aes_cbc.cpp @@ -34,6 +32,23 @@ set(SRCS Src/ABI.cpp Src/Crypto/md5.cpp Src/Crypto/sha1.cpp) +if(_M_ARM) #ARM + set(SRCS ${SRCS} + Src/ArmCPUDetect.cpp + Src/ArmEmitter.cpp) +else() + if(NOT _M_GENERIC) #X86 + set(SRCS ${SRCS} + Src/x64FPURoundMode.cpp + Src/x64Thunk.cpp + ) + endif() + set(SRCS ${SRCS} Src/x64CPUDetect.cpp) +endif() +if(_M_GENERIC) #Generic + set(SRCS ${SRCS} + Src/GenericFPURoundMode.cpp) +endif() if(WIN32) set(SRCS ${SRCS} Src/ExtendedTrace.cpp) endif(WIN32) diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 626204f344..373d274907 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -44,7 +44,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <UseDebugLibraries>false</UseDebugLibraries> <ConfigurationType>StaticLibrary</ConfigurationType> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> @@ -54,7 +54,7 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <UseDebugLibraries>false</UseDebugLibraries> <ConfigurationType>StaticLibrary</ConfigurationType> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration"> <ConfigurationType>StaticLibrary</ConfigurationType> @@ -158,12 +158,10 @@ <Lib /> </ItemDefinitionGroup> <ItemGroup> - <ClCompile Include="Src\ABI.cpp" /> <ClCompile Include="Src\BreakPoints.cpp" /> <ClCompile Include="Src\CDUtils.cpp" /> <ClCompile Include="Src\ColorUtil.cpp" /> <ClCompile Include="Src\ConsoleListener.cpp" /> - <ClCompile Include="Src\CPUDetect.cpp" /> <ClCompile Include="Src\Crypto\aes_cbc.cpp" /> <ClCompile Include="Src\Crypto\aes_core.cpp" /> <ClCompile Include="Src\Crypto\bn.cpp" /> @@ -196,15 +194,17 @@ <ClCompile Include="Src\SymbolDB.cpp" /> <ClCompile Include="Src\SysConf.cpp" /> <ClCompile Include="Src\Thread.cpp" /> - <ClCompile Include="Src\Thunk.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" /> <ClCompile Include="Src\x64Emitter.cpp" /> + <ClCompile Include="Src\x64FPURoundMode.cpp" /> + <ClCompile Include="Src\x64Thunk.cpp" /> </ItemGroup> <ItemGroup> - <ClInclude Include="Src\ABI.h" /> <ClInclude Include="Src\Atomic.h" /> <ClInclude Include="Src\Atomic_GCC.h" /> <ClInclude Include="Src\Atomic_Win32.h" /> @@ -253,6 +253,7 @@ <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" /> </ItemGroup> diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 6ae75788ce..26f66b850a 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -1,11 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> - <ClCompile Include="Src\ABI.cpp" /> <ClCompile Include="Src\BreakPoints.cpp" /> <ClCompile Include="Src\CDUtils.cpp" /> <ClCompile Include="Src\ColorUtil.cpp" /> - <ClCompile Include="Src\CPUDetect.cpp" /> <ClCompile Include="Src\ExtendedTrace.cpp" /> <ClCompile Include="Src\FileSearch.cpp" /> <ClCompile Include="Src\FileUtil.cpp" /> @@ -23,7 +21,6 @@ <ClCompile Include="Src\SymbolDB.cpp" /> <ClCompile Include="Src\SysConf.cpp" /> <ClCompile Include="Src\Thread.cpp" /> - <ClCompile Include="Src\Thunk.cpp" /> <ClCompile Include="Src\Timer.cpp" /> <ClCompile Include="Src\Version.cpp" /> <ClCompile Include="Src\VideoBackendBase.cpp" /> @@ -54,9 +51,12 @@ <Filter>Crypto</Filter> </ClCompile> <ClCompile Include="Src\SettingsHandler.cpp" /> + <ClCompile Include="Src\x64ABI.cpp" /> + <ClCompile Include="Src\x64CPUDetect.cpp" /> + <ClCompile Include="Src\x64FPURoundMode.cpp" /> + <ClCompile Include="Src\x64Thunk.cpp" /> </ItemGroup> <ItemGroup> - <ClInclude Include="Src\ABI.h" /> <ClInclude Include="Src\Atomic.h" /> <ClInclude Include="Src\Atomic_GCC.h" /> <ClInclude Include="Src\Atomic_Win32.h" /> @@ -123,6 +123,7 @@ <ClInclude Include="Src\StdMutex.h" /> <ClInclude Include="Src\StdConditionVariable.h" /> <ClInclude Include="Src\SettingsHandler.h" /> + <ClInclude Include="Src\x64ABI.h" /> </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> diff --git a/Source/Core/Common/Src/ArmCPUDetect.cpp b/Source/Core/Common/Src/ArmCPUDetect.cpp new file mode 100644 index 0000000000..33eee9f05e --- /dev/null +++ b/Source/Core/Common/Src/ArmCPUDetect.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +#include "CPUDetect.h" +#include "StringUtil.h" +#include "FileUtil.h" + +const char procfile[] = "/proc/cpuinfo"; + +char *GetCPUString() +{ + const char marker[] = "Hardware\t: "; + char *cpu_string = 0; + // Count the number of processor lines in /proc/cpuinfo + char buf[1024]; + + File::IOFile file(procfile, "r"); + auto const fp = file.GetHandle(); + if (!fp) + return 0; + + while (fgets(buf, sizeof(buf), fp)) + { + if (strncmp(buf, marker, sizeof(marker) - 1)) + continue; + cpu_string = buf + sizeof(marker) - 1; + cpu_string = strndup(cpu_string, strlen(cpu_string) - 1); // Strip the newline + break; + } + return cpu_string; +} +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) + return 0; + + while (fgets(buf, sizeof(buf), fp)) + { + if (strncmp(buf, marker, sizeof(marker) - 1)) + continue; + char *featurestring = buf + sizeof(marker) - 1; + char *token = strtok(featurestring, " "); + while (token != NULL) + { + if (strstr(token, feature)) + return true; + token = strtok(NULL, " "); + } + } + return false; +} +int GetCoreCount() +{ + const char marker[] = "processor\t: "; + int cores = 0; + char buf[1024]; + + File::IOFile file(procfile, "r"); + 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; +} + +CPUInfo cpu_info; + +CPUInfo::CPUInfo() { + Detect(); +} + +// Detects the various cpu features +void CPUInfo::Detect() +{ + // Set some defaults here + // When ARMv8 cpus come out, these need to be updated. + HTT = false; + OS64bit = false; + CPU64bit = false; + Mode64bit = false; + vendor = VENDOR_ARM; + + // Get the information about the CPU + strncpy(cpu_string, GetCPUString(), sizeof(cpu_string)); + num_cores = GetCoreCount(); + bSwp = CheckCPUFeature("swp"); + bHalf = CheckCPUFeature("half"); + bThumb = CheckCPUFeature("thumb"); + bFastMult = CheckCPUFeature("fastmult"); + bVFP = CheckCPUFeature("vfp"); + bEDSP = CheckCPUFeature("edsp"); + bThumbEE = CheckCPUFeature("thumbee"); + bNEON = CheckCPUFeature("neon"); + bVFPv3 = CheckCPUFeature("vfpv3"); + bTLS = CheckCPUFeature("tls"); + bVFPv4 = CheckCPUFeature("vfpv4"); + bIDIVa = CheckCPUFeature("idiva"); + bIDIVt = CheckCPUFeature("idivt"); + + // On some buggy kernels(Qualcomm) they show that they support VFPv4 but not IDIVa + // All VFPv4 CPUs will support IDIVa + if (bVFPv4) + bIDIVa = bIDIVt = true; + + // These two are ARMv8 specific. + bFP = CheckCPUFeature("fp"); + bASIMD = CheckCPUFeature("asimd"); + + +#if defined(__ARM_ARCH_7A__) + bArmV7 = true; +#else + bArmV7 = false; +#endif +} + +// Turn the cpu info into a string we can show +std::string CPUInfo::Summarize() +{ + std::string sum; + if (num_cores == 1) + sum = StringFromFormat("%s, %i core", cpu_string, num_cores); + else + sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); + + if (bSwp) sum += ", SWP"; + if (bHalf) sum += ", Half"; + if (bThumb) sum += ", Thumb"; + if (bFastMult) sum += ", FastMult"; + if (bVFP) sum += ", VFP"; + if (bEDSP) sum += ", EDSP"; + if (bThumbEE) sum += ", ThumbEE"; + if (bNEON) sum += ", NEON"; + if (bVFPv3) sum += ", VFPv3"; + if (bTLS) sum += ", TLS"; + if (bVFPv4) sum += ", VFPv4"; + if (bIDIVa) sum += ", IDIVa"; + if (bIDIVt) sum += ", IDIVt"; + + return sum; +} diff --git a/Source/Core/Common/Src/ArmEmitter.cpp b/Source/Core/Common/Src/ArmEmitter.cpp new file mode 100644 index 0000000000..9b738be030 --- /dev/null +++ b/Source/Core/Common/Src/ArmEmitter.cpp @@ -0,0 +1,1110 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +#include "ArmEmitter.h" +#include "CPUDetect.h" + +#include <assert.h> +#include <stdarg.h> + +// For cache flushing on Symbian/iOS/Blackberry +#ifdef __SYMBIAN32__ +#include <e32std.h> +#endif + +#ifdef IOS +#include <libkern/OSCacheControl.h> +#include <sys/mman.h> +#endif + +#ifdef BLACKBERRY +#include <sys/mman.h> +#endif + +namespace ArmGen +{ + +inline u32 RotR(u32 a, int amount) { + if (!amount) return a; + return (a >> amount) | (a << (32 - amount)); +} + +inline u32 RotL(u32 a, int amount) { + if (!amount) return a; + return (a << amount) | (a >> (32 - amount)); +} + +bool TryMakeOperand2(u32 imm, Operand2 &op2) { + // Just brute force it. + for (int i = 0; i < 16; i++) { + int mask = RotR(0xFF, i * 2); + if ((imm & mask) == imm) { + op2 = Operand2((u8)(RotL(imm, i * 2)), (u8)i); + return true; + } + } + return false; +} + +bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse) +{ + if (!TryMakeOperand2(imm, op2)) { + *inverse = true; + return TryMakeOperand2(~imm, op2); + } else { + *inverse = false; + return true; + } +} + +bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated) +{ + if (!TryMakeOperand2(imm, op2)) { + *negated = true; + return TryMakeOperand2(-imm, op2); + } else { + *negated = false; + return true; + } +} + +void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg) +{ + union {float f; u32 u;} conv; + conv.f = val; + MOVI2R(tempReg, conv.u); + VMOV(dest, tempReg); + // TODO: VMOV an IMM directly if possible + // Otherwise, use a literal pool and VLDR directly (+- 1020) +} + +void ARMXEmitter::ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) +{ + Operand2 op2; + bool inverse; + if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) { + if (!inverse) { + AND(rd, rs, op2); + } else { + BIC(rd, rs, op2); + } + } else { + MOVI2R(scratch, val); + AND(rd, rs, scratch); + } +} + +void ARMXEmitter::ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) +{ + Operand2 op2; + if (TryMakeOperand2(val, op2)) { + ORR(rd, rs, op2); + } else { + MOVI2R(scratch, val); + ORR(rd, rs, scratch); + } +} + +void ARMXEmitter::FlushLitPool() +{ + for(std::vector<LiteralPool>::iterator it = currentLitPool.begin(); it != currentLitPool.end(); ++it) { + // Search for duplicates + for(std::vector<LiteralPool>::iterator old_it = currentLitPool.begin(); old_it != it; ++old_it) { + if ((*old_it).val == (*it).val) + (*it).loc = (*old_it).loc; + } + + // Write the constant to Literal Pool + if (!(*it).loc) + { + (*it).loc = (s32)code; + Write32((*it).val); + } + s32 offset = (*it).loc - (s32)(*it).ldr_address - 8; + + // Backpatch the LDR + *(u32*)(*it).ldr_address |= (offset >= 0) << 23 | abs(offset); + } + // TODO: Save a copy of previous pools in case they are still in range. + currentLitPool.clear(); +} + +void ARMXEmitter::AddNewLit(u32 val) +{ + LiteralPool pool_item; + pool_item.loc = 0; + pool_item.val = val; + pool_item.ldr_address = code; + currentLitPool.push_back(pool_item); +} + +void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize) +{ + Operand2 op2; + bool inverse; + + if (cpu_info.bArmV7 && !optimize) + { + // For backpatching on ARMv7 + MOVW(reg, val & 0xFFFF); + MOVT(reg, val, true); + } + else if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) { + inverse ? MVN(reg, op2) : MOV(reg, op2); + } else { + if (cpu_info.bArmV7) + { + // Use MOVW+MOVT for ARMv7+ + MOVW(reg, val & 0xFFFF); + if(val & 0xFFFF0000) + MOVT(reg, val, true); + } else { + // Use literal pool for ARMv6. + AddNewLit(val); + LDR(reg, _PC); // To be backpatched later + } + } +} + +void ARMXEmitter::QuickCallFunction(ARMReg reg, void *func) { + MOVI2R(reg, (u32)(func)); + BL(reg); +} + +void ARMXEmitter::SetCodePtr(u8 *ptr) +{ + code = ptr; + startcode = code; +#ifdef IOS + lastCacheFlushEnd = ptr; +#endif +} + +const u8 *ARMXEmitter::GetCodePtr() const +{ + return code; +} + +u8 *ARMXEmitter::GetWritableCodePtr() +{ + return code; +} + +void ARMXEmitter::ReserveCodeSpace(u32 bytes) +{ + for (u32 i = 0; i < bytes/4; i++) + Write32(0xE1200070); //bkpt 0 +} + +const u8 *ARMXEmitter::AlignCode16() +{ + ReserveCodeSpace((-(s32)code) & 15); + return code; +} + +const u8 *ARMXEmitter::AlignCodePage() +{ + ReserveCodeSpace((-(s32)code) & 4095); + return code; +} + +void ARMXEmitter::FlushIcache() +{ + FlushIcacheSection(lastCacheFlushEnd, code); + lastCacheFlushEnd = code; +} + +void ARMXEmitter::FlushIcacheSection(u8 *start, u8 *end) +{ +#ifdef __SYMBIAN32__ + User::IMB_Range(start, end); +#elif defined(BLACKBERRY) + msync(start, end - start, MS_SYNC | MS_INVALIDATE_ICACHE); +#elif defined(IOS) + if (start != NULL) + sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); +#elif !defined(_WIN32) +#ifndef ANDROID + start = startcode; // Should be Linux Only +#endif + __builtin___clear_cache(start, end); +#endif +} + +void ARMXEmitter::SetCC(CCFlags cond) +{ + condition = cond << 28; +} + +void ARMXEmitter::NOP(int count) +{ + for (int i = 0; i < count; i++) { + Write32(condition | 0x01A00000); + } +} + +void ARMXEmitter::SETEND(bool BE) +{ + //SETEND is non-conditional + Write32( 0xF1010000 | (BE << 9)); +} +void ARMXEmitter::BKPT(u16 arg) +{ + Write32(condition | 0x01200070 | (arg << 4 & 0x000FFF00) | (arg & 0x0000000F)); +} +void ARMXEmitter::YIELD() +{ + Write32(condition | 0x0320F001); +} + +FixupBranch ARMXEmitter::B() +{ + FixupBranch branch; + branch.type = 0; // Zero for B + branch.ptr = code; + branch.condition = condition; + //We'll write NOP here for now. + Write32(condition | 0x01A00000); + return branch; +} +FixupBranch ARMXEmitter::BL() +{ + FixupBranch branch; + branch.type = 1; // Zero for B + branch.ptr = code; + branch.condition = condition; + //We'll write NOP here for now. + Write32(condition | 0x01A00000); + return branch; +} + +FixupBranch ARMXEmitter::B_CC(CCFlags Cond) +{ + FixupBranch branch; + branch.type = 0; // Zero for B + branch.ptr = code; + branch.condition = Cond << 28; + //We'll write NOP here for now. + Write32(condition | 0x01A00000); + return branch; +} +void ARMXEmitter::B_CC(CCFlags Cond, const void *fnptr) +{ + s32 distance = (s32)fnptr - (s32(code) + 8); + _assert_msg_(DYNA_REC, distance > -33554432 + && distance <= 33554432, + "B_CC out of range (%p calls %p)", code, fnptr); + + Write32((Cond << 28) | 0x0A000000 | ((distance >> 2) & 0x00FFFFFF)); +} +FixupBranch ARMXEmitter::BL_CC(CCFlags Cond) +{ + FixupBranch branch; + branch.type = 1; // Zero for B + branch.ptr = code; + branch.condition = Cond << 28; + //We'll write NOP here for now. + Write32(condition | 0x01A00000); + return branch; +} +void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) +{ + s32 distance = (s32(code) - 8) - (s32)branch.ptr; + _assert_msg_(DYNA_REC, distance > -33554432 + && distance <= 33554432, + "SetJumpTarget out of range (%p calls %p)", code, + branch.ptr); + if(branch.type == 0) // B + *(u32*)branch.ptr = (u32)(branch.condition | (10 << 24) | ((distance >> 2) & + 0x00FFFFFF)); + else // BL + *(u32*)branch.ptr = (u32)(branch.condition | 0x0B000000 | ((distance >> 2) + & 0x00FFFFFF)); +} +void ARMXEmitter::B (const void *fnptr) +{ + s32 distance = (s32)fnptr - (s32(code) + 8); + _assert_msg_(DYNA_REC, distance > -33554432 + && distance <= 33554432, + "B out of range (%p calls %p)", code, fnptr); + + Write32(condition | 0x0A000000 | ((distance >> 2) & 0x00FFFFFF)); +} + +void ARMXEmitter::B(ARMReg src) +{ + Write32(condition | 0x12FFF10 | src); +} + +void ARMXEmitter::BL(const void *fnptr) +{ + s32 distance = (s32)fnptr - (s32(code) + 8); + _assert_msg_(DYNA_REC, distance > -33554432 + && distance <= 33554432, + "BL out of range (%p calls %p)", code, fnptr); + Write32(condition | 0x0B000000 | ((distance >> 2) & 0x00FFFFFF)); +} +void ARMXEmitter::BL(ARMReg src) +{ + Write32(condition | 0x12FFF30 | src); +} +void ARMXEmitter::PUSH(const int num, ...) +{ + u16 RegList = 0; + u8 Reg; + int i; + va_list vl; + va_start(vl, num); + for (i=0;i<num;i++) + { + Reg = va_arg(vl, u32); + RegList |= (1 << Reg); + } + va_end(vl); + Write32(condition | (2349 << 16) | RegList); +} +void ARMXEmitter::POP(const int num, ...) +{ + u16 RegList = 0; + u8 Reg; + int i; + va_list vl; + va_start(vl, num); + for (i=0;i<num;i++) + { + Reg = va_arg(vl, u32); + RegList |= (1 << Reg); + } + va_end(vl); + Write32(condition | (2237 << 16) | RegList); +} + +void ARMXEmitter::WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2) +{ + Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | op2.Imm5() | (op << 4) | src); +} +void ARMXEmitter::WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2) +{ + Write32(condition | (13 << 21) | (SetFlags << 20) | (dest << 12) | (op2 << 8) | (op << 4) | src); +} + +// IMM, REG, IMMSREG, RSR +// -1 for invalid if the instruction doesn't support that +const s32 InstOps[][4] = {{16, 0, 0, 0}, // AND(s) + {17, 1, 1, 1}, // EOR(s) + {18, 2, 2, 2}, // SUB(s) + {19, 3, 3, 3}, // RSB(s) + {20, 4, 4, 4}, // ADD(s) + {21, 5, 5, 5}, // ADC(s) + {22, 6, 6, 6}, // SBC(s) + {23, 7, 7, 7}, // RSC(s) + {24, 8, 8, 8}, // TST + {25, 9, 9, 9}, // TEQ + {26, 10, 10, 10}, // CMP + {27, 11, 11, 11}, // CMN + {28, 12, 12, 12}, // ORR(s) + {29, 13, 13, 13}, // MOV(s) + {30, 14, 14, 14}, // BIC(s) + {31, 15, 15, 15}, // MVN(s) + {24, -1, -1, -1}, // MOVW + {26, -1, -1, -1}, // MOVT + }; + +const char *InstNames[] = { "AND", + "EOR", + "SUB", + "RSB", + "ADD", + "ADC", + "SBC", + "RSC", + "TST", + "TEQ", + "CMP", + "CMN", + "ORR", + "MOV", + "BIC", + "MVN" + }; + +void ARMXEmitter::AND (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(0, Rd, Rn, Rm); } +void ARMXEmitter::ANDS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(0, Rd, Rn, Rm, true); } +void ARMXEmitter::EOR (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(1, Rd, Rn, Rm); } +void ARMXEmitter::EORS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(1, Rd, Rn, Rm, true); } +void ARMXEmitter::SUB (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(2, Rd, Rn, Rm); } +void ARMXEmitter::SUBS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(2, Rd, Rn, Rm, true); } +void ARMXEmitter::RSB (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(3, Rd, Rn, Rm); } +void ARMXEmitter::RSBS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(3, Rd, Rn, Rm, true); } +void ARMXEmitter::ADD (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(4, Rd, Rn, Rm); } +void ARMXEmitter::ADDS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(4, Rd, Rn, Rm, true); } +void ARMXEmitter::ADC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(5, Rd, Rn, Rm); } +void ARMXEmitter::ADCS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(5, Rd, Rn, Rm, true); } +void ARMXEmitter::SBC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(6, Rd, Rn, Rm); } +void ARMXEmitter::SBCS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(6, Rd, Rn, Rm, true); } +void ARMXEmitter::RSC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(7, Rd, Rn, Rm); } +void ARMXEmitter::RSCS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(7, Rd, Rn, Rm, true); } +void ARMXEmitter::TST ( ARMReg Rn, Operand2 Rm) { WriteInstruction(8, R0, Rn, Rm, true); } +void ARMXEmitter::TEQ ( ARMReg Rn, Operand2 Rm) { WriteInstruction(9, R0, Rn, Rm, true); } +void ARMXEmitter::CMP ( ARMReg Rn, Operand2 Rm) { WriteInstruction(10, R0, Rn, Rm, true); } +void ARMXEmitter::CMN ( ARMReg Rn, Operand2 Rm) { WriteInstruction(11, R0, Rn, Rm, true); } +void ARMXEmitter::ORR (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(12, Rd, Rn, Rm); } +void ARMXEmitter::ORRS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(12, Rd, Rn, Rm, true); } +void ARMXEmitter::MOV (ARMReg Rd, Operand2 Rm) { WriteInstruction(13, Rd, R0, Rm); } +void ARMXEmitter::MOVS(ARMReg Rd, Operand2 Rm) { WriteInstruction(13, Rd, R0, Rm, true); } +void ARMXEmitter::BIC (ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(14, Rd, Rn, Rm); } +void ARMXEmitter::BICS(ARMReg Rd, ARMReg Rn, Operand2 Rm) { WriteInstruction(14, Rd, Rn, Rm, true); } +void ARMXEmitter::MVN (ARMReg Rd, Operand2 Rm) { WriteInstruction(15, Rd, R0, Rm); } +void ARMXEmitter::MVNS(ARMReg Rd, Operand2 Rm) { WriteInstruction(15, Rd, R0, Rm, true); } +void ARMXEmitter::MOVW(ARMReg Rd, Operand2 Rm) { WriteInstruction(16, Rd, R0, Rm); } +void ARMXEmitter::MOVT(ARMReg Rd, Operand2 Rm, bool TopBits) { WriteInstruction(17, Rd, R0, TopBits ? Rm.Value >> 16 : Rm); } + +void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags) // This can get renamed later +{ + s32 op = InstOps[Op][Rm.GetType()]; // Type always decided by last operand + u32 Data = Rm.GetData(); + if (Rm.GetType() == TYPE_IMM) + { + switch (Op) + { + // MOV cases that support IMM16 + case 16: + case 17: + Data = Rm.Imm16(); + break; + default: + break; + } + } + if (op == -1) + _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); +} + +// Data Operations +void ARMXEmitter::WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2) +{ + Write32(condition | (0x7 << 24) | (Op << 20) | (dest << 16) | (Op2 << 12) | (r1 << 8) | (Op3 << 5) | (1 << 4) | r2); +} +void ARMXEmitter::UDIV(ARMReg dest, ARMReg dividend, ARMReg divisor) +{ + if (!cpu_info.bIDIVa) + PanicAlert("Trying to use integer divide on hardware that doesn't support it. Bad programmer."); + WriteSignedMultiply(3, 0xF, 0, dest, divisor, dividend); +} +void ARMXEmitter::SDIV(ARMReg dest, ARMReg dividend, ARMReg divisor) +{ + if (!cpu_info.bIDIVa) + PanicAlert("Trying to use integer divide on hardware that doesn't support it. Bad programmer."); + WriteSignedMultiply(1, 0xF, 0, dest, divisor, dividend); +} +void ARMXEmitter::LSL (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, false, dest, src, op2);} +void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, true, dest, src, op2);} +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::MUL (ARMReg dest, ARMReg src, ARMReg op2) +{ + Write32(condition | (dest << 16) | (src << 8) | (9 << 4) | op2); +} +void ARMXEmitter::MULS(ARMReg dest, ARMReg src, ARMReg op2) +{ + Write32(condition | (1 << 20) | (dest << 16) | (src << 8) | (9 << 4) | op2); +} + +void ARMXEmitter::Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) { + Write32(condition | (op << 20) | (destHi << 16) | (destLo << 12) | (rm << 8) | (9 << 4) | rn); +} + +void ARMXEmitter::UMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0x8, destLo, destHi, rn, rm); +} + +void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0xC, destLo, destHi, rn, rm); +} + +void ARMXEmitter::UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0xA, destLo, destHi, rn, rm); +} + +void ARMXEmitter::SMLAL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0xE, destLo, destHi, rn, rm); +} + +void ARMXEmitter::UBFX(ARMReg dest, ARMReg rn, u8 lsb, u8 width) +{ + Write32(condition | (0x7E0 << 16) | ((width - 1) << 16) | (dest << 12) | (lsb << 7) | (5 << 4) | rn); +} + +void ARMXEmitter::CLZ(ARMReg rd, ARMReg rm) +{ + Write32(condition | (0x16F << 16) | (rd << 12) | (0xF1 << 4) | rm); +} + +void ARMXEmitter::BFI(ARMReg rd, ARMReg rn, u8 lsb, u8 width) +{ + u32 msb = (lsb + width - 1); + if (msb > 31) msb = 31; + Write32(condition | (0x7C0 << 16) | (msb << 16) | (rd << 12) | (lsb << 7) | (1 << 4) | rn); +} + +void ARMXEmitter::SXTB (ARMReg dest, ARMReg op2) +{ + Write32(condition | (0x6AF << 16) | (dest << 12) | (7 << 4) | op2); +} + +void ARMXEmitter::SXTH (ARMReg dest, ARMReg op2, u8 rotation) +{ + SXTAH(dest, (ARMReg)15, op2, rotation); +} +void ARMXEmitter::SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation) +{ + // bits ten and 11 are the rotation amount, see 8.8.232 for more + // information + Write32(condition | (0x6B << 20) | (src << 16) | (dest << 12) | (rotation << 10) | (7 << 4) | op2); +} +void ARMXEmitter::RBIT(ARMReg dest, ARMReg src) +{ + Write32(condition | (0x6F << 20) | (0xF << 16) | (dest << 12) | (0xF3 << 4) | src); +} +void ARMXEmitter::REV (ARMReg dest, ARMReg src) +{ + Write32(condition | (0x6B << 20) | (0xF << 16) | (dest << 12) | (0xF3 << 4) | src); +} +void ARMXEmitter::REV16(ARMReg dest, ARMReg src) +{ + Write32(condition | (0x3DF << 16) | (dest << 12) | (0xFD << 4) | src); +} + +void ARMXEmitter::_MSR (bool write_nzcvq, bool write_g, Operand2 op2) +{ + Write32(condition | (0x320F << 12) | (write_nzcvq << 19) | (write_g << 18) | op2.Imm12Mod()); +} +void ARMXEmitter::_MSR (bool write_nzcvq, bool write_g, ARMReg src) +{ + Write32(condition | (0x120F << 12) | (write_nzcvq << 19) | (write_g << 18) | src); +} +void ARMXEmitter::MRS (ARMReg dest) +{ + Write32(condition | (16 << 20) | (15 << 16) | (dest << 12)); +} +void ARMXEmitter::LDREX(ARMReg dest, ARMReg base) +{ + Write32(condition | (25 << 20) | (base << 16) | (dest << 12) | 0xF9F); +} +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"); + Write32(condition | (24 << 20) | (base << 16) | (result << 12) | (0xF9 << 4) | op); +} +void ARMXEmitter::DMB () +{ + Write32(0xF57FF05E); +} +void ARMXEmitter::SVC(Operand2 op) +{ + Write32(condition | (0x0F << 24) | op.Imm24()); +} + +// IMM, REG, IMMSREG, RSR +// -1 for invalid if the instruction doesn't support that +const s32 LoadStoreOps[][4] = { {0x40, 0x60, 0x60, -1}, // STR + {0x41, 0x61, 0x61, -1}, // LDR + {0x44, 0x64, 0x64, -1}, // STRB + {0x45, 0x65, 0x65, -1}, // LDRB + // Special encodings + { 0x4, 0x0, -1, -1}, // STRH + { 0x5, 0x1, -1, -1}, // LDRH + { 0x5, 0x1, -1, -1}, // LDRSB + { 0x5, 0x1, -1, -1}, // LDRSH + }; +const char *LoadStoreNames[] = { "STR", + "LDR", + "STRB", + "LDRB", + "STRH", + "LDRH", + "LDRSB", + "LDRSH", + }; + +void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool RegAdd) +{ + s32 op = LoadStoreOps[Op][Rm.GetType()]; // Type always decided by last operand + u32 Data; + + // Qualcomm chipsets get /really/ angry if you don't use index, even if the offset is zero. + // Some of these encodings require Index at all times anyway. Doesn't really matter. + // bool Index = op2 != 0 ? true : false; + bool Index = true; + bool Add = false; + + // Special Encoding + bool SpecialOp = false; + bool Half = false; + bool SignedLoad = false; + + if (op == -1) + _assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); + + switch (Op) + { + case 4: // STRH + SpecialOp = true; + Half = true; + SignedLoad = false; + break; + case 5: // LDRH + SpecialOp = true; + Half = true; + SignedLoad = false; + break; + case 6: // LDRSB + SpecialOp = true; + Half = false; + SignedLoad = true; + break; + case 7: // LDRSH + SpecialOp = true; + Half = true; + SignedLoad = true; + break; + } + switch (Rm.GetType()) + { + case TYPE_IMM: + { + s32 Temp = (s32)Rm.Value; + Data = abs(Temp); + // The offset is encoded differently on this one. + if (SpecialOp) + Data = (Data & 0xF0 << 4) | (Data & 0xF); + if (Temp >= 0) Add = true; + } + break; + case TYPE_REG: + case TYPE_IMMSREG: + if (!SpecialOp) + { + Data = Rm.GetData(); + Add = RegAdd; + break; + } + default: + // RSR not supported for any of these + // We already have the warning above + BKPT(0x2); + return; + break; + } + if (SpecialOp) + { + // Add SpecialOp things + Data = (0x5 << 4) | (SignedLoad << 6) | (Half << 5) | Data; + } + Write32(condition | (op << 20) | (Index << 24) | (Add << 23) | (Rn << 16) | (Rt << 12) | Data); +} + +void ARMXEmitter::LDR (ARMReg dest, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(1, dest, base, op2, RegAdd);} +void ARMXEmitter::LDRB(ARMReg dest, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(3, dest, base, op2, RegAdd);} +void ARMXEmitter::LDRH(ARMReg dest, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(5, dest, base, op2, RegAdd);} +void ARMXEmitter::LDRSB(ARMReg dest, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(6, dest, base, op2, RegAdd);} +void ARMXEmitter::LDRSH(ARMReg dest, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(7, dest, base, op2, RegAdd);} +void ARMXEmitter::STR (ARMReg result, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(0, result, base, op2, RegAdd);} +void ARMXEmitter::STRH (ARMReg result, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(4, result, base, op2, RegAdd);} +void ARMXEmitter::STRB (ARMReg result, ARMReg base, Operand2 op2, bool RegAdd) { WriteStoreOp(2, result, base, op2, RegAdd);} + +void ARMXEmitter::WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList) +{ + Write32(condition | (op << 20) | (WriteBack << 21) | (dest << 16) | RegList); +} +void ARMXEmitter::STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...) +{ + u16 RegList = 0; + u8 Reg; + int i; + va_list vl; + va_start(vl, Regnum); + for (i=0;i<Regnum;i++) + { + Reg = va_arg(vl, u32); + RegList |= (1 << Reg); + } + va_end(vl); + WriteRegStoreOp(0x90, dest, WriteBack, RegList); +} +void ARMXEmitter::LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...) +{ + u16 RegList = 0; + u8 Reg; + int i; + va_list vl; + va_start(vl, Regnum); + for (i=0;i<Regnum;i++) + { + Reg = va_arg(vl, u32); + RegList |= (1 << Reg); + } + va_end(vl); + WriteRegStoreOp(0x89, dest, WriteBack, RegList); +} + +ARMReg ARMXEmitter::SubBase(ARMReg Reg) +{ + if (Reg >= S0) + { + if (Reg >= D0) + { + if (Reg >= Q0) + return (ARMReg)((Reg - Q0) * 2); // Always gets encoded as a double register + return (ARMReg)(Reg - D0); + } + return (ARMReg)(Reg - S0); + } + return Reg; +} + +// NEON Specific +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"); + + bool register_quad = Vd >= Q0; + + // Gets encoded as a double register + Vd = SubBase(Vd); + Vn = SubBase(Vn); + Vm = SubBase(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) << 2) | (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"); + + // 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) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \ + | ((Vm & 0x10) << 2) | (Vm & 0xF)); +} + +// VFP Specific +struct VFPEnc +{ + s16 opc1; + s16 opc2; +}; +// Double/single, Neon +const VFPEnc VFPOps[][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 + }; +const char *VFPOpNames[] = { + "VMLA", + "VMLS", + "VADD", + "VSUB", + "VMUL", + "VABS", + "VDIV", + "VNEG", + "VSQRT", + "VCMP", + "VCMPE", + "VABSi", +}; + +u32 ARMXEmitter::EncodeVd(ARMReg Vd) +{ + bool quad_reg = Vd >= Q0; + bool double_reg = Vd >= D0; + + ARMReg Reg = SubBase(Vd); + + if (quad_reg) + return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 12); + else + if (double_reg) + return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 12); + else + return ((Reg & 0x1) << 22) | ((Reg & 0x1E) << 11); +} +u32 ARMXEmitter::EncodeVn(ARMReg Vn) +{ + bool quad_reg = Vn >= Q0; + bool double_reg = Vn >= D0; + + ARMReg Reg = SubBase(Vn); + if (quad_reg) + return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3); + else + if (double_reg) + return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3); + else + return ((Reg & 0x1E) << 15) | ((Reg & 0x1) << 7); +} +u32 ARMXEmitter::EncodeVm(ARMReg Vm) +{ + bool quad_reg = Vm >= Q0; + bool double_reg = Vm >= D0; + + ARMReg Reg = SubBase(Vm); + + if (quad_reg) + return ((Reg & 0x10) << 2) | (Reg & 0xF); + else + if (double_reg) + return ((Reg & 0x10) << 2) | (Reg & 0xF); + else + return ((Reg & 0x1) << 5) | (Reg >> 1); +} +void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm) +{ + bool quad_reg = Vd >= Q0; + bool double_reg = Vd >= D0 && Vd < Q0; + + 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"); + 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::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"); + + 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"); + + if (imm & 0xC03) + ERROR_LOG(DYNA_REC, "VLDR: Bad offset %08x", imm); + + bool single_reg = Dest < D0; + + Dest = SubBase(Dest); + + if (single_reg) + { + Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \ + | ((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)); + } +} +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"); + + 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"); + + if (imm & 0xC03) + ERROR_LOG(DYNA_REC, "VSTR: Bad offset %08x", imm); + + bool single_reg = Src < D0; + + Src = SubBase(Src); + + if (single_reg) + { + Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x1) << 22) | (Base << 16) \ + | ((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)); + } +} + +void ARMXEmitter::VMRS_APSR() { + Write32(condition | 0xEF10A10 | (15 << 12)); +} +void ARMXEmitter::VMRS(ARMReg Rt) { + Write32(condition | (0xEF << 20) | (1 << 16) | (Rt << 12) | 0xA10); +} +void ARMXEmitter::VMSR(ARMReg Rt) { + Write32(condition | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10); +} + +// VFP and ASIMD +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"); + + Dest = SubBase(Dest); + + Write32(condition | (0xE << 24) | (high << 21) | ((Dest & 0xF) << 16) | (Src << 12) \ + | (11 << 8) | ((Dest & 0x10) << 3) | (1 << 4)); +} + +void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) +{ + if (Dest > R15) + { + if (Src < S0) + { + if (Dest < D0) + { + // Moving to a Neon register FROM ARM Reg + Dest = (ARMReg)(Dest - S0); + Write32(condition | (0xE0 << 20) | ((Dest & 0x1E) << 15) | (Src << 12) \ + | (0xA << 8) | ((Dest & 0x1) << 7) | (1 << 4)); + return; + } + else + { + // Move 64bit from Arm reg + _assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON"); + return; + } + } + } + else + { + if (Src > R15) + { + if (Src < D0) + { + // Moving to ARM Reg from Neon Register + Src = (ARMReg)(Src - S0); + Write32(condition | (0xE1 << 20) | ((Src & 0x1E) << 15) | (Dest << 12) \ + | (0xA << 8) | ((Src & 0x1) << 7) | (1 << 4)); + return; + } + else + { + // Move 64bit To Arm reg + _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"); + } + } + // Moving NEON registers + int SrcSize = Src < D0 ? 1 : Src < Q0 ? 2 : 4; + int DestSize = Dest < D0 ? 1 : Dest < Q0 ? 2 : 4; + bool Single = DestSize == 1; + bool Quad = DestSize == 4; + + _assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); + + Dest = SubBase(Dest); + Src = SubBase(Src); + + if (Single) + { + Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | ((Dest & 0x1E) << 11) \ + | (0x5 << 9) | (1 << 6) | ((Src & 0x1) << 5) | ((Src & 0x1E) >> 1)); + } + else + { + // Double and quad + if (Quad) + { + _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) \ + | ((Src & 0x10) << 1) | (1 << 4) | (Src & 0xF)); + + } + else + { + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | ((Dest & 0xF) << 12) \ + | (0x2D << 6) | ((Src & 0x10) << 1) | (Src & 0xF)); + } + } +} + +void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags) +{ + bool single_reg = (Dest < D0) && (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) + { + 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 { + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ + | ((Dest & 0xF) << 12) | (1 << 8) | (op << 7) | (0x29 << 6) | ((Source & 0x10) << 1) | (Source & 0xF)); + } +} + +} diff --git a/Source/Core/Common/Src/ArmEmitter.h b/Source/Core/Common/Src/ArmEmitter.h new file mode 100644 index 0000000000..fe64584e0c --- /dev/null +++ b/Source/Core/Common/Src/ArmEmitter.h @@ -0,0 +1,637 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!! + +#ifndef _DOLPHIN_ARM_CODEGEN_ +#define _DOLPHIN_ARM_CODEGEN_ + +#include "Common.h" +#include "MemoryUtil.h" +#if defined(__SYMBIAN32__) || defined(PANDORA) +#include <signal.h> +#endif +#include <vector> + +#undef _IP +#undef R0 +#undef _SP +#undef _LR +#undef _PC + +// VCVT flags +#define TO_FLOAT 0 +#define TO_INT 1 << 0 +#define IS_SIGNED 1 << 1 +#define ROUND_TO_ZERO 1 << 2 + +namespace ArmGen +{ +enum ARMReg +{ + // GPRs + R0 = 0, R1, R2, R3, R4, R5, + R6, R7, R8, R9, R10, R11, + + // SPRs + // R13 - R15 are SP, LR, and PC. + // Almost always referred to by name instead of register number + R12 = 12, R13 = 13, R14 = 14, R15 = 15, + _IP = 12, _SP = 13, _LR = 14, _PC = 15, + + + // VFP single precision registers + S0, S1, S2, S3, S4, S5, S6, + S7, S8, S9, S10, S11, S12, S13, + S14, S15, S16, S17, S18, S19, S20, + S21, S22, S23, S24, S25, S26, S27, + S28, S29, S30, S31, + + // VFP Double Precision registers + D0, D1, D2, D3, D4, D5, D6, D7, + D8, D9, D10, D11, D12, D13, D14, D15, + D16, D17, D18, D19, D20, D21, D22, D23, + D24, D25, D26, D27, D28, D29, D30, D31, + + // ASIMD Quad-Word registers + Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, + Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15, + INVALID_REG = 0xFFFFFFFF +}; + +enum CCFlags +{ + CC_EQ = 0, // Equal + CC_NEQ, // Not equal + CC_CS, // Carry Set + CC_CC, // Carry Clear + CC_MI, // Minus (Negative) + CC_PL, // Plus + CC_VS, // Overflow + CC_VC, // No Overflow + CC_HI, // Unsigned higher + CC_LS, // Unsigned lower or same + CC_GE, // Signed greater than or equal + CC_LT, // Signed less than + CC_GT, // Signed greater than + CC_LE, // Signed less than or equal + CC_AL, // Always (unconditional) 14 + CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same + CC_LO = CC_CC, // Alias of CC_CC Unsigned lower +}; +const u32 NO_COND = 0xE0000000; + +enum ShiftType +{ + ST_LSL = 0, + ST_ASL = 0, + ST_LSR = 1, + ST_ASR = 2, + ST_ROR = 3, + ST_RRX = 4 +}; +enum IntegerSize +{ + I_I8 = 0, + I_I16, + I_I32, + I_I64 +}; + +enum +{ + NUMGPRs = 13, +}; + +class ARMXEmitter; + +enum OpType +{ + TYPE_IMM = 0, + TYPE_REG, + TYPE_IMMSREG, + TYPE_RSR, + TYPE_MEM +}; + +// This is no longer a proper operand2 class. Need to split up. +class Operand2 +{ + friend class ARMXEmitter; +protected: + u32 Value; + +private: + OpType Type; + + // IMM types + u8 Rotation; // Only for u8 values + + // Register types + u8 IndexOrShift; + ShiftType Shift; +public: + OpType GetType() + { + return Type; + } + Operand2() {} + Operand2(u32 imm, OpType type = TYPE_IMM) + { + Type = type; + Value = imm; + Rotation = 0; + } + + Operand2(ARMReg Reg) + { + Type = TYPE_REG; + Value = Reg; + Rotation = 0; + } + Operand2(u8 imm, u8 rotation) + { + Type = TYPE_IMM; + Value = imm; + Rotation = rotation; + } + Operand2(ARMReg base, ShiftType type, ARMReg shift) // RSR + { + Type = TYPE_RSR; + _assert_msg_(DYNA_REC, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount"); + IndexOrShift = shift; + Shift = type; + Value = base; + } + + Operand2(ARMReg base, ShiftType type, u8 shift)// For IMM shifted register + { + if(shift == 32) shift = 0; + switch (type) + { + case ST_LSL: + _assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSL %u", shift); + break; + case ST_LSR: + _assert_msg_(DYNA_REC, shift <= 32, "Invalid Operand2: LSR %u", shift); + if (!shift) + type = ST_LSL; + if (shift == 32) + shift = 0; + break; + case ST_ASR: + _assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSR %u", shift); + if (!shift) + type = ST_LSL; + if (shift == 32) + shift = 0; + break; + case ST_ROR: + _assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: ROR %u", shift); + if (!shift) + type = ST_LSL; + break; + case ST_RRX: + _assert_msg_(DYNA_REC, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount"); + type = ST_ROR; + break; + } + IndexOrShift = shift; + Shift = type; + Value = base; + Type = TYPE_IMMSREG; + } + u32 GetData() + { + switch(Type) + { + case TYPE_IMM: + return Imm12Mod(); // This'll need to be changed later + case TYPE_REG: + return Rm(); + case TYPE_IMMSREG: + return IMMSR(); + case TYPE_RSR: + return RSR(); + default: + _assert_msg_(DYNA_REC, false, "GetData with Invalid Type"); + return 0; + } + } + u32 IMMSR() // IMM shifted register + { + _assert_msg_(DYNA_REC, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register"); + return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value); + } + u32 RSR() // Register shifted register + { + _assert_msg_(DYNA_REC, Type == TYPE_RSR, "RSR must be RSR Of Course"); + return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value; + } + u32 Rm() + { + _assert_msg_(DYNA_REC, Type == TYPE_REG, "Rm must be with Reg"); + return Value; + } + + u32 Imm5() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm5 not IMM value"); + return ((Value & 0x0000001F) << 7); + } + u32 Imm8() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value"); + return Value & 0xFF; + } + u32 Imm8Rot() // IMM8 with Rotation + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value"); + _assert_msg_(DYNA_REC, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation); + return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF); + } + u32 Imm12() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12 not IMM"); + return (Value & 0x00000FFF); + } + + u32 Imm12Mod() + { + // This is a IMM12 with the top four bits being rotation and the + // bottom eight being a IMM. This is for instructions that need to + // expand a 8bit IMM to a 32bit value and gives you some rotation as + // well. + // Each rotation rotates to the right by 2 bits + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12Mod not IMM"); + return ((Rotation & 0xF) << 8) | (Value & 0xFF); + } + u32 Imm16() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM"); + return ( (Value & 0xF000) << 4) | (Value & 0x0FFF); + } + u32 Imm16Low() + { + return Imm16(); + } + u32 Imm16High() // Returns high 16bits + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM"); + return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF); + } + u32 Imm24() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM"); + return (Value & 0x0FFFFFFF); + } + // NEON and ASIMD specific + u32 Imm8ASIMD() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8ASIMD not IMM"); + return ((Value & 0x80) << 17) | ((Value & 0x70) << 12) | (Value & 0xF); + } + u32 Imm8VFP() + { + _assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8VFP not IMM"); + return ((Value & 0xF0) << 12) | (Value & 0xF); + } +}; + +// Use these when you don't know if an imm can be represented as an operand2. +// This lets you generate both an optimal and a fallback solution by checking +// the return value, which will be false if these fail to find a Operand2 that +// represents your 32-bit imm value. +bool TryMakeOperand2(u32 imm, Operand2 &op2); +bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse); +bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated); + +inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); } +inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); } +inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); } +//usage: struct {int e;} s; STRUCT_OFFSET(s,e) +#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str))) + + +struct FixupBranch +{ + u8 *ptr; + u32 condition; // Remembers our codition at the time + int type; //0 = B 1 = BL +}; + +struct LiteralPool +{ + s32 loc; + u8* ldr_address; + u32 val; +}; + +typedef const u8* JumpTarget; + +class ARMXEmitter +{ + friend struct OpArg; // for Write8 etc +private: + u8 *code, *startcode; + u8 *lastCacheFlushEnd; + u32 condition; + std::vector<LiteralPool> currentLitPool; + + void WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 op2, bool RegAdd); + void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList); + void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2); + void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2); + void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2); + + u32 EncodeVd(ARMReg Vd); + 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 + void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false); + +protected: + inline void Write32(u32 value) {*(u32*)code = value; code+=4;} + +public: + ARMXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) { + condition = CC_AL << 28; + } + ARMXEmitter(u8 *code_ptr) { + code = code_ptr; + lastCacheFlushEnd = code_ptr; + startcode = code_ptr; + condition = CC_AL << 28; + } + virtual ~ARMXEmitter() {} + + void SetCodePtr(u8 *ptr); + void ReserveCodeSpace(u32 bytes); + const u8 *AlignCode16(); + const u8 *AlignCodePage(); + const u8 *GetCodePtr() const; + void FlushIcache(); + void FlushIcacheSection(u8 *start, u8 *end); + u8 *GetWritableCodePtr(); + + void FlushLitPool(); + void AddNewLit(u32 val); + + CCFlags GetCC() { return CCFlags(condition >> 28); } + void SetCC(CCFlags cond = CC_AL); + + // Special purpose instructions + + // Dynamic Endian Switching + void SETEND(bool BE); + // Debug Breakpoint + void BKPT(u16 arg); + + // Hint instruction + void YIELD(); + + // Do nothing + void NOP(int count = 1); //nop padding - TODO: fast nop slides, for amd and intel (check their manuals) + +#ifdef CALL +#undef CALL +#endif + + // Branching + FixupBranch B(); + FixupBranch B_CC(CCFlags Cond); + void B_CC(CCFlags Cond, const void *fnptr); + FixupBranch BL(); + FixupBranch BL_CC(CCFlags Cond); + void SetJumpTarget(FixupBranch const &branch); + + void B (const void *fnptr); + void B (ARMReg src); + void BL(const void *fnptr); + void BL(ARMReg src); + + void PUSH(const int num, ...); + void POP(const int num, ...); + + // New Data Ops + void AND (ARMReg Rd, ARMReg Rn, Operand2 Rm); + void ANDS(ARMReg Rd, ARMReg Rn, Operand2 Rm); + void EOR (ARMReg dest, ARMReg src, Operand2 op2); + void EORS(ARMReg dest, ARMReg src, Operand2 op2); + void SUB (ARMReg dest, ARMReg src, Operand2 op2); + void SUBS(ARMReg dest, ARMReg src, Operand2 op2); + void RSB (ARMReg dest, ARMReg src, Operand2 op2); + void RSBS(ARMReg dest, ARMReg src, Operand2 op2); + void ADD (ARMReg dest, ARMReg src, Operand2 op2); + void ADDS(ARMReg dest, ARMReg src, Operand2 op2); + void ADC (ARMReg dest, ARMReg src, Operand2 op2); + void ADCS(ARMReg dest, ARMReg src, Operand2 op2); + void LSL (ARMReg dest, ARMReg src, Operand2 op2); + void LSL (ARMReg dest, ARMReg src, ARMReg op2); + 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 SBC (ARMReg dest, ARMReg src, Operand2 op2); + void SBCS(ARMReg dest, ARMReg src, Operand2 op2); + void RBIT(ARMReg dest, ARMReg src); + void REV (ARMReg dest, ARMReg src); + void REV16 (ARMReg dest, ARMReg src); + void RSC (ARMReg dest, ARMReg src, Operand2 op2); + void RSCS(ARMReg dest, ARMReg src, Operand2 op2); + void TST ( ARMReg src, Operand2 op2); + void TEQ ( ARMReg src, Operand2 op2); + void CMP ( ARMReg src, Operand2 op2); + void CMN ( ARMReg src, Operand2 op2); + void ORR (ARMReg dest, ARMReg src, Operand2 op2); + void ORRS(ARMReg dest, ARMReg src, Operand2 op2); + void MOV (ARMReg dest, Operand2 op2); + void MOVS(ARMReg dest, Operand2 op2); + void BIC (ARMReg dest, ARMReg src, Operand2 op2); // BIC = ANDN + void BICS(ARMReg dest, ARMReg src, Operand2 op2); + void MVN (ARMReg dest, Operand2 op2); + void MVNS(ARMReg dest, Operand2 op2); + void MOVW(ARMReg dest, Operand2 op2); + void MOVT(ARMReg dest, Operand2 op2, bool TopBits = false); + + // UDIV and SDIV are only available on CPUs that have + // the idiva hardare capacity + void UDIV(ARMReg dest, ARMReg dividend, ARMReg divisor); + void SDIV(ARMReg dest, ARMReg dividend, ARMReg divisor); + + void MUL (ARMReg dest, ARMReg src, ARMReg op2); + void MULS(ARMReg dest, ARMReg src, ARMReg op2); + + void UMULL(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); + void SMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + + void SXTB(ARMReg dest, ARMReg op2); + void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0); + void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0); + void BFI(ARMReg rd, ARMReg rn, u8 lsb, u8 width); + void UBFX(ARMReg dest, ARMReg op2, u8 lsb, u8 width); + void CLZ(ARMReg rd, ARMReg rm); + + // Using just MSR here messes with our defines on the PPC side of stuff (when this code was in dolphin...) + // Just need to put an underscore here, bit annoying. + void _MSR (bool nzcvq, bool g, Operand2 op2); + void _MSR (bool nzcvq, bool g, ARMReg src); + void MRS (ARMReg dest); + + // Memory load/store operations + void LDR (ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void LDRB (ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void LDRH (ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void LDRSB(ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void LDRSH(ARMReg dest, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void STR (ARMReg result, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void STRB (ARMReg result, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + void STRH (ARMReg result, ARMReg base, Operand2 op2 = 0, bool RegAdd = true); + + void STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...); + void LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...); + + // Exclusive Access operations + void LDREX(ARMReg dest, ARMReg base); + // result contains the result if the instruction managed to store the value + void STREX(ARMReg result, ARMReg base, ARMReg op); + void DMB (); + void SVC(Operand2 op); + + // NEON and ASIMD instructions + // None of these will be created with conditional since ARM + // is deprecating conditional execution of ASIMD instructions. + // ASIMD instructions don't even have a conditional encoding. + + // Subtracts the base from the register to give us the real one + ARMReg SubBase(ARMReg Reg); + // NEON Only + void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); + + // VFP Only + void VLDR(ARMReg Dest, ARMReg Base, s16 offset); + void VSTR(ARMReg Src, ARMReg Base, s16 offset); + void VCMP(ARMReg Vd, ARMReg Vm); + void VCMPE(ARMReg Vd, ARMReg Vm); + // Compares against zero + void VCMP(ARMReg Vd); + void VCMPE(ARMReg Vd); + void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VSQRT(ARMReg Vd, ARMReg Vm); + + // NEON and VFP + void VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VABS(ARMReg Vd, ARMReg Vm); + void VNEG(ARMReg Vd, ARMReg Vm); + 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, ARMReg Src, bool high); + void VMOV(ARMReg Dest, ARMReg Src); + void VCVT(ARMReg Dest, ARMReg Src, int flags); + + void VMRS_APSR(); + void VMRS(ARMReg Rt); + void VMSR(ARMReg Rt); + + void QuickCallFunction(ARMReg scratchreg, void *func); + + // Wrapper around MOVT/MOVW with fallbacks. + void MOVI2R(ARMReg reg, u32 val, bool optimize = true); + void MOVI2F(ARMReg dest, float val, ARMReg tempReg); + + void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); + void ORI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); + + +}; // class ARMXEmitter + + +// Everything that needs to generate X86 code should inherit from this. +// You get memory management for free, plus, you can use all the MOV etc functions without +// having to prefix them with gen-> or something similar. +class ARMXCodeBlock : public ARMXEmitter +{ +protected: + u8 *region; + size_t region_size; + +public: + ARMXCodeBlock() : region(NULL), region_size(0) {} + virtual ~ARMXCodeBlock() { if (region) FreeCodeSpace(); } + + // Call this before you generate any code. + void AllocCodeSpace(int size) + { + region_size = size; + region = (u8*)AllocateExecutableMemory(region_size); + SetCodePtr(region); + } + + // Always clear code space with breakpoints, so that if someone accidentally executes + // uninitialized, it just breaks into the debugger. + void ClearCodeSpace() + { + // x86/64: 0xCC = breakpoint + memset(region, 0xCC, region_size); + ResetCodePtr(); + } + + // Call this when shutting down. Don't rely on the destructor, even though it'll do the job. + void FreeCodeSpace() + { +#ifndef __SYMBIAN32__ + FreeMemoryPages(region, region_size); +#endif + region = NULL; + region_size = 0; + } + + bool IsInSpace(u8 *ptr) + { + return ptr >= region && ptr < region + region_size; + } + + // Cannot currently be undone. Will write protect the entire code region. + // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). + void WriteProtect() + { + WriteProtectMemory(region, region_size, true); + } + + void ResetCodePtr() + { + SetCodePtr(region); + } + + size_t GetSpaceLeft() const + { + return region_size - (GetCodePtr() - region); + } +}; + +} // namespace + +#endif // _DOLPHIN_INTEL_CODEGEN_ diff --git a/Source/Core/Common/Src/BreakPoints.h b/Source/Core/Common/Src/BreakPoints.h index c742f812a7..1268b4e80a 100644 --- a/Source/Core/Common/Src/BreakPoints.h +++ b/Source/Core/Common/Src/BreakPoints.h @@ -27,9 +27,9 @@ class DebugInterface; struct TBreakPoint { - u32 iAddress; + u32 iAddress; bool bOn; - bool bTemporary; + bool bTemporary; }; struct TMemCheck @@ -96,9 +96,9 @@ public: typedef std::vector<std::string> TMemChecksStr; TMemChecks m_MemChecks; - + const TMemChecks& GetMemChecks() { return m_MemChecks; } - + TMemChecksStr GetStrings() const; void AddFromStrings(const TMemChecksStr& mcs); diff --git a/Source/Core/Common/Src/CDUtils.cpp b/Source/Core/Common/Src/CDUtils.cpp index 42aa9bfe34..9a302b9189 100644 --- a/Source/Core/Common/Src/CDUtils.cpp +++ b/Source/Core/Common/Src/CDUtils.cpp @@ -6,6 +6,7 @@ #include <memory> // for std::unique_ptr #ifdef _WIN32 #include <windows.h> +#include "StringUtil.h" #elif __APPLE__ #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOBSD.h> @@ -25,7 +26,7 @@ #ifdef _WIN32 // takes a root drive path, returns true if it is a cdrom drive -bool is_cdrom(const char drive[]) +bool is_cdrom(const TCHAR* drive) { return (DRIVE_CDROM == GetDriveType(drive)); } @@ -36,15 +37,15 @@ std::vector<std::string> cdio_get_devices() std::vector<std::string> drives; const DWORD buffsize = GetLogicalDriveStrings(0, NULL); - std::unique_ptr<char[]> buff(new char[buffsize]); - if (GetLogicalDriveStrings(buffsize, buff.get()) == buffsize - 1) + std::vector<TCHAR> buff(buffsize); + if (GetLogicalDriveStrings(buffsize, buff.data()) == buffsize - 1) { - const char* drive = buff.get(); + auto drive = buff.data(); while (*drive) { if (is_cdrom(drive)) { - std::string str(drive); + std::string str(TStrToUTF8(drive)); str.pop_back(); // we don't want the final backslash drives.push_back(std::move(str)); } diff --git a/Source/Core/Common/Src/CPUDetect.h b/Source/Core/Common/Src/CPUDetect.h index 928b34c109..5c2b33b4b3 100644 --- a/Source/Core/Common/Src/CPUDetect.h +++ b/Source/Core/Common/Src/CPUDetect.h @@ -25,19 +25,20 @@ enum CPUVendor { VENDOR_INTEL = 0, VENDOR_AMD = 1, - VENDOR_OTHER = 2, + VENDOR_ARM = 2, + VENDOR_OTHER = 3, }; struct CPUInfo { CPUVendor vendor; - + char cpu_string[0x21]; char brand_string[0x41]; bool OS64bit; bool CPU64bit; bool Mode64bit; - + bool HTT; int num_cores; int logical_cpu_count; @@ -56,9 +57,29 @@ struct CPUInfo bool bLAHFSAHF64; bool bLongMode; + // ARM specific CPUInfo + bool bSwp; + bool bHalf; + bool bThumb; + bool bFastMult; + bool bVFP; + bool bEDSP; + bool bThumbEE; + bool bNEON; + bool bVFPv3; + bool bTLS; + bool bVFPv4; + bool bIDIVa; + bool bIDIVt; + bool bArmV7; // enable MOVT, MOVW etc + + // ARMv8 specific + bool bFP; + bool bASIMD; + // Call Detect() explicit CPUInfo(); - + // Turn the cpu info into a string we can show std::string Summarize(); diff --git a/Source/Core/Common/Src/ChunkFile.h b/Source/Core/Common/Src/ChunkFile.h index 38e1b2176c..ecf641a27b 100644 --- a/Source/Core/Common/Src/ChunkFile.h +++ b/Source/Core/Common/Src/ChunkFile.h @@ -29,6 +29,7 @@ #include <map> #include <vector> +#include <list> #include <deque> #include <string> @@ -45,7 +46,8 @@ struct LinkedListItem : public T class PointerWrap { public: - enum Mode { + enum Mode + { MODE_READ = 1, // load MODE_WRITE, // save MODE_MEASURE, // calculate size @@ -57,124 +59,95 @@ public: public: PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {} - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} + void SetMode(Mode mode_) { mode = mode_; } + Mode GetMode() const { return mode; } + u8** GetPPtr() { return ptr; } - void DoVoid(void *data, int size) + template <typename K, class V> + void Do(std::map<K, V>& x) { - switch (mode) { - case MODE_READ: memcpy(data, *ptr, size); break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; - default: break; // throw an error? - } - (*ptr) += size; - } + u32 count = (u32)x.size(); + Do(count); - template<class T> - void Do(std::map<unsigned int, T> &x) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { + switch (mode) + { case MODE_READ: + for (x.clear(); count != 0; --count) { - x.clear(); - while (number > 0) - { - unsigned int first = 0; - Do(first); - T second; - Do(second); - x[first] = second; - --number; - } + std::pair<K, V> pair; + Do(pair.first); + Do(pair.second); + x.insert(pair); } break; + case MODE_WRITE: case MODE_MEASURE: case MODE_VERIFY: + for (auto itr = x.begin(); itr != x.end(); ++itr) { - typename std::map<unsigned int, T>::iterator itr = x.begin(); - while (number > 0) - { - Do(itr->first); - Do(itr->second); - --number; - ++itr; - } + Do(itr->first); + Do(itr->second); } break; } } - // Store vectors. - template<class T> - void Do(std::vector<T> &x) + template <typename T> + void DoContainer(T& x) { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size); - DoArray(&x[0], vec_size); + u32 size = (u32)x.size(); + Do(size); + x.resize(size); + + for (auto itr = x.begin(); itr != x.end(); ++itr) + Do(*itr); } - - // Store deques. - template<class T> - void Do(std::deque<T> &x) + + template <typename T> + void Do(std::vector<T>& x) { - u32 deq_size = (u32)x.size(); - Do(deq_size); - x.resize(deq_size); - u32 i; - for(i = 0; i < deq_size; i++) - DoVoid(&x[i],sizeof(T)); + DoContainer(x); } - - // Store strings. - void Do(std::string &x) + + template <typename T> + void Do(std::list<T>& x) { - int stringLen = (int)x.length() + 1; - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (char*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; - } - (*ptr) += stringLen; + DoContainer(x); } - void Do(std::wstring &x) + template <typename T> + void Do(std::deque<T>& x) { - int stringLen = sizeof(wchar_t)*((int)x.length() + 1); - Do(stringLen); - - switch (mode) { - case MODE_READ: x.assign((wchar_t*)*ptr, (stringLen / sizeof(wchar_t)) - 1); break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; - } - (*ptr) += stringLen; + DoContainer(x); } - template<class T> - void DoArray(T *x, int count) { - DoVoid((void *)x, sizeof(T) * count); - } - - template<class T> - void Do(T &x) { - DoVoid((void *)&x, sizeof(x)); + template <typename T> + void Do(std::basic_string<T>& x) + { + DoContainer(x); } - template<class T> - void DoPointer(T* &x, T*const base) { + template <typename T> + void DoArray(T* x, u32 count) + { + for (u32 i = 0; i != count; ++i) + Do(x[i]); + } + + template <typename T> + void Do(T& x) + { + // TODO: Bad, Do(some_non_POD) will compile and fail at runtime + // type_traits are not fully supported everywhere yet + + DoVoid((void*)&x, sizeof(x)); + } + + template <typename T> + void DoPointer(T*& x, T* const base) + { // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range s32 offset = x - base; Do(offset); @@ -182,7 +155,8 @@ public: x = base + offset; } - template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> + // Let's pretend std::list doesn't exist! + template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0) { LinkedListItem<T>* list_cur = list_start; @@ -242,25 +216,61 @@ public: } } - void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) + void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) { u32 cookie = arbitraryNumber; Do(cookie); - if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) + + if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { - PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); + PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", + prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); mode = PointerWrap::MODE_MEASURE; } } -}; +private: + __forceinline void DoByte(u8& x) + { + switch (mode) + { + case MODE_READ: + x = **ptr; + break; + + case MODE_WRITE: + **ptr = x; + break; + + case MODE_MEASURE: + break; + + case MODE_VERIFY: + _dbg_assert_msg_(COMMON, (x == **ptr), + "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", + x, x, &x, **ptr, **ptr, *ptr); + break; + + default: + break; + } + + ++(*ptr); + } + + void DoVoid(void *data, u32 size) + { + for(u32 i = 0; i != size; ++i) + DoByte(reinterpret_cast<u8*>(data)[i]); + } +}; class CChunkFileReader { public: // Load file template template<class T> - static bool Load(const std::string& _rFilename, int _Revision, T& _class) + static bool Load(const std::string& _rFilename, u32 _Revision, T& _class) { INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); @@ -290,7 +300,7 @@ public: ERROR_LOG(COMMON,"ChunkReader: Bad header size"); return false; } - + // Check revision if (header.Revision != _Revision) { @@ -298,36 +308,35 @@ public: header.Revision, _Revision); return false; } - + // get size - const int sz = (int)(fileSize - headerSize); + const u32 sz = (u32)(fileSize - headerSize); if (header.ExpectedSize != sz) { ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", sz, header.ExpectedSize); return false; } - + // read the state - u8* buffer = new u8[sz]; - if (!pFile.ReadBytes(buffer, sz)) + std::vector<u8> buffer(sz); + if (!pFile.ReadArray(&buffer[0], sz)) { ERROR_LOG(COMMON,"ChunkReader: Error reading file"); return false; } - u8 *ptr = buffer; + u8* ptr = &buffer[0]; PointerWrap p(&ptr, PointerWrap::MODE_READ); _class.DoState(p); - delete[] buffer; INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); return true; } - + // Save file template template<class T> - static bool Save(const std::string& _rFilename, int _Revision, T& _class) + static bool Save(const std::string& _rFilename, u32 _Revision, T& _class) { INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); File::IOFile pFile(_rFilename, "wb"); @@ -346,13 +355,12 @@ public: ptr = &buffer[0]; p.SetMode(PointerWrap::MODE_WRITE); _class.DoState(p); - + // Create header SChunkHeader header; - header.Compress = 0; header.Revision = _Revision; - header.ExpectedSize = (int)sz; - + header.ExpectedSize = (u32)sz; + // Write to file if (!pFile.WriteArray(&header, 1)) { @@ -360,23 +368,21 @@ public: return false; } - if (!pFile.WriteBytes(&buffer[0], sz)) + if (!pFile.WriteArray(&buffer[0], sz)) { ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); return false; } - - INFO_LOG(COMMON,"ChunkReader: Done writing %s", - _rFilename.c_str()); + + INFO_LOG(COMMON,"ChunkReader: Done writing %s", _rFilename.c_str()); return true; } - + private: struct SChunkHeader { - int Revision; - int Compress; - int ExpectedSize; + u32 Revision; + u32 ExpectedSize; }; }; diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h index c3cab37dd8..904095e255 100644 --- a/Source/Core/Common/Src/Common.h +++ b/Source/Core/Common/Src/Common.h @@ -133,7 +133,9 @@ private: // wxWidgets does not have a true dummy macro for this. #define _trans(a) a -#if defined __GNUC__ +#if defined _M_GENERIC +# define _M_SSE 0x0 +#elif defined __GNUC__ # if defined __SSE4_2__ # define _M_SSE 0x402 # elif defined __SSE4_1__ @@ -144,7 +146,7 @@ private: # define _M_SSE 0x300 # endif #elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008 -# define _M_SSE 0x402 +# define _M_SSE 0x402 #endif // Host communication. @@ -155,7 +157,6 @@ enum HOST_COMM WM_USER_CREATE, WM_USER_SETCURSOR, WM_USER_KEYDOWN, - WIIMOTE_DISCONNECT // Disconnect Wiimote }; // Used for notification on emulation state diff --git a/Source/Core/Common/Src/CommonFuncs.h b/Source/Core/Common/Src/CommonFuncs.h index 585fe0999a..f892769280 100644 --- a/Source/Core/Common/Src/CommonFuncs.h +++ b/Source/Core/Common/Src/CommonFuncs.h @@ -35,7 +35,7 @@ template<> struct CompileTimeAssert<true> {}; #define b32(x) (b16(x) | (b16(x) >>16) ) #define ROUND_UP_POW2(x) (b32(x - 1) + 1) -#if defined __GNUC__ && !defined __SSSE3__ +#if defined __GNUC__ && !defined __SSSE3__ && !defined _M_GENERIC #include <emmintrin.h> static __inline __m128i __attribute__((__always_inline__)) _mm_shuffle_epi8(__m128i a, __m128i mask) @@ -60,15 +60,17 @@ _mm_shuffle_epi8(__m128i a, __m128i mask) // go to debugger mode #ifdef GEKKO #define Crash() + #elif defined _M_GENERIC + #define Crash() { exit(1); } #else #define Crash() {asm ("int $3");} #endif #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) inline u32 _rotl(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x << shift) | (x >> (32 - shift)); + shift &= 31; + if (!shift) return x; + return (x << shift) | (x >> (32 - shift)); } inline u64 _rotl64(u64 x, unsigned int shift){ @@ -77,9 +79,9 @@ inline u64 _rotl64(u64 x, unsigned int shift){ } inline u32 _rotr(u32 x, int shift) { - shift &= 31; - if (!shift) return x; - return (x >> shift) | (x << (32 - shift)); + shift &= 31; + if (!shift) return x; + return (x >> shift) | (x << (32 - shift)); } inline u64 _rotr64(u64 x, unsigned int shift){ @@ -136,6 +138,15 @@ inline u8 swap8(u8 _data) {return _data;} inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} +#elif _M_ARM +#ifdef ANDROID +#undef swap16 +#undef swap32 +#undef swap64 +#endif +inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} +inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} +inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} #elif __linux__ inline u16 swap16(u16 _data) {return bswap_16(_data);} inline u32 swap32(u32 _data) {return bswap_32(_data);} @@ -162,6 +173,40 @@ inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);} inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);} inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);} +template <int count> +void swap(u8*); + +template <> +inline void swap<1>(u8* data) +{} + +template <> +inline void swap<2>(u8* data) +{ + *reinterpret_cast<u16*>(data) = swap16(data); +} + +template <> +inline void swap<4>(u8* data) +{ + *reinterpret_cast<u32*>(data) = swap32(data); +} + +template <> +inline void swap<8>(u8* data) +{ + *reinterpret_cast<u64*>(data) = swap64(data); +} + +template <typename T> +inline T FromBigEndian(T data) +{ + //static_assert(std::is_arithmetic<T>::value, "function only makes sense with arithmetic types"); + + swap<sizeof(data)>(reinterpret_cast<u8*>(&data)); + return data; +} + } // Namespace Common #endif // _COMMONFUNCS_H_ diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h index 01180c67e3..ac6676cfcb 100644 --- a/Source/Core/Common/Src/CommonPaths.h +++ b/Source/Core/Common/Src/CommonPaths.h @@ -36,6 +36,9 @@ // You can use the File::GetUserPath() util for this #define USERDATA_DIR "Contents/Resources/User" #define DOLPHIN_DATA_DIR "Library/Application Support/Dolphin" +#elif defined ANDROID + #define USERDATA_DIR "user" + #define DOLPHIN_DATA_DIR "/sdcard/dolphin-emu" #else #define USERDATA_DIR "user" #ifdef USER_DIR @@ -52,6 +55,8 @@ #define SYSDATA_DIR "Contents/Resources/Sys" #define SHARED_USER_DIR File::GetBundleDirectory() + \ DIR_SEP USERDATA_DIR DIR_SEP +#elif defined ANDROID + #define SYSDATA_DIR "/sdcard/dolphin-emu" #else #ifdef DATA_DIR #define SYSDATA_DIR DATA_DIR "sys" @@ -123,9 +128,9 @@ #define GC_MEMCARDA "MemoryCardA" #define GC_MEMCARDB "MemoryCardB" -#define WII_STATE "state.dat" +#define WII_STATE "state.dat" -#define WII_SETTING "setting.txt" +#define WII_SETTING "setting.txt" #define GECKO_CODE_HANDLER "codehandler.bin" diff --git a/Source/Core/Common/Src/ConsoleListener.cpp b/Source/Core/Common/Src/ConsoleListener.cpp index cf03581431..934300f777 100644 --- a/Source/Core/Common/Src/ConsoleListener.cpp +++ b/Source/Core/Common/Src/ConsoleListener.cpp @@ -61,7 +61,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title // Save the window handle that AllocConsole() created hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // Set the console window title - SetConsoleTitle(Title); + SetConsoleTitle(UTF8ToTStr(Title).c_str()); // Set letter space LetterSpace(80, 4000); //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); @@ -195,7 +195,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool static const int MAX_BYTES = 1024 * 16; - std::vector<std::array<CHAR, MAX_BYTES>> Str; + std::vector<std::array<TCHAR, MAX_BYTES>> Str; std::vector<std::array<WORD, MAX_BYTES>> Attr; // ReadConsoleOutputAttribute seems to have a limit at this level @@ -227,7 +227,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool LetterSpace(LBufWidth, LBufHeight); - ClearScreen(true); + ClearScreen(true); coordScreen.Y = 0; coordScreen.X = 0; DWORD cCharsWritten = 0; @@ -270,7 +270,7 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) */ DWORD cCharsWritten; WORD Color; - + switch (Level) { case NOTICE_LEVEL: // light green @@ -334,9 +334,9 @@ void ConsoleListener::ClearScreen(bool Cursor) DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi; DWORD dwConSize; - + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - + GetConsoleScreenBufferInfo(hConsole, &csbi); dwConSize = csbi.dwSize.X * csbi.dwSize.Y; // Write space to the entire console diff --git a/Source/Core/Common/Src/Crypto/md5.cpp b/Source/Core/Common/Src/Crypto/md5.cpp index 7fff7713da..7b8dc149f4 100644 --- a/Source/Core/Common/Src/Crypto/md5.cpp +++ b/Source/Core/Common/Src/Crypto/md5.cpp @@ -37,6 +37,8 @@ #include <string.h> #include <stdio.h> +#include "../FileUtil.h" + /* * 32-bit integer manipulation macros (little endian) */ @@ -301,7 +303,10 @@ int md5_file( char *path, unsigned char output[16] ) md5_context ctx; unsigned char buf[1024]; - if( ( f = fopen( path, "rb" ) ) == NULL ) + File::IOFile file(path, "rb"); + f = file.GetHandle(); + + if (f == NULL) return( 1 ); md5_starts( &ctx ); @@ -315,11 +320,9 @@ int md5_file( char *path, unsigned char output[16] ) if( ferror( f ) != 0 ) { - fclose( f ); return( 2 ); } - fclose( f ); return( 0 ); } diff --git a/Source/Core/Common/Src/Crypto/sha1.cpp b/Source/Core/Common/Src/Crypto/sha1.cpp index 17ad930986..45b88b2b6e 100644 --- a/Source/Core/Common/Src/Crypto/sha1.cpp +++ b/Source/Core/Common/Src/Crypto/sha1.cpp @@ -36,6 +36,8 @@ #include <string.h> #include <stdio.h> +#include "../FileUtil.h" + /* * 32-bit integer manipulation macros (big endian) */ @@ -335,7 +337,10 @@ int sha1_file( char *path, unsigned char output[20] ) sha1_context ctx; unsigned char buf[1024]; - if( ( f = fopen( path, "rb" ) ) == NULL ) + File::IOFile file(path, "rb"); + f = file.GetHandle(); + + if (f == NULL) return( 1 ); sha1_starts( &ctx ); @@ -349,11 +354,9 @@ int sha1_file( char *path, unsigned char output[20] ) if( ferror( f ) != 0 ) { - fclose( f ); return( 2 ); } - fclose( f ); return( 0 ); } diff --git a/Source/Core/Common/Src/ExtendedTrace.cpp b/Source/Core/Common/Src/ExtendedTrace.cpp index 3fe661f2e4..85057639a5 100644 --- a/Source/Core/Common/Src/ExtendedTrace.cpp +++ b/Source/Core/Common/Src/ExtendedTrace.cpp @@ -17,6 +17,7 @@ #include <windows.h> #include <stdio.h> #include "ExtendedTrace.h" +#include "StringUtil.h" using namespace std; #include <tchar.h> @@ -274,13 +275,21 @@ static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo ) return ret; } -void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file ) +void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) +{ + TCHAR symInfo[BUFFERSIZE] = _T("?"); + TCHAR srcInfo[BUFFERSIZE] = _T("?"); + + GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); + GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); + etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); +} + +void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) { STACKFRAME callStack; BOOL bResult; CONTEXT context; - TCHAR symInfo[BUFFERSIZE] = _T("?"); - TCHAR srcInfo[BUFFERSIZE] = _T("?"); HANDLE hProcess = GetCurrentProcess(); // If it's not this thread, let's suspend it, and resume it at the end @@ -318,9 +327,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file ) etfprint(file, "Call stack info: \n"); etfprint(file, lpszMessage); - GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo ); - GetSourceInfoFromAddress( (ULONG)callStack.AddrPC.Offset, srcInfo ); - etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n")); + PrintFunctionAndSourceInfo(file, callStack); for( ULONG index = 0; ; index++ ) { @@ -341,9 +348,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file ) if( !bResult || callStack.AddrFrame.Offset == 0 ) break; - GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo ); - GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo ); - etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n")); + PrintFunctionAndSourceInfo(file, callStack); } @@ -351,19 +356,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file ) ResumeThread( hThread ); } -void StackTrace( HANDLE hThread, wchar_t const*lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) -{ - // TODO: remove when Common builds as unicode - size_t origsize = wcslen(lpszMessage) + 1; - const size_t newsize = 100; - size_t convertedChars = 0; - char nstring[newsize]; - wcstombs_s(&convertedChars, nstring, origsize, lpszMessage, _TRUNCATE); - - StackTrace(hThread, nstring, file, eip, esp, ebp ); -} - -void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) +void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp ) { STACKFRAME callStack; BOOL bResult; @@ -391,9 +384,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO etfprint(file, "Call stack info: \n"); etfprint(file, lpszMessage); - GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo ); - GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo ); - etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n")); + PrintFunctionAndSourceInfo(file, callStack); for( ULONG index = 0; ; index++ ) { @@ -414,10 +405,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO if( !bResult || callStack.AddrFrame.Offset == 0 ) break; - GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo ); - GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo ); - etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n")); - + PrintFunctionAndSourceInfo(file, callStack); } if ( hThread != GetCurrentThread() ) @@ -426,7 +414,8 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO char g_uefbuf[2048]; -void etfprintf(FILE *file, const char *format, ...) { +void etfprintf(FILE *file, const char *format, ...) +{ va_list ap; va_start(ap, format); int len = vsprintf(g_uefbuf, format, ap); @@ -434,7 +423,8 @@ void etfprintf(FILE *file, const char *format, ...) { va_end(ap); } -void etfprint(FILE *file, const std::string &text) { +void etfprint(FILE *file, const std::string &text) +{ size_t len = text.length(); fwrite(text.data(), 1, len, file); } diff --git a/Source/Core/Common/Src/ExtendedTrace.h b/Source/Core/Common/Src/ExtendedTrace.h index 12e7ed41fa..6d33eb632d 100644 --- a/Source/Core/Common/Src/ExtendedTrace.h +++ b/Source/Core/Common/Src/ExtendedTrace.h @@ -25,16 +25,15 @@ #pragma comment( lib, "imagehlp.lib" ) #define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath ) -#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo() -#define STACKTRACE(file) StackTrace( GetCurrentThread(), _T(""), file) -#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), _T(""), file, eip, esp, ebp) +#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo() +#define STACKTRACE(file) StackTrace( GetCurrentThread(), "", file) +#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), "", file, eip, esp, ebp) // class File; BOOL InitSymInfo( PCSTR ); BOOL UninitSymInfo(); -void StackTrace( HANDLE, LPCTSTR, FILE *file); -void StackTrace( HANDLE, LPCTSTR, FILE *file, DWORD eip, DWORD esp, DWORD ebp); -void StackTrace( HANDLE hThread, wchar_t const* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp); +void StackTrace(HANDLE, char const* msg, FILE *file); +void StackTrace(HANDLE, char const* msg, FILE *file, DWORD eip, DWORD esp, DWORD ebp); // functions by Masken void etfprintf(FILE *file, const char *format, ...); @@ -44,10 +43,10 @@ extern char g_uefbuf[UEFBUFSIZE]; #else // not WIN32 -#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0) -#define EXTENDEDTRACEUNINITIALIZE() ((void)0) -#define STACKTRACE(file) ((void)0) -#define STACKTRACE2(file, eip, esp, ebp) ((void)0) +#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) ((void)0) +#define EXTENDEDTRACEUNINITIALIZE() ((void)0) +#define STACKTRACE(file) ((void)0) +#define STACKTRACE2(file, eip, esp, ebp) ((void)0) #endif // WIN32 diff --git a/Source/Core/Common/Src/FPURoundMode.h b/Source/Core/Common/Src/FPURoundMode.h new file mode 100644 index 0000000000..2e26047689 --- /dev/null +++ b/Source/Core/Common/Src/FPURoundMode.h @@ -0,0 +1,52 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ +#ifndef FPU_ROUND_MODE_H_ +#define FPU_ROUND_MODE_H_ +#include "Common.h" + +namespace FPURoundMode +{ + enum RoundModes + { + ROUND_NEAR = 0, + ROUND_CHOP, + ROUND_UP, + ROUND_DOWN + }; + enum PrecisionModes { + PREC_24 = 0, + PREC_53, + PREC_64 + }; + void SetRoundMode(u32 mode); + + void SetPrecisionMode(u32 mode); + + void SetSIMDMode(u32 mode); + +/* + * There are two different flavors of float to int conversion: + * _mm_cvtps_epi32() and _mm_cvttps_epi32(). + * + * The first rounds according to the MXCSR rounding bits. + * The second one always uses round towards zero. + */ + void SaveSIMDState(); + void LoadSIMDState(); + void LoadDefaultSIMDState(); +} +#endif diff --git a/Source/Core/Common/Src/FileSearch.cpp b/Source/Core/Common/Src/FileSearch.cpp index 595dfe7000..674cf0e1d5 100644 --- a/Source/Core/Common/Src/FileSearch.cpp +++ b/Source/Core/Common/Src/FileSearch.cpp @@ -51,7 +51,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string& BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); #ifdef _WIN32 WIN32_FIND_DATA findData; - HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData); + HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); if (FindFirst != INVALID_HANDLE_VALUE) { @@ -62,7 +62,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string& if (findData.cFileName[0] != '.') { std::string strFilename; - BuildCompleteFilename(strFilename, _strPath, findData.cFileName); + BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); m_FileNames.push_back(strFilename); } @@ -112,7 +112,6 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string& #endif } - const CFileSearch::XStringVector& CFileSearch::GetFileNames() const { return m_FileNames; diff --git a/Source/Core/Common/Src/FileUtil.cpp b/Source/Core/Common/Src/FileUtil.cpp index b46b2498fe..bf7edb0844 100644 --- a/Source/Core/Common/Src/FileUtil.cpp +++ b/Source/Core/Common/Src/FileUtil.cpp @@ -41,10 +41,11 @@ #include <CoreFoundation/CFBundle.h> #endif -#include <fstream> #include <algorithm> #include <sys/stat.h> +#include "StringUtil.h" + #ifndef S_ISDIR #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) #endif @@ -81,7 +82,11 @@ bool Exists(const std::string &filename) std::string copy(filename); StripTailDirSlashes(copy); +#ifdef _WIN32 + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); +#else int result = stat64(copy.c_str(), &file_info); +#endif return (result == 0); } @@ -94,7 +99,11 @@ bool IsDirectory(const std::string &filename) std::string copy(filename); StripTailDirSlashes(copy); +#ifdef _WIN32 + int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); +#else int result = stat64(copy.c_str(), &file_info); +#endif if (result < 0) { WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", @@ -127,7 +136,7 @@ bool Delete(const std::string &filename) } #ifdef _WIN32 - if (!DeleteFile(filename.c_str())) + if (!DeleteFile(UTF8ToTStr(filename).c_str())) { WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg()); @@ -149,7 +158,7 @@ bool CreateDir(const std::string &path) { INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); #ifdef _WIN32 - if (::CreateDirectory(path.c_str(), NULL)) + if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) return true; DWORD error = GetLastError(); if (error == ERROR_ALREADY_EXISTS) @@ -181,7 +190,7 @@ bool CreateFullPath(const std::string &fullPath) { int panicCounter = 100; INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); - + if (File::Exists(fullPath)) { INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); @@ -197,7 +206,7 @@ bool CreateFullPath(const std::string &fullPath) // we're done, yay! if (position == fullPath.npos) return true; - + // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") std::string const subPath(fullPath.substr(0, position + 1)); if (!File::IsDirectory(subPath)) @@ -228,7 +237,7 @@ bool DeleteDir(const std::string &filename) } #ifdef _WIN32 - if (::RemoveDirectory(filename.c_str())) + if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) return true; #else if (rmdir(filename.c_str()) == 0) @@ -257,7 +266,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 - if (CopyFile(srcFilename.c_str(), destFilename.c_str(), FALSE)) + if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) return true; ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", @@ -342,8 +351,13 @@ u64 GetSize(const std::string &filename) WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); return 0; } + struct stat64 buf; +#ifdef _WIN32 + if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) +#else if (stat64(filename.c_str(), &buf) == 0) +#endif { DEBUG_LOG(COMMON, "GetSize: %s: %lld", filename.c_str(), (long long)buf.st_size); @@ -391,13 +405,13 @@ bool CreateEmptyFile(const std::string &filename) { INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); - FILE *pFile = fopen(filename.c_str(), "wb"); - if (!pFile) { + if (!File::IOFile(filename, "wb")) + { ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", filename.c_str(), GetLastErrorMsg()); return false; } - fclose(pFile); + return true; } @@ -413,7 +427,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) // Find the first file in the directory. WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd); + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { FindClose(hFind); @@ -423,7 +437,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) do { FSTEntry entry; - const std::string virtualName(ffd.cFileName); + const std::string virtualName(TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = NULL; @@ -472,7 +486,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) return foundEntries; } - + // Deletes the given directory and anything under it. Returns true on success. bool DeleteDirRecursively(const std::string &directory) { @@ -480,18 +494,18 @@ bool DeleteDirRecursively(const std::string &directory) #ifdef _WIN32 // Find the first file in the directory. WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd); + HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { FindClose(hFind); return false; } - + // windows loop do { - const std::string virtualName = ffd.cFileName; + const std::string virtualName(TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = NULL; DIR *dirp = opendir(directory.c_str()); @@ -518,7 +532,7 @@ bool DeleteDirRecursively(const std::string &directory) #ifndef _WIN32 closedir(dirp); #endif - + return false; } } @@ -529,7 +543,7 @@ bool DeleteDirRecursively(const std::string &directory) #ifndef _WIN32 closedir(dirp); #endif - + return false; } } @@ -591,7 +605,7 @@ std::string GetCurrentDir() if (!(dir = __getcwd(NULL, 0))) { ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", - GetLastErrorMsg()); + GetLastErrorMsg()); return NULL; } std::string strDir = dir; @@ -622,14 +636,14 @@ std::string GetBundleDirectory() #endif #ifdef _WIN32 -std::string &GetExeDirectory() +std::string& GetExeDirectory() { static std::string DolphinPath; if (DolphinPath.empty()) { - char Dolphin_exe_Path[2048]; - GetModuleFileNameA(NULL, Dolphin_exe_Path, 2048); - DolphinPath = Dolphin_exe_Path; + TCHAR Dolphin_exe_Path[2048]; + GetModuleFileName(NULL, Dolphin_exe_Path, 2048); + DolphinPath = TStrToUTF8(Dolphin_exe_Path); DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); } return DolphinPath; @@ -668,9 +682,10 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath) if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; else - paths[D_USER_IDX] = std::string(getenv("HOME") ? getenv("HOME") : getenv("PWD")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; + paths[D_USER_IDX] = std::string(getenv("HOME") ? + getenv("HOME") : getenv("PWD") ? + getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; #endif - INFO_LOG(COMMON, "GetUserPath: Setting user directory to %s:", paths[D_USER_IDX].c_str()); paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP; paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR; @@ -731,31 +746,19 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath) bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) { - FILE *f = fopen(filename, text_file ? "w" : "wb"); - if (!f) - return false; - size_t len = str.size(); - if (len != fwrite(str.data(), 1, str.size(), f)) // TODO: string::data() may not be contiguous - { - fclose(f); - return false; - } - fclose(f); - return true; + return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); } bool ReadFileToString(bool text_file, const char *filename, std::string &str) { - FILE *f = fopen(filename, text_file ? "r" : "rb"); + File::IOFile file(filename, text_file ? "r" : "rb"); + auto const f = file.GetHandle(); + if (!f) return false; - size_t len = (size_t)GetSize(f); - char *buf = new char[len + 1]; - buf[fread(buf, 1, len, f)] = 0; - str = std::string(buf, len); - fclose(f); - delete [] buf; - return true; + + str.resize(GetSize(f)); + return file.ReadArray(&str[0], str.size()); } IOFile::IOFile() @@ -799,7 +802,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) { Close(); #ifdef _WIN32 - fopen_s(&m_file, filename.c_str(), openmode); + _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); #else m_file = fopen(filename.c_str(), openmode); #endif @@ -848,7 +851,7 @@ bool IOFile::Seek(s64 off, int origin) } u64 IOFile::Tell() -{ +{ if (IsOpen()) return ftello(m_file); else diff --git a/Source/Core/Common/Src/FileUtil.h b/Source/Core/Common/Src/FileUtil.h index 2bc55285ed..523e756307 100644 --- a/Source/Core/Common/Src/FileUtil.h +++ b/Source/Core/Common/Src/FileUtil.h @@ -25,6 +25,7 @@ #include <string.h> #include "Common.h" +#include "StringUtil.h" // User directory indices for GetUserPath enum { @@ -227,4 +228,15 @@ private: } // namespace +// To deal with Windows being dumb at unicode: +template <typename T> +void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) +{ +#ifdef _WIN32 + fstream.open(UTF8ToTStr(filename).c_str(), openmode); +#else + fstream.open(filename.c_str(), openmode); +#endif +} + #endif diff --git a/Source/Core/Common/Src/GenericFPURoundMode.cpp b/Source/Core/Common/Src/GenericFPURoundMode.cpp new file mode 100644 index 0000000000..cc878291a1 --- /dev/null +++ b/Source/Core/Common/Src/GenericFPURoundMode.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "FPURoundMode.h" + +// Generic, do nothing +namespace FPURoundMode +{ + void SetRoundMode(u32 mode) + { + } + void SetPrecisionMode(u32 mode) + { + } + void SetSIMDMode(u32 mode) + { + } + void SaveSIMDState() + { + } + void LoadSIMDState() + { + } + void LoadDefaultSIMDState() + { + } +} diff --git a/Source/Core/Common/Src/Hash.cpp b/Source/Core/Common/Src/Hash.cpp index 8e8d6f85bd..bc72b16f2a 100644 --- a/Source/Core/Common/Src/Hash.cpp +++ b/Source/Core/Common/Src/Hash.cpp @@ -119,7 +119,7 @@ u32 HashEctor(const u8* ptr, int length) inline u64 getblock(const u64 * p, int i) { - return p[i]; + return p[i]; } //---------- @@ -127,25 +127,25 @@ inline u64 getblock(const u64 * p, int i) inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2) { - k1 *= c1; - k1 = _rotl64(k1,23); - k1 *= c2; - h1 ^= k1; - h1 += h2; + k1 *= c1; + k1 = _rotl64(k1,23); + k1 *= c2; + h1 ^= k1; + h1 += h2; - h2 = _rotl64(h2,41); + h2 = _rotl64(h2,41); - k2 *= c2; - k2 = _rotl64(k2,23); - k2 *= c1; - h2 ^= k2; - h2 += h1; + k2 *= c2; + k2 = _rotl64(k2,23); + k2 *= c1; + h2 ^= k2; + h2 += h1; - h1 = h1*3+0x52dce729; - h2 = h2*3+0x38495ab5; + h1 = h1*3+0x52dce729; + h2 = h2*3+0x38495ab5; - c1 = c1*5+0x7b7d159c; - c2 = c2*5+0x6bce6396; + c1 = c1*5+0x7b7d159c; + c2 = c2*5+0x6bce6396; } //---------- @@ -153,87 +153,87 @@ inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2) inline u64 fmix64(u64 k) { - k ^= k >> 33; - k *= 0xff51afd7ed558ccd; - k ^= k >> 33; - k *= 0xc4ceb9fe1a85ec53; - k ^= k >> 33; + k ^= k >> 33; + k *= 0xff51afd7ed558ccd; + k ^= k >> 33; + k *= 0xc4ceb9fe1a85ec53; + k ^= k >> 33; - return k; + return k; } u64 GetMurmurHash3(const u8 *src, int len, u32 samples) { - const u8 * data = (const u8*)src; - const int nblocks = len / 16; + const u8 * data = (const u8*)src; + const int nblocks = len / 16; u32 Step = (len / 8); if(samples == 0) samples = max(Step, 1u); Step = Step / samples; if(Step < 1) Step = 1; - u64 h1 = 0x9368e53c2f6af274; - u64 h2 = 0x586dcd208f7cd3fd; + u64 h1 = 0x9368e53c2f6af274; + u64 h2 = 0x586dcd208f7cd3fd; - u64 c1 = 0x87c37b91114253d5; - u64 c2 = 0x4cf5ad432745937f; + u64 c1 = 0x87c37b91114253d5; + u64 c2 = 0x4cf5ad432745937f; - //---------- - // body - - const u64 * blocks = (const u64 *)(data); + //---------- + // body - for(int i = 0; i < nblocks; i+=Step) - { - u64 k1 = getblock(blocks,i*2+0); - u64 k2 = getblock(blocks,i*2+1); + const u64 * blocks = (const u64 *)(data); - bmix64(h1,h2,k1,k2,c1,c2); - } + for(int i = 0; i < nblocks; i+=Step) + { + u64 k1 = getblock(blocks,i*2+0); + u64 k2 = getblock(blocks,i*2+1); - //---------- - // tail + bmix64(h1,h2,k1,k2,c1,c2); + } - const u8 * tail = (const u8*)(data + nblocks*16); + //---------- + // tail - u64 k1 = 0; - u64 k2 = 0; + const u8 * tail = (const u8*)(data + nblocks*16); - switch(len & 15) - { - case 15: k2 ^= u64(tail[14]) << 48; - case 14: k2 ^= u64(tail[13]) << 40; - case 13: k2 ^= u64(tail[12]) << 32; - case 12: k2 ^= u64(tail[11]) << 24; - case 11: k2 ^= u64(tail[10]) << 16; - case 10: k2 ^= u64(tail[ 9]) << 8; - case 9: k2 ^= u64(tail[ 8]) << 0; + u64 k1 = 0; + u64 k2 = 0; - case 8: k1 ^= u64(tail[ 7]) << 56; - case 7: k1 ^= u64(tail[ 6]) << 48; - case 6: k1 ^= u64(tail[ 5]) << 40; - case 5: k1 ^= u64(tail[ 4]) << 32; - case 4: k1 ^= u64(tail[ 3]) << 24; - case 3: k1 ^= u64(tail[ 2]) << 16; - case 2: k1 ^= u64(tail[ 1]) << 8; - case 1: k1 ^= u64(tail[ 0]) << 0; - bmix64(h1,h2,k1,k2,c1,c2); - }; + switch(len & 15) + { + case 15: k2 ^= u64(tail[14]) << 48; + case 14: k2 ^= u64(tail[13]) << 40; + case 13: k2 ^= u64(tail[12]) << 32; + case 12: k2 ^= u64(tail[11]) << 24; + case 11: k2 ^= u64(tail[10]) << 16; + case 10: k2 ^= u64(tail[ 9]) << 8; + case 9: k2 ^= u64(tail[ 8]) << 0; + + case 8: k1 ^= u64(tail[ 7]) << 56; + case 7: k1 ^= u64(tail[ 6]) << 48; + case 6: k1 ^= u64(tail[ 5]) << 40; + case 5: k1 ^= u64(tail[ 4]) << 32; + case 4: k1 ^= u64(tail[ 3]) << 24; + case 3: k1 ^= u64(tail[ 2]) << 16; + case 2: k1 ^= u64(tail[ 1]) << 8; + case 1: k1 ^= u64(tail[ 0]) << 0; + bmix64(h1,h2,k1,k2,c1,c2); + }; - //---------- - // finalization + //---------- + // finalization - h2 ^= len; + h2 ^= len; - h1 += h2; - h2 += h1; + h1 += h2; + h2 += h1; - h1 = fmix64(h1); - h2 = fmix64(h2); + h1 = fmix64(h1); + h2 = fmix64(h2); - h1 += h2; + h1 += h2; - return h1; + return h1; } @@ -262,11 +262,13 @@ u64 GetCRC32(const u8 *src, int len, u32 samples) } -/* NOTE: This hash function is used for custom texture loading/dumping, so - it should not be changed, which would require all custom textures to be - recalculated for their new hash values. If the hashing function is - changed, make sure this one is still used when the legacy parameter is - true. */ +/* + * NOTE: This hash function is used for custom texture loading/dumping, so + * it should not be changed, which would require all custom textures to be + * recalculated for their new hash values. If the hashing function is + * changed, make sure this one is still used when the legacy parameter is + * true. + */ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) { const u64 m = 0xc6a4a7935bd1e995; @@ -282,11 +284,11 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) { u64 k = data[0]; data+=Step; - k *= m; + k *= m; k ^= k >> r; - k *= m; + k *= m; h ^= k; - h *= m; + h *= m; } const u8 * data2 = (const u8*)end; @@ -453,9 +455,11 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples) return *((u64 *)&out); } -/* FIXME: The old 32-bit version of this hash made different hashes than the - 64-bit version. Until someone can make a new version of the 32-bit one that - makes identical hashes, this is just a c/p of the 64-bit one. */ +/* + * FIXME: The old 32-bit version of this hash made different hashes than the + * 64-bit version. Until someone can make a new version of the 32-bit one that + * makes identical hashes, this is just a c/p of the 64-bit one. + */ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) { const u64 m = 0xc6a4a7935bd1e995ULL; @@ -473,7 +477,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) data+=Step; k *= m; k ^= k >> r; - k *= m; + k *= m; h ^= k; h *= m; } @@ -502,7 +506,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) u64 GetHash64(const u8 *src, int len, u32 samples) { - return ptrHashFunction(src, len, samples); + return ptrHashFunction(src, len, samples); } // sets the hash function used for the texture cache diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp index acad498106..da44855941 100644 --- a/Source/Core/Common/Src/IniFile.cpp +++ b/Source/Core/Common/Src/IniFile.cpp @@ -25,6 +25,7 @@ #include <fstream> #include <algorithm> +#include "FileUtil.h" #include "StringUtil.h" #include "IniFile.h" @@ -400,7 +401,7 @@ bool IniFile::Load(const char* filename) // Open file std::ifstream in; - in.open(filename, std::ios::in); + OpenFStream(in, filename, std::ios::in); if (in.fail()) return false; @@ -452,7 +453,7 @@ bool IniFile::Load(const char* filename) bool IniFile::Save(const char* filename) { std::ofstream out; - out.open(filename, std::ios::out); + OpenFStream(out, filename, std::ios::out); if (out.fail()) { diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h index 9755c996bd..b60c849c8e 100644 --- a/Source/Core/Common/Src/LinearDiskCache.h +++ b/Source/Core/Common/Src/LinearDiskCache.h @@ -21,11 +21,8 @@ #include "Common.h" #include <fstream> -// Increment this every time you change shader generation code. -enum -{ - LINEAR_DISKCACHE_VER = 6979 -}; +// defined in Version.cpp +extern const char *scm_rev_git_str; // On disk format: //header{ @@ -74,7 +71,7 @@ public: m_num_entries = 0; // try opening for reading/writing - m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary); + OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); m_file.seekg(0, std::ios::end); std::fstream::pos_type end_pos = m_file.tellg(); @@ -187,13 +184,15 @@ private: { Header() : id(*(u32*)"DCAC") - , ver(LINEAR_DISKCACHE_VER) , key_t_size(sizeof(K)) , value_t_size(sizeof(V)) - {} + { + memcpy(ver, scm_rev_git_str, 40); + } - const u32 id, ver; + const u32 id; const u16 key_t_size, value_t_size; + char ver[40]; } m_header; diff --git a/Source/Core/Common/Src/LogManager.cpp b/Source/Core/Common/Src/LogManager.cpp index 26db5cbfc1..d5416fcd7d 100644 --- a/Source/Core/Common/Src/LogManager.cpp +++ b/Source/Core/Common/Src/LogManager.cpp @@ -17,6 +17,9 @@ #include <algorithm> +#ifdef ANDROID +#include "Host.h" +#endif #include "LogManager.h" #include "ConsoleListener.h" #include "Timer.h" @@ -42,9 +45,9 @@ LogManager::LogManager() m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); - m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); + m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); - m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); + m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine"); m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc"); m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt"); @@ -61,15 +64,15 @@ LogManager::LogManager() m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); m_Log[LogTypes::POWERPC] = new LogContainer("PowerPC", "IBM CPU"); m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE"); - m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); - m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); - m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); - m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); - m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); + m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE"); + m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE"); + m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails"); + m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend"); + m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator"); m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "Dynamic Recompiler"); m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console"); - m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); - m_Log[LogTypes::WIIMOTE] = new LogContainer("Wiimote", "Wiimote"); + m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport"); + m_Log[LogTypes::WIIMOTE] = new LogContainer("Wiimote", "Wiimote"); m_Log[LogTypes::WII_IOB] = new LogContainer("WII_IOB", "WII IO Bridge"); m_Log[LogTypes::WII_IPC] = new LogContainer("WII_IPC", "WII IPC"); m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); @@ -83,7 +86,7 @@ LogManager::LogManager() m_Log[LogTypes::WII_IPC_WC24] = new LogContainer("WII_IPC_WC24", "WII IPC WC24"); m_Log[LogTypes::WII_IPC_SSL] = new LogContainer("WII_IPC_SSL", "WII IPC SSL"); m_Log[LogTypes::WII_IPC_WIIMOTE] = new LogContainer("WII_IPC_WIIMOTE","WII IPC WIIMOTE"); - m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); + m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); @@ -136,7 +139,9 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, Common::Timer::GetTimeFormatted().c_str(), file, line, level_to_char[(int)level], log->GetShortName(), temp); - +#ifdef ANDROID + Host_SysMessage(msg); +#endif log->Trigger(level, msg); } @@ -185,7 +190,7 @@ void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg) FileLogListener::FileLogListener(const char *filename) { - m_logfile.open(filename, std::ios::app); + OpenFStream(m_logfile, filename, std::ios::app); SetEnable(true); } diff --git a/Source/Core/Common/Src/LogManager.h b/Source/Core/Common/Src/LogManager.h index 1722c0b1bf..f7ccb15034 100644 --- a/Source/Core/Common/Src/LogManager.h +++ b/Source/Core/Common/Src/LogManager.h @@ -26,7 +26,7 @@ #include <set> #include <string.h> -#define MAX_MESSAGES 8000 +#define MAX_MESSAGES 8000 #define MAX_MSGLEN 1024 diff --git a/Source/Core/Common/Src/MathUtil.cpp b/Source/Core/Common/Src/MathUtil.cpp index e078db2e9d..d5be1c3bb1 100644 --- a/Source/Core/Common/Src/MathUtil.cpp +++ b/Source/Core/Common/Src/MathUtil.cpp @@ -21,13 +21,6 @@ #include <cmath> #include <numeric> -namespace { - -static u32 saved_sse_state = _mm_getcsr(); -static const u32 default_sse_state = _mm_getcsr(); - -} - namespace MathUtil { @@ -95,7 +88,7 @@ u32 ClassifyFloat(float fvalue) else { // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; + return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; } } else if (exp) @@ -108,43 +101,26 @@ u32 ClassifyFloat(float fvalue) //Zero return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; } - } + } } } // namespace -void LoadDefaultSSEState() -{ - _mm_setcsr(default_sse_state); -} - - -void LoadSSEState() -{ - _mm_setcsr(saved_sse_state); -} - - -void SaveSSEState() -{ - saved_sse_state = _mm_getcsr(); -} - inline void MatrixMul(int n, const float *a, const float *b, float *result) -{ - for (int i = 0; i < n; ++i) +{ + for (int i = 0; i < n; ++i) { - for (int j = 0; j < n; ++j) + for (int j = 0; j < n; ++j) { - float temp = 0; - for (int k = 0; k < n; ++k) + float temp = 0; + for (int k = 0; k < n; ++k) { - temp += a[i * n + k] * b[k * n + j]; - } - result[i * n + j] = temp; - } - } + temp += a[i * n + k] * b[k * n + j]; + } + result[i * n + j] = temp; + } + } } // Calculate sum of a float list @@ -155,94 +131,94 @@ float MathFloatVectorSum(const std::vector<float>& Vec) void Matrix33::LoadIdentity(Matrix33 &mtx) { - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[4] = 1.0f; - mtx.data[8] = 1.0f; + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[4] = 1.0f; + mtx.data[8] = 1.0f; } void Matrix33::RotateX(Matrix33 &mtx, float rad) { - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1; - mtx.data[4] = c; - mtx.data[5] = -s; - mtx.data[7] = s; - mtx.data[8] = c; + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1; + mtx.data[4] = c; + mtx.data[5] = -s; + mtx.data[7] = s; + mtx.data[8] = c; } void Matrix33::RotateY(Matrix33 &mtx, float rad) { - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = c; - mtx.data[2] = s; - mtx.data[4] = 1; - mtx.data[6] = -s; - mtx.data[8] = c; + float s = sin(rad); + float c = cos(rad); + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = c; + mtx.data[2] = s; + mtx.data[4] = 1; + mtx.data[6] = -s; + mtx.data[8] = c; } void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result) { - MatrixMul(3, a.data, b.data, result.data); + MatrixMul(3, a.data, b.data, result.data); } void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3]) { - for (int i = 0; i < 3; ++i) { - result[i] = 0; - for (int k = 0; k < 3; ++k) { - result[i] += a.data[i * 3 + k] * vec[k]; - } - } + for (int i = 0; i < 3; ++i) { + result[i] = 0; + for (int k = 0; k < 3; ++k) { + result[i] += a.data[i * 3 + k] * vec[k]; + } + } } void Matrix44::LoadIdentity(Matrix44 &mtx) { - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[5] = 1.0f; - mtx.data[10] = 1.0f; - mtx.data[15] = 1.0f; + memset(mtx.data, 0, sizeof(mtx.data)); + mtx.data[0] = 1.0f; + mtx.data[5] = 1.0f; + mtx.data[10] = 1.0f; + mtx.data[15] = 1.0f; } void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33) { - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) + for (int j = 0; j < 3; ++j) { - mtx.data[i * 4 + j] = m33.data[i * 3 + j]; - } - } + mtx.data[i * 4 + j] = m33.data[i * 3 + j]; + } + } - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { - mtx.data[i * 4 + 3] = 0; - mtx.data[i + 12] = 0; - } - mtx.data[15] = 1.0f; + mtx.data[i * 4 + 3] = 0; + mtx.data[i + 12] = 0; + } + mtx.data[15] = 1.0f; } void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16]) { - for(int i = 0; i < 16; ++i) { - mtx.data[i] = mtxArray[i]; - } + for(int i = 0; i < 16; ++i) { + mtx.data[i] = mtxArray[i]; + } } void Matrix44::Translate(Matrix44 &mtx, const float vec[3]) { - LoadIdentity(mtx); - mtx.data[3] = vec[0]; - mtx.data[7] = vec[1]; - mtx.data[11] = vec[2]; + LoadIdentity(mtx); + mtx.data[3] = vec[0]; + mtx.data[7] = vec[1]; + mtx.data[11] = vec[2]; } void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result) { - MatrixMul(4, a.data, b.data, result.data); + MatrixMul(4, a.data, b.data, result.data); } diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index a6290ff602..ccb9a95e81 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -20,8 +20,8 @@ #include "Common.h" -#include <xmmintrin.h> #include <vector> +#include "FPURoundMode.h" namespace MathUtil { @@ -117,6 +117,8 @@ struct Rectangle Rectangle(T theLeft, T theTop, T theRight, T theBottom) : left(theLeft), top(theTop), right(theRight), bottom(theBottom) { } + + bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } T GetWidth() const { return abs(right - left); } T GetHeight() const { return abs(bottom - top); } @@ -147,22 +149,32 @@ struct Rectangle inline float pow2f(float x) {return x * x;} inline double pow2(double x) {return x * x;} - -/* - There are two different flavors of float to int conversion: - _mm_cvtps_epi32() and _mm_cvttps_epi32(). The first rounds - according to the MXCSR rounding bits. The second one always - uses round towards zero. - */ - -void SaveSSEState(); -void LoadSSEState(); -void LoadDefaultSSEState(); float MathFloatVectorSum(const std::vector<float>&); #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) +// Rounds down. 0 -> undefined +inline u64 Log2(u64 val) +{ +#if defined(__GNUC__) + return 63 - __builtin_clzll(val); + +#elif defined(_MSC_VER) && defined(_M_X64) + unsigned long result = -1; + _BitScanReverse64(&result, val); + return result; + +#else + u64 result = -1; + while (val != 0) + { + val >>= 1; + ++result; + } + return result; +#endif +} // Tiny matrix/vector library. // Used for things like Free-Look in the gfx backend. @@ -170,32 +182,32 @@ float MathFloatVectorSum(const std::vector<float>&); class Matrix33 { public: - static void LoadIdentity(Matrix33 &mtx); + static void LoadIdentity(Matrix33 &mtx); - // set mtx to be a rotation matrix around the x axis - static void RotateX(Matrix33 &mtx, float rad); - // set mtx to be a rotation matrix around the y axis - static void RotateY(Matrix33 &mtx, float rad); + // set mtx to be a rotation matrix around the x axis + static void RotateX(Matrix33 &mtx, float rad); + // set mtx to be a rotation matrix around the y axis + static void RotateY(Matrix33 &mtx, float rad); - // set result = a x b - static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result); - static void Multiply(const Matrix33 &a, const float vec[3], float result[3]); + // set result = a x b + static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result); + static void Multiply(const Matrix33 &a, const float vec[3], float result[3]); - float data[9]; + float data[9]; }; class Matrix44 { public: - static void LoadIdentity(Matrix44 &mtx); - static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33); - static void Set(Matrix44 &mtx, const float mtxArray[16]); + static void LoadIdentity(Matrix44 &mtx); + static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33); + static void Set(Matrix44 &mtx, const float mtxArray[16]); - static void Translate(Matrix44 &mtx, const float vec[3]); + static void Translate(Matrix44 &mtx, const float vec[3]); - static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result); + static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result); - float data[16]; + float data[16]; }; #endif // _MATH_UTIL_H_ diff --git a/Source/Core/Common/Src/MemArena.cpp b/Source/Core/Common/Src/MemArena.cpp index 1dcdef6672..26ce81f578 100644 --- a/Source/Core/Common/Src/MemArena.cpp +++ b/Source/Core/Common/Src/MemArena.cpp @@ -27,6 +27,10 @@ #include <unistd.h> #include <cerrno> #include <cstring> +#ifdef ANDROID +#include <sys/ioctl.h> +#include <linux/ashmem.h> +#endif #endif #if defined(__APPLE__) @@ -34,11 +38,41 @@ static const char* ram_temp_file = "/tmp/gc_mem.tmp"; #elif !defined(_WIN32) // non OSX unixes static const char* ram_temp_file = "/dev/shm/gc_mem.tmp"; #endif +#ifdef ANDROID +#define ASHMEM_DEVICE "/dev/ashmem" + +int AshmemCreateFileMapping(const char *name, size_t size) +{ + int fd, ret; + fd = open(ASHMEM_DEVICE, O_RDWR); + if (fd < 0) + return fd; + + // We don't really care if we can't set the name, it is optional + ret = ioctl(fd, ASHMEM_SET_NAME, name); + + ret = ioctl(fd, ASHMEM_SET_SIZE, size); + if (ret < 0) + { + close(fd); + NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret); + return ret; + } + return fd; +} +#endif void MemArena::GrabLowMemSpace(size_t size) { #ifdef _WIN32 hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); +#elif defined(ANDROID) + fd = AshmemCreateFileMapping("Dolphin-emu", size); + if (fd < 0) + { + NOTICE_LOG(MEMMAP, "Ashmem allocation failed"); + return; + } #else mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; fd = open(ram_temp_file, O_RDWR | O_CREAT, mode); diff --git a/Source/Core/Common/Src/MemoryUtil.cpp b/Source/Core/Common/Src/MemoryUtil.cpp index 0888746d42..d788783c5a 100644 --- a/Source/Core/Common/Src/MemoryUtil.cpp +++ b/Source/Core/Common/Src/MemoryUtil.cpp @@ -117,9 +117,12 @@ void* AllocateAlignedMemory(size_t size,size_t alignment) void* ptr = _aligned_malloc(size,alignment);
#else
void* ptr = NULL;
+#ifdef ANDROID
+ ptr = memalign(alignment, size);
+#else
if (posix_memalign(&ptr, alignment, size) != 0)
ERROR_LOG(MEMMAP, "Failed to allocate aligned memory");
-;
+#endif
#endif
// printf("Mapped memory at %p (size %ld)\n", ptr,
@@ -152,9 +155,7 @@ void FreeAlignedMemory(void* ptr) if (ptr)
{
#ifdef _WIN32
-
- _aligned_free(ptr);
-
+ _aligned_free(ptr);
#else
free(ptr);
#endif
diff --git a/Source/Core/Common/Src/Misc.cpp b/Source/Core/Common/Src/Misc.cpp index aafe37886f..8364bda48d 100644 --- a/Source/Core/Common/Src/Misc.cpp +++ b/Source/Core/Common/Src/Misc.cpp @@ -31,7 +31,7 @@ const char* GetLastErrorMsg() #ifdef _WIN32 static __declspec(thread) char err_str[buff_size] = {}; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, NULL); #else diff --git a/Source/Core/Common/Src/MsgHandler.cpp b/Source/Core/Common/Src/MsgHandler.cpp index 7c666227aa..90369df1ae 100644 --- a/Source/Core/Common/Src/MsgHandler.cpp +++ b/Source/Core/Common/Src/MsgHandler.cpp @@ -102,15 +102,14 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...) bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style) { #ifdef _WIN32 - int STYLE = MB_ICONINFORMATION; - if (Style == QUESTION) STYLE = MB_ICONQUESTION; - if (Style == WARNING) STYLE = MB_ICONWARNING; - - return IDYES == MessageBox(0, text, caption, STYLE | (yes_no ? MB_YESNO : MB_OK)); - + int STYLE = MB_ICONINFORMATION; + if (Style == QUESTION) STYLE = MB_ICONQUESTION; + if (Style == WARNING) STYLE = MB_ICONWARNING; + + return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK)); #else - printf("%s\n", text); - return true; + printf("%s\n", text); + return true; #endif } diff --git a/Source/Core/Common/Src/NandPaths.cpp b/Source/Core/Common/Src/NandPaths.cpp index cec79414a7..eb0673afe0 100644 --- a/Source/Core/Common/Src/NandPaths.cpp +++ b/Source/Core/Common/Src/NandPaths.cpp @@ -86,7 +86,8 @@ bool CheckTitleTIK(u64 _titleID) static void CreateReplacementFile(std::string &filename) { - std::ofstream replace(filename.c_str()); + std::ofstream replace; + OpenFStream(replace, filename, std::ios_base::out); replace <<"\" __22__\n"; replace << "* __2a__\n"; //replace << "/ __2f__\n"; @@ -108,7 +109,8 @@ void ReadReplacements(replace_v& replacements) if (!File::Exists(filename)) CreateReplacementFile(filename); - std::ifstream f(filename.c_str()); + std::ifstream f; + OpenFStream(f, filename, std::ios_base::in); char letter; std::string replacement; diff --git a/Source/Core/Common/Src/SDCardUtil.cpp b/Source/Core/Common/Src/SDCardUtil.cpp index 0f2ad08607..cf37ffff3e 100644 --- a/Source/Core/Common/Src/SDCardUtil.cpp +++ b/Source/Core/Common/Src/SDCardUtil.cpp @@ -29,6 +29,7 @@ // Modified for Dolphin. #include "SDCardUtil.h" +#include "FileUtil.h" #include <time.h> #include <stdio.h> @@ -190,7 +191,6 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename) { u32 sectors_per_fat; u32 sectors_per_disk; - FILE* f; // Convert MB to bytes disk_size *= 1024 * 1024; @@ -207,7 +207,8 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename) boot_sector_init(s_boot_sector, s_fsinfo_sector, disk_size, nullptr); fat_init(s_fat_head); - f = fopen(filename, "wb"); + File::IOFile file(filename, "wb"); + FILE* const f = file.GetHandle(); if (!f) { ERROR_LOG(COMMON, "Could not create file '%s', aborting...\n", filename); @@ -247,13 +248,11 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename) if (write_empty(f, sectors_per_disk - RESERVED_SECTORS - 2*sectors_per_fat)) goto FailWrite; - fclose(f); return true; FailWrite: ERROR_LOG(COMMON, "Could not write to '%s', aborting...\n", filename); if (unlink(filename) < 0) ERROR_LOG(COMMON, "unlink(%s) failed\n%s", filename, GetLastErrorMsg()); - fclose(f); return false; } diff --git a/Source/Core/Common/Src/StdConditionVariable.h b/Source/Core/Common/Src/StdConditionVariable.h index 1b81766ee0..6530712c8f 100644 --- a/Source/Core/Common/Src/StdConditionVariable.h +++ b/Source/Core/Common/Src/StdConditionVariable.h @@ -5,7 +5,7 @@ #define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) #define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID // GCC 4.4 provides <condition_variable> #include <condition_variable> #else @@ -133,7 +133,7 @@ public: // bool wait_for(unique_lock<mutex>& lock, // const chrono::duration<Rep, Period>& rel_time, // Predicate pred); - + native_handle_type native_handle() { #ifdef USE_EVENTS diff --git a/Source/Core/Common/Src/StdMutex.h b/Source/Core/Common/Src/StdMutex.h index 8949e905ac..8a5d22f928 100644 --- a/Source/Core/Common/Src/StdMutex.h +++ b/Source/Core/Common/Src/StdMutex.h @@ -5,7 +5,7 @@ #define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) #define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID // GCC 4.4 provides <mutex> #include <mutex> #else diff --git a/Source/Core/Common/Src/StdThread.h b/Source/Core/Common/Src/StdThread.h index fea058c874..8893c36204 100644 --- a/Source/Core/Common/Src/StdThread.h +++ b/Source/Core/Common/Src/StdThread.h @@ -5,7 +5,7 @@ #define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) #define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ +#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID // GCC 4.4 provides <thread> #ifndef _GLIBCXX_USE_SCHED_YIELD #define _GLIBCXX_USE_SCHED_YIELD @@ -88,7 +88,7 @@ public: { return !(*this == rhs); } - + bool operator<(const id& rhs) const { return m_thread < rhs.m_thread; diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index e5c70b2c6b..43c4aebf12 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -17,11 +17,21 @@ #include <stdlib.h> #include <stdio.h> +#include <algorithm> #include "Common.h" #include "CommonPaths.h" #include "StringUtil.h" +#ifdef _WIN32 + #include <Windows.h> +#elif defined(ANDROID) + +#else + #include <iconv.h> + #include <errno.h> +#endif + // faster than sscanf bool AsciiToHex(const char* _szValue, u32& result) { @@ -263,25 +273,25 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st const char HEX2DEC[256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - /* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, - - /* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - - /* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - - /* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - /* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 + /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 1 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 2 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,16,16, 16,16,16,16, + + /* 4 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16, + /* 5 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 6 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16, + /* 7 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + + /* 8 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* 9 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* A */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* B */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + + /* C */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* D */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* E */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, + /* F */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16 }; std::string UriDecode(const std::string & sSrc) @@ -303,8 +313,8 @@ std::string UriDecode(const std::string & sSrc) if (*pSrc == '%') { char dec1, dec2; - if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)]) - && -1 != (dec2 = HEX2DEC[*(pSrc + 2)])) + if (16 != (dec1 = HEX2DEC[*(pSrc + 1)]) + && 16 != (dec2 = HEX2DEC[*(pSrc + 2)])) { *pEnd++ = (dec1 << 4) + dec2; pSrc += 3; @@ -375,3 +385,137 @@ std::string UriEncode(const std::string & sSrc) delete [] pStart; return sResult; } + +#ifdef _WIN32 + +std::string UTF16ToUTF8(const std::wstring& input) +{ + auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); + + std::string output; + output.resize(size); + + if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) + output.clear(); + + return output; +} + +std::wstring CPToUTF16(u32 code_page, const std::string& input) +{ + auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); + + std::wstring output; + output.resize(size); + + if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size())) + output.clear(); + + return output; +} + +std::wstring UTF8ToUTF16(const std::string& input) +{ + return CPToUTF16(CP_UTF8, input); +} + +std::string SHIFTJISToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(932, input)); +} + +std::string CP1252ToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(1252, input)); +} + +#else + +template <typename T> +std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) +{ + std::string result; + +#if defined(ANDROID) + result = "Not implemented on Android!"; + +#else + iconv_t const conv_desc = iconv_open("UTF-8", fromcode); + if ((iconv_t)-1 == conv_desc) + { + ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); + } + else + { + size_t const in_bytes = sizeof(T) * input.size(); + size_t const out_buffer_size = 4 * in_bytes; + + std::string out_buffer; + out_buffer.resize(out_buffer_size); + + auto src_buffer = &input[0]; + size_t src_bytes = in_bytes; + auto dst_buffer = &out_buffer[0]; + size_t dst_bytes = out_buffer.size(); + + while (src_bytes != 0) + { + size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, + &dst_buffer, &dst_bytes); + + if ((size_t)-1 == iconv_result) + { + if (EILSEQ == errno || EINVAL == errno) + { + // Try to skip the bad character + if (src_bytes != 0) + { + --src_bytes; + ++src_buffer; + } + } + else + { + ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); + break; + } + } + } + + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); + + iconv_close(conv_desc); + } + +#endif + return result; +} + +std::string CP1252ToUTF8(const std::string& input) +{ + //return CodeToUTF8("CP1252//TRANSLIT", input); + //return CodeToUTF8("CP1252//IGNORE", input); + return CodeToUTF8("CP1252", input); +} + +std::string SHIFTJISToUTF8(const std::string& input) +{ + //return CodeToUTF8("CP932", input); + return CodeToUTF8("SJIS", input); +} + +std::string UTF16ToUTF8(const std::wstring& input) +{ + std::string result = + // CodeToUTF8("UCS-2", input); + // CodeToUTF8("UCS-2LE", input); + // CodeToUTF8("UTF-16", input); + CodeToUTF8("UTF-16LE", input); + + // TODO: why is this needed? + result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); + return result; +} + +#endif diff --git a/Source/Core/Common/Src/StringUtil.h b/Source/Core/Common/Src/StringUtil.h index 102ae2d5fb..9463db5bb1 100644 --- a/Source/Core/Common/Src/StringUtil.h +++ b/Source/Core/Common/Src/StringUtil.h @@ -97,4 +97,28 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st std::string UriDecode(const std::string & sSrc); std::string UriEncode(const std::string & sSrc); +std::string CP1252ToUTF8(const std::string& str); +std::string SHIFTJISToUTF8(const std::string& str); +std::string UTF16ToUTF8(const std::wstring& str); + +#ifdef _WIN32 + +std::wstring UTF8ToUTF16(const std::string& str); + +#ifdef _UNICODE +inline std::string TStrToUTF8(const std::wstring& str) +{ return UTF16ToUTF8(str); } + +inline std::wstring UTF8ToTStr(const std::string& str) +{ return UTF8ToUTF16(str); } +#else +inline std::string TStrToUTF8(const std::string& str) +{ return str; } + +inline std::string UTF8ToTStr(const std::string& str) +{ return str; } +#endif + +#endif + #endif // _STRINGUTIL_H_ diff --git a/Source/Core/Common/Src/Thread.cpp b/Source/Core/Common/Src/Thread.cpp index 73f83c204f..3e8440b74f 100644 --- a/Source/Core/Common/Src/Thread.cpp +++ b/Source/Core/Common/Src/Thread.cpp @@ -105,7 +105,7 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) #ifdef __APPLE__ thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1); -#elif defined __linux__ || defined BSD4_4 +#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID) cpu_set_t cpu_set; CPU_ZERO(&cpu_set); diff --git a/Source/Core/Common/Src/Thread.h b/Source/Core/Common/Src/Thread.h index e711fcab5c..b5f899c43b 100644 --- a/Source/Core/Common/Src/Thread.h +++ b/Source/Core/Common/Src/Thread.h @@ -33,8 +33,6 @@ #define INFINITE 0xffffffff #endif -#include <xmmintrin.h> - //for gettimeofday and struct time(spec|val) #include <time.h> #include <sys/time.h> @@ -64,7 +62,7 @@ public: m_condvar.notify_one(); } } - + void Wait() { std::unique_lock<std::mutex> lk(m_mutex); diff --git a/Source/Core/Common/Src/Version.cpp b/Source/Core/Common/Src/Version.cpp index 97e232785d..a668d24e1b 100644 --- a/Source/Core/Common/Src/Version.cpp +++ b/Source/Core/Common/Src/Version.cpp @@ -50,3 +50,5 @@ const char *netplay_dolphin_ver = SCM_DESC_STR " M" NP_ARCH; #else const char *netplay_dolphin_ver = SCM_DESC_STR " L" NP_ARCH; #endif + +const char *scm_rev_git_str = SCM_REV_STR; diff --git a/Source/Core/Common/Src/VideoBackendBase.cpp b/Source/Core/Common/Src/VideoBackendBase.cpp index 62bb42997f..a5aa572039 100644 --- a/Source/Core/Common/Src/VideoBackendBase.cpp +++ b/Source/Core/Common/Src/VideoBackendBase.cpp @@ -29,6 +29,7 @@ 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 @@ -49,17 +50,27 @@ static bool IsGteVista() void VideoBackend::PopulateList() { + VideoBackend* backends[4] = { NULL }; + + // D3D11 > OGL > D3D9 > SW #ifdef _WIN32 - g_available_video_backends.push_back(new DX9::VideoBackend); + g_available_video_backends.push_back(backends[2] = new DX9::VideoBackend); if (IsGteVista()) - g_available_video_backends.push_back(new DX11::VideoBackend); + g_available_video_backends.push_back(backends[0] = new DX11::VideoBackend); #endif #ifndef USE_GLES - g_available_video_backends.push_back(new OGL::VideoBackend); + g_available_video_backends.push_back(backends[1] = new OGL::VideoBackend); #endif - g_available_video_backends.push_back(new SW::VideoSoftware); + g_available_video_backends.push_back(backends[3] = new SW::VideoSoftware); - g_video_backend = g_available_video_backends.front(); + for (int i = 0; i < 4; ++i) + { + if (backends[i]) + { + s_default_backend = g_video_backend = backends[i]; + break; + } + } } void VideoBackend::ClearList() @@ -73,8 +84,8 @@ void VideoBackend::ClearList() void VideoBackend::ActivateBackend(const std::string& name) { - if (name.length() == 0) // If NULL, set it to the first one in the list. Expected behavior - g_video_backend = g_available_video_backends.front(); + 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()) diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h index 311fa66104..c4455b3234 100644 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ b/Source/Core/Common/Src/VideoBackendBase.h @@ -22,6 +22,7 @@ #include <vector> #include "ChunkFile.h" +#include "../../VideoCommon/Src/PerfQueryBase.h" typedef void (*writeFn16)(const u16,const u32); typedef void (*writeFn32)(const u32,const u32); @@ -96,17 +97,20 @@ public: 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; @@ -156,8 +160,10 @@ class VideoBackendHardware : public VideoBackend void Video_ExitLoop(); void Video_BeginField(u32, FieldType, u32, u32); void Video_EndField(); - u32 Video_AccessEFB(EFBAccessType, u32, u32, u32); + 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); diff --git a/Source/Core/Common/Src/ABI.cpp b/Source/Core/Common/Src/x64ABI.cpp index 63a8e76934..468d02d9b9 100644 --- a/Source/Core/Common/Src/ABI.cpp +++ b/Source/Core/Common/Src/x64ABI.cpp @@ -17,7 +17,7 @@ #include "Common.h" #include "x64Emitter.h" -#include "ABI.h" +#include "x64ABI.h" using namespace Gen; @@ -226,11 +226,11 @@ void XEmitter::ABI_CallFunction(void *func) { u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -239,11 +239,11 @@ void XEmitter::ABI_CallFunctionC16(void *func, u16 param1) { u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -266,11 +266,11 @@ void XEmitter::ABI_CallFunctionC(void *func, u32 param1) { u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -280,11 +280,11 @@ void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) { u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -295,11 +295,11 @@ void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -310,11 +310,11 @@ void XEmitter::ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *par u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -326,11 +326,11 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 para u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -341,11 +341,11 @@ void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 p u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -356,11 +356,11 @@ void XEmitter::ABI_CallFunctionR(void *func, X64Reg reg1) { u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -380,11 +380,11 @@ void XEmitter::ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) { u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -396,11 +396,11 @@ void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2 u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } @@ -411,11 +411,11 @@ void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1) u64 distance = u64(func) - (u64(code) + 5); if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { - // Far call - MOV(64, R(RAX), Imm64((u64)func)); - CALLptr(R(RAX)); + // Far call + MOV(64, R(RAX), Imm64((u64)func)); + CALLptr(R(RAX)); } else { - CALL(func); + CALL(func); } } diff --git a/Source/Core/Common/Src/ABI.h b/Source/Core/Common/Src/x64ABI.h index 7226870e58..7226870e58 100644 --- a/Source/Core/Common/Src/ABI.h +++ b/Source/Core/Common/Src/x64ABI.h diff --git a/Source/Core/Common/Src/x64Analyzer.cpp b/Source/Core/Common/Src/x64Analyzer.cpp index 66a2fe217f..37a9030a4b 100644 --- a/Source/Core/Common/Src/x64Analyzer.cpp +++ b/Source/Core/Common/Src/x64Analyzer.cpp @@ -60,18 +60,18 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc codeByte = *codePtr++; - // Skip two-byte opcode byte - bool twoByte = false; - if(codeByte == 0x0F) - { - twoByte = true; + // Skip two-byte opcode byte + bool twoByte = false; + if(codeByte == 0x0F) + { + twoByte = true; codeByte2 = *codePtr++; - } + } if (!twoByte) { - if ((codeByte & 0xF0) == 0x80 || - ((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02)) + if ((codeByte & 0xF0) == 0x80 || + ((codeByte & 0xF8) == 0xC0 && (codeByte & 0x0E) != 0x02)) { modRMbyte = *codePtr++; hasModRM = true; @@ -79,20 +79,20 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc } else { - if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) || - (codeByte2 & 0xF0) == 0x30 || - codeByte2 == 0x77 || - (codeByte2 & 0xF0) == 0x80 || - ((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) || - (codeByte2 & 0xF8) == 0xC8) - { - // No mod R/M byte - } - else - { + if (((codeByte2 & 0xF0) == 0x00 && (codeByte2 & 0x0F) >= 0x04 && (codeByte2 & 0x0D) != 0x0D) || + (codeByte2 & 0xF0) == 0x30 || + codeByte2 == 0x77 || + (codeByte2 & 0xF0) == 0x80 || + ((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) || + (codeByte2 & 0xF8) == 0xC8) + { + // No mod R/M byte + } + else + { modRMbyte = *codePtr++; hasModRM = true; - } + } } if (hasModRM) @@ -130,7 +130,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc info.displacement = *((s32 *)codePtr); codePtr += displacementSize; - + if (accessType == 1) { info.isMemoryWrite = true; diff --git a/Source/Core/Common/Src/x64Analyzer.h b/Source/Core/Common/Src/x64Analyzer.h index 8b13ca94aa..e9676ec250 100644 --- a/Source/Core/Common/Src/x64Analyzer.h +++ b/Source/Core/Common/Src/x64Analyzer.h @@ -51,7 +51,7 @@ enum{ MOVZX_SHORT = 0xB7, //movzx on short MOVSX_BYTE = 0xBE, //movsx on byte MOVSX_SHORT = 0xBF, //movsx on short - MOVE_8BIT = 0xC6, //move 8-bit immediate + MOVE_8BIT = 0xC6, //move 8-bit immediate MOVE_16_32BIT = 0xC7, //move 16 or 32-bit immediate MOVE_REG_TO_MEM = 0x89, //move reg to memory }; diff --git a/Source/Core/Common/Src/CPUDetect.cpp b/Source/Core/Common/Src/x64CPUDetect.cpp index 282929e7b2..dcde313630 100644 --- a/Source/Core/Common/Src/CPUDetect.cpp +++ b/Source/Core/Common/Src/x64CPUDetect.cpp @@ -30,16 +30,20 @@ #else //#include <config/i386/cpuid.h> +#ifndef _M_GENERIC #include <xmmintrin.h> +#endif #if defined __FreeBSD__ #include <sys/types.h> #include <machine/cpufunc.h> #else static inline void do_cpuid(unsigned int *eax, unsigned int *ebx, - unsigned int *ecx, unsigned int *edx) + unsigned int *ecx, unsigned int *edx) { -#ifdef _LP64 +#if defined _M_GENERIC + (*eax) = (*ebx) = (*ecx) = (*edx) = 0; +#elif defined _LP64 // Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to // restored at the end of the asm block. __asm__ ( diff --git a/Source/Core/Common/Src/x64Emitter.cpp b/Source/Core/Common/Src/x64Emitter.cpp index 5f8d0a66f1..1a74eaef80 100644 --- a/Source/Core/Common/Src/x64Emitter.cpp +++ b/Source/Core/Common/Src/x64Emitter.cpp @@ -17,7 +17,7 @@ #include "Common.h" #include "x64Emitter.h" -#include "ABI.h" +#include "x64ABI.h" #include "CPUDetect.h" namespace Gen @@ -51,13 +51,13 @@ static const NormalOpDef nops[11] = enum NormalSSEOps { - sseCMP = 0xC2, - sseADD = 0x58, //ADD + sseCMP = 0xC2, + sseADD = 0x58, //ADD sseSUB = 0x5C, //SUB sseAND = 0x54, //AND sseANDN = 0x55, //ANDN - sseOR = 0x56, - sseXOR = 0x57, + sseOR = 0x56, + sseXOR = 0x57, sseMUL = 0x59, //MUL, sseDIV = 0x5E, //DIV sseMIN = 0x5D, //MIN @@ -143,18 +143,18 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const if (indexReg & 8) op |= 2; if (offsetOrBaseReg & 8) op |= 1; //TODO investigate if this is dangerous if (op != 0x40 || - (bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || - (opBits == 8 && (customOp & 0x10c) == 4)) { + (bits == 8 && (offsetOrBaseReg & 0x10c) == 4) || + (opBits == 8 && (customOp & 0x10c) == 4)) { emit->Write8(op); _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x100) == 0 || bits != 8); _dbg_assert_(DYNA_REC, (customOp & 0x100) == 0 || opBits != 8); } else { _dbg_assert_(DYNA_REC, (offsetOrBaseReg & 0x10c) == 0 || - (offsetOrBaseReg & 0x10c) == 0x104 || - bits != 8); + (offsetOrBaseReg & 0x10c) == 0x104 || + bits != 8); _dbg_assert_(DYNA_REC, (customOp & 0x10c) == 0 || - (customOp & 0x10c) == 0x104 || - opBits != 8); + (customOp & 0x10c) == 0x104 || + opBits != 8); } #else @@ -969,15 +969,15 @@ void OpArg::WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &o immToWrite = 8; } else if ((operand.scale == SCALE_IMM16 && bits == 16) || - (operand.scale == SCALE_IMM32 && bits == 32) || - (operand.scale == SCALE_IMM32 && bits == 64)) + (operand.scale == SCALE_IMM32 && bits == 32) || + (operand.scale == SCALE_IMM32 && bits == 64)) { emit->Write8(nops[op].imm32); immToWrite = bits == 16 ? 16 : 32; } else if ((operand.scale == SCALE_IMM8 && bits == 16) || - (operand.scale == SCALE_IMM8 && bits == 32) || - (operand.scale == SCALE_IMM8 && bits == 64)) + (operand.scale == SCALE_IMM8 && bits == 32) || + (operand.scale == SCALE_IMM8 && bits == 64)) { emit->Write8(nops[op].simm8); immToWrite = 8; @@ -1471,142 +1471,142 @@ void XEmitter::RTDSC() { Write8(0x0F); Write8(0x31); } // helper routines for setting pointers void XEmitter::CallCdeclFunction3(void* fnptr, u32 arg0, u32 arg1, u32 arg2) { - using namespace Gen; + using namespace Gen; #ifdef _M_X64 #ifdef _MSC_VER - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - CALL(fnptr); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + CALL(fnptr); #else - MOV(32, R(RDI), Imm32(arg0)); - MOV(32, R(RSI), Imm32(arg1)); - MOV(32, R(RDX), Imm32(arg2)); - CALL(fnptr); + MOV(32, R(RDI), Imm32(arg0)); + MOV(32, R(RSI), Imm32(arg1)); + MOV(32, R(RDX), Imm32(arg2)); + CALL(fnptr); #endif #else - ABI_AlignStack(3 * 4); - PUSH(32, Imm32(arg2)); - PUSH(32, Imm32(arg1)); - PUSH(32, Imm32(arg0)); - CALL(fnptr); + ABI_AlignStack(3 * 4); + PUSH(32, Imm32(arg2)); + PUSH(32, Imm32(arg1)); + PUSH(32, Imm32(arg0)); + CALL(fnptr); #ifdef _WIN32 - // don't inc stack + // don't inc stack #else - ABI_RestoreStack(3 * 4); + ABI_RestoreStack(3 * 4); #endif #endif } void XEmitter::CallCdeclFunction4(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3) { - using namespace Gen; + using namespace Gen; #ifdef _M_X64 #ifdef _MSC_VER - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - MOV(32, R(R9), Imm32(arg3)); - CALL(fnptr); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(R9), Imm32(arg3)); + CALL(fnptr); #else - MOV(32, R(RDI), Imm32(arg0)); - MOV(32, R(RSI), Imm32(arg1)); - MOV(32, R(RDX), Imm32(arg2)); - MOV(32, R(RCX), Imm32(arg3)); - CALL(fnptr); + MOV(32, R(RDI), Imm32(arg0)); + MOV(32, R(RSI), Imm32(arg1)); + MOV(32, R(RDX), Imm32(arg2)); + MOV(32, R(RCX), Imm32(arg3)); + CALL(fnptr); #endif #else - ABI_AlignStack(4 * 4); - PUSH(32, Imm32(arg3)); - PUSH(32, Imm32(arg2)); - PUSH(32, Imm32(arg1)); - PUSH(32, Imm32(arg0)); - CALL(fnptr); + ABI_AlignStack(4 * 4); + PUSH(32, Imm32(arg3)); + PUSH(32, Imm32(arg2)); + PUSH(32, Imm32(arg1)); + PUSH(32, Imm32(arg0)); + CALL(fnptr); #ifdef _WIN32 - // don't inc stack + // don't inc stack #else - ABI_RestoreStack(4 * 4); + ABI_RestoreStack(4 * 4); #endif #endif } void XEmitter::CallCdeclFunction5(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { - using namespace Gen; + using namespace Gen; #ifdef _M_X64 #ifdef _MSC_VER - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - MOV(32, R(R9), Imm32(arg3)); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(R9), Imm32(arg3)); MOV(32, MDisp(RSP, 0x20), Imm32(arg4)); - CALL(fnptr); + CALL(fnptr); #else - MOV(32, R(RDI), Imm32(arg0)); - MOV(32, R(RSI), Imm32(arg1)); - MOV(32, R(RDX), Imm32(arg2)); - MOV(32, R(RCX), Imm32(arg3)); - MOV(32, R(R8), Imm32(arg4)); - CALL(fnptr); + MOV(32, R(RDI), Imm32(arg0)); + MOV(32, R(RSI), Imm32(arg1)); + MOV(32, R(RDX), Imm32(arg2)); + MOV(32, R(RCX), Imm32(arg3)); + MOV(32, R(R8), Imm32(arg4)); + CALL(fnptr); #endif #else - ABI_AlignStack(5 * 4); - PUSH(32, Imm32(arg4)); - PUSH(32, Imm32(arg3)); - PUSH(32, Imm32(arg2)); - PUSH(32, Imm32(arg1)); - PUSH(32, Imm32(arg0)); - CALL(fnptr); + ABI_AlignStack(5 * 4); + PUSH(32, Imm32(arg4)); + PUSH(32, Imm32(arg3)); + PUSH(32, Imm32(arg2)); + PUSH(32, Imm32(arg1)); + PUSH(32, Imm32(arg0)); + CALL(fnptr); #ifdef _WIN32 - // don't inc stack + // don't inc stack #else - ABI_RestoreStack(5 * 4); + ABI_RestoreStack(5 * 4); #endif #endif } void XEmitter::CallCdeclFunction6(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5) { - using namespace Gen; + using namespace Gen; #ifdef _M_X64 #ifdef _MSC_VER - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - MOV(32, R(R9), Imm32(arg3)); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(R9), Imm32(arg3)); MOV(32, MDisp(RSP, 0x20), Imm32(arg4)); MOV(32, MDisp(RSP, 0x28), Imm32(arg5)); - CALL(fnptr); + CALL(fnptr); #else - MOV(32, R(RDI), Imm32(arg0)); - MOV(32, R(RSI), Imm32(arg1)); - MOV(32, R(RDX), Imm32(arg2)); - MOV(32, R(RCX), Imm32(arg3)); - MOV(32, R(R8), Imm32(arg4)); - MOV(32, R(R9), Imm32(arg5)); - CALL(fnptr); + MOV(32, R(RDI), Imm32(arg0)); + MOV(32, R(RSI), Imm32(arg1)); + MOV(32, R(RDX), Imm32(arg2)); + MOV(32, R(RCX), Imm32(arg3)); + MOV(32, R(R8), Imm32(arg4)); + MOV(32, R(R9), Imm32(arg5)); + CALL(fnptr); #endif #else - ABI_AlignStack(6 * 4); - PUSH(32, Imm32(arg5)); - PUSH(32, Imm32(arg4)); - PUSH(32, Imm32(arg3)); - PUSH(32, Imm32(arg2)); - PUSH(32, Imm32(arg1)); - PUSH(32, Imm32(arg0)); - CALL(fnptr); + ABI_AlignStack(6 * 4); + PUSH(32, Imm32(arg5)); + PUSH(32, Imm32(arg4)); + PUSH(32, Imm32(arg3)); + PUSH(32, Imm32(arg2)); + PUSH(32, Imm32(arg1)); + PUSH(32, Imm32(arg0)); + CALL(fnptr); #ifdef _WIN32 - // don't inc stack + // don't inc stack #else - ABI_RestoreStack(6 * 4); + ABI_RestoreStack(6 * 4); #endif #endif } @@ -1615,31 +1615,31 @@ void XEmitter::CallCdeclFunction6(void* fnptr, u32 arg0, u32 arg1, u32 arg2, u32 // See header void XEmitter::___CallCdeclImport3(void* impptr, u32 arg0, u32 arg1, u32 arg2) { - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); CALLptr(M(impptr)); } void XEmitter::___CallCdeclImport4(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3) { - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - MOV(32, R(R9), Imm32(arg3)); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(R9), Imm32(arg3)); CALLptr(M(impptr)); } void XEmitter::___CallCdeclImport5(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - MOV(32, R(R9), Imm32(arg3)); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(R9), Imm32(arg3)); MOV(32, MDisp(RSP, 0x20), Imm32(arg4)); CALLptr(M(impptr)); } void XEmitter::___CallCdeclImport6(void* impptr, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 arg5) { - MOV(32, R(RCX), Imm32(arg0)); - MOV(32, R(RDX), Imm32(arg1)); - MOV(32, R(R8), Imm32(arg2)); - MOV(32, R(R9), Imm32(arg3)); + MOV(32, R(RCX), Imm32(arg0)); + MOV(32, R(RDX), Imm32(arg1)); + MOV(32, R(R8), Imm32(arg2)); + MOV(32, R(R9), Imm32(arg3)); MOV(32, MDisp(RSP, 0x20), Imm32(arg4)); MOV(32, MDisp(RSP, 0x28), Imm32(arg5)); CALLptr(M(impptr)); diff --git a/Source/Core/Common/Src/x64Emitter.h b/Source/Core/Common/Src/x64Emitter.h index 3b699c81a0..97ba080790 100644 --- a/Source/Core/Common/Src/x64Emitter.h +++ b/Source/Core/Common/Src/x64Emitter.h @@ -757,7 +757,7 @@ public: region_size = 0; } - bool IsInCodeSpace(u8 *ptr) + bool IsInSpace(u8 *ptr) { return ptr >= region && ptr < region + region_size; } @@ -766,7 +766,7 @@ 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 ResetCodePtr() diff --git a/Source/Core/Common/Src/x64FPURoundMode.cpp b/Source/Core/Common/Src/x64FPURoundMode.cpp new file mode 100644 index 0000000000..41363f7999 --- /dev/null +++ b/Source/Core/Common/Src/x64FPURoundMode.cpp @@ -0,0 +1,120 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "Common.h" +#include "FPURoundMode.h" + +#ifndef _WIN32 +static const unsigned short FPU_ROUND_NEAR = 0 << 10; +static const unsigned short FPU_ROUND_DOWN = 1 << 10; +static const unsigned short FPU_ROUND_UP = 2 << 10; +static const unsigned short FPU_ROUND_CHOP = 3 << 10; +static const unsigned short FPU_ROUND_MASK = 3 << 10; +#include <xmmintrin.h> +#endif + +const u32 MASKS = 0x1F80; // mask away the interrupts. +const u32 DAZ = 0x40; +const u32 FTZ = 0x8000; + +namespace FPURoundMode +{ + // Get the default SSE states here. + static u32 saved_sse_state = _mm_getcsr(); + static const u32 default_sse_state = _mm_getcsr(); + + void SetRoundMode(u32 mode) + { + // Set FPU rounding mode to mimic the PowerPC's + #ifdef _M_IX86 + // This shouldn't really be needed anymore since we use SSE + #ifdef _WIN32 + const int table[4] = + { + _RC_NEAR, + _RC_CHOP, + _RC_UP, + _RC_DOWN + }; + _set_controlfp(_MCW_RC, table[mode]); + #else + const unsigned short table[4] = + { + FPU_ROUND_NEAR, + FPU_ROUND_CHOP, + FPU_ROUND_UP, + FPU_ROUND_DOWN + }; + unsigned short _mode; + asm ("fstcw %0" : "=m" (_mode) : ); + _mode = (_mode & ~FPU_ROUND_MASK) | table[mode]; + asm ("fldcw %0" : : "m" (_mode)); + #endif + #endif + } + + void SetPrecisionMode(u32 mode) + { + #ifdef _M_IX86 + // sets the floating-point lib to 53-bit + // PowerPC has a 53bit floating pipeline only + // eg: sscanf is very sensitive + #ifdef _WIN32 + _control87(_PC_53, MCW_PC); + #else + const unsigned short table[4] = { + 0 << 8, // FPU_PREC_24 + 2 << 8, // FPU_PREC_53 + 3 << 8, // FPU_PREC_64 + 3 << 8, // FPU_PREC_MASK + }; + unsigned short _mode; + asm ("fstcw %0" : : "m" (_mode)); + _mode = (_mode & ~table[3]) | table[mode]; + asm ("fldcw %0" : : "m" (_mode)); + #endif + #else + //x64 doesn't need this - fpu is done with SSE + //but still - set any useful sse options here + #endif + } + void SetSIMDMode(u32 mode) + { + static const u32 ssetable[4] = + { + (0 << 13) | MASKS, + (3 << 13) | MASKS, + (2 << 13) | MASKS, + (1 << 13) | MASKS, + }; + u32 csr = ssetable[mode]; + _mm_setcsr(csr); + } + + void SaveSIMDState() + { + saved_sse_state = _mm_getcsr(); + } + void LoadSIMDState() + { + _mm_setcsr(saved_sse_state); + } + void LoadDefaultSIMDState() + { + _mm_setcsr(default_sse_state); + } +} diff --git a/Source/Core/Common/Src/Thunk.cpp b/Source/Core/Common/Src/x64Thunk.cpp index 1792df3e77..b9fd54f354 100644 --- a/Source/Core/Common/Src/Thunk.cpp +++ b/Source/Core/Common/Src/x64Thunk.cpp @@ -18,9 +18,8 @@ #include <map> #include "Common.h" -#include "x64Emitter.h" #include "MemoryUtil.h" -#include "ABI.h" +#include "x64ABI.h" #include "Thunk.h" #define THUNK_ARENA_SIZE 1024*1024*1 |
