mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-22 10:05:09 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c52a6371a4 |
Vendored
+579
-624
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+503
-548
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+508
-550
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
Vendored
+527
-573
File diff suppressed because it is too large
Load Diff
Vendored
+502
-547
File diff suppressed because it is too large
Load Diff
@@ -788,7 +788,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
|
|||||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
|
||||||
jstring jprogramId,
|
jstring jprogramId,
|
||||||
jstring jupdatePath) {
|
jstring jupdatePath) {
|
||||||
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
|
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||||
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
|
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
|
||||||
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
|
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
|
||||||
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
|
||||||
@@ -796,7 +796,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
|
|||||||
for (const auto& item : nsp->GetNCAs()) {
|
for (const auto& item : nsp->GetNCAs()) {
|
||||||
for (const auto& nca_details : item.second) {
|
for (const auto& nca_details : item.second) {
|
||||||
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
|
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
|
||||||
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId());
|
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
|
||||||
if (update_id == program_id) {
|
if (update_id == program_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,7 +289,6 @@
|
|||||||
<string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string>
|
<string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string>
|
||||||
<string name="gpu_driver_manager">Gestor de controladores de la GPU</string>
|
<string name="gpu_driver_manager">Gestor de controladores de la GPU</string>
|
||||||
<string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string>
|
<string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string>
|
||||||
<string name="post_processing_add">Añadir efecto</string>
|
|
||||||
<string name="post_processing_open_list">Abrir lista</string>
|
<string name="post_processing_open_list">Abrir lista</string>
|
||||||
<string name="post_processing_close_list">Cerrar lista</string>
|
<string name="post_processing_close_list">Cerrar lista</string>
|
||||||
<string name="post_processing_reset">Restablecer a predeterminado</string>
|
<string name="post_processing_reset">Restablecer a predeterminado</string>
|
||||||
|
|||||||
@@ -318,13 +318,6 @@
|
|||||||
<string name="frame_gen_target_rate">Целевая частота кадров</string>
|
<string name="frame_gen_target_rate">Целевая частота кадров</string>
|
||||||
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string>
|
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string>
|
||||||
<string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string>
|
<string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string>
|
||||||
<string name="frame_gen_on">Вкл.</string>
|
|
||||||
<string name="frame_gen_off">Выкл.</string>
|
|
||||||
<string name="frame_gen_fixed">Фикс.</string>
|
|
||||||
<string name="frame_gen_flow_auto">Авто</string>
|
|
||||||
<string name="frame_gen_quick_description">Включите или выключите генерацию кадров и выберите множитель кадров.</string>
|
|
||||||
<string name="frame_gen_target_rate_quick_description">Генерация кадров с заданной частотой кадров. Множитель регулируется автоматически.</string>
|
|
||||||
<string name="frame_gen_flow_scale_quick_description">Разрешение, используемое для оценки движения между кадрами. Меньшие значения экономят время ГПУ.</string>
|
|
||||||
<string name="frame_gen_queue_target">Целевой размер очереди кадров</string>
|
<string name="frame_gen_queue_target">Целевой размер очереди кадров</string>
|
||||||
<string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
|
<string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
|
||||||
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
|
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
|
||||||
@@ -335,14 +328,12 @@
|
|||||||
<string name="frame_gen_flow_scale">Разрешение оценки движения</string>
|
<string name="frame_gen_flow_scale">Разрешение оценки движения</string>
|
||||||
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string>
|
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string>
|
||||||
<string name="frame_gen_unsupported">Генерация кадров недоступна</string>
|
<string name="frame_gen_unsupported">Генерация кадров недоступна</string>
|
||||||
<string name="frame_gen_unsupported_description">В этом ГПУ драйвере отсутствует поддержка модели памяти Vulkan или половинной точности (float16), которая требуется шейдерам Lossless Scaling.</string>
|
|
||||||
<string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string>
|
<string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string>
|
||||||
<string name="lossless_scaling_install">Установить Lossless.dll</string>
|
<string name="lossless_scaling_install">Установить Lossless.dll</string>
|
||||||
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
|
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
|
||||||
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
|
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
|
||||||
<string name="frame_generation_support">Генерация кадров</string>
|
<string name="frame_generation_support">Генерация кадров</string>
|
||||||
<string name="frame_generation_supported">Поддерживается</string>
|
<string name="frame_generation_supported">Поддерживается</string>
|
||||||
<string name="frame_generation_unsupported">Не поддерживается (нет модели памяти Vulkan или float16)</string>
|
|
||||||
<string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string>
|
<string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string>
|
||||||
<string name="lossless_scaling_installed">Установлена</string>
|
<string name="lossless_scaling_installed">Установлена</string>
|
||||||
<string name="lossless_scaling_not_installed">Не установлена</string>
|
<string name="lossless_scaling_not_installed">Не установлена</string>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||||
|
|
||||||
<string name="app_disclaimer">本软件可以运行用于 Nintendo Switch 游戏机的游戏。不包含任何游戏或密钥。<br /><br />在您开始之前, 请定位您设备存储上的 <![CDATA[<b> prod.keys </b>]]> 文件。<br /><br /><![CDATA[<a href=\"https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/QuickStart.md\">了解更多</a>]]></string>
|
|
||||||
<string name="notice_notification_channel_name">错误与注意事项</string>
|
<string name="notice_notification_channel_name">错误与注意事项</string>
|
||||||
<string name="notice_notification_channel_description">当发生错误时显示通知。</string>
|
<string name="notice_notification_channel_description">当发生错误时显示通知。</string>
|
||||||
<string name="notification_permission_not_granted">未授予通知权限!</string>
|
<string name="notification_permission_not_granted">未授予通知权限!</string>
|
||||||
@@ -291,25 +290,6 @@
|
|||||||
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
|
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
|
||||||
<string name="gpu_driver_manager">GPU 驱动管理器</string>
|
<string name="gpu_driver_manager">GPU 驱动管理器</string>
|
||||||
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
|
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
|
||||||
<string name="post_processing">后处理效果</string>
|
|
||||||
<string name="post_processing_description">在渲染完成后应用 ReShade FX 效果</string>
|
|
||||||
<string name="post_processing_per_game_description">配置此游戏的效果链</string>
|
|
||||||
<string name="post_processing_add">添加效果</string>
|
|
||||||
<string name="post_processing_remove">移除</string>
|
|
||||||
<string name="post_processing_open_list">打开列表</string>
|
|
||||||
<string name="post_processing_close_list">关闭列表</string>
|
|
||||||
<string name="post_processing_remove_all">移除效果</string>
|
|
||||||
<string name="post_processing_preset_locked">预设已激活。在开始游戏前可以在后处理效果中编辑它。</string>
|
|
||||||
<string name="post_processing_preset_modified">数值已从原始预设被更改。</string>
|
|
||||||
<string name="post_processing_presets">预设</string>
|
|
||||||
<string name="post_processing_preset_new">新建预设</string>
|
|
||||||
<string name="post_processing_preset_new_description">把您加载的效果及当前数值保存为一个预设,以便今后选用。</string>
|
|
||||||
<string name="post_processing_preset_name_invalid">请给预设起一个不含等号的名称。</string>
|
|
||||||
<string name="post_processing_preset_none">无预设</string>
|
|
||||||
<string name="post_processing_preset_delete">删除预设</string>
|
|
||||||
<string name="post_processing_preset_reset">重置预设值</string>
|
|
||||||
<string name="post_processing_reset">重置为默认值</string>
|
|
||||||
<string name="post_processing_empty">找不到效果。请在此文件中放置 .fx 文件:</string>
|
|
||||||
<string name="frame_gen">帧生成</string>
|
<string name="frame_gen">帧生成</string>
|
||||||
<string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string>
|
<string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string>
|
||||||
<string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string>
|
<string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string>
|
||||||
@@ -324,13 +304,6 @@
|
|||||||
<string name="frame_gen_target_rate_60">60 FPS</string>
|
<string name="frame_gen_target_rate_60">60 FPS</string>
|
||||||
<string name="frame_gen_target_rate_90">90 FPS</string>
|
<string name="frame_gen_target_rate_90">90 FPS</string>
|
||||||
<string name="frame_gen_target_rate_120">120 FPS</string>
|
<string name="frame_gen_target_rate_120">120 FPS</string>
|
||||||
<string name="frame_gen_on">开</string>
|
|
||||||
<string name="frame_gen_off">关</string>
|
|
||||||
<string name="frame_gen_fixed">固定</string>
|
|
||||||
<string name="frame_gen_flow_auto">自动</string>
|
|
||||||
<string name="frame_gen_quick_description">打开或关闭帧生成并选择帧生成倍数。</string>
|
|
||||||
<string name="frame_gen_target_rate_quick_description">生成帧到目标帧率。倍率会自动调整。</string>
|
|
||||||
<string name="frame_gen_flow_scale_quick_description">用来估算帧间运动的分辨率。较低的值可以节省 GPU 时间。</string>
|
|
||||||
<string name="frame_gen_queue_target">帧队列目标</string>
|
<string name="frame_gen_queue_target">帧队列目标</string>
|
||||||
<string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string>
|
<string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string>
|
||||||
<string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string>
|
<string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string>
|
||||||
@@ -341,14 +314,12 @@
|
|||||||
<string name="frame_gen_flow_scale">运动预估分辨率</string>
|
<string name="frame_gen_flow_scale">运动预估分辨率</string>
|
||||||
<string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string>
|
<string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string>
|
||||||
<string name="frame_gen_unsupported">帧生成不可用</string>
|
<string name="frame_gen_unsupported">帧生成不可用</string>
|
||||||
<string name="frame_gen_unsupported_description">这个 GPU 驱动缺少 Lossless Scaling 着色器所需的 Vulkan 内存模型或半精度 (float16) 支持。</string>
|
|
||||||
<string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string>
|
<string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string>
|
||||||
<string name="lossless_scaling_install">安装 Lossless.dll</string>
|
<string name="lossless_scaling_install">安装 Lossless.dll</string>
|
||||||
<string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string>
|
<string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string>
|
||||||
<string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string>
|
<string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string>
|
||||||
<string name="frame_generation_support">帧生成</string>
|
<string name="frame_generation_support">帧生成</string>
|
||||||
<string name="frame_generation_supported">支持</string>
|
<string name="frame_generation_supported">支持</string>
|
||||||
<string name="frame_generation_unsupported">不支持 (无 Vulkan 内存模型或 float16)</string>
|
|
||||||
<string name="lossless_scaling">无损缩放</string>
|
<string name="lossless_scaling">无损缩放</string>
|
||||||
<string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string>
|
<string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string>
|
||||||
<string name="lossless_scaling_installed">已安装</string>
|
<string name="lossless_scaling_installed">已安装</string>
|
||||||
@@ -640,11 +611,6 @@
|
|||||||
<string name="log">日志记录</string>
|
<string name="log">日志记录</string>
|
||||||
<string name="flush_by_line">按行刷新调试日志</string>
|
<string name="flush_by_line">按行刷新调试日志</string>
|
||||||
<string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string>
|
<string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string>
|
||||||
<string name="extended_logging">开启扩展日志</string>
|
|
||||||
<string name="extended_logging_description">将最大日志文件大小从 100 MiB 提升至 1GiB。</string>
|
|
||||||
<string name="log_filter">日志筛选器</string>
|
|
||||||
<string name="log_filter_description">控制 Eden 的日志类别。例如: *:Info Service.LM:Debug</string>
|
|
||||||
|
|
||||||
<!-- GPU Logging strings -->
|
<!-- GPU Logging strings -->
|
||||||
<string name="gpu_logging_header">GPU 日志</string>
|
<string name="gpu_logging_header">GPU 日志</string>
|
||||||
<string name="gpu_log_level">日志等级</string>
|
<string name="gpu_log_level">日志等级</string>
|
||||||
@@ -928,8 +894,6 @@
|
|||||||
<string name="loader_error_file_not_found">ROM 文件不存在</string>
|
<string name="loader_error_file_not_found">ROM 文件不存在</string>
|
||||||
|
|
||||||
<string name="loader_requires_firmware">游戏需要固件</string>
|
<string name="loader_requires_firmware">游戏需要固件</string>
|
||||||
<string name="loader_requires_firmware_description"><![CDATA[这个游戏可能需要固件才能正常运行,但您还没有安装任何固件。请在启动前安装固件,或者按 “确定” 继续启动。]]></string>
|
|
||||||
|
|
||||||
<!-- Intent Launch strings -->
|
<!-- Intent Launch strings -->
|
||||||
<string name="searching_for_game">正在搜索游戏...</string>
|
<string name="searching_for_game">正在搜索游戏...</string>
|
||||||
<string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string>
|
<string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string>
|
||||||
|
|||||||
@@ -229,7 +229,7 @@
|
|||||||
<string name="add_directory_success">遊戲目錄新增成功</string>
|
<string name="add_directory_success">遊戲目錄新增成功</string>
|
||||||
<string name="enable_update_checks">檢查更新</string>
|
<string name="enable_update_checks">檢查更新</string>
|
||||||
<string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string>
|
<string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string>
|
||||||
<string name="update_available">發現新版本</string>
|
<string name="update_available">偵測到新版本</string>
|
||||||
<string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string>
|
<string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string>
|
||||||
<string name="downloading_update">下載更新中</string>
|
<string name="downloading_update">下載更新中</string>
|
||||||
<string name="update_download_failed">更新下載失敗</string>
|
<string name="update_download_failed">更新下載失敗</string>
|
||||||
@@ -1020,40 +1020,9 @@
|
|||||||
<string name="memory_6gb">6GB (不穩定)</string>
|
<string name="memory_6gb">6GB (不穩定)</string>
|
||||||
<string name="memory_8gb">8GB (不穩定)</string>
|
<string name="memory_8gb">8GB (不穩定)</string>
|
||||||
|
|
||||||
<!-- CPU clock levels -->
|
|
||||||
<string name="clock_normal">正常</string>
|
|
||||||
<string name="clock_boost">加速</string>
|
|
||||||
<string name="clock_fast">超頻</string>
|
|
||||||
|
|
||||||
<!-- GPU clock levels -->
|
|
||||||
<string name="fast_gpu_normal">正常</string>
|
|
||||||
<string name="fast_gpu_medium">加速</string>
|
|
||||||
<string name="fast_gpu_high">超頻</string>
|
|
||||||
|
|
||||||
<!-- GPU swizzle texture size -->
|
|
||||||
<string name="gpu_texturesizeswizzle_verysmall">極小 (16MB)</string>
|
|
||||||
<string name="gpu_texturesizeswizzle_small">小(32MB)</string>
|
|
||||||
<string name="gpu_texturesizeswizzle_normal">正常(128MB)</string>
|
|
||||||
<string name="gpu_texturesizeswizzle_large">大(256MB)</string>
|
|
||||||
<string name="gpu_texturesizeswizzle_verylarge">極大(512MB)</string>
|
|
||||||
|
|
||||||
<!-- GPU swizzle streams -->
|
|
||||||
<string name="gpu_swizzle_verylow">極小(4MB)</string>
|
|
||||||
<string name="gpu_swizzle_low">小(8MB)</string>
|
|
||||||
<string name="gpu_swizzle_normal">正常(16MB)</string>
|
|
||||||
<string name="gpu_swizzle_medium">中(32MB)</string>
|
|
||||||
<string name="gpu_swizzle_high">大(64MB)</string>
|
|
||||||
|
|
||||||
<!-- GPU swizzle chunks -->
|
|
||||||
<string name="gpu_swizzlechunk_verylow">極小(32)</string>
|
|
||||||
<string name="gpu_swizzlechunk_low">小(64)</string>
|
|
||||||
<string name="gpu_swizzlechunk_normal">正常(128)</string>
|
|
||||||
<string name="gpu_swizzlechunk_medium">中(256)</string>
|
|
||||||
<string name="gpu_swizzlechunk_high">大(512)</string>
|
|
||||||
|
|
||||||
<!-- Temperature Units -->
|
<!-- Temperature Units -->
|
||||||
<string name="temperature_celsius">攝氏</string>
|
<string name="temperature_celsius">攝氏度</string>
|
||||||
<string name="temperature_fahrenheit">華氏</string>
|
<string name="temperature_fahrenheit">華氏度</string>
|
||||||
|
|
||||||
<!-- Memory Sizes -->
|
<!-- Memory Sizes -->
|
||||||
<string name="memory_byte_shorthand">B</string>
|
<string name="memory_byte_shorthand">B</string>
|
||||||
@@ -1066,8 +1035,6 @@
|
|||||||
|
|
||||||
<string name="renderer_none">無</string>
|
<string name="renderer_none">無</string>
|
||||||
|
|
||||||
<!-- Renderer Accuracy -->
|
|
||||||
<string name="renderer_accuracy_low">效能</string>
|
|
||||||
<string name="renderer_accuracy_high">準確</string>
|
<string name="renderer_accuracy_high">準確</string>
|
||||||
|
|
||||||
<!-- DMA Accuracy -->
|
<!-- DMA Accuracy -->
|
||||||
|
|||||||
+20
-18
@@ -17,33 +17,35 @@
|
|||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
// glibc, mlibc, musl, and newlib all define their own variants of strerror_r
|
|
||||||
// We don't need to use the preprocessor, we can just select depending on return type
|
|
||||||
template<typename T> std::string HandleStrerrorR(T r, char *err_str);
|
|
||||||
template<> std::string HandleStrerrorR(char* r, char *) { return std::string{r}; }
|
|
||||||
template<> std::string HandleStrerrorR(const char* r, char *) { return std::string{r}; }
|
|
||||||
template<> std::string HandleStrerrorR(int r, char *err_str) {
|
|
||||||
return std::string{r != 0
|
|
||||||
? "(strerror_r failed to format error)"
|
|
||||||
: err_str};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string NativeErrorToString(int e) {
|
std::string NativeErrorToString(int e) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LPSTR err_str;
|
LPSTR err_str;
|
||||||
|
|
||||||
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
LPSTR(&err_str), 1, nullptr);
|
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
|
||||||
if (res) {
|
if (!res) {
|
||||||
std::string ret(err_str);
|
return "(FormatMessageA failed to format error)";
|
||||||
LocalFree(err_str);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
return "(FormatMessageA failed to format error)";
|
std::string ret(err_str);
|
||||||
|
LocalFree(err_str);
|
||||||
|
return ret;
|
||||||
#else
|
#else
|
||||||
char err_str[255];
|
char err_str[255];
|
||||||
return HandleStrerrorR(strerror_r(e, err_str, sizeof(err_str)), err_str);
|
#if defined(__ANDROID__) || \
|
||||||
|
(defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)))
|
||||||
|
// Thread safe (GNU-specific)
|
||||||
|
const char* str = strerror_r(e, err_str, sizeof(err_str));
|
||||||
|
return std::string(str);
|
||||||
|
#else
|
||||||
|
// Thread safe (XSI-compliant)
|
||||||
|
int second_err = strerror_r(e, err_str, sizeof(err_str));
|
||||||
|
if (second_err != 0) {
|
||||||
|
return "(strerror_r failed to format error)";
|
||||||
|
}
|
||||||
|
return std::string(err_str);
|
||||||
|
#endif // GLIBC etc.
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/uuid.h"
|
#include "common/uuid.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/registered_cache.h"
|
||||||
#include "core/file_sys/savedata_factory.h"
|
#include "core/file_sys/savedata_factory.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
|
||||||
@@ -61,17 +62,24 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
|||||||
|
|
||||||
SaveDataFactory::~SaveDataFactory() = default;
|
SaveDataFactory::~SaveDataFactory() = default;
|
||||||
|
|
||||||
|
std::string SaveDataFactory::GetSaveDataPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id) const {
|
||||||
|
if (type == SaveDataType::Account || type == SaveDataType::Device) {
|
||||||
|
const auto requested_id = title_id != 0 ? title_id : program_id;
|
||||||
|
const auto parent_id = system.GetContentProvider().GetParentApplicationId(requested_id);
|
||||||
|
title_id = parent_id.value_or(requested_id);
|
||||||
|
}
|
||||||
|
return GetFullPath(program_id, dir, space, type, title_id, user_id, save_id);
|
||||||
|
}
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
const auto save_directory = GetSaveDataPath(space, meta.type, meta.program_id, meta.user_id, meta.system_save_data_id);
|
||||||
meta.user_id, meta.system_save_data_id);
|
|
||||||
|
|
||||||
return dir->CreateDirectoryRelative(save_directory);
|
return dir->CreateDirectoryRelative(save_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
|
|
||||||
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
|
const auto save_directory = GetSaveDataPath(space, meta.type, meta.program_id, meta.user_id, meta.system_save_data_id);
|
||||||
meta.user_id, meta.system_save_data_id);
|
|
||||||
|
|
||||||
auto out = dir->GetDirectoryRelative(save_directory);
|
auto out = dir->GetDirectoryRelative(save_directory);
|
||||||
|
|
||||||
@@ -154,8 +162,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
|
|||||||
|
|
||||||
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||||
u128 user_id) const {
|
u128 user_id) const {
|
||||||
const auto path =
|
const auto path = GetSaveDataPath(SaveDataSpaceId::User, type, title_id, user_id, 0);
|
||||||
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
|
|
||||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
||||||
@@ -173,8 +180,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
|||||||
|
|
||||||
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||||
SaveDataSize new_value) const {
|
SaveDataSize new_value) const {
|
||||||
const auto path =
|
const auto path = GetSaveDataPath(SaveDataSpaceId::User, type, title_id, user_id, 0);
|
||||||
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
|
|
||||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public:
|
|||||||
void SetAutoCreate(bool state);
|
void SetAutoCreate(bool state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string GetSaveDataPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, u128 user_id, u64 save_id) const;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
ProgramId program_id;
|
ProgramId program_id;
|
||||||
VirtualDir dir;
|
VirtualDir dir;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@
|
|||||||
#include "core/hle/service/am/frontend/applet_web_browser.h"
|
#include "core/hle/service/am/frontend/applet_web_browser.h"
|
||||||
#include "core/hle/service/am/frontend/applets.h"
|
#include "core/hle/service/am/frontend/applets.h"
|
||||||
#include "core/hle/service/am/service/storage.h"
|
#include "core/hle/service/am/service/storage.h"
|
||||||
#include "core/hle/service/am/window_system.h"
|
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
|
|
||||||
namespace Service::AM::Frontend {
|
namespace Service::AM::Frontend {
|
||||||
@@ -73,16 +72,10 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
|
|||||||
|
|
||||||
void FrontendApplet::Exit() {
|
void FrontendApplet::Exit() {
|
||||||
auto applet_ = applet.lock();
|
auto applet_ = applet.lock();
|
||||||
{
|
|
||||||
std::scoped_lock lk{applet_->lock};
|
std::scoped_lock lk{applet_->lock};
|
||||||
applet_->is_completed = true;
|
applet_->is_completed = true;
|
||||||
applet_->state_changed_event.Signal(system.Kernel());
|
applet_->state_changed_event.Signal(system.Kernel());
|
||||||
}
|
|
||||||
if (auto caller_applet = applet_->caller_applet.lock()) {
|
|
||||||
std::scoped_lock lk{caller_applet->lock};
|
|
||||||
std::erase(caller_applet->child_applets, applet_);
|
|
||||||
}
|
|
||||||
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) window_system->RequestUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FrontendAppletSet::FrontendAppletSet() = default;
|
FrontendAppletSet::FrontendAppletSet() = default;
|
||||||
|
|||||||
@@ -122,10 +122,7 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
|||||||
auto broker = std::make_shared<AppletDataBroker>(system);
|
auto broker = std::make_shared<AppletDataBroker>(system);
|
||||||
applet->caller_applet = caller_applet;
|
applet->caller_applet = caller_applet;
|
||||||
applet->caller_applet_broker = broker;
|
applet->caller_applet_broker = broker;
|
||||||
{
|
caller_applet->child_applets.push_back(applet);
|
||||||
std::scoped_lock lk{caller_applet->lock};
|
|
||||||
caller_applet->child_applets.push_back(applet);
|
|
||||||
}
|
|
||||||
window_system.TrackApplet(applet, false);
|
window_system.TrackApplet(applet, false);
|
||||||
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
|
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
|
||||||
}
|
}
|
||||||
@@ -151,10 +148,10 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
|
|||||||
applet->caller_applet = caller_applet;
|
applet->caller_applet = caller_applet;
|
||||||
applet->caller_applet_broker = storage;
|
applet->caller_applet_broker = storage;
|
||||||
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
|
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
|
||||||
{
|
caller_applet->child_applets.push_back(applet);
|
||||||
std::scoped_lock lk{caller_applet->lock};
|
|
||||||
caller_applet->child_applets.push_back(applet);
|
window_system.TrackApplet(applet, false);
|
||||||
}
|
|
||||||
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
|
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,66 +23,30 @@
|
|||||||
|
|
||||||
namespace Dynarmic::Backend::Arm64 {
|
namespace Dynarmic::Backend::Arm64 {
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
|
||||||
static void* EmitCallReadTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
|
||||||
using namespace oaknut::util;
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
|
||||||
oaknut::Label l_addr, l_this;
|
|
||||||
void* target = code.xptr<void*>();
|
|
||||||
// params = { this, vaddr, bitsize }
|
|
||||||
code.LDR(X0, l_this);
|
|
||||||
// X1 = vaddr
|
|
||||||
code.MOV(X2, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
|
||||||
code.BR(Xscratch0);
|
|
||||||
code.align(8);
|
|
||||||
code.l(l_this);
|
|
||||||
code.dx(info.this_ptr);
|
|
||||||
code.l(l_addr);
|
|
||||||
code.dx(info.fn_ptr);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
|
||||||
static void* EmitCallWriteTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
|
||||||
using namespace oaknut::util;
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
|
||||||
oaknut::Label l_addr, l_this;
|
|
||||||
void* target = code.xptr<void*>();
|
|
||||||
// params = { this, vaddr, value, bitsize }
|
|
||||||
code.LDR(X0, l_this);
|
|
||||||
// X1 = vaddr
|
|
||||||
// X2 = value
|
|
||||||
code.MOV(X3, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
|
||||||
code.BR(Xscratch0);
|
|
||||||
code.align(8);
|
|
||||||
code.l(l_this);
|
|
||||||
code.dx(info.this_ptr);
|
|
||||||
code.l(l_addr);
|
|
||||||
code.dx(info.fn_ptr);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
template<auto mfp, typename T>
|
||||||
static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
const auto info = Devirtualize<mfp>(this_);
|
||||||
|
|
||||||
oaknut::Label l_addr, l_this;
|
oaknut::Label l_addr, l_this;
|
||||||
|
|
||||||
void* target = code.xptr<void*>();
|
void* target = code.xptr<void*>();
|
||||||
code.LDR(X0, l_this);
|
code.LDR(X0, l_this);
|
||||||
code.LDR(Xscratch0, l_addr);
|
code.LDR(Xscratch0, l_addr);
|
||||||
code.BR(Xscratch0);
|
code.BR(Xscratch0);
|
||||||
|
|
||||||
code.align(8);
|
code.align(8);
|
||||||
code.l(l_this);
|
code.l(l_this);
|
||||||
code.dx(info.this_ptr);
|
code.dx(info.this_ptr);
|
||||||
code.l(l_addr);
|
code.l(l_addr);
|
||||||
code.dx(info.fn_ptr);
|
code.dx(info.fn_ptr);
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
template<auto mfp, typename T>
|
||||||
static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
const auto info = Devirtualize<mfp>(this_);
|
||||||
@@ -95,7 +59,6 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_
|
|||||||
ABI_PushRegisters(code, save_regs, 0);
|
ABI_PushRegisters(code, save_regs, 0);
|
||||||
code.LDR(X0, l_this);
|
code.LDR(X0, l_this);
|
||||||
code.MOV(X1, Xscratch0);
|
code.MOV(X1, Xscratch0);
|
||||||
code.MOV(X2, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
code.LDR(Xscratch0, l_addr);
|
||||||
code.BLR(Xscratch0);
|
code.BLR(Xscratch0);
|
||||||
code.MOV(Xscratch0, X0);
|
code.MOV(Xscratch0, X0);
|
||||||
@@ -138,7 +101,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
template<auto mfp, typename T>
|
||||||
static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
const auto info = Devirtualize<mfp>(this_);
|
||||||
@@ -152,7 +115,6 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this
|
|||||||
code.LDR(X0, l_this);
|
code.LDR(X0, l_this);
|
||||||
code.MOV(X1, Xscratch0);
|
code.MOV(X1, Xscratch0);
|
||||||
code.MOV(X2, Xscratch1);
|
code.MOV(X2, Xscratch1);
|
||||||
code.MOV(X3, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
code.LDR(Xscratch0, l_addr);
|
||||||
code.BLR(Xscratch0);
|
code.BLR(Xscratch0);
|
||||||
ABI_PopRegisters(code, save_regs, 0);
|
ABI_PopRegisters(code, save_regs, 0);
|
||||||
@@ -214,27 +176,14 @@ void A32AddressSpace::EmitPrelude() {
|
|||||||
|
|
||||||
UnprotectCodeMemory();
|
UnprotectCodeMemory();
|
||||||
|
|
||||||
|
prelude_info.read_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_8 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_16 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.read_memory_32 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.read_memory_64 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
|
||||||
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u8>(code, conf);
|
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u8>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u16>(code, conf);
|
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u16>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u32>(code, conf);
|
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u32>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf);
|
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf);
|
||||||
prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
|
prelude_info.write_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
|
|
||||||
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
|
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
|
||||||
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
|
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
|
||||||
prelude_info.exclusive_write_memory_32 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive32, u32>(code, conf);
|
prelude_info.exclusive_write_memory_32 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive32, u32>(code, conf);
|
||||||
|
|||||||
@@ -22,66 +22,30 @@
|
|||||||
|
|
||||||
namespace Dynarmic::Backend::Arm64 {
|
namespace Dynarmic::Backend::Arm64 {
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
|
||||||
static void* EmitCallReadTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
|
||||||
using namespace oaknut::util;
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
|
||||||
oaknut::Label l_addr, l_this;
|
|
||||||
void* target = code.xptr<void*>();
|
|
||||||
// params = { this, vaddr, bitsize }
|
|
||||||
code.LDR(X0, l_this);
|
|
||||||
// X1 = vaddr
|
|
||||||
code.MOV(X2, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
|
||||||
code.BR(Xscratch0);
|
|
||||||
code.align(8);
|
|
||||||
code.l(l_this);
|
|
||||||
code.dx(info.this_ptr);
|
|
||||||
code.l(l_addr);
|
|
||||||
code.dx(info.fn_ptr);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
|
||||||
static void* EmitCallWriteTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
|
||||||
using namespace oaknut::util;
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
|
||||||
oaknut::Label l_addr, l_this;
|
|
||||||
void* target = code.xptr<void*>();
|
|
||||||
// params = { this, vaddr, value, bitsize }
|
|
||||||
code.LDR(X0, l_this);
|
|
||||||
// X1 = vaddr
|
|
||||||
// X2 = value
|
|
||||||
code.MOV(X3, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
|
||||||
code.BR(Xscratch0);
|
|
||||||
code.align(8);
|
|
||||||
code.l(l_this);
|
|
||||||
code.dx(info.this_ptr);
|
|
||||||
code.l(l_addr);
|
|
||||||
code.dx(info.fn_ptr);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
template<auto mfp, typename T>
|
||||||
static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
static void* EmitCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
const auto info = Devirtualize<mfp>(this_);
|
||||||
|
|
||||||
oaknut::Label l_addr, l_this;
|
oaknut::Label l_addr, l_this;
|
||||||
|
|
||||||
void* target = code.xptr<void*>();
|
void* target = code.xptr<void*>();
|
||||||
code.LDR(X0, l_this);
|
code.LDR(X0, l_this);
|
||||||
code.LDR(Xscratch0, l_addr);
|
code.LDR(Xscratch0, l_addr);
|
||||||
code.BR(Xscratch0);
|
code.BR(Xscratch0);
|
||||||
|
|
||||||
code.align(8);
|
code.align(8);
|
||||||
code.l(l_this);
|
code.l(l_this);
|
||||||
code.dx(info.this_ptr);
|
code.dx(info.this_ptr);
|
||||||
code.l(l_addr);
|
code.l(l_addr);
|
||||||
code.dx(info.fn_ptr);
|
code.dx(info.fn_ptr);
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
template<auto mfp, typename T>
|
||||||
static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
const auto info = Devirtualize<mfp>(this_);
|
||||||
@@ -94,7 +58,6 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_
|
|||||||
ABI_PushRegisters(code, save_regs, 0);
|
ABI_PushRegisters(code, save_regs, 0);
|
||||||
code.LDR(X0, l_this);
|
code.LDR(X0, l_this);
|
||||||
code.MOV(X1, Xscratch0);
|
code.MOV(X1, Xscratch0);
|
||||||
code.MOV(X2, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
code.LDR(Xscratch0, l_addr);
|
||||||
code.BLR(Xscratch0);
|
code.BLR(Xscratch0);
|
||||||
code.MOV(Xscratch0, X0);
|
code.MOV(Xscratch0, X0);
|
||||||
@@ -137,7 +100,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<auto mfp, typename T>
|
template<auto mfp, typename T>
|
||||||
static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_, size_t bitsize) {
|
static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this_) {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
const auto info = Devirtualize<mfp>(this_);
|
const auto info = Devirtualize<mfp>(this_);
|
||||||
@@ -151,7 +114,6 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this
|
|||||||
code.LDR(X0, l_this);
|
code.LDR(X0, l_this);
|
||||||
code.MOV(X1, Xscratch0);
|
code.MOV(X1, Xscratch0);
|
||||||
code.MOV(X2, Xscratch1);
|
code.MOV(X2, Xscratch1);
|
||||||
code.MOV(X3, bitsize);
|
|
||||||
code.LDR(Xscratch0, l_addr);
|
code.LDR(Xscratch0, l_addr);
|
||||||
code.BLR(Xscratch0);
|
code.BLR(Xscratch0);
|
||||||
ABI_PopRegisters(code, save_regs, 0);
|
ABI_PopRegisters(code, save_regs, 0);
|
||||||
@@ -380,30 +342,18 @@ void A64AddressSpace::EmitPrelude() {
|
|||||||
|
|
||||||
UnprotectCodeMemory();
|
UnprotectCodeMemory();
|
||||||
|
|
||||||
prelude_info.read_memory_8 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
prelude_info.read_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_16 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.read_memory_32 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.read_memory_64 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.read_memory_128 = EmitRead128CallTrampoline(code, conf.callbacks);
|
prelude_info.read_memory_128 = EmitRead128CallTrampoline(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.wrapped_read_memory_128 = EmitWrappedRead128CallTrampoline(code, conf.callbacks);
|
prelude_info.wrapped_read_memory_128 = EmitWrappedRead128CallTrampoline(code, conf.callbacks);
|
||||||
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u8>(code, conf);
|
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u8>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u16>(code, conf);
|
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u16>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u32>(code, conf);
|
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u32>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u64>(code, conf);
|
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u64>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_128 = EmitExclusiveRead128CallTrampoline(code, conf);
|
prelude_info.exclusive_read_memory_128 = EmitExclusiveRead128CallTrampoline(code, conf);
|
||||||
prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
|
prelude_info.write_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.write_memory_128 = EmitWrite128CallTrampoline(code, conf.callbacks);
|
prelude_info.write_memory_128 = EmitWrite128CallTrampoline(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
|
prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
|
||||||
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
|
||||||
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
|
||||||
prelude_info.wrapped_write_memory_128 = EmitWrappedWrite128CallTrampoline(code, conf.callbacks);
|
prelude_info.wrapped_write_memory_128 = EmitWrappedWrite128CallTrampoline(code, conf.callbacks);
|
||||||
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
|
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
|
||||||
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
|
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
|
||||||
|
|||||||
@@ -147,37 +147,44 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
break;
|
break;
|
||||||
// { this, vaddr, size }
|
// { this, vaddr, size }
|
||||||
case LinkTarget::ReadMemory8:
|
case LinkTarget::ReadMemory8:
|
||||||
c.BL(prelude_info.read_memory_8);
|
c.LDR(X2, 1);
|
||||||
|
c.BL(prelude_info.read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::ReadMemory16:
|
case LinkTarget::ReadMemory16:
|
||||||
c.BL(prelude_info.read_memory_16);
|
c.LDR(X2, 2);
|
||||||
|
c.BL(prelude_info.read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::ReadMemory32:
|
case LinkTarget::ReadMemory32:
|
||||||
c.BL(prelude_info.read_memory_32);
|
c.LDR(X2, 4);
|
||||||
|
c.BL(prelude_info.read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::ReadMemory64:
|
case LinkTarget::ReadMemory64:
|
||||||
c.BL(prelude_info.read_memory_64);
|
c.LDR(X2, 8);
|
||||||
|
c.BL(prelude_info.read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::ReadMemory128:
|
case LinkTarget::ReadMemory128:
|
||||||
c.BL(prelude_info.read_memory_128);
|
c.BL(prelude_info.read_memory_128);
|
||||||
break;
|
break;
|
||||||
// { this, vaddr, size }
|
// { this, vaddr, size }
|
||||||
case LinkTarget::WrappedReadMemory8:
|
case LinkTarget::WrappedReadMemory8:
|
||||||
c.BL(prelude_info.wrapped_read_memory_8);
|
c.LDR(X2, 1);
|
||||||
|
c.BL(prelude_info.wrapped_read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedReadMemory16:
|
case LinkTarget::WrappedReadMemory16:
|
||||||
c.BL(prelude_info.wrapped_read_memory_16);
|
c.LDR(X2, 2);
|
||||||
|
c.BL(prelude_info.wrapped_read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedReadMemory32:
|
case LinkTarget::WrappedReadMemory32:
|
||||||
c.BL(prelude_info.wrapped_read_memory_32);
|
c.LDR(X2, 4);
|
||||||
|
c.BL(prelude_info.wrapped_read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedReadMemory64:
|
case LinkTarget::WrappedReadMemory64:
|
||||||
c.BL(prelude_info.wrapped_read_memory_64);
|
c.LDR(X2, 8);
|
||||||
|
c.BL(prelude_info.wrapped_read_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedReadMemory128:
|
case LinkTarget::WrappedReadMemory128:
|
||||||
c.BL(prelude_info.wrapped_read_memory_128);
|
c.BL(prelude_info.wrapped_read_memory_128);
|
||||||
break;
|
break;
|
||||||
//
|
|
||||||
case LinkTarget::ExclusiveReadMemory8:
|
case LinkTarget::ExclusiveReadMemory8:
|
||||||
c.BL(prelude_info.exclusive_read_memory_8);
|
c.BL(prelude_info.exclusive_read_memory_8);
|
||||||
break;
|
break;
|
||||||
@@ -195,37 +202,43 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
break;
|
break;
|
||||||
// { this, vaddr, value, size }
|
// { this, vaddr, value, size }
|
||||||
case LinkTarget::WriteMemory8:
|
case LinkTarget::WriteMemory8:
|
||||||
c.BL(prelude_info.write_memory_8);
|
c.LDR(X3, 1);
|
||||||
|
c.BL(prelude_info.write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WriteMemory16:
|
case LinkTarget::WriteMemory16:
|
||||||
c.BL(prelude_info.write_memory_16);
|
c.LDR(X3, 2);
|
||||||
|
c.BL(prelude_info.write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WriteMemory32:
|
case LinkTarget::WriteMemory32:
|
||||||
c.BL(prelude_info.write_memory_32);
|
c.LDR(X3, 4);
|
||||||
|
c.BL(prelude_info.write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WriteMemory64:
|
case LinkTarget::WriteMemory64:
|
||||||
c.BL(prelude_info.write_memory_64);
|
c.LDR(X3, 8);
|
||||||
|
c.BL(prelude_info.write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WriteMemory128:
|
case LinkTarget::WriteMemory128:
|
||||||
c.BL(prelude_info.write_memory_128);
|
c.BL(prelude_info.write_memory_128);
|
||||||
break;
|
break;
|
||||||
//
|
|
||||||
case LinkTarget::WrappedWriteMemory8:
|
case LinkTarget::WrappedWriteMemory8:
|
||||||
c.BL(prelude_info.wrapped_write_memory_8);
|
c.LDR(X3, 1);
|
||||||
|
c.BL(prelude_info.wrapped_write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedWriteMemory16:
|
case LinkTarget::WrappedWriteMemory16:
|
||||||
c.BL(prelude_info.wrapped_write_memory_16);
|
c.LDR(X3, 2);
|
||||||
|
c.BL(prelude_info.wrapped_write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedWriteMemory32:
|
case LinkTarget::WrappedWriteMemory32:
|
||||||
c.BL(prelude_info.wrapped_write_memory_32);
|
c.LDR(X3, 4);
|
||||||
|
c.BL(prelude_info.wrapped_write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedWriteMemory64:
|
case LinkTarget::WrappedWriteMemory64:
|
||||||
c.BL(prelude_info.wrapped_write_memory_64);
|
c.LDR(X3, 8);
|
||||||
|
c.BL(prelude_info.wrapped_write_memory);
|
||||||
break;
|
break;
|
||||||
case LinkTarget::WrappedWriteMemory128:
|
case LinkTarget::WrappedWriteMemory128:
|
||||||
c.BL(prelude_info.wrapped_write_memory_128);
|
c.BL(prelude_info.wrapped_write_memory_128);
|
||||||
break;
|
break;
|
||||||
//
|
|
||||||
case LinkTarget::ExclusiveWriteMemory8:
|
case LinkTarget::ExclusiveWriteMemory8:
|
||||||
c.BL(prelude_info.exclusive_write_memory_8);
|
c.BL(prelude_info.exclusive_write_memory_8);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -93,30 +93,18 @@ protected:
|
|||||||
void* return_to_dispatcher;
|
void* return_to_dispatcher;
|
||||||
void* return_from_run_code;
|
void* return_from_run_code;
|
||||||
|
|
||||||
void* read_memory_8;
|
void* read_memory;
|
||||||
void* read_memory_16;
|
|
||||||
void* read_memory_32;
|
|
||||||
void* read_memory_64;
|
|
||||||
void* read_memory_128;
|
void* read_memory_128;
|
||||||
void* wrapped_read_memory_8;
|
void* wrapped_read_memory;
|
||||||
void* wrapped_read_memory_16;
|
|
||||||
void* wrapped_read_memory_32;
|
|
||||||
void* wrapped_read_memory_64;
|
|
||||||
void* wrapped_read_memory_128;
|
void* wrapped_read_memory_128;
|
||||||
void* exclusive_read_memory_8;
|
void* exclusive_read_memory_8;
|
||||||
void* exclusive_read_memory_16;
|
void* exclusive_read_memory_16;
|
||||||
void* exclusive_read_memory_32;
|
void* exclusive_read_memory_32;
|
||||||
void* exclusive_read_memory_64;
|
void* exclusive_read_memory_64;
|
||||||
void* exclusive_read_memory_128;
|
void* exclusive_read_memory_128;
|
||||||
void* write_memory_8;
|
void* write_memory;
|
||||||
void* write_memory_16;
|
|
||||||
void* write_memory_32;
|
|
||||||
void* write_memory_64;
|
|
||||||
void* write_memory_128;
|
void* write_memory_128;
|
||||||
void* wrapped_write_memory_8;
|
void* wrapped_write_memory;
|
||||||
void* wrapped_write_memory_16;
|
|
||||||
void* wrapped_write_memory_32;
|
|
||||||
void* wrapped_write_memory_64;
|
|
||||||
void* wrapped_write_memory_128;
|
void* wrapped_write_memory_128;
|
||||||
void* exclusive_write_memory_8;
|
void* exclusive_write_memory_8;
|
||||||
void* exclusive_write_memory_16;
|
void* exclusive_write_memory_16;
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include "common/logging.h"
|
||||||
#include <fmt/ostream.h>
|
|
||||||
#include "dynarmic/mcl/integer_of_size.hpp"
|
#include "dynarmic/mcl/integer_of_size.hpp"
|
||||||
#include "dynarmic/backend/x64/xbyak.h"
|
#include "dynarmic/backend/x64/xbyak.h"
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include "common/logging.h"
|
||||||
#include <fmt/ostream.h>
|
|
||||||
#include "dynarmic/mcl/integer_of_size.hpp"
|
#include "dynarmic/mcl/integer_of_size.hpp"
|
||||||
#include "dynarmic/backend/x64/xbyak.h"
|
#include "dynarmic/backend/x64/xbyak.h"
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,6 @@
|
|||||||
#define AxxJitState CONCATENATE_TOKENS(Axx, JitState)
|
#define AxxJitState CONCATENATE_TOKENS(Axx, JitState)
|
||||||
#define AxxUserConfig Axx::UserConfig
|
#define AxxUserConfig Axx::UserConfig
|
||||||
|
|
||||||
namespace {
|
|
||||||
using Vector = std::array<u64, 2>;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitContext& ctx, IR::Inst* inst) const {
|
std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitContext& ctx, IR::Inst* inst) const {
|
||||||
if (!conf.fastmem_pointer || !exception_handler.SupportsFastmem()) {
|
if (!conf.fastmem_pointer || !exception_handler.SupportsFastmem()) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -31,22 +27,19 @@ std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitC
|
|||||||
}
|
}
|
||||||
|
|
||||||
FakeCall AxxEmitX64::FastmemCallback(u64 rip_) {
|
FakeCall AxxEmitX64::FastmemCallback(u64 rip_) {
|
||||||
const auto iter = fastmem_patch_info.find(rip_);
|
if (auto const it = fastmem_patch_info.find(rip_); it != fastmem_patch_info.end()) {
|
||||||
if (iter != fastmem_patch_info.end()) {
|
|
||||||
FakeCall result{
|
FakeCall result{
|
||||||
.call_rip = iter->second.callback,
|
.call_rip = it->second.callback,
|
||||||
.ret_rip = iter->second.resume_rip,
|
.ret_rip = it->second.resume_rip,
|
||||||
};
|
};
|
||||||
if (iter->second.recompile) {
|
if (it->second.recompile) {
|
||||||
const auto marker = iter->second.marker;
|
const auto marker = it->second.marker;
|
||||||
do_not_fastmem.insert(marker);
|
do_not_fastmem.insert(marker);
|
||||||
InvalidateBasicBlocks({std::get<0>(marker)});
|
InvalidateBasicBlocks({std::get<0>(marker)});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
fmt::print("dynarmic: Segfault happened within JITted code at rip = {:016x}\n"
|
UNREACHABLE_MSG("SIGSEGV @ JIT, rip={:#016x}", rip_); //("iter != fastmem_patch_info.end()");
|
||||||
"Segfault wasn't at a fastmem patch location!\n", rip_);
|
|
||||||
UNREACHABLE(); //("iter != fastmem_patch_info.end()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t bitsize, auto callback>
|
template<std::size_t bitsize, auto callback>
|
||||||
@@ -83,22 +76,17 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
|
|
||||||
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]);
|
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]);
|
||||||
const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm(code).getIdx() : ctx.reg_alloc.ScratchGpr(code).getIdx();
|
const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm(code).getIdx() : ctx.reg_alloc.ScratchGpr(code).getIdx();
|
||||||
|
|
||||||
const auto wrapped_fn = read_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
|
const auto wrapped_fn = read_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
|
||||||
|
|
||||||
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||||
|
|
||||||
if (fastmem_marker) {
|
if (fastmem_marker) {
|
||||||
// Use fastmem
|
// Use fastmem
|
||||||
bool require_abort_handling = false;
|
bool require_abort_handling = false;
|
||||||
const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
|
const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
|
||||||
|
|
||||||
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
|
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
|
||||||
|
|
||||||
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
||||||
code.L(*abort);
|
code.L(*abort);
|
||||||
code.call(wrapped_fn);
|
code.call(wrapped_fn);
|
||||||
|
|
||||||
fastmem_patch_info.emplace(
|
fastmem_patch_info.emplace(
|
||||||
std::bit_cast<u64>(location),
|
std::bit_cast<u64>(location),
|
||||||
FastmemPatchInfo{
|
FastmemPatchInfo{
|
||||||
@@ -107,25 +95,23 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
*fastmem_marker,
|
*fastmem_marker,
|
||||||
conf.recompile_on_fastmem_failure,
|
conf.recompile_on_fastmem_failure,
|
||||||
});
|
});
|
||||||
|
|
||||||
EmitCheckMemoryAbort(ctx, inst, end);
|
EmitCheckMemoryAbort(ctx, inst, end);
|
||||||
code.jmp(*end, code.T_NEAR);
|
code.jmp(*end, code.T_NEAR);
|
||||||
});
|
});
|
||||||
} else {
|
} else if (conf.page_table) {
|
||||||
// Use page table
|
// Use page table
|
||||||
ASSERT(conf.page_table);
|
|
||||||
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
|
const auto src_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
|
||||||
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
|
EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
|
||||||
|
|
||||||
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
||||||
code.L(*abort);
|
code.L(*abort);
|
||||||
code.call(wrapped_fn);
|
code.call(wrapped_fn);
|
||||||
EmitCheckMemoryAbort(ctx, inst, end);
|
EmitCheckMemoryAbort(ctx, inst, end);
|
||||||
code.jmp(*end, code.T_NEAR);
|
code.jmp(*end, code.T_NEAR);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
code.L(*end);
|
code.L(*end);
|
||||||
|
|
||||||
if constexpr (bitsize == 128) {
|
if constexpr (bitsize == 128) {
|
||||||
ctx.reg_alloc.DefineValue(code, inst, Xbyak::Xmm{value_idx});
|
ctx.reg_alloc.DefineValue(code, inst, Xbyak::Xmm{value_idx});
|
||||||
} else {
|
} else {
|
||||||
@@ -168,18 +154,16 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
|
|
||||||
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]);
|
const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(code, args[1]);
|
||||||
const int value_idx = bitsize == 128
|
const int value_idx = bitsize == 128
|
||||||
? ctx.reg_alloc.UseXmm(code, args[2]).getIdx()
|
? ctx.reg_alloc.UseXmm(code, args[2]).getIdx()
|
||||||
: (ordered ? ctx.reg_alloc.UseScratchGpr(code, args[2]).getIdx() : ctx.reg_alloc.UseGpr(code, args[2]).getIdx());
|
: (ordered ? ctx.reg_alloc.UseScratchGpr(code, args[2]).getIdx() : ctx.reg_alloc.UseGpr(code, args[2]).getIdx());
|
||||||
|
|
||||||
const auto wrapped_fn = write_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
|
const auto wrapped_fn = write_fallbacks[std::make_tuple(ordered, bitsize, vaddr.getIdx(), value_idx)];
|
||||||
|
|
||||||
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
SharedLabel abort = ctx.GenSharedLabel(), end = ctx.GenSharedLabel();
|
||||||
|
|
||||||
if (fastmem_marker) {
|
if (fastmem_marker) {
|
||||||
// Use fastmem
|
// Use fastmem
|
||||||
bool require_abort_handling = false;
|
bool require_abort_handling = false;
|
||||||
const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
|
const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling);
|
||||||
|
|
||||||
const auto location = EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
|
const auto location = EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
|
||||||
|
|
||||||
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
ctx.deferred_emits.emplace_back([=, this, &ctx] {
|
||||||
@@ -198,9 +182,8 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
EmitCheckMemoryAbort(ctx, inst, end);
|
EmitCheckMemoryAbort(ctx, inst, end);
|
||||||
code.jmp(*end, code.T_NEAR);
|
code.jmp(*end, code.T_NEAR);
|
||||||
});
|
});
|
||||||
} else {
|
} else if (conf.page_table) {
|
||||||
// Use page table
|
// Use page table
|
||||||
ASSERT(conf.page_table);
|
|
||||||
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
|
const auto dest_ptr = EmitVAddrLookup(code, ctx, bitsize, *abort, vaddr);
|
||||||
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
|
EmitWriteMemoryMov<bitsize>(code, dest_ptr, value_idx, ordered);
|
||||||
|
|
||||||
@@ -210,6 +193,8 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
EmitCheckMemoryAbort(ctx, inst, end);
|
EmitCheckMemoryAbort(ctx, inst, end);
|
||||||
code.jmp(*end, code.T_NEAR);
|
code.jmp(*end, code.T_NEAR);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
code.L(*end);
|
code.L(*end);
|
||||||
}
|
}
|
||||||
@@ -249,8 +234,8 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
if (ordered) {
|
if (ordered) {
|
||||||
code.mfence();
|
code.mfence();
|
||||||
}
|
}
|
||||||
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& ret) {
|
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, u128& ret) {
|
||||||
ret = conf.global_monitor->ReadAndMark<Vector>(conf.processor_id, vaddr, [&]() -> Vector {
|
ret = conf.global_monitor->ReadAndMark<u128>(conf.processor_id, vaddr, [&]() -> u128 {
|
||||||
return (conf.callbacks->*callback)(vaddr);
|
return (conf.callbacks->*callback)(vaddr);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -301,8 +286,8 @@ void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
ctx.reg_alloc.AllocStackSpace(code, 16 + ABI_SHADOW_SPACE);
|
ctx.reg_alloc.AllocStackSpace(code, 16 + ABI_SHADOW_SPACE);
|
||||||
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
|
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
|
||||||
code.movaps(xword[code.ABI_PARAM3], xmm1);
|
code.movaps(xword[code.ABI_PARAM3], xmm1);
|
||||||
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& value) -> u32 {
|
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, u128& value) -> u32 {
|
||||||
return conf.global_monitor->DoExclusiveOperation<Vector>(conf.processor_id, vaddr, [&](Vector expected) -> bool {
|
return conf.global_monitor->DoExclusiveOperation<u128>(conf.processor_id, vaddr, [&](u128 expected) -> bool {
|
||||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||||
}) ? 0 : 1;
|
}) ? 0 : 1;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -135,10 +135,16 @@ template<>
|
|||||||
if (unused_top_bits == 0) {
|
if (unused_top_bits == 0) {
|
||||||
code.mov(tmp, vaddr);
|
code.mov(tmp, vaddr);
|
||||||
code.shr(tmp, int(page_table_const_bits));
|
code.shr(tmp, int(page_table_const_bits));
|
||||||
|
if (ctx.conf.page_table_log2_stride > 3) {
|
||||||
|
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
|
||||||
|
code.mov(page, qword[r14 + tmp.cvt64()]);
|
||||||
|
} else {
|
||||||
|
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
|
||||||
|
}
|
||||||
} else if (ctx.conf.silently_mirror_page_table) {
|
} else if (ctx.conf.silently_mirror_page_table) {
|
||||||
if (valid_page_index_bits >= 32) {
|
if (valid_page_index_bits >= 32) {
|
||||||
if (code.HasHostFeature(HostFeature::BMI2)) {
|
if (code.HasHostFeature(HostFeature::BMI2)) {
|
||||||
const Xbyak::Reg64 bit_count = ctx.reg_alloc.ScratchGpr(code);
|
auto const bit_count = ctx.reg_alloc.ScratchGpr(code);
|
||||||
code.mov(bit_count, unused_top_bits);
|
code.mov(bit_count, unused_top_bits);
|
||||||
code.bzhi(tmp, vaddr, bit_count);
|
code.bzhi(tmp, vaddr, bit_count);
|
||||||
code.shr(tmp, int(page_table_const_bits));
|
code.shr(tmp, int(page_table_const_bits));
|
||||||
@@ -153,19 +159,31 @@ template<>
|
|||||||
code.shr(tmp, int(page_table_const_bits));
|
code.shr(tmp, int(page_table_const_bits));
|
||||||
code.and_(tmp, u32((1 << valid_page_index_bits) - 1));
|
code.and_(tmp, u32((1 << valid_page_index_bits) - 1));
|
||||||
}
|
}
|
||||||
|
if (ctx.conf.page_table_log2_stride > 3) {
|
||||||
|
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
|
||||||
|
code.mov(page, qword[r14 + tmp.cvt64()]);
|
||||||
|
} else {
|
||||||
|
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Common VA sizes: 39 - 12 => 27, 42 - 12 => 30
|
||||||
|
// Check if bits outside of VA space are non-zero
|
||||||
ASSERT(valid_page_index_bits < 32);
|
ASSERT(valid_page_index_bits < 32);
|
||||||
code.mov(tmp, vaddr);
|
code.mov(tmp, vaddr);
|
||||||
|
if (ctx.conf.check_halt_on_memory_access) {
|
||||||
|
auto const tmp2 = ctx.reg_alloc.ScratchGpr(code);
|
||||||
|
code.mov(tmp2, u64(-(1ull << valid_page_index_bits) << page_table_const_bits));
|
||||||
|
code.test(tmp, tmp2);
|
||||||
|
code.jnz(abort, code.T_NEAR);
|
||||||
|
ctx.reg_alloc.Release(tmp2);
|
||||||
|
}
|
||||||
code.shr(tmp, int(page_table_const_bits));
|
code.shr(tmp, int(page_table_const_bits));
|
||||||
code.test(tmp, u32(-(1 << valid_page_index_bits)));
|
if (ctx.conf.page_table_log2_stride > 3) {
|
||||||
code.jnz(abort, code.T_NEAR);
|
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
|
||||||
}
|
code.mov(page, qword[r14 + tmp.cvt64()]);
|
||||||
|
} else {
|
||||||
if (ctx.conf.page_table_log2_stride > 3) {
|
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
|
||||||
code.shl(tmp, int(ctx.conf.page_table_log2_stride));
|
}
|
||||||
code.mov(page, qword[r14 + tmp.cvt64()]);
|
|
||||||
} else {
|
|
||||||
code.mov(page, qword[r14 + tmp.cvt64() * int(1 << ctx.conf.page_table_log2_stride)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for marked bit, use as unmapped if marked
|
// check for marked bit, use as unmapped if marked
|
||||||
@@ -193,7 +211,7 @@ template<>
|
|||||||
return page + vaddr;
|
return page + vaddr;
|
||||||
}
|
}
|
||||||
code.mov(tmp, vaddr);
|
code.mov(tmp, vaddr);
|
||||||
code.and_(tmp, static_cast<u32>(page_table_const_mask));
|
code.and_(tmp, u32(page_table_const_mask));
|
||||||
return page + tmp;
|
return page + tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user