160 changes: 160 additions & 0 deletions Source/Core/Common/Src/ArmCPUDetect.cpp
@@ -0,0 +1,160 @@
// 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"

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 *fp;

fp = fopen(procfile, "r");
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 *fp;

fp = fopen(procfile, "r");
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 *fp;

fp = fopen(procfile, "r");
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");
// 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;
}
967 changes: 967 additions & 0 deletions Source/Core/Common/Src/ArmEmitter.cpp

Large diffs are not rendered by default.

587 changes: 587 additions & 0 deletions Source/Core/Common/Src/ArmEmitter.h

Large diffs are not rendered by default.

23 changes: 22 additions & 1 deletion Source/Core/Common/Src/CPUDetect.h
Expand Up @@ -25,7 +25,8 @@ enum CPUVendor
{
VENDOR_INTEL = 0,
VENDOR_AMD = 1,
VENDOR_OTHER = 2,
VENDOR_ARM = 2,
VENDOR_OTHER = 3,
};

struct CPUInfo
Expand Down Expand Up @@ -55,6 +56,26 @@ struct CPUInfo
bool bAES;
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();
Expand Down
6 changes: 4 additions & 2 deletions Source/Core/Common/Src/Common.h
Expand Up @@ -133,7 +133,9 @@ class NonCopyable
// 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__
Expand All @@ -144,7 +146,7 @@ class NonCopyable
# 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.
Expand Down
14 changes: 12 additions & 2 deletions Source/Core/Common/Src/CommonFuncs.h
Expand Up @@ -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)
Expand All @@ -60,6 +60,8 @@ _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
Expand Down Expand Up @@ -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);}
Expand All @@ -161,7 +172,6 @@ inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 3
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);}

} // Namespace Common

#endif // _COMMONFUNCS_H_
5 changes: 5 additions & 0 deletions Source/Core/Common/Src/CommonPaths.h
Expand Up @@ -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
Expand All @@ -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"
Expand Down
51 changes: 51 additions & 0 deletions Source/Core/Common/Src/FPURoundMode.h
@@ -0,0 +1,51 @@
// 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
5 changes: 3 additions & 2 deletions Source/Core/Common/Src/FileUtil.cpp
Expand Up @@ -668,9 +668,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;
Expand Down
41 changes: 41 additions & 0 deletions 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()
{
}
}
7 changes: 6 additions & 1 deletion Source/Core/Common/Src/LogManager.cpp
Expand Up @@ -17,6 +17,9 @@

#include <algorithm>

#ifdef ANDROID
#include "Host.h"
#endif
#include "LogManager.h"
#include "ConsoleListener.h"
#include "Timer.h"
Expand Down Expand Up @@ -132,7 +135,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);
}

Expand Down
24 changes: 0 additions & 24 deletions Source/Core/Common/Src/MathUtil.cpp
Expand Up @@ -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
{

Expand Down Expand Up @@ -114,23 +107,6 @@ u32 ClassifyFloat(float fvalue)

} // 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)
Expand Down
13 changes: 1 addition & 12 deletions Source/Core/Common/Src/MathUtil.h
Expand Up @@ -20,8 +20,8 @@

#include "Common.h"

#include <xmmintrin.h>
#include <vector>
#include "FPURoundMode.h"

namespace MathUtil
{
Expand Down Expand Up @@ -147,17 +147,6 @@ 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))
Expand Down
34 changes: 34 additions & 0 deletions Source/Core/Common/Src/MemArena.cpp
Expand Up @@ -27,18 +27,52 @@
#include <unistd.h>
#include <cerrno>
#include <cstring>
#ifdef ANDROID
#include <sys/ioctl.h>
#include <linux/ashmem.h>
#endif
#endif

#if defined(__APPLE__)
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);
Expand Down
5 changes: 4 additions & 1 deletion Source/Core/Common/Src/MemoryUtil.cpp
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Common/Src/StdConditionVariable.h
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Common/Src/StdMutex.h
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Common/Src/StdThread.h
Expand Up @@ -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
Expand Down
44 changes: 22 additions & 22 deletions Source/Core/Common/Src/StringUtil.cpp
Expand Up @@ -245,7 +245,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
while(1)
{
const int pos = result.find(src);
if (pos == -1) break;
if (pos == 16) break;
result.replace(pos, src.size(), dest);
}
return result;
Expand All @@ -263,25 +263,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)
Expand All @@ -303,8 +303,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;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Common/Src/Thread.cpp
Expand Up @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions Source/Core/Common/Src/Thread.h
Expand Up @@ -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>
Expand Down
Expand Up @@ -17,7 +17,7 @@

#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

using namespace Gen;

Expand Down
File renamed without changes.
Expand Up @@ -30,7 +30,9 @@
#else

//#include <config/i386/cpuid.h>
#ifndef _M_GENERIC
#include <xmmintrin.h>
#endif

#if defined __FreeBSD__
#include <sys/types.h>
Expand All @@ -39,7 +41,9 @@
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
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__ (
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Common/Src/x64Emitter.cpp
Expand Up @@ -17,7 +17,7 @@

#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "CPUDetect.h"

namespace Gen
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Common/Src/x64Emitter.h
Expand Up @@ -757,7 +757,7 @@ class XCodeBlock : public XEmitter
region_size = 0;
}

