Merge branch 'master' into new-ax-hle
This commit is contained in:
@@ -6,6 +6,11 @@ set(SRCS Src/AudioCommon.cpp
|
||||
|
||||
set(LIBS "")
|
||||
|
||||
if(ANDROID)
|
||||
set(SRCS ${SRCS} Src/OpenSLESStream.cpp)
|
||||
set(LIBS ${LIBS} OpenSLES)
|
||||
endif(ANDROID)
|
||||
|
||||
if(ALSA_FOUND)
|
||||
set(SRCS ${SRCS} Src/AlsaSoundStream.cpp)
|
||||
set(LIBS ${LIBS} ${ALSA_LIBRARIES})
|
||||
|
||||
@@ -34,7 +34,7 @@ void AOSound::SoundLoop()
|
||||
format.channels = 2;
|
||||
format.rate = m_mixer->GetSampleRate();
|
||||
format.byte_format = AO_FMT_LITTLE;
|
||||
|
||||
|
||||
device = ao_open_live(default_driver, &format, NULL /* no options */);
|
||||
if (!device)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ void AOSound::SoundLoop()
|
||||
while (!threadData)
|
||||
{
|
||||
m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2);
|
||||
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(soundCriticalSection);
|
||||
ao_play(device, (char*)realtimeBuffer, numBytesToRender);
|
||||
@@ -62,7 +62,7 @@ void AOSound::SoundLoop()
|
||||
bool AOSound::Start()
|
||||
{
|
||||
memset(realtimeBuffer, 0, sizeof(realtimeBuffer));
|
||||
|
||||
|
||||
thread = std::thread(std::mem_fun(&AOSound::SoundLoop), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,21 +45,21 @@ public:
|
||||
AOSound(CMixer *mixer) : SoundStream(mixer) {}
|
||||
|
||||
virtual ~AOSound();
|
||||
|
||||
|
||||
virtual bool Start();
|
||||
|
||||
|
||||
virtual void SoundLoop();
|
||||
|
||||
|
||||
virtual void Stop();
|
||||
|
||||
|
||||
static bool isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual bool usesMixer() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual void Update();
|
||||
|
||||
#else
|
||||
|
||||
@@ -88,7 +88,7 @@ bool AlsaSound::AlsaInit()
|
||||
snd_pcm_hw_params_t *hwparams;
|
||||
snd_pcm_uframes_t buffer_size,buffer_size_max;
|
||||
unsigned int periods;
|
||||
|
||||
|
||||
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if (err < 0)
|
||||
{
|
||||
@@ -97,7 +97,7 @@ bool AlsaSound::AlsaInit()
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_alloca(&hwparams);
|
||||
|
||||
|
||||
err = snd_pcm_hw_params_any(handle, hwparams);
|
||||
if (err < 0)
|
||||
{
|
||||
@@ -111,8 +111,8 @@ bool AlsaSound::AlsaInit()
|
||||
ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
|
||||
|
||||
err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
|
||||
if (err < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err));
|
||||
@@ -126,14 +126,14 @@ bool AlsaSound::AlsaInit()
|
||||
ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = snd_pcm_hw_params_set_channels(handle, hwparams, 2);
|
||||
|
||||
err = snd_pcm_hw_params_set_channels(handle, hwparams, 2);
|
||||
if (err < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
periods = BUFFER_SIZE_MAX / FRAME_COUNT_MIN;
|
||||
err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, &dir);
|
||||
if (err < 0)
|
||||
@@ -153,10 +153,10 @@ bool AlsaSound::AlsaInit()
|
||||
err = snd_pcm_hw_params(handle, hwparams);
|
||||
if (err < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err));
|
||||
ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
|
||||
if (err < 0)
|
||||
{
|
||||
@@ -176,10 +176,10 @@ bool AlsaSound::AlsaInit()
|
||||
frames_to_deliver = buffer_size / periods;
|
||||
//limit the minimum size. pulseaudio advertises a minimum of 32 samples.
|
||||
if (frames_to_deliver < FRAME_COUNT_MIN)
|
||||
frames_to_deliver = FRAME_COUNT_MIN;
|
||||
frames_to_deliver = FRAME_COUNT_MIN;
|
||||
//it is probably a bad idea to try to send more than one buffer of data
|
||||
if ((unsigned int)frames_to_deliver > buffer_size)
|
||||
frames_to_deliver = buffer_size;
|
||||
frames_to_deliver = buffer_size;
|
||||
NOTICE_LOG(AUDIO, "ALSA gave us a %ld sample \"hardware\" buffer with %d periods. Will send %d samples per fragments.\n", buffer_size, periods, frames_to_deliver);
|
||||
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
@@ -187,21 +187,21 @@ bool AlsaSound::AlsaInit()
|
||||
err = snd_pcm_sw_params_current(handle, swparams);
|
||||
if (err < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err));
|
||||
ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U);
|
||||
if (err < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err));
|
||||
ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
err = snd_pcm_sw_params(handle, swparams);
|
||||
if (err < 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err));
|
||||
ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "CoreAudioSoundStream.h"
|
||||
#include "OpenALStream.h"
|
||||
#include "PulseAudioStream.h"
|
||||
#include "OpenSLESStream.h"
|
||||
#include "../../Core/Src/Movie.h"
|
||||
#include "../../Core/Src/ConfigManager.h"
|
||||
|
||||
@@ -55,7 +56,8 @@ namespace AudioCommon
|
||||
soundStream = new CoreAudioSound(mixer);
|
||||
else if (backend == BACKEND_PULSEAUDIO && PulseAudio::isValid())
|
||||
soundStream = new PulseAudio(mixer);
|
||||
|
||||
else if (backend == BACKEND_OPENSLES && OpenSLESStream::isValid())
|
||||
soundStream = new OpenSLESStream(mixer);
|
||||
if (soundStream != NULL)
|
||||
{
|
||||
UpdateSoundStream();
|
||||
@@ -116,7 +118,8 @@ namespace AudioCommon
|
||||
backends.push_back(BACKEND_PULSEAUDIO);
|
||||
if (OpenALStream::isValid())
|
||||
backends.push_back(BACKEND_OPENAL);
|
||||
|
||||
if (OpenSLESStream::isValid())
|
||||
backends.push_back(BACKEND_OPENSLES);
|
||||
return backends;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,19 +30,19 @@ class CoreAudioSound : public SoundStream
|
||||
public:
|
||||
CoreAudioSound(CMixer *mixer);
|
||||
virtual ~CoreAudioSound();
|
||||
|
||||
|
||||
virtual bool Start();
|
||||
virtual void SetVolume(int volume);
|
||||
virtual void SoundLoop();
|
||||
virtual void Stop();
|
||||
|
||||
|
||||
static bool isValid() {
|
||||
return true;
|
||||
}
|
||||
virtual bool usesMixer() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual void Update();
|
||||
|
||||
private:
|
||||
|
||||
@@ -130,15 +130,15 @@ returns 0 if OK, -1 if fail
|
||||
*/
|
||||
float* design_fir(unsigned int *n, float* fc, float opt)
|
||||
{
|
||||
unsigned int o = *n & 1; // Indicator for odd filter length
|
||||
unsigned int end = ((*n + 1) >> 1) - o; // Loop end
|
||||
unsigned int i; // Loop index
|
||||
unsigned int o = *n & 1; // Indicator for odd filter length
|
||||
unsigned int end = ((*n + 1) >> 1) - o; // Loop end
|
||||
unsigned int i; // Loop index
|
||||
|
||||
float k1 = 2 * float(M_PI); // 2*pi*fc1
|
||||
float k2 = 0.5f * (float)(1 - o);// Constant used if the filter has even length
|
||||
float g = 0.0f; // Gain
|
||||
float t1; // Temporary variables
|
||||
float fc1; // Cutoff frequencies
|
||||
float k1 = 2 * float(M_PI); // 2*pi*fc1
|
||||
float k2 = 0.5f * (float)(1 - o); // Constant used if the filter has even length
|
||||
float g = 0.0f; // Gain
|
||||
float t1; // Temporary variables
|
||||
float fc1; // Cutoff frequencies
|
||||
|
||||
// Sanity check
|
||||
if(*n==0) return NULL;
|
||||
@@ -232,92 +232,92 @@ float passive_lock(float x)
|
||||
|
||||
void matrix_decode(const float *in, const int k, const int il,
|
||||
const int ir, bool decode_rear,
|
||||
const int dlbuflen,
|
||||
float l_fwr, float r_fwr,
|
||||
float lpr_fwr, float lmr_fwr,
|
||||
float *adapt_l_gain, float *adapt_r_gain,
|
||||
float *adapt_lpr_gain, float *adapt_lmr_gain,
|
||||
float *lf, float *rf, float *lr,
|
||||
float *rr, float *cf)
|
||||
const int _dlbuflen,
|
||||
float _l_fwr, float _r_fwr,
|
||||
float _lpr_fwr, float _lmr_fwr,
|
||||
float *_adapt_l_gain, float *_adapt_r_gain,
|
||||
float *_adapt_lpr_gain, float *_adapt_lmr_gain,
|
||||
float *_lf, float *_rf, float *_lr,
|
||||
float *_rr, float *_cf)
|
||||
{
|
||||
static const float M9_03DB = 0.3535533906f;
|
||||
static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */
|
||||
static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */
|
||||
static const float MATAGCTRIG = 8.0f; /* (Fuzzy) AGC trigger */
|
||||
static const float MATAGCDECAY = 1.0f; /* AGC baseline decay rate (1/samp.) */
|
||||
static const float MATCOMPGAIN = 0.37f; /* Cross talk compensation gain, 0.50 - 0.55 is full cancellation. */
|
||||
|
||||
const int kr = (k + olddelay) % dlbuflen;
|
||||
float l_gain = (l_fwr + r_fwr) / (1 + l_fwr + l_fwr);
|
||||
float r_gain = (l_fwr + r_fwr) / (1 + r_fwr + r_fwr);
|
||||
/* The 2nd axis has strong gain fluctuations, and therefore require
|
||||
limits. The factor corresponds to the 1 / amplification of (Lt
|
||||
- Rt) when (Lt, Rt) is strongly correlated. (e.g. during
|
||||
dialogues). It should be bigger than -12 dB to prevent
|
||||
distortion. */
|
||||
float lmr_lim_fwr = lmr_fwr > M9_03DB * lpr_fwr ? lmr_fwr : M9_03DB * lpr_fwr;
|
||||
float lpr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lpr_fwr + lpr_fwr);
|
||||
float lmr_gain = (lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
|
||||
float lmr_unlim_gain = (lpr_fwr + lmr_fwr) / (1 + lmr_fwr + lmr_fwr);
|
||||
const int kr = (k + olddelay) % _dlbuflen;
|
||||
float l_gain = (_l_fwr + _r_fwr) / (1 + _l_fwr + _l_fwr);
|
||||
float r_gain = (_l_fwr + _r_fwr) / (1 + _r_fwr + _r_fwr);
|
||||
// The 2nd axis has strong gain fluctuations, and therefore require
|
||||
// limits. The factor corresponds to the 1 / amplification of (Lt
|
||||
// - Rt) when (Lt, Rt) is strongly correlated. (e.g. during
|
||||
// dialogues). It should be bigger than -12 dB to prevent
|
||||
// distortion.
|
||||
float lmr_lim_fwr = _lmr_fwr > M9_03DB * _lpr_fwr ? _lmr_fwr : M9_03DB * _lpr_fwr;
|
||||
float lpr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + _lpr_fwr + _lpr_fwr);
|
||||
float lmr_gain = (_lpr_fwr + lmr_lim_fwr) / (1 + lmr_lim_fwr + lmr_lim_fwr);
|
||||
float lmr_unlim_gain = (_lpr_fwr + _lmr_fwr) / (1 + _lmr_fwr + _lmr_fwr);
|
||||
float lpr, lmr;
|
||||
float l_agc, r_agc, lpr_agc, lmr_agc;
|
||||
float f, d_gain, c_gain, c_agc_cfk;
|
||||
|
||||
/*** AXIS NO. 1: (Lt, Rt) -> (C, Ls, Rs) ***/
|
||||
/* AGC adaption */
|
||||
d_gain = (fabs(l_gain - *adapt_l_gain) + fabs(r_gain - *adapt_r_gain)) * 0.5f;
|
||||
d_gain = (fabs(l_gain - *_adapt_l_gain) + fabs(r_gain - *_adapt_r_gain)) * 0.5f;
|
||||
f = d_gain * (1.0f / MATAGCTRIG);
|
||||
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
|
||||
*adapt_l_gain = (1 - f) * *adapt_l_gain + f * l_gain;
|
||||
*adapt_r_gain = (1 - f) * *adapt_r_gain + f * r_gain;
|
||||
*_adapt_l_gain = (1 - f) * *_adapt_l_gain + f * l_gain;
|
||||
*_adapt_r_gain = (1 - f) * *_adapt_r_gain + f * r_gain;
|
||||
/* Matrix */
|
||||
l_agc = in[il] * passive_lock(*adapt_l_gain);
|
||||
r_agc = in[ir] * passive_lock(*adapt_r_gain);
|
||||
cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
|
||||
l_agc = in[il] * passive_lock(*_adapt_l_gain);
|
||||
r_agc = in[ir] * passive_lock(*_adapt_r_gain);
|
||||
_cf[k] = (l_agc + r_agc) * (float)M_SQRT1_2;
|
||||
if (decode_rear)
|
||||
{
|
||||
lr[kr] = rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
|
||||
/* Stereo rear channel is steered with the same AGC steering as
|
||||
the decoding matrix. Note this requires a fast updating AGC
|
||||
at the order of 20 ms (which is the case here). */
|
||||
lr[kr] *= (l_fwr + l_fwr) / (1 + l_fwr + r_fwr);
|
||||
rr[kr] *= (r_fwr + r_fwr) / (1 + l_fwr + r_fwr);
|
||||
_lr[kr] = _rr[kr] = (l_agc - r_agc) * (float)M_SQRT1_2;
|
||||
// Stereo rear channel is steered with the same AGC steering as
|
||||
// the decoding matrix. Note this requires a fast updating AGC
|
||||
// at the order of 20 ms (which is the case here).
|
||||
_lr[kr] *= (_l_fwr + _l_fwr) / (1 + _l_fwr + _r_fwr);
|
||||
_rr[kr] *= (_r_fwr + _r_fwr) / (1 + _l_fwr + _r_fwr);
|
||||
}
|
||||
|
||||
/*** AXIS NO. 2: (Lt + Rt, Lt - Rt) -> (L, R) ***/
|
||||
lpr = (in[il] + in[ir]) * (float)M_SQRT1_2;
|
||||
lmr = (in[il] - in[ir]) * (float)M_SQRT1_2;
|
||||
/* AGC adaption */
|
||||
d_gain = fabs(lmr_unlim_gain - *adapt_lmr_gain);
|
||||
d_gain = fabs(lmr_unlim_gain - *_adapt_lmr_gain);
|
||||
f = d_gain * (1.0f / MATAGCTRIG);
|
||||
f = MATAGCDECAY - MATAGCDECAY / (1 + f * f);
|
||||
*adapt_lpr_gain = (1 - f) * *adapt_lpr_gain + f * lpr_gain;
|
||||
*adapt_lmr_gain = (1 - f) * *adapt_lmr_gain + f * lmr_gain;
|
||||
*_adapt_lpr_gain = (1 - f) * *_adapt_lpr_gain + f * lpr_gain;
|
||||
*_adapt_lmr_gain = (1 - f) * *_adapt_lmr_gain + f * lmr_gain;
|
||||
/* Matrix */
|
||||
lpr_agc = lpr * passive_lock(*adapt_lpr_gain);
|
||||
lmr_agc = lmr * passive_lock(*adapt_lmr_gain);
|
||||
lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
|
||||
rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;
|
||||
lpr_agc = lpr * passive_lock(*_adapt_lpr_gain);
|
||||
lmr_agc = lmr * passive_lock(*_adapt_lmr_gain);
|
||||
_lf[k] = (lpr_agc + lmr_agc) * (float)M_SQRT1_2;
|
||||
_rf[k] = (lpr_agc - lmr_agc) * (float)M_SQRT1_2;
|
||||
|
||||
/*** CENTER FRONT CANCELLATION ***/
|
||||
/* A heuristic approach exploits that Lt + Rt gain contains the
|
||||
information about Lt, Rt correlation. This effectively reshapes
|
||||
the front and rear "cones" to concentrate Lt + Rt to C and
|
||||
introduce Lt - Rt in L, R. */
|
||||
// A heuristic approach exploits that Lt + Rt gain contains the
|
||||
// information about Lt, Rt correlation. This effectively reshapes
|
||||
// the front and rear "cones" to concentrate Lt + Rt to C and
|
||||
// introduce Lt - Rt in L, R.
|
||||
/* 0.67677 is the empirical lower bound for lpr_gain. */
|
||||
c_gain = 8 * (*adapt_lpr_gain - 0.67677f);
|
||||
c_gain = 8 * (*_adapt_lpr_gain - 0.67677f);
|
||||
c_gain = c_gain > 0 ? c_gain : 0;
|
||||
/* c_gain should not be too high, not even reaching full
|
||||
cancellation (~ 0.50 - 0.55 at current AGC implementation), or
|
||||
the center will sound too narrow. */
|
||||
// c_gain should not be too high, not even reaching full
|
||||
// cancellation (~ 0.50 - 0.55 at current AGC implementation), or
|
||||
// the center will sound too narrow. */
|
||||
c_gain = MATCOMPGAIN / (1 + c_gain * c_gain);
|
||||
c_agc_cfk = c_gain * cf[k];
|
||||
lf[k] -= c_agc_cfk;
|
||||
rf[k] -= c_agc_cfk;
|
||||
cf[k] += c_agc_cfk + c_agc_cfk;
|
||||
c_agc_cfk = c_gain * _cf[k];
|
||||
_lf[k] -= c_agc_cfk;
|
||||
_rf[k] -= c_agc_cfk;
|
||||
_cf[k] += c_agc_cfk + c_agc_cfk;
|
||||
}
|
||||
|
||||
void dpl2decode(float *samples, int numsamples, float *out)
|
||||
{
|
||||
static const unsigned int FWRDURATION = 240; /* FWR average duration (samples) */
|
||||
static const unsigned int FWRDURATION = 240; // FWR average duration (samples)
|
||||
static const int cfg_delay = 0;
|
||||
static const unsigned int fmt_freq = 48000;
|
||||
static const unsigned int fmt_nchannels = 2; // input channels
|
||||
|
||||
@@ -122,7 +122,7 @@ void DSound::SoundLoop()
|
||||
bool DSound::Start()
|
||||
{
|
||||
if (FAILED(DirectSoundCreate8(0, &ds, 0)))
|
||||
return false;
|
||||
return false;
|
||||
if (hWnd)
|
||||
{
|
||||
HRESULT hr = ds->SetCooperativeLevel((HWND)hWnd, DSSCL_PRIORITY);
|
||||
|
||||
@@ -31,33 +31,33 @@
|
||||
class DSound : public SoundStream
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::thread thread;
|
||||
Common::Event soundSyncEvent;
|
||||
void *hWnd;
|
||||
std::thread thread;
|
||||
Common::Event soundSyncEvent;
|
||||
void *hWnd;
|
||||
|
||||
IDirectSound8* ds;
|
||||
IDirectSoundBuffer* dsBuffer;
|
||||
|
||||
int bufferSize; //i bytes
|
||||
IDirectSound8* ds;
|
||||
IDirectSoundBuffer* dsBuffer;
|
||||
|
||||
int bufferSize; //i bytes
|
||||
int m_volume;
|
||||
|
||||
// playback position
|
||||
int currentPos;
|
||||
int lastPos;
|
||||
short realtimeBuffer[BUFSIZE / sizeof(short)];
|
||||
|
||||
inline int FIX128(int x)
|
||||
|
||||
// playback position
|
||||
int currentPos;
|
||||
int lastPos;
|
||||
short realtimeBuffer[BUFSIZE / sizeof(short)];
|
||||
|
||||
inline int FIX128(int x)
|
||||
{
|
||||
return x & (~127);
|
||||
}
|
||||
}
|
||||
|
||||
inline int ModBufferSize(int x)
|
||||
inline int ModBufferSize(int x)
|
||||
{
|
||||
return (x + bufferSize) % bufferSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool CreateBuffer();
|
||||
bool WriteDataToBuffer(DWORD dwOffset, char* soundData, DWORD dwSoundBytes);
|
||||
bool CreateBuffer();
|
||||
bool WriteDataToBuffer(DWORD dwOffset, char* soundData, DWORD dwSoundBytes);
|
||||
|
||||
public:
|
||||
DSound(CMixer *mixer, void *_hWnd = NULL)
|
||||
@@ -70,16 +70,16 @@ public:
|
||||
, hWnd(_hWnd)
|
||||
{}
|
||||
|
||||
virtual ~DSound() {}
|
||||
virtual ~DSound() {}
|
||||
|
||||
virtual bool Start();
|
||||
virtual void SoundLoop();
|
||||
virtual void SoundLoop();
|
||||
virtual void SetVolume(int volume);
|
||||
virtual void Stop();
|
||||
virtual void Stop();
|
||||
virtual void Clear(bool mute);
|
||||
static bool isValid() { return true; }
|
||||
virtual bool usesMixer() const { return true; }
|
||||
virtual void Update();
|
||||
static bool isValid() { return true; }
|
||||
virtual bool usesMixer() const { return true; }
|
||||
virtual void Update();
|
||||
|
||||
#else
|
||||
public:
|
||||
|
||||
@@ -67,7 +67,7 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||
{
|
||||
static const __m128i sr_mask =
|
||||
_mm_set_epi32(0x0C0D0E0FL, 0x08090A0BL,
|
||||
0x04050607L, 0x00010203L);
|
||||
0x04050607L, 0x00010203L);
|
||||
|
||||
for (unsigned int i = 0; i < numLeft * 2; i += 8)
|
||||
{
|
||||
@@ -99,12 +99,11 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||
if ((m_indexR2 & INDEX_MASK) == (m_indexW & INDEX_MASK)) //..if it exists
|
||||
m_indexR2 = m_indexR;
|
||||
|
||||
|
||||
s16 l1 = Common::swap16(m_buffer[m_indexR & INDEX_MASK]); //current
|
||||
s16 l2 = Common::swap16(m_buffer[m_indexR2 & INDEX_MASK]); //next
|
||||
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
|
||||
samples[i+1] = sampleL;
|
||||
|
||||
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
|
||||
samples[i+1] = sampleL;
|
||||
|
||||
s16 r1 = Common::swap16(m_buffer[(m_indexR + 1) & INDEX_MASK]); //current
|
||||
s16 r2 = Common::swap16(m_buffer[(m_indexR2 + 1) & INDEX_MASK]); //next
|
||||
int sampleR = ((r1 << 16) + (r2 - r1) * (u16)frac) >> 16;
|
||||
@@ -116,8 +115,6 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
numLeft = 0;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
|
||||
std::mutex& MixerCritical() { return m_csMixing; }
|
||||
|
||||
volatile float GetCurrentSpeed() const { return m_speed; }
|
||||
float GetCurrentSpeed() const { return m_speed; }
|
||||
void UpdateSpeed(volatile float val) { m_speed = val; }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -25,24 +25,24 @@
|
||||
|
||||
class NullSound : public SoundStream
|
||||
{
|
||||
// playback position
|
||||
short realtimeBuffer[BUF_SIZE / sizeof(short)];
|
||||
// playback position
|
||||
short realtimeBuffer[BUF_SIZE / sizeof(short)];
|
||||
|
||||
public:
|
||||
NullSound(CMixer *mixer, void *hWnd = NULL)
|
||||
: SoundStream(mixer)
|
||||
{}
|
||||
|
||||
virtual ~NullSound() {}
|
||||
|
||||
virtual ~NullSound() {}
|
||||
|
||||
virtual bool Start();
|
||||
virtual void SoundLoop();
|
||||
virtual void SoundLoop();
|
||||
virtual void SetVolume(int volume);
|
||||
virtual void Stop();
|
||||
virtual void Stop();
|
||||
virtual void Clear(bool mute);
|
||||
static bool isValid() { return true; }
|
||||
virtual bool usesMixer() const { return true; }
|
||||
virtual void Update();
|
||||
static bool isValid() { return true; }
|
||||
virtual bool usesMixer() const { return true; }
|
||||
virtual void Update();
|
||||
};
|
||||
|
||||
#endif //_NULLSOUNDSTREAM_H_
|
||||
|
||||
@@ -200,6 +200,7 @@ void OpenALStream::SoundLoop()
|
||||
u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond();
|
||||
|
||||
unsigned int numSamples = (unsigned int)num_samples_to_render;
|
||||
unsigned int minSamples = surround_capable ? 240 : 0; // DPL2 accepts 240 samples minimum (FWRDURATION)
|
||||
|
||||
numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples;
|
||||
numSamples = m_mixer->Mix(realtimeBuffer, numSamples);
|
||||
@@ -236,9 +237,15 @@ void OpenALStream::SoundLoop()
|
||||
// Adjust SETTING_SEQUENCE_MS to balance between lag vs hollow audio
|
||||
soundTouch.setSetting(SETTING_SEQUENCE_MS, (int)(1 / (rate * rate)));
|
||||
soundTouch.setTempo(rate);
|
||||
if (rate > 10)
|
||||
{
|
||||
soundTouch.clear();
|
||||
}
|
||||
}
|
||||
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS);
|
||||
if (nSamples > 0)
|
||||
|
||||
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * OAL_MAX_BUFFERS);
|
||||
|
||||
if (nSamples > minSamples)
|
||||
{
|
||||
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
|
||||
if (iBuffersFilled == 0)
|
||||
@@ -288,7 +295,6 @@ void OpenALStream::SoundLoop()
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering float32 data: %08x", err);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
if (!float32_capable)
|
||||
@@ -301,7 +307,6 @@ void OpenALStream::SoundLoop()
|
||||
stereo[i * 2 + 1] = (short)((float)sampleBuffer[i * 2 + 1] * (1 << 16));
|
||||
}
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, stereo, nSamples * 2 * 2, ulFrequency);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +321,7 @@ void OpenALStream::SoundLoop()
|
||||
if (iBuffersFilled == numBuffers)
|
||||
{
|
||||
alSourcePlay(uiSource);
|
||||
ALenum err = alGetError();
|
||||
err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err);
|
||||
@@ -328,7 +333,7 @@ void OpenALStream::SoundLoop()
|
||||
{
|
||||
// Buffer underrun occurred, resume playback
|
||||
alSourcePlay(uiSource);
|
||||
ALenum err = alGetError();
|
||||
err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err);
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
// 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/
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "Common.h"
|
||||
#include <assert.h>
|
||||
#include "OpenSLESStream.h"
|
||||
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
|
||||
// engine interfaces
|
||||
static SLObjectItf engineObject;
|
||||
static SLEngineItf engineEngine;
|
||||
static SLObjectItf outputMixObject;
|
||||
|
||||
// buffer queue player interfaces
|
||||
static SLObjectItf bqPlayerObject = NULL;
|
||||
static SLPlayItf bqPlayerPlay;
|
||||
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
||||
static SLMuteSoloItf bqPlayerMuteSolo;
|
||||
static SLVolumeItf bqPlayerVolume;
|
||||
static CMixer *g_mixer;
|
||||
#define BUFFER_SIZE 512
|
||||
#define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2)
|
||||
|
||||
// Double buffering.
|
||||
static short buffer[2][BUFFER_SIZE];
|
||||
static int curBuffer = 0;
|
||||
|
||||
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
|
||||
assert(bq == bqPlayerBufferQueue);
|
||||
assert(NULL == context);
|
||||
|
||||
short *nextBuffer = buffer[curBuffer];
|
||||
int nextSize = sizeof(buffer[0]);
|
||||
|
||||
SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
|
||||
|
||||
// Comment from sample code:
|
||||
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
||||
// which for this code example would indicate a programming error
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
curBuffer ^= 1; // Switch buffer
|
||||
// Render to the fresh buffer
|
||||
g_mixer->Mix(reinterpret_cast<short *>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES);
|
||||
}
|
||||
bool OpenSLESStream::Start()
|
||||
{
|
||||
SLresult result;
|
||||
// create engine
|
||||
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
||||
SLDataFormat_PCM format_pcm = {
|
||||
SL_DATAFORMAT_PCM,
|
||||
2,
|
||||
SL_SAMPLINGRATE_44_1,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
|
||||
SL_BYTEORDER_LITTLEENDIAN
|
||||
};
|
||||
|
||||
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
|
||||
|
||||
// configure audio sink
|
||||
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
|
||||
SLDataSink audioSnk = {&loc_outmix, NULL};
|
||||
|
||||
// create audio player
|
||||
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
|
||||
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
|
||||
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
|
||||
&bqPlayerBufferQueue);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
|
||||
// Render and enqueue a first buffer. (or should we just play the buffer empty?)
|
||||
curBuffer = 0;
|
||||
|
||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer]));
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
return false;
|
||||
}
|
||||
curBuffer ^= 1;
|
||||
g_mixer = m_mixer;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenSLESStream::Stop()
|
||||
{
|
||||
if (bqPlayerObject != NULL) {
|
||||
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
||||
bqPlayerObject = NULL;
|
||||
bqPlayerPlay = NULL;
|
||||
bqPlayerBufferQueue = NULL;
|
||||
bqPlayerMuteSolo = NULL;
|
||||
bqPlayerVolume = NULL;
|
||||
}
|
||||
if (outputMixObject != NULL) {
|
||||
(*outputMixObject)->Destroy(outputMixObject);
|
||||
outputMixObject = NULL;
|
||||
}
|
||||
if (engineObject != NULL) {
|
||||
(*engineObject)->Destroy(engineObject);
|
||||
engineObject = NULL;
|
||||
engineEngine = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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 _OPENSLSTREAM_H_
|
||||
#define _OPENSLSTREAM_H_
|
||||
|
||||
#include "Thread.h"
|
||||
#include "SoundStream.h"
|
||||
|
||||
class OpenSLESStream : public SoundStream
|
||||
{
|
||||
#ifdef ANDROID
|
||||
public:
|
||||
OpenSLESStream(CMixer *mixer, void *hWnd = NULL)
|
||||
: SoundStream(mixer)
|
||||
{};
|
||||
|
||||
virtual ~OpenSLESStream() {};
|
||||
|
||||
virtual bool Start();
|
||||
virtual void Stop();
|
||||
static bool isValid() { return true; }
|
||||
virtual bool usesMixer() const { return true; }
|
||||
|
||||
private:
|
||||
std::thread thread;
|
||||
Common::Event soundSyncEvent;
|
||||
#else
|
||||
public:
|
||||
OpenSLESStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}
|
||||
#endif // HAVE_OPENSL
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -27,17 +27,17 @@ class SoundStream
|
||||
protected:
|
||||
|
||||
CMixer *m_mixer;
|
||||
// We set this to shut down the sound thread.
|
||||
// 0=keep playing, 1=stop playing NOW.
|
||||
volatile int threadData;
|
||||
bool m_logAudio;
|
||||
// We set this to shut down the sound thread.
|
||||
// 0=keep playing, 1=stop playing NOW.
|
||||
volatile int threadData;
|
||||
bool m_logAudio;
|
||||
WaveFileWriter g_wave_writer;
|
||||
bool m_muted;
|
||||
|
||||
public:
|
||||
SoundStream(CMixer *mixer) : m_mixer(mixer), threadData(0), m_logAudio(false), m_muted(false) {}
|
||||
virtual ~SoundStream() { delete m_mixer;}
|
||||
|
||||
|
||||
static bool isValid() { return false; }
|
||||
virtual CMixer *GetMixer() const { return m_mixer; }
|
||||
virtual bool Start() { return false; }
|
||||
|
||||
@@ -104,21 +104,21 @@ void WaveFileWriter::AddStereoSamples(const short *sample_data, u32 count)
|
||||
{
|
||||
if (!file)
|
||||
PanicAlertT("WaveFileWriter - file not open.");
|
||||
|
||||
|
||||
if (skip_silence)
|
||||
{
|
||||
bool all_zero = true;
|
||||
|
||||
|
||||
for (u32 i = 0; i < count * 2; i++)
|
||||
{
|
||||
if (sample_data[i])
|
||||
all_zero = false;
|
||||
}
|
||||
|
||||
|
||||
if (all_zero)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
file.WriteBytes(sample_data, count * 4);
|
||||
audio_size += count * 4;
|
||||
}
|
||||
@@ -134,7 +134,7 @@ void WaveFileWriter::AddStereoSamplesBE(const short *sample_data, u32 count)
|
||||
if (skip_silence)
|
||||
{
|
||||
bool all_zero = true;
|
||||
|
||||
|
||||
for (u32 i = 0; i < count * 2; i++)
|
||||
{
|
||||
if (sample_data[i])
|
||||
|
||||
@@ -95,10 +95,10 @@ void StreamingVoiceContext::OnBufferEnd(void* context)
|
||||
|
||||
if (!m_source_voice || !context)
|
||||
return;
|
||||
|
||||
|
||||
//m_sound_sync_event->Wait(); // sync
|
||||
//m_sound_sync_event->Spin(); // or tight sync
|
||||
|
||||
|
||||
m_mixer->Mix(static_cast<short*>(context), SAMPLES_PER_BUFFER);
|
||||
SubmitBuffer(static_cast<BYTE*>(context));
|
||||
}
|
||||
@@ -183,6 +183,6 @@ void XAudio2::Stop()
|
||||
m_mastering_voice->DestroyVoice();
|
||||
m_mastering_voice = nullptr;
|
||||
}
|
||||
|
||||
|
||||
m_xaudio2.reset(); // release interface
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -20,10 +18,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
|
||||
@@ -33,6 +31,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)
|
||||
|
||||
@@ -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" />
|
||||
@@ -195,15 +193,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" />
|
||||
@@ -251,6 +251,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>
|
||||
|
||||
@@ -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" />
|
||||
@@ -53,9 +50,12 @@
|
||||
<ClCompile Include="Src\Crypto\sha1.cpp">
|
||||
<Filter>Crypto</Filter>
|
||||
</ClCompile>
|
||||
<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" />
|
||||
@@ -121,6 +121,7 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\StdMutex.h" />
|
||||
<ClInclude Include="Src\StdConditionVariable.h" />
|
||||
<ClInclude Include="Src\x64ABI.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
+127
-121
@@ -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);
|
||||
DoContainer(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Do(std::deque<T>& x)
|
||||
{
|
||||
DoContainer(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Do(std::basic_string<T>& x)
|
||||
{
|
||||
DoContainer(x);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
DoVoid((void*)&x, sizeof(x));
|
||||
}
|
||||
|
||||
void Do(std::wstring &x)
|
||||
template <typename T>
|
||||
void DoPointer(T*& x, T* const base)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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<class 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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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"
|
||||
@@ -122,9 +127,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 WII_EUR_SETTING "setting-eur.txt"
|
||||
#define WII_USA_SETTING "setting-usa.txt"
|
||||
#define WII_JAP_SETTING "setting-jpn.txt"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -41,9 +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
|
||||
@@ -80,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);
|
||||
}
|
||||
@@ -93,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",
|
||||
@@ -126,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());
|
||||
@@ -148,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)
|
||||
@@ -180,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());
|
||||
@@ -196,8 +206,9 @@ bool CreateFullPath(const std::string &fullPath)
|
||||
// we're done, yay!
|
||||
if (position == fullPath.npos)
|
||||
return true;
|
||||
|
||||
std::string subPath = fullPath.substr(0, position);
|
||||
|
||||
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
|
||||
std::string const subPath(fullPath.substr(0, position + 1));
|
||||
if (!File::IsDirectory(subPath))
|
||||
File::CreateDir(subPath);
|
||||
|
||||
@@ -226,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)
|
||||
@@ -255,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",
|
||||
@@ -340,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);
|
||||
@@ -389,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;
|
||||
}
|
||||
|
||||
@@ -411,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);
|
||||
@@ -421,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;
|
||||
|
||||
@@ -470,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)
|
||||
{
|
||||
@@ -478,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());
|
||||
@@ -512,12 +528,24 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
if (IsDirectory(newPath))
|
||||
{
|
||||
if (!DeleteDirRecursively(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!File::Delete(newPath))
|
||||
{
|
||||
#ifndef _WIN32
|
||||
closedir(dirp);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -577,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;
|
||||
@@ -608,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;
|
||||
@@ -654,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;
|
||||
@@ -715,31 +744,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()
|
||||
@@ -761,11 +778,29 @@ IOFile::~IOFile()
|
||||
Close();
|
||||
}
|
||||
|
||||
IOFile::IOFile(IOFile&& other)
|
||||
: m_file(NULL), m_good(true)
|
||||
{
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
IOFile& IOFile::operator=(IOFile&& other)
|
||||
{
|
||||
IOFile((IOFile&&)other).Swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void IOFile::Swap(IOFile& other)
|
||||
{
|
||||
std::swap(m_file, other.m_file);
|
||||
std::swap(m_good, other.m_good);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -814,7 +849,7 @@ bool IOFile::Seek(s64 off, int origin)
|
||||
}
|
||||
|
||||
u64 IOFile::Tell()
|
||||
{
|
||||
{
|
||||
if (IsOpen())
|
||||
return ftello(m_file);
|
||||
else
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
// User directory indices for GetUserPath
|
||||
enum {
|
||||
@@ -150,7 +151,7 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str);
|
||||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
// and make forgetting an fclose() harder
|
||||
class IOFile : NonCopyable
|
||||
class IOFile
|
||||
{
|
||||
public:
|
||||
IOFile();
|
||||
@@ -158,6 +159,11 @@ public:
|
||||
IOFile(const std::string& filename, const char openmode[]);
|
||||
|
||||
~IOFile();
|
||||
|
||||
IOFile(IOFile&& other);
|
||||
IOFile& operator=(IOFile&& other);
|
||||
|
||||
void Swap(IOFile& other);
|
||||
|
||||
bool Open(const std::string& filename, const char openmode[]);
|
||||
bool Close();
|
||||
@@ -212,6 +218,7 @@ public:
|
||||
void Clear() { m_good = true; std::clearerr(m_file); }
|
||||
|
||||
private:
|
||||
IOFile(const IOFile&) /*= delete*/;
|
||||
IOFile& operator=(const IOFile&) /*= delete*/;
|
||||
|
||||
std::FILE* m_file;
|
||||
@@ -220,4 +227,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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
//----------
|
||||
// body
|
||||
|
||||
const u64 * blocks = (const u64 *)(data);
|
||||
const u64 * blocks = (const u64 *)(data);
|
||||
|
||||
for(int i = 0; i < nblocks; i+=Step)
|
||||
{
|
||||
u64 k1 = getblock(blocks,i*2+0);
|
||||
u64 k2 = getblock(blocks,i*2+1);
|
||||
for(int i = 0; i < nblocks; i+=Step)
|
||||
{
|
||||
u64 k1 = getblock(blocks,i*2+0);
|
||||
u64 k2 = getblock(blocks,i*2+1);
|
||||
|
||||
bmix64(h1,h2,k1,k2,c1,c2);
|
||||
}
|
||||
bmix64(h1,h2,k1,k2,c1,c2);
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const u8 * tail = (const u8*)(data + nblocks*16);
|
||||
const u8 * tail = (const u8*)(data + nblocks*16);
|
||||
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
|
||||
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;
|
||||
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);
|
||||
};
|
||||
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
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
@@ -60,15 +63,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_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE");
|
||||
@@ -79,7 +82,7 @@ LogManager::LogManager()
|
||||
m_Log[LogTypes::WII_IPC_STM] = new LogContainer("WII_IPC_STM", "WII IPC STM");
|
||||
m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET");
|
||||
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");
|
||||
|
||||
@@ -113,6 +116,7 @@ LogManager::~LogManager()
|
||||
|
||||
delete m_fileLog;
|
||||
delete m_consoleLog;
|
||||
delete m_debuggerLog;
|
||||
}
|
||||
|
||||
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
|
||||
@@ -132,7 +136,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);
|
||||
}
|
||||
|
||||
@@ -181,7 +187,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <set>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_MESSAGES 8000
|
||||
#define MAX_MESSAGES 8000
|
||||
#define MAX_MSGLEN 1024
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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,16 +38,47 @@ 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);
|
||||
unlink(ram_temp_file);
|
||||
ftruncate(fd, size);
|
||||
if (ftruncate(fd, size) < 0)
|
||||
ERROR_LOG(MEMMAP, "Failed to allocate low memory space");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -117,8 +117,12 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
void* ptr = _aligned_malloc(size,alignment);
|
||||
#else
|
||||
void* ptr = NULL;
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
;
|
||||
#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,
|
||||
@@ -151,9 +155,7 @@ void FreeAlignedMemory(void* ptr)
|
||||
if (ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
_aligned_free(ptr);
|
||||
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -69,7 +79,8 @@ std::string StringFromFormat(const char* format, ...)
|
||||
delete[] buf;
|
||||
#else
|
||||
va_start(args, format);
|
||||
vasprintf(&buf, format, args);
|
||||
if (vasprintf(&buf, format, args) < 0)
|
||||
ERROR_LOG(COMMON, "Unable to allocate memory for string");
|
||||
va_end(args);
|
||||
|
||||
std::string temp = buf;
|
||||
@@ -262,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,
|
||||
/* 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 */ -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,
|
||||
/* 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 */ -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,
|
||||
/* 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 */ -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
|
||||
/* 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)
|
||||
@@ -302,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;
|
||||
@@ -374,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
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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__ (
|
||||
@@ -205,14 +209,7 @@ void CPUInfo::Detect()
|
||||
// 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 (HTT) sum += StringFromFormat(" (%i logical threads per physical core)", logical_cpu_count);
|
||||
}
|
||||
std::string sum(cpu_string);
|
||||
if (bSSE) sum += ", SSE";
|
||||
if (bSSE2) sum += ", SSE2";
|
||||
if (bSSE3) sum += ", SSE3";
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -152,6 +151,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
|
||||
@@ -161,6 +161,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
|
||||
@@ -185,12 +194,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)
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -331,7 +331,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" />
|
||||
@@ -377,6 +377,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" />
|
||||
@@ -386,10 +387,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>
|
||||
@@ -559,6 +560,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" />
|
||||
|
||||
@@ -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" />
|
||||
@@ -559,6 +558,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" />
|
||||
@@ -1036,6 +1038,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" />
|
||||
|
||||
@@ -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
|
||||
@@ -90,9 +90,7 @@ bool CBoot::Boot_WiiWAD(const char* _pFilename)
|
||||
u64 titleID = ContentLoader.GetTitleID();
|
||||
// create data directory
|
||||
File::CreateFullPath(Common::GetTitleDataPath(titleID));
|
||||
|
||||
if (titleID == TITLEID_SYSMENU)
|
||||
HLE_IPC_CreateVirtualFATFilesystem();
|
||||
|
||||
// setup wii mem
|
||||
if (!SetupWiiMemory(ContentLoader.GetCountry()))
|
||||
return false;
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace BootManager
|
||||
// Apply fire liberally
|
||||
struct ConfigCache
|
||||
{
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bMMUBAT,
|
||||
bVBeam, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bDisableWiimoteSpeaker, bHLE_BS2;
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
|
||||
bVBeam, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
||||
int iTLBHack, iCPUCore;
|
||||
std::string strBackend;
|
||||
};
|
||||
@@ -92,13 +92,13 @@ bool BootCore(const std::string& _rFilename)
|
||||
config_cache.iCPUCore = StartUp.iCPUCore;
|
||||
config_cache.bEnableFPRF = StartUp.bEnableFPRF;
|
||||
config_cache.bMMU = StartUp.bMMU;
|
||||
config_cache.bMMUBAT = StartUp.bMMUBAT;
|
||||
config_cache.bDCBZOFF = StartUp.bDCBZOFF;
|
||||
config_cache.iTLBHack = StartUp.iTLBHack;
|
||||
config_cache.bVBeam = StartUp.bVBeam;
|
||||
config_cache.bSyncGPU = StartUp.bSyncGPU;
|
||||
config_cache.bFastDiscSpeed = StartUp.bFastDiscSpeed;
|
||||
config_cache.bMergeBlocks = StartUp.bMergeBlocks;
|
||||
config_cache.bDSPHLE = StartUp.bDSPHLE;
|
||||
config_cache.bDisableWiimoteSpeaker = StartUp.bDisableWiimoteSpeaker;
|
||||
config_cache.strBackend = StartUp.m_strVideoBackend;
|
||||
config_cache.bHLE_BS2 = StartUp.bHLE_BS2;
|
||||
|
||||
@@ -107,13 +107,13 @@ bool BootCore(const std::string& _rFilename)
|
||||
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
|
||||
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
|
||||
game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU);
|
||||
game_ini.Get("Core", "BAT", &StartUp.bMMUBAT, StartUp.bMMUBAT);
|
||||
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
|
||||
game_ini.Get("Core", "DCBZ", &StartUp.bDCBZOFF, StartUp.bDCBZOFF);
|
||||
game_ini.Get("Core", "VBeam", &StartUp.bVBeam, StartUp.bVBeam);
|
||||
game_ini.Get("Core", "SyncGPU", &StartUp.bSyncGPU, StartUp.bSyncGPU);
|
||||
game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
|
||||
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
|
||||
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
|
||||
game_ini.Get("Wii", "DisableWiimoteSpeaker",&StartUp.bDisableWiimoteSpeaker, StartUp.bDisableWiimoteSpeaker);
|
||||
game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str());
|
||||
game_ini.Get("Core", "CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore);
|
||||
game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2);
|
||||
@@ -167,13 +167,13 @@ void Stop()
|
||||
StartUp.iCPUCore = config_cache.iCPUCore;
|
||||
StartUp.bEnableFPRF = config_cache.bEnableFPRF;
|
||||
StartUp.bMMU = config_cache.bMMU;
|
||||
StartUp.bMMUBAT = config_cache.bMMUBAT;
|
||||
StartUp.bDCBZOFF = config_cache.bDCBZOFF;
|
||||
StartUp.iTLBHack = config_cache.iTLBHack;
|
||||
StartUp.bVBeam = config_cache.bVBeam;
|
||||
StartUp.bSyncGPU = config_cache.bSyncGPU;
|
||||
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
|
||||
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
|
||||
StartUp.bDSPHLE = config_cache.bDSPHLE;
|
||||
StartUp.bDisableWiimoteSpeaker = config_cache.bDisableWiimoteSpeaker;
|
||||
StartUp.m_strVideoBackend = config_cache.strBackend;
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
StartUp.bHLE_BS2 = config_cache.bHLE_BS2;
|
||||
|
||||
@@ -100,9 +100,6 @@ SConfig::SConfig()
|
||||
{
|
||||
// Make sure we have log manager
|
||||
LoadSettings();
|
||||
//Make sure we load any extra settings
|
||||
LoadSettingsWii();
|
||||
|
||||
}
|
||||
|
||||
void SConfig::Init()
|
||||
@@ -140,7 +137,7 @@ void SConfig::SaveSettings()
|
||||
ini.Get("General", "GCMPathes", &oldPaths, 0);
|
||||
for (int i = numPaths; i < oldPaths; i++)
|
||||
{
|
||||
TCHAR tmp[16];
|
||||
char tmp[16];
|
||||
sprintf(tmp, "GCMPath%i", i);
|
||||
ini.DeleteKey("General", tmp);
|
||||
}
|
||||
@@ -149,7 +146,7 @@ void SConfig::SaveSettings()
|
||||
|
||||
for (int i = 0; i < numPaths; i++)
|
||||
{
|
||||
TCHAR tmp[16];
|
||||
char tmp[16];
|
||||
sprintf(tmp, "GCMPath%i", i);
|
||||
ini.Set("General", tmp, m_ISOFolder[i]);
|
||||
}
|
||||
@@ -244,6 +241,8 @@ void SConfig::SaveSettings()
|
||||
ini.Set("Core", "WiiSDCard", m_WiiSDCard);
|
||||
ini.Set("Core", "WiiKeyboard", m_WiiKeyboard);
|
||||
ini.Set("Core", "WiimoteReconnectOnLoad", m_WiimoteReconnectOnLoad);
|
||||
ini.Set("Core", "WiimoteContinuousScanning", m_WiimoteContinuousScanning);
|
||||
ini.Set("Core", "WiimoteEnableSpeaker", m_WiimoteEnableSpeaker);
|
||||
ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer);
|
||||
ini.Set("Core", "RunCompareClient", m_LocalCoreStartupParameter.bRunCompareClient);
|
||||
ini.Set("Core", "FrameLimit", m_Framelimit);
|
||||
@@ -285,7 +284,7 @@ void SConfig::LoadSettings()
|
||||
{
|
||||
for (int i = 0; i < numGCMPaths; i++)
|
||||
{
|
||||
TCHAR tmp[16];
|
||||
char tmp[16];
|
||||
sprintf(tmp, "GCMPath%i", i);
|
||||
std::string tmpPath;
|
||||
ini.Get("General", tmp, &tmpPath, "");
|
||||
@@ -363,7 +362,11 @@ void SConfig::LoadSettings()
|
||||
|
||||
// Core
|
||||
ini.Get("Core", "HLE_BS2", &m_LocalCoreStartupParameter.bHLE_BS2, false);
|
||||
#ifdef _M_ARM
|
||||
ini.Get("Core", "CPUCore", &m_LocalCoreStartupParameter.iCPUCore, 3);
|
||||
#else
|
||||
ini.Get("Core", "CPUCore", &m_LocalCoreStartupParameter.iCPUCore, 1);
|
||||
#endif
|
||||
ini.Get("Core", "DSPThread", &m_LocalCoreStartupParameter.bDSPThread, false);
|
||||
ini.Get("Core", "DSPHLE", &m_LocalCoreStartupParameter.bDSPHLE, true);
|
||||
ini.Get("Core", "CPUThread", &m_LocalCoreStartupParameter.bCPUThread, true);
|
||||
@@ -393,14 +396,17 @@ void SConfig::LoadSettings()
|
||||
|
||||
ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false);
|
||||
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
|
||||
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
|
||||
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
|
||||
ini.Get("Core", "WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false);
|
||||
ini.Get("Core", "WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, true);
|
||||
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
|
||||
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);
|
||||
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
|
||||
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
|
||||
ini.Get("Core", "VBeam", &m_LocalCoreStartupParameter.bVBeam, false);
|
||||
ini.Get("Core", "SyncGPU", &m_LocalCoreStartupParameter.bSyncGPU, false);
|
||||
ini.Get("Core", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
|
||||
ini.Get("Core", "BAT", &m_LocalCoreStartupParameter.bMMUBAT, false);
|
||||
ini.Get("Core", "DCBZ", &m_LocalCoreStartupParameter.bDCBZOFF, false);
|
||||
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
|
||||
ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default
|
||||
|
||||
@@ -408,7 +414,7 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Core", "GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, "");
|
||||
|
||||
// Movie
|
||||
ini.Get("General", "PauseMovie", &m_PauseMovie, false);
|
||||
ini.Get("Movie", "PauseMovie", &m_PauseMovie, false);
|
||||
ini.Get("Movie", "Author", &m_strMovieAuthor, "");
|
||||
|
||||
// DSP
|
||||
@@ -428,18 +434,3 @@ void SConfig::LoadSettings()
|
||||
|
||||
m_SYSCONF = new SysConf();
|
||||
}
|
||||
void SConfig::LoadSettingsWii()
|
||||
{
|
||||
IniFile ini;
|
||||
//Wiimote configs
|
||||
ini.Load((File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
char SectionName[32];
|
||||
sprintf(SectionName, "Wiimote%i", i + 1);
|
||||
ini.Get(SectionName, "AutoReconnectRealWiimote", &m_WiiAutoReconnect[i], false);
|
||||
}
|
||||
ini.Load((File::GetUserPath(D_CONFIG_IDX) + "wiimote.ini"));
|
||||
ini.Get("Real", "Unpair", &m_WiiAutoUnpair, false);
|
||||
|
||||
}
|
||||
|
||||
@@ -35,15 +35,15 @@
|
||||
#define BACKEND_OPENAL "OpenAL"
|
||||
#define BACKEND_PULSEAUDIO "Pulse"
|
||||
#define BACKEND_XAUDIO2 "XAudio2"
|
||||
|
||||
#define BACKEND_OPENSLES "OpenSLES"
|
||||
struct SConfig : NonCopyable
|
||||
{
|
||||
// Wii Devices
|
||||
bool m_WiiSDCard;
|
||||
bool m_WiiKeyboard;
|
||||
bool m_WiiAutoReconnect[4];
|
||||
bool m_WiiAutoUnpair;
|
||||
bool m_WiimoteReconnectOnLoad;
|
||||
bool m_WiimoteContinuousScanning;
|
||||
bool m_WiimoteEnableSpeaker;
|
||||
|
||||
// name of the last used filename
|
||||
std::string m_LastFilename;
|
||||
@@ -107,9 +107,6 @@ struct SConfig : NonCopyable
|
||||
// load settings
|
||||
void LoadSettings();
|
||||
|
||||
//Special load settings
|
||||
void LoadSettingsWii();
|
||||
|
||||
// Return the permanent and somewhat globally used instance of this struct
|
||||
static SConfig& GetInstance() {return(*m_Instance);}
|
||||
|
||||
|
||||
@@ -98,8 +98,8 @@ void Console_Submit(const char *cmd)
|
||||
}
|
||||
CASE("dump")
|
||||
{
|
||||
TCHAR temp[256];
|
||||
TCHAR filename[256];
|
||||
char temp[256];
|
||||
char filename[256];
|
||||
u32 start;
|
||||
u32 end;
|
||||
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
|
||||
|
||||
@@ -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"
|
||||
@@ -105,6 +104,7 @@ static bool g_requestRefreshInfo = false;
|
||||
static int g_pauseAndLockDepth = 0;
|
||||
|
||||
SCoreStartupParameter g_CoreStartupParameter;
|
||||
bool isTabPressed = false;
|
||||
|
||||
std::string GetStateFileName() { return g_stateFileName; }
|
||||
void SetStateFileName(std::string val) { g_stateFileName = val; }
|
||||
@@ -140,7 +140,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);
|
||||
@@ -189,7 +189,7 @@ bool IsGPUThread()
|
||||
return IsCPUThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This is called from the GUI thread. See the booting call schedule in
|
||||
// BootManager.cpp
|
||||
bool Init()
|
||||
@@ -310,9 +310,7 @@ void CpuThread()
|
||||
g_video_backend->Video_Prepare();
|
||||
}
|
||||
|
||||
Common::SetCurrentThreadAffinity(1); // Force to first core
|
||||
|
||||
#if defined(_M_X64)
|
||||
#if defined(_M_X64) || _M_ARM
|
||||
EMM::InstallExceptionHandler(); // Let's run under memory watch
|
||||
#endif
|
||||
|
||||
@@ -325,6 +323,9 @@ void CpuThread()
|
||||
CCPU::Run();
|
||||
|
||||
g_bStarted = false;
|
||||
|
||||
if (!_CoreParameter.bCPUThread)
|
||||
g_video_backend->Video_Cleanup();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -343,8 +344,6 @@ void FifoPlayerThread()
|
||||
Common::SetCurrentThreadName("FIFO-GPU thread");
|
||||
}
|
||||
|
||||
Common::SetCurrentThreadAffinity(1); // Force to first core
|
||||
|
||||
g_bStarted = true;
|
||||
|
||||
// Enter CPU run loop. When we leave it - we are done.
|
||||
@@ -355,6 +354,9 @@ void FifoPlayerThread()
|
||||
}
|
||||
|
||||
g_bStarted = false;
|
||||
|
||||
if(!_CoreParameter.bCPUThread)
|
||||
g_video_backend->Video_Cleanup();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -369,13 +371,6 @@ void EmuThread()
|
||||
|
||||
Common::SetCurrentThreadName("Emuthread - Starting");
|
||||
|
||||
{
|
||||
if (cpu_info.num_cores > 3) // Force to third, non-HT core
|
||||
Common::SetCurrentThreadAffinity(4);
|
||||
else // Force to second core
|
||||
Common::SetCurrentThreadAffinity(2);
|
||||
}
|
||||
|
||||
DisplayMessage(cpu_info.brand_string, 8000);
|
||||
DisplayMessage(cpu_info.Summarize(), 8000);
|
||||
DisplayMessage(_CoreParameter.m_strFilename, 3000);
|
||||
@@ -488,6 +483,9 @@ void EmuThread()
|
||||
g_cpu_thread.join();
|
||||
|
||||
INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str());
|
||||
|
||||
if(_CoreParameter.bCPUThread)
|
||||
g_video_backend->Video_Cleanup();
|
||||
|
||||
VolumeHandler::EjectVolume();
|
||||
FileMon::Close();
|
||||
@@ -606,9 +604,13 @@ void VideoThrottle()
|
||||
u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ?
|
||||
(SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate;
|
||||
|
||||
if (Host_GetKeyState('\t'))
|
||||
isTabPressed = true;
|
||||
|
||||
// Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2
|
||||
if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'))
|
||||
{
|
||||
isTabPressed = false;
|
||||
u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS;
|
||||
|
||||
u32 timeDifference = (u32)Timer.GetTimeDifference();
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Core
|
||||
// TODO: kill, use SConfig instead
|
||||
extern SCoreStartupParameter g_CoreStartupParameter;
|
||||
|
||||
extern bool isTabPressed;
|
||||
|
||||
void Callback_VideoCopiedToXFB(bool video_update);
|
||||
|
||||
enum EState
|
||||
|
||||
@@ -49,10 +49,10 @@ SCoreStartupParameter::SCoreStartupParameter()
|
||||
bMergeBlocks(false),
|
||||
bDPL2Decoder(false), iLatency(14),
|
||||
bRunCompareServer(false), bRunCompareClient(false),
|
||||
bMMU(false), bMMUBAT(false), iTLBHack(0), bVBeam(false),
|
||||
bFastDiscSpeed(false),
|
||||
SelectedLanguage(0), bWii(false), bDisableWiimoteSpeaker(false),
|
||||
bConfirmStop(false), bHideCursor(false),
|
||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeam(false),
|
||||
bSyncGPU(false), bFastDiscSpeed(false),
|
||||
SelectedLanguage(0), bWii(false),
|
||||
bConfirmStop(false), bHideCursor(false),
|
||||
bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true),
|
||||
iRenderWindowXPos(-1), iRenderWindowYPos(-1),
|
||||
iRenderWindowWidth(640), iRenderWindowHeight(480),
|
||||
@@ -75,9 +75,10 @@ void SCoreStartupParameter::LoadDefaults()
|
||||
bDSPThread = true;
|
||||
bEnableFPRF = false;
|
||||
bMMU = false;
|
||||
bMMUBAT = false;
|
||||
bDCBZOFF = false;
|
||||
iTLBHack = 0;
|
||||
bVBeam = false;
|
||||
bSyncGPU = false;
|
||||
bFastDiscSpeed = false;
|
||||
bMergeBlocks = false;
|
||||
SelectedLanguage = 0;
|
||||
@@ -99,8 +100,6 @@ void SCoreStartupParameter::LoadDefaults()
|
||||
bJITPairedOff = false;
|
||||
bJITSystemRegistersOff = false;
|
||||
|
||||
bDisableWiimoteSpeaker = false;
|
||||
|
||||
m_strName = "NONE";
|
||||
m_strUniqueID = "00000000";
|
||||
}
|
||||
@@ -348,7 +347,11 @@ void SCoreStartupParameter::CheckMemcardPath(std::string& memcardPath, std::stri
|
||||
{
|
||||
// Use default memcard path if there is no user defined name
|
||||
std::string defaultFilename = isSlotA ? GC_MEMCARDA : GC_MEMCARDB;
|
||||
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
|
||||
#ifdef _WIN32
|
||||
memcardPath = "." + File::GetUserPath(D_GCUSER_IDX).substr(File::GetExeDirectory().size()) + defaultFilename + ext;
|
||||
#else
|
||||
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -113,15 +113,15 @@ struct SCoreStartupParameter
|
||||
bool bRunCompareClient;
|
||||
|
||||
bool bMMU;
|
||||
bool bMMUBAT;
|
||||
bool bDCBZOFF;
|
||||
int iTLBHack;
|
||||
bool bVBeam;
|
||||
bool bSyncGPU;
|
||||
bool bFastDiscSpeed;
|
||||
|
||||
int SelectedLanguage;
|
||||
|
||||
bool bWii;
|
||||
bool bDisableWiimoteSpeaker;
|
||||
|
||||
// Interface settings
|
||||
bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages;
|
||||
|
||||
@@ -413,6 +413,15 @@ void SetMaximumSlice(int maximumSliceLength)
|
||||
maxSliceLength = maximumSliceLength;
|
||||
}
|
||||
|
||||
void ForceExceptionCheck(int cycles)
|
||||
{
|
||||
if (downcount > cycles)
|
||||
{
|
||||
slicelength -= (downcount - cycles); // Account for cycles already executed by adjusting the slicelength
|
||||
downcount = cycles;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetSliceLength()
|
||||
{
|
||||
maxSliceLength = MAX_SLICE_LENGTH;
|
||||
@@ -468,7 +477,6 @@ void MoveEvents()
|
||||
|
||||
void Advance()
|
||||
{
|
||||
|
||||
MoveEvents();
|
||||
|
||||
int cyclesExecuted = slicelength - downcount;
|
||||
|
||||
@@ -92,6 +92,8 @@ void SetFakeTBStartValue(u64 val);
|
||||
u64 GetFakeTBStartTicks();
|
||||
void SetFakeTBStartTicks(u64 val);
|
||||
|
||||
void ForceExceptionCheck(int cycles);
|
||||
|
||||
extern int downcount;
|
||||
extern int slicelength;
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ u16 dsp_read_accelerator()
|
||||
// Somehow, YN1 and YN2 must be initialized with their "loop" values,
|
||||
// so yeah, it seems likely that we should raise an exception to let
|
||||
// the DSP program do that, at least if DSP_FORMAT == 0x0A.
|
||||
if ((Address & ~0x1f) == (EndAddress & ~0x1f))
|
||||
if ((Address & ~1) == (EndAddress & ~1))
|
||||
{
|
||||
// Set address back to start address.
|
||||
Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL];
|
||||
|
||||
@@ -77,37 +77,50 @@ static bool LoadRom(const char *fname, int size_in_words, u16 *rom)
|
||||
// Returns false iff the hash fails and the user hits "Yes"
|
||||
static bool VerifyRoms(const char *irom_filename, const char *coef_filename)
|
||||
{
|
||||
static const u32 hash[] = { 0x66f334fe, 0xf3b93527 };
|
||||
static const u32 hash_mini[] = { 0x9c8f593c, 0x10000001 };
|
||||
static const int size[] = { DSP_IROM_BYTE_SIZE, DSP_COEF_BYTE_SIZE };
|
||||
const u16 *data[] = { g_dsp.irom, g_dsp.coef };
|
||||
u32 h = 0;
|
||||
u8 count = 0;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
struct DspRomHashes
|
||||
{
|
||||
h = HashAdler32((u8*)data[i], size[i]);
|
||||
u32 hash_irom; // dsp_rom.bin
|
||||
u32 hash_drom; // dsp_coef.bin
|
||||
} KNOWN_ROMS[] = {
|
||||
// Official Nintendo ROM
|
||||
{ 0x66f334fe, 0xf3b93527 },
|
||||
|
||||
if (h == hash_mini[i])
|
||||
{
|
||||
count++;
|
||||
}
|
||||
else if (h != hash[i])
|
||||
{
|
||||
if (AskYesNoT("%s has an incorrect hash.\n"
|
||||
"Would you like to stop now to fix the problem?\n"
|
||||
"If you select \"No\", audio will be garbled.",
|
||||
(i == 0) ? irom_filename : coef_filename))
|
||||
return false;
|
||||
}
|
||||
// LM1234 replacement ROM (Zelda UCode only)
|
||||
{ 0x9c8f593c, 0x10000001 },
|
||||
|
||||
// delroth's improvement on LM1234 replacement ROM (Zelda and AX only,
|
||||
// IPL/Card/GBA still broken)
|
||||
{ 0xd9907f71, 0xb019c2fb }
|
||||
};
|
||||
|
||||
u32 hash_irom = HashAdler32((u8*)g_dsp.irom, DSP_IROM_BYTE_SIZE);
|
||||
u32 hash_drom = HashAdler32((u8*)g_dsp.coef, DSP_COEF_BYTE_SIZE);
|
||||
int rom_idx = -1;
|
||||
|
||||
for (u32 i = 0; i < sizeof (KNOWN_ROMS) / sizeof (KNOWN_ROMS[0]); ++i)
|
||||
{
|
||||
DspRomHashes& rom = KNOWN_ROMS[i];
|
||||
if (hash_irom == rom.hash_irom && hash_drom == rom.hash_drom)
|
||||
rom_idx = i;
|
||||
}
|
||||
|
||||
if (count == 2)
|
||||
if (rom_idx < 0)
|
||||
{
|
||||
PanicAlertT("You are using free dsp roms made by Dolphin Team.\n"
|
||||
"Only Zelda ucode games will work correctly with them.\n");
|
||||
if (AskYesNoT("Your DSP ROMs have incorrect hashes.\n"
|
||||
"Would you like to stop now to fix the problem?\n"
|
||||
"If you select \"No\", audio might be garbled."))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rom_idx == 1)
|
||||
PanicAlertT("You are using an old free DSP ROM made by the Dolphin Team.\n"
|
||||
"Only games using the Zelda UCode will work correctly.\n");
|
||||
|
||||
if (rom_idx == 2)
|
||||
PanicAlertT("You are using a free DSP ROM made by the Dolphin Team.\n"
|
||||
"All Wii games will work correctly, and most GC games should "
|
||||
"also work fine, but the GBA/IPL/CARD UCodes will not work.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
u8 DSPHost_ReadHostMemory(u32 addr);
|
||||
void DSPHost_WriteHostMemory(u8 value, u32 addr);
|
||||
bool DSPHost_OnThread();
|
||||
bool DSPHost_Wii();
|
||||
void DSPHost_InterruptRequest();
|
||||
u32 DSPHost_CodeLoaded(const u8 *ptr, int size);
|
||||
void DSPHost_UpdateDebugger();
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "DSPJitUtil.h"
|
||||
#endif
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
using namespace Gen;
|
||||
|
||||
// CLR $acR
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "../DSPAnalyzer.h"
|
||||
#include "DSPJitUtil.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "../DSPEmitter.h"
|
||||
#include "DSPJitUtil.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "../DSPEmitter.h"
|
||||
#include "DSPJitUtil.h"
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
using namespace Gen;
|
||||
|
||||
//clobbers:
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "DSPJitUtil.h"
|
||||
#endif
|
||||
#include "x64Emitter.h"
|
||||
#include "ABI.h"
|
||||
#include "x64ABI.h"
|
||||
using namespace Gen;
|
||||
|
||||
// Returns s64 in RAX
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user