Merge branch 'master' into android-core-control
@@ -7,10 +7,10 @@
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="14" />
|
||||
android:targetSdkVersion="18" />
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" />
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" >
|
||||
</uses-feature>
|
||||
<uses-feature android:name="android.hardware.screen.landscape" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
@@ -18,7 +18,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/launcher"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name" >
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.DolphinEmulator"
|
||||
@@ -40,8 +40,8 @@
|
||||
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.settings.PrefsActivity"
|
||||
android:label="@string/settings" >
|
||||
</activity>
|
||||
android:label="@string/settings" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -10,7 +10,7 @@ CPUCore = 3
|
||||
CPUThread = False
|
||||
GFXBackend = Software Renderer
|
||||
HLE_BS2 = False
|
||||
Fastmem = True
|
||||
Fastmem = False
|
||||
DSPThread = False
|
||||
DSPHLE = True
|
||||
SkipIdle = True
|
||||
@@ -56,7 +56,7 @@ ShowStatusbar = True
|
||||
ShowLogWindow = False
|
||||
ShowLogConfigWindow = False
|
||||
ShowConsole = False
|
||||
ThemeName = Boomy
|
||||
ThemeName40 = Clean
|
||||
[Hotkeys]
|
||||
Open = 79
|
||||
OpenModifier = 2
|
||||
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 80 KiB |
@@ -2,22 +2,23 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="6dp">
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/AboutItemTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dip"
|
||||
android:layout_marginTop="5dip"
|
||||
android:layout_marginLeft="15dip"
|
||||
android:layout_marginTop="6dip"
|
||||
android:singleLine="true"
|
||||
android:textStyle="bold" />
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/AboutItemSubTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dip" />
|
||||
android:layout_marginLeft="15dip"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,7 +1,7 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/saveStateRoot"
|
||||
android:showAsAction="always"
|
||||
android:showAsAction="ifRoom"
|
||||
android:title="@string/overlay_savestate">
|
||||
<menu>
|
||||
<item android:id="@+id/saveSlot1"
|
||||
@@ -22,8 +22,8 @@
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/loadtateRoot"
|
||||
android:showAsAction="always"
|
||||
android:id="@+id/loadStateRoot"
|
||||
android:showAsAction="ifRoom"
|
||||
android:title="@string/overlay_loadstate">
|
||||
<menu>
|
||||
<item android:id="@+id/loadSlot1"
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
<string name="drawer_close">ナビゲーションウィンドウを閉じる</string>
|
||||
|
||||
<!-- About Fragment -->
|
||||
<string name="build_revision">ビルドのバージョン:</string>
|
||||
<string name="supports_gles3">サポートのOpenGL ES 3:</string>
|
||||
<string name="build_revision">ビルドのバージョン</string>
|
||||
<string name="supports_gles3">サポートのOpenGL ES 3</string>
|
||||
|
||||
<!-- Folder Browser -->
|
||||
<string name="current_dir">現在のディレクトリ: </string>
|
||||
<string name="parent_directory">親ディレクトリ</string>
|
||||
<string name="folder">フォルダ</string>
|
||||
<string name="file_size">ファイルサイズ: </string>
|
||||
|
||||
<!-- Game List Activity -->
|
||||
@@ -24,7 +23,6 @@
|
||||
<string name="game_list">ゲームリスト</string>
|
||||
<string name="browse_folder">フォルダの参照</string>
|
||||
<string name="settings">設定</string>
|
||||
<string name="gamepad_config">ゲームパッド設定</string>
|
||||
<string name="about">について</string>
|
||||
|
||||
<!-- Game List Fragment -->
|
||||
@@ -42,9 +40,9 @@
|
||||
<string name="overlay_slot5">スロット 5</string>
|
||||
|
||||
<!-- Input Config Fragment -->
|
||||
<string name="input_settings">入力設定</string>
|
||||
<string name="input_settings">入力</string>
|
||||
<string name="input_binding">入力バインディング</string>
|
||||
<string name="input_binding_descrip">このコントロールにバインドするための入力を移動または押してください。</string>
|
||||
<string name="input_binding_descrip">%1$sにバインドするための入力を移動または押してください。</string>
|
||||
<string name="button_a">Aボタン</string>
|
||||
<string name="button_b">Bボタン</string>
|
||||
<string name="button_start">スタートボタン</string>
|
||||
@@ -65,7 +63,6 @@
|
||||
<string name="c_stick_right">C-スティック: →</string>
|
||||
<string name="trigger_left">左のトリガー</string>
|
||||
<string name="trigger_right">右のトリガー</string>
|
||||
<string name="press_button_to_config">%1$sを設定するにはボタンを押して</string>
|
||||
|
||||
<!-- Prefs Fragment -->
|
||||
<string name="interpreter">Interpreter</string>
|
||||
@@ -73,11 +70,13 @@
|
||||
<string name="jitil_recompiler">JITIL Recompiler</string>
|
||||
<string name="jit_arm_recompiler">JIT ARM Recompiler</string>
|
||||
<string name="cpu_core">CPUコア</string>
|
||||
<string name="cpu_settings">CPU設定</string>
|
||||
<string name="cpu_settings">CPU</string>
|
||||
<string name="emu_core_to_use">使用するエミュレーションコア</string>
|
||||
<string name="dual_core">デュアルコア</string>
|
||||
<string name="dual_core_descrip">処理のための2つのCPUコアを使用して。速度が向上します。</string>
|
||||
<string name="video_settings">ビデオ設定</string>
|
||||
<string name="fastmem">Fastmem</string>
|
||||
<string name="fastmem_desc">メモリアクセスのために潜在的に危険な最適化を使用して。</string>
|
||||
<string name="video_settings">ビデオ</string>
|
||||
<string name="software_renderer">Software Renderer</string>
|
||||
<string name="opengl_es3">OpenGL ES 3</string>
|
||||
<string name="video_backend">ビデオレンダラ</string>
|
||||
@@ -89,6 +88,8 @@
|
||||
<string name="enhancements">画質向上の設定</string>
|
||||
<string name="internal_resolution">内部解像度の変更</string>
|
||||
<string name="internal_resolution_descrip">内部解像度の計算方式を設定します。高解像度に設定することで大きく 画質が向上します。 しかし、ゲームによっては非常に重くなったり描画バグの原因となります。 【ゲーム解像度の倍数】は【ウィンドウサイズに拡大】より少し重くなり ますが、描画バグは発生しにくくなります。 また一般的に内部解像度が低いほど、動作速度は向上します。</string>
|
||||
<string name="FSAA">フルシーンアンチエイリアシング</string>
|
||||
<string name="FSAA_descrip">3Dグラフィックスをラスタライズによって生じるエイリアシングの量が減少。 レンダリングされた画像はあまりギザギザになります。 抽選でエミュレーション速度を下げます。問題を引き起こす可能性があります。</string>
|
||||
<string name="anisotropic_filtering">異方性フィルタリング</string>
|
||||
<string name="anisotropic_filtering_descrip">異方性フィルタリングを適用します。 奥行きのあるテクスチャをより精細に描画することが出来ます。 特定のゲームでは描画バグの原因になることがあります。</string>
|
||||
<string name="scaled_efb_copy">Scaled EFB Copy</string>
|
||||
|
||||
@@ -108,7 +108,19 @@
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
</string-array>
|
||||
|
||||
|
||||
<!-- FSAA Preference -->
|
||||
<string-array name="FSAAEntries" translatable="false">
|
||||
<item>1x</item>
|
||||
<item>2x</item>
|
||||
<item>4x</item>
|
||||
</string-array>
|
||||
<string-array name="FSAAValues" translatable="false">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Anisotropic Filtering Preference -->
|
||||
<string-array name="anisotropicFilteringEntries" translatable="false">
|
||||
<item>1x</item>
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
<string name="drawer_close">Close navigation drawer</string>
|
||||
|
||||
<!-- About Fragment -->
|
||||
<string name="build_revision">Build Revision:</string>
|
||||
<string name="supports_gles3">Supports OpenGL ES 3:</string>
|
||||
<string name="build_revision">Build Revision</string>
|
||||
<string name="supports_gles3">Supports OpenGL ES 3</string>
|
||||
|
||||
<!-- Folder Browser -->
|
||||
<string name="current_dir">Current Dir: </string>
|
||||
<string name="parent_directory">Parent Directory</string>
|
||||
<string name="folder">Folder</string>
|
||||
<string name="file_size">File Size: </string>
|
||||
|
||||
<!-- Game List Activity -->
|
||||
@@ -24,7 +23,6 @@
|
||||
<string name="game_list">Game List</string>
|
||||
<string name="browse_folder">Browse Folder</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="gamepad_config">Gamepad Config</string>
|
||||
<string name="about">About</string>
|
||||
|
||||
<!-- Game List Fragment -->
|
||||
@@ -44,7 +42,7 @@
|
||||
<!-- Input Config Fragment -->
|
||||
<string name="input_settings">Input</string>
|
||||
<string name="input_binding">Input Binding</string>
|
||||
<string name="input_binding_descrip">Press or move an input to bind it to this control.</string>
|
||||
<string name="input_binding_descrip">Press or move an input to bind it to %1$s.</string>
|
||||
<string name="button_a">Button A</string>
|
||||
<string name="button_b">Button B</string>
|
||||
<string name="button_start">Button Start</string>
|
||||
@@ -65,7 +63,6 @@
|
||||
<string name="c_stick_right">C Stick Right</string>
|
||||
<string name="trigger_left">Trigger L</string>
|
||||
<string name="trigger_right">Trigger R</string>
|
||||
<string name="press_button_to_config">Press button to configure %1$s</string>
|
||||
|
||||
<!-- Preference Related -->
|
||||
<string name="interpreter">Interpreter</string>
|
||||
@@ -77,6 +74,8 @@
|
||||
<string name="emu_core_to_use">Emulation core to use</string>
|
||||
<string name="dual_core">Dual Core</string>
|
||||
<string name="dual_core_descrip">Split workload to two CPU cores instead of one. Increases speed.</string>
|
||||
<string name="fastmem">Fastmem</string>
|
||||
<string name="fastmem_desc">Uses potentially unsafe optimizations for memory access.</string>
|
||||
<string name="video_settings">Video</string>
|
||||
<string name="software_renderer">Software Renderer</string>
|
||||
<string name="opengl_es3">OpenGL ES 3</string>
|
||||
@@ -89,6 +88,8 @@
|
||||
<string name="enhancements">Enhancements</string>
|
||||
<string name="internal_resolution">Internal Resolution</string>
|
||||
<string name="internal_resolution_descrip">Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain games.</string>
|
||||
<string name="FSAA">Full-scene Anti-aliasing</string>
|
||||
<string name="FSAA_descrip">Reduces the amount of aliasing caused by rasterizing 3D graphics. This makes the rendered picture look less blocky. Heavily decreases emulation speed and sometimes causes issues.</string>
|
||||
<string name="anisotropic_filtering">Anisotropic Filtering</string>
|
||||
<string name="anisotropic_filtering_descrip">Enhances visual quality of textures that are at oblique viewing angles. Might cause issues in a small number of games.</string>
|
||||
<string name="scaled_efb_copy">Scaled EFB Copy</string>
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- CPU Settings -->
|
||||
<!-- CPU Settings -->
|
||||
<CheckBoxPreference
|
||||
android:key="dualCorePref"
|
||||
android:summary="@string/dual_core_descrip"
|
||||
android:title="@string/dual_core" />
|
||||
|
||||
android:defaultValue="false"
|
||||
android:key="dualCorePref"
|
||||
android:summary="@string/dual_core_descrip"
|
||||
android:title="@string/dual_core" />
|
||||
|
||||
<ListPreference
|
||||
android:key="cpuCorePref"
|
||||
android:summary="@string/emu_core_to_use"
|
||||
android:title="@string/cpu_core" />
|
||||
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:key="fastmemPref"
|
||||
android:summary="@string/fastmem_desc"
|
||||
android:title="@string/fastmem" />
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -14,6 +14,13 @@
|
||||
android:summary="@string/internal_resolution_descrip"
|
||||
android:title="@string/internal_resolution"/>
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/FSAAEntries"
|
||||
android:entryValues="@array/FSAAValues"
|
||||
android:key="FSAA"
|
||||
android:summary="@string/FSAA_descrip"
|
||||
android:title="@string/FSAA"/>
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/anisotropicFilteringEntries"
|
||||
android:entryValues="@array/anisotropicFilteringValues"
|
||||
@@ -129,9 +136,10 @@
|
||||
android:key="showFPS"
|
||||
android:summary="@string/show_fps_descrip"
|
||||
android:title="@string/show_fps"/>
|
||||
|
||||
<!--
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="drawOnscreenControls"
|
||||
android:title="@string/draw_onscreen_controls"/>
|
||||
-->
|
||||
</PreferenceScreen>
|
||||
@@ -7,7 +7,7 @@
|
||||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.ListFragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -25,7 +25,7 @@ import org.dolphinemu.dolphinemu.settings.VideoSettingsFragment;
|
||||
/**
|
||||
* Represents the about screen.
|
||||
*/
|
||||
public final class AboutFragment extends Fragment
|
||||
public final class AboutFragment extends ListFragment
|
||||
{
|
||||
private static Activity m_activity;
|
||||
|
||||
@@ -44,6 +44,7 @@ public final class AboutFragment extends Fragment
|
||||
|
||||
AboutFragmentAdapter adapter = new AboutFragmentAdapter(m_activity, R.layout.about_layout, Input);
|
||||
mMainList.setAdapter(adapter);
|
||||
mMainList.setEnabled(false); // Makes the list view non-clickable.
|
||||
|
||||
return mMainList;
|
||||
}
|
||||
@@ -108,7 +109,7 @@ public final class AboutFragment extends Fragment
|
||||
View v = convertView;
|
||||
if (v == null)
|
||||
{
|
||||
LayoutInflater vi = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
LayoutInflater vi = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
v = vi.inflate(id, parent, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,16 +58,15 @@ public final class DolphinEmulator extends Activity
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState == null)
|
||||
{
|
||||
Intent ListIntent = new Intent(this, GameListActivity.class);
|
||||
startActivityForResult(ListIntent, 1);
|
||||
Intent GameListIntent = new Intent(this, GameListActivity.class);
|
||||
startActivity(GameListIntent);
|
||||
|
||||
String BaseDir = Environment.getExternalStorageDirectory()+File.separator+"dolphin-emu";
|
||||
String ConfigDir = BaseDir + File.separator + "Config";
|
||||
String GCDir = BaseDir + File.separator + "GC";
|
||||
String WiiDir = BaseDir + File.separator + "Wii";
|
||||
|
||||
// Copy assets if needed
|
||||
File file = new File(WiiDir + File.separator + "setting-usa.txt");
|
||||
File file = new File(GCDir + File.separator + "font_sjis.bin");
|
||||
if(!file.exists())
|
||||
{
|
||||
NativeLibrary.CreateUserFolders();
|
||||
@@ -81,10 +80,6 @@ public final class DolphinEmulator extends Activity
|
||||
CopyAsset("dsp_rom.bin", GCDir + File.separator + "dsp_rom.bin");
|
||||
CopyAsset("font_ansi.bin", GCDir + File.separator + "font_ansi.bin");
|
||||
CopyAsset("font_sjis.bin", GCDir + File.separator + "font_sjis.bin");
|
||||
CopyAsset("setting-eur.txt", WiiDir + File.separator + "setting-eur.txt");
|
||||
CopyAsset("setting-jpn.txt", WiiDir + File.separator + "setting-jpn.txt");
|
||||
CopyAsset("setting-kor.txt", WiiDir + File.separator + "setting-kor.txt");
|
||||
CopyAsset("setting-usa.txt", WiiDir + File.separator + "setting-usa.txt");
|
||||
}
|
||||
|
||||
// Load the configuration keys set in the Dolphin ini and gfx ini files
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.dolphinemu.dolphinemu.settings.InputConfigFragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.*;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import org.dolphinemu.dolphinemu.settings.InputConfigFragment;
|
||||
import org.dolphinemu.dolphinemu.settings.VideoSettingsFragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is the activity where all of the emulation handling happens.
|
||||
@@ -63,7 +58,18 @@ public final class EmulationActivity extends Activity
|
||||
// and set on the native side of the code so the emulator can actually
|
||||
// load the game.
|
||||
Intent gameToEmulate = getIntent();
|
||||
NativeLibrary.SetDimensions((int)screenWidth, (int)screenHeight);
|
||||
|
||||
// Due to a bug in Adreno, it renders the screen rotated 90 degrees when using OpenGL
|
||||
// Flip the width and height when on Adreno to work around this.
|
||||
// Mali isn't affected by this bug.
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
if (prefs.getString("gpuPref", "Software Rendering").equals("OGL")
|
||||
&& VideoSettingsFragment.SupportsGLES3()
|
||||
&& VideoSettingsFragment.m_GLVendor.equals("Qualcomm"))
|
||||
NativeLibrary.SetDimensions((int)screenHeight, (int)screenWidth);
|
||||
else
|
||||
NativeLibrary.SetDimensions((int)screenWidth, (int)screenHeight);
|
||||
|
||||
NativeLibrary.SetFilename(gameToEmulate.getStringExtra("SelectedGame"));
|
||||
Running = true;
|
||||
|
||||
@@ -224,7 +230,7 @@ public final class EmulationActivity extends Activity
|
||||
}
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected( item );
|
||||
return super.onMenuItemSelected(itemId, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,12 +51,12 @@ public final class NativeGLSurfaceView extends SurfaceView
|
||||
}
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public void surfaceDestroyed(SurfaceHolder arg0)
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ public final class NativeLibrary
|
||||
}
|
||||
catch (UnsatisfiedLinkError ex)
|
||||
{
|
||||
Log.w("NativeLibrary", ex.toString());
|
||||
Log.e("NativeLibrary", ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
package org.dolphinemu.dolphinemu.folderbrowser;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.ListFragment;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.io.File;
|
||||
@@ -33,16 +32,15 @@ import org.dolphinemu.dolphinemu.gamelist.GameListActivity;
|
||||
* the game list for easy browsing the next time the
|
||||
* application is used.
|
||||
* <p>
|
||||
* Note that invalid items will be shown in the color red. <br/>
|
||||
* Also note that this file browser does not display files
|
||||
* Note that this file browser does not display files
|
||||
* or directories that are hidden
|
||||
*/
|
||||
public final class FolderBrowser extends Fragment
|
||||
public final class FolderBrowser extends ListFragment
|
||||
{
|
||||
private Activity m_activity;
|
||||
private FolderBrowserAdapter adapter;
|
||||
private ListView mDrawerList;
|
||||
private View rootView;
|
||||
private ListView mFolderBrowserList;
|
||||
private ListView rootView;
|
||||
private static File currentDir = null;
|
||||
|
||||
// Populates the FolderView with the given currDir's contents.
|
||||
@@ -54,7 +52,7 @@ public final class FolderBrowser extends Fragment
|
||||
List<FolderBrowserItem>fls = new ArrayList<FolderBrowserItem>();
|
||||
|
||||
// Supported extensions to filter by
|
||||
Set<String> validExts = new HashSet<String>(Arrays.asList(".gcm", ".iso", ".wbfs", ".gcz", ".dol", ".elf", ".dff", ".wad"));
|
||||
Set<String> validExts = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
|
||||
|
||||
// Search for any directories or files within the current dir.
|
||||
for(File entry : dirs)
|
||||
@@ -65,7 +63,7 @@ public final class FolderBrowser extends Fragment
|
||||
boolean hasExtension = (entryName.lastIndexOf(".") != -1);
|
||||
|
||||
// Skip hidden folders/files.
|
||||
if (entryName.charAt(0) != '.')
|
||||
if (!entry.isHidden())
|
||||
{
|
||||
if(entry.isDirectory())
|
||||
{
|
||||
@@ -82,7 +80,7 @@ public final class FolderBrowser extends Fragment
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.e("Exception-FolderBrowser", ex.toString());
|
||||
Log.e("FolderBrowser", ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +93,23 @@ public final class FolderBrowser extends Fragment
|
||||
dir.add(0, new FolderBrowserItem("..", getString(R.string.parent_directory), currDir.getParent()));
|
||||
|
||||
adapter = new FolderBrowserAdapter(m_activity, R.layout.gamelist_folderbrowser_list, dir);
|
||||
mDrawerList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
mDrawerList.setAdapter(adapter);
|
||||
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
|
||||
mFolderBrowserList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
mFolderBrowserList.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListItemClick(ListView lv, View v, int position, long id)
|
||||
{
|
||||
FolderBrowserItem item = adapter.getItem(position);
|
||||
if(item.isDirectory())
|
||||
{
|
||||
currentDir = new File(item.getPath());
|
||||
Fill(currentDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FolderSelected();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,29 +118,12 @@ public final class FolderBrowser extends Fragment
|
||||
if(currentDir == null)
|
||||
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
rootView = (ListView) inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
|
||||
Fill(currentDir);
|
||||
return mDrawerList;
|
||||
return mFolderBrowserList;
|
||||
}
|
||||
|
||||
private final AdapterView.OnItemClickListener mMenuItemClickListener = new AdapterView.OnItemClickListener()
|
||||
{
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||
{
|
||||
FolderBrowserItem item = adapter.getItem(position);
|
||||
if(item.isDirectory())
|
||||
{
|
||||
currentDir = new File(item.getPath());
|
||||
Fill(currentDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FolderSelected();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity)
|
||||
{
|
||||
|
||||
@@ -104,6 +104,6 @@ public final class FolderBrowserItem implements Comparable<FolderBrowserItem>
|
||||
if(name != null)
|
||||
return name.toLowerCase().compareTo(other.getName().toLowerCase());
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
throw new NullPointerException("The name of this FolderBrowserItem is null");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public final class GameListFragment extends Fragment
|
||||
int intDirectories = Integer.parseInt(Directories);
|
||||
|
||||
// Extensions to filter by.
|
||||
Set<String> exts = new HashSet<String>(Arrays.asList(".gcm", ".iso", ".wbfs", ".gcz", ".dol", ".elf", ".dff", ".wad"));
|
||||
Set<String> exts = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs"));
|
||||
|
||||
for (int a = 0; a < intDirectories; ++a)
|
||||
{
|
||||
@@ -83,13 +83,10 @@ public final class GameListFragment extends Fragment
|
||||
{
|
||||
String entryName = entry.getName();
|
||||
|
||||
if (entryName.charAt(0) != '.')
|
||||
if (!entry.isHidden() && !entry.isDirectory())
|
||||
{
|
||||
if (!entry.isDirectory())
|
||||
{
|
||||
if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
fls.add(new GameListItem(mMe.getApplicationContext(), entryName, getString(R.string.file_size)+entry.length(),entry.getAbsolutePath()));
|
||||
}
|
||||
if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
fls.add(new GameListItem(mMe, entryName, getString(R.string.file_size)+entry.length(),entry.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public final class GameListItem implements Comparable<GameListItem>
|
||||
this.path = path;
|
||||
|
||||
File file = new File(path);
|
||||
if (!file.isDirectory() && !path.equals(""))
|
||||
if (!file.isDirectory() && !path.isEmpty())
|
||||
{
|
||||
int[] Banner = NativeLibrary.GetBanner(path);
|
||||
if (Banner[0] == 0)
|
||||
@@ -60,7 +60,7 @@ public final class GameListItem implements Comparable<GameListItem>
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e("Exception-GameListItem", e.toString());
|
||||
Log.e("GameListItem", e.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -117,7 +117,7 @@ public final class GameListItem implements Comparable<GameListItem>
|
||||
if (name != null)
|
||||
return name.toLowerCase().compareTo(o.getName().toLowerCase());
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
throw new NullPointerException("The name of this GameListItem is null");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ public final class InputConfigFragment extends PreferenceFragment
|
||||
|
||||
// Set the title and description message.
|
||||
dialog.setTitle(R.string.input_binding);
|
||||
dialog.setMessage(getString(R.string.input_binding_descrip));
|
||||
dialog.setMessage(String.format(getString(R.string.input_binding_descrip), pref.getTitle()));
|
||||
|
||||
// Don't allow the dialog to close when a user taps
|
||||
// outside of it. They must press cancel or provide an input.
|
||||
@@ -208,7 +208,7 @@ public final class InputConfigFragment extends PreferenceFragment
|
||||
* to be set anonymously, so the creation of an explicit class for
|
||||
* providing functionality is not necessary.
|
||||
*/
|
||||
protected static final class MotionAlertDialog extends AlertDialog
|
||||
private static final class MotionAlertDialog extends AlertDialog
|
||||
{
|
||||
private OnMotionEventListener motionListener;
|
||||
|
||||
@@ -229,6 +229,13 @@ public final class InputConfigFragment extends PreferenceFragment
|
||||
*/
|
||||
public interface OnMotionEventListener
|
||||
{
|
||||
/**
|
||||
* Denotes the behavior that should happen when a motion event occurs.
|
||||
*
|
||||
* @param event Reference to the {@link MotionEvent} that occurred.
|
||||
*
|
||||
* @return true if the {@link MotionEvent} is consumed in this call; false otherwise.
|
||||
*/
|
||||
boolean onMotion(MotionEvent event);
|
||||
}
|
||||
|
||||
@@ -245,7 +252,7 @@ public final class InputConfigFragment extends PreferenceFragment
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event)
|
||||
{
|
||||
if (this.onKeyDown(event.getKeyCode(), event))
|
||||
if (onKeyDown(event.getKeyCode(), event))
|
||||
return true;
|
||||
|
||||
return super.dispatchKeyEvent(event);
|
||||
|
||||
@@ -76,7 +76,7 @@ public final class PrefsActivity extends Activity implements ActionBar.TabListen
|
||||
actionBar.addTab(actionBar.newTab().setText(R.string.video_settings).setTabListener(this));
|
||||
}
|
||||
|
||||
public void onTabReselected(Tab arg0, FragmentTransaction arg1)
|
||||
public void onTabReselected(Tab tab, FragmentTransaction ft)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
@@ -135,13 +135,13 @@ public final class PrefsActivity extends Activity implements ActionBar.TabListen
|
||||
switch(position)
|
||||
{
|
||||
case 0:
|
||||
return getString(R.string.cpu_settings).toUpperCase();
|
||||
return getString(R.string.cpu_settings);
|
||||
|
||||
case 1:
|
||||
return getString(R.string.input_settings).toUpperCase();
|
||||
return getString(R.string.input_settings);
|
||||
|
||||
case 2:
|
||||
return getString(R.string.video_settings).toUpperCase();
|
||||
return getString(R.string.video_settings);
|
||||
|
||||
default: // Should never happen.
|
||||
return null;
|
||||
|
||||
@@ -36,12 +36,14 @@ public final class UserPreferences
|
||||
// Add the settings.
|
||||
editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "3"));
|
||||
editor.putBoolean("dualCorePref", getConfig("Dolphin.ini", "Core", "CPUThread", "False").equals("True"));
|
||||
editor.putBoolean("fastmemPref", getConfig("Dolphin.ini", "Core", "Fastmem", "False").equals("True"));
|
||||
|
||||
editor.putString("gpuPref", getConfig("Dolphin.ini", "Core", "GFXBackend ", "Software Renderer"));
|
||||
editor.putString("gpuPref", getConfig("Dolphin.ini", "Core", "GFXBackend", "Software Renderer"));
|
||||
editor.putBoolean("showFPS", getConfig("gfx_opengl.ini", "Settings", "ShowFPS", "False").equals("True"));
|
||||
editor.putBoolean("drawOnscreenControls", getConfig("Dolphin.ini", "Android", "ScreenControls", "True").equals("True"));
|
||||
|
||||
editor.putString("internalResolution", getConfig("gfx_opengl.ini", "Settings", "EFBScale", "2") );
|
||||
editor.putString("FSAA", getConfig("gfx_opengl.ini", "Settings", "MSAA", "0"));
|
||||
editor.putString("anisotropicFiltering", getConfig("gfx_opengl.ini", "Enhancements", "MaxAnisotropy", "0"));
|
||||
editor.putBoolean("scaledEFBCopy", getConfig("gfx_opengl.ini", "Hacks", "EFBScaleCopy", "True").equals("True"));
|
||||
editor.putBoolean("perPixelLighting", getConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", "False").equals("True"));
|
||||
@@ -118,6 +120,9 @@ public final class UserPreferences
|
||||
// Current CPU core being used. Falls back to interpreter upon error.
|
||||
String currentEmuCore = prefs.getString("cpuCorePref", "0");
|
||||
|
||||
// Fastmem JIT core usage
|
||||
boolean isUsingFastmem = prefs.getBoolean("fastmemPref", false);
|
||||
|
||||
// Current video backend being used. Falls back to software rendering upon error.
|
||||
String currentVideoBackend = prefs.getString("gpuPref", "Software Rendering");
|
||||
|
||||
@@ -154,6 +159,9 @@ public final class UserPreferences
|
||||
// Internal resolution. Falls back to 1x Native upon error.
|
||||
String internalResolution = prefs.getString("internalResolution", "2");
|
||||
|
||||
// FSAA Level. Falls back to 1x upon error.
|
||||
String FSAALevel = prefs.getString("FSAA", "0");
|
||||
|
||||
// Anisotropic Filtering Level. Falls back to 1x upon error.
|
||||
String anisotropicFiltLevel = prefs.getString("anisotropicFiltering", "0");
|
||||
|
||||
@@ -173,6 +181,7 @@ public final class UserPreferences
|
||||
// CPU related Settings
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUCore", currentEmuCore);
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUThread", isUsingDualCore ? "True" : "False");
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "Fastmem", isUsingFastmem ? "True" : "False");
|
||||
|
||||
// General Video Settings
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "Core", "GFXBackend", currentVideoBackend);
|
||||
@@ -231,6 +240,7 @@ public final class UserPreferences
|
||||
|
||||
//-- Enhancement Settings --//
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EFBScale", internalResolution);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "MSAA", FSAALevel);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "MaxAnisotropy", anisotropicFiltLevel);
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBScaledCopy", usingScaledEFBCopy ? "True" : "False");
|
||||
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", usingPerPixelLighting ? "True" : "False");
|
||||
|
||||
@@ -6,15 +6,6 @@
|
||||
|
||||
package org.dolphinemu.dolphinemu.settings;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLContext;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
import javax.microedition.khronos.egl.EGLSurface;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
@@ -23,12 +14,19 @@ import android.preference.ListPreference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.PreferenceScreen;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
|
||||
import javax.microedition.khronos.egl.*;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
* Responsible for handling the loading of the video preferences.
|
||||
*/
|
||||
public final class VideoSettingsFragment extends PreferenceFragment
|
||||
{
|
||||
public static String m_GLVersion;
|
||||
public static String m_GLVendor;
|
||||
public static String m_GLRenderer;
|
||||
private Activity m_activity;
|
||||
|
||||
/**
|
||||
@@ -138,9 +136,9 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
public static boolean SupportsGLES3()
|
||||
{
|
||||
VersionCheck mbuffer = new VersionCheck();
|
||||
String m_GLVersion = mbuffer.getVersion();
|
||||
String m_GLVendor = mbuffer.getVendor();
|
||||
String m_GLRenderer = mbuffer.getRenderer();
|
||||
m_GLVersion = mbuffer.getVersion();
|
||||
m_GLVendor = mbuffer.getVendor();
|
||||
m_GLRenderer = mbuffer.getRenderer();
|
||||
|
||||
boolean mSupportsGLES3 = false;
|
||||
|
||||
@@ -207,7 +205,7 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
// denotes the placement on the UI. So if more elements are
|
||||
// added to the video settings, these may need to change.
|
||||
//
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(m_activity);
|
||||
final PreferenceScreen mainScreen = getPreferenceScreen();
|
||||
|
||||
if (videoBackends.getValue().equals("Software Renderer"))
|
||||
@@ -215,14 +213,14 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
mainScreen.getPreference(0).setEnabled(false);
|
||||
mainScreen.getPreference(1).setEnabled(false);
|
||||
mainScreen.getPreference(3).setEnabled(false);
|
||||
mainScreen.getPreference(4).setEnabled(false);
|
||||
//mainScreen.getPreference(4).setEnabled(true);
|
||||
}
|
||||
else if (videoBackends.getValue().equals("OGL"))
|
||||
{
|
||||
mainScreen.getPreference(0).setEnabled(true);
|
||||
mainScreen.getPreference(1).setEnabled(true);
|
||||
mainScreen.getPreference(3).setEnabled(true);
|
||||
mainScreen.getPreference(4).setEnabled(true);
|
||||
//mainScreen.getPreference(4).setEnabled(false);
|
||||
}
|
||||
|
||||
// Also set a listener, so that if someone changes the video backend, it will disable
|
||||
@@ -239,14 +237,14 @@ public final class VideoSettingsFragment extends PreferenceFragment
|
||||
mainScreen.getPreference(0).setEnabled(false);
|
||||
mainScreen.getPreference(1).setEnabled(false);
|
||||
mainScreen.getPreference(3).setEnabled(false);
|
||||
mainScreen.getPreference(4).setEnabled(false);
|
||||
//mainScreen.getPreference(4).setEnabled(true);
|
||||
}
|
||||
else if (preference.getString(key, "Software Renderer").equals("OGL"))
|
||||
{
|
||||
mainScreen.getPreference(0).setEnabled(true);
|
||||
mainScreen.getPreference(1).setEnabled(true);
|
||||
mainScreen.getPreference(3).setEnabled(true);
|
||||
mainScreen.getPreference(4).setEnabled(true);
|
||||
//mainScreen.getPreference(4).setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ package org.dolphinemu.dolphinemu.sidemenu;
|
||||
/**
|
||||
* Represents an item that goes in the sidemenu of the app.
|
||||
*/
|
||||
public final class SideMenuItem implements Comparable<SideMenuItem>
|
||||
public final class SideMenuItem
|
||||
{
|
||||
private final String name;
|
||||
private final int id;
|
||||
@@ -46,13 +46,5 @@ public final class SideMenuItem implements Comparable<SideMenuItem>
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public int compareTo(SideMenuItem o)
|
||||
{
|
||||
if (name != null)
|
||||
return name.toLowerCase().compareTo(o.getName().toLowerCase());
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
#include <string.h>
|
||||
#include "DPL2Decoder.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_SQRT1_2
|
||||
#define M_SQRT1_2 0.70710678118654752440
|
||||
#endif
|
||||
|
||||
int olddelay = -1;
|
||||
unsigned int oldfreq = 0;
|
||||
|
||||
@@ -210,7 +210,7 @@ unsigned int CMixer::GetNumSamples()
|
||||
u32 numSamples = ((Common::AtomicLoad(m_indexW) - Common::AtomicLoad(m_indexR)) & INDEX_MASK) / 2;
|
||||
|
||||
if (AudioInterface::GetAIDSampleRate() == m_sampleRate)
|
||||
numSamples = numSamples; // 1:1
|
||||
; //numSamples = numSamples; // 1:1
|
||||
else if (m_sampleRate == 48000 && AudioInterface::GetAIDSampleRate() == 32000)
|
||||
numSamples = numSamples * 3 / 2 - 2; // most common case
|
||||
else
|
||||
|
||||
@@ -86,6 +86,7 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated)
|
||||
Operand2 AssumeMakeOperand2(u32 imm) {
|
||||
Operand2 op2;
|
||||
bool result = TryMakeOperand2(imm, op2);
|
||||
(void) result;
|
||||
_dbg_assert_msg_(DYNA_REC, result, "Could not make assumed Operand2.");
|
||||
return op2;
|
||||
}
|
||||
@@ -611,9 +612,15 @@ void ARMXEmitter::LSL (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedData
|
||||
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(0, true, dest, src, op2);}
|
||||
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);}
|
||||
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(3, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(2, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(2, true, dest, src, op2);}
|
||||
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, false, dest, src, op2);}
|
||||
void ARMXEmitter::LSRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(3, true, dest, src, op2);}
|
||||
void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, false, dest, src, op2);}
|
||||
void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, true, dest, src, op2);}
|
||||
void ARMXEmitter::ASR (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, false, dest, src, op2);}
|
||||
void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(5, true, dest, src, op2);}
|
||||
|
||||
void ARMXEmitter::MUL (ARMReg dest, ARMReg src, ARMReg op2)
|
||||
{
|
||||
Write32(condition | (dest << 16) | (src << 8) | (9 << 4) | op2);
|
||||
@@ -891,54 +898,6 @@ ARMReg ARMXEmitter::SubBase(ARMReg Reg)
|
||||
return Reg;
|
||||
}
|
||||
|
||||
// NEON Specific
|
||||
void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VABD(float)");
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it");
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
|
||||
| ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \
|
||||
| ((Vm & 0x10) << 2) | (Vm & 0xF));
|
||||
}
|
||||
void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)");
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it");
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
|
||||
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \
|
||||
| ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
|
||||
}
|
||||
void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)");
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it");
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
|
||||
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
|
||||
| ((Vm & 0x10) << 2) | (Vm & 0xF));
|
||||
}
|
||||
|
||||
// Double/single, Neon
|
||||
extern const VFPEnc VFPOps[16][2] = {
|
||||
{{0xE0, 0xA0}, {0x20, 0xD1}}, // 0: VMLA
|
||||
@@ -958,7 +917,7 @@ extern const VFPEnc VFPOps[16][2] = {
|
||||
{{ -1, -1}, {0x3B, 0x30}}, // 14: VABSi
|
||||
};
|
||||
|
||||
extern const char *VFPOpNames[16] = {
|
||||
const char *VFPOpNames[16] = {
|
||||
"VMLA",
|
||||
"VNMLA",
|
||||
"VMLS",
|
||||
@@ -1013,10 +972,10 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm)
|
||||
ARMReg Reg = SubBase(Vm);
|
||||
|
||||
if (quad_reg)
|
||||
return ((Reg & 0x10) << 2) | (Reg & 0xF);
|
||||
return ((Reg & 0x10) << 1) | (Reg & 0xF);
|
||||
else
|
||||
if (double_reg)
|
||||
return ((Reg & 0x10) << 2) | (Reg & 0xF);
|
||||
return ((Reg & 0x10) << 1) | (Reg & 0xF);
|
||||
else
|
||||
return ((Reg & 0x1) << 5) | (Reg >> 1);
|
||||
}
|
||||
@@ -1036,6 +995,22 @@ void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
|
||||
Write32(cond | (enc.opc1 << 20) | VnEnc | VdEnc | (enc.opc2 << 4) | (quad_reg << 6) | (double_reg << 8) | VmEnc);
|
||||
}
|
||||
void ARMXEmitter::WriteVFPDataOp6bit(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm, u32 bit6)
|
||||
{
|
||||
bool quad_reg = Vd >= Q0;
|
||||
bool double_reg = Vd >= D0 && Vd < Q0;
|
||||
|
||||
VFPEnc enc = VFPOps[Op][quad_reg];
|
||||
if (enc.opc1 == -1 && enc.opc2 == -1)
|
||||
_dbg_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP");
|
||||
u32 VdEnc = EncodeVd(Vd);
|
||||
u32 VnEnc = EncodeVn(Vn);
|
||||
u32 VmEnc = EncodeVm(Vm);
|
||||
u32 cond = quad_reg ? (0xF << 28) : condition;
|
||||
|
||||
Write32(cond | (enc.opc1 << 20) | VnEnc | VdEnc | (enc.opc2 << 4) | (bit6 << 6) | (double_reg << 8) | VmEnc);
|
||||
}
|
||||
|
||||
void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(0, Vd, Vn, Vm); }
|
||||
void ARMXEmitter::VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); }
|
||||
void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); }
|
||||
@@ -1047,11 +1022,11 @@ void ARMXEmitter::VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(7, Vd,
|
||||
void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D0, Vm); }
|
||||
void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(9, Vd, Vn, Vm); }
|
||||
void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D1, Vm); }
|
||||
void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(11, Vd, D1, Vm); }
|
||||
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(12, Vd, D4, Vm); }
|
||||
void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(13, Vd, D4, Vm); }
|
||||
void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(12, Vd, D5, D0); }
|
||||
void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(13, Vd, D5, D0); }
|
||||
void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp6bit(11, Vd, D1, Vm, 3); }
|
||||
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp6bit(12, Vd, D4, Vm, 1); }
|
||||
void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp6bit(13, Vd, D4, Vm, 1); }
|
||||
void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp6bit(12, Vd, D5, D0, 1); }
|
||||
void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp6bit(13, Vd, D5, D0, 1); }
|
||||
|
||||
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
|
||||
{
|
||||
@@ -1110,9 +1085,6 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset)
|
||||
}
|
||||
}
|
||||
|
||||
void ARMXEmitter::VMRS_APSR() {
|
||||
Write32(condition | 0xEF10A10 | (15 << 12));
|
||||
}
|
||||
void ARMXEmitter::VMRS(ARMReg Rt) {
|
||||
Write32(condition | (0xEF << 20) | (1 << 16) | (Rt << 12) | 0xA10);
|
||||
}
|
||||
@@ -1124,7 +1096,8 @@ void ARMXEmitter::VMSR(ARMReg Rt) {
|
||||
void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bVFPv3, "VMOV #imm requires VFPv3");
|
||||
Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (0xA << 8) | op2.Imm8VFP());
|
||||
bool double_reg = Dest >= D0;
|
||||
Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (0x5 << 9) | (double_reg << 8) | op2.Imm8VFP());
|
||||
}
|
||||
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high)
|
||||
{
|
||||
@@ -1177,7 +1150,10 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||
else
|
||||
{
|
||||
// Move 64bit To Arm reg
|
||||
_dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON");
|
||||
ARMReg Dest2 = (ARMReg)(Dest + 1);
|
||||
Src = SubBase(Src);
|
||||
Write32(condition | (0xC5 << 20) | (Dest2 << 16) | (Dest << 12) \
|
||||
| (0xB << 8) | ((Dest & 0x10) << 1) | (1 << 4) | (Src & 0xF));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1189,6 +1165,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||
}
|
||||
// Moving NEON registers
|
||||
int SrcSize = Src < D0 ? 1 : Src < Q0 ? 2 : 4;
|
||||
(void) SrcSize;
|
||||
int DestSize = Dest < D0 ? 1 : Dest < Q0 ? 2 : 4;
|
||||
bool Single = DestSize == 1;
|
||||
bool Quad = DestSize == 4;
|
||||
@@ -1267,4 +1244,147 @@ void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
void NEONXEmitter::VABD(NEONElementType Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VABD(float)");
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it");
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (encodedSize(Size) << 20) | ((Vn & 0xF) << 16) \
|
||||
| ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \
|
||||
| ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
}
|
||||
void NEONXEmitter::VADD(NEONElementType Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)");
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it");
|
||||
|
||||
bool register_quad = Vd >= Q0;
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | (encodedSize(Size) << 20) | ((Vn & 0xF) << 16) \
|
||||
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \
|
||||
| ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
|
||||
}
|
||||
void NEONXEmitter::VSUB(NEONElementType Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
_dbg_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)");
|
||||
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it");
|
||||
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (encodedSize(Size) << 20) | ((Vn & 0xF) << 16) \
|
||||
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
|
||||
| ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
}
|
||||
|
||||
void NEONXEmitter::VLD1(NEONElementType Size, ARMReg Vd, ARMReg Rn, NEONAlignment align, ARMReg Rm)
|
||||
{
|
||||
u32 spacing = 0x7; // Only support loading to 1 reg
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
|
||||
Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (1 << 21) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
|
||||
| (align << 4) | Rm);
|
||||
}
|
||||
|
||||
void NEONXEmitter::VLD2(NEONElementType Size, ARMReg Vd, ARMReg Rn, NEONAlignment align, ARMReg Rm)
|
||||
{
|
||||
u32 spacing = 0x8; // Single spaced registers
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
|
||||
Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (1 << 21) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
|
||||
| (align << 4) | Rm);
|
||||
}
|
||||
|
||||
void NEONXEmitter::VST1(NEONElementType Size, ARMReg Vd, ARMReg Rn, NEONAlignment align, ARMReg Rm)
|
||||
{
|
||||
u32 spacing = 0x7; // Single spaced registers
|
||||
// Gets encoded as a double register
|
||||
Vd = SubBase(Vd);
|
||||
|
||||
Write32((0xF4 << 24) | ((Vd & 0x10) << 18) | (Rn << 16)
|
||||
| ((Vd & 0xF) << 12) | (spacing << 8) | (encodedSize(Size) << 6)
|
||||
| (align << 4) | Rm);
|
||||
}
|
||||
|
||||
|
||||
void NEONXEmitter::VREVX(u32 size, NEONElementType Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
bool register_quad = Vd >= Q0;
|
||||
Vd = SubBase(Vd);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | (1 << 23) | ((Vd & 0x10) << 18) | (0x3 << 20)
|
||||
| (encodedSize(Size) << 18) | ((Vd & 0xF) << 12) | (size << 7)
|
||||
| (register_quad << 6) | ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
}
|
||||
|
||||
void NEONXEmitter::VREV64(NEONElementType Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
VREVX(2, Size, Vd, Vm);
|
||||
}
|
||||
|
||||
void NEONXEmitter::VREV32(NEONElementType Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
VREVX(1, Size, Vd, Vm);
|
||||
}
|
||||
|
||||
void NEONXEmitter::VREV16(NEONElementType Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
VREVX(0, Size, Vd, Vm);
|
||||
}
|
||||
|
||||
void NEONXEmitter::VRSQRTE(NEONElementType Size, ARMReg Vd, ARMReg Vm)
|
||||
{
|
||||
bool register_quad = Vd >= Q0;
|
||||
Vd = SubBase(Vd);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | (0xB << 20) | ((Vd & 0x10) << 18) | (0xB << 16)
|
||||
| ((Vd & 0xF) << 12) | (9 << 7) | (Size & F_32 ? (1 << 8) : 0) | (register_quad << 6)
|
||||
| ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
}
|
||||
|
||||
void NEONXEmitter::VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
bool register_quad = Vd >= Q0;
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16)
|
||||
| ((Vd & 0xF) << 12) | (1 << 8) | ((Vn & 0x10) << 3)
|
||||
| (register_quad << 6) | ((Vm & 0x10) << 1) | (1 << 4) | (Vm & 0xF));
|
||||
}
|
||||
void NEONXEmitter::VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
{
|
||||
bool register_quad = Vd >= Q0;
|
||||
Vd = SubBase(Vd);
|
||||
Vn = SubBase(Vn);
|
||||
Vm = SubBase(Vm);
|
||||
|
||||
Write32((0xF2 << 24) | (0x1 << 21) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16)
|
||||
| ((Vd & 0xF) << 12) | (1 << 8) | ((Vn & 0x10) << 3)
|
||||
| (register_quad << 6) | ((Vm & 0x10) << 1) | (1 << 4) | (Vm & 0xF));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -104,13 +104,6 @@ enum ShiftType
|
||||
ST_ROR = 3,
|
||||
ST_RRX = 4
|
||||
};
|
||||
enum IntegerSize
|
||||
{
|
||||
I_I8 = 0,
|
||||
I_I16,
|
||||
I_I32,
|
||||
I_I64
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -349,6 +342,7 @@ typedef const u8* JumpTarget;
|
||||
class ARMXEmitter
|
||||
{
|
||||
friend struct OpArg; // for Write8 etc
|
||||
friend class NEONXEmitter;
|
||||
private:
|
||||
u8 *code, *startcode;
|
||||
u8 *lastCacheFlushEnd;
|
||||
@@ -365,6 +359,7 @@ private:
|
||||
u32 EncodeVn(ARMReg Vn);
|
||||
u32 EncodeVm(ARMReg Vm);
|
||||
void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void WriteVFPDataOp6bit(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm, u32 bit6);
|
||||
|
||||
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||
|
||||
@@ -454,8 +449,13 @@ public:
|
||||
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSLS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSRS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void LSR (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void LSRS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void ASR (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ASRS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void ASR (ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void ASRS(ARMReg dest, ARMReg src, ARMReg op2);
|
||||
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
|
||||
void RBIT(ARMReg dest, ARMReg src);
|
||||
@@ -533,11 +533,7 @@ public:
|
||||
|
||||
// Subtracts the base from the register to give us the real one
|
||||
ARMReg SubBase(ARMReg Reg);
|
||||
// NEON Only
|
||||
void VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
|
||||
|
||||
// VFP Only
|
||||
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
|
||||
void VSTR(ARMReg Src, ARMReg Base, s16 offset);
|
||||
@@ -566,7 +562,6 @@ public:
|
||||
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);
|
||||
|
||||
@@ -584,6 +579,72 @@ public:
|
||||
|
||||
}; // class ARMXEmitter
|
||||
|
||||
enum NEONElementType
|
||||
{
|
||||
I_8 = (1 << 0),
|
||||
I_16 = (1 << 1),
|
||||
I_32 = (1 << 2),
|
||||
I_64 = (1 << 3),
|
||||
I_SIGNED = (1 << 4),
|
||||
I_UNSIGNED = (1 << 5),
|
||||
F_32 = (1 << 6)
|
||||
};
|
||||
|
||||
enum NEONAlignment
|
||||
{
|
||||
ALIGN_NONE = 0,
|
||||
ALIGN_64 = 1,
|
||||
ALIGN_128 = 2,
|
||||
ALIGN_256 = 3
|
||||
};
|
||||
|
||||
|
||||
class NEONXEmitter
|
||||
{
|
||||
private:
|
||||
ARMXEmitter *_emit;
|
||||
ARMReg SubBase(ARMReg Reg) { return _emit->SubBase(Reg); }
|
||||
inline void Write32(u32 value) { _emit->Write32(value); }
|
||||
|
||||
inline u32 encodedSize(u32 value)
|
||||
{
|
||||
if (value & I_8)
|
||||
return 0;
|
||||
else if (value & I_16)
|
||||
return 1;
|
||||
else if (value & I_32)
|
||||
return 2;
|
||||
else if (value & I_64)
|
||||
return 3;
|
||||
else
|
||||
_dbg_assert_msg_(DYNA_REC, false, "Passed invalid size to integer NEON instruction");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VREVX(u32 size, NEONElementType Size, ARMReg Vd, ARMReg Vm);
|
||||
|
||||
public:
|
||||
NEONXEmitter(ARMXEmitter *emit)
|
||||
: _emit(emit)
|
||||
{}
|
||||
|
||||
void VABD(NEONElementType Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VADD(NEONElementType Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VSUB(NEONElementType Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VREV64(NEONElementType Size, ARMReg Vd, ARMReg Vm);
|
||||
void VREV32(NEONElementType Size, ARMReg Vd, ARMReg Vm);
|
||||
void VREV16(NEONElementType Size, ARMReg Vd, ARMReg Vm);
|
||||
|
||||
void VRSQRTE(NEONElementType Size, ARMReg Vd, ARMReg Vm);
|
||||
|
||||
void VEOR(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
void VORR(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||
|
||||
void VLD1(NEONElementType Size, ARMReg Vd, ARMReg Rn, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
void VLD2(NEONElementType Size, ARMReg Vd, ARMReg Rn, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
|
||||
void VST1(NEONElementType Size, ARMReg Vd, ARMReg Rn, NEONAlignment align = ALIGN_NONE, ARMReg Rm = _PC);
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
@@ -40,27 +40,45 @@ inline void AtomicIncrement(volatile u32& target) {
|
||||
__sync_add_and_fetch(&target, 1);
|
||||
}
|
||||
|
||||
inline u32 AtomicLoad(volatile u32& src) {
|
||||
return src; // 32-bit reads are always atomic.
|
||||
}
|
||||
inline u32 AtomicLoadAcquire(volatile u32& src) {
|
||||
//keep the compiler from caching any memory references
|
||||
u32 result = src; // 32-bit reads are always atomic.
|
||||
//__sync_synchronize(); // TODO: May not be necessary.
|
||||
// Compiler instruction only. x86 loads always have acquire semantics.
|
||||
__asm__ __volatile__ ( "":::"memory" );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void AtomicOr(volatile u32& target, u32 value) {
|
||||
__sync_or_and_fetch(&target, value);
|
||||
}
|
||||
|
||||
inline void AtomicStore(volatile u32& dest, u32 value) {
|
||||
dest = value; // 32-bit writes are always atomic.
|
||||
#ifdef __clang__
|
||||
template <typename T>
|
||||
_Atomic(T)* ToC11Atomic(volatile T* loc)
|
||||
{
|
||||
return (_Atomic(T)*) loc;
|
||||
}
|
||||
inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
|
||||
__sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics.
|
||||
|
||||
#define __atomic_load_n(p, m) __c11_atomic_load(ToC11Atomic(p), m)
|
||||
#define __atomic_store_n(p, v, m) __c11_atomic_store(ToC11Atomic(p), v, m)
|
||||
#define __atomic_exchange_n(p, v, m) __c11_atomic_exchange(ToC11Atomic(p), v, m)
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline T AtomicLoad(volatile T& src) {
|
||||
return __atomic_load_n(&src, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T AtomicLoadAcquire(volatile T& src) {
|
||||
return __atomic_load_n(&src, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline void AtomicStore(volatile T& dest, U value) {
|
||||
__atomic_store_n(&dest, value, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline void AtomicStoreRelease(volatile T& dest, U value) {
|
||||
__atomic_store_n(&dest, value, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) {
|
||||
return __atomic_exchange_n(&loc, newval, __ATOMIC_ACQ_REL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -74,9 +92,9 @@ LONG SyncInterlockedIncrement(LONG *Dest)
|
||||
#else
|
||||
register int result;
|
||||
__asm__ __volatile__("lock; xadd %0,%1"
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (1), "m" (*Dest)
|
||||
: "memory");
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (1), "m" (*Dest)
|
||||
: "memory");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
@@ -88,9 +106,9 @@ LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val)
|
||||
#else
|
||||
register int result;
|
||||
__asm__ __volatile__("lock; xadd %0,%1"
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (Val), "m" (*Dest)
|
||||
: "memory");
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (Val), "m" (*Dest)
|
||||
: "memory");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
@@ -102,9 +120,9 @@ LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
||||
#else
|
||||
register int result;
|
||||
__asm__ __volatile__("lock; xchg %0,%1"
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (Val), "m" (*Dest)
|
||||
: "memory");
|
||||
: "=r" (result), "=m" (*Dest)
|
||||
: "0" (Val), "m" (*Dest)
|
||||
: "memory");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Common
|
||||
{
|
||||
|
||||
inline void AtomicAdd(volatile u32& target, u32 value) {
|
||||
InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value);
|
||||
_InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value);
|
||||
}
|
||||
|
||||
inline void AtomicAnd(volatile u32& target, u32 value) {
|
||||
@@ -39,32 +39,43 @@ inline void AtomicAnd(volatile u32& target, u32 value) {
|
||||
}
|
||||
|
||||
inline void AtomicIncrement(volatile u32& target) {
|
||||
InterlockedIncrement((volatile LONG*)&target);
|
||||
_InterlockedIncrement((volatile LONG*)&target);
|
||||
}
|
||||
|
||||
inline void AtomicDecrement(volatile u32& target) {
|
||||
InterlockedDecrement((volatile LONG*)&target);
|
||||
}
|
||||
|
||||
inline u32 AtomicLoad(volatile u32& src) {
|
||||
return src; // 32-bit reads are always atomic.
|
||||
}
|
||||
inline u32 AtomicLoadAcquire(volatile u32& src) {
|
||||
u32 result = src; // 32-bit reads are always atomic.
|
||||
_ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics.
|
||||
return result;
|
||||
_InterlockedDecrement((volatile LONG*)&target);
|
||||
}
|
||||
|
||||
inline void AtomicOr(volatile u32& target, u32 value) {
|
||||
_InterlockedOr((volatile LONG*)&target, (LONG)value);
|
||||
}
|
||||
|
||||
inline void AtomicStore(volatile u32& dest, u32 value) {
|
||||
dest = value; // 32-bit writes are always atomic.
|
||||
template <typename T>
|
||||
inline T AtomicLoad(volatile T& src) {
|
||||
return src; // 32-bit reads are always atomic.
|
||||
}
|
||||
inline void AtomicStoreRelease(volatile u32& dest, u32 value) {
|
||||
|
||||
template <typename T>
|
||||
inline T AtomicLoadAcquire(volatile T& src) {
|
||||
T result = src; // 32-bit reads are always atomic.
|
||||
_ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics.
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline void AtomicStore(volatile T& dest, U value) {
|
||||
dest = (T) value; // 32-bit writes are always atomic.
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline void AtomicStoreRelease(volatile T& dest, U value) {
|
||||
_WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics.
|
||||
dest = value; // 32-bit writes are always atomic.
|
||||
dest = (T) value; // 32-bit writes are always atomic.
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) {
|
||||
return (T*) _InterlockedExchangePointer_acq((void* volatile*) &loc, (void*) newval);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -214,7 +214,8 @@ bool cdio_is_cdrom(std::string device)
|
||||
#ifdef __linux__
|
||||
// Resolve symbolic links. This allows symbolic links to valid
|
||||
// drives to be passed from the command line with the -e flag.
|
||||
char *devname = realpath(device.c_str(), NULL);
|
||||
char resolved_path[MAX_PATH];
|
||||
char *devname = realpath(device.c_str(), resolved_path);
|
||||
if (!devname)
|
||||
return false;
|
||||
#endif
|
||||
@@ -234,11 +235,6 @@ bool cdio_is_cdrom(std::string device)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (devname)
|
||||
free(devname);
|
||||
#endif
|
||||
|
||||
devices.clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -12,8 +12,16 @@
|
||||
#define SLEEP(x) usleep(x*1000)
|
||||
#endif
|
||||
|
||||
template <bool> struct CompileTimeAssert;
|
||||
template<> struct CompileTimeAssert<true> {};
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
// Will fail to compile on a non-array:
|
||||
// TODO: make this a function when constexpr is available
|
||||
template <typename T>
|
||||
struct ArraySizeImpl : public std::extent<T>
|
||||
{ static_assert(std::is_array<T>::value, "is array"); };
|
||||
|
||||
#define ArraySize(x) ArraySizeImpl<decltype(x)>::value
|
||||
|
||||
#define b2(x) ( (x) | ( (x) >> 1) )
|
||||
#define b4(x) ( b2(x) | ( b2(x) >> 2) )
|
||||
@@ -52,7 +60,7 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
|
||||
#else
|
||||
#define Crash() {asm ("int $3");}
|
||||
#endif
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
|
||||
// GCC 4.8 defines all the rotate functions now
|
||||
// Small issue with GCC's lrotl/lrotr intrinsics is they are still 32bit while we require 64bit
|
||||
#ifndef _rotl
|
||||
|
||||
@@ -40,18 +40,13 @@
|
||||
#define SYSDATA_DIR "Sys"
|
||||
#elif defined __APPLE__
|
||||
#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"
|
||||
#define SHARED_USER_DIR SYSDATA_DIR
|
||||
#else
|
||||
#ifdef DATA_DIR
|
||||
#define SYSDATA_DIR DATA_DIR "sys"
|
||||
#define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP
|
||||
#else
|
||||
#define SYSDATA_DIR "sys"
|
||||
#define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -64,7 +59,7 @@
|
||||
#define GC_USER_DIR "GC"
|
||||
#define WII_USER_DIR "Wii"
|
||||
#define CONFIG_DIR "Config"
|
||||
#define GAMECONFIG_DIR "GameConfig"
|
||||
#define GAMESETTINGS_DIR "GameSettings"
|
||||
#define MAPS_DIR "Maps"
|
||||
#define CACHE_DIR "Cache"
|
||||
#define SHADERCACHE_DIR "ShaderCache"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace Common
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
template <typename T, bool NeedSize = true>
|
||||
class FifoQueue
|
||||
{
|
||||
public:
|
||||
@@ -27,37 +27,42 @@ public:
|
||||
|
||||
u32 Size() const
|
||||
{
|
||||
static_assert(NeedSize, "using Size() on FifoQueue without NeedSize");
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
//return (m_read_ptr == m_write_ptr);
|
||||
return (0 == m_size);
|
||||
return !AtomicLoad(m_read_ptr->next);
|
||||
}
|
||||
|
||||
T& Front() const
|
||||
{
|
||||
return *m_read_ptr->current;
|
||||
AtomicLoadAcquire(m_read_ptr->next);
|
||||
return m_read_ptr->current;
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
void Push(Arg&& t)
|
||||
{
|
||||
// create the element, add it to the queue
|
||||
m_write_ptr->current = new T(std::forward<Arg>(t));
|
||||
m_write_ptr->current = std::forward<Arg>(t);
|
||||
// set the next pointer to a new element ptr
|
||||
// then advance the write pointer
|
||||
m_write_ptr = m_write_ptr->next = new ElementPtr();
|
||||
Common::AtomicIncrement(m_size);
|
||||
ElementPtr* new_ptr = new ElementPtr();
|
||||
AtomicStoreRelease(m_write_ptr->next, new_ptr);
|
||||
m_write_ptr = new_ptr;
|
||||
if (NeedSize)
|
||||
Common::AtomicIncrement(m_size);
|
||||
}
|
||||
|
||||
void Pop()
|
||||
{
|
||||
Common::AtomicDecrement(m_size);
|
||||
ElementPtr *const tmpptr = m_read_ptr;
|
||||
if (NeedSize)
|
||||
Common::AtomicDecrement(m_size);
|
||||
ElementPtr *tmpptr = m_read_ptr;
|
||||
// advance the read pointer
|
||||
m_read_ptr = m_read_ptr->next;
|
||||
m_read_ptr = AtomicLoad(tmpptr->next);
|
||||
// set the next element to NULL to stop the recursive deletion
|
||||
tmpptr->next = NULL;
|
||||
delete tmpptr; // this also deletes the element
|
||||
@@ -68,9 +73,14 @@ public:
|
||||
if (Empty())
|
||||
return false;
|
||||
|
||||
t = std::move(Front());
|
||||
Pop();
|
||||
if (NeedSize)
|
||||
Common::AtomicDecrement(m_size);
|
||||
|
||||
ElementPtr *tmpptr = m_read_ptr;
|
||||
m_read_ptr = AtomicLoadAcquire(tmpptr->next);
|
||||
t = std::move(tmpptr->current);
|
||||
tmpptr->next = NULL;
|
||||
delete tmpptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,25 +98,20 @@ private:
|
||||
class ElementPtr
|
||||
{
|
||||
public:
|
||||
ElementPtr() : current(NULL), next(NULL) {}
|
||||
ElementPtr() : next(NULL) {}
|
||||
|
||||
~ElementPtr()
|
||||
{
|
||||
if (current)
|
||||
{
|
||||
delete current;
|
||||
// recusion ftw
|
||||
if (next)
|
||||
delete next;
|
||||
}
|
||||
if (next)
|
||||
delete next;
|
||||
}
|
||||
|
||||
T *volatile current;
|
||||
T current;
|
||||
ElementPtr *volatile next;
|
||||
};
|
||||
|
||||
ElementPtr *volatile m_write_ptr;
|
||||
ElementPtr *volatile m_read_ptr;
|
||||
ElementPtr *m_write_ptr;
|
||||
ElementPtr *m_read_ptr;
|
||||
volatile u32 m_size;
|
||||
};
|
||||
|
||||
|
||||
@@ -551,11 +551,24 @@ bool DeleteDirRecursively(const std::string &directory)
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path) return;
|
||||
if (!File::Exists(source_path)) return;
|
||||
if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);
|
||||
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(hFind);
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
const std::string virtualName(TStrToUTF8(ffd.cFileName));
|
||||
#else
|
||||
struct dirent dirent, *result = NULL;
|
||||
DIR *dirp = opendir(source_path.c_str());
|
||||
if (!dirp) return;
|
||||
@@ -563,10 +576,9 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
while (!readdir_r(dirp, &dirent, &result) && result)
|
||||
{
|
||||
const std::string virtualName(result->d_name);
|
||||
#endif
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
if (virtualName == "." || virtualName == "..")
|
||||
continue;
|
||||
|
||||
std::string source, dest;
|
||||
@@ -580,6 +592,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
CopyDir(source, dest);
|
||||
}
|
||||
else if (!File::Exists(dest)) File::Copy(source, dest);
|
||||
#ifdef _WIN32
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
FindClose(hFind);
|
||||
#else
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
@@ -643,9 +659,9 @@ std::string GetSysDirectory()
|
||||
std::string sysDir;
|
||||
|
||||
#if defined (__APPLE__)
|
||||
sysDir = GetBundleDirectory();
|
||||
sysDir += DIR_SEP;
|
||||
sysDir += SYSDATA_DIR;
|
||||
sysDir = GetBundleDirectory() + DIR_SEP + SYSDATA_DIR;
|
||||
#elif defined (_WIN32)
|
||||
sysDir = GetExeDirectory() + DIR_SEP + SYSDATA_DIR;
|
||||
#else
|
||||
sysDir = SYSDATA_DIR;
|
||||
#endif
|
||||
@@ -665,7 +681,56 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
|
||||
if (paths[D_USER_IDX].empty())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
// Detect where the User directory is. There are five different cases (on top of the
|
||||
// command line flag, which overrides all this):
|
||||
// 1. GetExeDirectory()\portable.txt exists
|
||||
// -> Use GetExeDirectory()\User
|
||||
// 2. HKCU\Software\Dolphin Emulator\LocalUserConfig exists and is true
|
||||
// -> Use GetExeDirectory()\User
|
||||
// 3. HKCU\Software\Dolphin Emulator\UserConfigPath exists
|
||||
// -> Use this as the user directory path
|
||||
// 4. My Documents exists
|
||||
// -> Use My Documents\Dolphin Emulator as the User directory path
|
||||
// 5. Default
|
||||
// -> Use GetExeDirectory()\User
|
||||
|
||||
// Check our registry keys
|
||||
HKEY hkey;
|
||||
DWORD local = 0;
|
||||
TCHAR configPath[MAX_PATH] = {0};
|
||||
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), NULL, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD size = 4;
|
||||
if (RegQueryValueEx(hkey, TEXT("LocalUserConfig"), NULL, NULL, reinterpret_cast<LPBYTE>(&local), &size) != ERROR_SUCCESS)
|
||||
local = 0;
|
||||
|
||||
size = MAX_PATH;
|
||||
if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), NULL, NULL, (LPBYTE)configPath, &size) != ERROR_SUCCESS)
|
||||
configPath[0] = 0;
|
||||
RegCloseKey(hkey);
|
||||
}
|
||||
|
||||
local = local || File::Exists(GetExeDirectory() + DIR_SEP "portable.txt");
|
||||
|
||||
// Get Program Files path in case we need it.
|
||||
TCHAR my_documents[MAX_PATH];
|
||||
bool my_documents_found = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, my_documents));
|
||||
|
||||
if (local) // Case 1-2
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
else if (configPath[0]) // Case 3
|
||||
paths[D_USER_IDX] = TStrToUTF8(configPath);
|
||||
else if (my_documents_found) // Case 4
|
||||
paths[D_USER_IDX] = TStrToUTF8(my_documents) + DIR_SEP "Dolphin Emulator" DIR_SEP;
|
||||
else // Case 5
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
|
||||
// Prettify the path: it will be displayed in some places, we don't want a mix of \ and /.
|
||||
paths[D_USER_IDX] = ReplaceAll(paths[D_USER_IDX], "\\", DIR_SEP);
|
||||
|
||||
// Make sure it ends in DIR_SEP.
|
||||
if (*paths[D_USER_IDX].rbegin() != DIR_SEP_CHR)
|
||||
paths[D_USER_IDX] += DIR_SEP;
|
||||
#else
|
||||
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
@@ -679,7 +744,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
|
||||
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
|
||||
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
|
||||
paths[D_GAMESETTINGS_IDX] = paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
@@ -730,37 +795,37 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
|
||||
break;
|
||||
|
||||
case D_USER_IDX:
|
||||
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
|
||||
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
|
||||
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_OPENCL_IDX] = paths[D_USER_IDX] + OPENCL_DIR DIR_SEP;
|
||||
paths[D_HIRESTEXTURES_IDX] = paths[D_USER_IDX] + HIRES_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_DUMPDSP_IDX] = paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[D_MAILLOGS_IDX] = paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP;
|
||||
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
|
||||
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
|
||||
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
|
||||
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
paths[F_WIISYSCONF_IDX] = paths[D_WIISYSCONF_IDX] + WII_SYSCONF;
|
||||
paths[F_RAMDUMP_IDX] = paths[D_DUMP_IDX] + RAM_DUMP;
|
||||
paths[F_ARAMDUMP_IDX] = paths[D_DUMP_IDX] + ARAM_DUMP;
|
||||
paths[F_FAKEVMEMDUMP_IDX] = paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
|
||||
paths[F_GCSRAM_IDX] = paths[D_GCUSER_IDX] + GC_SRAM;
|
||||
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
|
||||
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
|
||||
paths[D_WIIUSER_IDX] = paths[D_WIIROOT_IDX] + DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_GAMESETTINGS_IDX] = paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_OPENCL_IDX] = paths[D_USER_IDX] + OPENCL_DIR DIR_SEP;
|
||||
paths[D_HIRESTEXTURES_IDX] = paths[D_USER_IDX] + HIRES_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_DUMPDSP_IDX] = paths[D_DUMP_IDX] + DUMP_DSP_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[D_MAILLOGS_IDX] = paths[D_LOGS_IDX] + MAIL_LOGS_DIR DIR_SEP;
|
||||
paths[D_WIISYSCONF_IDX] = paths[D_WIIUSER_IDX] + WII_SYSCONF_DIR DIR_SEP;
|
||||
paths[D_THEMES_IDX] = paths[D_USER_IDX] + THEMES_DIR DIR_SEP;
|
||||
paths[F_DOLPHINCONFIG_IDX] = paths[D_CONFIG_IDX] + DOLPHIN_CONFIG;
|
||||
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
paths[F_WIISYSCONF_IDX] = paths[D_WIISYSCONF_IDX] + WII_SYSCONF;
|
||||
paths[F_RAMDUMP_IDX] = paths[D_DUMP_IDX] + RAM_DUMP;
|
||||
paths[F_ARAMDUMP_IDX] = paths[D_DUMP_IDX] + ARAM_DUMP;
|
||||
paths[F_FAKEVMEMDUMP_IDX] = paths[D_DUMP_IDX] + FAKEVMEM_DUMP;
|
||||
paths[F_GCSRAM_IDX] = paths[D_GCUSER_IDX] + GC_SRAM;
|
||||
break;
|
||||
|
||||
case D_CONFIG_IDX:
|
||||
@@ -800,12 +865,10 @@ std::string GetThemeDir(const std::string& theme_name)
|
||||
{
|
||||
std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/";
|
||||
|
||||
#if !defined(_WIN32)
|
||||
// If theme does not exist in user's dir load from shared directory
|
||||
if (!File::Exists(dir))
|
||||
dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
|
||||
#endif
|
||||
|
||||
dir = GetSysDirectory() + THEMES_DIR "/" + theme_name + "/";
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -822,8 +885,34 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str)
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
size_t read_size;
|
||||
str.resize(GetSize(f));
|
||||
return file.ReadArray(&str[0], str.size());
|
||||
bool retval = file.ReadArray(&str[0], str.size(), &read_size);
|
||||
|
||||
// On Windows, reading a text file automatically translates \r\n to \n.
|
||||
// This means we will read less characters than the expected size of the
|
||||
// file. In that case, ignore the return value and count ourselves.
|
||||
#ifdef _WIN32
|
||||
if (text_file)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < read_size; ++i)
|
||||
{
|
||||
if (str[i] == '\n')
|
||||
count += 2;
|
||||
else
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if (count != str.size())
|
||||
return false;
|
||||
|
||||
str.resize(read_size);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
IOFile::IOFile()
|
||||
|
||||
@@ -21,8 +21,8 @@ enum {
|
||||
D_GCUSER_IDX,
|
||||
D_WIIROOT_IDX,
|
||||
D_WIIUSER_IDX,
|
||||
D_CONFIG_IDX,
|
||||
D_GAMECONFIG_IDX,
|
||||
D_CONFIG_IDX, // global settings
|
||||
D_GAMESETTINGS_IDX, // user-specified settings which override both the global and the default settings (per game)
|
||||
D_MAPS_IDX,
|
||||
D_CACHE_IDX,
|
||||
D_SHADERCACHE_IDX,
|
||||
@@ -161,11 +161,15 @@ public:
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
bool ReadArray(T* data, size_t length)
|
||||
bool ReadArray(T* data, size_t length, size_t* pReadBytes = NULL)
|
||||
{
|
||||
if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file))
|
||||
size_t read_bytes = 0;
|
||||
if (!IsOpen() || length != (read_bytes = std::fread(data, sizeof(T), length, m_file)))
|
||||
m_good = false;
|
||||
|
||||
if (pReadBytes)
|
||||
*pReadBytes = read_bytes;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
|
||||
void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
|
||||
{
|
||||
if (line[0] == '#')
|
||||
return;
|
||||
@@ -37,32 +37,15 @@ static void ParseLine(const std::string& line, std::string* keyOut, std::string*
|
||||
|
||||
}
|
||||
|
||||
std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut)
|
||||
{
|
||||
for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
||||
{
|
||||
std::string& line = *iter;
|
||||
std::string lineKey;
|
||||
ParseLine(line, &lineKey, valueOut);
|
||||
if (!strcasecmp(lineKey.c_str(), key))
|
||||
return &line;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IniFile::Section::Set(const char* key, const char* newValue)
|
||||
{
|
||||
std::string value;
|
||||
std::string* line = GetLine(key, &value);
|
||||
if (line)
|
||||
{
|
||||
// Change the value - keep the key and comment
|
||||
*line = StripSpaces(key) + " = " + newValue;
|
||||
}
|
||||
auto it = values.find(key);
|
||||
if (it != values.end())
|
||||
it->second = newValue;
|
||||
else
|
||||
{
|
||||
// The key did not already exist in this section - let's add it.
|
||||
lines.push_back(std::string(key) + " = " + newValue);
|
||||
values[key] = newValue;
|
||||
keys_order.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,20 +57,6 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s
|
||||
Delete(key);
|
||||
}
|
||||
|
||||
bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
|
||||
{
|
||||
std::string* line = GetLine(key, value);
|
||||
if (!line)
|
||||
{
|
||||
if (defaultValue)
|
||||
{
|
||||
*value = defaultValue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IniFile::Section::Set(const char* key, const float newValue, const float defaultValue)
|
||||
{
|
||||
if (newValue != defaultValue)
|
||||
@@ -126,7 +95,24 @@ void IniFile::Section::Set(const char* key, const std::vector<std::string>& newV
|
||||
Set(key, temp.c_str());
|
||||
}
|
||||
|
||||
bool IniFile::Section::Get(const char* key, std::vector<std::string>& values)
|
||||
bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
|
||||
{
|
||||
auto it = values.find(key);
|
||||
if (it != values.end())
|
||||
{
|
||||
*value = it->second;
|
||||
return true;
|
||||
}
|
||||
else if (defaultValue)
|
||||
{
|
||||
*value = defaultValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IniFile::Section::Get(const char* key, std::vector<std::string>& out)
|
||||
{
|
||||
std::string temp;
|
||||
bool retval = Get(key, &temp, 0);
|
||||
@@ -145,7 +131,7 @@ bool IniFile::Section::Get(const char* key, std::vector<std::string>& values)
|
||||
subEnd = temp.find_first_of(",", subStart);
|
||||
if (subStart != subEnd)
|
||||
// take from first char until next ,
|
||||
values.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));
|
||||
out.push_back(StripSpaces(temp.substr(subStart, subEnd - subStart)));
|
||||
|
||||
// Find the next non , char
|
||||
subStart = temp.find_first_not_of(",", subEnd);
|
||||
@@ -206,28 +192,18 @@ bool IniFile::Section::Get(const char* key, double* value, double defaultValue)
|
||||
|
||||
bool IniFile::Section::Exists(const char *key) const
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
||||
{
|
||||
std::string lineKey;
|
||||
ParseLine(*iter, &lineKey, NULL);
|
||||
if (!strcasecmp(lineKey.c_str(), key))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return values.find(key) != values.end();
|
||||
}
|
||||
|
||||
bool IniFile::Section::Delete(const char *key)
|
||||
{
|
||||
std::string* line = GetLine(key, 0);
|
||||
for (std::vector<std::string>::iterator liter = lines.begin(); liter != lines.end(); ++liter)
|
||||
{
|
||||
if (line == &*liter)
|
||||
{
|
||||
lines.erase(liter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
auto it = values.find(key);
|
||||
if (it == values.end())
|
||||
return false;
|
||||
|
||||
values.erase(it);
|
||||
keys_order.erase(std::find(keys_order.begin(), keys_order.end(), key));
|
||||
return true;
|
||||
}
|
||||
|
||||
// IniFile
|
||||
@@ -286,11 +262,7 @@ bool IniFile::Exists(const char* sectionName, const char* key) const
|
||||
void IniFile::SetLines(const char* sectionName, const std::vector<std::string> &lines)
|
||||
{
|
||||
Section* section = GetOrCreateSection(sectionName);
|
||||
section->lines.clear();
|
||||
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
||||
{
|
||||
section->lines.push_back(*iter);
|
||||
}
|
||||
section->lines = lines;
|
||||
}
|
||||
|
||||
bool IniFile::DeleteKey(const char* sectionName, const char* key)
|
||||
@@ -298,16 +270,7 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key)
|
||||
Section* section = GetSection(sectionName);
|
||||
if (!section)
|
||||
return false;
|
||||
std::string* line = section->GetLine(key, 0);
|
||||
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
||||
{
|
||||
if (line == &(*liter))
|
||||
{
|
||||
section->lines.erase(liter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; //shouldn't happen
|
||||
return section->Delete(key);
|
||||
}
|
||||
|
||||
// Return a list of all keys in a section
|
||||
@@ -316,13 +279,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c
|
||||
const Section* section = GetSection(sectionName);
|
||||
if (!section)
|
||||
return false;
|
||||
keys.clear();
|
||||
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
|
||||
{
|
||||
std::string key;
|
||||
ParseLine(*liter, &key, 0);
|
||||
keys.push_back(key);
|
||||
}
|
||||
keys = section->keys_order;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -364,13 +321,13 @@ void IniFile::SortSections()
|
||||
std::sort(sections.begin(), sections.end());
|
||||
}
|
||||
|
||||
bool IniFile::Load(const char* filename)
|
||||
bool IniFile::Load(const char* filename, bool keep_current_data)
|
||||
{
|
||||
// Maximum number of letters in a line
|
||||
static const int MAX_BYTES = 1024*32;
|
||||
|
||||
sections.clear();
|
||||
sections.push_back(Section(""));
|
||||
if (!keep_current_data)
|
||||
sections.clear();
|
||||
// first section consists of the comments before the first real section
|
||||
|
||||
// Open file
|
||||
@@ -379,12 +336,13 @@ bool IniFile::Load(const char* filename)
|
||||
|
||||
if (in.fail()) return false;
|
||||
|
||||
Section* current_section = NULL;
|
||||
while (!in.eof())
|
||||
{
|
||||
char templine[MAX_BYTES];
|
||||
in.getline(templine, MAX_BYTES);
|
||||
std::string line = templine;
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
// Check for CRLF eol and convert it to LF
|
||||
if (!line.empty() && line.at(line.size()-1) == '\r')
|
||||
@@ -393,8 +351,6 @@ bool IniFile::Load(const char* filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (in.eof()) break;
|
||||
|
||||
if (line.size() > 0)
|
||||
{
|
||||
if (line[0] == '[')
|
||||
@@ -405,12 +361,25 @@ bool IniFile::Load(const char* filename)
|
||||
{
|
||||
// New section!
|
||||
std::string sub = line.substr(1, endpos - 1);
|
||||
sections.push_back(Section(sub));
|
||||
current_section = GetOrCreateSection(sub.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sections[sections.size() - 1].lines.push_back(line);
|
||||
if (current_section)
|
||||
{
|
||||
std::string key, value;
|
||||
ParseLine(line, &key, &value);
|
||||
|
||||
// Lines starting with '$', '*' or '+' are kept verbatim.
|
||||
// Kind of a hack, but the support for raw lines inside an
|
||||
// INI is a hack anyway.
|
||||
if ((key == "" && value == "")
|
||||
|| (line.size() >= 1 && (line[0] == '$' || line[0] == '+' || line[0] == '*')))
|
||||
current_section->lines.push_back(line.c_str());
|
||||
else
|
||||
current_section->Set(key, value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,27 +398,33 @@ bool IniFile::Save(const char* filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Currently testing if dolphin community can handle the requirements of C++11 compilation
|
||||
// If you get a compiler error on this line, your compiler is probably old.
|
||||
// Update to g++ 4.4 or a recent version of clang (XCode 4.2 on OS X).
|
||||
// If you don't want to update, complain in a google code issue, the dolphin forums or #dolphin-emu.
|
||||
for (auto iter = sections.begin(); iter != sections.end(); ++iter)
|
||||
{
|
||||
const Section& section = *iter;
|
||||
|
||||
if (section.name != "")
|
||||
{
|
||||
if (section.keys_order.size() != 0 || section.lines.size() != 0)
|
||||
out << "[" << section.name << "]" << std::endl;
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)
|
||||
if (section.keys_order.size() == 0)
|
||||
{
|
||||
std::string s = *liter;
|
||||
out << s << std::endl;
|
||||
for (auto liter = section.lines.begin(); liter != section.lines.end(); ++liter)
|
||||
{
|
||||
std::string s = *liter;
|
||||
out << s << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto kvit = section.keys_order.begin(); kvit != section.keys_order.end(); ++kvit)
|
||||
{
|
||||
auto pair = section.values.find(*kvit);
|
||||
out << pair->first << " = " << pair->second << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,21 @@
|
||||
#ifndef _INIFILE_H_
|
||||
#define _INIFILE_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
struct CaseInsensitiveStringCompare
|
||||
{
|
||||
bool operator() (const std::string& a, const std::string& b) const
|
||||
{
|
||||
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class IniFile
|
||||
{
|
||||
public:
|
||||
@@ -25,7 +35,6 @@ public:
|
||||
bool Exists(const char *key) const;
|
||||
bool Delete(const char *key);
|
||||
|
||||
std::string* GetLine(const char* key, std::string* valueOut);
|
||||
void Set(const char* key, const char* newValue);
|
||||
void Set(const char* key, const std::string& newValue, const std::string& defaultValue);
|
||||
|
||||
@@ -68,12 +77,24 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<std::string> lines;
|
||||
std::string name;
|
||||
|
||||
std::vector<std::string> keys_order;
|
||||
std::map<std::string, std::string, CaseInsensitiveStringCompare> values;
|
||||
|
||||
std::vector<std::string> lines;
|
||||
};
|
||||
|
||||
bool Load(const char* filename);
|
||||
bool Load(const std::string &filename) { return Load(filename.c_str()); }
|
||||
/**
|
||||
* Loads sections and keys.
|
||||
* @param filename filename of the ini file which should be loaded
|
||||
* @param keep_current_data If true, "extends" the currently loaded list of sections and keys with the loaded data (and replaces existing entries). If false, existing data will be erased.
|
||||
* @warning Using any other operations than "Get*" and "Exists" is untested and will behave unexpectedly
|
||||
* @todo This really is just a hack to support having two levels of gameinis (defaults and user-specified) and should eventually be replaced with a less stupid system.
|
||||
*/
|
||||
bool Load(const char* filename, bool keep_current_data = false);
|
||||
bool Load(const std::string &filename, bool keep_current_data = false) { return Load(filename.c_str(), keep_current_data); }
|
||||
|
||||
bool Save(const char* filename);
|
||||
bool Save(const std::string &filename) { return Save(filename.c_str()); }
|
||||
|
||||
|
||||
@@ -143,20 +143,20 @@ u8* MemArena::Find4GBBase()
|
||||
return base;
|
||||
#else
|
||||
#ifdef ANDROID
|
||||
const u32 MemSize = 0x04000000;
|
||||
// Android 4.3 changed how mmap works.
|
||||
// if we map it private and then munmap it, we can't use the base returned.
|
||||
// This may be due to changes in them support a full SELinux implementation.
|
||||
const int flags = MAP_ANON;
|
||||
#else
|
||||
const u32 MemSize = 0x31000000;
|
||||
const int flags = MAP_ANON | MAP_PRIVATE;
|
||||
#endif
|
||||
void* base = mmap(0, MemSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
const u32 MemSize = 0x31000000;
|
||||
void* base = mmap(0, MemSize, PROT_NONE, flags, -1, 0);
|
||||
if (base == MAP_FAILED) {
|
||||
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
#ifndef ANDROID
|
||||
// Android 4.3 changes how munmap works which causes crashes.
|
||||
// Keep the memory space after allocating it...
|
||||
munmap(base, MemSize);
|
||||
#endif
|
||||
return static_cast<u8*>(base);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -45,7 +45,7 @@ const std::string SettingsHandler::GetValue(const std::string key)
|
||||
else
|
||||
{
|
||||
toFind = key + "=";
|
||||
size_t found = decoded.find(toFind);
|
||||
found = decoded.find(toFind);
|
||||
if (found == 0)
|
||||
{
|
||||
size_t delimFound = decoded.find(delim, found + toFind.length());
|
||||
|
||||
@@ -164,12 +164,11 @@ bool TryParse(const std::string &str, u32 *const output)
|
||||
if (errno == ERANGE)
|
||||
return false;
|
||||
|
||||
if (ULONG_MAX > UINT_MAX) {
|
||||
// Note: The typecasts avoid GCC warnings when long is 32 bits wide.
|
||||
if (value >= static_cast<unsigned long>(0x100000000ull)
|
||||
&& value <= static_cast<unsigned long>(0xFFFFFFFF00000000ull))
|
||||
return false;
|
||||
}
|
||||
#if ULONG_MAX > UINT_MAX
|
||||
if (value >= 0x100000000ull
|
||||
&& value <= 0xFFFFFFFF00000000ull)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
*output = static_cast<u32>(value);
|
||||
return true;
|
||||
@@ -270,8 +269,8 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
const int pos = result.find(src);
|
||||
if (pos == -1) break;
|
||||
size_t pos = result.find(src);
|
||||
if (pos == std::string::npos) break;
|
||||
result.replace(pos, src.size(), dest);
|
||||
}
|
||||
return result;
|
||||
@@ -317,7 +316,7 @@ std::string UriDecode(const std::string & sSrc)
|
||||
// for future extension"
|
||||
|
||||
const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
|
||||
const int SRC_LEN = sSrc.length();
|
||||
const size_t SRC_LEN = sSrc.length();
|
||||
const unsigned char * const SRC_END = pSrc + SRC_LEN;
|
||||
const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%'
|
||||
|
||||
@@ -379,7 +378,7 @@ std::string UriEncode(const std::string & sSrc)
|
||||
{
|
||||
const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
|
||||
const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
|
||||
const int SRC_LEN = sSrc.length();
|
||||
const size_t SRC_LEN = sSrc.length();
|
||||
unsigned char * const pStart = new unsigned char[SRC_LEN * 3];
|
||||
unsigned char * pEnd = pStart;
|
||||
const unsigned char * const SRC_END = pSrc + SRC_LEN;
|
||||
|
||||
@@ -39,10 +39,6 @@ Timer::Timer()
|
||||
: m_LastTime(0), m_StartTime(0), m_Running(false)
|
||||
{
|
||||
Update();
|
||||
|
||||
#ifdef _WIN32
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&m_frequency);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write the starting time
|
||||
|
||||
@@ -38,7 +38,6 @@ public:
|
||||
private:
|
||||
u64 m_LastTime;
|
||||
u64 m_StartTime;
|
||||
u64 m_frequency;
|
||||
bool m_Running;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,38 +10,51 @@ using namespace Gen;
|
||||
|
||||
// Shared code between Win64 and Unix64
|
||||
|
||||
// Sets up a __cdecl function.
|
||||
void XEmitter::ABI_EmitPrologue(int maxCallParams)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
// Don't really need to do anything
|
||||
#elif defined(_M_X64)
|
||||
#if _WIN32
|
||||
int stacksize = ((maxCallParams + 1) & ~1) * 8 + 8;
|
||||
// Set up a stack frame so that we can call functions
|
||||
// TODO: use maxCallParams
|
||||
SUB(64, R(RSP), Imm8(stacksize));
|
||||
#endif
|
||||
unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize, bool noProlog) {
|
||||
// On platforms other than Windows 32-bit: At the beginning of a function,
|
||||
// the stack pointer is 4/8 bytes less than a multiple of 16; however, the
|
||||
// function prolog immediately subtracts an appropriate amount to align
|
||||
// it, so no alignment is required around a call.
|
||||
// In the functions generated by ThunkManager::ProtectFunction and some
|
||||
// others, we add the necessary subtraction (and 0x20 bytes shadow space
|
||||
// for Win64) into this rather than having a separate prolog.
|
||||
// On Windows 32-bit, the required alignment is only 4 bytes, so we just
|
||||
// ensure that the frame size isn't misaligned.
|
||||
#ifdef _M_X64
|
||||
// expect frameSize == 0
|
||||
frameSize = noProlog ? 0x28 : 0;
|
||||
#elif defined(_WIN32)
|
||||
frameSize = (frameSize + 3) & -4;
|
||||
#else
|
||||
#error Arch not supported
|
||||
unsigned int existingAlignment = noProlog ? 0xc : 0;
|
||||
frameSize -= existingAlignment;
|
||||
frameSize = (frameSize + 15) & -16;
|
||||
frameSize += existingAlignment;
|
||||
#endif
|
||||
return frameSize;
|
||||
}
|
||||
|
||||
void XEmitter::ABI_EmitEpilogue(int maxCallParams)
|
||||
{
|
||||
#ifdef _M_IX86
|
||||
RET();
|
||||
#elif defined(_M_X64)
|
||||
#ifdef _WIN32
|
||||
int stacksize = ((maxCallParams+1)&~1)*8 + 8;
|
||||
ADD(64, R(RSP), Imm8(stacksize));
|
||||
#endif
|
||||
RET();
|
||||
void XEmitter::ABI_AlignStack(unsigned int frameSize, bool noProlog) {
|
||||
unsigned int fillSize =
|
||||
ABI_GetAlignedFrameSize(frameSize, noProlog) - frameSize;
|
||||
if (fillSize != 0) {
|
||||
#ifdef _M_X64
|
||||
SUB(64, R(RSP), Imm8(fillSize));
|
||||
#else
|
||||
#error Arch not supported
|
||||
|
||||
|
||||
SUB(32, R(ESP), Imm8(fillSize));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int frameSize, bool noProlog) {
|
||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize, noProlog);
|
||||
if (alignedSize != 0) {
|
||||
#ifdef _M_X64
|
||||
ADD(64, R(RSP), Imm8(alignedSize));
|
||||
#else
|
||||
ADD(32, R(ESP), Imm8(alignedSize));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _M_IX86 // All32
|
||||
@@ -65,7 +78,7 @@ void XEmitter::ABI_CallFunctionCC16(void *func, u32 param1, u16 param2) {
|
||||
PUSH(16, Imm16(param2));
|
||||
PUSH(32, Imm32(param1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(1 * 2 + 1 * 4);
|
||||
ABI_AlignStack(1 * 2 + 1 * 4);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC(void *func, u32 param1) {
|
||||
@@ -129,13 +142,13 @@ void XEmitter::ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||
}
|
||||
|
||||
// Pass two registers as parameters.
|
||||
void XEmitter::ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2)
|
||||
void XEmitter::ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2, bool noProlog)
|
||||
{
|
||||
ABI_AlignStack(2 * 4);
|
||||
ABI_AlignStack(2 * 4, noProlog);
|
||||
PUSH(32, R(reg2));
|
||||
PUSH(32, R(reg1));
|
||||
CALL(func);
|
||||
ABI_RestoreStack(2 * 4);
|
||||
ABI_RestoreStack(2 * 4, noProlog);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
||||
@@ -156,60 +169,27 @@ void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1)
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
// Note: 4 * 4 = 16 bytes, so alignment is preserved.
|
||||
PUSH(EBP);
|
||||
MOV(32, R(EBP), R(ESP));
|
||||
PUSH(EBX);
|
||||
PUSH(ESI);
|
||||
PUSH(EDI);
|
||||
SUB(32, R(ESP), Imm8(0xc));
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
ADD(32, R(ESP), Imm8(0xc));
|
||||
POP(EDI);
|
||||
POP(ESI);
|
||||
POP(EBX);
|
||||
POP(EBP);
|
||||
}
|
||||
|
||||
unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
||||
frameSize += 4; // reserve space for return address
|
||||
unsigned int alignedSize =
|
||||
#ifdef __GNUC__
|
||||
(frameSize + 15) & -16;
|
||||
#else
|
||||
(frameSize + 3) & -4;
|
||||
#endif
|
||||
return alignedSize;
|
||||
}
|
||||
|
||||
|
||||
void XEmitter::ABI_AlignStack(unsigned int frameSize) {
|
||||
// Mac OS X requires the stack to be 16-byte aligned before every call.
|
||||
// Linux requires the stack to be 16-byte aligned before calls that put SSE
|
||||
// vectors on the stack, but since we do not keep track of which calls do that,
|
||||
// it is effectively every call as well.
|
||||
// Windows binaries compiled with MSVC do not have such a restriction*, but I
|
||||
// expect that GCC on Windows acts the same as GCC on Linux in this respect.
|
||||
// It would be nice if someone could verify this.
|
||||
// *However, the MSVC optimizing compiler assumes a 4-byte-aligned stack at times.
|
||||
unsigned int fillSize =
|
||||
ABI_GetAlignedFrameSize(frameSize) - (frameSize + 4);
|
||||
if (fillSize != 0) {
|
||||
SUB(32, R(ESP), Imm8(fillSize));
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int frameSize) {
|
||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(frameSize);
|
||||
alignedSize -= 4; // return address is POPped at end of call
|
||||
if (alignedSize != 0) {
|
||||
ADD(32, R(ESP), Imm8(alignedSize));
|
||||
}
|
||||
}
|
||||
|
||||
#else //64bit
|
||||
|
||||
// Common functions
|
||||
void XEmitter::ABI_CallFunction(void *func) {
|
||||
ABI_AlignStack(0);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
@@ -219,9 +199,11 @@ void XEmitter::ABI_CallFunction(void *func) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC16(void *func, u16 param1) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32((u32)param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
@@ -232,9 +214,11 @@ void XEmitter::ABI_CallFunctionC16(void *func, u16 param1) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC16(void *func, u32 param1, u16 param2) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32((u32)param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
@@ -246,9 +230,11 @@ void XEmitter::ABI_CallFunctionCC16(void *func, u32 param1, u16 param2) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC(void *func, u32 param1) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
@@ -259,9 +245,11 @@ void XEmitter::ABI_CallFunctionC(void *func, u32 param1) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
@@ -273,9 +261,11 @@ void XEmitter::ABI_CallFunctionCC(void *func, u32 param1, u32 param2) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param3) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
@@ -288,9 +278,11 @@ void XEmitter::ABI_CallFunctionCCC(void *func, u32 param1, u32 param2, u32 param
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *param3) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(64, R(ABI_PARAM3), Imm64((u64)param3));
|
||||
@@ -303,9 +295,11 @@ void XEmitter::ABI_CallFunctionCCP(void *func, u32 param1, u32 param2, void *par
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 param3, void *param4) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
@@ -319,9 +313,11 @@ void XEmitter::ABI_CallFunctionCCCP(void *func, u32 param1, u32 param2, u32 para
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 param3) {
|
||||
ABI_AlignStack(0);
|
||||
MOV(64, R(ABI_PARAM1), Imm64((u64)param1));
|
||||
MOV(64, R(ABI_PARAM2), Imm64((u64)param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
@@ -334,10 +330,12 @@ void XEmitter::ABI_CallFunctionPPC(void *func, void *param1, void *param2, u32 p
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
// Pass a register as a parameter.
|
||||
void XEmitter::ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||
ABI_AlignStack(0);
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(32, R(ABI_PARAM1), R(reg1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
@@ -349,10 +347,12 @@ void XEmitter::ABI_CallFunctionR(void *func, X64Reg reg1) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
// Pass two registers as parameters.
|
||||
void XEmitter::ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
|
||||
void XEmitter::ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2, bool noProlog) {
|
||||
ABI_AlignStack(0, noProlog);
|
||||
if (reg2 != ABI_PARAM1) {
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(64, R(ABI_PARAM1), R(reg1));
|
||||
@@ -373,10 +373,12 @@ void XEmitter::ABI_CallFunctionRR(void *func, X64Reg reg1, X64Reg reg2) {
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0, noProlog);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2)
|
||||
{
|
||||
ABI_AlignStack(0);
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
@@ -389,10 +391,12 @@ void XEmitter::ABI_CallFunctionAC(void *func, const Gen::OpArg &arg1, u32 param2
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
ABI_RestoreStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1)
|
||||
{
|
||||
ABI_AlignStack(0);
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
@@ -404,42 +408,9 @@ void XEmitter::ABI_CallFunctionA(void *func, const Gen::OpArg &arg1)
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int XEmitter::ABI_GetAlignedFrameSize(unsigned int frameSize) {
|
||||
return frameSize;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Win64 Specific Code
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
//we only want to do this once
|
||||
PUSH(RBX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(RBP);
|
||||
PUSH(R12);
|
||||
PUSH(R13);
|
||||
PUSH(R14);
|
||||
PUSH(R15);
|
||||
//TODO: Also preserve XMM0-3?
|
||||
ABI_AlignStack(0);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
ABI_RestoreStack(0);
|
||||
POP(R15);
|
||||
POP(R14);
|
||||
POP(R13);
|
||||
POP(R12);
|
||||
POP(RBP);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RBX);
|
||||
}
|
||||
|
||||
// Win64 Specific Code
|
||||
void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||
PUSH(RCX);
|
||||
PUSH(RDX);
|
||||
@@ -449,12 +420,11 @@ void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||
PUSH(R9);
|
||||
PUSH(R10);
|
||||
PUSH(R11);
|
||||
//TODO: Also preserve XMM0-15?
|
||||
ABI_AlignStack(0);
|
||||
PUSH(R11);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||
ABI_RestoreStack(0);
|
||||
POP(R11);
|
||||
POP(R11);
|
||||
POP(R10);
|
||||
POP(R9);
|
||||
@@ -465,66 +435,59 @@ void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||
POP(RCX);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Win64 Specific Code
|
||||
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
//we only want to do this once
|
||||
PUSH(RBP);
|
||||
MOV(64, R(RBP), R(RSP));
|
||||
PUSH(RBX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(R12);
|
||||
PUSH(R13);
|
||||
PUSH(R14);
|
||||
PUSH(R15);
|
||||
SUB(64, R(RSP), Imm8(0x28));
|
||||
//TODO: Also preserve XMM0-3?
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
ADD(64, R(RSP), Imm8(0x28));
|
||||
POP(R15);
|
||||
POP(R14);
|
||||
POP(R13);
|
||||
POP(R12);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RBX);
|
||||
POP(RBP);
|
||||
}
|
||||
|
||||
#else
|
||||
// Unix64 Specific Code
|
||||
|
||||
void XEmitter::ABI_PushAllCalleeSavedRegsAndAdjustStack() {
|
||||
PUSH(RBX);
|
||||
PUSH(RBP);
|
||||
MOV(64, R(RBP), R(RSP));
|
||||
PUSH(RBX);
|
||||
PUSH(R12);
|
||||
PUSH(R13);
|
||||
PUSH(R14);
|
||||
PUSH(R15);
|
||||
PUSH(R15); //just to align stack. duped push/pop doesn't hurt.
|
||||
SUB(64, R(RSP), Imm8(8));
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCalleeSavedRegsAndAdjustStack() {
|
||||
POP(R15);
|
||||
ADD(64, R(RSP), Imm8(8));
|
||||
POP(R15);
|
||||
POP(R14);
|
||||
POP(R13);
|
||||
POP(R12);
|
||||
POP(RBP);
|
||||
POP(RBX);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PushAllCallerSavedRegsAndAdjustStack() {
|
||||
PUSH(RCX);
|
||||
PUSH(RDX);
|
||||
PUSH(RSI);
|
||||
PUSH(RDI);
|
||||
PUSH(R8);
|
||||
PUSH(R9);
|
||||
PUSH(R10);
|
||||
PUSH(R11);
|
||||
PUSH(R11);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopAllCallerSavedRegsAndAdjustStack() {
|
||||
POP(R11);
|
||||
POP(R11);
|
||||
POP(R10);
|
||||
POP(R9);
|
||||
POP(R8);
|
||||
POP(RDI);
|
||||
POP(RSI);
|
||||
POP(RDX);
|
||||
POP(RCX);
|
||||
}
|
||||
|
||||
void XEmitter::ABI_AlignStack(unsigned int /*frameSize*/) {
|
||||
SUB(64, R(RSP), Imm8(0x08));
|
||||
}
|
||||
|
||||
void XEmitter::ABI_RestoreStack(unsigned int /*frameSize*/) {
|
||||
ADD(64, R(RSP), Imm8(0x08));
|
||||
POP(RBP);
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "x64Analyzer.h"
|
||||
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
|
||||
{
|
||||
unsigned const char *startCodePtr = codePtr;
|
||||
u8 rex = 0;
|
||||
@@ -12,11 +12,11 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
u8 codeByte2 = 0;
|
||||
|
||||
//Check for regular prefix
|
||||
info.operandSize = 4;
|
||||
info.zeroExtend = false;
|
||||
info.signExtend = false;
|
||||
info.hasImmediate = false;
|
||||
info.isMemoryWrite = false;
|
||||
info->operandSize = 4;
|
||||
info->zeroExtend = false;
|
||||
info->signExtend = false;
|
||||
info->hasImmediate = false;
|
||||
info->isMemoryWrite = false;
|
||||
|
||||
u8 modRMbyte = 0;
|
||||
u8 sibByte = 0;
|
||||
@@ -26,7 +26,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
|
||||
if (*codePtr == 0x66)
|
||||
{
|
||||
info.operandSize = 2;
|
||||
info->operandSize = 2;
|
||||
codePtr++;
|
||||
}
|
||||
else if (*codePtr == 0x67)
|
||||
@@ -40,7 +40,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
rex = *codePtr;
|
||||
if (rex & 8) //REX.W
|
||||
{
|
||||
info.operandSize = 8;
|
||||
info->operandSize = 8;
|
||||
}
|
||||
codePtr++;
|
||||
}
|
||||
@@ -72,11 +72,11 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
(codeByte2 & 0xF0) == 0x80 ||
|
||||
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
|
||||
(codeByte2 & 0xF8) == 0xC8)
|
||||
{
|
||||
{
|
||||
// No mod R/M byte
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
modRMbyte = *codePtr++;
|
||||
hasModRM = true;
|
||||
}
|
||||
@@ -85,21 +85,21 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
if (hasModRM)
|
||||
{
|
||||
ModRM mrm(modRMbyte, rex);
|
||||
info.regOperandReg = mrm.reg;
|
||||
info->regOperandReg = mrm.reg;
|
||||
if (mrm.mod < 3)
|
||||
{
|
||||
if (mrm.rm == 4)
|
||||
{
|
||||
//SIB byte
|
||||
sibByte = *codePtr++;
|
||||
info.scaledReg = (sibByte >> 3) & 7;
|
||||
info.otherReg = (sibByte & 7);
|
||||
if (rex & 2) info.scaledReg += 8;
|
||||
if (rex & 1) info.otherReg += 8;
|
||||
info->scaledReg = (sibByte >> 3) & 7;
|
||||
info->otherReg = (sibByte & 7);
|
||||
if (rex & 2) info->scaledReg += 8;
|
||||
if (rex & 1) info->otherReg += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
//info.scaledReg =
|
||||
//info->scaledReg =
|
||||
}
|
||||
}
|
||||
if (mrm.mod == 1 || mrm.mod == 2)
|
||||
@@ -112,100 +112,103 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
|
||||
}
|
||||
|
||||
if (displacementSize == 1)
|
||||
info.displacement = (s32)(s8)*codePtr;
|
||||
info->displacement = (s32)(s8)*codePtr;
|
||||
else
|
||||
info.displacement = *((s32 *)codePtr);
|
||||
info->displacement = *((s32 *)codePtr);
|
||||
codePtr += displacementSize;
|
||||
|
||||
|
||||
if (accessType == 1)
|
||||
switch (codeByte)
|
||||
{
|
||||
info.isMemoryWrite = true;
|
||||
//Write access
|
||||
switch (codeByte)
|
||||
// writes
|
||||
case 0xC6: // mem <- imm8
|
||||
{
|
||||
case MOVE_8BIT: //move 8-bit immediate
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *codePtr;
|
||||
codePtr++; //move past immediate
|
||||
}
|
||||
break;
|
||||
|
||||
case MOVE_16_32BIT: //move 16 or 32-bit immediate, easiest case for writes
|
||||
{
|
||||
if (info.operandSize == 2)
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *(u16*)codePtr;
|
||||
codePtr += 2;
|
||||
}
|
||||
else if (info.operandSize == 4)
|
||||
{
|
||||
info.hasImmediate = true;
|
||||
info.immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
else if (info.operandSize == 8)
|
||||
{
|
||||
info.zeroExtend = true;
|
||||
info.immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_REG_TO_MEM: //move reg to memory
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
|
||||
return false;
|
||||
info->isMemoryWrite = true;
|
||||
info->hasImmediate = true;
|
||||
info->immediate = *codePtr;
|
||||
codePtr++; //move past immediate
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Memory read
|
||||
break;
|
||||
|
||||
//mov eax, dword ptr [rax] == 8b 00
|
||||
switch (codeByte)
|
||||
case 0xC7: // mem <- imm16/32
|
||||
{
|
||||
case 0x0F:
|
||||
info->isMemoryWrite = true;
|
||||
if (info->operandSize == 2)
|
||||
{
|
||||
info->hasImmediate = true;
|
||||
info->immediate = *(u16*)codePtr;
|
||||
codePtr += 2;
|
||||
}
|
||||
else if (info->operandSize == 4)
|
||||
{
|
||||
info->hasImmediate = true;
|
||||
info->immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
else if (info->operandSize == 8)
|
||||
{
|
||||
info->zeroExtend = true;
|
||||
info->immediate = *(u32*)codePtr;
|
||||
codePtr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
case 0x89: // mem <- r16/32/64
|
||||
{
|
||||
info->isMemoryWrite = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0F: // two-byte escape
|
||||
{
|
||||
info->isMemoryWrite = false;
|
||||
switch (codeByte2)
|
||||
{
|
||||
case MOVZX_BYTE: //movzx on byte
|
||||
info.zeroExtend = true;
|
||||
info.operandSize = 1;
|
||||
case 0xB6: // movzx on byte
|
||||
info->zeroExtend = true;
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
case MOVZX_SHORT: //movzx on short
|
||||
info.zeroExtend = true;
|
||||
info.operandSize = 2;
|
||||
case 0xB7: // movzx on short
|
||||
info->zeroExtend = true;
|
||||
info->operandSize = 2;
|
||||
break;
|
||||
case MOVSX_BYTE: //movsx on byte
|
||||
info.signExtend = true;
|
||||
info.operandSize = 1;
|
||||
case 0xBE: // movsx on byte
|
||||
info->signExtend = true;
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
case MOVSX_SHORT: //movsx on short
|
||||
info.signExtend = true;
|
||||
info.operandSize = 2;
|
||||
case 0xBF: // movsx on short
|
||||
info->signExtend = true;
|
||||
info->operandSize = 2;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 0x8a:
|
||||
if (info.operandSize == 4)
|
||||
}
|
||||
|
||||
case 0x8A: // r8 <- mem
|
||||
{
|
||||
info->isMemoryWrite = false;
|
||||
if (info->operandSize == 4)
|
||||
{
|
||||
info.operandSize = 1;
|
||||
info->operandSize = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
else
|
||||
return false;
|
||||
case 0x8b:
|
||||
break; //it's OK don't need to do anything
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case 0x8B: // r16/32/64 <- mem
|
||||
{
|
||||
info->isMemoryWrite = false;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
info.instructionSize = (int)(codePtr - startCodePtr);
|
||||
info->instructionSize = (int)(codePtr - startCodePtr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,21 +33,12 @@ struct ModRM
|
||||
}
|
||||
};
|
||||
|
||||
enum{
|
||||
MOVZX_BYTE = 0xB6, //movzx on byte
|
||||
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_16_32BIT = 0xC7, //move 16 or 32-bit immediate
|
||||
MOVE_REG_TO_MEM = 0x89, //move reg to memory
|
||||
};
|
||||
|
||||
enum AccessType{
|
||||
enum AccessType
|
||||
{
|
||||
OP_ACCESS_READ = 0,
|
||||
OP_ACCESS_WRITE = 1
|
||||
};
|
||||
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType);
|
||||
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info);
|
||||
|
||||
#endif // _X64ANALYZER_H_
|
||||
|
||||
@@ -38,28 +38,28 @@ static const NormalOpDef nops[11] =
|
||||
|
||||
enum NormalSSEOps
|
||||
{
|
||||
sseCMP = 0xC2,
|
||||
sseADD = 0x58, //ADD
|
||||
sseSUB = 0x5C, //SUB
|
||||
sseAND = 0x54, //AND
|
||||
sseANDN = 0x55, //ANDN
|
||||
sseOR = 0x56,
|
||||
sseXOR = 0x57,
|
||||
sseMUL = 0x59, //MUL,
|
||||
sseDIV = 0x5E, //DIV
|
||||
sseMIN = 0x5D, //MIN
|
||||
sseMAX = 0x5F, //MAX
|
||||
sseCOMIS = 0x2F, //COMIS
|
||||
sseUCOMIS = 0x2E, //UCOMIS
|
||||
sseSQRT = 0x51, //SQRT
|
||||
sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!)
|
||||
sseCMP = 0xC2,
|
||||
sseADD = 0x58, //ADD
|
||||
sseSUB = 0x5C, //SUB
|
||||
sseAND = 0x54, //AND
|
||||
sseANDN = 0x55, //ANDN
|
||||
sseOR = 0x56,
|
||||
sseXOR = 0x57,
|
||||
sseMUL = 0x59, //MUL
|
||||
sseDIV = 0x5E, //DIV
|
||||
sseMIN = 0x5D, //MIN
|
||||
sseMAX = 0x5F, //MAX
|
||||
sseCOMIS = 0x2F, //COMIS
|
||||
sseUCOMIS = 0x2E, //UCOMIS
|
||||
sseSQRT = 0x51, //SQRT
|
||||
sseRSQRT = 0x52, //RSQRT (NO DOUBLE PRECISION!!!)
|
||||
sseMOVAPfromRM = 0x28, //MOVAP from RM
|
||||
sseMOVAPtoRM = 0x29, //MOVAP to RM
|
||||
sseMOVAPtoRM = 0x29, //MOVAP to RM
|
||||
sseMOVUPfromRM = 0x10, //MOVUP from RM
|
||||
sseMOVUPtoRM = 0x11, //MOVUP to RM
|
||||
sseMASKMOVDQU = 0xF7,
|
||||
sseLDDQU = 0xF0,
|
||||
sseSHUF = 0xC6,
|
||||
sseMOVUPtoRM = 0x11, //MOVUP to RM
|
||||
sseMASKMOVDQU = 0xF7,
|
||||
sseLDDQU = 0xF0,
|
||||
sseSHUF = 0xC6,
|
||||
sseMOVNTDQ = 0xE7,
|
||||
sseMOVNTP = 0x2B,
|
||||
};
|
||||
@@ -155,7 +155,7 @@ void OpArg::WriteRex(XEmitter *emit, int opBits, int bits, int customOp) const
|
||||
}
|
||||
|
||||
void OpArg::WriteRest(XEmitter *emit, int extraBytes, X64Reg _operandReg,
|
||||
bool warn_64bit_offset) const
|
||||
bool warn_64bit_offset) const
|
||||
{
|
||||
if (_operandReg == 0xff)
|
||||
_operandReg = (X64Reg)this->operandReg;
|
||||
@@ -1276,7 +1276,7 @@ void XEmitter::CVTPD2PS(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x5A, true, reg
|
||||
|
||||
void XEmitter::CVTSD2SS(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x5A, false, regOp, arg);}
|
||||
void XEmitter::CVTSS2SD(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0x5A, false, regOp, arg);}
|
||||
void XEmitter::CVTSD2SI(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0xF2, false, regOp, arg);}
|
||||
void XEmitter::CVTSD2SI(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x2D, false, regOp, arg);}
|
||||
|
||||
void XEmitter::CVTDQ2PD(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0xE6, false, regOp, arg);}
|
||||
void XEmitter::CVTDQ2PS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0x5B, true, regOp, arg);}
|
||||
@@ -1429,8 +1429,8 @@ void XEmitter::PCMPGTB(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x64, true, dest
|
||||
void XEmitter::PCMPGTW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x65, true, dest, arg);}
|
||||
void XEmitter::PCMPGTD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0x66, true, dest, arg);}
|
||||
|
||||
void XEmitter::PEXTRW(X64Reg dest, OpArg arg, u8 subreg) {WriteSSEOp(64, 0x64, true, dest, arg); Write8(subreg);}
|
||||
void XEmitter::PINSRW(X64Reg dest, OpArg arg, u8 subreg) {WriteSSEOp(64, 0x64, true, dest, arg); Write8(subreg);}
|
||||
void XEmitter::PEXTRW(X64Reg dest, OpArg arg, u8 subreg) {WriteSSEOp(64, 0xC5, true, dest, arg); Write8(subreg);}
|
||||
void XEmitter::PINSRW(X64Reg dest, OpArg arg, u8 subreg) {WriteSSEOp(64, 0xC4, true, dest, arg); Write8(subreg);}
|
||||
|
||||
void XEmitter::PMADDWD(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xF5, true, dest, arg); }
|
||||
void XEmitter::PSADBW(X64Reg dest, OpArg arg) {WriteSSEOp(64, 0xF6, true, dest, arg);}
|
||||
|
||||
@@ -639,7 +639,7 @@ public:
|
||||
|
||||
// Pass a register as a parameter.
|
||||
void ABI_CallFunctionR(void *func, Gen::X64Reg reg1);
|
||||
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2);
|
||||
void ABI_CallFunctionRR(void *func, Gen::X64Reg reg1, Gen::X64Reg reg2, bool noProlog = false);
|
||||
|
||||
// A function that doesn't have any control over what it will do to regs,
|
||||
// such as the dispatcher, should be surrounded by these.
|
||||
@@ -652,14 +652,9 @@ public:
|
||||
void ABI_PushAllCallerSavedRegsAndAdjustStack();
|
||||
void ABI_PopAllCallerSavedRegsAndAdjustStack();
|
||||
|
||||
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize);
|
||||
void ABI_AlignStack(unsigned int frameSize);
|
||||
void ABI_RestoreStack(unsigned int frameSize);
|
||||
|
||||
// Sets up a __cdecl function.
|
||||
// Only x64 really needs the parameter count.
|
||||
void ABI_EmitPrologue(int maxCallParams);
|
||||
void ABI_EmitEpilogue(int maxCallParams);
|
||||
unsigned int ABI_GetAlignedFrameSize(unsigned int frameSize, bool noProlog = false);
|
||||
void ABI_AlignStack(unsigned int frameSize, bool noProlog = false);
|
||||
void ABI_RestoreStack(unsigned int frameSize, bool noProlog = false);
|
||||
|
||||
#ifdef _M_IX86
|
||||
inline int ABI_GetNumXMMRegs() { return 8; }
|
||||
|
||||
@@ -91,35 +91,27 @@ void *ThunkManager::ProtectFunction(void *function, int num_params)
|
||||
PanicAlert("Trying to protect functions before the emu is started. Bad bad bad.");
|
||||
|
||||
const u8 *call_point = GetCodePtr();
|
||||
// Make sure to align stack.
|
||||
#ifdef _M_X64
|
||||
#ifdef _WIN32
|
||||
SUB(64, R(ESP), Imm8(0x28));
|
||||
#else
|
||||
SUB(64, R(ESP), Imm8(0x8));
|
||||
#endif
|
||||
// Make sure to align stack.
|
||||
ABI_AlignStack(0, true);
|
||||
CALL((void*)save_regs);
|
||||
CALL((void*)function);
|
||||
CALL((void*)load_regs);
|
||||
#ifdef _WIN32
|
||||
ADD(64, R(ESP), Imm8(0x28));
|
||||
#else
|
||||
ADD(64, R(ESP), Imm8(0x8));
|
||||
#endif
|
||||
ABI_RestoreStack(0, true);
|
||||
RET();
|
||||
#else
|
||||
CALL((void*)save_regs);
|
||||
// Since parameters are in the previous stack frame, not in registers, this takes some
|
||||
// trickery : we simply re-push the parameters. might not be optimal, but that doesn't really
|
||||
// matter.
|
||||
ABI_AlignStack(num_params * 4);
|
||||
ABI_AlignStack(num_params * 4, true);
|
||||
unsigned int alignedSize = ABI_GetAlignedFrameSize(num_params * 4);
|
||||
for (int i = 0; i < num_params; i++) {
|
||||
// ESP is changing, so we do not need i
|
||||
PUSH(32, MDisp(ESP, alignedSize - 4));
|
||||
PUSH(32, MDisp(ESP, alignedSize));
|
||||
}
|
||||
CALL(function);
|
||||
ABI_RestoreStack(num_params * 4);
|
||||
ABI_RestoreStack(num_params * 4, true);
|
||||
CALL((void*)load_regs);
|
||||
RET();
|
||||
#endif
|
||||
|
||||
@@ -215,6 +215,7 @@ if(_M_ARM)
|
||||
Src/PowerPC/JitArm32/JitArm_LoadStore.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_Paired.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_LoadStorePaired.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp
|
||||
Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp)
|
||||
endif()
|
||||
@@ -231,7 +232,7 @@ if(LIBUSB_FOUND)
|
||||
set(SRCS ${SRCS} Src/IPC_HLE/WII_IPC_HLE_Device_hid.cpp)
|
||||
endif(LIBUSB_FOUND)
|
||||
|
||||
set(LIBS ${LIBS} polarssl)
|
||||
set(LIBS ${LIBS} ${POLARSSL_LIBRARY})
|
||||
|
||||
if(WIN32)
|
||||
set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Win32.cpp Src/stdafx.cpp
|
||||
|
||||
@@ -111,115 +111,121 @@ bool CompareValues(const u32 val1, const u32 val2, const int type);
|
||||
|
||||
// ----------------------
|
||||
// AR Remote Functions
|
||||
void LoadCodes(IniFile &ini, bool forceLoad)
|
||||
void LoadCodes(IniFile &globalIni, IniFile &localIni, bool forceLoad)
|
||||
{
|
||||
// Parses the Action Replay section of a game ini file.
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats
|
||||
&& !forceLoad)
|
||||
return;
|
||||
|
||||
std::vector<std::string> lines;
|
||||
std::vector<std::string> encryptedLines;
|
||||
ARCode currentCode;
|
||||
arCodes.clear();
|
||||
|
||||
if (!ini.GetLines("ActionReplay", lines))
|
||||
return; // no codes found.
|
||||
|
||||
std::vector<std::string>::const_iterator
|
||||
it = lines.begin(),
|
||||
lines_end = lines.end();
|
||||
for (; it != lines_end; ++it)
|
||||
std::vector<std::string> enabledLines;
|
||||
std::set<std::string> enabledNames;
|
||||
localIni.GetLines("ActionReplay_Enabled", enabledLines);
|
||||
for (auto iter = enabledLines.begin(); iter != enabledLines.end(); ++iter)
|
||||
{
|
||||
const std::string line = *it;
|
||||
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
std::vector<std::string> pieces;
|
||||
|
||||
// Check if the line is a name of the code
|
||||
if (line[0] == '+' || line[0] == '$')
|
||||
const std::string& line = *iter;
|
||||
if (line.size() != 0 && line[0] == '$')
|
||||
{
|
||||
if (currentCode.ops.size())
|
||||
{
|
||||
arCodes.push_back(currentCode);
|
||||
currentCode.ops.clear();
|
||||
}
|
||||
if (encryptedLines.size())
|
||||
{
|
||||
DecryptARCode(encryptedLines, currentCode.ops);
|
||||
arCodes.push_back(currentCode);
|
||||
currentCode.ops.clear();
|
||||
encryptedLines.clear();
|
||||
}
|
||||
|
||||
if (line.size() > 1)
|
||||
{
|
||||
if (line[0] == '+')
|
||||
{
|
||||
currentCode.active = true;
|
||||
currentCode.name = line.substr(2, line.size() - 2);;
|
||||
if (!forceLoad)
|
||||
Core::DisplayMessage("AR code active: " + currentCode.name, 5000);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCode.active = false;
|
||||
currentCode.name = line.substr(1, line.size() - 1);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
std::string name = line.substr(1, line.size() - 1);
|
||||
enabledNames.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
SplitString(line, ' ', pieces);
|
||||
IniFile* inis[] = {&globalIni, &localIni};
|
||||
for (size_t i = 0; i < ArraySize(inis); ++i)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::vector<std::string> encryptedLines;
|
||||
ARCode currentCode;
|
||||
|
||||
inis[i]->GetLines("ActionReplay", lines);
|
||||
|
||||
// Check if the AR code is decrypted
|
||||
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
|
||||
std::vector<std::string>::const_iterator
|
||||
it = lines.begin(),
|
||||
lines_end = lines.end();
|
||||
for (; it != lines_end; ++it)
|
||||
{
|
||||
AREntry op;
|
||||
bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr);
|
||||
bool success_val = TryParse(std::string("0x") + pieces[1], &op.value);
|
||||
if (!(success_addr | success_val)) {
|
||||
PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str());
|
||||
if (!success_addr) PanicAlertT("The address is invalid");
|
||||
if (!success_val) PanicAlertT("The value is invalid");
|
||||
const std::string line = *it;
|
||||
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
std::vector<std::string> pieces;
|
||||
|
||||
// Check if the line is a name of the code
|
||||
if (line[0] == '$')
|
||||
{
|
||||
if (currentCode.ops.size())
|
||||
{
|
||||
arCodes.push_back(currentCode);
|
||||
currentCode.ops.clear();
|
||||
}
|
||||
if (encryptedLines.size())
|
||||
{
|
||||
DecryptARCode(encryptedLines, currentCode.ops);
|
||||
arCodes.push_back(currentCode);
|
||||
currentCode.ops.clear();
|
||||
encryptedLines.clear();
|
||||
}
|
||||
|
||||
currentCode.name = line.substr(1, line.size() - 1);
|
||||
currentCode.active = enabledNames.find(currentCode.name) != enabledNames.end();
|
||||
currentCode.user_defined = (i == 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCode.ops.push_back(op);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitString(line, '-', pieces);
|
||||
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
|
||||
{
|
||||
// Encrypted AR code
|
||||
// Decryption is done in "blocks", so we must push blocks into a vector,
|
||||
// then send to decrypt when a new block is encountered, or if it's the last block.
|
||||
encryptedLines.push_back(pieces[0]+pieces[1]+pieces[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
SplitString(line, ' ', pieces);
|
||||
|
||||
// Handle the last code correctly.
|
||||
if (currentCode.ops.size())
|
||||
{
|
||||
arCodes.push_back(currentCode);
|
||||
}
|
||||
if (encryptedLines.size())
|
||||
{
|
||||
DecryptARCode(encryptedLines, currentCode.ops);
|
||||
arCodes.push_back(currentCode);
|
||||
// Check if the AR code is decrypted
|
||||
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
|
||||
{
|
||||
AREntry op;
|
||||
bool success_addr = TryParse(std::string("0x") + pieces[0], &op.cmd_addr);
|
||||
bool success_val = TryParse(std::string("0x") + pieces[1], &op.value);
|
||||
if (!(success_addr | success_val)) {
|
||||
PanicAlertT("Action Replay Error: invalid AR code line: %s", line.c_str());
|
||||
if (!success_addr) PanicAlertT("The address is invalid");
|
||||
if (!success_val) PanicAlertT("The value is invalid");
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCode.ops.push_back(op);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitString(line, '-', pieces);
|
||||
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
|
||||
{
|
||||
// Encrypted AR code
|
||||
// Decryption is done in "blocks", so we must push blocks into a vector,
|
||||
// then send to decrypt when a new block is encountered, or if it's the last block.
|
||||
encryptedLines.push_back(pieces[0]+pieces[1]+pieces[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the last code correctly.
|
||||
if (currentCode.ops.size())
|
||||
{
|
||||
arCodes.push_back(currentCode);
|
||||
}
|
||||
if (encryptedLines.size())
|
||||
{
|
||||
DecryptARCode(encryptedLines, currentCode.ops);
|
||||
arCodes.push_back(currentCode);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateActiveList();
|
||||
}
|
||||
|
||||
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &ini)
|
||||
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &globalIni, IniFile& localIni)
|
||||
{
|
||||
LoadCodes(ini, true);
|
||||
LoadCodes(globalIni, localIni, true);
|
||||
_arCodes = arCodes;
|
||||
}
|
||||
|
||||
@@ -878,7 +884,7 @@ bool ConditionalCode(const ARAddr addr, const u32 data, int* const pSkipCount)
|
||||
// Skip lines until a "00000000 40000000" line is reached
|
||||
case CONDTIONAL_ALL_LINES:
|
||||
case CONDTIONAL_ALL_LINES_UNTIL:
|
||||
*pSkipCount = -addr.subtype;
|
||||
*pSkipCount = -(int) addr.subtype;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -23,12 +23,13 @@ struct ARCode
|
||||
std::string name;
|
||||
std::vector<AREntry> ops;
|
||||
bool active;
|
||||
bool user_defined;
|
||||
};
|
||||
|
||||
void RunAllActive();
|
||||
bool RunCode(const ARCode &arcode);
|
||||
void LoadCodes(IniFile &ini, bool forceLoad);
|
||||
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &ini);
|
||||
void LoadCodes(IniFile &globalIni, IniFile &localIni, bool forceLoad);
|
||||
void LoadCodes(std::vector<ARCode> &_arCodes, IniFile &globalIni, IniFile &localIni);
|
||||
size_t GetCodeListSize();
|
||||
ARCode GetARCode(size_t index);
|
||||
void SetARCode_IsActive(bool active, size_t index);
|
||||
|
||||
@@ -81,11 +81,9 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
|
||||
|
||||
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);
|
||||
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, &fake_ctx);
|
||||
if (new_rip) {
|
||||
ctx->arm_pc = fake_ctx.reg_pc;
|
||||
}
|
||||
|
||||
@@ -71,59 +71,73 @@ void CBoot::UpdateDebugger_MapLoaded(const char *_gameID)
|
||||
Host_NotifyMapLoaded();
|
||||
}
|
||||
|
||||
std::string CBoot::GenerateMapFilename()
|
||||
bool CBoot::FindMapFile(std::string* existing_map_file,
|
||||
std::string* writable_map_file)
|
||||
{
|
||||
std::string title_id_str;
|
||||
|
||||
SCoreStartupParameter& _StartupPara = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||
switch (_StartupPara.m_BootType)
|
||||
{
|
||||
case SCoreStartupParameter::BOOT_WII_NAND:
|
||||
{
|
||||
const DiscIO::INANDContentLoader& Loader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
|
||||
const DiscIO::INANDContentLoader& Loader =
|
||||
DiscIO::CNANDContentManager::Access().GetNANDLoader(_StartupPara.m_strFilename);
|
||||
if (Loader.IsValid())
|
||||
{
|
||||
u64 TitleID = Loader.GetTitleID();
|
||||
char tmpBuffer[32];
|
||||
sprintf(tmpBuffer, "%08x_%08x", (u32)(TitleID >> 32) & 0xFFFFFFFF , (u32)TitleID & 0xFFFFFFFF );
|
||||
return File::GetUserPath(D_MAPS_IDX) + std::string(tmpBuffer) + ".map";
|
||||
title_id_str = StringFromFormat("%08X_%08X",
|
||||
(u32)(TitleID >> 32) & 0xFFFFFFFF,
|
||||
(u32)TitleID & 0xFFFFFFFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SCoreStartupParameter::BOOT_ELF:
|
||||
case SCoreStartupParameter::BOOT_DOL:
|
||||
return _StartupPara.m_strFilename.substr(0, _StartupPara.m_strFilename.size()-4) + ".map";
|
||||
// Strip the .elf/.dol file extension
|
||||
title_id_str = _StartupPara.m_strFilename.substr(
|
||||
0, _StartupPara.m_strFilename.size() - 4);
|
||||
break;
|
||||
|
||||
default:
|
||||
return File::GetUserPath(D_MAPS_IDX) + _StartupPara.GetUniqueID() + ".map";
|
||||
title_id_str = _StartupPara.GetUniqueID();
|
||||
break;
|
||||
}
|
||||
|
||||
return std::string("unknown map");
|
||||
}
|
||||
if (writable_map_file)
|
||||
*writable_map_file = File::GetUserPath(D_MAPS_IDX) + title_id_str + ".map";
|
||||
|
||||
bool CBoot::LoadMapFromFilename(const std::string &_rFilename, const char *_gameID)
|
||||
{
|
||||
if (_rFilename.size() == 0)
|
||||
return false;
|
||||
|
||||
std::string strMapFilename = GenerateMapFilename();
|
||||
|
||||
bool success = false;
|
||||
if (!g_symbolDB.LoadMap(strMapFilename.c_str()))
|
||||
bool found = false;
|
||||
static const std::string maps_directories[] = {
|
||||
File::GetUserPath(D_MAPS_IDX),
|
||||
File::GetSysDirectory() + MAPS_DIR DIR_SEP
|
||||
};
|
||||
for (size_t i = 0; !found && i < ArraySize(maps_directories); ++i)
|
||||
{
|
||||
if (_gameID != NULL)
|
||||
std::string path = maps_directories[i] + title_id_str + ".map";
|
||||
if (File::Exists(path))
|
||||
{
|
||||
BuildCompleteFilename(strMapFilename, "maps", std::string(_gameID) + ".map");
|
||||
success = g_symbolDB.LoadMap(strMapFilename.c_str());
|
||||
found = true;
|
||||
if (existing_map_file)
|
||||
*existing_map_file = path;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool CBoot::LoadMapFromFilename()
|
||||
{
|
||||
std::string strMapFilename;
|
||||
bool found = FindMapFile(&strMapFilename, NULL);
|
||||
if (found && g_symbolDB.LoadMap(strMapFilename.c_str()))
|
||||
{
|
||||
success = true;
|
||||
UpdateDebugger_MapLoaded();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (success)
|
||||
UpdateDebugger_MapLoaded();
|
||||
|
||||
return success;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If ipl.bin is not found, this function does *some* of what BS1 does:
|
||||
@@ -184,14 +198,6 @@ bool CBoot::BootUp()
|
||||
|
||||
NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str());
|
||||
|
||||
// HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats)
|
||||
{
|
||||
HLE::Patch(0x80001800, "HBReload");
|
||||
const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' };
|
||||
Memory::WriteBigEData(stubstr, 0x80001804, 8);
|
||||
}
|
||||
|
||||
g_symbolDB.Clear();
|
||||
VideoInterface::Preset(_StartupPara.bNTSC);
|
||||
switch (_StartupPara.m_BootType)
|
||||
@@ -209,10 +215,6 @@ bool CBoot::BootUp()
|
||||
PanicAlertT("Warning - starting ISO in wrong console mode!");
|
||||
}
|
||||
|
||||
char gameID[7];
|
||||
memcpy(gameID, pVolume->GetUniqueID().c_str(), 6);
|
||||
gameID[6] = 0;
|
||||
|
||||
// setup the map from ISOFile ID
|
||||
VolumeHandler::SetVolumeName(_StartupPara.m_strFilename);
|
||||
|
||||
@@ -260,7 +262,7 @@ bool CBoot::BootUp()
|
||||
|
||||
/* Try to load the symbol map if there is one, and then scan it for
|
||||
and eventually replace code */
|
||||
if (LoadMapFromFilename(_StartupPara.m_strFilename, gameID))
|
||||
if (LoadMapFromFilename())
|
||||
HLE::PatchFunctions();
|
||||
|
||||
// We don't need the volume any more
|
||||
@@ -306,7 +308,7 @@ bool CBoot::BootUp()
|
||||
PC = dolLoader.GetEntryPoint();
|
||||
}
|
||||
|
||||
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||
if (LoadMapFromFilename())
|
||||
HLE::PatchFunctions();
|
||||
|
||||
break;
|
||||
@@ -376,7 +378,7 @@ bool CBoot::BootUp()
|
||||
case SCoreStartupParameter::BOOT_WII_NAND:
|
||||
Boot_WiiWAD(_StartupPara.m_strFilename.c_str());
|
||||
|
||||
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||
if (LoadMapFromFilename())
|
||||
HLE::PatchFunctions();
|
||||
|
||||
// load default image or create virtual drive from directory
|
||||
@@ -395,7 +397,7 @@ bool CBoot::BootUp()
|
||||
DVDInterface::SetDiscInside(VolumeHandler::IsValid());
|
||||
if (Load_BS2(_StartupPara.m_strBootROM))
|
||||
{
|
||||
if (LoadMapFromFilename(_StartupPara.m_strFilename))
|
||||
if (LoadMapFromFilename())
|
||||
HLE::PatchFunctions();
|
||||
}
|
||||
else
|
||||
@@ -415,6 +417,19 @@ bool CBoot::BootUp()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler
|
||||
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats)
|
||||
{
|
||||
HLE::Patch(0x80001800, "HBReload");
|
||||
const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' };
|
||||
Memory::WriteBigEData(stubstr, 0x80001804, 8);
|
||||
}
|
||||
|
||||
// Not part of the binary itself, but either we or Gecko OS might insert
|
||||
// this, and it doesn't clear the icache properly.
|
||||
HLE::Patch(0x800018a8, "GeckoCodehandler");
|
||||
|
||||
Host_UpdateLogDisplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,26 @@ public:
|
||||
|
||||
static bool BootUp();
|
||||
static bool IsElfWii(const char *filename);
|
||||
static std::string GenerateMapFilename();
|
||||
|
||||
// Tries to find a map file for the current game by looking first in the
|
||||
// local user directory, then in the shared user directory.
|
||||
//
|
||||
// If existing_map_file is not NULL and a map file exists, it is set to the
|
||||
// path to the existing map file.
|
||||
//
|
||||
// If writable_map_file is not NULL, it is set to the path to where a map
|
||||
// file should be saved.
|
||||
//
|
||||
// Returns true if a map file exists, false if none could be found.
|
||||
static bool FindMapFile(std::string* existing_map_file,
|
||||
std::string* writable_map_file);
|
||||
|
||||
private:
|
||||
static void RunFunction(u32 _iAddr);
|
||||
|
||||
static void UpdateDebugger_MapLoaded(const char* _gameID = NULL);
|
||||
|
||||
static bool LoadMapFromFilename(const std::string& _rFilename, const char* _gameID = NULL);
|
||||
static bool LoadMapFromFilename();
|
||||
static bool Boot_ELF(const char *filename);
|
||||
static bool Boot_WiiWAD(const char *filename);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ bool CBoot::Boot_ELF(const char *filename)
|
||||
reader.LoadInto(0x80000000);
|
||||
if (!reader.LoadSymbols())
|
||||
{
|
||||
if (LoadMapFromFilename(filename))
|
||||
if (LoadMapFromFilename())
|
||||
HLE::PatchFunctions();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -79,7 +79,9 @@ 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;
|
||||
|
||||
@@ -27,7 +27,6 @@ private:
|
||||
Elf32_Phdr *segments;
|
||||
Elf32_Shdr *sections;
|
||||
|
||||
u32 *sectionOffsets;
|
||||
u32 *sectionAddrs;
|
||||
bool bRelocate;
|
||||
u32 entryPoint;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Common.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "IniFile.h"
|
||||
#include "BootManager.h"
|
||||
#include "Volume.h"
|
||||
@@ -34,7 +35,7 @@
|
||||
#include "Host.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "Movie.h"
|
||||
#include "NetPlayClient.h"
|
||||
#include "NetPlayProto.h"
|
||||
|
||||
namespace BootManager
|
||||
{
|
||||
@@ -46,6 +47,7 @@ struct ConfigCache
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF, m_EnableJIT, bDSPThread,
|
||||
bVBeamSpeedHack, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
||||
int iTLBHack, iCPUCore;
|
||||
TEXIDevices m_EXIDevice[2];
|
||||
std::string strBackend;
|
||||
};
|
||||
static ConfigCache config_cache;
|
||||
@@ -72,11 +74,16 @@ bool BootCore(const std::string& _rFilename)
|
||||
return false;
|
||||
|
||||
// Load game specific settings
|
||||
IniFile game_ini;
|
||||
std::string unique_id = StartUp.GetUniqueID();
|
||||
StartUp.m_strGameIni = File::GetUserPath(D_GAMECONFIG_IDX) + unique_id + ".ini";
|
||||
if (unique_id.size() == 6 && game_ini.Load(StartUp.m_strGameIni.c_str()))
|
||||
StartUp.m_strGameIniDefault = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + unique_id + ".ini";
|
||||
StartUp.m_strGameIniLocal = File::GetUserPath(D_GAMESETTINGS_IDX) + unique_id + ".ini";
|
||||
|
||||
if (unique_id.size() == 6)
|
||||
{
|
||||
IniFile game_ini;
|
||||
game_ini.Load(StartUp.m_strGameIniDefault);
|
||||
game_ini.Load(StartUp.m_strGameIniLocal, true);
|
||||
|
||||
config_cache.valid = true;
|
||||
config_cache.bCPUThread = StartUp.bCPUThread;
|
||||
config_cache.bSkipIdle = StartUp.bSkipIdle;
|
||||
@@ -94,6 +101,8 @@ bool BootCore(const std::string& _rFilename)
|
||||
config_cache.bHLE_BS2 = StartUp.bHLE_BS2;
|
||||
config_cache.m_EnableJIT = SConfig::GetInstance().m_EnableJIT;
|
||||
config_cache.bDSPThread = StartUp.bDSPThread;
|
||||
config_cache.m_EXIDevice[0] = SConfig::GetInstance().m_EXIDevice[0];
|
||||
config_cache.m_EXIDevice[1] = SConfig::GetInstance().m_EXIDevice[1];
|
||||
|
||||
// General settings
|
||||
game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread);
|
||||
@@ -144,6 +153,8 @@ bool BootCore(const std::string& _rFilename)
|
||||
StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE;
|
||||
StartUp.bEnableMemcardSaving = g_NetPlaySettings.m_WriteToMemcard;
|
||||
SConfig::GetInstance().m_EnableJIT = g_NetPlaySettings.m_DSPEnableJIT;
|
||||
SConfig::GetInstance().m_EXIDevice[0] = g_NetPlaySettings.m_EXIDevice[0];
|
||||
SConfig::GetInstance().m_EXIDevice[1] = g_NetPlaySettings.m_EXIDevice[1];
|
||||
}
|
||||
|
||||
// Run the game
|
||||
@@ -184,6 +195,8 @@ void Stop()
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
StartUp.bHLE_BS2 = config_cache.bHLE_BS2;
|
||||
SConfig::GetInstance().m_EnableJIT = config_cache.m_EnableJIT;
|
||||
SConfig::GetInstance().m_EXIDevice[0] = config_cache.m_EXIDevice[0];
|
||||
SConfig::GetInstance().m_EXIDevice[1] = config_cache.m_EXIDevice[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ void SConfig::SaveSettings()
|
||||
}
|
||||
|
||||
ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder);
|
||||
ini.Set("General", "NANDRoot", m_NANDPath);
|
||||
ini.Set("General", "NANDRootPath", m_NANDPath);
|
||||
ini.Set("General", "WirelessMac", m_WirelessMac);
|
||||
#ifdef USE_GDBSTUB
|
||||
ini.Set("General", "GDBPort", m_LocalCoreStartupParameter.iGDBPort);
|
||||
@@ -189,7 +189,7 @@ void SConfig::SaveSettings()
|
||||
ini.Set("Interface", "ShowLogWindow", m_InterfaceLogWindow);
|
||||
ini.Set("Interface", "ShowLogConfigWindow", m_InterfaceLogConfigWindow);
|
||||
ini.Set("Interface", "ShowConsole", m_InterfaceConsole);
|
||||
ini.Set("Interface", "ThemeName", m_LocalCoreStartupParameter.theme_name);
|
||||
ini.Set("Interface", "ThemeName40", m_LocalCoreStartupParameter.theme_name);
|
||||
|
||||
// Hotkeys
|
||||
for (int i = 0; i < NUM_HOTKEYS; i++)
|
||||
@@ -244,8 +244,8 @@ void SConfig::SaveSettings()
|
||||
ini.Set("Core", "SelectedLanguage", m_LocalCoreStartupParameter.SelectedLanguage);
|
||||
ini.Set("Core", "DPL2Decoder", m_LocalCoreStartupParameter.bDPL2Decoder);
|
||||
ini.Set("Core", "Latency", m_LocalCoreStartupParameter.iLatency);
|
||||
ini.Set("Core", "MemcardA", m_strMemoryCardA);
|
||||
ini.Set("Core", "MemcardB", m_strMemoryCardB);
|
||||
ini.Set("Core", "MemcardAPath", m_strMemoryCardA);
|
||||
ini.Set("Core", "MemcardBPath", m_strMemoryCardB);
|
||||
ini.Set("Core", "SlotA", m_EXIDevice[0]);
|
||||
ini.Set("Core", "SlotB", m_EXIDevice[1]);
|
||||
ini.Set("Core", "SerialPort1", m_EXIDevice[2]);
|
||||
@@ -318,7 +318,7 @@ void SConfig::LoadSettings()
|
||||
|
||||
ini.Get("General", "RecursiveGCMPaths", &m_RecursiveISOFolder, false);
|
||||
|
||||
ini.Get("General", "NANDRoot", &m_NANDPath);
|
||||
ini.Get("General", "NANDRootPath", &m_NANDPath);
|
||||
m_NANDPath = File::GetUserPath(D_WIIROOT_IDX, m_NANDPath);
|
||||
DiscIO::cUIDsys::AccessInstance().UpdateLocation();
|
||||
DiscIO::CSharedContent::AccessInstance().UpdateLocation();
|
||||
@@ -342,7 +342,7 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Interface", "ShowLogWindow", &m_InterfaceLogWindow, false);
|
||||
ini.Get("Interface", "ShowLogConfigWindow", &m_InterfaceLogConfigWindow, false);
|
||||
ini.Get("Interface", "ShowConsole", &m_InterfaceConsole, false);
|
||||
ini.Get("Interface", "ThemeName", &m_LocalCoreStartupParameter.theme_name, "Boomy");
|
||||
ini.Get("Interface", "ThemeName40", &m_LocalCoreStartupParameter.theme_name, "Clean");
|
||||
|
||||
// Hotkeys
|
||||
for (int i = 0; i < NUM_HOTKEYS; i++)
|
||||
@@ -403,8 +403,8 @@ void SConfig::LoadSettings()
|
||||
ini.Get("Core", "SelectedLanguage", &m_LocalCoreStartupParameter.SelectedLanguage, 0);
|
||||
ini.Get("Core", "DPL2Decoder", &m_LocalCoreStartupParameter.bDPL2Decoder, false);
|
||||
ini.Get("Core", "Latency", &m_LocalCoreStartupParameter.iLatency, 2);
|
||||
ini.Get("Core", "MemcardA", &m_strMemoryCardA);
|
||||
ini.Get("Core", "MemcardB", &m_strMemoryCardB);
|
||||
ini.Get("Core", "MemcardAPath", &m_strMemoryCardA);
|
||||
ini.Get("Core", "MemcardBPath", &m_strMemoryCardB);
|
||||
ini.Get("Core", "SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD);
|
||||
ini.Get("Core", "SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE);
|
||||
ini.Get("Core", "SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE);
|
||||
|
||||
@@ -205,7 +205,8 @@ bool Init()
|
||||
if (g_aspect_wide)
|
||||
{
|
||||
IniFile gameIni;
|
||||
gameIni.Load(_CoreParameter.m_strGameIni.c_str());
|
||||
gameIni.Load(_CoreParameter.m_strGameIniDefault.c_str());
|
||||
gameIni.Load(_CoreParameter.m_strGameIniLocal.c_str(), true);
|
||||
gameIni.Get("Wii", "Widescreen", &g_aspect_wide,
|
||||
!!SConfig::GetInstance().m_SYSCONF->
|
||||
GetData<u8>("IPL.AR"));
|
||||
|
||||
@@ -351,11 +351,7 @@ 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;
|
||||
#ifdef _WIN32
|
||||
memcardPath = "." + File::GetUserPath(D_GCUSER_IDX).substr(File::GetExeDirectory().size()) + defaultFilename + ext;
|
||||
#else
|
||||
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
|
||||
#endif
|
||||
memcardPath = File::GetUserPath(D_GCUSER_IDX) + defaultFilename + ext;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -198,7 +198,8 @@ struct SCoreStartupParameter
|
||||
std::string m_strApploader;
|
||||
std::string m_strUniqueID;
|
||||
std::string m_strName;
|
||||
std::string m_strGameIni;
|
||||
std::string m_strGameIniDefault;
|
||||
std::string m_strGameIniLocal;
|
||||
|
||||
// Constructor just calls LoadDefaults
|
||||
SCoreStartupParameter();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Core.h"
|
||||
#include "StringUtil.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "FifoQueue.h"
|
||||
|
||||
#define MAX_SLICE_LENGTH 20000
|
||||
|
||||
@@ -29,20 +30,17 @@ struct BaseEvent
|
||||
s64 time;
|
||||
u64 userdata;
|
||||
int type;
|
||||
// Event *next;
|
||||
};
|
||||
|
||||
typedef LinkedListItem<BaseEvent> Event;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
Event *first;
|
||||
Event *tsFirst;
|
||||
Event *tsLast;
|
||||
static Event *first;
|
||||
static std::mutex tsWriteLock;
|
||||
Common::FifoQueue<BaseEvent, false> tsQueue;
|
||||
|
||||
// event pools
|
||||
Event *eventPool = 0;
|
||||
Event *eventTsPool = 0;
|
||||
int allocatedTsEvents = 0;
|
||||
|
||||
int downcount, slicelength;
|
||||
int maxSliceLength = MAX_SLICE_LENGTH;
|
||||
@@ -57,7 +55,6 @@ u64 fakeTBStartTicks;
|
||||
|
||||
int ev_lost;
|
||||
|
||||
static std::recursive_mutex externalEventSection;
|
||||
|
||||
void (*advanceCallback)(int cyclesExecuted) = NULL;
|
||||
|
||||
@@ -71,31 +68,12 @@ Event* GetNewEvent()
|
||||
return ev;
|
||||
}
|
||||
|
||||
Event* GetNewTsEvent()
|
||||
{
|
||||
allocatedTsEvents++;
|
||||
|
||||
if(!eventTsPool)
|
||||
return new Event;
|
||||
|
||||
Event* ev = eventTsPool;
|
||||
eventTsPool = ev->next;
|
||||
return ev;
|
||||
}
|
||||
|
||||
void FreeEvent(Event* ev)
|
||||
{
|
||||
ev->next = eventPool;
|
||||
eventPool = ev;
|
||||
}
|
||||
|
||||
void FreeTsEvent(Event* ev)
|
||||
{
|
||||
ev->next = eventTsPool;
|
||||
eventTsPool = ev;
|
||||
allocatedTsEvents--;
|
||||
}
|
||||
|
||||
static void EmptyTimedCallback(u64 userdata, int cyclesLate) {}
|
||||
|
||||
int RegisterEvent(const char *name, TimedCallback callback)
|
||||
@@ -141,6 +119,7 @@ void Init()
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(tsWriteLock);
|
||||
MoveEvents();
|
||||
ClearPendingEvents();
|
||||
UnregisterAllEvents();
|
||||
@@ -151,14 +130,6 @@ void Shutdown()
|
||||
eventPool = ev->next;
|
||||
delete ev;
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
while(eventTsPool)
|
||||
{
|
||||
Event *ev = eventTsPool;
|
||||
eventTsPool = ev->next;
|
||||
delete ev;
|
||||
}
|
||||
}
|
||||
|
||||
void EventDoState(PointerWrap &p, BaseEvent* ev)
|
||||
@@ -197,7 +168,7 @@ void EventDoState(PointerWrap &p, BaseEvent* ev)
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
std::lock_guard<std::mutex> lk(tsWriteLock);
|
||||
p.Do(downcount);
|
||||
p.Do(slicelength);
|
||||
p.Do(globalTimer);
|
||||
@@ -208,11 +179,10 @@ void DoState(PointerWrap &p)
|
||||
p.Do(fakeTBStartTicks);
|
||||
p.DoMarker("CoreTimingData");
|
||||
|
||||
MoveEvents();
|
||||
|
||||
p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, EventDoState>(first);
|
||||
p.DoMarker("CoreTimingEvents");
|
||||
|
||||
p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, EventDoState>(tsFirst, &tsLast);
|
||||
p.DoMarker("CoreTimingTsEvents");
|
||||
}
|
||||
|
||||
u64 GetTicks()
|
||||
@@ -229,17 +199,12 @@ u64 GetIdleTicks()
|
||||
// schedule things to be executed on the main thread.
|
||||
void ScheduleEvent_Threadsafe(int cyclesIntoFuture, int event_type, u64 userdata)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
Event *ne = GetNewTsEvent();
|
||||
ne->time = globalTimer + cyclesIntoFuture;
|
||||
ne->type = event_type;
|
||||
ne->next = 0;
|
||||
ne->userdata = userdata;
|
||||
if(!tsFirst)
|
||||
tsFirst = ne;
|
||||
if(tsLast)
|
||||
tsLast->next = ne;
|
||||
tsLast = ne;
|
||||
std::lock_guard<std::mutex> lk(tsWriteLock);
|
||||
Event ne;
|
||||
ne.time = globalTimer + cyclesIntoFuture;
|
||||
ne.type = event_type;
|
||||
ne.userdata = userdata;
|
||||
tsQueue.Push(ne);
|
||||
}
|
||||
|
||||
// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread
|
||||
@@ -248,7 +213,6 @@ void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata)
|
||||
{
|
||||
if(Core::IsCPUThread())
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
event_types[event_type].callback(userdata, 0);
|
||||
}
|
||||
else
|
||||
@@ -355,54 +319,9 @@ void RemoveEvent(int event_type)
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveThreadsafeEvent(int event_type)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
if (!tsFirst)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while(tsFirst)
|
||||
{
|
||||
if (tsFirst->type == event_type)
|
||||
{
|
||||
Event *next = tsFirst->next;
|
||||
FreeTsEvent(tsFirst);
|
||||
tsFirst = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tsFirst)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Event *prev = tsFirst;
|
||||
Event *ptr = prev->next;
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr->type == event_type)
|
||||
{
|
||||
prev->next = ptr->next;
|
||||
FreeTsEvent(ptr);
|
||||
ptr = prev->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveAllEvents(int event_type)
|
||||
{
|
||||
RemoveThreadsafeEvent(event_type);
|
||||
{
|
||||
MoveEvents();
|
||||
RemoveEvent(event_type);
|
||||
}
|
||||
|
||||
@@ -447,34 +366,24 @@ void ProcessFifoWaitEvents()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveEvents()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(externalEventSection);
|
||||
// Move events from async queue into main queue
|
||||
while (tsFirst)
|
||||
BaseEvent sevt;
|
||||
while (tsQueue.Pop(sevt))
|
||||
{
|
||||
Event *next = tsFirst->next;
|
||||
AddEventToQueue(tsFirst);
|
||||
tsFirst = next;
|
||||
}
|
||||
tsLast = NULL;
|
||||
|
||||
// Move free events to threadsafe pool
|
||||
while(allocatedTsEvents > 0 && eventPool)
|
||||
{
|
||||
Event *ev = eventPool;
|
||||
eventPool = ev->next;
|
||||
ev->next = eventTsPool;
|
||||
eventTsPool = ev;
|
||||
allocatedTsEvents--;
|
||||
Event *evt = GetNewEvent();
|
||||
evt->time = sevt.time;
|
||||
evt->userdata = sevt.userdata;
|
||||
evt->type = sevt.type;
|
||||
AddEventToQueue(evt);
|
||||
}
|
||||
}
|
||||
|
||||
void Advance()
|
||||
{
|
||||
{
|
||||
MoveEvents();
|
||||
|
||||
int cyclesExecuted = slicelength - downcount;
|
||||
@@ -606,3 +515,4 @@ void SetFakeTBStartTicks(u64 val)
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata=0);
|
||||
|
||||
// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(int event_type);
|
||||
void RemoveThreadsafeEvent(int event_type);
|
||||
void RemoveAllEvents(int event_type);
|
||||
bool IsScheduled(int event_type);
|
||||
void Advance();
|
||||
|
||||
@@ -342,7 +342,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||
if (!unresolvedJumps[i].empty())
|
||||
{
|
||||
// Check if there were any blocks waiting for this block to be linkable
|
||||
unsigned int size = unresolvedJumps[i].size();
|
||||
size_t size = unresolvedJumps[i].size();
|
||||
unresolvedJumps[i].remove(start_addr);
|
||||
if (unresolvedJumps[i].size() < size)
|
||||
{
|
||||
|
||||
@@ -932,12 +932,12 @@ void DSPJitRegCache::writeReg(int dreg, OpArg arg)
|
||||
{
|
||||
switch(regs[dreg].size)
|
||||
{
|
||||
case 2: emitter.MOV(16, reg, Imm16(arg.offset)); break;
|
||||
case 4: emitter.MOV(32, reg, Imm32(arg.offset)); break;
|
||||
case 2: emitter.MOV(16, reg, Imm16((u16) arg.offset)); break;
|
||||
case 4: emitter.MOV(32, reg, Imm32((u32) arg.offset)); break;
|
||||
#ifdef _M_X64
|
||||
case 8:
|
||||
if ((s32)arg.offset == (s64)arg.offset)
|
||||
emitter.MOV(64, reg, Imm32(arg.offset));
|
||||
if ((u32) arg.offset == arg.offset)
|
||||
emitter.MOV(64, reg, Imm32((u32) arg.offset));
|
||||
else
|
||||
emitter.MOV(64, reg, Imm64(arg.offset));
|
||||
break;
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include "FileUtil.h"
|
||||
|
||||
CDump::CDump(const char* _szFilename) :
|
||||
m_pData(NULL),
|
||||
m_bInit(false)
|
||||
m_pData(NULL)
|
||||
{
|
||||
File::IOFile pStream(_szFilename, "rb");
|
||||
if (pStream)
|
||||
|
||||
@@ -32,7 +32,6 @@ private:
|
||||
|
||||
u8 *m_pData;
|
||||
|
||||
bool m_bInit;
|
||||
size_t m_size;
|
||||
|
||||
u32 Read32(u32 _pos);
|
||||
|
||||
@@ -75,14 +75,14 @@ void FifoRecorder::WriteGPCommand(u8 *data, u32 size)
|
||||
m_RecordAnalyzer.AnalyzeGPCommand(data);
|
||||
|
||||
// Copy data to buffer
|
||||
u32 currentSize = m_FifoData.size();
|
||||
size_t currentSize = m_FifoData.size();
|
||||
m_FifoData.resize(currentSize + size);
|
||||
memcpy(&m_FifoData[currentSize], data, size);
|
||||
}
|
||||
|
||||
if (m_FrameEnded && m_FifoData.size() > 0)
|
||||
{
|
||||
u32 dataSize = m_FifoData.size();
|
||||
size_t dataSize = m_FifoData.size();
|
||||
m_CurrentFrame.fifoDataSize = dataSize;
|
||||
m_CurrentFrame.fifoData = new u8[dataSize];
|
||||
memcpy(m_CurrentFrame.fifoData, &m_FifoData[0], dataSize);
|
||||
|
||||
@@ -154,8 +154,9 @@ bool InstallCodeHandler()
|
||||
// Turn off Pause on start
|
||||
Memory::Write_U32(0, 0x80002774);
|
||||
|
||||
// Write the Game ID into the location expected by WiiRD
|
||||
Memory::WriteBigEData(Memory::GetPointer(0x80000000), 0x80001800, 6);
|
||||
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
|
||||
// For the purpose of this, see HLEGeckoCodehandler.
|
||||
Memory::Write_U32(0xd01f1bad, 0x80001800);
|
||||
|
||||
// Create GCT in memory
|
||||
Memory::Write_U32(0x00d0c0de, codelist_location);
|
||||
@@ -279,10 +280,7 @@ void RunCodeHandler()
|
||||
{
|
||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats && active_codes.size() > 0)
|
||||
{
|
||||
u8 *gameId = Memory::GetPointer(0x80000000);
|
||||
u8 *wiirdId = Memory::GetPointer(0x80001800);
|
||||
|
||||
if (!code_handler_installed || memcmp(gameId, wiirdId, 6))
|
||||
if (!code_handler_installed || Memory::Read_U32(0x80001800) - 0xd01f1bad > 5)
|
||||
code_handler_installed = InstallCodeHandler();
|
||||
|
||||
if (code_handler_installed)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
namespace Gecko
|
||||
{
|
||||
|
||||
// TODO: Support loading codes from default game inis.
|
||||
void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
@@ -96,7 +97,7 @@ void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcode)
|
||||
}
|
||||
|
||||
lines.push_back(name);
|
||||
|
||||
|
||||
// save all the code lines
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
codes_iter = gcode.codes.begin(),
|
||||
|
||||
@@ -42,57 +42,7 @@ static const SPatch OSPatches[] =
|
||||
{
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// speedup
|
||||
//{ "OSProtectRange", HLE_Misc::UnimplementedFunctionFalse, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "THPPlayerGetState", HLE_Misc:THPPlayerGetState, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "memcpy", HLE_Misc::gc_memcpy, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
//{ "memcmp", HLE_Misc::gc_memcmp, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
//{ "memset", HLE_Misc::gc_memset, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
//{ "memmove", HLE_Misc::gc_memmove, HLE_HOOK_REPLACE, HLE_TYPE_MEMORY },
|
||||
|
||||
//{ "__div2i", HLE_Misc::div2i, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC }, // Slower?
|
||||
//{ "__div2u", HLE_Misc::div2u, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC }, // Slower?
|
||||
|
||||
//{ "DCFlushRange", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "DCInvalidateRange", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ "DCZeroRange", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// debug out is very nice ;)
|
||||
|
||||
{ "OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "OSPanic", HLE_OS::HLE_OSPanic, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // gcc-optimized printf?
|
||||
{ "___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used for early init things (normally)
|
||||
{ "___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used by sysmenu (+more?)
|
||||
|
||||
// wii only
|
||||
//{ "__OSInitAudioSystem", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// Super Monkey Ball - no longer needed.
|
||||
//{ ".evil_vec_cosine", HLE_Misc::SMB_EvilVecCosine, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".evil_normalize", HLE_Misc::SMB_EvilNormalize, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".evil_vec_setlength", HLE_Misc::SMB_evil_vec_setlength, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".evil_vec_something", HLE_Misc::FZero_evil_vec_normalize, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
{ "PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
//{ ".sqrt_internal_needs_cr1", HLE_Misc::SMB_sqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".rsqrt_internal_needs_cr1", HLE_Misc::SMB_rsqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".atan2", HLE_Misc::SMB_atan2HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".sqrt_fz", HLE_Misc::FZ_sqrtHLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// F-zero still isn't working correctly, but these aren't really helping.
|
||||
|
||||
//{ ".sqrt_internal_fz", HLE_Misc::FZ_sqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
//{ ".rsqrt_internal_fz", HLE_Misc::FZ_rsqrt_internal, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
//{ ".kill_infinites", HLE_Misc::FZero_kill_infinites, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
// special
|
||||
// { "GXPeekZ", HLE_Misc::GXPeekZHLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
// { "GXPeekARGB", HLE_Misc::GXPeekARGBHLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// Name doesn't matter, installed in CBoot::BootUp()
|
||||
{ "HBReload", HLE_Misc::HBReload, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
@@ -101,11 +51,24 @@ static const SPatch OSPatches[] =
|
||||
{ "__OSBootDol", HLE_Misc::OSBootDol, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
{ "OSGetResetCode", HLE_Misc::OSGetResetCode, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC },
|
||||
|
||||
// Debug/OS Support
|
||||
{ "OSPanic", HLE_OS::HLE_OSPanic, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
|
||||
{ "OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // gcc-optimized printf?
|
||||
{ "___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used for early init things (normally)
|
||||
{ "___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG },
|
||||
{ "__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used by sysmenu (+more?)
|
||||
{ "GeckoCodehandler", HLE_Misc::HLEGeckoCodehandler, HLE_HOOK_START, HLE_TYPE_GENERIC },
|
||||
};
|
||||
|
||||
static const SPatch OSBreakPoints[] =
|
||||
{
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||
{ "FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction },
|
||||
};
|
||||
|
||||
void Patch(u32 addr, const char *hle_func_name)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
|
||||
#include "HLE.h"
|
||||
#include "PowerPC/PPCAnalyst.h"
|
||||
#include "PowerPC/PPCCache.h"
|
||||
#include "PowerPC/SignatureDB.h"
|
||||
#include "PowerPC/PPCSymbolDB.h"
|
||||
#include "CommonPaths.h"
|
||||
@@ -27,21 +28,6 @@ namespace HLE_Misc
|
||||
|
||||
std::string args;
|
||||
u32 argsPtr;
|
||||
u32 bootType;
|
||||
|
||||
// Helper to quickly read the floating point value at a memory location.
|
||||
inline float F(u32 addr)
|
||||
{
|
||||
u32 mem = Memory::ReadFast32(addr);
|
||||
return *((float*)&mem);
|
||||
}
|
||||
|
||||
// Helper to quickly write a floating point value to a memory location.
|
||||
inline void FW(u32 addr, float x)
|
||||
{
|
||||
u32 data = *((u32*)&x);
|
||||
Memory::WriteUnchecked_U32(data, addr);
|
||||
}
|
||||
|
||||
// If you just want to kill a function, one of the three following are usually appropriate.
|
||||
// According to the PPC ABI, the return value is always in r3.
|
||||
@@ -50,32 +36,6 @@ void UnimplementedFunction()
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void UnimplementedFunctionTrue()
|
||||
{
|
||||
GPR(3) = 1;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void UnimplementedFunctionFalse()
|
||||
{
|
||||
GPR(3) = 0;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void GXPeekZ()
|
||||
{
|
||||
// Just some fake Z value.
|
||||
Memory::Write_U32(0xFFFFFF, GPR(5));
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void GXPeekARGB()
|
||||
{
|
||||
// Just some fake color value.
|
||||
Memory::Write_U32(0xFFFFFFFF, GPR(5));
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// If you want a function to panic, you can rename it PanicAlert :p
|
||||
// Don't know if this is worth keeping.
|
||||
void HLEPanicAlert()
|
||||
@@ -84,200 +44,6 @@ void HLEPanicAlert()
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Computes the cosine of the angle between the two fvec3s pointed at by r3 and r4.
|
||||
void SMB_EvilVecCosine()
|
||||
{
|
||||
u32 r3 = GPR(3);
|
||||
u32 r4 = GPR(4);
|
||||
|
||||
float x1 = F(r3);
|
||||
float y1 = F(r3 + 4);
|
||||
float z1 = F(r3 + 8);
|
||||
|
||||
float x2 = F(r4);
|
||||
float y2 = F(r4 + 4);
|
||||
float z2 = F(r4 + 8);
|
||||
|
||||
float s1 = x1*x1 + y1*y1 + z1*z1;
|
||||
float s2 = x2*x2 + y2*y2 + z2*z2;
|
||||
|
||||
float dot = x1*x2 + y1*y2 + z1*z2;
|
||||
|
||||
rPS0(1) = dot / sqrtf(s1 * s2);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Normalizes the vector pointed at by r3.
|
||||
void SMB_EvilNormalize()
|
||||
{
|
||||
u32 r3 = GPR(3);
|
||||
float x = F(r3);
|
||||
float y = F(r3 + 4);
|
||||
float z = F(r3 + 8);
|
||||
float len = x*x + y*y + z*z;
|
||||
float inv_len;
|
||||
if (len <= 0)
|
||||
inv_len = 0;
|
||||
else
|
||||
inv_len = 1.0f / sqrtf(len);
|
||||
x *= inv_len;
|
||||
y *= inv_len;
|
||||
z *= inv_len;
|
||||
FW(r3, x);
|
||||
FW(r3 + 4, y);
|
||||
FW(r3 + 8, z);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Scales the vector pointed at by r3 to the length specified by f0.
|
||||
// Writes results to vector pointed at by r4.
|
||||
void SMB_evil_vec_setlength()
|
||||
{
|
||||
u32 r3 = GPR(3);
|
||||
u32 r4 = GPR(4);
|
||||
float x = F(r3);
|
||||
float y = F(r3 + 4);
|
||||
float z = F(r3 + 8);
|
||||
float inv_len = (float)(rPS0(0) / sqrt(x*x + y*y + z*z));
|
||||
x *= inv_len;
|
||||
y *= inv_len;
|
||||
z *= inv_len;
|
||||
FW(r4, x);
|
||||
FW(r4 + 4, y);
|
||||
FW(r4 + 8, z);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Internal square root function in the crazy math lib. Acts a bit odd, just read it. It's not a bug :p
|
||||
void SMB_sqrt_internal()
|
||||
{
|
||||
double f = sqrt(rPS0(1));
|
||||
rPS0(0) = rPS0(1);
|
||||
rPS1(0) = rPS0(1);
|
||||
rPS0(1) = f;
|
||||
rPS1(1) = f;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Internal inverse square root function in the crazy math lib.
|
||||
void SMB_rsqrt_internal()
|
||||
{
|
||||
double f = 1.0 / sqrt(rPS0(1));
|
||||
rPS0(1) = f;
|
||||
rPS1(1) = f;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void SMB_atan2()
|
||||
{
|
||||
// in: f1 = x, f2 = y
|
||||
// out: r3 = angle
|
||||
double angle = atan2(rPS0(1), rPS0(2));
|
||||
int angle_fixpt = (int)(angle / 3.14159 * 32767);
|
||||
if (angle_fixpt < -32767) angle_fixpt = -32767;
|
||||
if (angle_fixpt > 32767) angle_fixpt = 32767;
|
||||
GPR(3) = angle_fixpt;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
|
||||
// F-zero math lib range: 8006d044 - 8006f770
|
||||
|
||||
void FZero_kill_infinites()
|
||||
{
|
||||
// TODO: Kill infinites in FPR(1)
|
||||
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void FZ_sqrt() {
|
||||
u32 r3 = GPR(3);
|
||||
double x = rPS0(0);
|
||||
x = sqrt(x);
|
||||
FW(r3, (float)x);
|
||||
rPS0(0) = x;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Internal square root function in the crazy math lib. Acts a bit odd, just read it. It's not a bug :p
|
||||
void FZ_sqrt_internal()
|
||||
{
|
||||
double f = sqrt(rPS0(1));
|
||||
rPS0(0) = rPS0(1);
|
||||
rPS1(0) = rPS0(1);
|
||||
rPS0(1) = f;
|
||||
rPS1(1) = f;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
// Internal inverse square root function in the crazy math lib.
|
||||
void FZ_rsqrt_internal()
|
||||
{
|
||||
double f = 1.0 / sqrt(rPS0(1));
|
||||
rPS0(1) = f;
|
||||
rPS1(1) = f;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void FZero_evil_vec_normalize()
|
||||
{
|
||||
u32 r3 = GPR(3);
|
||||
float x = F(r3);
|
||||
float y = F(r3 + 4);
|
||||
float z = F(r3 + 8);
|
||||
float sq_len = x*x + y*y + z*z;
|
||||
float inv_len = 1.0f / sqrtf(sq_len);
|
||||
x *= inv_len;
|
||||
y *= inv_len;
|
||||
z *= inv_len;
|
||||
FW(r3, x);
|
||||
FW(r3 + 4, y);
|
||||
FW(r3 + 8, z);
|
||||
rPS0(1) = inv_len * sq_len; // len
|
||||
rPS1(1) = inv_len * sq_len; // len
|
||||
NPC = LR;
|
||||
|
||||
/*
|
||||
.evil_vec_something
|
||||
|
||||
(f6, f7, f8) <- [r3]
|
||||
f1 = f6 * f6
|
||||
f1 += f7 * f7
|
||||
f1 += f8 * f8
|
||||
f2 = mystery
|
||||
f4 = f2 * f1
|
||||
f3 = f2 + f2
|
||||
f1 = 1/f0
|
||||
|
||||
f6 *= f1
|
||||
f7 *= f1
|
||||
f8 *= f1
|
||||
|
||||
8006d668: lis r5, 0xE000
|
||||
8006d684: lfs f2, 0x01A0 (r5)
|
||||
8006d69c: fmr f0,f2
|
||||
8006d6a0: fmuls f4,f2,f1
|
||||
8006d6a4: fadds f3,f2,f2
|
||||
8006d6a8: frsqrte f1,f0,f1
|
||||
8006d6ac: fadds f3,f3,f2
|
||||
8006d6b0: fmuls f5,f1,f1
|
||||
8006d6b4: fnmsubs f5,f5,f4,f3
|
||||
8006d6b8: fmuls f1,f1,f5
|
||||
8006d6bc: fmuls f5,f1,f1
|
||||
8006d6c0: fnmsubs f5,f5,f4,f3
|
||||
8006d6c4: fmuls f1,f1,f5
|
||||
8006d6c8: fmuls f6,f6,f1
|
||||
8006d6cc: stfs f6, 0 (r3)
|
||||
8006d6d0: fmuls f7,f7,f1
|
||||
8006d6d4: stfs f7, 0x0004 (r3)
|
||||
8006d6d8: fmuls f8,f8,f1
|
||||
8006d6dc: stfs f8, 0x0008 (r3)
|
||||
8006d6e0: fmuls f1,f1,f0
|
||||
8006d6e4: blr
|
||||
*/
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void HBReload()
|
||||
{
|
||||
// There isn't much we can do. Just stop cleanly.
|
||||
@@ -403,62 +169,6 @@ u32 GetDolFileSize(std::string dol)
|
||||
return (u32)pFileSystem->GetFileSize(dolFile.c_str());
|
||||
}
|
||||
|
||||
void gc_memmove()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 src = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
memmove((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void gc_memcpy()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 src = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
memcpy((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void gc_memset()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 ch = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
memset((u8*)(Memory::base + dest), ch, count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void gc_memcmp()
|
||||
{
|
||||
u32 dest = GPR(3);
|
||||
u32 src = GPR(4);
|
||||
u32 count = GPR(5);
|
||||
GPR(3) = memcmp((u8*)(Memory::base + dest), (u8*)(Memory::base + src), count);
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void div2i()
|
||||
{
|
||||
s64 num = (s64)(GPR(3)) << 32 | GPR(4);
|
||||
s64 den = (s64)(GPR(5)) << 32 | GPR(6);
|
||||
s64 quo = num / den;
|
||||
GPR(3) = quo >> 32;
|
||||
GPR(4) = quo & 0xffffffff;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void div2u()
|
||||
{
|
||||
u64 num = (u64)(GPR(3)) << 32 | GPR(4);
|
||||
u64 den = (u64)(GPR(5)) << 32 | GPR(6);
|
||||
u64 quo = num / den;
|
||||
GPR(3) = quo >> 32;
|
||||
GPR(4) = quo & 0xffffffff;
|
||||
NPC = LR;
|
||||
}
|
||||
|
||||
void OSGetResetCode()
|
||||
{
|
||||
u32 resetCode = Memory::Read_U32(0xCC003024);
|
||||
@@ -484,8 +194,6 @@ void OSBootDol()
|
||||
{
|
||||
if (GetIOSVersion() >= 30)
|
||||
{
|
||||
bootType = GPR(4);
|
||||
|
||||
if ((GPR(4) >> 28) == 0x8)
|
||||
{
|
||||
u32 resetCode = GPR(30);
|
||||
@@ -535,4 +243,26 @@ void OSBootDol()
|
||||
NPC = PC;
|
||||
}
|
||||
|
||||
void HLEGeckoCodehandler()
|
||||
{
|
||||
// Work around the codehandler not properly invalidating the icache, but
|
||||
// only the first few frames.
|
||||
// (Project M uses a conditional to only apply patches after something has
|
||||
// been read into memory, or such, so we do the first 5 frames. More
|
||||
// robust alternative would be to actually detect memory writes, but that
|
||||
// would be even uglier.)
|
||||
u32 magic = 0xd01f1bad;
|
||||
u32 existing = Memory::Read_U32(0x80001800);
|
||||
if (existing - magic == 5)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if(existing - magic > 5)
|
||||
{
|
||||
existing = magic;
|
||||
}
|
||||
Memory::Write_U32(existing + 1, 0x80001800);
|
||||
PowerPC::ppcState.iCache.Reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,34 +7,12 @@
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
void Pass();
|
||||
void HLEPanicAlert();
|
||||
void UnimplementedFunction();
|
||||
void UnimplementedFunctionTrue();
|
||||
void UnimplementedFunctionFalse();
|
||||
void GXPeekZ();
|
||||
void GXPeekARGB();
|
||||
void SMB_EvilVecCosine();
|
||||
void SMB_EvilNormalize();
|
||||
void SMB_sqrt_internal();
|
||||
void SMB_rsqrt_internal();
|
||||
void SMB_atan2();
|
||||
void SMB_evil_vec_setlength();
|
||||
void FZero_kill_infinites();
|
||||
void FZero_evil_vec_normalize();
|
||||
void FZ_sqrt();
|
||||
void FZ_sqrt_internal();
|
||||
void FZ_rsqrt_internal();
|
||||
void HBReload();
|
||||
void OSBootDol();
|
||||
void OSGetResetCode();
|
||||
void memcpy();
|
||||
void memset();
|
||||
void memmove();
|
||||
void memcmp();
|
||||
void div2i();
|
||||
void div2u();
|
||||
void ExecuteDOL(u8* dolFile, u32 fileSize);
|
||||
void HLEGeckoCodehandler();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -364,7 +364,7 @@ void CUCode_AXWii::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nv
|
||||
for (size_t i = 0; i < nvals; ++i)
|
||||
{
|
||||
curr += (vol2 - vol1) / (float)nvals;
|
||||
output[i] = curr;
|
||||
output[i] = (u16) curr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ bool WritePB(u32 addr, const PB_TYPE& pb)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Dump the value of a PB for debugging
|
||||
#define DUMP_U16(field) WARN_LOG(DSPHLE, " %04x (%s)", pb.field, #field)
|
||||
#define DUMP_U32(field) WARN_LOG(DSPHLE, " %08x (%s)", HILO_TO_32(pb.field), #field)
|
||||
@@ -122,6 +123,7 @@ void DumpPB(const PB_TYPE& pb)
|
||||
|
||||
// TODO: complete as needed
|
||||
}
|
||||
#endif
|
||||
|
||||
// Simulated accelerator state.
|
||||
static u32 acc_loop_addr, acc_end_addr;
|
||||
|
||||
@@ -219,8 +219,7 @@ void PrintObject(const T &Obj)
|
||||
|
||||
// If this miscompiles, adjust the size of
|
||||
// ZeldaVoicePB to 0x180 bytes (0xc0 shorts).
|
||||
CompileTimeAssert<sizeof(ZeldaVoicePB) == 0x180> ensure_zpb_size_correct;
|
||||
(void)ensure_zpb_size_correct;
|
||||
static_assert(sizeof(ZeldaVoicePB) == 0x180, "ZeldaVoicePB incorrectly defined.");
|
||||
|
||||
ss << std::hex;
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
|
||||
@@ -116,7 +116,7 @@ void GeckoSockServer::ClientThread()
|
||||
char data[128];
|
||||
std::size_t got = 0;
|
||||
|
||||
if (client.Receive(&data[0], ARRAYSIZE(data), got) == sf::Socket::Disconnected)
|
||||
if (client.Receive(&data[0], ArraySize(data), got) == sf::Socket::Disconnected)
|
||||
client_running = false;
|
||||
|
||||
if (got != 0)
|
||||
|
||||
@@ -52,7 +52,9 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
|
||||
: m_valid(false)
|
||||
, m_fileName(filename)
|
||||
{
|
||||
File::IOFile mcdFile(m_fileName, "r+b");
|
||||
// Currently there is a string freeze. instead of adding a new message about needing r/w
|
||||
// open file read only, if write is denied the error will be reported at that point
|
||||
File::IOFile mcdFile(m_fileName, "rb");
|
||||
if (!mcdFile.IsOpen())
|
||||
{
|
||||
if (!forceCreation && !AskYesNoT("\"%s\" does not exist.\n Create a new 16MB Memcard?", filename))
|
||||
@@ -1324,8 +1326,8 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP)
|
||||
void GCMemcard::CARD_GetSerialNo(u32 *serial1,u32 *serial2)
|
||||
{
|
||||
u32 serial[8];
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
memcpy(&serial[i], (u8 *) &hdr+(i*4), 4);
|
||||
}
|
||||
@@ -1429,15 +1431,15 @@ s32 GCMemcard::PSO_MakeSaveGameValid(DEntry& direntry, std::vector<GCMBlock> &Fi
|
||||
for (i=0; i < 256; i++)
|
||||
{
|
||||
chksum = i;
|
||||
for (j=8; j > 0; j--)
|
||||
{
|
||||
if (chksum & 1)
|
||||
chksum = (chksum>>1)^0xEDB88320;
|
||||
else
|
||||
chksum >>= 1;
|
||||
}
|
||||
for (j=8; j > 0; j--)
|
||||
{
|
||||
if (chksum & 1)
|
||||
chksum = (chksum>>1)^0xEDB88320;
|
||||
else
|
||||
chksum >>= 1;
|
||||
}
|
||||
|
||||
crc32LUT[i] = chksum;
|
||||
crc32LUT[i] = chksum;
|
||||
}
|
||||
|
||||
// PSO initial crc32 value
|
||||
|
||||
@@ -119,7 +119,7 @@ void GCPad::GetInput(SPADStatus* const pad)
|
||||
void GCPad::SetMotor(const u8 on)
|
||||
{
|
||||
float state = (float)on / 255;
|
||||
float force = abs(state - 0.5) * 2;
|
||||
float force = abs(state - 0.5f) * 2;
|
||||
if (state < 0.5)
|
||||
force = -force;
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ u32 Read_Instruction(const u32 em_address)
|
||||
return inst.hex;
|
||||
}
|
||||
|
||||
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
|
||||
void WriteBigEData(const u8 *_pData, const u32 _Address, const size_t _iSize)
|
||||
{
|
||||
memcpy(GetPointer(_Address), _pData, _iSize);
|
||||
}
|
||||
|
||||
@@ -140,7 +140,6 @@ u64 Read_U64(const u32 _Address);
|
||||
float Read_F32(const u32 _Address);
|
||||
double Read_F64(const u32 _Address);
|
||||
|
||||
|
||||
// used by JIT. Return zero-extended 32bit values
|
||||
u32 Read_U8_ZX(const u32 _Address);
|
||||
u32 Read_U16_ZX(const u32 _Address);
|
||||
@@ -157,10 +156,13 @@ void Write_U16_Swap(const u16 _Data, const u32 _Address);
|
||||
void Write_U32_Swap(const u32 _Data, const u32 _Address);
|
||||
void Write_U64_Swap(const u64 _Data, const u32 _Address);
|
||||
|
||||
// Useful helper functions, used by ARM JIT
|
||||
void Write_F64(const double _Data, const u32 _Address);
|
||||
|
||||
void WriteHW_U32(const u32 _Data, const u32 _Address);
|
||||
void GetString(std::string& _string, const u32 _Address);
|
||||
|
||||
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 size);
|
||||
void WriteBigEData(const u8 *_pData, const u32 _Address, const size_t size);
|
||||
void ReadBigEData(u8 *_pDest, const u32 _Address, const u32 size);
|
||||
u8* GetPointer(const u32 _Address);
|
||||
void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks);
|
||||
|
||||
@@ -507,6 +507,16 @@ void Write_U64_Swap(const u64 _Data, const u32 _Address) {
|
||||
Write_U64(Common::swap64(_Data), _Address);
|
||||
}
|
||||
|
||||
void Write_F64(const double _Data, const u32 _Address)
|
||||
{
|
||||
union
|
||||
{
|
||||
u64 i;
|
||||
double d;
|
||||
} cvt;
|
||||
cvt.d = _Data;
|
||||
Write_U64(cvt.i, _Address);
|
||||
}
|
||||
u8 ReadUnchecked_U8(const u32 _Address)
|
||||
{
|
||||
u8 _var = 0;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "../ConfigManager.h"
|
||||
#include "../CoreTiming.h"
|
||||
#include "../Movie.h"
|
||||
#include "../NetPlayClient.h"
|
||||
#include "../NetPlayProto.h"
|
||||
|
||||
#include "SystemTimers.h"
|
||||
#include "ProcessorInterface.h"
|
||||
@@ -644,7 +644,10 @@ int GetTicksToNextSIPoll()
|
||||
// Poll for input at regular intervals (once per frame) when playing or recording a movie
|
||||
if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
|
||||
{
|
||||
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
|
||||
if (Movie::IsNetPlayRecording())
|
||||
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2;
|
||||
else
|
||||
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
|
||||
}
|
||||
if (NetPlay::IsNetPlayRunning())
|
||||
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2;
|
||||
|
||||
@@ -231,7 +231,7 @@ void CSIDevice_DanceMat::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
unsigned int uStrength = command.Parameter2;
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Rumble(numPAD, uType, uStrength);
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(u8 numPAD, SPADStatus status, u32 *PADStatus);
|
||||
static u8 NetPlay_GetPadNum(u8 numPAD);
|
||||
static u8 NetPlay_InGamePadToLocalPad(u8 numPAD);
|
||||
|
||||
// Return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
@@ -249,7 +249,7 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
unsigned int uStrength = command.Parameter2;
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Rumble(numPAD, uType, uStrength);
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(u8 numPAD, SPADStatus status, u32 *PADStatus);
|
||||
static u8 NetPlay_GetPadNum(u8 numPAD);
|
||||
static u8 NetPlay_InGamePadToLocalPad(u8 numPAD);
|
||||
|
||||
// Return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
@@ -254,7 +254,7 @@ void CSIDevice_GCSteeringWheel::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
unsigned int uType = command.Parameter2; // 06 = motor on, 04 = motor off
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Motor(numPAD, uType, uStrength);
|
||||
@@ -273,7 +273,7 @@ void CSIDevice_GCSteeringWheel::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
unsigned int uStrength = command.Parameter2;
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Rumble(numPAD, uType, uStrength);
|
||||
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(u8 numPAD, SPADStatus status, u32 *PADStatus);
|
||||
static u8 NetPlay_GetPadNum(u8 numPAD);
|
||||
static u8 NetPlay_InGamePadToLocalPad(u8 numPAD);
|
||||
|
||||
// Return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
@@ -29,7 +29,7 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
||||
break;
|
||||
// WiiMenu... no idea
|
||||
case 0x24:
|
||||
ERROR_LOG(WII_IOB, "IOP: Read32 from 0x18 = 0x%08x (WiiMenu)", _Address);
|
||||
ERROR_LOG(WII_IOB, "IOP: Read32 from 0x24 = 0x%08x (WiiMenu)", _Address);
|
||||
break;
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ public:
|
||||
|
||||
private:
|
||||
Buttons* m_buttons;
|
||||
MixedTriggers* m_triggers;
|
||||
AnalogStick* m_stick;
|
||||
Triggers *m_effect_dial;
|
||||
Slider *m_left_table, *m_right_table, *m_crossfade;
|
||||
|
||||