bool IsInCodeSpace(u8 *ptr)
bool IsInSpace(u8 *ptr)
{
return ptr >= region && ptr < region + region_size;
}
Expand Down
120 changes: 120 additions & 0 deletions 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[4]) | 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);
}
}
Expand Up @@ -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
Expand Down
36 changes: 29 additions & 7 deletions Source/Core/Core/CMakeLists.txt
Expand Up @@ -9,7 +9,6 @@ set(SRCS Src/ActionReplay.cpp
Src/DSPEmulator.cpp
Src/GeckoCodeConfig.cpp
Src/GeckoCode.cpp
Src/MemTools.cpp
Src/Movie.cpp
Src/NetPlay.cpp
Src/NetPlayClient.cpp
Expand Down Expand Up @@ -153,6 +152,7 @@ set(SRCS Src/ActionReplay.cpp
Src/PowerPC/PPCTables.cpp
Src/PowerPC/Profiler.cpp
Src/PowerPC/SignatureDB.cpp
Src/PowerPC/JitInterface.cpp
Src/PowerPC/Interpreter/Interpreter_Branch.cpp
Src/PowerPC/Interpreter/Interpreter.cpp
Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
Expand All @@ -162,6 +162,15 @@ set(SRCS Src/ActionReplay.cpp
Src/PowerPC/Interpreter/Interpreter_Paired.cpp
Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
Src/PowerPC/Interpreter/Interpreter_Tables.cpp
Src/PowerPC/JitCommon/JitAsmCommon.cpp
Src/PowerPC/JitCommon/JitBackpatch.cpp
Src/PowerPC/JitCommon/JitBase.cpp
Src/PowerPC/JitCommon/JitCache.cpp
Src/PowerPC/JitCommon/Jit_Util.cpp)

if(NOT _M_GENERIC)
set(SRCS ${SRCS}
Src/x64MemTools.cpp
Src/PowerPC/Jit64IL/IR.cpp
Src/PowerPC/Jit64IL/IR_X86.cpp
Src/PowerPC/Jit64IL/JitILAsm.cpp
Expand All @@ -186,12 +195,25 @@ set(SRCS Src/ActionReplay.cpp
Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp
Src/PowerPC/Jit64/Jit_Paired.cpp
Src/PowerPC/Jit64/JitRegCache.cpp
Src/PowerPC/Jit64/Jit_SystemRegisters.cpp
Src/PowerPC/JitCommon/JitAsmCommon.cpp
Src/PowerPC/JitCommon/JitBackpatch.cpp
Src/PowerPC/JitCommon/JitBase.cpp
Src/PowerPC/JitCommon/JitCache.cpp
Src/PowerPC/JitCommon/Jit_Util.cpp)
Src/PowerPC/Jit64/Jit_SystemRegisters.cpp)
endif()
if(_M_ARM)
set(SRCS ${SRCS}
Src/ArmMemTools.cpp
Src/PowerPC/JitArm32/Jit.cpp
Src/PowerPC/JitArm32/JitAsm.cpp
Src/PowerPC/JitArm32/JitArm_BackPatch.cpp
Src/PowerPC/JitArm32/JitArm_Tables.cpp
Src/PowerPC/JitArm32/JitArmCache.cpp
Src/PowerPC/JitArm32/JitRegCache.cpp
Src/PowerPC/JitArm32/JitFPRCache.cpp
Src/PowerPC/JitArm32/JitArm_Branch.cpp
Src/PowerPC/JitArm32/JitArm_Integer.cpp
Src/PowerPC/JitArm32/JitArm_LoadStore.cpp
Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp
Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp
Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp)
endif()

set(LIBS bdisasm inputcommon videosoftware sfml-network)

Expand Down
12 changes: 7 additions & 5 deletions Source/Core/Core/Core.vcxproj
Expand Up @@ -332,7 +332,7 @@
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb_kbd.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_WiiMote.cpp" />
<ClCompile Include="Src\MemTools.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\Movie.cpp" />
<ClCompile Include="Src\NetPlay.cpp" />
<ClCompile Include="Src\NetPlayClient.cpp" />
Expand Down Expand Up @@ -378,6 +378,7 @@
<ClCompile Include="Src\PowerPC\JitCommon\JitBase.cpp" />
<ClCompile Include="Src\PowerPC\JitCommon\JitCache.cpp" />
<ClCompile Include="Src\PowerPC\JitCommon\Jit_Util.cpp" />
<ClCompile Include="Src\PowerPC\JitInterface.cpp" />
<ClCompile Include="Src\PowerPC\LUT_frsqrtex.cpp" />
<ClCompile Include="Src\PowerPC\PowerPC.cpp" />
<ClCompile Include="Src\PowerPC\PPCAnalyst.cpp" />
Expand All @@ -387,10 +388,10 @@
<ClCompile Include="Src\PowerPC\Profiler.cpp" />
<ClCompile Include="Src\PowerPC\SignatureDB.cpp" />
<ClCompile Include="Src\State.cpp">
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</OpenMPSupport>
</ClCompile>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</OpenMPSupport>
</ClCompile>
<ClCompile Include="Src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
Expand Down Expand Up @@ -563,6 +564,7 @@
<ClInclude Include="Src\PowerPC\JitCommon\JitBase.h" />
<ClInclude Include="Src\PowerPC\JitCommon\JitCache.h" />
<ClInclude Include="Src\PowerPC\JitCommon\Jit_Util.h" />
<ClInclude Include="Src\PowerPC\JitInterface.h" />
<ClInclude Include="Src\PowerPC\LUT_frsqrtex.h" />
<ClInclude Include="Src\PowerPC\PowerPC.h" />
<ClInclude Include="Src\PowerPC\PPCAnalyst.h" />
Expand Down
9 changes: 7 additions & 2 deletions Source/Core/Core/Core.vcxproj.filters
Expand Up @@ -5,9 +5,8 @@
<ClCompile Include="Src\Console.cpp" />
<ClCompile Include="Src\Core.cpp" />
<ClCompile Include="Src\CoreParameter.cpp" />
<ClCompile Include="Src\CoreRerecording.cpp" />
<ClCompile Include="Src\CoreTiming.cpp" />
<ClCompile Include="Src\MemTools.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\PatchEngine.cpp" />
<ClCompile Include="Src\DSPEmulator.cpp" />
<ClCompile Include="Src\State.cpp" />
Expand Down Expand Up @@ -562,6 +561,9 @@
<ClCompile Include="Src\HW\GCMemcard.cpp">
<Filter>HW %28Flipper/Hollywood%29\GCMemcard</Filter>
</ClCompile>
<ClCompile Include="Src\PowerPC\JitInterface.cpp">
<Filter>PowerPC</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\ConfigManager.h" />
Expand Down Expand Up @@ -1048,6 +1050,9 @@
<ClInclude Include="Src\HW\GCMemcard.h">
<Filter>HW %28Flipper/Hollywood%29\GCMemcard</Filter>
</ClInclude>
<ClInclude Include="Src\PowerPC\JitInterface.h">
<Filter>PowerPC</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
Expand Down
103 changes: 103 additions & 0 deletions Source/Core/Core/Src/ArmMemTools.cpp
@@ -0,0 +1,103 @@
// 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 <stdio.h>
#include <signal.h>
#ifdef ANDROID
#include <asm/sigcontext.h>
#else
#include <sys/ucontext.h> // Look in here for the context definition.
#include <execinfo.h>
#endif

#include "Common.h"
#include "MemTools.h"
#include "HW/Memmap.h"
#include "PowerPC/PowerPC.h"
#include "PowerPC/JitInterface.h"
#include "PowerPC/JitCommon/JitBase.h"

namespace EMM
{
#ifdef ANDROID
typedef struct sigcontext mcontext_t;
typedef struct ucontext {
uint32_t uc_flags;
struct ucontext* uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
// Other fields are not used by Google Breakpad. Don't define them.
} ucontext_t;
#endif

void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
{
if (signal != SIGSEGV)
{
// We are not interested in other signals - handle it as usual.
return;
}
ucontext_t *context = (ucontext_t *)raw_context;
int sicode = info->si_code;
if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR)
{
// Huh? Return.
return;
}


// Get all the information we can out of the context.
mcontext_t *ctx = &context->uc_mcontext;

void *fault_memory_ptr = (void*)ctx->arm_r10;
u8 *fault_instruction_ptr = (u8 *)ctx->arm_pc;

if (!JitInterface::IsInCodeSpace(fault_instruction_ptr)) {
// Let's not prevent debugging.
return;
}

u64 bad_address = (u64)fault_memory_ptr;
u64 memspace_bottom = (u64)Memory::base;
if (bad_address < memspace_bottom) {
PanicAlertT("Exception handler - access below memory space. %08llx%08llx",
bad_address >> 32, bad_address);
}

u32 em_address = (u32)(bad_address - memspace_bottom);

int access_type = 0;

CONTEXT fake_ctx;
fake_ctx.reg_pc = ctx->arm_pc;
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, access_type, em_address, &fake_ctx);
if (new_rip) {
ctx->arm_pc = fake_ctx.reg_pc;
}
}

void InstallExceptionHandler()
{
struct sigaction sa;
sa.sa_handler = 0;
sa.sa_sigaction = &sigsegv_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, NULL);
}
} // namespace
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/ConfigManager.h
Expand Up @@ -35,7 +35,7 @@
#define BACKEND_OPENAL "OpenAL"
#define BACKEND_PULSEAUDIO "Pulse"
#define BACKEND_XAUDIO2 "XAudio2"

#define BACKEND_OPENSLES "OpenSLES"
struct SConfig : NonCopyable
{
// Wii Devices
Expand Down
7 changes: 3 additions & 4 deletions Source/Core/Core/Src/Core.cpp
Expand Up @@ -54,7 +54,6 @@
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"

#include "PowerPC/PowerPC.h"
#include "PowerPC/JitCommon/JitBase.h"

#include "DSPEmulator.h"
#include "ConfigManager.h"
Expand Down Expand Up @@ -140,7 +139,7 @@ void DisplayMessage(const char *message, int time_in_ms)
if (_CoreParameter.bRenderToMain &&
SConfig::GetInstance().m_InterfaceStatusbar)
{
Host_UpdateStatusBar(message);
Host_UpdateStatusBar(message);
}
else
Host_UpdateTitle(message);
Expand Down Expand Up @@ -189,7 +188,7 @@ bool IsGPUThread()
return IsCPUThread();
}
}

// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init()
Expand Down Expand Up @@ -310,7 +309,7 @@ void CpuThread()
g_video_backend->Video_Prepare();
}

#if defined(_M_X64)
#if defined(_M_X64) || _M_ARM
EMM::InstallExceptionHandler(); // Let's run under memory watch
#endif

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/DSPEmitter.cpp
Expand Up @@ -25,7 +25,7 @@
#include "DSPAnalyzer.h"
#include "Jit/DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#define MAX_BLOCK_SIZE 250
#define DSP_IDLE_SKIP_CYCLES 0x1000
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/Src/DSP/DSPHWInterface.cpp
Expand Up @@ -252,7 +252,9 @@ static void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size)
ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size);
}

#if _M_SSE >= 0x301
static const __m128i s_mask = _mm_set_epi32(0x0E0F0C0DL, 0x0A0B0809L, 0x06070405L, 0x02030001L);
#endif

// TODO: These should eat clock cycles.
static void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitArithmetic.cpp
Expand Up @@ -25,7 +25,7 @@
#include "DSPJitUtil.h"
#endif
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;

// CLR $acR
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitBranch.cpp
Expand Up @@ -21,7 +21,7 @@
#include "../DSPAnalyzer.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

using namespace Gen;

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitCCUtil.cpp
Expand Up @@ -24,7 +24,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;

// In: RAX: s64 _Value
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp
Expand Up @@ -18,7 +18,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

using namespace Gen;

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp
Expand Up @@ -22,7 +22,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;

// SRS @M, $(0x18+S)
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp
Expand Up @@ -20,7 +20,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;

//clobbers:
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitMultiplier.cpp
Expand Up @@ -27,7 +27,7 @@
#include "DSPJitUtil.h"
#endif
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;

// Returns s64 in RAX
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp
Expand Up @@ -20,7 +20,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

using namespace Gen;

Expand Down
126 changes: 0 additions & 126 deletions Source/Core/Core/Src/HW/Memmap.cpp
Expand Up @@ -419,132 +419,6 @@ u32 Read_Instruction(const u32 em_address)
return inst.hex;
}

u32 Read_Opcode_JIT_Uncached(const u32 _Address)
{
u8* iCache;
u32 addr;
if (_Address & JIT_ICACHE_VMEM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheVMEM();
addr = _Address & JIT_ICACHE_MASK;
}
else if (_Address & JIT_ICACHE_EXRAM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheEx();
addr = _Address & JIT_ICACHEEX_MASK;
}
else
{
iCache = jit->GetBlockCache()->GetICache();
addr = _Address & JIT_ICACHE_MASK;
}
u32 inst = *(u32*)(iCache + addr);
if (inst == JIT_ICACHE_INVALID_WORD)
{
u32 cache_block_start = addr & ~0x1f;
u32 mem_block_start = _Address & ~0x1f;
u8 *pMem = Memory::GetPointer(mem_block_start);
memcpy(iCache + cache_block_start, pMem, 32);
inst = *(u32*)(iCache + addr);
}
inst = Common::swap32(inst);

if ((inst & 0xfc000000) == 0)
{
inst = jit->GetBlockCache()->GetOriginalFirstOp(inst);
}

return inst;
}

u32 Read_Opcode_JIT(u32 _Address)
{
#ifdef FAST_ICACHE
if (bMMU && !bFakeVMEM && (_Address & ADDR_MASK_MEM1))
{
_Address = Memory::TranslateAddress(_Address, FLAG_OPCODE);
if (_Address == 0)
{
return 0;
}
}
u32 inst = 0;

// Bypass the icache for the external interrupt exception handler
if ( (_Address & 0x0FFFFF00) == 0x00000500 )
inst = Read_Opcode_JIT_Uncached(_Address);
else
inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
#else
u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif
return inst;
}

// The following function is deprecated in favour of FAST_ICACHE
u32 Read_Opcode_JIT_LC(const u32 _Address)
{
#ifdef JIT_UNLIMITED_ICACHE
if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 &&
(_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area
(_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000)
{
PanicAlertT("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
ERROR_LOG(MEMMAP, "iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0;
}
u8* iCache;
u32 addr;
if (_Address & JIT_ICACHE_VMEM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheVMEM();
addr = _Address & JIT_ICACHE_MASK;
}
else if (_Address & JIT_ICACHE_EXRAM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheEx();
addr = _Address & JIT_ICACHEEX_MASK;
}
else
{
iCache = jit->GetBlockCache()->GetICache();
addr = _Address & JIT_ICACHE_MASK;
}
u32 inst = *(u32*)(iCache + addr);
if (inst == JIT_ICACHE_INVALID_WORD)
inst = Memory::ReadUnchecked_U32(_Address);
else
inst = Common::swap32(inst);
#else
u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif
if ((inst & 0xfc000000) == 0)
{
inst = jit->GetBlockCache()->GetOriginalFirstOp(inst);
}
return inst;
}

// WARNING! No checks!
// We assume that _Address is cached
void Write_Opcode_JIT(const u32 _Address, const u32 _Value)
{
#ifdef JIT_UNLIMITED_ICACHE
if (_Address & JIT_ICACHE_VMEM_BIT)
{
*(u32*)(jit->GetBlockCache()->GetICacheVMEM() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value);
}
else if (_Address & JIT_ICACHE_EXRAM_BIT)
{
*(u32*)(jit->GetBlockCache()->GetICacheEx() + (_Address & JIT_ICACHEEX_MASK)) = Common::swap32(_Value);
}
else
*(u32*)(jit->GetBlockCache()->GetICache() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value);
#else
Memory::WriteUnchecked_U32(_Value, _Address);
#endif
}

void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
{
memcpy(GetPointer(_Address), _pData, _iSize);
Expand Down
5 changes: 0 additions & 5 deletions Source/Core/Core/Src/HW/Memmap.h
Expand Up @@ -119,11 +119,6 @@ inline u32 ReadFast32(const u32 _Address)

// used by interpreter to read instructions, uses iCache
u32 Read_Opcode(const u32 _Address);
// used by JIT to read instructions
u32 Read_Opcode_JIT(const u32 _Address);
// used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode
u32 Read_Opcode_JIT_LC(const u32 _Address);
void Write_Opcode_JIT(const u32 _Address, const u32 _Value);
// this is used by Debugger a lot.
// For now, just reads from memory!
u32 Read_Instruction(const u32 _Address);
Expand Down
Expand Up @@ -28,8 +28,6 @@
#undef _interlockedbittestandreset
#undef _interlockedbittestandset64
#undef _interlockedbittestandreset64
#else
#include <xmmintrin.h>
#endif

#include "../../Core.h"
Expand Down Expand Up @@ -514,4 +512,4 @@ void Interpreter::fsqrtx(UGeckoInstruction _inst)
rPS0(_inst.FD) = sqrt(b);
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD));
}
}
21 changes: 5 additions & 16 deletions Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
Expand Up @@ -24,8 +24,7 @@
#include "Interpreter.h"
#include "../../Core.h"

#include "../JitCommon/JitBase.h"
#include "../JitCommon/JitCache.h"
#include "../JitInterface.h"

#include "Interpreter_FPUtils.h"

Expand Down Expand Up @@ -363,34 +362,24 @@ void Interpreter::dcbf(UGeckoInstruction _inst)
{
NPC = PC + 12;
}*/
// Invalidate the jit block cache on dcbf
if (jit)
{
u32 address = Helper_Get_EA_X(_inst);
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
}
JitInterface::InvalidateICache(address & ~0x1f, 32);
}

void Interpreter::dcbi(UGeckoInstruction _inst)
{
// Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache
// However, we invalidate the jit block cache on dcbi
if (jit)
{
u32 address = Helper_Get_EA_X(_inst);
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
}
JitInterface::InvalidateICache(address & ~0x1f, 32);
}

