mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-21 17:55:38 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4045f418e8 | |||
| c3bf576df1 | |||
| 710c97dea8 |
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 -->
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ add_library(
|
|||||||
cityhash.h
|
cityhash.h
|
||||||
common_funcs.h
|
common_funcs.h
|
||||||
common_types.h
|
common_types.h
|
||||||
concepts.h
|
|
||||||
container_hash.h
|
container_hash.h
|
||||||
demangle.cpp
|
demangle.cpp
|
||||||
demangle.h
|
demangle.h
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
// Check if type satisfies the ContiguousContainer named requirement.
|
|
||||||
template <typename T>
|
|
||||||
concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
|
|
||||||
|
|
||||||
} // namespace Common
|
|
||||||
@@ -244,8 +244,7 @@ WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept
|
|||||||
, ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0}
|
, ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0}
|
||||||
, us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0}
|
, us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0}
|
||||||
, ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0}
|
, ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0}
|
||||||
, rdtsc_ns_integer{invariant_ ? rdtsc_frequency_ / NsRatio::den : 1}
|
, rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_, NsRatio::den) : 1}
|
||||||
, rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_ % NsRatio::den, NsRatio::den) : 0}
|
|
||||||
, cntpct_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_) : 0}
|
, cntpct_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_) : 0}
|
||||||
, gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0}
|
, gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0}
|
||||||
, invariant{invariant_}
|
, invariant{invariant_}
|
||||||
@@ -292,7 +291,7 @@ bool WallClock::IsNative() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
|
u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
|
||||||
return ns.count() * rdtsc_ns_integer + MultiplyHigh(ns.count(), rdtsc_ns_factor);
|
return invariant ? MultiplyHigh(ns.count(), rdtsc_ns_factor) : ns.count();
|
||||||
}
|
}
|
||||||
#elif defined(HAS_NCE)
|
#elif defined(HAS_NCE)
|
||||||
namespace {
|
namespace {
|
||||||
@@ -417,7 +416,7 @@ u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
|
|||||||
const WallClock g_wall_clock = [] {
|
const WallClock g_wall_clock = [] {
|
||||||
#if defined(ARCHITECTURE_x86_64)
|
#if defined(ARCHITECTURE_x86_64)
|
||||||
auto const& caps = Common::g_cpu_caps;
|
auto const& caps = Common::g_cpu_caps;
|
||||||
return WallClock(caps.invariant_tsc && caps.tsc_frequency > std::nano::den, caps.tsc_frequency);
|
return WallClock(caps.invariant_tsc && caps.tsc_frequency >= std::nano::den, caps.tsc_frequency);
|
||||||
#elif defined(HAS_NCE)
|
#elif defined(HAS_NCE)
|
||||||
return WallClock(false, 1);
|
return WallClock(false, 1);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ public:
|
|||||||
u64 ns_rdtsc_factor;
|
u64 ns_rdtsc_factor;
|
||||||
u64 us_rdtsc_factor;
|
u64 us_rdtsc_factor;
|
||||||
u64 ms_rdtsc_factor;
|
u64 ms_rdtsc_factor;
|
||||||
u64 rdtsc_ns_integer;
|
|
||||||
u64 rdtsc_ns_factor;
|
u64 rdtsc_ns_factor;
|
||||||
u64 cntpct_rdtsc_factor;
|
u64 cntpct_rdtsc_factor;
|
||||||
u64 gputick_rdtsc_factor;
|
u64 gputick_rdtsc_factor;
|
||||||
|
|||||||
+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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2015 Evan Teran
|
// SPDX-FileCopyrightText: 2015 Evan Teran
|
||||||
@@ -15,8 +15,6 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include <common/concepts.h>
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
// No equivalent for "std::arithmetic" in the stdlib
|
// No equivalent for "std::arithmetic" in the stdlib
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "common/concepts.h"
|
|
||||||
#include "common/fs/fs_types.h"
|
#include "common/fs/fs_types.h"
|
||||||
#include "common/fs/fs_util.h"
|
#include "common/fs/fs_util.h"
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function which deduces the value type of a contiguous STL container used in ReadSpan.
|
* Helper function which deduces the value type of a contiguous STL container used in ReadSpan.
|
||||||
* If T is not a contiguous container as defined by the concept IsContiguousContainer, this
|
* If T is not a contiguous container as defined by the concept, this
|
||||||
* calls ReadObject and T must be a trivially copyable object.
|
* calls ReadObject and T must be a trivially copyable object.
|
||||||
*
|
*
|
||||||
* See ReadSpan for more details if T is a contiguous container.
|
* See ReadSpan for more details if T is a contiguous container.
|
||||||
@@ -226,7 +226,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
[[nodiscard]] size_t Read(T& data) const {
|
[[nodiscard]] size_t Read(T& data) const {
|
||||||
if constexpr (IsContiguousContainer<T>) {
|
if constexpr (std::contiguous_iterator<typename T::iterator>) {
|
||||||
using ContiguousType = typename T::value_type;
|
using ContiguousType = typename T::value_type;
|
||||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||||
"Data type must be trivially copyable.");
|
"Data type must be trivially copyable.");
|
||||||
@@ -238,7 +238,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function which deduces the value type of a contiguous STL container used in WriteSpan.
|
* Helper function which deduces the value type of a contiguous STL container used in WriteSpan.
|
||||||
* If T is not a contiguous STL container as defined by the concept IsContiguousContainer, this
|
* If T is not a contiguous STL container as defined by the concept, this
|
||||||
* calls WriteObject and T must be a trivially copyable object.
|
* calls WriteObject and T must be a trivially copyable object.
|
||||||
*
|
*
|
||||||
* See WriteSpan for more details if T is a contiguous container.
|
* See WriteSpan for more details if T is a contiguous container.
|
||||||
@@ -252,7 +252,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
[[nodiscard]] size_t Write(const T& data) const {
|
[[nodiscard]] size_t Write(const T& data) const {
|
||||||
if constexpr (IsContiguousContainer<T>) {
|
if constexpr (std::contiguous_iterator<typename T::iterator>) {
|
||||||
using ContiguousType = typename T::value_type;
|
using ContiguousType = typename T::value_type;
|
||||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||||
"Data type must be trivially copyable.");
|
"Data type must be trivially copyable.");
|
||||||
|
|||||||
@@ -22,15 +22,21 @@ DynarmicCallbacks32::DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess
|
|||||||
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
u64 DynarmicCallbacks32::MemoryRead(u32 vaddr, size_t size) {
|
u8 DynarmicCallbacks32::MemoryRead8(u32 vaddr) {
|
||||||
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
||||||
switch (size) {
|
return m_memory.Read8(vaddr);
|
||||||
case sizeof(u64): return m_memory.Read64(vaddr);
|
}
|
||||||
case sizeof(u32): return m_memory.Read32(vaddr);
|
u16 DynarmicCallbacks32::MemoryRead16(u32 vaddr) {
|
||||||
case sizeof(u16): return m_memory.Read16(vaddr);
|
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
|
||||||
case sizeof(u8): return m_memory.Read8(vaddr);
|
return m_memory.Read16(vaddr);
|
||||||
default: UNREACHABLE();
|
}
|
||||||
}
|
u32 DynarmicCallbacks32::MemoryRead32(u32 vaddr) {
|
||||||
|
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
|
||||||
|
return m_memory.Read32(vaddr);
|
||||||
|
}
|
||||||
|
u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
|
||||||
|
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||||
|
return m_memory.Read64(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||||
@@ -44,17 +50,27 @@ std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
|||||||
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks32::MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) {
|
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
||||||
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
|
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
||||||
switch (size) {
|
m_memory.Write8(vaddr, value);
|
||||||
case sizeof(u64): return m_memory.Write64(vaddr, value);
|
|
||||||
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
|
|
||||||
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
|
|
||||||
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
|
|
||||||
default: UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void DynarmicCallbacks32::MemoryWrite16(u32 vaddr, u16 value) {
|
||||||
|
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
|
||||||
|
m_memory.Write16(vaddr, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DynarmicCallbacks32::MemoryWrite32(u32 vaddr, u32 value) {
|
||||||
|
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
|
||||||
|
m_memory.Write32(vaddr, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DynarmicCallbacks32::MemoryWrite64(u32 vaddr, u64 value) {
|
||||||
|
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
|
||||||
|
m_memory.Write64(vaddr, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
|
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
|
||||||
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
|
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
|
||||||
m_memory.WriteExclusive8(vaddr, value, expected);
|
m_memory.WriteExclusive8(vaddr, value, expected);
|
||||||
|
|||||||
@@ -30,12 +30,18 @@ class System;
|
|||||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
|
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
|
||||||
u64 MemoryRead(u32 vaddr, size_t size) override;
|
u8 MemoryRead8(u32 vaddr) override;
|
||||||
|
u16 MemoryRead16(u32 vaddr) override;
|
||||||
|
u32 MemoryRead32(u32 vaddr) override;
|
||||||
|
u64 MemoryRead64(u32 vaddr) override;
|
||||||
std::optional<u32> MemoryReadCode(u32 vaddr) override;
|
std::optional<u32> MemoryReadCode(u32 vaddr) override;
|
||||||
void InstructionSynchronizationBarrierRaised() override {
|
void InstructionSynchronizationBarrierRaised() override {
|
||||||
last_code_addr = u64(-1); //reset back, force refetch
|
last_code_addr = u64(-1); //reset back, force refetch
|
||||||
}
|
}
|
||||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override;
|
void MemoryWrite8(u32 vaddr, u8 value) override;
|
||||||
|
void MemoryWrite16(u32 vaddr, u16 value) override;
|
||||||
|
void MemoryWrite32(u32 vaddr, u32 value) override;
|
||||||
|
void MemoryWrite64(u32 vaddr, u64 value) override;
|
||||||
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
|
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
|
||||||
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
|
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
|
||||||
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
|
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@@ -22,15 +21,21 @@ DynarmicCallbacks64::DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess
|
|||||||
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
u64 DynarmicCallbacks64::MemoryRead(u64 vaddr, size_t size) {
|
u8 DynarmicCallbacks64::MemoryRead8(u64 vaddr) {
|
||||||
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
|
||||||
switch (size) {
|
return m_memory.Read8(vaddr);
|
||||||
case sizeof(u64): return m_memory.Read64(vaddr);
|
}
|
||||||
case sizeof(u32): return m_memory.Read32(vaddr);
|
u16 DynarmicCallbacks64::MemoryRead16(u64 vaddr) {
|
||||||
case sizeof(u16): return m_memory.Read16(vaddr);
|
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
|
||||||
case sizeof(u8): return m_memory.Read8(vaddr);
|
return m_memory.Read16(vaddr);
|
||||||
default: UNREACHABLE();
|
}
|
||||||
}
|
u32 DynarmicCallbacks64::MemoryRead32(u64 vaddr) {
|
||||||
|
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
|
||||||
|
return m_memory.Read32(vaddr);
|
||||||
|
}
|
||||||
|
u64 DynarmicCallbacks64::MemoryRead64(u64 vaddr) {
|
||||||
|
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||||
|
return m_memory.Read64(vaddr);
|
||||||
}
|
}
|
||||||
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
||||||
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
||||||
@@ -48,15 +53,24 @@ std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
|||||||
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks64::MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) {
|
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
||||||
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
|
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
|
||||||
switch (size) {
|
m_memory.Write8(vaddr, value);
|
||||||
case sizeof(u64): return m_memory.Write64(vaddr, u64(value));
|
}
|
||||||
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
|
}
|
||||||
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
|
void DynarmicCallbacks64::MemoryWrite16(u64 vaddr, u16 value) {
|
||||||
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
|
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
|
||||||
default: UNREACHABLE();
|
m_memory.Write16(vaddr, value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
void DynarmicCallbacks64::MemoryWrite32(u64 vaddr, u32 value) {
|
||||||
|
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
|
||||||
|
m_memory.Write32(vaddr, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DynarmicCallbacks64::MemoryWrite64(u64 vaddr, u64 value) {
|
||||||
|
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
|
||||||
|
m_memory.Write64(vaddr, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
|
void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
class Memory;
|
class Memory;
|
||||||
@@ -37,13 +36,19 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
|||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
|
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
|
||||||
|
|
||||||
u64 MemoryRead(u64 vaddr, size_t size) override;
|
u8 MemoryRead8(u64 vaddr) override;
|
||||||
|
u16 MemoryRead16(u64 vaddr) override;
|
||||||
|
u32 MemoryRead32(u64 vaddr) override;
|
||||||
|
u64 MemoryRead64(u64 vaddr) override;
|
||||||
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
|
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
|
||||||
std::optional<u32> MemoryReadCode(u64 vaddr) override;
|
std::optional<u32> MemoryReadCode(u64 vaddr) override;
|
||||||
void InstructionSynchronizationBarrierRaised() override {
|
void InstructionSynchronizationBarrierRaised() override {
|
||||||
last_code_addr = u64(-1); //reset back, force refetch
|
last_code_addr = u64(-1); //reset back, force refetch
|
||||||
}
|
}
|
||||||
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) override;
|
void MemoryWrite8(u64 vaddr, u8 value) override;
|
||||||
|
void MemoryWrite16(u64 vaddr, u16 value) override;
|
||||||
|
void MemoryWrite32(u64 vaddr, u32 value) override;
|
||||||
|
void MemoryWrite64(u64 vaddr, u64 value) override;
|
||||||
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override;
|
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override;
|
||||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override;
|
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override;
|
||||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override;
|
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/hex_util.h"
|
#include "common/hex_util.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
@@ -157,15 +156,12 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64
|
|||||||
NACP nacp{nacp_file};
|
NACP nacp{nacp_file};
|
||||||
return nacp.GetVersionString();
|
return nacp.GetVersionString();
|
||||||
}
|
}
|
||||||
YUZU_NO_INLINE std::optional<u64> GetParentApplicationId(const ContentProvider* provider, u64 title_id) {
|
|
||||||
return provider == nullptr ? std::nullopt : provider->GetParentApplicationId(title_id);
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
PatchManager::PatchManager(u64 title_id_,
|
PatchManager::PatchManager(u64 title_id_,
|
||||||
const Service::FileSystem::FileSystemController& fs_controller_,
|
const Service::FileSystem::FileSystemController& fs_controller_,
|
||||||
const ContentProvider& content_provider_)
|
const ContentProvider& content_provider_)
|
||||||
: title_id{title_id_}, parent_title_id{GetParentApplicationId(std::addressof(content_provider_), title_id_)}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
|
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
|
||||||
|
|
||||||
PatchManager::~PatchManager() = default;
|
PatchManager::~PatchManager() = default;
|
||||||
|
|
||||||
@@ -173,35 +169,13 @@ u64 PatchManager::GetTitleID() const {
|
|||||||
return title_id;
|
return title_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualDir PatchManager::GetModificationLoadRoot(bool sdmc) const {
|
|
||||||
const auto get_root = [&](u64 id) {
|
|
||||||
return sdmc ? fs_controller.GetSDMCModificationLoadRoot(id) : fs_controller.GetModificationLoadRoot(id);
|
|
||||||
};
|
|
||||||
auto root = get_root(title_id);
|
|
||||||
if (!parent_title_id) {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
std::vector<VirtualDir> roots{std::move(root), get_root(*parent_title_id)};
|
|
||||||
std::erase(roots, nullptr);
|
|
||||||
return LayeredVfsDirectory::MakeLayeredDirectory(std::move(roots));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> PatchManager::GetDisabledAddons() const {
|
|
||||||
auto disabled = Settings::values.disabled_addons[title_id];
|
|
||||||
if (parent_title_id) {
|
|
||||||
const auto& shared = Settings::values.disabled_addons[*parent_title_id];
|
|
||||||
disabled.insert(disabled.end(), shared.begin(), shared.end());
|
|
||||||
}
|
|
||||||
return disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||||
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
|
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
|
||||||
|
|
||||||
if (exefs == nullptr)
|
if (exefs == nullptr)
|
||||||
return exefs;
|
return exefs;
|
||||||
|
|
||||||
const auto disabled = GetDisabledAddons();
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
|
|
||||||
bool update_disabled = true;
|
bool update_disabled = true;
|
||||||
std::optional<u32> enabled_version;
|
std::optional<u32> enabled_version;
|
||||||
@@ -329,8 +303,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LayeredExeFS
|
// LayeredExeFS
|
||||||
const auto load_dir = GetModificationLoadRoot();
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||||
const auto sdmc_load_dir = GetModificationLoadRoot(true);
|
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
|
||||||
|
|
||||||
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
|
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
|
||||||
if (load_dir != nullptr) {
|
if (load_dir != nullptr) {
|
||||||
@@ -372,7 +346,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const {
|
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const {
|
||||||
const auto disabled = GetDisabledAddons();
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
const auto nso_build_id = fmt::format("{:0<64}", build_id);
|
const auto nso_build_id = fmt::format("{:0<64}", build_id);
|
||||||
|
|
||||||
std::vector<VirtualFile> out;
|
std::vector<VirtualFile> out;
|
||||||
@@ -431,7 +405,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
|||||||
|
|
||||||
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
|
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
|
||||||
|
|
||||||
const auto load_dir = GetModificationLoadRoot();
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||||
return nso;
|
return nso;
|
||||||
@@ -474,7 +448,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
|
|||||||
|
|
||||||
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
|
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
|
||||||
|
|
||||||
const auto load_dir = GetModificationLoadRoot();
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||||
return false;
|
return false;
|
||||||
@@ -488,13 +462,13 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
||||||
const auto load_dir = GetModificationLoadRoot();
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||||
if (load_dir == nullptr) {
|
if (load_dir == nullptr) {
|
||||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto disabled = GetDisabledAddons();
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
auto patch_dirs = load_dir->GetSubdirectories();
|
auto patch_dirs = load_dir->GetSubdirectories();
|
||||||
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
|
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
|
||||||
|
|
||||||
@@ -528,16 +502,17 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatchManager::ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const {
|
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
|
||||||
const auto load_dir = GetModificationLoadRoot();
|
const Service::FileSystem::FileSystemController& fs_controller) {
|
||||||
const auto sdmc_load_dir = GetModificationLoadRoot(true);
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||||
|
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
|
||||||
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
|
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
|
||||||
type != ContentRecordType::HtmlDocument) ||
|
type != ContentRecordType::HtmlDocument) ||
|
||||||
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
|
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto disabled = GetDisabledAddons();
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
|
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
|
||||||
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
|
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
|
||||||
patch_dirs.push_back(sdmc_load_dir);
|
patch_dirs.push_back(sdmc_load_dir);
|
||||||
@@ -616,7 +591,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
|||||||
|
|
||||||
// Game Updates
|
// Game Updates
|
||||||
const auto update_tid = GetUpdateTitleID(title_id);
|
const auto update_tid = GetUpdateTitleID(title_id);
|
||||||
const auto disabled = GetDisabledAddons();
|
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||||
|
|
||||||
bool update_disabled = true;
|
bool update_disabled = true;
|
||||||
std::optional<u32> enabled_version;
|
std::optional<u32> enabled_version;
|
||||||
@@ -723,7 +698,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
|||||||
|
|
||||||
// LayeredFS
|
// LayeredFS
|
||||||
if (apply_layeredfs) {
|
if (apply_layeredfs) {
|
||||||
ApplyLayeredFS(romfs, type);
|
ApplyLayeredFS(romfs, title_id, type, fs_controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
return romfs;
|
return romfs;
|
||||||
@@ -1097,22 +1072,15 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||||||
std::optional<u32> PatchManager::GetGameVersion() const {
|
std::optional<u32> PatchManager::GetGameVersion() const {
|
||||||
const auto update_tid = GetUpdateTitleID(title_id);
|
const auto update_tid = GetUpdateTitleID(title_id);
|
||||||
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
|
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
|
||||||
const auto version = content_provider.GetEntryVersion(update_tid);
|
return content_provider.GetEntryVersion(update_tid);
|
||||||
return version || !parent_title_id ? version : content_provider.GetEntryVersion(GetUpdateTitleID(*parent_title_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto version = content_provider.GetEntryVersion(title_id);
|
return content_provider.GetEntryVersion(title_id);
|
||||||
return version || !parent_title_id ? version : content_provider.GetEntryVersion(*parent_title_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchManager::Metadata PatchManager::GetControlMetadata() const {
|
PatchManager::Metadata PatchManager::GetControlMetadata() const {
|
||||||
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
|
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
|
||||||
if (base_control_nca == nullptr) {
|
if (base_control_nca == nullptr) {
|
||||||
if (parent_title_id) {
|
|
||||||
const auto control_id = content_provider.HasEntry(*parent_title_id, ContentRecordType::Control) ? *parent_title_id : GetUpdateTitleID(*parent_title_id);
|
|
||||||
const PatchManager parent{control_id, fs_controller, content_provider};
|
|
||||||
return parent.GetControlMetadata();
|
|
||||||
}
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,14 +109,10 @@ public:
|
|||||||
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
|
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] VirtualDir GetModificationLoadRoot(bool sdmc = false) const;
|
|
||||||
[[nodiscard]] std::vector<std::string> GetDisabledAddons() const;
|
|
||||||
void ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const;
|
|
||||||
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
||||||
const std::string& build_id) const;
|
const std::string& build_id) const;
|
||||||
|
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
std::optional<u64> parent_title_id;
|
|
||||||
const Service::FileSystem::FileSystemController& fs_controller;
|
const Service::FileSystem::FileSystemController& fs_controller;
|
||||||
const ContentProvider& content_provider;
|
const ContentProvider& content_provider;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
@@ -349,22 +348,6 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
|
|||||||
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
|
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u64> ContentProvider::GetParentApplicationId(u64 program_id) const {
|
|
||||||
const auto application_id = GetBaseTitleID(program_id);
|
|
||||||
const auto program_index = program_id - application_id;
|
|
||||||
if (program_index == 0 || program_index > std::numeric_limits<u8>::max()) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
if (!ListEntriesFilter(TitleType::Application, ContentRecordType::Meta, program_id).empty()) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
if ((!ListEntriesFilter(TitleType::Application, ContentRecordType::Meta, application_id).empty() && HasEntry(program_id, ContentRecordType::Program))
|
|
||||||
|| (!ListEntriesFilter(TitleType::Update, ContentRecordType::Meta, GetUpdateTitleID(application_id)).empty() && HasEntry(GetUpdateTitleID(program_id), ContentRecordType::Program))) {
|
|
||||||
return application_id;
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
|
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
|
||||||
|
|
||||||
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
||||||
|
|||||||
@@ -100,8 +100,6 @@ public:
|
|||||||
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
||||||
std::optional<u64> title_id = {}) const = 0;
|
std::optional<u64> title_id = {}) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] std::optional<u64> GetParentApplicationId(u64 program_id) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// A single instance of KeyManager to be used by GetEntry()
|
// A single instance of KeyManager to be used by GetEntry()
|
||||||
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
|
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -92,13 +92,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestFocusStateChangedNotification(Kernel::KernelCore& kernel) {
|
|
||||||
if (m_focus_state_changed_notification_enabled) {
|
|
||||||
m_has_focus_state_changed = true;
|
|
||||||
this->SignalSystemEventIfNeeded(kernel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnOperationAndPerformanceModeChanged(Kernel::KernelCore& kernel);
|
void OnOperationAndPerformanceModeChanged(Kernel::KernelCore& kernel);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -164,15 +164,15 @@ Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
|
|||||||
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
|
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get()));
|
|
||||||
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
|
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
|
||||||
std::scoped_lock lk{caller_applet->lock};
|
caller_applet->lifecycle_manager.GetSystemEvent().Signal(system.Kernel());
|
||||||
const bool focus_state_changed = caller_applet->lifecycle_manager.UpdateRequestedFocusState();
|
caller_applet->lifecycle_manager.RequestResumeNotification();
|
||||||
const bool is_front_app = m_applet->frontend && caller_applet->lifecycle_manager.IsApplication();
|
caller_applet->lifecycle_manager.GetSystemEvent().Clear(system.Kernel());
|
||||||
if (focus_state_changed) caller_applet->lifecycle_manager.SignalSystemEventIfNeeded(system.Kernel());
|
caller_applet->lifecycle_manager.UpdateRequestedFocusState();
|
||||||
else if (is_front_app) caller_applet->lifecycle_manager.RequestFocusStateChangedNotification(system.Kernel());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get()));
|
||||||
|
|
||||||
if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) {
|
if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) {
|
||||||
auto impl = (*out_storage)->GetImpl();
|
auto impl = (*out_storage)->GetImpl();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
|||||||
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
||||||
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
||||||
{549, nullptr, "GetConnectableRegisteredDevices"},
|
{549, nullptr, "GetConnectableRegisteredDevices"},
|
||||||
{551, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+ //mocked via 548 for Diablo 3 (at least)
|
{551, nullptr, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+
|
||||||
{700, nullptr, "ActivateUniquePad"},
|
{700, nullptr, "ActivateUniquePad"},
|
||||||
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
||||||
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
||||||
@@ -758,7 +758,7 @@ void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLEReque
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_HID, "(STUBBED) called, command={}", ctx.GetCommand()); //548 or 551
|
LOG_WARNING(Service_HID, "(STUBBED) called");
|
||||||
|
|
||||||
struct RegisterData {
|
struct RegisterData {
|
||||||
std::array<u8, 0x68> data;
|
std::array<u8, 0x68> data;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -18,7 +19,6 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/concepts.h"
|
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/k_handle_table.h"
|
#include "core/hle/kernel/k_handle_table.h"
|
||||||
@@ -292,18 +292,20 @@ public:
|
|||||||
* @param data The container/data to write into a buffer.
|
* @param data The container/data to write into a buffer.
|
||||||
* @param buffer_index The buffer in particular to write to.
|
* @param buffer_index The buffer in particular to write to.
|
||||||
*/
|
*/
|
||||||
template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
|
template <typename T>
|
||||||
|
requires (!std::is_pointer_v<T>
|
||||||
|
&& std::contiguous_iterator<typename T::iterator>)
|
||||||
std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
|
std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
|
||||||
if constexpr (Common::IsContiguousContainer<T>) {
|
using C = typename T::value_type;
|
||||||
using ContiguousType = typename T::value_type;
|
static_assert(std::is_trivially_copyable_v<C>, "Container to WriteBuffer must contain trivially copyable objects");
|
||||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
return WriteBuffer(std::data(data), std::size(data) * sizeof(C), buffer_index);
|
||||||
"Container to WriteBuffer must contain trivially copyable objects");
|
}
|
||||||
return WriteBuffer(std::data(data), std::size(data) * sizeof(ContiguousType),
|
template <typename T>
|
||||||
buffer_index);
|
requires (!std::is_pointer_v<T>
|
||||||
} else {
|
&& !std::contiguous_iterator<typename T::iterator>)
|
||||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
|
||||||
return WriteBuffer(&data, sizeof(T), buffer_index);
|
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||||
}
|
return WriteBuffer(&data, sizeof(T), buffer_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to get the size of the input buffer
|
/// Helper function to get the size of the input buffer
|
||||||
|
|||||||
@@ -71,14 +71,17 @@ public:
|
|||||||
void InstructionSynchronizationBarrierRaised() override {
|
void InstructionSynchronizationBarrierRaised() override {
|
||||||
last_code_addr = u64(-1); //reset back, force refetch
|
last_code_addr = u64(-1); //reset back, force refetch
|
||||||
}
|
}
|
||||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
u8 MemoryRead8(u64 vaddr) override {
|
||||||
switch (size) {
|
return ReadMemory<u8>(vaddr);
|
||||||
case sizeof(u64): return ReadMemory<u64>(vaddr);
|
}
|
||||||
case sizeof(u32): return ReadMemory<u32>(vaddr);
|
u16 MemoryRead16(u64 vaddr) override {
|
||||||
case sizeof(u16): return ReadMemory<u16>(vaddr);
|
return ReadMemory<u16>(vaddr);
|
||||||
case sizeof(u8): return ReadMemory<u8>(vaddr);
|
}
|
||||||
default: UNREACHABLE();
|
u32 MemoryRead32(u64 vaddr) override {
|
||||||
}
|
return ReadMemory<u32>(vaddr);
|
||||||
|
}
|
||||||
|
u64 MemoryRead64(u64 vaddr) override {
|
||||||
|
return ReadMemory<u64>(vaddr);
|
||||||
}
|
}
|
||||||
u128 MemoryRead128(u64 vaddr) override {
|
u128 MemoryRead128(u64 vaddr) override {
|
||||||
return ReadMemory<u128>(vaddr);
|
return ReadMemory<u128>(vaddr);
|
||||||
@@ -86,19 +89,22 @@ public:
|
|||||||
std::string MemoryReadCString(u64 vaddr) {
|
std::string MemoryReadCString(u64 vaddr) {
|
||||||
std::string result{};
|
std::string result{};
|
||||||
u8 next;
|
u8 next;
|
||||||
while ((next = u8(MemoryRead(vaddr++, sizeof(u8)))) != 0)
|
while ((next = MemoryRead8(vaddr++)) != 0)
|
||||||
result += char(next);
|
result += char(next);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(u64 vaddr, u64 value, size_t size) override {
|
void MemoryWrite8(u64 vaddr, u8 value) override {
|
||||||
switch (size) {
|
WriteMemory<u8>(vaddr, value);
|
||||||
case sizeof(u64): WriteMemory<u64>(vaddr, u64(value)); break;
|
}
|
||||||
case sizeof(u32): WriteMemory<u32>(vaddr, u32(value)); break;
|
void MemoryWrite16(u64 vaddr, u16 value) override {
|
||||||
case sizeof(u16): WriteMemory<u16>(vaddr, u16(value)); break;
|
WriteMemory<u16>(vaddr, value);
|
||||||
case sizeof(u8): WriteMemory<u8>(vaddr, u8(value)); break;
|
}
|
||||||
default: UNREACHABLE();
|
void MemoryWrite32(u64 vaddr, u32 value) override {
|
||||||
}
|
WriteMemory<u32>(vaddr, value);
|
||||||
|
}
|
||||||
|
void MemoryWrite64(u64 vaddr, u64 value) override {
|
||||||
|
WriteMemory<u64>(vaddr, value);
|
||||||
}
|
}
|
||||||
void MemoryWrite128(u64 vaddr, u128 value) override {
|
void MemoryWrite128(u64 vaddr, u128 value) override {
|
||||||
WriteMemory<u128>(vaddr, value);
|
WriteMemory<u128>(vaddr, value);
|
||||||
@@ -187,14 +193,14 @@ public:
|
|||||||
// The loaded NRO file has ELF relocations that must be processed before it can run.
|
// The loaded NRO file has ELF relocations that must be processed before it can run.
|
||||||
// Normally this would be processed by RTLD, but in HLE context, we don't have
|
// Normally this would be processed by RTLD, but in HLE context, we don't have
|
||||||
// the linker available, so we have to do it ourselves.
|
// the linker available, so we have to do it ourselves.
|
||||||
const VAddr mod_offset{callbacks->MemoryRead(4, sizeof(u32))};
|
const VAddr mod_offset{callbacks->MemoryRead32(4)};
|
||||||
if (callbacks->MemoryRead(mod_offset, sizeof(u32)) != Common::MakeMagic('M', 'O', 'D', '0'))
|
if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// For more info about dynamic entries, see the ELF ABI specification:
|
// For more info about dynamic entries, see the ELF ABI specification:
|
||||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
|
||||||
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
|
||||||
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead(mod_offset + 4, sizeof(u32))};
|
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)};
|
||||||
VAddr rela_dyn = 0, relr_dyn = 0;
|
VAddr rela_dyn = 0, relr_dyn = 0;
|
||||||
size_t num_rela = 0, num_relr = 0;
|
size_t num_rela = 0, num_relr = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -216,8 +222,8 @@ public:
|
|||||||
for (size_t i = 0; i < num_rela; i++) {
|
for (size_t i = 0; i < num_rela; i++) {
|
||||||
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
||||||
if (Elf64RelType(rela.r_info) == ElfAArch64Relative) {
|
if (Elf64RelType(rela.r_info) == ElfAArch64Relative) {
|
||||||
const VAddr contents{callbacks->MemoryRead(rela.r_offset, sizeof(u64))};
|
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};
|
||||||
callbacks->MemoryWrite(rela.r_offset, contents + rela.r_addend, sizeof(u64));
|
callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +231,7 @@ public:
|
|||||||
for (size_t i = 0; i < num_relr; i++) {
|
for (size_t i = 0; i < num_relr; i++) {
|
||||||
const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr));
|
const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr));
|
||||||
const auto incr = [&](VAddr where) {
|
const auto incr = [&](VAddr where) {
|
||||||
callbacks->MemoryWrite(where, callbacks->MemoryRead(where, sizeof(u64)) + relocbase, sizeof(u64));
|
callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase);
|
||||||
};
|
};
|
||||||
if ((relr & 1) == 0) {
|
if ((relr & 1) == 0) {
|
||||||
// where pointer
|
// where pointer
|
||||||
@@ -288,7 +294,7 @@ public:
|
|||||||
if (argument_stack.size() > 8) {
|
if (argument_stack.size() > 8) {
|
||||||
const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN);
|
const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN);
|
||||||
for (size_t i = 8; i < argument_stack.size(); i++)
|
for (size_t i = 8; i < argument_stack.size(); i++)
|
||||||
callbacks->MemoryWrite(new_sp + (i - 8) * sizeof(u64), argument_stack[i], sizeof(u64));
|
callbacks->MemoryWrite64(new_sp + (i - 8) * sizeof(u64), argument_stack[i]);
|
||||||
jit->SetSP(new_sp);
|
jit->SetSP(new_sp);
|
||||||
}
|
}
|
||||||
// Reset the call state for the next invocation
|
// Reset the call state for the next invocation
|
||||||
@@ -379,17 +385,17 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
|
|||||||
|
|
||||||
if (dest < src) {
|
if (dest < src) {
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
MemoryWrite(dest + i, u8(MemoryRead(src + i, sizeof(u8))), sizeof(u8));
|
MemoryWrite8(dest + i, MemoryRead8(src + i));
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = n; i > 0; i--)
|
for (size_t i = n; i > 0; i--)
|
||||||
MemoryWrite(dest + i - 1, u8(MemoryRead(src + i - 1, sizeof(u8))), sizeof(u8));
|
MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1));
|
||||||
}
|
}
|
||||||
} else if (pc == parent.helpers[size_t(HelperFn::Memset)]) {
|
} else if (pc == parent.helpers[size_t(HelperFn::Memset)]) {
|
||||||
const VAddr dest{parent.jit->GetRegister(0)};
|
const VAddr dest{parent.jit->GetRegister(0)};
|
||||||
const u64 c{parent.jit->GetRegister(1)};
|
const u64 c{parent.jit->GetRegister(1)};
|
||||||
const size_t n{parent.jit->GetRegister(2)};
|
const size_t n{parent.jit->GetRegister(2)};
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
MemoryWrite(dest + i, u8(c), sizeof(u8));
|
MemoryWrite8(dest + i, u8(c));
|
||||||
} else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) {
|
} else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) {
|
||||||
// X0 contains a char* for a symbol to resolve
|
// X0 contains a char* for a symbol to resolve
|
||||||
const auto name{MemoryReadCString(parent.jit->GetRegister(0))};
|
const auto name{MemoryReadCString(parent.jit->GetRegister(0))};
|
||||||
@@ -416,7 +422,7 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) {
|
void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) {
|
||||||
auto const inst = MemoryRead(pc, sizeof(u32));
|
auto const inst = MemoryRead32(pc);
|
||||||
LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst);
|
LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst);
|
||||||
parent.jit->HaltExecution();
|
parent.jit->HaltExecution();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/concepts.h"
|
|
||||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||||
|
|
||||||
namespace Service::Nvidia::Devices {
|
namespace Service::Nvidia::Devices {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "common/concepts.h"
|
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
|||||||
@@ -33,10 +33,18 @@ u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) {
|
|||||||
|
|
||||||
void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
|
void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 value) {
|
||||||
switch (width) {
|
switch (width) {
|
||||||
case sizeof(u64): return memory.Write64(addr, value);
|
case 1:
|
||||||
case sizeof(u32): return memory.Write32(addr, u32(value));
|
memory.Write8(addr, static_cast<u8>(value));
|
||||||
case sizeof(u16): return memory.Write16(addr, u16(value));
|
break;
|
||||||
case sizeof(u8): return memory.Write8(addr, u8(value));
|
case 2:
|
||||||
|
memory.Write16(addr, static_cast<u16>(value));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
memory.Write32(addr, static_cast<u32>(value));
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
memory.Write64(addr, value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -119,7 +82,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
|
|||||||
|
|
||||||
auto fn = [](const A32::UserConfig& conf, A32::VAddr vaddr) -> T {
|
auto fn = [](const A32::UserConfig& conf, A32::VAddr vaddr) -> T {
|
||||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||||
return (conf.callbacks->*callback)(vaddr, sizeof(T));
|
return (conf.callbacks->*callback)(vaddr);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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);
|
||||||
@@ -174,9 +136,12 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
|
|||||||
oaknut::Label l_addr, l_this;
|
oaknut::Label l_addr, l_this;
|
||||||
|
|
||||||
auto fn = [](const A32::UserConfig& conf, A32::VAddr vaddr, T value) -> u32 {
|
auto fn = [](const A32::UserConfig& conf, A32::VAddr vaddr, T value) -> u32 {
|
||||||
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr, [&](T expected) -> bool {
|
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr,
|
||||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
[&](T expected) -> bool {
|
||||||
}) ? 0 : 1;
|
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||||
|
})
|
||||||
|
? 0
|
||||||
|
: 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void* target = code.xptr<void*>();
|
void* target = code.xptr<void*>();
|
||||||
@@ -214,27 +179,26 @@ void A32AddressSpace::EmitPrelude() {
|
|||||||
|
|
||||||
UnprotectCodeMemory();
|
UnprotectCodeMemory();
|
||||||
|
|
||||||
|
prelude_info.read_memory_8 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_8 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
prelude_info.read_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_16 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
prelude_info.read_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_32 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
prelude_info.read_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_64 = EmitCallReadTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead8, 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::MemoryRead16, 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::MemoryRead32, 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::MemoryRead64, u64>(code, conf);
|
||||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf);
|
prelude_info.write_memory_8 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_8 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
|
prelude_info.write_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
prelude_info.write_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
prelude_info.write_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u8));
|
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||||
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);
|
||||||
@@ -118,7 +81,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
|
|||||||
|
|
||||||
auto fn = [](const A64::UserConfig& conf, A64::VAddr vaddr) -> T {
|
auto fn = [](const A64::UserConfig& conf, A64::VAddr vaddr) -> T {
|
||||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||||
return (conf.callbacks->*callback)(vaddr, sizeof(T));
|
return (conf.callbacks->*callback)(vaddr);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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);
|
||||||
@@ -171,10 +133,14 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
|
|||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
oaknut::Label l_addr, l_this;
|
oaknut::Label l_addr, l_this;
|
||||||
|
|
||||||
auto fn = [](const A64::UserConfig& conf, A64::VAddr vaddr, T value) -> u32 {
|
auto fn = [](const A64::UserConfig& conf, A64::VAddr vaddr, T value) -> u32 {
|
||||||
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr, [&](T expected) -> bool {
|
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr,
|
||||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
[&](T expected) -> bool {
|
||||||
}) ? 0 : 1;
|
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||||
|
})
|
||||||
|
? 0
|
||||||
|
: 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
void* target = code.xptr<void*>();
|
void* target = code.xptr<void*>();
|
||||||
@@ -380,30 +346,30 @@ void A64AddressSpace::EmitPrelude() {
|
|||||||
|
|
||||||
UnprotectCodeMemory();
|
UnprotectCodeMemory();
|
||||||
|
|
||||||
prelude_info.read_memory_8 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u8));
|
prelude_info.read_memory_8 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_16 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
prelude_info.read_memory_16 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_32 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
prelude_info.read_memory_32 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||||
prelude_info.read_memory_64 = EmitCallReadTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
prelude_info.read_memory_64 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||||
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_8 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u16));
|
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u32));
|
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks, sizeof(u64));
|
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||||
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::MemoryRead8, 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::MemoryRead16, 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::MemoryRead32, 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::MemoryRead64, 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_8 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_16 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
prelude_info.write_memory_16 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_32 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
prelude_info.write_memory_32 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||||
prelude_info.write_memory_64 = EmitCallWriteTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
prelude_info.write_memory_64 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||||
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_8 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u16));
|
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u32));
|
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||||
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks, sizeof(u64));
|
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||||
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);
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
case LinkTarget::ReturnFromRunCode:
|
case LinkTarget::ReturnFromRunCode:
|
||||||
c.B(prelude_info.return_from_run_code);
|
c.B(prelude_info.return_from_run_code);
|
||||||
break;
|
break;
|
||||||
// { this, vaddr, size }
|
|
||||||
case LinkTarget::ReadMemory8:
|
case LinkTarget::ReadMemory8:
|
||||||
c.BL(prelude_info.read_memory_8);
|
c.BL(prelude_info.read_memory_8);
|
||||||
break;
|
break;
|
||||||
@@ -161,7 +160,6 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
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 }
|
|
||||||
case LinkTarget::WrappedReadMemory8:
|
case LinkTarget::WrappedReadMemory8:
|
||||||
c.BL(prelude_info.wrapped_read_memory_8);
|
c.BL(prelude_info.wrapped_read_memory_8);
|
||||||
break;
|
break;
|
||||||
@@ -177,7 +175,6 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
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;
|
||||||
@@ -193,7 +190,6 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
case LinkTarget::ExclusiveReadMemory128:
|
case LinkTarget::ExclusiveReadMemory128:
|
||||||
c.BL(prelude_info.exclusive_read_memory_128);
|
c.BL(prelude_info.exclusive_read_memory_128);
|
||||||
break;
|
break;
|
||||||
// { this, vaddr, value, size }
|
|
||||||
case LinkTarget::WriteMemory8:
|
case LinkTarget::WriteMemory8:
|
||||||
c.BL(prelude_info.write_memory_8);
|
c.BL(prelude_info.write_memory_8);
|
||||||
break;
|
break;
|
||||||
@@ -209,7 +205,6 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
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.BL(prelude_info.wrapped_write_memory_8);
|
||||||
break;
|
break;
|
||||||
@@ -225,7 +220,6 @@ void AddressSpace::Link(EmittedBlockInfo& block_info) {
|
|||||||
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;
|
||||||
|
|||||||
@@ -31,16 +31,16 @@ using namespace Xbyak::util;
|
|||||||
void A32EmitX64::GenFastmemFallbacks() {
|
void A32EmitX64::GenFastmemFallbacks() {
|
||||||
const std::initializer_list<int> idxes{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
|
const std::initializer_list<int> idxes{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
|
||||||
const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
|
const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
|
||||||
{8, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{8, Devirtualize<&A32::UserCallbacks::MemoryRead8>(conf.callbacks)},
|
||||||
{16, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{16, Devirtualize<&A32::UserCallbacks::MemoryRead16>(conf.callbacks)},
|
||||||
{32, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{32, Devirtualize<&A32::UserCallbacks::MemoryRead32>(conf.callbacks)},
|
||||||
{64, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{64, Devirtualize<&A32::UserCallbacks::MemoryRead64>(conf.callbacks)},
|
||||||
}};
|
}};
|
||||||
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
|
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
|
||||||
{8, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{8, Devirtualize<&A32::UserCallbacks::MemoryWrite8>(conf.callbacks)},
|
||||||
{16, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{16, Devirtualize<&A32::UserCallbacks::MemoryWrite16>(conf.callbacks)},
|
||||||
{32, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{32, Devirtualize<&A32::UserCallbacks::MemoryWrite32>(conf.callbacks)},
|
||||||
{64, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{64, Devirtualize<&A32::UserCallbacks::MemoryWrite64>(conf.callbacks)},
|
||||||
}};
|
}};
|
||||||
const std::array<std::pair<size_t, ArgCallback>, 4> exclusive_write_callbacks{{
|
const std::array<std::pair<size_t, ArgCallback>, 4> exclusive_write_callbacks{{
|
||||||
{8, Devirtualize<&A32::UserCallbacks::MemoryWriteExclusive8>(conf.callbacks)},
|
{8, Devirtualize<&A32::UserCallbacks::MemoryWriteExclusive8>(conf.callbacks)},
|
||||||
@@ -56,12 +56,12 @@ void A32EmitX64::GenFastmemFallbacks() {
|
|||||||
code.align();
|
code.align();
|
||||||
read_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
read_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||||
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
|
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
|
||||||
// params = { this, vaddr, size }
|
|
||||||
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
|
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
|
||||||
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
|
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
|
||||||
}
|
}
|
||||||
code.mov(code.ABI_PARAM3, bitsize / CHAR_BIT);
|
if (ordered) {
|
||||||
if (ordered) code.mfence();
|
code.mfence();
|
||||||
|
}
|
||||||
callback.EmitCall(code);
|
callback.EmitCall(code);
|
||||||
if (value_idx != code.ABI_RETURN.getIdx()) {
|
if (value_idx != code.ABI_RETURN.getIdx()) {
|
||||||
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
|
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
|
||||||
@@ -76,7 +76,6 @@ void A32EmitX64::GenFastmemFallbacks() {
|
|||||||
code.align();
|
code.align();
|
||||||
write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||||
ABI_PushCallerSaveRegistersAndAdjustStack(code);
|
ABI_PushCallerSaveRegistersAndAdjustStack(code);
|
||||||
// params = { this, vaddr, value, size }
|
|
||||||
if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
|
if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
|
||||||
code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
|
code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||||
} else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
|
} else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
|
||||||
@@ -93,9 +92,10 @@ void A32EmitX64::GenFastmemFallbacks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
code.ZeroExtendFrom(bitsize, code.ABI_PARAM3);
|
code.ZeroExtendFrom(bitsize, code.ABI_PARAM3);
|
||||||
code.mov(code.ABI_PARAM4, bitsize / CHAR_BIT);
|
|
||||||
callback.EmitCall(code);
|
callback.EmitCall(code);
|
||||||
if (ordered) code.mfence();
|
if (ordered) {
|
||||||
|
code.mfence();
|
||||||
|
}
|
||||||
ABI_PopCallerSaveRegistersAndAdjustStack(code);
|
ABI_PopCallerSaveRegistersAndAdjustStack(code);
|
||||||
code.ret();
|
code.ret();
|
||||||
PerfMapRegister(write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a32_write_fallback_{}", bitsize));
|
PerfMapRegister(write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a32_write_fallback_{}", bitsize));
|
||||||
@@ -138,35 +138,35 @@ void A32EmitX64::GenFastmemFallbacks() {
|
|||||||
#undef Axx
|
#undef Axx
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<8, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<8, &A32::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<16, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<16, &A32::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<32, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<32, &A32::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<64, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<64, &A32::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32WriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32WriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<8, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<8, &A32::UserCallbacks::MemoryWrite8>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32WriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32WriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<16, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<16, &A32::UserCallbacks::MemoryWrite16>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32WriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32WriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<32, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<32, &A32::UserCallbacks::MemoryWrite32>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<64, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<64, &A32::UserCallbacks::MemoryWrite64>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) {
|
void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) {
|
||||||
@@ -175,33 +175,33 @@ void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) {
|
|||||||
|
|
||||||
void A32EmitX64::EmitA32ExclusiveReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ExclusiveReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<8, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<8, &A32::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<8, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<8, &A32::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ExclusiveReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ExclusiveReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<16, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<16, &A32::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<16, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<16, &A32::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ExclusiveReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ExclusiveReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<32, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<32, &A32::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<32, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<32, &A32::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void A32EmitX64::EmitA32ExclusiveReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
void A32EmitX64::EmitA32ExclusiveReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<64, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<64, &A32::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<64, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<64, &A32::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,16 +115,16 @@ void A64EmitX64::GenMemory128Accessors() {
|
|||||||
void A64EmitX64::GenFastmemFallbacks() {
|
void A64EmitX64::GenFastmemFallbacks() {
|
||||||
const std::initializer_list<int> idxes{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
const std::initializer_list<int> idxes{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||||
const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
|
const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
|
||||||
{8, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{8, Devirtualize<&A64::UserCallbacks::MemoryRead8>(conf.callbacks)},
|
||||||
{16, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{16, Devirtualize<&A64::UserCallbacks::MemoryRead16>(conf.callbacks)},
|
||||||
{32, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{32, Devirtualize<&A64::UserCallbacks::MemoryRead32>(conf.callbacks)},
|
||||||
{64, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
{64, Devirtualize<&A64::UserCallbacks::MemoryRead64>(conf.callbacks)},
|
||||||
}};
|
}};
|
||||||
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
|
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
|
||||||
{8, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{8, Devirtualize<&A64::UserCallbacks::MemoryWrite8>(conf.callbacks)},
|
||||||
{16, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{16, Devirtualize<&A64::UserCallbacks::MemoryWrite16>(conf.callbacks)},
|
||||||
{32, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{32, Devirtualize<&A64::UserCallbacks::MemoryWrite32>(conf.callbacks)},
|
||||||
{64, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
{64, Devirtualize<&A64::UserCallbacks::MemoryWrite64>(conf.callbacks)},
|
||||||
}};
|
}};
|
||||||
const std::array<std::pair<size_t, ArgCallback>, 4> exclusive_write_callbacks{{
|
const std::array<std::pair<size_t, ArgCallback>, 4> exclusive_write_callbacks{{
|
||||||
{8, Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive8>(conf.callbacks)},
|
{8, Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive8>(conf.callbacks)},
|
||||||
@@ -204,12 +204,12 @@ void A64EmitX64::GenFastmemFallbacks() {
|
|||||||
code.align();
|
code.align();
|
||||||
read_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
read_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||||
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
|
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
|
||||||
// params = { this, vaddr, size }
|
|
||||||
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
|
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
|
||||||
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
|
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
|
||||||
}
|
}
|
||||||
code.mov(code.ABI_PARAM3, bitsize / CHAR_BIT);
|
if (ordered) {
|
||||||
if (ordered) code.mfence();
|
code.mfence();
|
||||||
|
}
|
||||||
callback.EmitCall(code);
|
callback.EmitCall(code);
|
||||||
if (value_idx != code.ABI_RETURN.getIdx()) {
|
if (value_idx != code.ABI_RETURN.getIdx()) {
|
||||||
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
|
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
|
||||||
@@ -224,7 +224,6 @@ void A64EmitX64::GenFastmemFallbacks() {
|
|||||||
code.align();
|
code.align();
|
||||||
write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||||
ABI_PushCallerSaveRegistersAndAdjustStack(code);
|
ABI_PushCallerSaveRegistersAndAdjustStack(code);
|
||||||
// params = { this, vaddr, value, size }
|
|
||||||
if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
|
if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
|
||||||
code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
|
code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||||
} else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
|
} else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
|
||||||
@@ -241,9 +240,10 @@ void A64EmitX64::GenFastmemFallbacks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
code.ZeroExtendFrom(bitsize, code.ABI_PARAM3);
|
code.ZeroExtendFrom(bitsize, code.ABI_PARAM3);
|
||||||
code.mov(code.ABI_PARAM4, bitsize / CHAR_BIT);
|
|
||||||
callback.EmitCall(code);
|
callback.EmitCall(code);
|
||||||
if (ordered) code.mfence();
|
if (ordered) {
|
||||||
|
code.mfence();
|
||||||
|
}
|
||||||
ABI_PopCallerSaveRegistersAndAdjustStack(code);
|
ABI_PopCallerSaveRegistersAndAdjustStack(code);
|
||||||
code.ret();
|
code.ret();
|
||||||
PerfMapRegister(write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a64_write_fallback_{}", bitsize));
|
PerfMapRegister(write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a64_write_fallback_{}", bitsize));
|
||||||
@@ -286,19 +286,19 @@ void A64EmitX64::GenFastmemFallbacks() {
|
|||||||
#undef Axx
|
#undef Axx
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<8, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<16, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<16, &A64::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<32, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<32, &A64::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryRead<64, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitMemoryRead<64, &A64::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
@@ -306,23 +306,23 @@ void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<8, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<8, &A64::UserCallbacks::MemoryWrite8>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<16, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<16, &A64::UserCallbacks::MemoryWrite16>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<32, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<32, &A64::UserCallbacks::MemoryWrite32>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<64, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<64, &A64::UserCallbacks::MemoryWrite64>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
EmitMemoryWrite<128, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
EmitMemoryWrite<128, &A64::UserCallbacks::MemoryWrite64>(ctx, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) {
|
void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) {
|
||||||
@@ -331,33 +331,33 @@ void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) {
|
|||||||
|
|
||||||
void A64EmitX64::EmitA64ExclusiveReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ExclusiveReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<8, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<8, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ExclusiveReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ExclusiveReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<16, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<16, &A64::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<16, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<16, &A64::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ExclusiveReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ExclusiveReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<32, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<32, &A64::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<32, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<32, &A64::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64ExclusiveReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64ExclusiveReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
if (conf.fastmem_exclusive_access) {
|
if (conf.fastmem_exclusive_access) {
|
||||||
EmitExclusiveReadMemoryInline<64, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemoryInline<64, &A64::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||||
} else {
|
} else {
|
||||||
EmitExclusiveReadMemory<64, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
EmitExclusiveReadMemory<64, &A64::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
* Copyright (c) 2022 MerryMage
|
* Copyright (c) 2022 MerryMage
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
@@ -59,13 +56,16 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
// Neither fastmem nor page table: Use callbacks
|
// Neither fastmem nor page table: Use callbacks
|
||||||
if constexpr (bitsize == 128) {
|
if constexpr (bitsize == 128) {
|
||||||
ctx.reg_alloc.HostCall(code, nullptr, {}, args[1]);
|
ctx.reg_alloc.HostCall(code, nullptr, {}, args[1]);
|
||||||
if (ordered) code.mfence();
|
if (ordered) {
|
||||||
|
code.mfence();
|
||||||
|
}
|
||||||
code.CallFunction(memory_read_128);
|
code.CallFunction(memory_read_128);
|
||||||
ctx.reg_alloc.DefineValue(code, inst, xmm1);
|
ctx.reg_alloc.DefineValue(code, inst, xmm1);
|
||||||
} else {
|
} else {
|
||||||
ctx.reg_alloc.HostCall(code, inst, {}, args[1]);
|
ctx.reg_alloc.HostCall(code, inst, {}, args[1]);
|
||||||
code.mov(code.ABI_PARAM3.cvt32(), bitsize / CHAR_BIT);
|
if (ordered) {
|
||||||
if (ordered) code.mfence();
|
code.mfence();
|
||||||
|
}
|
||||||
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
||||||
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
||||||
}
|
}
|
||||||
@@ -148,12 +148,12 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
ctx.reg_alloc.HostCall(code, nullptr);
|
ctx.reg_alloc.HostCall(code, nullptr);
|
||||||
code.CallFunction(memory_write_128);
|
code.CallFunction(memory_write_128);
|
||||||
} else {
|
} else {
|
||||||
// { this, vaddr, value, size }
|
|
||||||
ctx.reg_alloc.HostCall(code, nullptr, {}, args[1], args[2]);
|
ctx.reg_alloc.HostCall(code, nullptr, {}, args[1], args[2]);
|
||||||
code.mov(code.ABI_PARAM4.cvt32(), bitsize / CHAR_BIT);
|
|
||||||
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
||||||
}
|
}
|
||||||
if (ordered) code.mfence();
|
if (ordered) {
|
||||||
|
code.mfence();
|
||||||
|
}
|
||||||
EmitCheckMemoryAbort(ctx, inst);
|
EmitCheckMemoryAbort(ctx, inst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -230,11 +230,12 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
|
|||||||
if (ordered) {
|
if (ordered) {
|
||||||
code.mfence();
|
code.mfence();
|
||||||
}
|
}
|
||||||
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr) -> T {
|
code.CallLambda(
|
||||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
[](AxxUserConfig& conf, Axx::VAddr vaddr) -> T {
|
||||||
return (conf.callbacks->*callback)(vaddr, bitsize / CHAR_BIT);
|
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||||
|
return (conf.callbacks->*callback)(vaddr);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
||||||
} else {
|
} else {
|
||||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
||||||
@@ -249,11 +250,12 @@ 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(
|
||||||
ret = conf.global_monitor->ReadAndMark<Vector>(conf.processor_id, vaddr, [&]() -> Vector {
|
[](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& ret) {
|
||||||
return (conf.callbacks->*callback)(vaddr);
|
ret = conf.global_monitor->ReadAndMark<Vector>(conf.processor_id, vaddr, [&]() -> Vector {
|
||||||
|
return (conf.callbacks->*callback)(vaddr);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
code.movups(result, xword[rsp + ABI_SHADOW_SPACE]);
|
code.movups(result, xword[rsp + ABI_SHADOW_SPACE]);
|
||||||
ctx.reg_alloc.ReleaseStackSpace(code, 16 + ABI_SHADOW_SPACE);
|
ctx.reg_alloc.ReleaseStackSpace(code, 16 + ABI_SHADOW_SPACE);
|
||||||
|
|
||||||
|
|||||||
@@ -66,9 +66,7 @@ struct UserCallbacks : public TranslateCallbacks {
|
|||||||
|
|
||||||
// All reads through this callback are 4-byte aligned.
|
// All reads through this callback are 4-byte aligned.
|
||||||
// Memory must be interpreted as little endian.
|
// Memory must be interpreted as little endian.
|
||||||
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override {
|
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); }
|
||||||
return std::uint32_t(MemoryRead(vaddr, sizeof(std::uint32_t)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is called before the instruction at pc is read.
|
// This function is called before the instruction at pc is read.
|
||||||
// IR code can be emitted by the callee prior to instruction handling.
|
// IR code can be emitted by the callee prior to instruction handling.
|
||||||
@@ -82,10 +80,16 @@ struct UserCallbacks : public TranslateCallbacks {
|
|||||||
|
|
||||||
// Reads through these callbacks may not be aligned.
|
// Reads through these callbacks may not be aligned.
|
||||||
// Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.
|
// Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.
|
||||||
virtual std::uint64_t MemoryRead(VAddr vaddr, std::size_t size) = 0;
|
virtual std::uint8_t MemoryRead8(VAddr vaddr) = 0;
|
||||||
|
virtual std::uint16_t MemoryRead16(VAddr vaddr) = 0;
|
||||||
|
virtual std::uint32_t MemoryRead32(VAddr vaddr) = 0;
|
||||||
|
virtual std::uint64_t MemoryRead64(VAddr vaddr) = 0;
|
||||||
|
|
||||||
// Writes through these callbacks may not be aligned.
|
// Writes through these callbacks may not be aligned.
|
||||||
virtual void MemoryWrite(VAddr vaddr, std::uint64_t value, std::size_t size) = 0;
|
virtual void MemoryWrite8(VAddr vaddr, std::uint8_t value) = 0;
|
||||||
|
virtual void MemoryWrite16(VAddr vaddr, std::uint16_t value) = 0;
|
||||||
|
virtual void MemoryWrite32(VAddr vaddr, std::uint32_t value) = 0;
|
||||||
|
virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
|
||||||
|
|
||||||
// Writes through these callbacks may not be aligned.
|
// Writes through these callbacks may not be aligned.
|
||||||
virtual bool MemoryWriteExclusive8(VAddr /*vaddr*/, std::uint8_t /*value*/, std::uint8_t /*expected*/) { return false; }
|
virtual bool MemoryWriteExclusive8(VAddr /*vaddr*/, std::uint8_t /*value*/, std::uint8_t /*expected*/) { return false; }
|
||||||
|
|||||||
@@ -89,16 +89,20 @@ struct UserCallbacks {
|
|||||||
|
|
||||||
// All reads through this callback are 4-byte aligned.
|
// All reads through this callback are 4-byte aligned.
|
||||||
// Memory must be interpreted as little endian.
|
// Memory must be interpreted as little endian.
|
||||||
virtual std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) {
|
virtual std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) { return MemoryRead32(vaddr); }
|
||||||
return std::uint32_t(MemoryRead(vaddr, sizeof(std::uint32_t)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reads through these callbacks may not be aligned.
|
// Reads through these callbacks may not be aligned.
|
||||||
virtual std::uint64_t MemoryRead(VAddr vaddr, std::size_t size) = 0;
|
virtual std::uint8_t MemoryRead8(VAddr vaddr) = 0;
|
||||||
|
virtual std::uint16_t MemoryRead16(VAddr vaddr) = 0;
|
||||||
|
virtual std::uint32_t MemoryRead32(VAddr vaddr) = 0;
|
||||||
|
virtual std::uint64_t MemoryRead64(VAddr vaddr) = 0;
|
||||||
virtual Vector MemoryRead128(VAddr vaddr) = 0;
|
virtual Vector MemoryRead128(VAddr vaddr) = 0;
|
||||||
|
|
||||||
// Writes through these callbacks may not be aligned.
|
// Writes through these callbacks may not be aligned.
|
||||||
virtual void MemoryWrite(VAddr vaddr, std::uint64_t value, std::size_t size) = 0;
|
virtual void MemoryWrite8(VAddr vaddr, std::uint8_t value) = 0;
|
||||||
|
virtual void MemoryWrite16(VAddr vaddr, std::uint16_t value) = 0;
|
||||||
|
virtual void MemoryWrite32(VAddr vaddr, std::uint32_t value) = 0;
|
||||||
|
virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
|
||||||
virtual void MemoryWrite128(VAddr vaddr, Vector value) = 0;
|
virtual void MemoryWrite128(VAddr vaddr, Vector value) = 0;
|
||||||
|
|
||||||
// Writes through these callbacks may not be aligned.
|
// Writes through these callbacks may not be aligned.
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
|||||||
if (inst.AreAllArgsImmediates()) {
|
if (inst.AreAllArgsImmediates()) {
|
||||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||||
const u8 value_from_memory = u8(cb->MemoryRead(vaddr, sizeof(u8)));
|
const u8 value_from_memory = cb->MemoryRead8(vaddr);
|
||||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
|||||||
if (inst.AreAllArgsImmediates()) {
|
if (inst.AreAllArgsImmediates()) {
|
||||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||||
const u16 value_from_memory = u16(cb->MemoryRead(vaddr, sizeof(u16)));
|
const u16 value_from_memory = cb->MemoryRead16(vaddr);
|
||||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
|||||||
if (inst.AreAllArgsImmediates()) {
|
if (inst.AreAllArgsImmediates()) {
|
||||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||||
const u32 value_from_memory = u32(cb->MemoryRead(vaddr, sizeof(u32)));
|
const u32 value_from_memory = cb->MemoryRead32(vaddr);
|
||||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
|||||||
if (inst.AreAllArgsImmediates()) {
|
if (inst.AreAllArgsImmediates()) {
|
||||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||||
const u64 value_from_memory = u64(cb->MemoryRead(vaddr, sizeof(u64)));
|
const u64 value_from_memory = cb->MemoryRead64(vaddr);
|
||||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -503,7 +503,7 @@ TEST_CASE("Fuzz Thumb32 instructions set", "[JitX64][Thumb][Thumb32]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Verify fix for off by one error in MemoryRead<32> worked", "[Thumb][Thumb16]") {
|
TEST_CASE("Verify fix for off by one error in MemoryRead32 worked", "[Thumb][Thumb16]") {
|
||||||
ThumbTestEnv test_env;
|
ThumbTestEnv test_env;
|
||||||
|
|
||||||
// Prepare test subjects
|
// Prepare test subjects
|
||||||
|
|||||||
@@ -553,9 +553,9 @@ TEST_CASE("arm: Memory access (fastmem)", "[arm][A32]") {
|
|||||||
memset(backing_memory, 0, memory_size);
|
memset(backing_memory, 0, memory_size);
|
||||||
memcpy(backing_memory + 0x100, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 57);
|
memcpy(backing_memory + 0x100, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 57);
|
||||||
|
|
||||||
env.MemoryWrite(0, 0xE5904000, sizeof(u32)); // LDR R4, [R0]
|
env.MemoryWrite32(0, 0xE5904000); // LDR R4, [R0]
|
||||||
env.MemoryWrite(4, 0xE5814000, sizeof(u32)); // STR R4, [R1]
|
env.MemoryWrite32(4, 0xE5814000); // STR R4, [R1]
|
||||||
env.MemoryWrite(8, 0xEAFFFFFE, sizeof(u32)); // B .
|
env.MemoryWrite32(8, 0xEAFFFFFE); // B .
|
||||||
jit.Regs()[0] = 0x100;
|
jit.Regs()[0] = 0x100;
|
||||||
jit.Regs()[1] = 0x1F0;
|
jit.Regs()[1] = 0x1F0;
|
||||||
jit.Regs()[15] = 0; // PC = 0
|
jit.Regs()[15] = 0; // PC = 0
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
|
|
||||||
template<typename InstructionType_, u32 infinite_loop_u32>
|
template<typename InstructionType_, u32 infinite_loop_u32>
|
||||||
@@ -60,51 +59,42 @@ public:
|
|||||||
return infinite_loop_u32; // B .
|
return infinite_loop_u32; // B .
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 MemoryRead(u32 vaddr, size_t size) override {
|
std::uint8_t MemoryRead8(u32 vaddr) override {
|
||||||
switch (size) {
|
if (IsInCodeMem(vaddr)) {
|
||||||
case sizeof(u64):
|
return reinterpret_cast<u8*>(code_mem.data())[vaddr];
|
||||||
return MemoryRead(vaddr, sizeof(u32))
|
|
||||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
|
||||||
case sizeof(u32):
|
|
||||||
return MemoryRead(vaddr, sizeof(u16))
|
|
||||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
|
||||||
case sizeof(u16):
|
|
||||||
return MemoryRead(vaddr, sizeof(u8))
|
|
||||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
|
||||||
case sizeof(u8): {
|
|
||||||
if (IsInCodeMem(vaddr))
|
|
||||||
return reinterpret_cast<u8*>(code_mem.data())[vaddr];
|
|
||||||
if (auto iter = modified_memory.find(vaddr); iter != modified_memory.end())
|
|
||||||
return iter->second;
|
|
||||||
return u8(vaddr);
|
|
||||||
}
|
}
|
||||||
default:
|
if (auto iter = modified_memory.find(vaddr); iter != modified_memory.end()) {
|
||||||
std::abort();
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
return static_cast<u8>(vaddr);
|
||||||
|
}
|
||||||
|
std::uint16_t MemoryRead16(u32 vaddr) override {
|
||||||
|
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||||
|
}
|
||||||
|
std::uint32_t MemoryRead32(u32 vaddr) override {
|
||||||
|
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||||
|
}
|
||||||
|
std::uint64_t MemoryRead64(u32 vaddr) override {
|
||||||
|
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override {
|
void MemoryWrite8(u32 vaddr, std::uint8_t value) override {
|
||||||
switch (size) {
|
if (vaddr < code_mem.size() * sizeof(u32)) {
|
||||||
case sizeof(u64):
|
code_mem_modified_by_guest = true;
|
||||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
|
||||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
|
||||||
break;
|
|
||||||
case sizeof(u32):
|
|
||||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
|
||||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
|
||||||
break;
|
|
||||||
case sizeof(u16):
|
|
||||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
|
||||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
|
||||||
break;
|
|
||||||
case sizeof(u8):
|
|
||||||
if (vaddr < code_mem.size() * sizeof(u32))
|
|
||||||
code_mem_modified_by_guest = true;
|
|
||||||
modified_memory[vaddr] = value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::abort();
|
|
||||||
}
|
}
|
||||||
|
modified_memory[vaddr] = value;
|
||||||
|
}
|
||||||
|
void MemoryWrite16(u32 vaddr, std::uint16_t value) override {
|
||||||
|
MemoryWrite8(vaddr, static_cast<u8>(value));
|
||||||
|
MemoryWrite8(vaddr + 1, static_cast<u8>(value >> 8));
|
||||||
|
}
|
||||||
|
void MemoryWrite32(u32 vaddr, std::uint32_t value) override {
|
||||||
|
MemoryWrite16(vaddr, static_cast<u16>(value));
|
||||||
|
MemoryWrite16(vaddr + 2, static_cast<u16>(value >> 16));
|
||||||
|
}
|
||||||
|
void MemoryWrite64(u32 vaddr, std::uint64_t value) override {
|
||||||
|
MemoryWrite32(vaddr, static_cast<u32>(value));
|
||||||
|
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSVC(std::uint32_t swi) override {
|
void CallSVC(std::uint32_t swi) override {
|
||||||
@@ -153,41 +143,46 @@ public:
|
|||||||
return read<std::uint32_t>(vaddr);
|
return read<std::uint32_t>(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 MemoryRead(u32 vaddr, size_t size) override {
|
std::uint8_t MemoryRead8(std::uint32_t vaddr) override {
|
||||||
switch (size) {
|
return read<std::uint8_t>(vaddr);
|
||||||
case sizeof(u64): return read<u64>(vaddr);
|
}
|
||||||
case sizeof(u32): return read<u32>(vaddr);
|
std::uint16_t MemoryRead16(std::uint32_t vaddr) override {
|
||||||
case sizeof(u16): return read<u16>(vaddr);
|
return read<std::uint16_t>(vaddr);
|
||||||
case sizeof(u8): return read<u8>(vaddr);
|
}
|
||||||
default:
|
std::uint32_t MemoryRead32(std::uint32_t vaddr) override {
|
||||||
std::abort();
|
return read<std::uint32_t>(vaddr);
|
||||||
}
|
}
|
||||||
|
std::uint64_t MemoryRead64(std::uint32_t vaddr) override {
|
||||||
|
return read<std::uint64_t>(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, std::uint64_t value, size_t size) override {
|
void MemoryWrite8(std::uint32_t vaddr, std::uint8_t value) override {
|
||||||
switch (size) {
|
write(vaddr, value);
|
||||||
case sizeof(u64): return write<u64>(vaddr, u64(value));
|
}
|
||||||
case sizeof(u32): return write<u32>(vaddr, u32(value));
|
void MemoryWrite16(std::uint32_t vaddr, std::uint16_t value) override {
|
||||||
case sizeof(u16): return write<u16>(vaddr, u16(value));
|
write(vaddr, value);
|
||||||
case sizeof(u8): return write<u8>(vaddr, u8(value));
|
}
|
||||||
default: std::abort();
|
void MemoryWrite32(std::uint32_t vaddr, std::uint32_t value) override {
|
||||||
}
|
write(vaddr, value);
|
||||||
|
}
|
||||||
|
void MemoryWrite64(std::uint32_t vaddr, std::uint64_t value) override {
|
||||||
|
write(vaddr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryWriteExclusive8(Dynarmic::A32::VAddr vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
bool MemoryWriteExclusive8(std::uint32_t vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u8));
|
MemoryWrite8(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive16(Dynarmic::A32::VAddr vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
bool MemoryWriteExclusive16(std::uint32_t vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u16));
|
MemoryWrite16(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive32(Dynarmic::A32::VAddr vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
bool MemoryWriteExclusive32(std::uint32_t vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u32));
|
MemoryWrite32(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive64(Dynarmic::A32::VAddr vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
bool MemoryWriteExclusive64(std::uint32_t vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u64));
|
MemoryWrite64(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -25,55 +25,48 @@ public:
|
|||||||
u64 ticks_left = 0;
|
u64 ticks_left = 0;
|
||||||
::Common::unordered_map<u64, u8> memory{};
|
::Common::unordered_map<u64, u8> memory{};
|
||||||
|
|
||||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
u8 MemoryRead8(u64 vaddr) override {
|
||||||
switch (size) {
|
return memory[vaddr];
|
||||||
case sizeof(u64):
|
}
|
||||||
return MemoryRead(vaddr, sizeof(u32))
|
|
||||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
u16 MemoryRead16(u64 vaddr) override {
|
||||||
case sizeof(u32):
|
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||||
return MemoryRead(vaddr, sizeof(u16))
|
}
|
||||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
|
||||||
case sizeof(u16):
|
u32 MemoryRead32(u64 vaddr) override {
|
||||||
return MemoryRead(vaddr, sizeof(u8))
|
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
}
|
||||||
case sizeof(u8):
|
|
||||||
return memory[vaddr];
|
u64 MemoryRead64(u64 vaddr) override {
|
||||||
default:
|
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<u64, 2> MemoryRead128(u64 vaddr) override {
|
std::array<u64, 2> MemoryRead128(u64 vaddr) override {
|
||||||
return {
|
return {MemoryRead64(vaddr), MemoryRead64(vaddr + 8)};
|
||||||
MemoryRead(vaddr, sizeof(u64)),
|
|
||||||
MemoryRead(vaddr + sizeof(u64), sizeof(u64))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, size_t size) override {
|
void MemoryWrite8(u64 vaddr, u8 value) override {
|
||||||
switch (size) {
|
memory[vaddr] = value;
|
||||||
case sizeof(u64):
|
|
||||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
|
||||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
|
||||||
break;
|
|
||||||
case sizeof(u32):
|
|
||||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
|
||||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
|
||||||
break;
|
|
||||||
case sizeof(u16):
|
|
||||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
|
||||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
|
||||||
break;
|
|
||||||
case sizeof(u8):
|
|
||||||
memory[vaddr] = value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryWrite16(u64 vaddr, u16 value) override {
|
||||||
|
MemoryWrite8(vaddr, u8(value));
|
||||||
|
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryWrite32(u64 vaddr, u32 value) override {
|
||||||
|
MemoryWrite16(vaddr, u16(value));
|
||||||
|
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryWrite64(u64 vaddr, u64 value) override {
|
||||||
|
MemoryWrite32(vaddr, u32(value));
|
||||||
|
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryWrite128(u64 vaddr, std::array<u64, 2> value) override {
|
void MemoryWrite128(u64 vaddr, std::array<u64, 2> value) override {
|
||||||
MemoryWrite(vaddr, value[0], sizeof(u64));
|
MemoryWrite64(vaddr, value[0]);
|
||||||
MemoryWrite(vaddr + 8, value[1], sizeof(u64));
|
MemoryWrite64(vaddr + 8, value[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSVC(u32) override {
|
void CallSVC(u32) override {
|
||||||
@@ -142,9 +135,9 @@ TEST_CASE("A64: fibonacci", "[a64]") {
|
|||||||
code.RET();
|
code.RET();
|
||||||
|
|
||||||
for (size_t i = 0; i < 1024; i++) {
|
for (size_t i = 0; i < 1024; i++) {
|
||||||
env.MemoryWrite(i * 4, instructions[i], sizeof(u32));
|
env.MemoryWrite32(i * 4, instructions[i]);
|
||||||
}
|
}
|
||||||
env.MemoryWrite(8888, 0xd4200000, sizeof(u32));
|
env.MemoryWrite32(8888, 0xd4200000);
|
||||||
cpu.SetRegister(30, 8888);
|
cpu.SetRegister(30, 8888);
|
||||||
|
|
||||||
cpu.SetRegister(0, 10);
|
cpu.SetRegister(0, 10);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "dynarmic/interface/A64/a64.h"
|
#include "dynarmic/interface/A64/a64.h"
|
||||||
#include "dynarmic/interface/A64/config.h"
|
|
||||||
|
|
||||||
using Vector = Dynarmic::A64::Vector;
|
using Vector = Dynarmic::A64::Vector;
|
||||||
|
|
||||||
@@ -35,79 +34,64 @@ public:
|
|||||||
return code_mem[index];
|
return code_mem[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
std::uint8_t MemoryRead8(u64 vaddr) override {
|
||||||
switch (size) {
|
if (IsInCodeMem(vaddr)) {
|
||||||
case sizeof(u64):
|
return reinterpret_cast<u8*>(code_mem.data())[vaddr - code_mem_start_address];
|
||||||
return MemoryRead(vaddr, sizeof(u32))
|
|
||||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
|
||||||
case sizeof(u32):
|
|
||||||
return MemoryRead(vaddr, sizeof(u16))
|
|
||||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
|
||||||
case sizeof(u16):
|
|
||||||
return MemoryRead(vaddr, sizeof(u8))
|
|
||||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
|
||||||
case sizeof(u8): {
|
|
||||||
if (IsInCodeMem(vaddr))
|
|
||||||
return reinterpret_cast<u8*>(code_mem.data())[vaddr - code_mem_start_address];
|
|
||||||
if (auto const it = modified_memory.find(vaddr); it != modified_memory.end())
|
|
||||||
return it->second;
|
|
||||||
return u8(vaddr);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
std::abort();
|
|
||||||
}
|
}
|
||||||
|
if (auto const it = modified_memory.find(vaddr); it != modified_memory.end())
|
||||||
|
return it->second;
|
||||||
|
return u8(vaddr);
|
||||||
|
}
|
||||||
|
std::uint16_t MemoryRead16(u64 vaddr) override {
|
||||||
|
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||||
|
}
|
||||||
|
std::uint32_t MemoryRead32(u64 vaddr) override {
|
||||||
|
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||||
|
}
|
||||||
|
std::uint64_t MemoryRead64(u64 vaddr) override {
|
||||||
|
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector MemoryRead128(u64 vaddr) override {
|
Vector MemoryRead128(u64 vaddr) override {
|
||||||
return {
|
return {MemoryRead64(vaddr), MemoryRead64(vaddr + 8)};
|
||||||
MemoryRead(vaddr, sizeof(u64)),
|
|
||||||
MemoryRead(vaddr + 8, sizeof(u64))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, size_t size) override {
|
void MemoryWrite8(u64 vaddr, std::uint8_t value) override {
|
||||||
switch (size) {
|
if (IsInCodeMem(vaddr)) {
|
||||||
case sizeof(u64):
|
code_mem_modified_by_guest = true;
|
||||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
|
||||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
|
||||||
break;
|
|
||||||
case sizeof(u32):
|
|
||||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
|
||||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
|
||||||
break;
|
|
||||||
case sizeof(u16):
|
|
||||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
|
||||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
|
||||||
break;
|
|
||||||
case sizeof(u8):
|
|
||||||
if (IsInCodeMem(vaddr)) {
|
|
||||||
code_mem_modified_by_guest = true;
|
|
||||||
}
|
|
||||||
modified_memory[vaddr] = value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::abort();
|
|
||||||
}
|
}
|
||||||
|
modified_memory[vaddr] = value;
|
||||||
|
}
|
||||||
|
void MemoryWrite16(u64 vaddr, std::uint16_t value) override {
|
||||||
|
MemoryWrite8(vaddr, u8(value));
|
||||||
|
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||||
|
}
|
||||||
|
void MemoryWrite32(u64 vaddr, std::uint32_t value) override {
|
||||||
|
MemoryWrite16(vaddr, u16(value));
|
||||||
|
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||||
|
}
|
||||||
|
void MemoryWrite64(u64 vaddr, std::uint64_t value) override {
|
||||||
|
MemoryWrite32(vaddr, u32(value));
|
||||||
|
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||||
}
|
}
|
||||||
void MemoryWrite128(u64 vaddr, Vector value) override {
|
void MemoryWrite128(u64 vaddr, Vector value) override {
|
||||||
MemoryWrite(vaddr, value[0], sizeof(u64));
|
MemoryWrite64(vaddr, value[0]);
|
||||||
MemoryWrite(vaddr + 8, value[1], sizeof(u64));
|
MemoryWrite64(vaddr + 8, value[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u8));
|
MemoryWrite8(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u16));
|
MemoryWrite16(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u32));
|
MemoryWrite32(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u64));
|
MemoryWrite64(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
|
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
|
||||||
@@ -161,46 +145,52 @@ public:
|
|||||||
return read<std::uint32_t>(vaddr);
|
return read<std::uint32_t>(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
std::uint8_t MemoryRead8(u64 vaddr) override {
|
||||||
switch (size) {
|
return read<std::uint8_t>(vaddr);
|
||||||
case sizeof(u64): return read<u64>(vaddr);
|
}
|
||||||
case sizeof(u32): return read<u32>(vaddr);
|
std::uint16_t MemoryRead16(u64 vaddr) override {
|
||||||
case sizeof(u16): return read<u16>(vaddr);
|
return read<std::uint16_t>(vaddr);
|
||||||
case sizeof(u8): return read<u8>(vaddr);
|
}
|
||||||
default: std::abort();
|
std::uint32_t MemoryRead32(u64 vaddr) override {
|
||||||
}
|
return read<std::uint32_t>(vaddr);
|
||||||
|
}
|
||||||
|
std::uint64_t MemoryRead64(u64 vaddr) override {
|
||||||
|
return read<std::uint64_t>(vaddr);
|
||||||
}
|
}
|
||||||
Vector MemoryRead128(u64 vaddr) override {
|
Vector MemoryRead128(u64 vaddr) override {
|
||||||
return read<Vector>(vaddr);
|
return read<Vector>(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(u64 vaddr, std::uint64_t value, size_t size) override {
|
void MemoryWrite8(u64 vaddr, std::uint8_t value) override {
|
||||||
switch (size) {
|
write(vaddr, value);
|
||||||
case sizeof(u64): return write<u64>(vaddr, u64(value));
|
}
|
||||||
case sizeof(u32): return write<u32>(vaddr, u32(value));
|
void MemoryWrite16(u64 vaddr, std::uint16_t value) override {
|
||||||
case sizeof(u16): return write<u16>(vaddr, u16(value));
|
write(vaddr, value);
|
||||||
case sizeof(u8): return write<u8>(vaddr, u8(value));
|
}
|
||||||
default: std::abort();
|
void MemoryWrite32(u64 vaddr, std::uint32_t value) override {
|
||||||
}
|
write(vaddr, value);
|
||||||
|
}
|
||||||
|
void MemoryWrite64(u64 vaddr, std::uint64_t value) override {
|
||||||
|
write(vaddr, value);
|
||||||
}
|
}
|
||||||
void MemoryWrite128(u64 vaddr, Vector value) override {
|
void MemoryWrite128(u64 vaddr, Vector value) override {
|
||||||
write(vaddr, value);
|
write(vaddr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u8));
|
MemoryWrite8(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u16));
|
MemoryWrite16(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u32));
|
MemoryWrite32(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||||
MemoryWrite(vaddr, value, sizeof(u64));
|
MemoryWrite64(vaddr, value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
|
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
|
||||||
#include "dynarmic/mcl/bit.hpp"
|
#include "dynarmic/mcl/bit.hpp"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
@@ -119,47 +118,36 @@ public:
|
|||||||
u64 ticks_left = 0;
|
u64 ticks_left = 0;
|
||||||
std::map<u32, u8> memory;
|
std::map<u32, u8> memory;
|
||||||
|
|
||||||
u64 MemoryRead(Dynarmic::A32::VAddr vaddr, size_t size) override {
|
std::uint8_t MemoryRead8(u32 vaddr) override {
|
||||||
switch (size) {
|
if (auto iter = memory.find(vaddr); iter != memory.end()) {
|
||||||
case sizeof(u64):
|
return iter->second;
|
||||||
return MemoryRead(vaddr, sizeof(u32))
|
|
||||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
|
||||||
case sizeof(u32):
|
|
||||||
return MemoryRead(vaddr, sizeof(u16))
|
|
||||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
|
||||||
case sizeof(u16):
|
|
||||||
return MemoryRead(vaddr, sizeof(u8))
|
|
||||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
|
||||||
case sizeof(u8): {
|
|
||||||
if (auto const it = memory.find(vaddr); it != memory.end())
|
|
||||||
return it->second;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
std::abort();
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::uint16_t MemoryRead16(u32 vaddr) override {
|
||||||
|
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||||
|
}
|
||||||
|
std::uint32_t MemoryRead32(u32 vaddr) override {
|
||||||
|
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||||
|
}
|
||||||
|
std::uint64_t MemoryRead64(u32 vaddr) override {
|
||||||
|
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override {
|
void MemoryWrite8(u32 vaddr, std::uint8_t value) override {
|
||||||
switch (size) {
|
memory[vaddr] = value;
|
||||||
case sizeof(u64):
|
}
|
||||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
void MemoryWrite16(u32 vaddr, std::uint16_t value) override {
|
||||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
MemoryWrite8(vaddr, static_cast<u8>(value));
|
||||||
break;
|
MemoryWrite8(vaddr + 1, static_cast<u8>(value >> 8));
|
||||||
case sizeof(u32):
|
}
|
||||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
void MemoryWrite32(u32 vaddr, std::uint32_t value) override {
|
||||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
MemoryWrite16(vaddr, static_cast<u16>(value));
|
||||||
break;
|
MemoryWrite16(vaddr + 2, static_cast<u16>(value >> 16));
|
||||||
case sizeof(u16):
|
}
|
||||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
void MemoryWrite64(u32 vaddr, std::uint64_t value) override {
|
||||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
MemoryWrite32(vaddr, static_cast<u32>(value));
|
||||||
break;
|
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
|
||||||
case sizeof(u8):
|
|
||||||
memory[vaddr] = value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSVC(std::uint32_t swi) override {
|
void CallSVC(std::uint32_t swi) override {
|
||||||
@@ -243,7 +231,7 @@ void ExecuteA32Instruction(u32 instruction) {
|
|||||||
if (const auto address = get_value()) {
|
if (const auto address = get_value()) {
|
||||||
fmt::print("value: ");
|
fmt::print("value: ");
|
||||||
if (const auto value = get_value()) {
|
if (const auto value = get_value()) {
|
||||||
env.MemoryWrite(*address, *value, sizeof(u32));
|
env.MemoryWrite32(*address, *value);
|
||||||
fmt::print("> mem[{:#08x}] = {:#08x}\n", *address, *value);
|
fmt::print("> mem[{:#08x}] = {:#08x}\n", *address, *value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,8 +247,8 @@ void ExecuteA32Instruction(u32 instruction) {
|
|||||||
cpu.SetFpscr(fpscr);
|
cpu.SetFpscr(fpscr);
|
||||||
|
|
||||||
const u32 initial_pc = regs[15];
|
const u32 initial_pc = regs[15];
|
||||||
env.MemoryWrite(initial_pc + 0, instruction, sizeof(u32));
|
env.MemoryWrite32(initial_pc + 0, instruction);
|
||||||
env.MemoryWrite(initial_pc + 4, 0xEAFFFFFE, sizeof(u32)); // B +0
|
env.MemoryWrite32(initial_pc + 4, 0xEAFFFFFE); // B +0
|
||||||
|
|
||||||
cpu.Run();
|
cpu.Run();
|
||||||
fmt::print("{}", fmt::join(cpu.Disassemble(), "\n"));
|
fmt::print("{}", fmt::join(cpu.Disassemble(), "\n"));
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ bool A32Unicorn<TestEnvironment>::UnmappedMemoryHook(uc_engine* uc, uc_mem_type
|
|||||||
auto page = std::make_unique<Page>();
|
auto page = std::make_unique<Page>();
|
||||||
page->address = base_address;
|
page->address = base_address;
|
||||||
for (size_t i = 0; i < page->data.size(); ++i)
|
for (size_t i = 0; i < page->data.size(); ++i)
|
||||||
page->data[i] = u8(this_->testenv.MemoryRead(u32(base_address + i), sizeof(u8)));
|
page->data[i] = this_->testenv.MemoryRead8(static_cast<u32>(base_address + i));
|
||||||
|
|
||||||
uc_err err = uc_mem_map_ptr(uc, base_address, page->data.size(), permissions, page->data.data());
|
uc_err err = uc_mem_map_ptr(uc, base_address, page->data.size(), permissions, page->data.data());
|
||||||
if (err == UC_ERR_MAP)
|
if (err == UC_ERR_MAP)
|
||||||
@@ -321,7 +321,24 @@ bool A32Unicorn<TestEnvironment>::UnmappedMemoryHook(uc_engine* uc, uc_mem_type
|
|||||||
template<class TestEnvironment>
|
template<class TestEnvironment>
|
||||||
bool A32Unicorn<TestEnvironment>::MemoryWriteHook(uc_engine* /*uc*/, uc_mem_type /*type*/, u32 start_address, int size, u64 value, void* user_data) {
|
bool A32Unicorn<TestEnvironment>::MemoryWriteHook(uc_engine* /*uc*/, uc_mem_type /*type*/, u32 start_address, int size, u64 value, void* user_data) {
|
||||||
auto* this_ = static_cast<A32Unicorn*>(user_data);
|
auto* this_ = static_cast<A32Unicorn*>(user_data);
|
||||||
this_->testenv.MemoryWrite(start_address, value, size);
|
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
this_->testenv.MemoryWrite8(start_address, static_cast<u8>(value));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this_->testenv.MemoryWrite16(start_address, static_cast<u16>(value));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
this_->testenv.MemoryWrite32(start_address, static_cast<u32>(value));
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
this_->testenv.MemoryWrite64(start_address, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ bool A64Unicorn::UnmappedMemoryHook(uc_engine* uc, uc_mem_type /*type*/, u64 sta
|
|||||||
auto page = std::make_unique<Page>();
|
auto page = std::make_unique<Page>();
|
||||||
page->address = base_address;
|
page->address = base_address;
|
||||||
for (size_t i = 0; i < page->data.size(); ++i)
|
for (size_t i = 0; i < page->data.size(); ++i)
|
||||||
page->data[i] = u8(this_->testenv.MemoryRead(base_address + i, sizeof(u8)));
|
page->data[i] = this_->testenv.MemoryRead8(base_address + i);
|
||||||
|
|
||||||
uc_err err = uc_mem_map_ptr(uc, base_address, page->data.size(), permissions, page->data.data());
|
uc_err err = uc_mem_map_ptr(uc, base_address, page->data.size(), permissions, page->data.data());
|
||||||
if (err == UC_ERR_MAP)
|
if (err == UC_ERR_MAP)
|
||||||
@@ -227,6 +227,23 @@ bool A64Unicorn::UnmappedMemoryHook(uc_engine* uc, uc_mem_type /*type*/, u64 sta
|
|||||||
|
|
||||||
bool A64Unicorn::MemoryWriteHook(uc_engine* /*uc*/, uc_mem_type /*type*/, u64 start_address, int size, u64 value, void* user_data) {
|
bool A64Unicorn::MemoryWriteHook(uc_engine* /*uc*/, uc_mem_type /*type*/, u64 start_address, int size, u64 value, void* user_data) {
|
||||||
auto* this_ = static_cast<A64Unicorn*>(user_data);
|
auto* this_ = static_cast<A64Unicorn*>(user_data);
|
||||||
this_->testenv.MemoryWrite(start_address, value, size);
|
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
this_->testenv.MemoryWrite8(start_address, static_cast<u8>(value));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this_->testenv.MemoryWrite16(start_address, static_cast<u16>(value));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
this_->testenv.MemoryWrite32(start_address, static_cast<u32>(value));
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
this_->testenv.MemoryWrite64(start_address, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -398,21 +398,21 @@ void NPad::InitNewlyAddedController(Kernel::KernelCore& kernel, u64 aruid, Core:
|
|||||||
void NPad::WriteEmptyEntry(NpadInternalState* npad) {
|
void NPad::WriteEmptyEntry(NpadInternalState* npad) {
|
||||||
NPadGenericState dummy_pad_state{};
|
NPadGenericState dummy_pad_state{};
|
||||||
NpadGcTriggerState dummy_gc_state{};
|
NpadGcTriggerState dummy_gc_state{};
|
||||||
dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->fullkey_lifo.WriteNextEntry(dummy_pad_state);
|
npad->fullkey_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->handheld_lifo.WriteNextEntry(dummy_pad_state);
|
npad->handheld_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state);
|
npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->joy_left_lifo.WriteNextEntry(dummy_pad_state);
|
npad->joy_left_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->joy_right_lifo.WriteNextEntry(dummy_pad_state);
|
npad->joy_right_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->palma_lifo.WriteNextEntry(dummy_pad_state);
|
npad->palma_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->system_ext_lifo.WriteNextEntry(dummy_pad_state);
|
npad->system_ext_lifo.WriteNextEntry(dummy_pad_state);
|
||||||
dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1;
|
||||||
npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
|
npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user