void Interpreter::dcbst(UGeckoInstruction _inst)
{
// Cache line flush. Since we don't emulate the data cache, we don't need to do anything.
// Invalidate the jit block cache on dcbst in case new code has been loaded via the data cache
if (jit)
{
u32 address = Helper_Get_EA_X(_inst);
jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32);
}
JitInterface::InvalidateICache(address & ~0x1f, 32);
}

void Interpreter::dcbt(UGeckoInstruction _inst)
Expand All @@ -409,7 +398,7 @@ void Interpreter::dcbz(UGeckoInstruction _inst)
// HACK but works... we think
if (!Core::g_CoreStartupParameter.bDCBZOFF)
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
if (!jit)
if (!JitInterface::GetCore())
PowerPC::CheckExceptions();
}

Expand Down
Expand Up @@ -26,13 +26,6 @@
#undef _interlockedbittestandreset
#undef _interlockedbittestandset64
#undef _interlockedbittestandreset64
#else
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

#include "CPUDetect.h"
Expand All @@ -43,6 +36,7 @@ static const unsigned short FPU_ROUND_MASK = 3 << 10;
#include "../../HW/SystemTimers.h"
#include "../../Core.h"
#include "Interpreter.h"
#include "FPURoundMode.h"

#include "Interpreter_FPUtils.h"

Expand All @@ -61,38 +55,11 @@ mffsx: 80036650 (huh?)
// That is, set rounding mode etc when entering jit code or the interpreter loop
// Restore rounding mode when calling anything external

const u32 MASKS = 0x1F80; // mask away the interrupts.
const u32 DAZ = 0x40;
const u32 FTZ = 0x8000;

static void FPSCRtoFPUSettings(UReg_FPSCR fp)
{
// 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[fp.RN]);
#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[fp.RN];
asm ("fldcw %0" : : "m" (mode));
#endif
#endif

FPURoundMode::SetRoundMode(fp.RN);

if (fp.VE || fp.OE || fp.UE || fp.ZE || fp.XE)
{
//PanicAlert("FPSCR - exceptions enabled. Please report. VE=%i OE=%i UE=%i ZE=%i XE=%i",
Expand All @@ -101,22 +68,14 @@ static void FPSCRtoFPUSettings(UReg_FPSCR fp)
}

// Also corresponding SSE rounding mode setting
static const u32 ssetable[4] =
{
(0 << 13) | MASKS,
(3 << 13) | MASKS,
(2 << 13) | MASKS,
(1 << 13) | MASKS,
};
u32 csr = ssetable[FPSCR.RN];
if (FPSCR.NI)
{
// Either one of these two breaks Beyond Good & Evil.
// if (cpu_info.bSSSE3)
// csr |= DAZ;
// csr |= FTZ;
}
_mm_setcsr(csr);
FPURoundMode::SetSIMDMode(FPSCR.RN);
}

void Interpreter::mtfsb0x(UGeckoInstruction _inst)
Expand Down
Expand Up @@ -267,7 +267,7 @@ static GekkoOPTemplate table31[] =
{19, Interpreter::mfcr, {"mfcr", OPTYPE_SYSTEM, FL_OUT_D, 0, 0, 0, 0}},
{83, Interpreter::mfmsr, {"mfmsr", OPTYPE_SYSTEM, FL_OUT_D, 0, 0, 0, 0}},
{144, Interpreter::mtcrf, {"mtcrf", OPTYPE_SYSTEM, 0, 0, 0, 0, 0}},
{146, Interpreter::mtmsr, {"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK, 0, 0, 0, 0}},
{146, Interpreter::mtmsr, {"mtmsr", OPTYPE_SYSTEM, FL_IN_S | FL_ENDBLOCK, 0, 0, 0, 0}},
{210, Interpreter::mtsr, {"mtsr", OPTYPE_SYSTEM, 0, 0, 0, 0, 0}},
{242, Interpreter::mtsrin, {"mtsrin", OPTYPE_SYSTEM, 0, 0, 0, 0, 0}},
{339, Interpreter::mfspr, {"mfspr", OPTYPE_SPR, FL_OUT_D, 0, 0, 0, 0}},
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp
Expand Up @@ -24,7 +24,7 @@

#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "Thunk.h"
#include "../../HLE/HLE.h"
#include "../../Core.h"
Expand Down Expand Up @@ -357,7 +357,7 @@ void Jit64::WriteExternalExceptionExit()
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.dispatcher, true);
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64/Jit.h
Expand Up @@ -62,7 +62,7 @@
if (js.memcheck) \
SetJumpTarget(memException);

class Jit64 : public JitBase
class Jit64 : public Jitx86Base
{
private:
GPRRegCache gpr;
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
Expand Up @@ -15,7 +15,7 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/

#include "ABI.h"
#include "x64ABI.h"
#include "x64Emitter.h"

#include "../../HW/Memmap.h"
Expand All @@ -24,7 +24,7 @@
#include "../../CoreTiming.h"
#include "MemoryUtil.h"

#include "ABI.h"
#include "x64ABI.h"
#include "Jit.h"
#include "../JitCommon/JitCache.h"

Expand Down Expand Up @@ -204,7 +204,7 @@ void Jit64AsmRoutineManager::Generate()
MOV(32, M(&NPC), R(EAX));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions));
SetJumpTarget(noExtException);

TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop, true);

Expand Down
1 change: 0 additions & 1 deletion Source/Core/Core/Src/PowerPC/Jit64/JitAsm.h
Expand Up @@ -18,7 +18,6 @@
#ifndef _JIT64ASM_H
#define _JIT64ASM_H

#include "x64Emitter.h"
#include "../JitCommon/JitAsmCommon.h"

// In Dolphin, we don't use inline assembly. Instead, we generate all machine-near
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp
Expand Up @@ -28,7 +28,7 @@
#include "../../HW/Memmap.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#include "Jit.h"
#include "JitAsm.h"
Expand Down
Expand Up @@ -27,7 +27,7 @@
#include "../PPCTables.h"
#include "CPUDetect.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#include "Jit.h"
#include "JitAsm.h"
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp
Expand Up @@ -28,7 +28,7 @@
#include "../PPCTables.h"
#include "CPUDetect.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#include "Jit.h"
#include "JitAsm.h"
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp
Expand Up @@ -23,7 +23,7 @@
#include "../PowerPC.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "Thunk.h"

#include "Jit.h"
Expand Down
10 changes: 6 additions & 4 deletions Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
Expand Up @@ -1991,8 +1991,10 @@ void JitIL::WriteCode() {
}

void ProfiledReJit() {
jit->SetCodePtr(jit->js.rewriteStart);
DoWriteCode(&((JitIL *)jit)->ibuild, (JitIL *)jit, true, false);
jit->js.curBlock->codeSize = (int)(jit->GetCodePtr() - jit->js.rewriteStart);
jit->GetBlockCache()->FinalizeBlock(jit->js.curBlock->blockNum, jit->jo.enableBlocklink, jit->js.curBlock->normalEntry);
JitIL *jitil = (JitIL *)jit;
jitil->SetCodePtr(jitil->js.rewriteStart);
DoWriteCode(&jitil->ibuild, jitil, true, false);
jitil->js.curBlock->codeSize = (int)(jitil->GetCodePtr() - jitil->js.rewriteStart);
jitil->GetBlockCache()->FinalizeBlock(jitil->js.curBlock->blockNum, jitil->jo.enableBlocklink,
jitil->js.curBlock->normalEntry);
}
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
Expand Up @@ -19,7 +19,7 @@

#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "Thunk.h"
#include "../../HLE/HLE.h"
#include "../../Core.h"
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h
Expand Up @@ -57,7 +57,7 @@
#define DISABLE64
#endif

class JitIL : public JitBase
class JitIL : public Jitx86Base
{
private:

Expand Down
8 changes: 4 additions & 4 deletions Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp
Expand Up @@ -15,7 +15,7 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/

#include "ABI.h"
#include "x64ABI.h"
#include "x64Emitter.h"

#include "../../HW/Memmap.h"
Expand All @@ -25,7 +25,7 @@
#include "MemoryUtil.h"
#include "CPUDetect.h"

#include "ABI.h"
#include "x64ABI.h"
#include "Thunk.h"

#include "../../HW/GPFifo.h"
Expand Down Expand Up @@ -211,14 +211,14 @@ void JitILAsmRoutineManager::Generate()
doTiming = GetCodePtr();

ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));

testExceptions = GetCodePtr();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX));

TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outer_loop, true);
//Landing pad for drec space
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_LoadStore.cpp
Expand Up @@ -27,7 +27,7 @@
#include "../../HW/Memmap.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILAsm.h"
Expand Down
Expand Up @@ -27,7 +27,7 @@
#include "../PPCTables.h"
#include "CPUDetect.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILAsm.h"
Expand Down
Expand Up @@ -25,7 +25,7 @@
#include "../PPCTables.h"
#include "CPUDetect.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"

#include "JitIL.h"
#include "JitILAsm.h"
Expand Down
Expand Up @@ -23,7 +23,7 @@
#include "../PowerPC.h"
#include "../PPCTables.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "Thunk.h"

#include "JitIL.h"
Expand Down
498 changes: 498 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp

Large diffs are not rendered by default.

186 changes: 186 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/Jit.h
@@ -0,0 +1,186 @@
// 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/

// ========================
// See comments in Jit.cpp.
// ========================

// Mystery: Capcom vs SNK 800aa278

// CR flags approach:
// * Store that "N+Z flag contains CR0" or "S+Z flag contains CR3".
// * All flag altering instructions flush this
// * A flush simply does a conditional write to the appropriate CRx.
// * If flag available, branch code can become absolutely trivial.

// Settings
// ----------
#ifndef _JITARM_H
#define _JITARM_H
#include "../CPUCoreBase.h"
#include "../PPCAnalyst.h"
#include "JitArmCache.h"
#include "JitRegCache.h"
#include "JitFPRCache.h"
#include "JitAsm.h"
#include "../JitCommon/JitBase.h"

// Use these to control the instruction selection
// #define INSTRUCTION_START Default(inst); return;
// #define INSTRUCTION_START PPCTables::CountInstruction(inst);
#define INSTRUCTION_START
#define JITDISABLE(type) \
if (Core::g_CoreStartupParameter.bJITOff || \
Core::g_CoreStartupParameter.bJIT##type##Off) \
{Default(inst); return;}

class JitArm : public JitBase, public ArmGen::ARMXCodeBlock
{
private:
JitArmBlockCache blocks;

JitArmAsmRoutineManager asm_routines;

// TODO: Make arm specific versions of these, shouldn't be too hard to
// make it so we allocate some space at the start(?) of code generation
// and keep the registers in a cache. Will burn this bridge when we get to
// it.
ArmRegCache gpr;
ArmFPRCache fpr;

PPCAnalyst::CodeBuffer code_buffer;
void DoDownCount();

void PrintDebug(UGeckoInstruction inst, u32 level);

void Helper_UpdateCR1(ARMReg value);
public:
JitArm() : code_buffer(32000) {}
~JitArm() {}

void Init();
void Shutdown();

// Jit!

void Jit(u32 em_address);
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b);

JitBaseBlockCache *GetBlockCache() { return &blocks; }

const u8 *BackPatch(u8 *codePtr, int accessType, u32 em_address, void *ctx);

bool IsInCodeSpace(u8 *ptr) { return IsInSpace(ptr); }

void Trace();

void ClearCache();

const u8 *GetDispatcher() {
return asm_routines.dispatcher;
}
CommonAsmRoutinesBase *GetAsmRoutines() {
return &asm_routines;
}

const char *GetName() {
return "JITARM";
}
// Run!

void Run();
void SingleStep();

// Utilities for use by opcodes

void WriteExit(u32 destination, int exit_num);
void WriteExitDestInR(ARMReg Reg);
void WriteRfiExitDestInR(ARMReg Reg);
void WriteExceptionExit();
void WriteCallInterpreter(UGeckoInstruction _inst);
void Cleanup();

void GenerateRC(int cr = 0);
void ComputeRC(int cr = 0);

// TODO: This shouldn't be here
void StoreFromReg(ARMReg dest, ARMReg value, int accessSize, s32 offset);
void LoadToReg(ARMReg dest, ARMReg addr, int accessSize, s32 offset);

// OPCODES
void unknown_instruction(UGeckoInstruction _inst);
void Default(UGeckoInstruction _inst);
void DoNothing(UGeckoInstruction _inst);
void HLEFunction(UGeckoInstruction _inst);

void DynaRunTable4(UGeckoInstruction _inst);
void DynaRunTable19(UGeckoInstruction _inst);
void DynaRunTable31(UGeckoInstruction _inst);
void DynaRunTable59(UGeckoInstruction _inst);
void DynaRunTable63(UGeckoInstruction _inst);

// Breakin shit
void Break(UGeckoInstruction _inst);
// Branch
void bx(UGeckoInstruction _inst);
void bcx(UGeckoInstruction _inst);
void bclrx(UGeckoInstruction _inst);
void sc(UGeckoInstruction _inst);
void rfi(UGeckoInstruction _inst);
void bcctrx(UGeckoInstruction _inst);

// Integer
void addi(UGeckoInstruction _inst);
void addis(UGeckoInstruction _inst);
void addx(UGeckoInstruction _inst);
void cmp (UGeckoInstruction _inst);
void cmpi(UGeckoInstruction _inst);
void cmpli(UGeckoInstruction _inst);
void negx(UGeckoInstruction _inst);
void mulli(UGeckoInstruction _inst);
void ori(UGeckoInstruction _inst);
void oris(UGeckoInstruction _inst);
void orx(UGeckoInstruction _inst);
void rlwimix(UGeckoInstruction _inst);
void rlwinmx(UGeckoInstruction _inst);
void extshx(UGeckoInstruction inst);
void extsbx(UGeckoInstruction inst);

// System Registers
void mtmsr(UGeckoInstruction _inst);
void mtspr(UGeckoInstruction _inst);
void mfspr(UGeckoInstruction _inst);

// LoadStore
void icbi(UGeckoInstruction _inst);
void lbz(UGeckoInstruction _inst);
void lhz(UGeckoInstruction _inst);
void lwz(UGeckoInstruction _inst);
void lwzx(UGeckoInstruction _inst);
void stw(UGeckoInstruction _inst);
void stwu(UGeckoInstruction _inst);

// Floating point
void fabsx(UGeckoInstruction _inst);
void faddx(UGeckoInstruction _inst);
void fmrx(UGeckoInstruction _inst);

// Floating point loadStore
void lfs(UGeckoInstruction _inst);
};

#endif // _JIT64_H
46 changes: 46 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArmCache.cpp
@@ -0,0 +1,46 @@
// 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/

// Enable define below to enable oprofile integration. For this to work,
// it requires at least oprofile version 0.9.4, and changing the build
// system to link the Dolphin executable against libopagent. Since the
// dependency is a little inconvenient and this is possibly a slight
// performance hit, it's not enabled by default, but it's useful for
// locating performance issues.

#include "../JitInterface.h"
#include "JitArmCache.h"


using namespace ArmGen;

void JitArmBlockCache::WriteLinkBlock(u8* location, const u8* address)
{
ARMXEmitter emit(location);
emit.B(address);
}
void JitArmBlockCache::WriteDestroyBlock(const u8* location, u32 address)
{
ARMXEmitter emit((u8 *)location);
emit.MOVI2R(R10, (u32)&PC);
emit.MOVI2R(R11, address);
emit.MOVI2R(R12, (u32)jit->GetAsmRoutines()->dispatcher);
emit.STR(R10, R11);
emit.B(R12);
}


33 changes: 33 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArmCache.h
@@ -0,0 +1,33 @@
// 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 _JITARMCACHE_H
#define _JITARMCACHE_H

#include "../JitCommon/JitCache.h"


typedef void (*CompiledCode)();

class JitArmBlockCache : public JitBaseBlockCache
{
private:
void WriteLinkBlock(u8* location, const u8* address);
void WriteDestroyBlock(const u8* location, u32 address);
};

#endif
164 changes: 164 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArm_BackPatch.cpp
@@ -0,0 +1,164 @@
// 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 <string>

#include "Common.h"

#include "../../HW/Memmap.h"
#include "Jit.h"
#include "../JitCommon/JitBackpatch.h"
#include "StringUtil.h"

#ifdef _M_X64
static void BackPatchError(const std::string &text, u8 *codePtr, u32 emAddress) {
u64 code_addr = (u64)codePtr;
disassembler disasm;
char disbuf[256];
memset(disbuf, 0, 256);
#ifdef _M_IX86
disasm.disasm32(0, code_addr, codePtr, disbuf);
#else
disasm.disasm64(0, code_addr, codePtr, disbuf);
#endif
PanicAlert("%s\n\n"
"Error encountered accessing emulated address %08x.\n"
"Culprit instruction: \n%s\nat %#llx",
text.c_str(), emAddress, disbuf, code_addr);
return;
}
#endif

// This generates some fairly heavy trampolines, but:
// 1) It's really necessary. We don't know anything about the context.
// 2) It doesn't really hurt. Only instructions that access I/O will get these, and there won't be
// that many of them in a typical program/game.
bool DisamLoadStore(const u32 inst, ARMReg &rD, u8 &accessSize, bool &Store)
{
u8 op = (inst >> 20) & 0xFF;
printf("op: 0x%08x\n", op);
switch (op)
{
case 0x58: // STR
{
rD = (ARMReg)((inst >> 16) & 0xF);
Store = true;
accessSize = 32;
}
break;
case 0x59: // LDR
{
rD = (ARMReg)((inst >> 16) & 0xF);
Store = false;
accessSize = 32;
}
break;
case 0x05: // LDRH
{
rD = (ARMReg)((inst >> 16) & 0xF);
Store = false;
accessSize = 16;
}
break;
case 0x45 + 0x18: // LDRB
{
rD = (ARMReg)((inst >> 16) & 0xF);
Store = false;
accessSize = 8;
}
break;
case 0x44 + 0x18: // STRB
default:
return false;
}
return true;
}
const u8 *JitArm::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void *ctx_void)
{
// TODO: This ctx needs to be filled with our information
CONTEXT *ctx = (CONTEXT *)ctx_void;

// We need to get the destination register before we start
u32 Value = *(u32*)codePtr;
ARMReg rD;
u8 accessSize;
bool Store;

if (!DisamLoadStore(Value, rD, accessSize, Store))
{
printf("Invalid backpatch at location 0x%08x(0x%08x)\n", ctx->reg_pc, Value);
exit(0);
}

if (Store)
{
const u32 ARMREGOFFSET = 4 * 7;
ARMXEmitter emitter(codePtr - ARMREGOFFSET);
switch (accessSize)
{
case 8: // 8bit
//emitter.MOVI2R(R14, (u32)&Memory::Write_U8, false); // 1-2
return 0;
break;
case 16: // 16bit
//emitter.MOVI2R(R14, (u32)&Memory::Write_U16, false); // 1-2
return 0;
break;
case 32: // 32bit
emitter.MOVI2R(R14, (u32)&Memory::Write_U32, false); // 1-2
break;
}
emitter.PUSH(4, R0, R1, R2, R3); // 3
emitter.MOV(R0, rD); // Value - 4
emitter.MOV(R1, R10); // Addr- 5
emitter.BL(R14); // 6
emitter.POP(4, R0, R1, R2, R3); // 7
emitter.NOP(1); // 8
u32 newPC = ctx->reg_pc - (ARMREGOFFSET + 4 * 4);
ctx->reg_pc = newPC;
emitter.FlushIcache();
return codePtr;
}
else
{
const u32 ARMREGOFFSET = 4 * 6;
ARMXEmitter emitter(codePtr - ARMREGOFFSET);
switch (accessSize)
{
case 8: // 8bit
emitter.MOVI2R(R14, (u32)&Memory::Read_U8, false); // 2
break;
case 16: // 16bit
emitter.MOVI2R(R14, (u32)&Memory::Read_U16, false); // 2
break;
case 32: // 32bit
emitter.MOVI2R(R14, (u32)&Memory::Read_U32, false); // 2
break;
}
emitter.PUSH(4, R0, R1, R2, R3); // 3
emitter.MOV(R0, R10); // 4
emitter.BL(R14); // 5
emitter.MOV(R14, R0); // 6
emitter.POP(4, R0, R1, R2, R3); // 7
emitter.MOV(rD, R14); // 8
ctx->reg_pc -= ARMREGOFFSET + (4 * 4);
emitter.FlushIcache();
return codePtr;
}
return 0;
}

347 changes: 347 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Branch.cpp
@@ -0,0 +1,347 @@
// 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 "Thunk.h"

#include "../../Core.h"
#include "../PowerPC.h"
#include "../../CoreTiming.h"
#include "../PPCTables.h"
#include "ArmEmitter.h"

#include "Jit.h"
#include "JitRegCache.h"
#include "JitAsm.h"

// The branches are known good, or at least reasonably good.
// No need for a disable-mechanism.

// If defined, clears CR0 at blr and bl-s. If the assumption that
// flags never carry over between functions holds, then the task for
// an optimizer becomes much easier.

// #define ACID_TEST

// Zelda and many more games seem to pass the Acid Test.


using namespace ArmGen;
void JitArm::sc(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Branch)

gpr.Flush();
fpr.Flush();

ARMABI_MOVI2M((u32)&PC, js.compilerPC + 4); // Destroys R12 and R14
ARMReg rA = gpr.GetReg();
LDR(rA, R9, STRUCT_OFF(PowerPC::ppcState, Exceptions));
ORR(rA, rA, EXCEPTION_SYSCALL);
STR(R9, rA, STRUCT_OFF(PowerPC::ppcState, Exceptions));
gpr.Unlock(rA);

WriteExceptionExit();
}

void JitArm::rfi(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Branch)

gpr.Flush();
fpr.Flush();

// See Interpreter rfi for details
const u32 mask = 0x87C0FFFF;
const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13]
// MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13;
// R0 = MSR location
// R1 = MSR contents
// R2 = Mask
// R3 = Mask
ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();
ARMReg rC = gpr.GetReg();
ARMReg rD = gpr.GetReg();
MOVI2R(rA, (u32)&MSR);
MOVI2R(rB, (~mask) & clearMSR13);
MOVI2R(rC, mask & clearMSR13);

LDR(rD, rA);

AND(rD, rD, rB); // rD = Masked MSR
STR(rA, rD);

MOVI2R(rB, (u32)&SRR1);
LDR(rB, rB); // rB contains SRR1 here

AND(rB, rB, rC); // rB contains masked SRR1 here
ORR(rB, rD, rB); // rB = Masked MSR OR masked SRR1

STR(rA, rB); // STR rB in to rA

MOVI2R(rA, (u32)&SRR0);
LDR(rA, rA);

gpr.Unlock(rB, rC, rD);
WriteRfiExitDestInR(rA); // rA gets unlocked here
//AND(32, M(&MSR), Imm32((~mask) & clearMSR13));
//MOV(32, R(EAX), M(&SRR1));
//AND(32, R(EAX), Imm32(mask & clearMSR13));
//OR(32, M(&MSR), R(EAX));
// NPC = SRR0;
//MOV(32, R(EAX), M(&SRR0));
//WriteRfiExitDestInEAX();
}

void JitArm::bx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Branch)
// We must always process the following sentence
// even if the blocks are merged by PPCAnalyst::Flatten().
if (inst.LK)
ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);

// If this is not the last instruction of a block,
// we will skip the rest process.
// Because PPCAnalyst::Flatten() merged the blocks.
if (!js.isLastInstruction) {
return;
}

gpr.Flush();
fpr.Flush();

u32 destination;
if (inst.AA)
destination = SignExt26(inst.LI << 2);
else
destination = js.compilerPC + SignExt26(inst.LI << 2);
#ifdef ACID_TEST
// TODO: Not implemented yet.
//if (inst.LK)
//AND(32, M(&PowerPC::ppcState.cr), Imm32(~(0xFF000000)));
#endif
if (destination == js.compilerPC)
{
//PanicAlert("Idle loop detected at %08x", destination);
// CALL(ProtectFunction(&CoreTiming::Idle, 0));
// JMP(Asm::testExceptions, true);
// make idle loops go faster
js.downcountAmount += 8;
}
WriteExit(destination, 0);
}

void JitArm::bcx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Branch)
// USES_CR
_assert_msg_(DYNA_REC, js.isLastInstruction, "bcx not last instruction of block");

gpr.Flush();
fpr.Flush();

ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();
FixupBranch pCTRDontBranch;
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
{
MOVI2R(rA, (u32)&CTR);
LDR(rB, rA);
SUBS(rB, rB, 1);
STR(rA, rB);

//SUB(32, M(&CTR), Imm8(1));
if (inst.BO & BO_BRANCH_IF_CTR_0)
pCTRDontBranch = B_CC(CC_NEQ);
else
pCTRDontBranch = B_CC(CC_EQ);
}

FixupBranch pConditionDontBranch;
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
{
LDRB(rA, R9, STRUCT_OFF(PowerPC::ppcState, cr_fast) + (inst.BI >> 2));
TST(rA, 8 >> (inst.BI & 3));

//TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
pConditionDontBranch = B_CC(CC_EQ); // Zero
else
pConditionDontBranch = B_CC(CC_NEQ); // Not Zero
}
gpr.Unlock(rA, rB);
if (inst.LK)
ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4); // Careful, destroys R14, R12

u32 destination;
if(inst.AA)
destination = SignExt16(inst.BD << 2);
else
destination = js.compilerPC + SignExt16(inst.BD << 2);
WriteExit(destination, 0);

if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
SetJumpTarget( pConditionDontBranch );
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
SetJumpTarget( pCTRDontBranch );

WriteExit(js.compilerPC + 4, 1);
}
void JitArm::bcctrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Branch)

gpr.Flush();
fpr.Flush();

// bcctrx doesn't decrement and/or test CTR
_dbg_assert_msg_(POWERPC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!");

if (inst.BO_2 & BO_DONT_CHECK_CONDITION)
{
// BO_2 == 1z1zz -> b always

//NPC = CTR & 0xfffffffc;
if(inst.LK_3)
ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();
MOVI2R(rA, (u32)&CTR);
MVN(rB, 0x3); // 0xFFFFFFFC
LDR(rA, rA);
AND(rA, rA, rB);
gpr.Unlock(rB);
WriteExitDestInR(rA);
}
else
{
// Rare condition seen in (just some versions of?) Nintendo's NES Emulator

// BO_2 == 001zy -> b if false
// BO_2 == 011zy -> b if true
ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();

LDRB(rA, R9, STRUCT_OFF(PowerPC::ppcState, cr_fast) + (inst.BI >> 2));
TST(rA, 8 >> (inst.BI & 3));
CCFlags branch;
if (inst.BO_2 & BO_BRANCH_IF_TRUE)
branch = CC_EQ;
else
branch = CC_NEQ;
FixupBranch b = B_CC(branch);

MOVI2R(rA, (u32)&CTR);
LDR(rA, rA);
MVN(rB, 0x3); // 0xFFFFFFFC
AND(rA, rA, rB);

if (inst.LK_3){
ARMReg rC = gpr.GetReg(false);
u32 Jumpto = js.compilerPC + 4;
MOVI2R(rB, (u32)&LR);
MOVI2R(rC, Jumpto);
STR(rB, rC);
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
}
gpr.Unlock(rB); // rA gets unlocked in WriteExitDestInR
WriteExitDestInR(rA);

SetJumpTarget(b);
WriteExit(js.compilerPC + 4, 1);
}
}
void JitArm::bclrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Branch)
if (!js.isLastInstruction &&
(inst.BO & (1 << 4)) && (inst.BO & (1 << 2))) {
if (inst.LK)
{
ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
}
return;
}
gpr.Flush();
fpr.Flush();

ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();
FixupBranch pCTRDontBranch;
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
{
MOVI2R(rA, (u32)&CTR);
LDR(rB, rA);
SUBS(rB, rB, 1);
STR(rA, rB);

//SUB(32, M(&CTR), Imm8(1));
if (inst.BO & BO_BRANCH_IF_CTR_0)
pCTRDontBranch = B_CC(CC_NEQ);
else
pCTRDontBranch = B_CC(CC_EQ);
}

FixupBranch pConditionDontBranch;
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
{
LDRB(rA, R9, STRUCT_OFF(PowerPC::ppcState, cr_fast) + (inst.BI >> 2));
TST(rA, 8 >> (inst.BI & 3));
//TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
pConditionDontBranch = B_CC(CC_EQ); // Zero
else
pConditionDontBranch = B_CC(CC_NEQ); // Not Zero
}

// This below line can be used to prove that blr "eats flags" in practice.
// This observation will let us do a lot of fun observations.
#ifdef ACID_TEST
// TODO: Not yet implemented
// AND(32, M(&PowerPC::ppcState.cr), Imm32(~(0xFF000000)));
#endif

//MOV(32, R(EAX), M(&LR));
//AND(32, R(EAX), Imm32(0xFFFFFFFC));
MOVI2R(rA, (u32)&LR);
MVN(rB, 0x3); // 0xFFFFFFFC
LDR(rA, rA);
AND(rA, rA, rB);
if (inst.LK){
ARMReg rC = gpr.GetReg(false);
u32 Jumpto = js.compilerPC + 4;
MOVI2R(rB, (u32)&LR);
MOVI2R(rC, Jumpto);
STR(rB, rC);
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
}
gpr.Unlock(rB); // rA gets unlocked in WriteExitDestInR
WriteExitDestInR(rA);

if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
SetJumpTarget( pConditionDontBranch );
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
SetJumpTarget( pCTRDontBranch );
WriteExit(js.compilerPC + 4, 1);
}
80 changes: 80 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp
@@ -0,0 +1,80 @@
// 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 "Thunk.h"

#include "../../Core.h"
#include "../PowerPC.h"
#include "../../ConfigManager.h"
#include "../../CoreTiming.h"
#include "../PPCTables.h"
#include "ArmEmitter.h"
#include "../../HW/Memmap.h"


#include "Jit.h"
#include "JitRegCache.h"
#include "JitFPRCache.h"
#include "JitAsm.h"

void JitArm::Helper_UpdateCR1(ARMReg value)
{
// Should just update exception flags, not do any compares.
PanicAlert("CR1");
}

void JitArm::fabsx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)

ARMReg vD = fpr.R0(inst.FD);
ARMReg vB = fpr.R0(inst.FB);

VABS(vD, vB);

if (inst.Rc) Helper_UpdateCR1(vD);
}

void JitArm::faddx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)

ARMReg vD = fpr.R0(inst.FD);
ARMReg vA = fpr.R0(inst.FA);
ARMReg vB = fpr.R0(inst.FB);

VADD(vD, vA, vB);
if (inst.Rc) Helper_UpdateCR1(vD);
}

void JitArm::fmrx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(FloatingPoint)
Default(inst); return;

ARMReg vD = fpr.R0(inst.FD);
ARMReg vB = fpr.R0(inst.FB);

VMOV(vD, vB);

if (inst.Rc) Helper_UpdateCR1(vD);
}

297 changes: 297 additions & 0 deletions Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Integer.cpp
@@ -0,0 +1,297 @@
// 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 "Thunk.h"

#include "../../Core.h"
#include "../PowerPC.h"
#include "../../CoreTiming.h"
#include "../PPCTables.h"
#include "ArmEmitter.h"

#include "Jit.h"
#include "JitRegCache.h"
#include "JitAsm.h"
extern u32 Helper_Mask(u8 mb, u8 me);
// ADDI and RLWINMX broken for now

// Assumes that Sign and Zero flags were set by the last operation. Preserves all flags and registers.
// Jit64 ComputerRC is signed
// JIT64 GenerateRC is unsigned
void JitArm::GenerateRC(int cr) {
ARMReg rB = gpr.GetReg();

MOV(rB, 0x4); // Result > 0
SetCC(CC_EQ); MOV(rB, 0x2); // Result == 0
SetCC(CC_MI); MOV(rB, 0x8); // Result < 0
SetCC();

STRB(R9, rB, STRUCT_OFF(PowerPC::ppcState, cr_fast) + cr);
gpr.Unlock(rB);
}
void JitArm::ComputeRC(int cr) {
ARMReg rB = gpr.GetReg();

MOV(rB, 0x2); // Result == 0
SetCC(CC_LT); MOV(rB, 0x8); // Result < 0
SetCC(CC_GT); MOV(rB, 0x4); // Result > 0
SetCC();

STRB(R9, rB, STRUCT_OFF(PowerPC::ppcState, cr_fast) + cr);
gpr.Unlock(rB);
}

void JitArm::addi(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RD = gpr.R(inst.RD);

if (inst.RA)
{
ARMReg rA = gpr.GetReg(false);
ARMReg RA = gpr.R(inst.RA);
MOVI2R(rA, (u32)inst.SIMM_16);
ADD(RD, RA, rA);
}
else
MOVI2R(RD, inst.SIMM_16);
}
void JitArm::addis(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RD = gpr.R(inst.RD);
if (inst.RA)
{
ARMReg rA = gpr.GetReg(false);
ARMReg RA = gpr.R(inst.RA);
MOVI2R(rA, inst.SIMM_16 << 16);
ADD(RD, RA, rA);
}
else
MOVI2R(RD, inst.SIMM_16 << 16);
}
void JitArm::addx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RA = gpr.R(inst.RA);
ARMReg RB = gpr.R(inst.RB);
ARMReg RD = gpr.R(inst.RD);
ADDS(RD, RA, RB);
if (inst.Rc) ComputeRC();
}
// Wrong - 28/10/2012
void JitArm::mulli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

Default(inst); return;
ARMReg RA = gpr.R(inst.RA);
ARMReg RD = gpr.R(inst.RD);
ARMReg rA = gpr.GetReg();
MOVI2R(rA, inst.SIMM_16);
MUL(RD, RA, rA);
gpr.Unlock(rA);
}
void JitArm::ori(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RA = gpr.R(inst.RA);
ARMReg RS = gpr.R(inst.RS);
ARMReg rA = gpr.GetReg();
MOVI2R(rA, inst.UIMM);
ORR(RA, RS, rA);
gpr.Unlock(rA);
}
void JitArm::oris(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RA = gpr.R(inst.RA);
ARMReg RS = gpr.R(inst.RS);
ARMReg rA = gpr.GetReg();
MOVI2R(rA, inst.UIMM << 16);
ORR(RA, RS, rA);
gpr.Unlock(rA);
}
void JitArm::orx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg rA = gpr.R(inst.RA);
ARMReg rS = gpr.R(inst.RS);
ARMReg rB = gpr.R(inst.RB);
ORRS(rA, rS, rB);
if (inst.Rc)
ComputeRC();
}

void JitArm::extshx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
ARMReg RA, RS;
RA = gpr.R(inst.RA);
RS = gpr.R(inst.RS);
SXTH(RA, RS);
if (inst.Rc){
CMP(RA, 0);
ComputeRC();
}
}
void JitArm::extsbx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)
ARMReg RA, RS;
RA = gpr.R(inst.RA);
RS = gpr.R(inst.RS);
SXTB(RA, RS);
if (inst.Rc){
CMP(RA, 0);
ComputeRC();
}
}
void JitArm::cmp (UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RA = gpr.R(inst.RA);
ARMReg RB = gpr.R(inst.RB);
int crf = inst.CRFD;
CMP(RA, RB);
ComputeRC(crf);
}
void JitArm::cmpi(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RA = gpr.R(inst.RA);
ARMReg rA = gpr.GetReg();
int crf = inst.CRFD;
MOVI2R(rA, inst.SIMM_16);
CMP(RA, rA);
gpr.Unlock(rA);
ComputeRC(crf);
}
void JitArm::cmpli(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

ARMReg RA = gpr.R(inst.RA);
ARMReg rA = gpr.GetReg();
int crf = inst.CRFD;
MOVI2R(rA, (u32)inst.UIMM);
CMP(RA, rA);

// Unsigned GenerateRC()

MOV(rA, 0x2); // Result == 0
SetCC(CC_LO); MOV(rA, 0x8); // Result < 0
SetCC(CC_HI); MOV(rA, 0x4); // Result > 0
SetCC();

STRB(R9, rA, STRUCT_OFF(PowerPC::ppcState, cr_fast) + crf);
gpr.Unlock(rA);

}
// Wrong - 27/10/2012
void JitArm::negx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

Default(inst);return;
ARMReg RA = gpr.R(inst.RA);
ARMReg RD = gpr.R(inst.RD);

RSBS(RD, RA, 0);
if (inst.Rc)
{
GenerateRC();
}
if (inst.OE)
{
BKPT(0x333);
//GenerateOverflow();
}
}
void JitArm::rlwimix(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

u32 mask = Helper_Mask(inst.MB,inst.ME);
ARMReg RA = gpr.R(inst.RA);
ARMReg RS = gpr.R(inst.RS);
ARMReg rA = gpr.GetReg();
ARMReg rB = gpr.GetReg();
MOVI2R(rA, mask);

Operand2 Shift(32 - inst.SH, ST_ROR, RS); // This rotates left, while ARM has only rotate right, so swap it.
if (inst.Rc)
{
BIC (rB, RA, rA); // RA & ~mask
AND (rA, rA, Shift);
ORRS(RA, rB, rA);
GenerateRC();
}
else
{
BIC (rB, RA, rA); // RA & ~mask
AND (rA, rA, Shift);
ORR(RA, rB, rA);
}
gpr.Unlock(rA, rB);
}
void JitArm::rlwinmx(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(Integer)

u32 mask = Helper_Mask(inst.MB,inst.ME);
ARMReg RA = gpr.R(inst.RA);
ARMReg RS = gpr.R(inst.RS);
ARMReg rA = gpr.GetReg();
MOVI2R(rA, mask);

Operand2 Shift(32 - inst.SH, ST_ROR, RS); // This rotates left, while ARM has only rotate right, so swap it.
if (inst.Rc)
{
ANDS(RA, rA, Shift);
GenerateRC();
}
else
AND (RA, rA, Shift);
gpr.Unlock(rA);

//m_GPR[inst.RA] = _rotl(m_GPR[inst.RS],inst.SH) & mask;
}