mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 12:21:28 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f130fab1d | ||
|
|
08f8666596 | ||
|
|
fb5294a125 | ||
|
|
b3384b5c81 | ||
|
|
7058d990c4 | ||
|
|
8557ede0e9 | ||
|
|
78383901f2 | ||
|
|
ebccae45e3 | ||
|
|
80b5e387d2 | ||
|
|
15e065ae5d | ||
|
|
00ca85606d | ||
|
|
bc181e7812 | ||
|
|
0f6b8ccc68 | ||
|
|
ffeff6599b | ||
|
|
3e71996209 | ||
|
|
bbb2560ff8 | ||
|
|
30b1bf210d | ||
|
|
178e344b98 | ||
|
|
1c2fc72c20 | ||
|
|
b7ed2c57f5 | ||
|
|
23f8db631d | ||
|
|
f22f5adb55 | ||
|
|
f02526fdbb | ||
|
|
675814f912 | ||
|
|
c44264eba0 | ||
|
|
35ea2eedcd | ||
|
|
25f49cbf25 | ||
|
|
2dd1600cdd | ||
|
|
327b0870f0 | ||
|
|
7097ead476 | ||
|
|
887d5ca523 | ||
|
|
54c35ef172 | ||
|
|
a78eec4ebf | ||
|
|
ed140eade7 | ||
|
|
7c6c963168 | ||
|
|
e058be73ca | ||
|
|
d9a136d31c | ||
|
|
5910a52a60 | ||
|
|
e67bd4b6f6 | ||
|
|
9270fc3727 | ||
|
|
5101489d21 | ||
|
|
41c3a0caa5 | ||
|
|
382065544d | ||
|
|
e2a2c801f2 | ||
|
|
9e2fa9e360 | ||
|
|
588f1d9c93 | ||
|
|
347f3b1a13 | ||
|
|
c32ebc76fd | ||
|
|
a2ae0500d8 | ||
|
|
478972a34b | ||
|
|
f4ee1c1b53 | ||
|
|
93fe536549 | ||
|
|
3698562aae | ||
|
|
d8df33a9cb | ||
|
|
0de71be3e5 | ||
|
|
fd895bd142 | ||
|
|
edc68c032a | ||
|
|
40a841df8f | ||
|
|
df697c683c | ||
|
|
e3cb94f490 | ||
|
|
88f6cb97c7 | ||
|
|
bdd226b9d3 | ||
|
|
537d92bf57 | ||
|
|
c08644a729 | ||
|
|
7b07789173 | ||
|
|
585e0a6308 | ||
|
|
fd6bdfe69e | ||
|
|
654e36622f | ||
|
|
38df9afcf2 | ||
|
|
b442786811 | ||
|
|
ff943b5d5a | ||
|
|
ef8b463a25 | ||
|
|
02a9f25707 | ||
|
|
9a4b78d35a | ||
|
|
7d8ae5f7e2 | ||
|
|
f7208a7241 | ||
|
|
da25b06705 | ||
|
|
66e9f120bb | ||
|
|
79b72348c2 | ||
|
|
6994c012b8 | ||
|
|
26ab7ad6b0 | ||
|
|
67962cd10d | ||
|
|
603730dd3c | ||
|
|
7c3c5dd0d9 | ||
|
|
121cf70278 | ||
|
|
c8a5246766 | ||
|
|
9c0214dd34 | ||
|
|
d9df72e602 | ||
|
|
8b1fbc150d | ||
|
|
0cec433211 | ||
|
|
31cb8b5d61 | ||
|
|
f681291c1d | ||
|
|
099982d356 | ||
|
|
2e7a8867cb | ||
|
|
d22f9e6169 | ||
|
|
f79babc541 | ||
|
|
5640228909 | ||
|
|
3e2ab21e70 | ||
|
|
f19936e53b | ||
|
|
d8cb528a2d | ||
|
|
2544543b3a | ||
|
|
ceb5c13822 | ||
|
|
8ace9188e8 | ||
|
|
5a20e40e29 | ||
|
|
0dc712cec0 | ||
|
|
0d8356702b | ||
|
|
cf633e161a | ||
|
|
3ac45c1ac6 | ||
|
|
86f3d6d316 | ||
|
|
290dc73a3a | ||
|
|
c5215cb2f5 | ||
|
|
a107c2a52b | ||
|
|
373e1306ad | ||
|
|
0910384e6f | ||
|
|
894a183180 | ||
|
|
e016c5a6cd | ||
|
|
900d327aa1 | ||
|
|
eb3cd0c1bd | ||
|
|
4280f4b259 | ||
|
|
07b76e6f99 | ||
|
|
5134a414a8 | ||
|
|
919e426d03 | ||
|
|
4bf60dec65 | ||
|
|
3e9dc054af | ||
|
|
a5a320ae3c | ||
|
|
1dd0323f8f | ||
|
|
4b482fb0e1 | ||
|
|
0ccd7513b4 | ||
|
|
a96396985e | ||
|
|
8ee3d8f2c8 | ||
|
|
bc61374812 | ||
|
|
862fef5e0f | ||
|
|
65898277e9 | ||
|
|
bd0131e973 | ||
|
|
f7aa4942de | ||
|
|
1953db9145 | ||
|
|
2d5d7d1a41 | ||
|
|
d53d99ebcf | ||
|
|
32f966210b | ||
|
|
24d550147f | ||
|
|
384972df38 | ||
|
|
7fb6dc4353 | ||
|
|
5a1114c76e | ||
|
|
86a850cfcd | ||
|
|
f5c0d135d0 | ||
|
|
17b0ca1d43 | ||
|
|
462b3c0d78 | ||
|
|
2a5480652a | ||
|
|
ecc6b95a75 | ||
|
|
c08554e3f3 | ||
|
|
d6e43153db | ||
|
|
d701932fe6 | ||
|
|
b47131c1e4 | ||
|
|
70dc4e4897 | ||
|
|
5a6419d322 | ||
|
|
0c3d2391f0 | ||
|
|
baacff1811 | ||
|
|
39e75158ee | ||
|
|
b1d094f9bd | ||
|
|
89a2e7d66a | ||
|
|
90dffce78a | ||
|
|
55922238d3 | ||
|
|
38a4a2c751 | ||
|
|
e6de218979 | ||
|
|
d9fca2f365 | ||
|
|
2f850d4e88 | ||
|
|
dd180478f1 | ||
|
|
fc8a8d0b83 | ||
|
|
83d9c30aa4 | ||
|
|
ffa7c1a77b | ||
|
|
148a1a21e8 | ||
|
|
d7b78a092f | ||
|
|
7da44e5d7e | ||
|
|
3bf34a77c7 | ||
|
|
2cc903bbe0 | ||
|
|
f1f572a087 | ||
|
|
8e96a34da3 | ||
|
|
38d64baba2 | ||
|
|
896b965325 | ||
|
|
17865c3a9e | ||
|
|
8e661d2907 | ||
|
|
46459ebee1 | ||
|
|
75464e9d94 | ||
|
|
49e248923e | ||
|
|
6656708831 | ||
|
|
153b6613cc | ||
|
|
2d74207bb7 | ||
|
|
61131566bb | ||
|
|
915a28f84c | ||
|
|
75c0edc100 | ||
|
|
0053799955 | ||
|
|
95b02080ec | ||
|
|
12ba6c1c3c | ||
|
|
a6f44ac2bd | ||
|
|
758f352bf5 | ||
|
|
274c5a8f11 | ||
|
|
fdabd38e7b | ||
|
|
59c6aa4932 | ||
|
|
9ddbc50844 | ||
|
|
093e6353d7 | ||
|
|
6597bef108 | ||
|
|
5fa5298977 | ||
|
|
15cced707b | ||
|
|
50c8b90b09 | ||
|
|
53968e0d4e | ||
|
|
03157ce442 | ||
|
|
c018889389 | ||
|
|
3ac87fd225 | ||
|
|
63c956d8ac | ||
|
|
00ee467812 | ||
|
|
75a1456bc3 | ||
|
|
4b669fbe99 | ||
|
|
d39bf05f39 | ||
|
|
df36391e74 | ||
|
|
0873ab1824 | ||
|
|
514d5cd770 | ||
|
|
87d06d3afd | ||
|
|
956c89d820 | ||
|
|
cd15d459b1 | ||
|
|
befc90de1c | ||
|
|
05136b7bfb | ||
|
|
f1bbd6f8c6 | ||
|
|
e823292457 | ||
|
|
8a3ecb8cc5 | ||
|
|
4ececfb100 | ||
|
|
e424cdb940 | ||
|
|
fe86cb68f2 | ||
|
|
83a3b787e6 | ||
|
|
7031e700b3 | ||
|
|
64ac6bc0a2 | ||
|
|
efa5a51365 | ||
|
|
80bdf9bac7 | ||
|
|
d0ab518074 | ||
|
|
17f57e6804 | ||
|
|
771672e6d4 | ||
|
|
d4f675e7bd | ||
|
|
1a66f7ee40 | ||
|
|
3f747727f2 | ||
|
|
f5e1ebb554 | ||
|
|
8f445d9a0c | ||
|
|
0292a66f37 | ||
|
|
4f5d171032 | ||
|
|
8d7f6a54d7 | ||
|
|
d6e26bc9aa | ||
|
|
be4db11199 | ||
|
|
326784b81e | ||
|
|
b9ce9049a2 | ||
|
|
ad6b10f060 | ||
|
|
34fc743599 | ||
|
|
c7d6dad1a8 | ||
|
|
c14f0eca84 | ||
|
|
b15badbc53 | ||
|
|
e731c91204 | ||
|
|
15a165f842 | ||
|
|
422007abd9 | ||
|
|
665cacbe7c | ||
|
|
e2345d735a | ||
|
|
7a52697f9a | ||
|
|
7f1cae956c | ||
|
|
5ab21087dd | ||
|
|
58a8629135 | ||
|
|
ae53c4c8ae | ||
|
|
c0aed34f41 | ||
|
|
e694f2ca8b | ||
|
|
93abdcf317 | ||
|
|
cad3b16525 | ||
|
|
b7bf42c8b7 | ||
|
|
a49be7e78d | ||
|
|
7468d58af2 | ||
|
|
c6c5e4f797 | ||
|
|
09bce33a45 | ||
|
|
dab3fdc351 | ||
|
|
1a2ad946cb | ||
|
|
00cbf50c98 | ||
|
|
8182d2b7c0 | ||
|
|
f7cede9878 | ||
|
|
419e095ea0 | ||
|
|
7fb417db98 | ||
|
|
3583d9c90e | ||
|
|
194d577d51 | ||
|
|
87f896e85b | ||
|
|
ea33518f47 | ||
|
|
5b7308fecf | ||
|
|
5c84eb6f3a | ||
|
|
239fb1ccb3 | ||
|
|
e2186c1e8e | ||
|
|
b77a21b1e1 | ||
|
|
2d14666f3d | ||
|
|
ba3b80e3f1 | ||
|
|
2e718b464d | ||
|
|
4feb8b1863 | ||
|
|
d39062d3d7 | ||
|
|
f05bdb1f93 | ||
|
|
df37f6acf0 | ||
|
|
1299966a02 | ||
|
|
5687b460b9 | ||
|
|
1867645ef0 | ||
|
|
113b8b427e | ||
|
|
86c7d13769 | ||
|
|
174a9496fa | ||
|
|
b946deaeea | ||
|
|
ce8ae476b8 | ||
|
|
0bce9e5612 | ||
|
|
de3c2a2e60 | ||
|
|
c1d2de4538 | ||
|
|
5873363e4c | ||
|
|
ef7852773b | ||
|
|
8707b8d1ed | ||
|
|
e7a0dc92d7 | ||
|
|
86ff049f6b | ||
|
|
0e8124e7e8 | ||
|
|
7ccab5ef92 | ||
|
|
02d26a8038 | ||
|
|
8b5cc0888a |
No files matched your search
@@ -1 +0,0 @@
|
||||
{ "contextFileName": "AGENTS.md" }
|
||||
+5
-1
@@ -51,7 +51,7 @@ Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# from box86
|
||||
# Box64
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
@@ -60,6 +60,7 @@ build*/
|
||||
src/git_head.h
|
||||
src/dynacache_hashes.h
|
||||
backup/
|
||||
box64-bundle-x86-libs.sha256
|
||||
|
||||
# Wrapper helper
|
||||
/wrapperhelper/bin
|
||||
@@ -90,3 +91,6 @@ backup/
|
||||
*.zip
|
||||
*.zst
|
||||
*.zstd
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
@@ -1 +0,0 @@
|
||||
IMPORTANT: Ensure you’ve thoroughly reviewed the [AGENTS.md](AGENTS.md) file before beginning any work.
|
||||
+114
-506
@@ -49,6 +49,7 @@ option(BOX32_BINFMT "Also setup binfmt integration for box32" ${BOX32_BINFMT})
|
||||
option(LARCH64_ABI_1 "Set to ON if building for Loongarch64 ABI 1.0 system" ${LARCH64_ABI_1})
|
||||
option(GDBJIT "Set to ON to enable GDB JIT support" ${GDBJIT})
|
||||
option(WOW64 "Set to ON if you want a WOW64 PE build in addition")
|
||||
option(BOX64_KDE_PROFILE_PLUGIN "Build the Dolphin/KIO Box64 profile properties plugin when KF5 or KF6 is available" OFF)
|
||||
|
||||
if(TERMUX)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
@@ -131,18 +132,19 @@ option(STATICBUILD "Set to ON to have a static build (Warning, not working)" ${S
|
||||
option(NO_LIB_INSTALL "Set ON to not install a few x86_64 libs that are used by many program" ${NO_LIB_INSTALL})
|
||||
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
|
||||
|
||||
set(BOX64_PYTHON_MIN_VERSION 3.7)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
find_package(PythonInterp ${BOX64_PYTHON_MIN_VERSION})
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpreter, CMake will exit." )
|
||||
endif()
|
||||
if(${PYTHON_VERSION_MAJOR} LESS 3)
|
||||
message( FATAL_ERROR "You need a Python 3 interpreter, CMake will exit." )
|
||||
if(${PYTHON_VERSION_STRING} VERSION_LESS ${BOX64_PYTHON_MIN_VERSION})
|
||||
message( FATAL_ERROR "You need a Python ${BOX64_PYTHON_MIN_VERSION} or newer interpreter, CMake will exit." )
|
||||
endif()
|
||||
else()
|
||||
find_package(Python3)
|
||||
find_package(Python3 ${BOX64_PYTHON_MIN_VERSION})
|
||||
if(NOT Python3_Interpreter_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpreter, CMake will exit." )
|
||||
message( FATAL_ERROR "You need a Python ${BOX64_PYTHON_MIN_VERSION} or newer interpreter, CMake will exit." )
|
||||
endif()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
@@ -158,6 +160,10 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
include(CheckLinkerFlag)
|
||||
enable_language(C)
|
||||
check_linker_flag(C "-fuse-ld=gold" HAS_FUSE_LD_GOLD)
|
||||
|
||||
if(RPI3ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3ARM64)
|
||||
@@ -241,7 +247,11 @@ elseif(SDORYON1)
|
||||
set(CFLAGS -pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57)
|
||||
elseif(ADLINK)
|
||||
add_definitions(-DADLINK)
|
||||
set(CFLAGS -pipe -mcpu=neoverse-n1 -fuse-ld=gold -fuse-linker-plugin)
|
||||
set(CFLAGS -pipe -mcpu=neoverse-n1)
|
||||
if(HAS_FUSE_LD_GOLD)
|
||||
list(APPEND CFLAGS "-fuse-ld=gold")
|
||||
list(APPEND CFLAGS "-fuse-linker-plugin")
|
||||
endif()
|
||||
elseif(M1)
|
||||
add_definitions(-DM1)
|
||||
set(CFLAGS -pipe -march=armv8.5-a+simd+crypto)
|
||||
@@ -458,6 +468,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX64_ROOT}/src/libtools/signals.c"
|
||||
"${BOX64_ROOT}/src/libtools/sigtools.c"
|
||||
"${BOX64_ROOT}/src/libtools/syscall_user_dispatch.c"
|
||||
"${BOX64_ROOT}/src/libtools/decopcode.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
@@ -466,6 +477,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/tools/alternate.c"
|
||||
"${BOX64_ROOT}/src/tools/callback.c"
|
||||
"${BOX64_ROOT}/src/tools/cleanup.c"
|
||||
"${BOX64_ROOT}/src/tools/cpumask.c"
|
||||
"${BOX64_ROOT}/src/tools/gdbjit.c"
|
||||
"${BOX64_ROOT}/src/tools/fileutils.c"
|
||||
"${BOX64_ROOT}/src/tools/pathcoll.c"
|
||||
@@ -850,6 +862,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtiff5.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbrotlidec.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedzstd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlz4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedproxy.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedssh4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmbclient.c"
|
||||
@@ -1135,6 +1148,10 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f3a.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1143,6 +1160,7 @@ if(LARCH64_DYNAREC)
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_arch.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_consts.c"
|
||||
@@ -1389,7 +1407,95 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
GROUP_READ GROUP_EXECUTE
|
||||
WORLD_READ WORLD_EXECUTE)
|
||||
if(NOT TERMUX)
|
||||
set(BOX64_CONFIGURATOR_OUTPUT ${CMAKE_BINARY_DIR}/bin/box64-configurator)
|
||||
set(BOX64_CONFIGURATOR_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/configurator/build_standalone.py
|
||||
${CMAKE_SOURCE_DIR}/configurator/box64rc.py
|
||||
${CMAKE_SOURCE_DIR}/configurator/configurator.py
|
||||
${CMAKE_SOURCE_DIR}/configurator/configurator.ui
|
||||
${CMAKE_SOURCE_DIR}/configurator/model.py
|
||||
${CMAKE_SOURCE_DIR}/configurator/usage.py
|
||||
${CMAKE_SOURCE_DIR}/configurator/text_en.json
|
||||
${CMAKE_SOURCE_DIR}/configurator/text_zh.json
|
||||
${CMAKE_SOURCE_DIR}/docs/gen/usage.json
|
||||
${CMAKE_SOURCE_DIR}/docs/gen/usage_cn.json)
|
||||
add_custom_command(
|
||||
OUTPUT ${BOX64_CONFIGURATOR_OUTPUT}
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/configurator/build_standalone.py"
|
||||
--output "${BOX64_CONFIGURATOR_OUTPUT}"
|
||||
--configurator-dir "${CMAKE_SOURCE_DIR}/configurator"
|
||||
--usage "${CMAKE_SOURCE_DIR}/docs/gen/usage.json"
|
||||
--usage-cn "${CMAKE_SOURCE_DIR}/docs/gen/usage_cn.json"
|
||||
DEPENDS ${BOX64_CONFIGURATOR_SOURCES}
|
||||
VERBATIM)
|
||||
add_custom_target(box64-configurator ALL DEPENDS ${BOX64_CONFIGURATOR_OUTPUT})
|
||||
install(TARGETS ${BOX64} RUNTIME DESTINATION bin)
|
||||
install(PROGRAMS ${BOX64_CONFIGURATOR_OUTPUT} DESTINATION bin)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64-configurator.desktop DESTINATION share/applications)
|
||||
if(BOX64_KDE_PROFILE_PLUGIN)
|
||||
include(CheckLanguage)
|
||||
check_language(CXX)
|
||||
if(CMAKE_CXX_COMPILER)
|
||||
enable_language(CXX)
|
||||
find_package(ECM QUIET NO_MODULE)
|
||||
if(ECM_FOUND)
|
||||
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR "")
|
||||
|
||||
set(QT_DEFAULT_MAJOR_VERSION 6)
|
||||
find_package(Qt6 QUIET COMPONENTS Core Widgets)
|
||||
find_package(KF6CoreAddons QUIET)
|
||||
find_package(KF6KIO QUIET)
|
||||
if(Qt6_FOUND AND Qt6Widgets_FOUND AND KF6CoreAddons_FOUND AND KF6KIO_FOUND)
|
||||
include(KDEInstallDirs6)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR 6)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_QT_WIDGETS_TARGET Qt6::Widgets)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_KIO_WIDGETS_TARGET KF6::KIOWidgets)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_INSTALL_NAMESPACE "kf6/propertiesdialog")
|
||||
else()
|
||||
set(QT_DEFAULT_MAJOR_VERSION 5)
|
||||
find_package(Qt5 QUIET COMPONENTS Core Widgets)
|
||||
find_package(KF5CoreAddons QUIET)
|
||||
find_package(KF5KIO QUIET)
|
||||
if(Qt5_FOUND AND Qt5Widgets_FOUND AND KF5CoreAddons_FOUND AND KF5KIO_FOUND)
|
||||
include(KDEInstallDirs5)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR 5)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_QT_WIDGETS_TARGET Qt5::Widgets)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_KIO_WIDGETS_TARGET KF5::KIOWidgets)
|
||||
set(_BOX64_KDE_PROFILE_PLUGIN_INSTALL_NAMESPACE "kf5/propertiesdialog")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR)
|
||||
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
endif()
|
||||
set(_BOX64_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
kcoreaddons_add_plugin(box64_profile_propertiesplugin
|
||||
SOURCES ${CMAKE_SOURCE_DIR}/system/kde/box64_profile_propertiesplugin.cpp
|
||||
INSTALL_NAMESPACE "${_BOX64_KDE_PROFILE_PLUGIN_INSTALL_NAMESPACE}")
|
||||
set(BUILD_SHARED_LIBS ${_BOX64_BUILD_SHARED_LIBS})
|
||||
target_link_libraries(box64_profile_propertiesplugin PRIVATE
|
||||
${_BOX64_KDE_PROFILE_PLUGIN_KIO_WIDGETS_TARGET}
|
||||
${_BOX64_KDE_PROFILE_PLUGIN_QT_WIDGETS_TARGET})
|
||||
set_target_properties(box64_profile_propertiesplugin PROPERTIES
|
||||
AUTOMOC ON
|
||||
PREFIX ""
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS OFF)
|
||||
message(STATUS "Building Box64 profile properties dialog plugin for KF${_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR}")
|
||||
else()
|
||||
message(STATUS "Dolphin/KIO Box64 profile plugin disabled: missing Qt5/KF5 or Qt6/KF6 KIO development packages")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Dolphin/KIO Box64 profile plugin disabled: ECM not found")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Dolphin/KIO Box64 profile plugin disabled: C++ compiler not found")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION bin)
|
||||
install(PROGRAMS ${CMAKE_SOURCE_DIR}/system/box64-python DESTINATION bin)
|
||||
@@ -1425,7 +1531,7 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
set(INSTALL_PATH "/usr/lib/box64-x86_64-linux-gnu/")
|
||||
set(INSTALL_PATH "/usr/lib/box64-x86_64-linux-gnu")
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
if(NOT TERMUX AND NOT ANDROID)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
@@ -1574,502 +1680,4 @@ set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVIS
|
||||
endif()
|
||||
INCLUDE(CPack)
|
||||
|
||||
if(NOT ANDROID)
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(bootSyscallC ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(printf ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(args ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(maths1 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(cppThreads_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(cppThreads_nocosim PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x64lib")
|
||||
|
||||
add_test(tlsData ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fpu ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(contexts ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#add_test(conditionalThreads ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(linkingIndirectNoversion ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_asm PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(sse_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(backtrace ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(longjumpInSignals_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21 -D TEST_OUTPUT=tmpfile21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22 -D TEST_OUTPUT=tmpfile22.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87 PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(pshufb ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23 -D TEST_OUTPUT=tmpfile23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24 -D TEST_OUTPUT=tmpfile24.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87cache ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25 -D TEST_OUTPUT=tmpfile25.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26 -D TEST_OUTPUT=tmpfile26.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
set_tests_properties(feround PROPERTIES ENVIRONMENT "BOX64_SYNC_ROUNDING=1")
|
||||
|
||||
add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test27 -D TEST_OUTPUT=tmpfile27.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref27.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(shaext ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test28 -D TEST_OUTPUT=tmpfile28.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref28.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29 -D TEST_OUTPUT=tmpfile29.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test30 -D TEST_OUTPUT=tmpfile30.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref30.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0;BOX64_AVX=2")
|
||||
|
||||
add_test(fpu_rounding ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test31 -D TEST_OUTPUT=tmpfile31.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref31.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(x87pc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test32 -D TEST_OUTPUT=tmpfile32.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref32.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87pc PROPERTIES ENVIRONMENT "BOX64_DYNAREC_X87DOUBLE=2")
|
||||
|
||||
add_test(Boundary ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test33 -D TEST_OUTPUT=tmpfile33.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref33.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#if(NOT CI)
|
||||
# add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01-x64.AppImage -D TEST_OUTPUT=tmpfileAppImage.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
#endif()
|
||||
|
||||
else()
|
||||
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01_android -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(bootSyscallC ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02_android -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(printf ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03_android -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(args ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04_android -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(maths1 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05_android -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06_android -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07_android -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08_android -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09_android -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fpu ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12_android -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12_android.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(linkingIndirectNoversion ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15_android -D TEST_OUTPUT=tmpfile15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# Box64 for Android now have problems with test16, then disable it for now
|
||||
|
||||
#add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16_android -D TEST_OUTPUT=tmpfile16.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# Box64 for Android now have problems with test17, then disable it for now
|
||||
|
||||
#set_tests_properties(sse_asm PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
#add_test(sse_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17_android -D TEST_OUTPUT=tmpfile17.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17_android.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#set_tests_properties(sse_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18_android -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# Android don't have backtrace symbols
|
||||
|
||||
add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20_android -D TEST_OUTPUT=tmpfile20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
# add_test(longjumpInSignals_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21_android -D TEST_OUTPUT=tmpfile21.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22_android -D TEST_OUTPUT=tmpfile22.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22_android.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87 PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(pshufb ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23_android -D TEST_OUTPUT=tmpfile23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24_android -D TEST_OUTPUT=tmpfile24.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87cache ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25_android -D TEST_OUTPUT=tmpfile25.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26_android -D TEST_OUTPUT=tmpfile26.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
set_tests_properties(feround PROPERTIES ENVIRONMENT "BOX64_SYNC_ROUNDING=1")
|
||||
|
||||
# TODO: need to regen test with latest test27.c sources
|
||||
|
||||
#add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test27_android -D TEST_OUTPUT=tmpfile27.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref27.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(shaext ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test28_android -D TEST_OUTPUT=tmpfile28.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref28.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29_android -D TEST_OUTPUT=tmpfile29.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test30_android -D TEST_OUTPUT=tmpfile30.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref30.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
#
|
||||
#set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0 BOX64_AVX=2")
|
||||
|
||||
#add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/hcl-X64.AppImage -D TEST_ARGS2=--help -D TEST_OUTPUT=tmpfileAppImage.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/refAppImage.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
endif()
|
||||
|
||||
if(NOT ANDROID)
|
||||
add_test(NAME xsave_xrstor COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/misc/xsave_xrstor -D TEST_OUTPUT=tmpfile-xsave_xrstor.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/misc/xsave_xrstor.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
else()
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}_android -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BOX32)
|
||||
add_test(NAME bootSyscall_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test01 -D TEST_OUTPUT=tmpfile32_01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME bootSyscallC_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test02 -D TEST_OUTPUT=tmpfile32_02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME printf_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test03 -D TEST_OUTPUT=tmpfile32_03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME args_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile32_04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME maths1_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile32_05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME threadsStart_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test06 -D TEST_OUTPUT=tmpfile32_06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME trig_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test07 -D TEST_OUTPUT=tmpfile32_07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME pi_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test08 -D TEST_OUTPUT=tmpfile32_08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fork_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test09 -D TEST_OUTPUT=tmpfile32_09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME cppThreads_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test10 -D TEST_OUTPUT=tmpfile32_10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
set_tests_properties(cppThreads_32bits_nocosim PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x86lib")
|
||||
|
||||
add_test(NAME tlsData_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test11 -D TEST_OUTPUT=tmpfile32_11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fpu_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test12 -D TEST_OUTPUT=tmpfile32_12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME contexts_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test13 -D TEST_OUTPUT=tmpfile32_13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
if(NOT LD80BITS)
|
||||
add_test(NAME conditionalThreads_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test14 -D TEST_OUTPUT=tmpfile32_14.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
|
||||
add_test(NAME linkingIndirectNoversion_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test15 -D TEST_OUTPUT=tmpfile32_15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectVersion_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test16 -D TEST_OUTPUT=tmpfile32_16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME sse_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17 -D TEST_OUTPUT=tmpfile32_17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(NAME longjumpInSignals_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test18 -D TEST_OUTPUT=tmpfile32_18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME x87_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test19 -D TEST_OUTPUT=tmpfile32_19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(NAME idiv_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test20 -D TEST_OUTPUT=tmpfile32_20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME multiple_dlopen_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test21 -D TEST_OUTPUT=tmpfile32_21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests32/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}_32bits" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/extensions/${testname} -D TEST_OUTPUT=tmpfile32_-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
|
||||
#add_test(NAME sse_optimized_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17_o2 -D TEST_OUTPUT=tmpfile32_17_o2.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17_o2.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#set_tests_properties(sse_optimized_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(bswap_32bits ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test23 -D TEST_OUTPUT=tmpfile32_23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
add_subdirectory(tests)
|
||||
@@ -16,7 +16,7 @@ Box64 enables running x86_64 Linux programs, including games, on non-x86_64 Linu
|
||||
|
||||
Box64 leverages native system libraries (libc, libm, SDL, OpenGL), offering ease of integration and surprising performance in many applications. For performance benchmarks, check [this analysis](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
With DynaRec for Arm, RISC-V and LoongArch platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/). For a more detailed look at Box64 internals and optimization strategies, see our EuroSys 2026 paper, [Practical and Efficient x86-64 Emulation on RISC-V](https://doi.org/10.1145/3767295.3803574), which focuses on RISC-V but covers many techniques that apply more broadly to Box64.
|
||||
With DynaRec for Arm, RISC-V and LoongArch platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/). For a more detailed look at Box64 internals and optimization strategies, see our EuroSys 2026 paper, [Practical and Efficient x86-64 Emulation on RISC-V](https://doi.org/10.1145/3767295.3803574), which focuses on RISC-V but covers many techniques that apply more broadly to Box64.
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
|
||||
|
||||
@@ -58,6 +58,15 @@ Box64 requires 64-bit libraries on the host system, as it directly translates x8
|
||||
1. Box32 is still experimental.
|
||||
2. Some shell scripts (such as the GOG game installer) may rely on `uname -m` to determine the current architecture. Please run them as `box64 script.sh` to allow Box64 to take over.
|
||||
|
||||
Note that DynaCache is now enabled by default (with compression). This will creates files in `~/.cache/box64` to save generated code for executed binaries and libraries, so launch time can be greatly reduced on second run. The files are compressed and will take up to 2Gb by default. You can disable DynaCache writting, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writting there
|
||||
|
||||
```ini
|
||||
[*]
|
||||
BOX64_DYNACACHE=2
|
||||
```
|
||||
|
||||
(or 0 to completly disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
+6
-6
@@ -29,16 +29,16 @@ _Logo 由 @grayduck 制作,感谢!_
|
||||
- `$ box64 ./program [args]` 运行 Linux x86_64 程序。
|
||||
- `$ box64 -k` 杀死所有模拟的进程。
|
||||
- `$ box64-bash` 进入 x86_64 bash 环境。
|
||||
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE_CN.md)。
|
||||
|
||||
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
|
||||
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE_CN.md)。
|
||||
|
||||
---
|
||||
|
||||
## 编译和安装
|
||||
|
||||
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
|
||||
- [编译说明](docs/COMPILE.md)
|
||||
- [安装 Wine](docs/WINE_CN.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -65,7 +65,7 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
|
||||
|
||||
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
|
||||
|
||||
更多信息,请参阅[使用文档](docs/USAGE.md)。
|
||||
更多信息,请参阅[使用文档](docs/USAGE_CN.md)。
|
||||
|
||||
---
|
||||
|
||||
@@ -88,7 +88,7 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
|
||||
|
||||
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
|
||||
|
||||
有关更多信息,请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
有关更多信息,请参阅 [Wine 使用说明](docs/WINE_CN.md)。
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -2,6 +2,12 @@ https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+de
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb,6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb,4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_amd64.deb,b49a24743eb2b6d1198c7cf014ee791bccd5d3223ed8a1e4769d899e1f894a5b
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_i386.deb,1d032b638081704393bc847e2e1f7a00c6894fa262ed0272fb7282962e8915a9
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_amd64.deb,6a4c2d7b127ed18c8c2a558e4d63fcd56de4a154bb9db5fafa7e497f4771dc4a
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_i386.deb,4585064f220490562c132e6fe6a2c46a66d319f6862f60f26e21bccbaadcbd90
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_amd64.deb,833a024051fcfa79208462486c2761b6e1c464676da96e0d3664f4a189449e34
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_i386.deb,5cbd85ab559d99dc5907898488c87b8cf0e117412e0d7981ca7e69e35fbc3f84
|
||||
https://archives.fedoraproject.org/pub/archive/epel/9.5/Everything/x86_64/Packages/m/mbedtls-2.28.8-1.el9.x86_64.rpm,54cb7e43e902a7378e912ecfec470ee30fe69af323d3812cbc39ddebd64790ff
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.i686.rpm,5e4f525f44d538e3467dd13c66010d54f3d12ec4a319829e15a23ff2d0195b5b
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.x86_64.rpm,49f956ad143399c29f5ddf6da6b6fc108ce130d1ed598b4ec5a68b1ff26091de
|
||||
@@ -79,6 +85,8 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i68
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.i686.rpm,4079b9fe93cef0d2ec5b74502ade41a175e1f95e72bace30af29cdcaab037cae
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.x86_64.rpm,5ff471276dcb8c38fe16bf91f963ec4f051954107c3f0ca28fbb3bd2c6521f2b
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm,dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm,e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/zlib-1.2.11-40.el9.i686.rpm,659ee5222028744806be3f822369a726c721aa346eed2882dcf019d83c111e67
|
||||
|
||||
|
@@ -77,10 +77,10 @@ done
|
||||
# reorganize the files
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
mkdir -p "${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
|
||||
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/*.so* usr/lib32/*.so* \
|
||||
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/* usr/lib32/*.so* \
|
||||
"${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
|
||||
mkdir -p "${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
|
||||
mv lib64/*.so* usr/lib/x86_64-linux-gnu/*.so* usr/lib64/*.so* \
|
||||
mv lib64/*.so* usr/lib/x86_64-linux-gnu/* usr/lib64/*.so* \
|
||||
"${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
|
||||
rm -f ./*.tar.* debian-binary files.xml metadata.xml
|
||||
rm -rf ./lib* etc run sbin usr var
|
||||
@@ -130,5 +130,10 @@ for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
|
||||
done
|
||||
done
|
||||
|
||||
# generate a SHA256 checksum of every file and symlink in the bundle
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
find usr \( -type f -o -type l \) -exec "${sha256sum}" {} + \
|
||||
| LC_ALL=C sort --key 2 > "${current_dir}"/box64-bundle-x86-libs.sha256
|
||||
|
||||
# generate the bundle libraries archive
|
||||
tar -C "${dir_tmp}"/bundle-libs -czvf "${current_dir}"/box64-bundle-x86-libs.tar.gz .
|
||||
@@ -0,0 +1,244 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable, List, Optional, Tuple
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SectionKey:
|
||||
kind: str
|
||||
name: str
|
||||
arch: str = ""
|
||||
|
||||
def sort_key(self) -> Tuple[int, str, str]:
|
||||
order = {"shared": 0, "exact": 1, "wildcard": 2, "file": 3}
|
||||
return (order.get(self.kind, 9), self.name.lower(), self.arch.lower())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Assignment:
|
||||
key: str
|
||||
value: str
|
||||
line_index: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RcSection:
|
||||
header: str
|
||||
start: int
|
||||
end: int
|
||||
key: SectionKey
|
||||
assignments: Tuple[Assignment, ...]
|
||||
|
||||
def last_value(self, key: str) -> Optional[str]:
|
||||
return next((item.value for item in reversed(self.assignments) if item.key == key), None)
|
||||
|
||||
|
||||
def normalize_arch(value: Optional[str]) -> str:
|
||||
value = (value or "").strip().strip("`")
|
||||
if value == "<empty>":
|
||||
return ""
|
||||
return value.lower()
|
||||
|
||||
|
||||
def section_key_from_header(header: str, arch: Optional[str] = None) -> SectionKey:
|
||||
name = header.strip()
|
||||
arch_value = normalize_arch(arch)
|
||||
if name == "*":
|
||||
return SectionKey("shared", "*", arch_value)
|
||||
if name.startswith("*") and name.endswith("*") and len(name) > 2:
|
||||
return SectionKey("wildcard", name[1:-1].strip().lower(), arch_value)
|
||||
if name.startswith("/"):
|
||||
return SectionKey("file", name.lower(), arch_value)
|
||||
return SectionKey("exact", name.lower(), arch_value)
|
||||
|
||||
|
||||
def normalize_section_input(value: str) -> str:
|
||||
name = value.strip()
|
||||
if name.startswith("[") or name.endswith("]"):
|
||||
if not (name.startswith("[") and name.endswith("]")):
|
||||
raise ValueError("Invalid section name")
|
||||
name = name[1:-1].strip()
|
||||
|
||||
if not name or any(char in name for char in "\r\n[]#"):
|
||||
raise ValueError("Invalid section name")
|
||||
return name
|
||||
|
||||
|
||||
def header_from_key(key: SectionKey) -> str:
|
||||
if key.kind == "shared":
|
||||
return "*"
|
||||
if key.kind == "wildcard":
|
||||
return f"*{key.name}*"
|
||||
return key.name
|
||||
|
||||
|
||||
def semantic_line(line: str) -> str:
|
||||
return line.rstrip("\n").split("#", 1)[0].strip()
|
||||
|
||||
|
||||
def parse_section_header(line: str) -> Optional[str]:
|
||||
semantic = semantic_line(line)
|
||||
return semantic[1 : semantic.find("]")].strip() if semantic.startswith("[") and "]" in semantic else None
|
||||
|
||||
|
||||
def parse_assignment(line: str) -> Optional[Tuple[str, str]]:
|
||||
semantic = semantic_line(line)
|
||||
if "=" not in semantic:
|
||||
return None
|
||||
key, value = semantic.split("=", 1)
|
||||
key = key.strip()
|
||||
return (key, value.strip()) if key else None
|
||||
|
||||
|
||||
def render_assignment_line(original: str, key: str, value: str) -> str:
|
||||
text = original.rstrip("\n")
|
||||
newline = "\n" if original.endswith("\n") else ""
|
||||
indent = text[: len(text) - len(text.lstrip())]
|
||||
comment = ""
|
||||
comment_start = text.find("#")
|
||||
if comment_start >= 0:
|
||||
comment = " " + text[comment_start:].strip()
|
||||
return f"{indent}{key}={value}{comment}{newline or os.linesep}"
|
||||
|
||||
|
||||
class RcDocument:
|
||||
def __init__(self, path: Path) -> None:
|
||||
self.path = path
|
||||
self.lines: List[str] = []
|
||||
self.sections: List[RcSection] = []
|
||||
self.sections_by_key: Dict[SectionKey, RcSection] = {}
|
||||
self.reload()
|
||||
|
||||
def reload(self) -> None:
|
||||
self.lines = self.path.read_text(encoding="utf-8").splitlines(True) if self.path.is_file() else []
|
||||
self._parse()
|
||||
|
||||
def _parse(self) -> None:
|
||||
builders: List[Dict[str, object]] = []
|
||||
current: Optional[Dict[str, object]] = None
|
||||
|
||||
for index, line in enumerate(self.lines):
|
||||
header = parse_section_header(line)
|
||||
if header is not None:
|
||||
if current is not None:
|
||||
current["end"] = index
|
||||
current = {
|
||||
"header": header,
|
||||
"start": index,
|
||||
"end": len(self.lines),
|
||||
"assignments": [],
|
||||
}
|
||||
builders.append(current)
|
||||
continue
|
||||
|
||||
if current is None:
|
||||
continue
|
||||
|
||||
parsed = parse_assignment(line)
|
||||
if parsed is None:
|
||||
continue
|
||||
key, value = parsed
|
||||
current["assignments"].append(Assignment(key, value, index))
|
||||
|
||||
if current is not None:
|
||||
current["end"] = len(self.lines)
|
||||
|
||||
sections: List[RcSection] = []
|
||||
for builder in builders:
|
||||
assignments = tuple(builder["assignments"])
|
||||
arch = next((item.value for item in reversed(assignments) if item.key == "BOX64_ARCH"), None)
|
||||
key = section_key_from_header(str(builder["header"]), arch)
|
||||
sections.append(
|
||||
RcSection(
|
||||
header=str(builder["header"]),
|
||||
start=int(builder["start"]),
|
||||
end=int(builder["end"]),
|
||||
key=key,
|
||||
assignments=assignments,
|
||||
)
|
||||
)
|
||||
|
||||
self.sections = sections
|
||||
self.sections_by_key = {section.key: section for section in sections}
|
||||
|
||||
def section_for_key(self, key: SectionKey) -> Optional[RcSection]:
|
||||
return self.sections_by_key.get(key)
|
||||
|
||||
def add_section(self, header: str, assignments: Optional[Dict[str, str]] = None) -> RcSection:
|
||||
if self.lines and self.lines[-1].strip():
|
||||
self.lines.append(os.linesep)
|
||||
self.lines.append(f"[{header}]{os.linesep}")
|
||||
for key, value in (assignments or {}).items():
|
||||
self.lines.append(f"{key}={value}{os.linesep}")
|
||||
self._parse()
|
||||
return self.sections[-1]
|
||||
|
||||
def delete_section(self, key: SectionKey) -> None:
|
||||
section = self.section_for_key(key)
|
||||
if section is None:
|
||||
return
|
||||
delete_end = section.end
|
||||
if section.assignments:
|
||||
delete_end = section.assignments[-1].line_index + 1
|
||||
del self.lines[section.start : delete_end]
|
||||
self._parse()
|
||||
|
||||
def set_assignment(self, section_key: SectionKey, key: str, value: str) -> SectionKey:
|
||||
section = self.section_for_key(section_key)
|
||||
if section is None:
|
||||
raise KeyError(section_key)
|
||||
|
||||
matching = [assignment for assignment in section.assignments if assignment.key == key]
|
||||
if matching:
|
||||
line_index = matching[-1].line_index
|
||||
self.lines[line_index] = render_assignment_line(self.lines[line_index], key, value)
|
||||
start = section.start
|
||||
else:
|
||||
insert_at = section.end
|
||||
self.lines.insert(insert_at, f"{key}={value}{os.linesep}")
|
||||
start = section.start
|
||||
|
||||
self._parse()
|
||||
for updated in self.sections:
|
||||
if updated.start == start:
|
||||
return updated.key
|
||||
raise KeyError(section_key)
|
||||
|
||||
def remove_assignment(self, section_key: SectionKey, key: str) -> SectionKey:
|
||||
section = self.section_for_key(section_key)
|
||||
if section is None:
|
||||
raise KeyError(section_key)
|
||||
|
||||
indexes = [assignment.line_index for assignment in section.assignments if assignment.key == key]
|
||||
start = section.start
|
||||
for line_index in reversed(indexes):
|
||||
del self.lines[line_index]
|
||||
|
||||
self._parse()
|
||||
for updated in self.sections:
|
||||
if updated.start == start:
|
||||
return updated.key
|
||||
return section_key
|
||||
|
||||
def save(self) -> None:
|
||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = "".join(self.lines)
|
||||
tmp_path = self.path.with_name(f"{self.path.name}.tmp")
|
||||
tmp_path.write_text(data, encoding="utf-8")
|
||||
if self.path.exists():
|
||||
mode = self.path.stat().st_mode
|
||||
os.chmod(tmp_path, mode)
|
||||
os.replace(tmp_path, self.path)
|
||||
|
||||
|
||||
def copy_assignments(section: RcSection) -> Dict[str, str]:
|
||||
return {assignment.key: assignment.value for assignment in section.assignments}
|
||||
|
||||
|
||||
def direct_box64_assignments(section: Optional[RcSection]) -> Iterable[Assignment]:
|
||||
return () if section is None else tuple(
|
||||
assignment for assignment in section.assignments if assignment.key.startswith("BOX64_")
|
||||
)
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import pprint
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, Sequence
|
||||
|
||||
|
||||
MODULES = {
|
||||
"box64rc": "box64rc.py",
|
||||
"usage": "usage.py",
|
||||
"model": "model.py",
|
||||
"configurator": "configurator.py",
|
||||
}
|
||||
|
||||
UI_FILE = "configurator.ui"
|
||||
|
||||
|
||||
def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Build the standalone box64-configurator script")
|
||||
parser.add_argument("--output", required=True, type=Path)
|
||||
parser.add_argument("--configurator-dir", required=True, type=Path)
|
||||
parser.add_argument("--usage", required=True, type=Path)
|
||||
parser.add_argument("--usage-cn", required=True, type=Path)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def read_modules(configurator_dir: Path) -> Dict[str, str]:
|
||||
return {
|
||||
name: (configurator_dir / filename).read_text(encoding="utf-8")
|
||||
for name, filename in MODULES.items()
|
||||
}
|
||||
|
||||
|
||||
def read_texts(configurator_dir: Path) -> Dict[str, Dict[str, str]]:
|
||||
return {language: read_json(configurator_dir / f"text_{language}.json") for language in ("en", "zh")}
|
||||
|
||||
|
||||
def read_ui(configurator_dir: Path) -> str:
|
||||
return (configurator_dir / UI_FILE).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def read_json(path: Path):
|
||||
with path.open("r", encoding="utf-8") as file:
|
||||
return json.load(file)
|
||||
|
||||
|
||||
def render_script(
|
||||
modules: Dict[str, str],
|
||||
texts: Dict[str, Dict[str, str]],
|
||||
ui: str,
|
||||
usage_data,
|
||||
usage_cn_data,
|
||||
) -> str:
|
||||
return f"""#!/usr/bin/env python3
|
||||
# Generated by configurator/build_standalone.py. Do not edit this file directly.
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import types
|
||||
|
||||
_MODULES = {pprint.pformat(modules, width=120)}
|
||||
_EMBEDDED_TEXTS = {pprint.pformat(texts, width=120)}
|
||||
_EMBEDDED_UI = {pprint.pformat(ui, width=120)}
|
||||
_EMBEDDED_USAGE_DATA = {pprint.pformat(usage_data, width=120)}
|
||||
_EMBEDDED_USAGE_CN_DATA = {pprint.pformat(usage_cn_data, width=120)}
|
||||
|
||||
|
||||
def _load_module(name: str) -> types.ModuleType:
|
||||
module = types.ModuleType(name)
|
||||
module.__file__ = f"<box64-configurator:{{name}}>"
|
||||
module.__package__ = ""
|
||||
if name == "usage":
|
||||
module._EMBEDDED_USAGE_DATA = _EMBEDDED_USAGE_DATA
|
||||
module._EMBEDDED_USAGE_CN_DATA = _EMBEDDED_USAGE_CN_DATA
|
||||
sys.modules[name] = module
|
||||
exec(compile(_MODULES[name], module.__file__, "exec"), module.__dict__)
|
||||
return module
|
||||
|
||||
|
||||
for _name in ("box64rc", "usage", "model"):
|
||||
_load_module(_name)
|
||||
|
||||
_app = types.ModuleType("box64_configurator_app")
|
||||
_app.__file__ = __file__
|
||||
_app.__package__ = ""
|
||||
_app._EMBEDDED_TEXTS = _EMBEDDED_TEXTS
|
||||
_app._EMBEDDED_UI = _EMBEDDED_UI
|
||||
sys.modules["box64_configurator_app"] = _app
|
||||
exec(compile(_MODULES["configurator"], __file__, "exec"), _app.__dict__)
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(_app.main())
|
||||
"""
|
||||
|
||||
|
||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
||||
args = parse_args(argv)
|
||||
configurator_dir = args.configurator_dir.resolve()
|
||||
output = args.output.resolve()
|
||||
|
||||
script = render_script(
|
||||
read_modules(configurator_dir),
|
||||
read_texts(configurator_dir),
|
||||
read_ui(configurator_dir),
|
||||
read_json(args.usage),
|
||||
read_json(args.usage_cn),
|
||||
)
|
||||
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
output.write_text(script, encoding="utf-8")
|
||||
os.chmod(output, 0o755)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Executable
+1354
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="show-close-button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="reload_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="language_combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkBox" id="root_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkPaned" id="main_paned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="sidebar">
|
||||
<property name="width-request">285</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="new_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="margin-start">14</property>
|
||||
<property name="margin-end">14</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">14</property>
|
||||
<property name="margin-end">14</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="mode_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">14</property>
|
||||
<property name="margin-end">14</property>
|
||||
<property name="margin-bottom">8</property>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="user_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="all_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="list_scroll">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="sidebar"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">False</property>
|
||||
<property name="shrink">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="detail_scroll">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStatusbar" id="statusbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,386 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
from .box64rc import (
|
||||
Assignment,
|
||||
RcDocument,
|
||||
RcSection,
|
||||
SectionKey,
|
||||
copy_assignments,
|
||||
direct_box64_assignments,
|
||||
header_from_key,
|
||||
normalize_section_input,
|
||||
section_key_from_header,
|
||||
)
|
||||
from .usage import EnvOption, UsageCatalog
|
||||
except ImportError:
|
||||
from box64rc import (
|
||||
Assignment,
|
||||
RcDocument,
|
||||
RcSection,
|
||||
SectionKey,
|
||||
copy_assignments,
|
||||
direct_box64_assignments,
|
||||
header_from_key,
|
||||
normalize_section_input,
|
||||
section_key_from_header,
|
||||
)
|
||||
from usage import EnvOption, UsageCatalog
|
||||
|
||||
|
||||
ARCH_ALIASES = {
|
||||
"aarch64": "arm64",
|
||||
"arm64": "arm64",
|
||||
"amd64": "x86_64",
|
||||
"loong64": "la64",
|
||||
"loongarch64": "la64",
|
||||
"powerpc64le": "ppc64le",
|
||||
"ppc64le": "ppc64le",
|
||||
"x86_64": "x86_64",
|
||||
}
|
||||
|
||||
|
||||
def box64_arch_from_machine(machine: Optional[str]) -> str:
|
||||
value = (machine or "").strip().lower().replace("-", "_")
|
||||
if value.startswith("riscv64"):
|
||||
return "rv64"
|
||||
return ARCH_ALIASES.get(value, value)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EntryRecord:
|
||||
key: SectionKey
|
||||
display_name: str
|
||||
system_section: Optional[RcSection]
|
||||
user_section: Optional[RcSection]
|
||||
|
||||
@property
|
||||
def editable_source(self) -> str:
|
||||
if self.user_section is not None:
|
||||
return "user"
|
||||
if self.system_section is not None:
|
||||
return "system"
|
||||
return "new"
|
||||
|
||||
@property
|
||||
def arch(self) -> str:
|
||||
return self.key.arch
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ValueState:
|
||||
option: EnvOption
|
||||
value: str
|
||||
source: str
|
||||
|
||||
|
||||
SectionIdentity = Tuple[str, str]
|
||||
|
||||
|
||||
OFTEN_USED_OPTION_NAMES = {
|
||||
"BOX64_DYNAREC_BIGBLOCK",
|
||||
"BOX64_DYNAREC_CALLRET",
|
||||
"BOX64_DYNAREC_SAFEFLAGS",
|
||||
"BOX64_DYNAREC_STRONGMEM",
|
||||
"BOX64_DYNAREC_DIRTY",
|
||||
"BOX64_DYNAREC_FASTROUND",
|
||||
"BOX64_DYNAREC_FASTNAN",
|
||||
"BOX64_MAXCPU",
|
||||
}
|
||||
|
||||
|
||||
PROFILE_OPTION_NAME = "BOX64_PROFILE"
|
||||
PROFILE_DEFAULT_VALUE = "default"
|
||||
PROFILE_SETTINGS = {
|
||||
"safest": (
|
||||
("BOX64_DYNAREC_FASTNAN", "0"),
|
||||
("BOX64_DYNAREC_FASTROUND", "0"),
|
||||
("BOX64_DYNAREC_BIGBLOCK", "0"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "2"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "2"),
|
||||
),
|
||||
"safe": (
|
||||
("BOX64_DYNAREC_BIGBLOCK", "0"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "2"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "1"),
|
||||
),
|
||||
"fast": (
|
||||
("BOX64_DYNAREC_CALLRET", "1"),
|
||||
("BOX64_DYNAREC_BIGBLOCK", "3"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "0"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "1"),
|
||||
("BOX64_DYNAREC_DIRTY", "1"),
|
||||
("BOX64_DYNAREC_FORWARD", "1024"),
|
||||
),
|
||||
"fastest": (
|
||||
("BOX64_DYNAREC_CALLRET", "1"),
|
||||
("BOX64_DYNAREC_BIGBLOCK", "3"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "0"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "0"),
|
||||
("BOX64_DYNAREC_DIRTY", "1"),
|
||||
("BOX64_DYNAREC_FORWARD", "1024"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class ConfigStore:
|
||||
def __init__(
|
||||
self, system_path: Path, user_path: Path, catalog: UsageCatalog, machine_arch: str = ""
|
||||
) -> None:
|
||||
self.catalog = catalog
|
||||
self.machine_arch = machine_arch
|
||||
self.system = RcDocument(system_path)
|
||||
self.user = RcDocument(user_path)
|
||||
self.dirty = False
|
||||
self._entries: Tuple[EntryRecord, ...] = ()
|
||||
self._entries_by_key: Dict[SectionKey, EntryRecord] = {}
|
||||
self._system_sections_by_identity: Dict[SectionIdentity, RcSection] = {}
|
||||
self._user_sections_by_identity: Dict[SectionIdentity, RcSection] = {}
|
||||
self._rebuild_entry_cache()
|
||||
|
||||
def reload(self) -> None:
|
||||
self.system.reload()
|
||||
self.user.reload()
|
||||
self.dirty = False
|
||||
self._rebuild_entry_cache()
|
||||
|
||||
def save(self) -> None:
|
||||
self.user.save()
|
||||
self.reload()
|
||||
|
||||
def entries(self) -> Tuple[EntryRecord, ...]:
|
||||
return self._entries
|
||||
|
||||
def entry_for_key(self, key: SectionKey) -> Optional[EntryRecord]:
|
||||
return self._entries_by_key.get(key)
|
||||
|
||||
def _rebuild_entry_cache(self) -> None:
|
||||
self._system_sections_by_identity = self._effective_sections(self.system)
|
||||
self._user_sections_by_identity = self._effective_sections(self.user)
|
||||
identities = set(self._system_sections_by_identity)
|
||||
identities.update(self._user_sections_by_identity)
|
||||
|
||||
entries: List[EntryRecord] = []
|
||||
for identity in identities:
|
||||
system_section = self._system_sections_by_identity.get(identity)
|
||||
user_section = self._user_sections_by_identity.get(identity)
|
||||
display_section = user_section or system_section
|
||||
if display_section is None:
|
||||
continue
|
||||
display_name = display_section.header if display_section else header_from_key(display_section.key)
|
||||
entries.append(EntryRecord(display_section.key, display_name, system_section, user_section))
|
||||
|
||||
self._entries = tuple(
|
||||
sorted(entries, key=lambda entry: (entry.key.sort_key(), entry.display_name.lower()))
|
||||
)
|
||||
self._entries_by_key = {entry.key: entry for entry in self._entries}
|
||||
|
||||
def _effective_sections(self, document: RcDocument) -> Dict[SectionIdentity, RcSection]:
|
||||
sections: Dict[SectionIdentity, RcSection] = {}
|
||||
for section in document.sections:
|
||||
if not self._section_matches_arch(section):
|
||||
continue
|
||||
|
||||
identity = self._identity(section.key)
|
||||
current = sections.get(identity)
|
||||
if current is None or self._section_replaces(current, section):
|
||||
sections[identity] = section
|
||||
return sections
|
||||
|
||||
def _section_matches_arch(self, section: RcSection) -> bool:
|
||||
return not section.key.arch or section.key.arch == self.machine_arch
|
||||
|
||||
def _section_replaces(self, current: RcSection, candidate: RcSection) -> bool:
|
||||
if candidate.key.arch:
|
||||
return candidate.key.arch == self.machine_arch
|
||||
return not current.key.arch
|
||||
|
||||
def _identity(self, key: SectionKey) -> SectionIdentity:
|
||||
return key.kind, key.name
|
||||
|
||||
def _mark_dirty(self) -> None:
|
||||
self.dirty = True
|
||||
self._rebuild_entry_cache()
|
||||
|
||||
def create_entry(self, header: str) -> SectionKey:
|
||||
normalized = normalize_section_input(header)
|
||||
requested_key = section_key_from_header(normalized)
|
||||
user_section = self.user.section_for_key(requested_key)
|
||||
if user_section is not None:
|
||||
return user_section.key
|
||||
|
||||
section = self.user.add_section(normalized)
|
||||
self._mark_dirty()
|
||||
return section.key
|
||||
|
||||
def delete_user_entry(self, key: SectionKey) -> None:
|
||||
self.user.delete_section(key)
|
||||
self._mark_dirty()
|
||||
|
||||
def fork_entry(self, entry: EntryRecord) -> Tuple[SectionKey, bool]:
|
||||
section, forked = self._ensure_user_section(entry)
|
||||
if forked:
|
||||
self._mark_dirty()
|
||||
return section.key, forked
|
||||
|
||||
def set_option(self, entry: EntryRecord, option_name: str, value: str) -> Tuple[SectionKey, bool]:
|
||||
section, forked = self._ensure_user_section(entry)
|
||||
if self._is_default_profile(option_name, value):
|
||||
new_key = self.user.remove_assignment(section.key, option_name)
|
||||
else:
|
||||
new_key = self.user.set_assignment(section.key, option_name, value)
|
||||
self._mark_dirty()
|
||||
return new_key, forked
|
||||
|
||||
def reset_option(self, entry: EntryRecord, option_name: str) -> SectionKey:
|
||||
user_section = entry.user_section
|
||||
if user_section is None:
|
||||
return entry.key
|
||||
|
||||
system_value = None
|
||||
if entry.system_section is not None:
|
||||
system_value = entry.system_section.last_value(option_name)
|
||||
|
||||
if system_value is not None and not self._is_default_profile(option_name, system_value):
|
||||
new_key = self.user.set_assignment(user_section.key, option_name, system_value)
|
||||
else:
|
||||
new_key = self.user.remove_assignment(user_section.key, option_name)
|
||||
self._mark_dirty()
|
||||
return new_key
|
||||
|
||||
def unsupported_assignments(self, entry: EntryRecord) -> Tuple[Assignment, ...]:
|
||||
section = entry.user_section or entry.system_section
|
||||
return tuple(
|
||||
assignment for assignment in direct_box64_assignments(section) if assignment.key not in self.catalog
|
||||
)
|
||||
|
||||
def effective_values(
|
||||
self, entry: EntryRecord
|
||||
) -> Tuple[List[ValueState], List[ValueState], List[ValueState]]:
|
||||
states: Dict[str, ValueState] = {}
|
||||
|
||||
if entry.key.kind != "shared":
|
||||
self._apply_shared(states)
|
||||
self._apply_matching_wildcards(states, entry)
|
||||
|
||||
self._apply_direct(states, entry)
|
||||
self._apply_profile(states)
|
||||
|
||||
active: List[ValueState] = []
|
||||
often_used: List[ValueState] = []
|
||||
defaults: List[ValueState] = []
|
||||
for option in self.catalog.options:
|
||||
state = states.get(option.name)
|
||||
if state is None:
|
||||
default_state = ValueState(
|
||||
option=option,
|
||||
value=option.default_value,
|
||||
source="default",
|
||||
)
|
||||
if option.name in OFTEN_USED_OPTION_NAMES:
|
||||
often_used.append(default_state)
|
||||
else:
|
||||
defaults.append(default_state)
|
||||
else:
|
||||
active.append(state)
|
||||
|
||||
active.sort(key=lambda state: state.option.name != PROFILE_OPTION_NAME)
|
||||
return active, often_used, defaults
|
||||
|
||||
def _apply_profile(self, states: Dict[str, ValueState]) -> None:
|
||||
profile_option = self.catalog.by_name.get(PROFILE_OPTION_NAME)
|
||||
if profile_option is None:
|
||||
return
|
||||
|
||||
profile_state = states.get(PROFILE_OPTION_NAME)
|
||||
if profile_state is None:
|
||||
profile_state = ValueState(
|
||||
option=profile_option,
|
||||
value=PROFILE_DEFAULT_VALUE,
|
||||
source="default",
|
||||
)
|
||||
states[PROFILE_OPTION_NAME] = profile_state
|
||||
|
||||
for option_name, value in PROFILE_SETTINGS.get(profile_state.value.lower(), ()):
|
||||
if option_name in states:
|
||||
continue
|
||||
option = self.catalog.by_name.get(option_name)
|
||||
if option is None:
|
||||
continue
|
||||
states[option_name] = ValueState(
|
||||
option=option,
|
||||
value=value,
|
||||
source="profile",
|
||||
)
|
||||
|
||||
def _is_default_profile(self, option_name: str, value: Optional[str]) -> bool:
|
||||
return (
|
||||
option_name == PROFILE_OPTION_NAME
|
||||
and (value or "").strip().lower() == PROFILE_DEFAULT_VALUE
|
||||
)
|
||||
|
||||
def _ensure_user_section(self, entry: EntryRecord) -> Tuple[RcSection, bool]:
|
||||
user_section = self.user.section_for_key(entry.key)
|
||||
if user_section is not None:
|
||||
return user_section, False
|
||||
|
||||
if entry.system_section is not None:
|
||||
assignments = copy_assignments(entry.system_section)
|
||||
user_section = self.user.add_section(entry.system_section.header, assignments)
|
||||
return user_section, True
|
||||
|
||||
user_section = self.user.add_section(entry.display_name)
|
||||
return user_section, True
|
||||
|
||||
def _apply_shared(self, states: Dict[str, ValueState]) -> None:
|
||||
for section, source in (
|
||||
(self._system_sections_by_identity.get(("shared", "*")), "shared-system"),
|
||||
(self._user_sections_by_identity.get(("shared", "*")), "shared-user"),
|
||||
):
|
||||
if section is not None:
|
||||
self._apply_assignments(states, section, source)
|
||||
|
||||
def _apply_matching_wildcards(self, states: Dict[str, ValueState], entry: EntryRecord) -> None:
|
||||
if entry.key.kind not in ("exact", "file"):
|
||||
return
|
||||
|
||||
target = entry.key.name.lower()
|
||||
wildcard_identities = {
|
||||
identity
|
||||
for identity in (
|
||||
*self._system_sections_by_identity.keys(),
|
||||
*self._user_sections_by_identity.keys(),
|
||||
)
|
||||
if identity[0] == "wildcard" and identity[1] in target
|
||||
}
|
||||
|
||||
for identity in sorted(wildcard_identities, key=lambda item: item[1]):
|
||||
user_section = self._user_sections_by_identity.get(identity)
|
||||
system_section = self._system_sections_by_identity.get(identity)
|
||||
if user_section is not None:
|
||||
self._apply_assignments(states, user_section, "wildcard-user")
|
||||
elif system_section is not None:
|
||||
self._apply_assignments(states, system_section, "wildcard-system")
|
||||
|
||||
def _apply_direct(self, states: Dict[str, ValueState], entry: EntryRecord) -> None:
|
||||
if entry.user_section is not None:
|
||||
self._apply_assignments(states, entry.user_section, "user")
|
||||
elif entry.system_section is not None:
|
||||
self._apply_assignments(states, entry.system_section, "system")
|
||||
|
||||
def _apply_assignments(
|
||||
self, states: Dict[str, ValueState], section: RcSection, source: str
|
||||
) -> None:
|
||||
for assignment in section.assignments:
|
||||
option = self.catalog.by_name.get(assignment.key)
|
||||
if option is None:
|
||||
continue
|
||||
states[assignment.key] = ValueState(
|
||||
option=option,
|
||||
value=assignment.value,
|
||||
source=source,
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"title": "Box64 Configurator",
|
||||
"filter_all": "All",
|
||||
"filter_user": "User",
|
||||
"search": "Search entries",
|
||||
"new": "New entry",
|
||||
"delete": "Delete user entry",
|
||||
"reload": "Reload",
|
||||
"save": "Save",
|
||||
"select_entry": "Select an entry on the left.",
|
||||
"effective": "Effective options",
|
||||
"often_used": "Often used options",
|
||||
"defaults": "Default values",
|
||||
"unsupported": "Other rcfile keys",
|
||||
"unsupported_help": "These keys are preserved when a system entry is forked, but this tool does not edit them.",
|
||||
"system_note": "This entry comes from the system rcfile. Fork it to edit it in the user rcfile.",
|
||||
"user_note": "This entry is stored in the user rcfile.",
|
||||
"forked": "Created a user fork; save writes it to the user rcfile.",
|
||||
"dirty": "Unsaved changes",
|
||||
"saved": "Saved user rcfile",
|
||||
"source_user": "User",
|
||||
"source_system": "System",
|
||||
"source_shared-user": "User shared",
|
||||
"source_shared-system": "System shared",
|
||||
"source_wildcard-user": "User wildcard",
|
||||
"source_wildcard-system": "System wildcard",
|
||||
"source_profile": "Profile",
|
||||
"source_default": "Default",
|
||||
"default_dynamic": "build dependent",
|
||||
"apply": "Apply",
|
||||
"edit": "Edit",
|
||||
"reset": "Reset",
|
||||
"default_marker": "Default",
|
||||
"new_title": "New entry",
|
||||
"new_prompt": "Executable name",
|
||||
"new_drop_hint": "You can also drag and drop an executable onto the window to create an emtry entry.",
|
||||
"new_global_hint": "Use * to create a global entry.",
|
||||
"cancel": "Cancel",
|
||||
"create": "Create",
|
||||
"delete_title": "Delete user entry?",
|
||||
"delete_body": "Only the user rcfile section will be removed. The system rcfile is not changed.",
|
||||
"delete_action": "Delete",
|
||||
"fork_action": "Fork",
|
||||
"save_changes_title": "Save changes before closing?",
|
||||
"save_changes_body": "Your user rcfile edits have not been saved.",
|
||||
"discard": "Discard",
|
||||
"error": "Error"
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"title": "Box64 配置器",
|
||||
"filter_all": "全部",
|
||||
"filter_user": "用户",
|
||||
"search": "搜索条目",
|
||||
"new": "新建条目",
|
||||
"delete": "删除用户条目",
|
||||
"reload": "重新载入",
|
||||
"save": "保存",
|
||||
"select_entry": "请在左侧选择一个条目。",
|
||||
"effective": "生效选项",
|
||||
"often_used": "常用选项",
|
||||
"defaults": "默认值",
|
||||
"unsupported": "其他配置项",
|
||||
"unsupported_help": "系统条目复制到用户时会保留这些项,但此工具不会编辑它们。",
|
||||
"system_note": "此条目来自系统配置。请先复制到用户后再编辑。",
|
||||
"user_note": "此条目保存在用户配置中。",
|
||||
"forked": "已复制到用户,保存后写入用户配置。",
|
||||
"dirty": "有未保存的修改",
|
||||
"saved": "已保存用户配置",
|
||||
"source_user": "用户",
|
||||
"source_system": "系统",
|
||||
"source_shared-user": "用户共享",
|
||||
"source_shared-system": "系统共享",
|
||||
"source_wildcard-user": "用户通配",
|
||||
"source_wildcard-system": "系统通配",
|
||||
"source_profile": "预设",
|
||||
"source_default": "默认",
|
||||
"default_dynamic": "随构建而定",
|
||||
"apply": "应用",
|
||||
"edit": "编辑",
|
||||
"reset": "重置",
|
||||
"default_marker": "默认",
|
||||
"new_title": "新建条目",
|
||||
"new_prompt": "可执行文件名",
|
||||
"new_drop_hint": "也可以将可执行文件拖放到窗口中来创建新条目。",
|
||||
"new_global_hint": "输入 * 可创建全局条目。",
|
||||
"cancel": "取消",
|
||||
"create": "创建",
|
||||
"delete_title": "删除用户条目?",
|
||||
"delete_body": "只会移除用户配置中的段,系统配置不会被修改。",
|
||||
"delete_action": "删除",
|
||||
"fork_action": "复制到用户",
|
||||
"save_changes_title": "关闭前保存修改?",
|
||||
"save_changes_body": "用户配置的修改尚未保存。",
|
||||
"discard": "放弃",
|
||||
"error": "错误"
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
||||
|
||||
|
||||
PLACEHOLDER_MARKERS = (
|
||||
"XXXX",
|
||||
"YYYY",
|
||||
"ZZZZ",
|
||||
"xxx",
|
||||
"yyy",
|
||||
"zzz",
|
||||
"symbolname",
|
||||
)
|
||||
|
||||
_EMBEDDED_USAGE_DATA: Optional[List[Dict[str, Any]]] = globals().get("_EMBEDDED_USAGE_DATA")
|
||||
_EMBEDDED_USAGE_CN_DATA: Optional[Dict[str, Any]] = globals().get("_EMBEDDED_USAGE_CN_DATA")
|
||||
ALWAYS_CONFIGURATOR_OPTIONS = {"BOX64_PROFILE"}
|
||||
|
||||
|
||||
def clean_choice_value(raw_key: str) -> str:
|
||||
value = str(raw_key).strip()
|
||||
if value.startswith("`") and value.endswith("`") and len(value) >= 2:
|
||||
value = value[1:-1]
|
||||
return "" if value == "<empty>" else value
|
||||
|
||||
|
||||
def is_placeholder_value(value: str) -> bool:
|
||||
return bool(value) and (
|
||||
any(marker in value for marker in PLACEHOLDER_MARKERS) or value.startswith("0x") and "X" in value
|
||||
)
|
||||
|
||||
|
||||
def localized(language: str, english: str, chinese: str) -> str:
|
||||
return (chinese or english) if language == "zh" else english
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Choice:
|
||||
value: str
|
||||
label: str
|
||||
description_en: str
|
||||
description_cn: str
|
||||
is_default: bool
|
||||
is_placeholder: bool
|
||||
|
||||
def description(self, language: str) -> str:
|
||||
return localized(language, self.description_en, self.description_cn)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EnvOption:
|
||||
name: str
|
||||
description_en: str
|
||||
description_cn: str
|
||||
choices: Tuple[Choice, ...]
|
||||
|
||||
@property
|
||||
def allows_custom_value(self) -> bool:
|
||||
return any(choice.is_placeholder for choice in self.choices)
|
||||
|
||||
@property
|
||||
def default_value(self) -> str:
|
||||
return next((choice.value for choice in self.choices if choice.is_default), "")
|
||||
|
||||
def description(self, language: str) -> str:
|
||||
return localized(language, self.description_en, self.description_cn)
|
||||
|
||||
|
||||
class UsageCatalog:
|
||||
def __init__(self, options: Iterable[EnvOption]) -> None:
|
||||
self.options: Tuple[EnvOption, ...] = tuple(options)
|
||||
self.by_name: Dict[str, EnvOption] = {option.name: option for option in self.options}
|
||||
|
||||
def __contains__(self, name: str) -> bool:
|
||||
return name in self.by_name
|
||||
|
||||
|
||||
def find_usage_paths(start: Optional[Path] = None) -> Tuple[Path, Path]:
|
||||
here = (start or Path(__file__)).resolve()
|
||||
for parent in (here.parent, *here.parents):
|
||||
for directory in (parent / "docs" / "gen", parent / "share" / "box64"):
|
||||
usage = directory / "usage.json"
|
||||
usage_cn = directory / "usage_cn.json"
|
||||
if usage.is_file() and usage_cn.is_file():
|
||||
return usage, usage_cn
|
||||
|
||||
raise FileNotFoundError("Could not find usage.json and usage_cn.json")
|
||||
|
||||
|
||||
def load_default_usage_catalog() -> UsageCatalog:
|
||||
if _EMBEDDED_USAGE_DATA is not None and _EMBEDDED_USAGE_CN_DATA is not None:
|
||||
return load_usage_catalog_from_data(_EMBEDDED_USAGE_DATA, _EMBEDDED_USAGE_CN_DATA)
|
||||
|
||||
usage_path, usage_cn_path = find_usage_paths()
|
||||
return load_usage_catalog(usage_path, usage_cn_path)
|
||||
|
||||
|
||||
def load_usage_catalog(usage_path: Path, usage_cn_path: Path) -> UsageCatalog:
|
||||
with usage_path.open("r", encoding="utf-8") as file:
|
||||
english_data = json.load(file)
|
||||
with usage_cn_path.open("r", encoding="utf-8") as file:
|
||||
chinese_data = json.load(file)
|
||||
return load_usage_catalog_from_data(english_data, chinese_data)
|
||||
|
||||
|
||||
def load_usage_catalog_from_data(
|
||||
english_data: Iterable[Dict[str, Any]], chinese_data: Dict[str, Any]
|
||||
) -> UsageCatalog:
|
||||
options: List[EnvOption] = []
|
||||
for entry in english_data:
|
||||
name = entry["name"]
|
||||
if not entry.get("configurator", False) and name not in ALWAYS_CONFIGURATOR_OPTIONS:
|
||||
continue
|
||||
|
||||
chinese_entry = chinese_data.get(name, {})
|
||||
chinese_choices = chinese_entry.get("options", {})
|
||||
choices = []
|
||||
|
||||
for option in entry.get("options", []):
|
||||
raw_key = str(option["key"])
|
||||
value = clean_choice_value(raw_key)
|
||||
choices.append(
|
||||
Choice(
|
||||
value=value,
|
||||
label="<empty>" if value == "" else value,
|
||||
description_en=option.get("description", ""),
|
||||
description_cn=chinese_choices.get(raw_key, ""),
|
||||
is_default=bool(option.get("default", False)),
|
||||
is_placeholder=is_placeholder_value(value),
|
||||
)
|
||||
)
|
||||
|
||||
options.append(
|
||||
EnvOption(
|
||||
name=name,
|
||||
description_en=entry.get("description", ""),
|
||||
description_cn=chinese_entry.get("description", ""),
|
||||
choices=tuple(choices),
|
||||
)
|
||||
)
|
||||
|
||||
return UsageCatalog(options)
|
||||
Vendored
+10
@@ -1,3 +1,13 @@
|
||||
box64 (0.4.4) unstable; urgency=low
|
||||
|
||||
This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
|
||||
=> A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
|
||||
=> DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
|
||||
=> You can use box64-configurator on the special `[*]` profile to change default values
|
||||
=> More improvements on emulation accuracy that help running more DRM'd games
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 2 Aug 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.4.2) unstable; urgency=low
|
||||
|
||||
This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
v0.4.4
|
||||
======
|
||||
|
||||
Highlights:
|
||||
* This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
|
||||
=> A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
|
||||
=> DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
|
||||
=> You can use box64-configurator on the special `[*]` profile to change default values
|
||||
=> More improvements on emulation accuracy that help running more DRM'd games
|
||||
|
||||
Version summary:
|
||||
|
||||
* RCFILE: Created a new GUI tools to edit custom rcfile: box64-configurator
|
||||
* RCFILE: Created a KDE plugin to quickly set box64 properties for an executable file
|
||||
* RCFILE: Added more profiles
|
||||
* RCFILE: Added BOX64_SKIPCPU to avoid using N first cores (for big.LITTLE configuration)
|
||||
* ELF: Some more Relocation handling
|
||||
* Wrapping: Improved MALLOC_HACK=2 behaviour
|
||||
* Wrapping: more fixes to some functions signatures
|
||||
* Wrapping: added more wrapped functions
|
||||
* Wrapping: added some more wrapped libraries
|
||||
* Wrapping: Added more Syscall
|
||||
* Wrapping: Some rework on the bridges to avoid unexpected reuse of bridges for different function signature
|
||||
* Wrapping: Box32: Some fixes and improvement on some wrapped functions
|
||||
* Emulation: Some improvement on handling of x87 80bits values
|
||||
* Emulation: Added some deferred signal support for improved stability
|
||||
* Emulation: Improved TF handling
|
||||
* Emulation: Improved CPUID handling
|
||||
* Emulation: optimised some sha1 function
|
||||
* Emulation: LA64: Enabled AVX by default (on par with ARM64)
|
||||
* Interpreter: A few fixes in some opcodes
|
||||
* Interpreter: Added unaligned handling of more lock opcodes
|
||||
* DynaCache: many improvements and fixes
|
||||
* DynaCache: added libz compression of the dynacache files
|
||||
* DynaCache: added disk size limit, to purge old/outdated dynacache once a threshold is reached
|
||||
* Dynarec: Many small opcodes optimisation here and there
|
||||
* Dynarec: Some improvement on handling of x87 80bits values
|
||||
* Dynarec: Optimised the internal jump handling while building a dynablock
|
||||
* Dynarec: Improved TF handling
|
||||
* Dynarec: Reworked Alt Address handling
|
||||
* Dynarec: Reworked a bit the jump table to save some memory
|
||||
* Dynarec: Made BOX64_CALLRET=2 default
|
||||
* Dynarec: ARM64: Some improvement in some x87 opcodes handling
|
||||
* Dynarec: ARM64: A few fixes to some opcodes
|
||||
* Dynarec: LA64: Added optimisation on the zeroing out of the upper 32 bits of registers
|
||||
* Dynarec: LA64: Added a Dynarec version of UpdateFlags (on par with ARM64)
|
||||
* Dynarec: LA64: More work FASTNAN / FASTROUND handling
|
||||
* Dynarec: LA64: Many fixes on many opcodes
|
||||
* Dynarec: LA64: Added a few opcodes
|
||||
* Dynarec: LA64: Added fastpath on many logical opcodes (when no flags are needed)
|
||||
* Dynarec: LA64: AES opcodes optimisations
|
||||
* Dynarec: LA64: Improved Native flags use for more cases
|
||||
* Dynarec: LA64: Improved jump_safe macro (removing many useless NOP)
|
||||
* Dynarec: RV64: Improvement on flags handling (on par with ARM64 & LA64)
|
||||
* Dynarec: RV64: Many fixes on NaN handling
|
||||
* Dynarec: RV64: Some fixes to various opcodes
|
||||
* Dynarec: RV64: Improved Native Flags handling
|
||||
* Dynarec: RV64: Added some opcodes
|
||||
* Dynarec: RV64: Detect and use the new Zicbop/Zicond/Zicbom cpu extension when available
|
||||
* WrapperHelper: some more improvements and fixes
|
||||
|
||||
v0.4.2
|
||||
======
|
||||
|
||||
|
||||
+11
-11
@@ -3,7 +3,7 @@ Compiling/Installing
|
||||
|
||||
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-built-packages) for alternatives.
|
||||
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-Compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-Compiling)
|
||||
|
||||
@@ -15,7 +15,7 @@ Additional installation steps may be necessary when copying only the box64 execu
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. ${OPTIONS}
|
||||
make -j4
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
@@ -288,13 +288,13 @@ To have a trace enabled build (***the interpreter will be slightly slower***), a
|
||||
|
||||
#### Build DynaRec
|
||||
|
||||
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
|
||||
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
|
||||
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
|
||||
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
|
||||
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
|
||||
#### Save memory at run time
|
||||
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. For now, it only increases the jumptable from 4 levels to 5. The added granularity avoids wasting space, but adds one more read from memory when jumping between blocks.
|
||||
You can use `-DSAVE_MEM=ON` to build Box64 with memory-saving optimizations. This uses a five-level jump table to reduce unused address-space allocations and enables secondary entry points (BOX64_DYNAREC_SEP=1) by default to reduce duplicate DynaRec blocks. These optimizations may reduce memory usage at the cost of additional memory accesses and lower performance on some workloads.
|
||||
|
||||
#### Build outside of a git repo
|
||||
|
||||
@@ -326,9 +326,9 @@ Box64 can also be packaged into a .deb file ***using the source code zip from th
|
||||
|
||||
## Pre-built packages
|
||||
|
||||
### Debian-based Linux
|
||||
### Debian-based Linux
|
||||
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
# check if .list file already exists
|
||||
@@ -358,12 +358,12 @@ sudo apt update
|
||||
sudo apt install box64-generic-arm -y
|
||||
```
|
||||
|
||||
## Cross-Compiling
|
||||
## Cross-Compiling
|
||||
----
|
||||
### Set Up the Cross-Compiler
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
|
||||
### Run CMake with Cross-Compilation Options
|
||||
### Run CMake with Cross-Compilation Options
|
||||
Follow the per-platform compilation instructions to configure the CMake options for your target architecture.
|
||||
In particular, you must specify the cross-compiler. For example:
|
||||
```
|
||||
|
||||
@@ -14,6 +14,11 @@ Linux Steam requires Box86 or Box32 and it's binfmt enabled, check [Compilation
|
||||
steam
|
||||
```
|
||||
|
||||
For additional stability with Box64 when Box86 is unavailable, it is recommended to use the new 64-bit-only runtime for the Steam client.
|
||||
|
||||
- Steam > Settings > Interface > Client Beta Participation: Steam Beta > Restart Now
|
||||
- Steam > Settings > Interface > Use experimental SteamRT3 Steam Client: On > Restart Now
|
||||
|
||||
## Install and run Windows Steam
|
||||
|
||||
It's simple, just download it from Steam website and install it like other Windows applications.
|
||||
+68
-49
@@ -71,22 +71,22 @@ Enable building bigger DynaRec code blocks for better performance. Available in
|
||||
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
|
||||
* 1: Build DynaRec block as big as possible.
|
||||
* 2: Build DynaRec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
|
||||
* 3: Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
|
||||
* 3: Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for Wine programs.
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
|
||||
* 0: Do not optimize CALL/RET, use jump table. [Default]
|
||||
* 0: Do not optimize CALL/RET, use jump table.
|
||||
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0: Do not add SEP at CALLRET return
|
||||
* 1: Add SEP at CALLRET return, on memory that are from known binary files [Default]
|
||||
* 0: Do not add SEP at CALLRET return [Default]
|
||||
* 1: Add SEP at CALLRET return, on memory that are from known binary files
|
||||
* 2: Add SEP at CALLRET return for all type of memory.
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
@@ -128,11 +128,13 @@ Enable or disable fast rounding. Available in WowBox64.
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
Define max allowed forward value when building block. Available in WowBox64.
|
||||
Define max allowed forward value when building block. Only 0, 128, 256, 512 and 1024 are valid; other values fall back to 128. Available in WowBox64.
|
||||
|
||||
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
|
||||
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
|
||||
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
|
||||
* 256: Allow up to 256 bytes of gap between end of the block and the next forward jump.
|
||||
* 512: Allow up to 512 bytes of gap between end of the block and the next forward jump.
|
||||
* 1024: Allow up to 1024 bytes of gap between end of the block and the next forward jump.
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
@@ -175,12 +177,49 @@ Use volatile metadata parsed from PE files, only valid for 64bit Windows games.
|
||||
* 0: Do not use volatile metadata.
|
||||
* 1: Use volatile metadata, which will guide Box64 for better strong memory emulation. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 1 (enable). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
|
||||
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
|
||||
* 1: Wait for a DynaRec code block to be ready. [Default]
|
||||
* 0: Disable DynaCache.
|
||||
* 1: Enable DynaCache. [Default]
|
||||
* 2: Use DynaCache files if present, but do not generate new one.
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
|
||||
|
||||
* XXXX: Use folder XXXX for DynaCache files.
|
||||
|
||||
### BOX64_DYNACACHE_LIMIT
|
||||
|
||||
Maximum size, in MiB, for the DynaCache folder. When the limit is exceeded, invalid DynaCache files are removed first, then the oldest valid files are removed if needed. Default size is 2048MiB.
|
||||
|
||||
* 0: Do not limit the DynaCache folder size.
|
||||
* XXXX: Keep the DynaCache folder below XXXX MiB by removing invalid cache files first, then the oldest valid cache files.
|
||||
* 2048: A size of 2048 MiB is the default value. [Default]
|
||||
|
||||
### BOX64_DYNACACHE_COMPRESS
|
||||
|
||||
Compress or not DynaCache files on disk
|
||||
|
||||
* 0: Do not compress dynacache files
|
||||
* 1: Compress dynacache files using Zlib with fastest compression. [Default]
|
||||
* 2: Compress dynacache files using ZLib with default compression.
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 30KB
|
||||
|
||||
* XXXX: Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 30: A size of 30 KB is the default value. [Default]
|
||||
|
||||
### BOX64_SKIPCPU
|
||||
|
||||
Skip N first CPU cores (Is apply before MAXCPU) Available in WowBox64.
|
||||
|
||||
* 0: Do not skip any CPU cores. [Default]
|
||||
* XXXX: Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
@@ -254,7 +293,7 @@ Specify the architecture in rcfiles to which the current entry applies. This opt
|
||||
|
||||
### BOX64_AVX
|
||||
|
||||
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 because it's fully implemented in DynaRec, 0 otherwise. Available in WowBox64.
|
||||
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 and LoongArch64 because it's fully implemented in DynaRec, 0 otherwise. Available in WowBox64.
|
||||
|
||||
* 0: Do not expose AVX capabilities.
|
||||
* 1: Expose AVX, BMI1, F16C and VAES extensions to CPUID and cpuinfo file.
|
||||
@@ -543,6 +582,7 @@ Enable DynaRec dump. Available in WowBox64.
|
||||
* 0: Do not dump DynaRec blocks. [Default]
|
||||
* 1: Dump DynaRec blocks.
|
||||
* 2: Dump DynaRec blocks with some colors.
|
||||
* 3: Dump only x86 and translated native instructions.
|
||||
|
||||
### BOX64_DYNAREC_DUMP_RANGE
|
||||
|
||||
@@ -550,6 +590,13 @@ Dump DynaRec blocks in the specified range. Available in WowBox64.
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where DynaBlock gets dumped (inclusive-exclusive).
|
||||
|
||||
### BOX64_DYNAREC_DISASM
|
||||
|
||||
Try to initialize libZydis for more readable x86 disassembly in dump, trace, crash report, etc.
|
||||
|
||||
* 0: Do not load Zydis for Dynarec. [Default]
|
||||
* 1: Try to load Zydis for Dynarec.
|
||||
|
||||
### BOX64_DYNAREC_GDBJIT
|
||||
|
||||
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
|
||||
@@ -732,6 +779,7 @@ Same as BOX64_TRACE but starts the trace immediately.
|
||||
* 1: Enable trace output. Trace starts before the initialization of dependencies.
|
||||
* symbolname: Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: Enable trace output only for the specified address list. Trace starts before the initialization of dependencies.
|
||||
|
||||
### BOX64_TRACE_START
|
||||
|
||||
@@ -756,6 +804,7 @@ Only available on box64 build with trace. Adds trace of all instructions execute
|
||||
* 1: Enable trace output.
|
||||
* symbolname: Enable trace output for `symbolname` only.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive).
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: Enable trace output only for the specified address list.
|
||||
|
||||
## Environment
|
||||
|
||||
@@ -787,6 +836,13 @@ Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
* 4096: Default age threshold. [Default]
|
||||
* XXXX: Custom age threshold (range: 10-65536).
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
|
||||
|
||||
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
|
||||
* 1: Wait for a DynaRec code block to be ready. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
Tweak the memory barriers to reduce the performance impact by strong memory emulation. Available in WowBox64.
|
||||
@@ -795,43 +851,6 @@ Tweak the memory barriers to reduce the performance impact by strong memory emul
|
||||
* 1: Use weak barriers to have more performance boost. [Default]
|
||||
* 2: All in 1, plus disable the last write barriers.
|
||||
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
|
||||
* 0: Disable DynaCache.
|
||||
* 1: Enable DynaCache.
|
||||
* 2: Use DynaCache files if present, but do not generate new one. [Default]
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
|
||||
|
||||
* XXXX: Use folder XXXX for DynaCache files.
|
||||
|
||||
### BOX64_DYNACACHE_LIMIT
|
||||
|
||||
Maximum size, in MiB, for the DynaCache folder. When the limit is exceeded, invalid DynaCache files are removed first, then the oldest valid files are removed if needed. Default size is 2048MiB.
|
||||
|
||||
* 0: Do not limit the DynaCache folder size.
|
||||
* XXXX: Keep the DynaCache folder below XXXX MiB by removing invalid cache files first, then the oldest valid cache files.
|
||||
* 2048: A size of 2048 MiB is the default value. [Default]
|
||||
|
||||
### BOX64_DYNACACHE_COMPRESS
|
||||
|
||||
Compress or not DynaCache files on disk
|
||||
|
||||
* 0: Do not compress dynacache files
|
||||
* 1: Compress dynacache files using Zlib with fastest compression. [Default]
|
||||
* 2: Compress dynacache files using ZLib with default compression.
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
|
||||
|
||||
* XXXX: Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 350: A size of 350 KB is the default value. [Default]
|
||||
|
||||
## Libraries
|
||||
|
||||
### BOX64_ADDLIBS
|
||||
|
||||
+77
-58
@@ -71,22 +71,22 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 0: 不尝试构建尽可能大的代码块,适用于使用大量线程和 JIT 的程序(如 Unity)。
|
||||
* 1: 尽可能构建大的代码块。
|
||||
* 2: 构建更大的代码块,代码块重叠时不停止,但仅针对 elf 内存中的代码块。 [默认值]
|
||||
* 3: 构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 wine 程序有用。
|
||||
* 3: 构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 Wine 程序有用。
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
优化 CALL/RET 指令。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不优化 CALL/RET,使用跳转表。 [默认值]
|
||||
* 0: 不优化 CALL/RET,使用跳转表。
|
||||
* 1: 尝试优化 CALL/RET,在可能的情况下跳过跳转表。
|
||||
* 2: 尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。
|
||||
* 2: 尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不在 CALLRET 返回时添加 SEP。
|
||||
* 1: 在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。 [默认值]
|
||||
* 0: 不在 CALLRET 返回时添加 SEP。 [默认值]
|
||||
* 1: 在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。
|
||||
* 2: 在 CALLRET 返回时添加 SEP,适用于所有类型的内存。
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
@@ -128,11 +128,13 @@ BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
定义构建代码块时允许的最大前向跳转值。 在 WowBox64 中可用。
|
||||
定义构建代码块时允许的最大前向跳转值。仅接受 0、128、256、512 和 1024;其他值将回退为 128。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 无前向跳转值。当前代码块结束时,即使存在之前的前向跳转也不尝试继续前进。
|
||||
* 128: 允许代码块结束与下一个前向跳转之间最多 128 字节的间隙。 [默认值]
|
||||
* XXXX: 允许代码块结束与下一个前向跳转之间最多 XXXX 字节的间隙。
|
||||
* 256: 允许代码块结束与下一个前向跳转之间最多 256 字节的间隙。
|
||||
* 512: 允许代码块结束与下一个前向跳转之间最多 512 字节的间隙。
|
||||
* 1024: 允许代码块结束与下一个前向跳转之间最多 1024 字节的间隙。
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
@@ -175,12 +177,49 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 0: 不使用 volatile 元数据。
|
||||
* 1: 使用 volatile 元数据,将指导 Box64 进行更好的强内存模拟。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
是否等待代码块构建完成。 在 WowBox64 中可用。
|
||||
启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 1(启用)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。
|
||||
|
||||
* 0: 不等待,改用解释器,可能在大量多线程或 JIT 程序上略微加速。
|
||||
* 1: 等待代码块构建完成。 [默认值]
|
||||
* 0: 禁用 DynaCache。
|
||||
* 1: 启用 DynaCache。 [默认值]
|
||||
* 2: 使用已有的 DynaCache 文件,但不生成新的。
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
设置 DynaCache 文件的文件夹。默认为 $XDG_CACHE_HOME/box64,如果 $XDG_CACHE_HOME 未设置则为 $HOME/.cache/box64。
|
||||
|
||||
* XXXX: 使用文件夹 XXXX 存储 DynaCache 文件。
|
||||
|
||||
### BOX64_DYNACACHE_LIMIT
|
||||
|
||||
DynaCache 文件夹的最大大小(MiB)。超过限制时,会先删除无效的 DynaCache 文件,如仍超限再删除最旧的有效文件。默认大小为 2048MiB。
|
||||
|
||||
* 0: 不限制 DynaCache 文件夹大小。
|
||||
* XXXX: 先删除无效缓存文件,如仍超限再删除最旧的有效缓存文件,将 DynaCache 文件夹保持在 XXXX MiB 以下。
|
||||
* 2048: 默认值为 2048 MiB。 [默认值]
|
||||
|
||||
### BOX64_DYNACACHE_COMPRESS
|
||||
|
||||
设置是否压缩磁盘上的 DynaCache 文件。
|
||||
|
||||
* 0: 不压缩 DynaCache 文件。
|
||||
* 1: 使用 Zlib 最快压缩级别压缩 DynaCache 文件。 [默认值]
|
||||
* 2: 使用 Zlib 默认压缩级别压缩 DynaCache 文件。
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
DynaCache 写入磁盘的最小大小(KB)。默认大小为 30KB。
|
||||
|
||||
* XXXX: 设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。
|
||||
* 30: 默认值为 30 KB。 [默认值]
|
||||
|
||||
### BOX64_SKIPCPU
|
||||
|
||||
Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
|
||||
|
||||
* 0: Do not skip any CPU cores. [默认值]
|
||||
* XXXX: Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
@@ -220,6 +259,13 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 4096: 默认年龄阈值。 [默认值]
|
||||
* XXXX: 自定义年龄阈值(范围:10-65536)。
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
是否等待代码块构建完成。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不等待,改用解释器,可能在大量多线程或 JIT 程序上略微加速。
|
||||
* 1: 等待代码块构建完成。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
调整内存屏障以减少强内存模拟的性能影响。 在 WowBox64 中可用。
|
||||
@@ -228,43 +274,6 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 1: 使用弱屏障以获得更多性能提升。 [默认值]
|
||||
* 2: 包含 1 的全部内容,外加禁用最后的写屏障。
|
||||
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 2(读取已有缓存但不生成新的)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。
|
||||
|
||||
* 0: 禁用 DynaCache。
|
||||
* 1: 启用 DynaCache。
|
||||
* 2: 使用已有的 DynaCache 文件,但不生成新的。 [默认值]
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
设置 DynaCache 文件的文件夹。默认为 $XDG_CACHE_HOME/box64,如果 $XDG_CACHE_HOME 未设置则为 $HOME/.cache/box64。
|
||||
|
||||
* XXXX: 使用文件夹 XXXX 存储 DynaCache 文件。
|
||||
|
||||
### BOX64_DYNACACHE_LIMIT
|
||||
|
||||
DynaCache 文件夹的最大大小(MiB)。超过限制时,会先删除无效的 DynaCache 文件,如仍超限再删除最旧的有效文件。默认大小为 2048MiB。
|
||||
|
||||
* 0: 不限制 DynaCache 文件夹大小。
|
||||
* XXXX: 先删除无效缓存文件,如仍超限再删除最旧的有效缓存文件,将 DynaCache 文件夹保持在 XXXX MiB 以下。
|
||||
* 2048: 默认值为 2048 MiB。 [默认值]
|
||||
|
||||
### BOX64_DYNACACHE_COMPRESS
|
||||
|
||||
设置是否压缩磁盘上的 DynaCache 文件。
|
||||
|
||||
* 0: 不压缩 DynaCache 文件。
|
||||
* 1: 使用 Zlib 最快压缩级别压缩 DynaCache 文件。 [默认值]
|
||||
* 2: 使用 Zlib 默认压缩级别压缩 DynaCache 文件。
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
|
||||
* XXXX: 设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。
|
||||
* 350: 默认值为 350 KB。 [默认值]
|
||||
|
||||
## 兼容性
|
||||
|
||||
### BOX64_AES
|
||||
@@ -285,7 +294,7 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
|
||||
### BOX64_AVX
|
||||
|
||||
向 CPUID 和 cpuinfo 文件暴露 AVX 扩展。在 Arm64 上默认值为 2,因为 DynaRec 已完全实现,其他架构默认为 0。 在 WowBox64 中可用。
|
||||
向 CPUID 和 cpuinfo 文件暴露 AVX 扩展。在 Arm64 和龙架构上默认值为 2,因为 DynaRec 已完全实现,其他架构默认为 0。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不暴露 AVX 能力。
|
||||
* 1: 向 CPUID 和 cpuinfo 文件暴露 AVX、BMI1、F16C 和 VAES 扩展。
|
||||
@@ -316,7 +325,7 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。
|
||||
|
||||
* 0: 不检测 MonoBleedingEdge。
|
||||
* 1: 检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_强内存模型=1。 [默认值]
|
||||
* 1: 检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_STRONGMEM=1。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_DIV0
|
||||
|
||||
@@ -380,7 +389,7 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
检测 libjvm 并应用保守设置。
|
||||
|
||||
* 0: 不执行任何操作。
|
||||
* 1: 检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_强内存模型=1 BOX64_SSE42=0。 [默认值]
|
||||
* 1: 检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0。 [默认值]
|
||||
|
||||
### BOX64_LIBCEF
|
||||
|
||||
@@ -428,10 +437,10 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
|
||||
预定义的环境变量集合,以兼容性或性能为导向。 在 WowBox64 中可用。
|
||||
|
||||
* safest: 禁用所有不安全的 DynaRec 优化的配置文件。
|
||||
* safe: 比 safest 略不安全。
|
||||
* safest: 禁用所有不安全的优化。
|
||||
* safe: 仅启用小部分不安全的优化。
|
||||
* default: 大多数程序都能正常运行且性能适中的默认设置。 [默认值]
|
||||
* fast: 启用许多不安全的优化,但同时启用 强内存模型 模拟。
|
||||
* fast: 启用许多不安全的优化,但同时启用强内存模型模拟。
|
||||
* fastest: 启用许多不安全的优化以获得更好的性能。
|
||||
|
||||
### BOX64_PYTHON3
|
||||
@@ -476,10 +485,10 @@ python3 可执行文件的路径。
|
||||
|
||||
### BOX64_SSE_FLUSHTO0
|
||||
|
||||
SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常FLAGS。 在 WowBox64 中可用。
|
||||
SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常 FLAGS。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 仅追踪FLAGS。 [默认值]
|
||||
* 1: 直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常FLAGS(如果可用)。
|
||||
* 0: 仅追踪 FLAGS。 [默认值]
|
||||
* 1: 直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常 FLAGS(如果可用)。
|
||||
|
||||
### BOX64_SSE42
|
||||
|
||||
@@ -514,7 +523,7 @@ SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常FLAGS。 在 WowBox64 中
|
||||
告诉 Box64 这是一个 Unity 游戏。
|
||||
|
||||
* 0: 不执行任何操作。
|
||||
* 1: 这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_强内存模型=1。 [默认值]
|
||||
* 1: 这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_STRONGMEM=1。 [默认值]
|
||||
|
||||
### BOX64_X11GLX
|
||||
|
||||
@@ -710,6 +719,7 @@ x87 80 位 long double 的行为。 在 WowBox64 中可用。
|
||||
* 0: 不转储代码块。 [默认值]
|
||||
* 1: 转储代码块。
|
||||
* 2: 转储代码块并带有颜色。
|
||||
* 3: 仅转储 x86 指令和翻译后的本机指令。
|
||||
|
||||
### BOX64_DYNAREC_DUMP_RANGE
|
||||
|
||||
@@ -717,6 +727,13 @@ x87 80 位 long double 的行为。 在 WowBox64 中可用。
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: 定义代码块 被转储的范围(左闭右开)。
|
||||
|
||||
### BOX64_DYNAREC_DISASM
|
||||
|
||||
尝试初始化 libZydis,以在转储、追踪、崩溃报告等场景中获得更具可读性的 x86 反汇编结果。
|
||||
|
||||
* 0: 不为 Dynarec 加载 Zydis。 [默认值]
|
||||
* 1: 尝试为 Dynarec 加载 Zydis。
|
||||
|
||||
### BOX64_DYNAREC_GDBJIT
|
||||
|
||||
GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb 命令启用:jit-reader-load /usr/local/lib/libbox64gdbjitreader.so。
|
||||
@@ -899,6 +916,7 @@ GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb
|
||||
* 1: 启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
* symbolname: 仅对 `symbolname` 启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
* 0xXXXXXXX-0xYYYYYYY: 对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: 对指定的地址列表启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
|
||||
### BOX64_TRACE_START
|
||||
|
||||
@@ -923,4 +941,5 @@ GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb
|
||||
* 1: 启用追踪输出。
|
||||
* symbolname: 仅对 `symbolname` 启用追踪输出。
|
||||
* 0xXXXXXXX-0xYYYYYYY: 对指定地址范围(左闭右开)启用追踪输出。
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: 对指定地址列表启用追踪输出。
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# 在 Box64 上使用 Wine 的指南
|
||||
|
||||
Wine 不是一个模拟器,但 Box64 是。Box64 以多种方式支持 Wine。在继续阅读之前,你应该对 Wine 有基本的了解。
|
||||
|
||||
## Wine 的变体
|
||||
|
||||
Wine 以多种形式发布:
|
||||
|
||||
|
||||
1. **x86 Wine**
|
||||
|
||||
**x86 Wine** 的可执行文件架构是 x86,它运行 x32 Windows 可执行文件。
|
||||
|
||||
x86 Wine 需要 32 位环境(读取 32 位 Linux 库),因为该架构天然的特点,这在 x86_64 机器上通常可用。
|
||||
|
||||
但是,当你尝试在 RISC 架构上通过模拟器运行它时,情况则有些不同。对于 Arm64,存在 armhf 这样的 32 位环境,也有为 armhf 设计的 Box86,因此你可以使用 Box86 运行 **x86 Wine**。
|
||||
|
||||
然而,对于 RISC-V 64、LoongArch64 以及许多较新的 Arm64 核心,32 位环境并不可用。Box64 引入了一种名为 Box32 的新模式,可以在编译时通过 CMake 选项 `BOX32` 启用。它本质上利用 64 位环境模拟 32 位环境,因此可以用来运行 x86 Wine。但请注意,Box32 仍是高度实验性且不稳定的。
|
||||
|
||||
2. **x86_64 Wine**
|
||||
|
||||
**x86_64 Wine** 的可执行文件架构是 x86_64,它运行 x64 Windows 可执行文件。
|
||||
|
||||
它可以与 Box64 配合使用。注意,**x86_64 Wine** 通常自带 **x86 Wine**。因此你可以结合使用 Box86 + Box64,或者仅使用启用了 Box32 的 Box64,来无缝运行 32 位和 64 位可执行文件。
|
||||
|
||||
3. **x86_64 Wine WOW64**
|
||||
|
||||
**x86_64 Wine WOW64** 的可执行文件架构是 x86_64,它同时能运行 x32 和 x64 Windows 可执行文件。
|
||||
|
||||
**x86_64 Wine WOW64** 的优点在于它运行 32 位 Windows 可执行文件时不需要 32 位环境,因为 32 位环境模拟已由 Wine WOW64 自身处理。
|
||||
|
||||
这意味着你可以只使用 Box64(无需 Box32)来运行 32 位 Windows 可执行文件。然而缺点是,对于 32 位程序,WineD3D 的性能相当差(请使用 DXVK!)。
|
||||
|
||||
4. **Arm64 Wine WOW64**
|
||||
|
||||
**Arm64 Wine WOW64** 的可执行文件架构是 Arm64,它能运行 x32、x64、Arm32 和 Arm64 的 Windows 可执行文件。
|
||||
|
||||
但是,要运行 x32 和 x64 的程序,需要一个 cpu.dll,也就是所谓的 WOW64(用于 32 位)和 Arm64EC(用于 64 位)。
|
||||
|
||||
Box64 现已支持 32 位 WOW64 DLL。你可以通过编译时启用 `WOW64` CMake 选项来启用它。我们计划在未来支持 Arm64EC。
|
||||
|
||||
## Wine 的安装
|
||||
|
||||
对于 x86 Wine,有很多下载渠道,略举几例:
|
||||
|
||||
- https://github.com/Kron4ek/Wine-Builds (Wine \[WOW64\])
|
||||
- https://github.com/GloriousEggroll/proton-ge-custom (Proton,即 Valve 优化过的 Wine)
|
||||
|
||||
下载后,只需以你喜欢的方式将 `bin` 文件夹添加到 `PATH` 环境变量中;Wine 应该能很好地与 Box64 配合工作。
|
||||
|
||||
要安装 DXVK、d3dcompiler_xx 或 cjkfonts 等组件,推荐使用 Winetricks:https://github.com/Winetricks/winetricks
|
||||
|
||||
对于 Arm64 Wine,推荐使用 Hangover:https://github.com/AndreRH/hangover
|
||||
+39
-18
@@ -96,7 +96,7 @@ Arguments to pass to the guest program, only valid if there is no existing argum
|
||||
|
||||
=item B<BOX64_AVX> =I<0|1|2>
|
||||
|
||||
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 because it's fully implemented in DynaRec, 0 otherwise. Available in WowBox64.
|
||||
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 and LoongArch64 because it's fully implemented in DynaRec, 0 otherwise. Available in WowBox64.
|
||||
|
||||
* 0 : Do not expose AVX capabilities.
|
||||
* 1 : Expose AVX, BMI1, F16C and VAES extensions to CPUID and cpuinfo file.
|
||||
@@ -165,7 +165,7 @@ Enable building bigger DynaRec code blocks for better performance. Available in
|
||||
* 0 : Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
|
||||
* 1 : Build DynaRec block as big as possible.
|
||||
* 2 : Build DynaRec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
|
||||
* 3 : Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
|
||||
* 3 : Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for Wine programs.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_BLEEDING_EDGE> =I<0|1>
|
||||
@@ -180,17 +180,17 @@ Detect MonoBleedingEdge and apply conservative settings (Linux only).
|
||||
|
||||
Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
|
||||
* 0 : Do not optimize CALL/RET, use jump table. [Default]
|
||||
* 0 : Do not optimize CALL/RET, use jump table.
|
||||
* 1 : Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SEP> =I<0|1|2>
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0 : Do not add SEP at CALLRET return
|
||||
* 1 : Add SEP at CALLRET return, on memory that are from known binary files [Default]
|
||||
* 0 : Do not add SEP at CALLRET return [Default]
|
||||
* 1 : Add SEP at CALLRET return, on memory that are from known binary files
|
||||
* 2 : Add SEP at CALLRET return for all type of memory.
|
||||
|
||||
|
||||
@@ -227,13 +227,14 @@ Enable or disable the generation of division-by-zero exception. Available in Wow
|
||||
* 1 : Generate the division-by-zero exception.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2>
|
||||
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2|3>
|
||||
|
||||
Enable DynaRec dump. Available in WowBox64.
|
||||
|
||||
* 0 : Do not dump DynaRec blocks. [Default]
|
||||
* 1 : Dump DynaRec blocks.
|
||||
* 2 : Dump DynaRec blocks with some colors.
|
||||
* 3 : Dump only x86 and translated native instructions.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP_RANGE> =I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
@@ -243,6 +244,14 @@ Dump DynaRec blocks in the specified range. Available in WowBox64.
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where DynaBlock gets dumped (inclusive-exclusive).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DISASM> =I<0|1>
|
||||
|
||||
Try to initialize libZydis for more readable x86 disassembly in dump, trace, crash report, etc.
|
||||
|
||||
* 0 : Do not load Zydis for Dynarec. [Default]
|
||||
* 1 : Try to load Zydis for Dynarec.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTNAN> =I<0|1>
|
||||
|
||||
Enable or disable fast NaN handling. Available in WowBox64.
|
||||
@@ -260,13 +269,15 @@ Enable or disable fast rounding. Available in WowBox64.
|
||||
* 2 : Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|XXXX>
|
||||
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|256|512|1024>
|
||||
|
||||
Define max allowed forward value when building block. Available in WowBox64.
|
||||
Define max allowed forward value when building block. Only 0, 128, 256, 512 and 1024 are valid; other values fall back to 128. Available in WowBox64.
|
||||
|
||||
* 0 : No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
|
||||
* 128 : Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
|
||||
* XXXX : Allow up to XXXX bytes of gap between end of the block and the next forward jump.
|
||||
* 256 : Allow up to 256 bytes of gap between end of the block and the next forward jump.
|
||||
* 512 : Allow up to 512 bytes of gap between end of the block and the next forward jump.
|
||||
* 1024 : Allow up to 1024 bytes of gap between end of the block and the next forward jump.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_GDBJIT> =I<0|1|2|3|0xXXXXXXX-0xYYYYYYY>
|
||||
@@ -455,11 +466,11 @@ Allow the use of DynaRec in Signal Handlers.
|
||||
|
||||
=item B<BOX64_DYNACACHE> =I<0|1|2>
|
||||
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 1 (enable). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
|
||||
* 0 : Disable DynaCache.
|
||||
* 1 : Enable DynaCache.
|
||||
* 2 : Use DynaCache files if present, but do not generate new one. [Default]
|
||||
* 1 : Enable DynaCache. [Default]
|
||||
* 2 : Use DynaCache files if present, but do not generate new one.
|
||||
|
||||
|
||||
=item B<BOX64_DYNACACHE_FOLDER> =I<XXXX>
|
||||
@@ -487,12 +498,12 @@ Compress or not DynaCache files on disk
|
||||
* 2 : Compress dynacache files using ZLib with default compression.
|
||||
|
||||
|
||||
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|350>
|
||||
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|30>
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 30KB
|
||||
|
||||
* XXXX : Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 350 : A size of 350 KB is the default value. [Default]
|
||||
* 30 : A size of 30 KB is the default value. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
|
||||
@@ -648,6 +659,14 @@ Maximum CPU cores exposed. Available in WowBox64.
|
||||
* XXXX : Use XXXX CPU cores.
|
||||
|
||||
|
||||
=item B<BOX64_SKIPCPU> =I<0|XXXX>
|
||||
|
||||
Skip N first CPU cores (Is apply before MAXCPU) Available in WowBox64.
|
||||
|
||||
* 0 : Do not skip any CPU cores. [Default]
|
||||
* XXXX : Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
|
||||
|
||||
|
||||
=item B<BOX64_MMAP32> =I<0|1>
|
||||
|
||||
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
|
||||
@@ -931,7 +950,7 @@ Send all log and trace to a file instead of `stdout`.
|
||||
* stdout : Send all log and trace to `stdout`.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
|
||||
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY|0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ>
|
||||
|
||||
Same as BOX64_TRACE but starts the trace immediately.
|
||||
|
||||
@@ -939,6 +958,7 @@ Same as BOX64_TRACE but starts the trace immediately.
|
||||
* 1 : Enable trace output. Trace starts before the initialization of dependencies.
|
||||
* symbolname : Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ : Enable trace output only for the specified address list. Trace starts before the initialization of dependencies.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE_START> =I<0|1|XXXX>
|
||||
@@ -958,7 +978,7 @@ Enable or disable XMM (i.e. SSE) trace output.
|
||||
* 1 : Enable XMM trace output.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
|
||||
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY|0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ>
|
||||
|
||||
Only available on box64 build with trace. Adds trace of all instructions executed, along with a register dump.
|
||||
|
||||
@@ -966,6 +986,7 @@ Only available on box64 build with trace. Adds trace of all instructions execute
|
||||
* 1 : Enable trace output.
|
||||
* symbolname : Enable trace output for `symbolname` only.
|
||||
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive).
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ : Enable trace output only for the specified address list.
|
||||
|
||||
|
||||
=item B<BOX64_UNITYPLAYER> =I<0|1>
|
||||
|
||||
+5
-5
@@ -281,16 +281,16 @@ for entry in data:
|
||||
# regex to match env.h C code
|
||||
regex = {
|
||||
"INTEGER": re.compile(
|
||||
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)\)"
|
||||
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)(?:, \w+)?\)"
|
||||
),
|
||||
"INTEGER64": re.compile(
|
||||
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)(?:, \w+)?\)"
|
||||
),
|
||||
"BOOLEAN": re.compile(
|
||||
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)(?:, \w+)?\)"
|
||||
),
|
||||
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)(?:, \w+)?\)"),
|
||||
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)(?:, \w+)?\)"),
|
||||
}
|
||||
|
||||
env_file = os.path.join(script_dir, "../../src/include/env.h")
|
||||
|
||||
+202
-21
File diff suppressed because it is too large.
Load diff
+31
-19
@@ -37,7 +37,7 @@
|
||||
}
|
||||
},
|
||||
"BOX64_AVX": {
|
||||
"description": "向 CPUID 和 cpuinfo 文件暴露 AVX 扩展。在 Arm64 上默认值为 2,因为 DynaRec 已完全实现,其他架构默认为 0。",
|
||||
"description": "向 CPUID 和 cpuinfo 文件暴露 AVX 扩展。在 Arm64 和龙架构上默认值为 2,因为 DynaRec 已完全实现,其他架构默认为 0。",
|
||||
"options": {
|
||||
"0": "不暴露 AVX 能力。",
|
||||
"1": "向 CPUID 和 cpuinfo 文件暴露 AVX、BMI1、F16C 和 VAES 扩展。",
|
||||
@@ -98,14 +98,14 @@
|
||||
"0": "不尝试构建尽可能大的代码块,适用于使用大量线程和 JIT 的程序(如 Unity)。",
|
||||
"1": "尽可能构建大的代码块。",
|
||||
"2": "构建更大的代码块,代码块重叠时不停止,但仅针对 elf 内存中的代码块。",
|
||||
"3": "构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 wine 程序有用。"
|
||||
"3": "构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 Wine 程序有用。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_BLEEDING_EDGE": {
|
||||
"description": "检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。",
|
||||
"options": {
|
||||
"0": "不检测 MonoBleedingEdge。",
|
||||
"1": "检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_强内存模型=1。"
|
||||
"1": "检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_STRONGMEM=1。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_CALLRET": {
|
||||
@@ -158,7 +158,8 @@
|
||||
"options": {
|
||||
"0": "不转储代码块。",
|
||||
"1": "转储代码块。",
|
||||
"2": "转储代码块并带有颜色。"
|
||||
"2": "转储代码块并带有颜色。",
|
||||
"3": "仅转储 x86 指令和翻译后的本机指令。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_DUMP_RANGE": {
|
||||
@@ -167,6 +168,13 @@
|
||||
"0xXXXXXXXX-0xYYYYYYYY": "定义代码块 被转储的范围(左闭右开)。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_DISASM": {
|
||||
"description": "尝试初始化 libZydis,以在转储、追踪、崩溃报告等场景中获得更具可读性的 x86 反汇编结果。",
|
||||
"options": {
|
||||
"0": "不为 Dynarec 加载 Zydis。",
|
||||
"1": "尝试为 Dynarec 加载 Zydis。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_FASTNAN": {
|
||||
"description": "启用或禁用快速 NaN 处理。",
|
||||
"options": {
|
||||
@@ -183,11 +191,13 @@
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_FORWARD": {
|
||||
"description": "定义构建代码块时允许的最大前向跳转值。",
|
||||
"description": "定义构建代码块时允许的最大前向跳转值。仅接受 0、128、256、512 和 1024;其他值将回退为 128。",
|
||||
"options": {
|
||||
"0": "无前向跳转值。当前代码块结束时,即使存在之前的前向跳转也不尝试继续前进。",
|
||||
"128": "允许代码块结束与下一个前向跳转之间最多 128 字节的间隙。",
|
||||
"XXXX": "允许代码块结束与下一个前向跳转之间最多 XXXX 字节的间隙。"
|
||||
"256": "允许代码块结束与下一个前向跳转之间最多 256 字节的间隙。",
|
||||
"512": "允许代码块结束与下一个前向跳转之间最多 512 字节的间隙。",
|
||||
"1024": "允许代码块结束与下一个前向跳转之间最多 1024 字节的间隙。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_GDBJIT": {
|
||||
@@ -354,7 +364,7 @@
|
||||
}
|
||||
},
|
||||
"BOX64_DYNACACHE": {
|
||||
"description": "启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 2(读取已有缓存但不生成新的)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。",
|
||||
"description": "启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 1(启用)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。",
|
||||
"options": {
|
||||
"0": "禁用 DynaCache。",
|
||||
"1": "启用 DynaCache。",
|
||||
@@ -384,10 +394,10 @@
|
||||
}
|
||||
},
|
||||
"BOX64_DYNACACHE_MIN": {
|
||||
"description": "DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。",
|
||||
"description": "DynaCache 写入磁盘的最小大小(KB)。默认大小为 30KB。",
|
||||
"options": {
|
||||
"XXXX": "设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。",
|
||||
"350": "默认值为 350 KB。"
|
||||
"30": "默认值为 30 KB。"
|
||||
}
|
||||
},
|
||||
"BOX64_EMULATED_LIBS": {
|
||||
@@ -464,7 +474,7 @@
|
||||
"description": "检测 libjvm 并应用保守设置。",
|
||||
"options": {
|
||||
"0": "不执行任何操作。",
|
||||
"1": "检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_强内存模型=1 BOX64_SSE42=0。"
|
||||
"1": "检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0。"
|
||||
}
|
||||
},
|
||||
"BOX64_LD_LIBRARY_PATH": {
|
||||
@@ -645,10 +655,10 @@
|
||||
"BOX64_PROFILE": {
|
||||
"description": "预定义的环境变量集合,以兼容性或性能为导向。",
|
||||
"options": {
|
||||
"safest": "禁用所有不安全的 DynaRec 优化的配置文件。",
|
||||
"safe": "比 safest 略不安全。",
|
||||
"safest": "禁用所有不安全的优化。",
|
||||
"safe": "仅启用小部分不安全的优化。",
|
||||
"default": "大多数程序都能正常运行且性能适中的默认设置。",
|
||||
"fast": "启用许多不安全的优化,但同时启用 强内存模型 模拟。",
|
||||
"fast": "启用许多不安全的优化,但同时启用强内存模型模拟。",
|
||||
"fastest": "启用许多不安全的优化以获得更好的性能。"
|
||||
}
|
||||
},
|
||||
@@ -722,10 +732,10 @@
|
||||
}
|
||||
},
|
||||
"BOX64_SSE_FLUSHTO0": {
|
||||
"description": "SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常FLAGS。",
|
||||
"description": "SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常 FLAGS。",
|
||||
"options": {
|
||||
"0": "仅追踪FLAGS。",
|
||||
"1": "直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常FLAGS(如果可用)。"
|
||||
"0": "仅追踪 FLAGS。",
|
||||
"1": "直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常 FLAGS(如果可用)。"
|
||||
}
|
||||
},
|
||||
"BOX64_SSE42": {
|
||||
@@ -778,7 +788,8 @@
|
||||
"0": "禁用追踪输出。",
|
||||
"1": "启用追踪输出。追踪在依赖项初始化之前开始。",
|
||||
"symbolname": "仅对 `symbolname` 启用追踪输出。追踪在依赖项初始化之前开始。",
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。"
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。",
|
||||
"0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ": "对指定的地址列表启用追踪输出。追踪在依赖项初始化之前开始。"
|
||||
}
|
||||
},
|
||||
"BOX64_TRACE_START": {
|
||||
@@ -802,7 +813,8 @@
|
||||
"0": "禁用追踪输出。",
|
||||
"1": "启用追踪输出。",
|
||||
"symbolname": "仅对 `symbolname` 启用追踪输出。",
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。"
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。",
|
||||
"0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ": "对指定地址列表启用追踪输出。"
|
||||
}
|
||||
},
|
||||
"BOX64_UNITYPLAYER": {
|
||||
@@ -816,7 +828,7 @@
|
||||
"description": "告诉 Box64 这是一个 Unity 游戏。",
|
||||
"options": {
|
||||
"0": "不执行任何操作。",
|
||||
"1": "这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_强内存模型=1。"
|
||||
"1": "这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_STRONGMEM=1。"
|
||||
}
|
||||
},
|
||||
"BOX64_WRAP_EGL": {
|
||||
|
||||
@@ -17,6 +17,7 @@ endif()
|
||||
|
||||
set(ENV{BOX64_LOG} 0)
|
||||
set(ENV{BOX64_NOBANNER} 1)
|
||||
set(ENV{BOX64_DYNACACHE} 0)
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
execute_process(
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 4
|
||||
#define BOX64_REVISION 3
|
||||
#define BOX64_REVISION 4
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+80
-37
@@ -70,6 +70,7 @@ int box64_steam = 0;
|
||||
int box64_steamcmd = 0;
|
||||
int box64_musl = 0;
|
||||
int box64_nolibs = 0;
|
||||
int box64_hasinterp = 0;
|
||||
char* box64_custom_gstreamer = NULL;
|
||||
int box64_tcmalloc_minimal = 0;
|
||||
uintptr_t fmod_smc_start = 0;
|
||||
@@ -90,6 +91,8 @@ const char* box64_wine_guest_name = NULL;
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t trace_start = 0, trace_end = 0;
|
||||
uintptr_t* trace_addrs = NULL;
|
||||
int trace_addrs_count = 0;
|
||||
char* trace_func = NULL;
|
||||
#endif
|
||||
|
||||
@@ -226,14 +229,15 @@ static void displayMiscInfo(void)
|
||||
#if defined(LA64)
|
||||
if (box64env.avx && !cpuext.lasx) {
|
||||
box64env.avx = 0;
|
||||
box64env.avx2 = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd", box64_sysinfo.cpuname, box64_sysinfo.ncpu, box64_sysinfo.ncpu > 1 ? "s" : "", box64_pagesize);
|
||||
if (BOX64ENV(maxcpu))
|
||||
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s\n", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
|
||||
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
|
||||
if (BOX64ENV(skipcpu))
|
||||
printf_log_prefix(0, LOG_INFO, " skipping %d core%s\n", BOX64ENV(skipcpu), BOX64ENV(skipcpu)>1? "s":"");
|
||||
else
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
computeRDTSC();
|
||||
@@ -425,10 +429,6 @@ static void addLibPaths(box64context_t* context)
|
||||
GO("libpng12.so.0");
|
||||
GO("libpng16.so.16");
|
||||
GO("libcurl.so.4");
|
||||
if(getenv("BOX64_PRESSURE_VESSEL_FILES")) { // use emulated gnutls in this case, it's safer (nettle is a gnutls dependancy)
|
||||
GO("libgnutls.so.30");
|
||||
GO("libnettle.so.8");
|
||||
}
|
||||
GO("libtbbmalloc.so.2");
|
||||
GO("libtbbmalloc_proxy.so.2");
|
||||
GO("libicuuc.so.64");
|
||||
@@ -472,7 +472,7 @@ static void setupZydis(box64context_t* context)
|
||||
if ((BOX64ENV(trace_init) && strcmp(BOX64ENV(trace_init), "0")) || (BOX64ENV(trace) && strcmp(BOX64ENV(trace), "0"))) {
|
||||
context->x64trace = 1;
|
||||
}
|
||||
if (context->x64trace) {
|
||||
if (context->x64trace || BOX64ENV(dynarec_disasm)) {
|
||||
printf_log(LOG_INFO, "Initializing Zydis lib\n");
|
||||
if (InitX64Trace(context)) {
|
||||
printf_log(LOG_INFO, "Zydis init failed. No x86 trace activated\n");
|
||||
@@ -547,6 +547,39 @@ void LoadLDPath(box64context_t *context)
|
||||
PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
static void setupTraceAddrList(char *p)
|
||||
{
|
||||
int cap = 16;
|
||||
int count = 0;
|
||||
char *saveptr = NULL;
|
||||
|
||||
uintptr_t* addrs = (uintptr_t*)box_malloc(cap * sizeof(uintptr_t));
|
||||
char* tmp = box_strdup(p);
|
||||
char* tok = strtok_r(tmp, ":", &saveptr);
|
||||
|
||||
while (tok) {
|
||||
if (count >= cap) {
|
||||
cap *= 2;
|
||||
addrs = (uintptr_t*)box_realloc(addrs, cap * sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
char* endptr;
|
||||
uintptr_t addr = (uintptr_t)strtoul(tok, &endptr, 0);
|
||||
if (endptr != tok)
|
||||
addrs[count++] = addr;
|
||||
|
||||
tok = strtok_r(NULL, ":", &saveptr);
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
SetTraceAddrs(addrs, count);
|
||||
|
||||
box_free(tmp);
|
||||
box_free(addrs);
|
||||
}
|
||||
#endif
|
||||
|
||||
EXPORTDYN
|
||||
void setupTraceInit()
|
||||
{
|
||||
@@ -566,6 +599,9 @@ void setupTraceInit()
|
||||
}
|
||||
if(s_trace_start || s_trace_end)
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
} else if (strchr(p,':')) {
|
||||
// Parse BOX64_TRACE=0x1000:0x2000:0x3000 format.
|
||||
setupTraceAddrList(p);
|
||||
} else {
|
||||
int veropt = 1;
|
||||
int ver = 0;
|
||||
@@ -643,6 +679,9 @@ void setupTrace()
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
}
|
||||
}
|
||||
} else if (strchr(p,':')) {
|
||||
// Parse BOX64_TRACE=0x1000:0x2000:0x3000 format.
|
||||
setupTraceAddrList(p);
|
||||
} else {
|
||||
int search = 0;
|
||||
if (my_context->elfs) {
|
||||
@@ -799,14 +838,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int is_test = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--test") || !strcmp(argv[i], "-t")) {
|
||||
is_test = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_test) {
|
||||
if (argc >= 3 && (!strcmp(argv[1], "--test") || !strcmp(argv[1], "-t"))) {
|
||||
box64_unittest_mode = 1;
|
||||
exit(unittest(argc, argv));
|
||||
}
|
||||
@@ -841,14 +873,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
DynaCacheClean();
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "--dynacache-list")) {
|
||||
if(!strcmp(prog, "-dl") || !strcmp(prog, "--dynacache-list")) {
|
||||
#ifdef DYNAREC
|
||||
DetectHostCpuFeatures();
|
||||
#endif
|
||||
DynaCacheList(argv[nextarg+1]);
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "--dynacache-clean")) {
|
||||
if(!strcmp(prog, "-dc") || !strcmp(prog, "--dynacache-clean")) {
|
||||
#ifdef DYNAREC
|
||||
DetectHostCpuFeatures();
|
||||
#endif
|
||||
@@ -941,24 +973,6 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
}
|
||||
}
|
||||
box64_wine = 1;
|
||||
// check if it's proton, with it's custom gstreamer build, to disable gtk3 loading
|
||||
char tmp[strlen(prog)+100];
|
||||
strcpy(tmp, prog);
|
||||
char* pp = strrchr(tmp, '/');
|
||||
if(pp) {
|
||||
*pp = '\0'; // remove the wine binary call
|
||||
strcat(tmp, "/../lib64/gstreamer-1.0");
|
||||
// check if it exist
|
||||
if(FileExist(tmp, 0)) {
|
||||
box64_custom_gstreamer = box_strdup(tmp);
|
||||
} else {
|
||||
*pp = '\0';
|
||||
strcat(tmp, "/../lib/x86_64-linux-gnu/gstreamer-1.0");
|
||||
if(FileExist(tmp, 0)) {
|
||||
box64_custom_gstreamer = box_strdup(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try to get the name of the exe being run, to ApplyEnvFileEntry laters
|
||||
if(argv[nextarg+1] && argv[nextarg+1][0]!='-' && strlen(argv[nextarg+1])>4 /*&& !strcasecmp(argv[nextarg+1]+strlen(argv[nextarg+1])-4, ".exe")*/) {
|
||||
const char* pp = strrchr(argv[nextarg+1], '/');
|
||||
@@ -1002,6 +1016,30 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
my_context = NewBox64Context(argc - nextarg);
|
||||
|
||||
addLibPaths(my_context);
|
||||
if(box64_wine) {
|
||||
// check if it's proton, with it's custom gstreamer build, to disable gtk3 loading
|
||||
char* tmp_ = ResolveFile(prog_, &my_context->box64_path);
|
||||
if(tmp_) {
|
||||
char tmp[strlen(tmp_)+100];
|
||||
strcpy(tmp, tmp_);
|
||||
box_free(tmp_);
|
||||
char* pp = strrchr(tmp, '/');
|
||||
if(pp) {
|
||||
*pp = '\0'; // remove the wine binary call
|
||||
strcat(tmp, "/../lib64/gstreamer-1.0");
|
||||
// check if it exist
|
||||
if(FileExist(tmp, 0)) {
|
||||
box64_custom_gstreamer = box_strdup(tmp);
|
||||
} else {
|
||||
*pp = '\0';
|
||||
strcat(tmp, "/../lib/x86_64-linux-gnu/gstreamer-1.0");
|
||||
if(FileExist(tmp, 0)) {
|
||||
box64_custom_gstreamer = box_strdup(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append ld_list if it exist
|
||||
if(ld_libs_args!=-1)
|
||||
@@ -1023,6 +1061,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
unsetenv("BOX64_ARG0");
|
||||
if(!my_context->bashpath)
|
||||
my_context->bashpath = ResolveFile("box64-bash", &my_context->box64_path);
|
||||
if(!my_context->pythonpath)
|
||||
my_context->pythonpath = ResolveFile("box64-python", &my_context->box64_path);
|
||||
pressure_vessel(argc, argv, nextarg+1, prog);
|
||||
}
|
||||
#endif
|
||||
@@ -1137,8 +1177,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
if (applied) {
|
||||
printf_log(LOG_INFO, "Applied settings from rcfile\n");
|
||||
displayMiscInfo();
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
}
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
setupZydis(my_context);
|
||||
|
||||
for(int i=1; i<my_context->argc; ++i) {
|
||||
@@ -1434,8 +1474,9 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
my_context->orig_argc = argc;
|
||||
my_context->orig_argv = (char**)argv;
|
||||
}
|
||||
box64_hasinterp = hasElfInterp(elf_header);
|
||||
box64_nolibs = (NeededLibs(elf_header)==0);
|
||||
if(box64_nolibs) printf_log(LOG_INFO, "Warning, box64 is not really compatible with staticaly linked binaries. Expect crash!\n");
|
||||
if(!box64_hasinterp) printf_log(LOG_INFO, "Warning, box64 is not really compatible with staticaly linked binaries. Expect crash!\n");
|
||||
box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34");
|
||||
if(box64_isglibc234)
|
||||
printf_log(LOG_DEBUG, "Program linked with GLIBC 2.34+\n");
|
||||
@@ -1546,12 +1587,14 @@ int emulate(x64emu_t* emu, elfheader_t* elf_header)
|
||||
SetEIP(emu, my_context->ep);
|
||||
Push32(emu, my_context->exit_bridge); // push to pop it just after
|
||||
SetEDX(emu, Pop32(emu)); // RDX is exit function
|
||||
if(!box64_hasinterp) SetEDX(emu, 0);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SetRIP(emu, my_context->ep);
|
||||
Push64(emu, my_context->exit_bridge); // push to pop it just after
|
||||
SetRDX(emu, Pop64(emu)); // RDX is exit function
|
||||
if(!box64_hasinterp) SetRDX(emu, 0);
|
||||
}
|
||||
DynaRun(emu);
|
||||
// Get EAX
|
||||
|
||||
+271
-269
@@ -16,6 +16,9 @@
|
||||
#include "callback.h"
|
||||
#include "x64trace.h"
|
||||
#include "custommem.h"
|
||||
#ifndef _WIN32
|
||||
#include "signals.h"
|
||||
#endif
|
||||
#include "khash.h"
|
||||
#include "threads.h"
|
||||
#include "rbtree.h"
|
||||
@@ -32,7 +35,7 @@
|
||||
// init inside dynablocks.c
|
||||
static mmaplist_t *mmaplist = NULL;
|
||||
static rbtree_t *rbt_dynmem = NULL;
|
||||
static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 = 0, jmptbl_allocated3 = 0;
|
||||
static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 = 0;
|
||||
#if JMPTABL_SHIFTMAX != 16
|
||||
#error Incorect value for jumptable shift max that should be 16
|
||||
#endif
|
||||
@@ -40,18 +43,15 @@ static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 =
|
||||
#if JMPTABL_SHIFT3 != 16
|
||||
#error Incorect value for jumptable shift3 that should be 16
|
||||
#endif
|
||||
static uint64_t jmptbl_allocated4 = 0;
|
||||
static uintptr_t**** box64_jmptbl4[1<<JMPTABL_SHIFT4];
|
||||
static uintptr_t*** box64_jmptbldefault3[1<<JMPTABL_SHIFT3];
|
||||
static uintptr_t*** box64_jmptbl_48[1<<JMPTABL_SHIFT3];
|
||||
static uint64_t jmptbl_allocated3 = 0;
|
||||
static uintptr_t*** box64_jmptbl3[1<<JMPTABL_SHIFT3];
|
||||
static uintptr_t** box64_jmptbldefault2[1<<JMPTABL_SHIFT2];
|
||||
#else
|
||||
#if JMPTABL_SHIFT2 != 16
|
||||
#error Incorect value for jumptable shift2 that should be 16
|
||||
#endif
|
||||
static uintptr_t*** box64_jmptbl3[1<<JMPTABL_SHIFT3];
|
||||
static uintptr_t** box64_jmptbl_48[1<<JMPTABL_SHIFT2];
|
||||
static uintptr_t** box64_jmptbl2[1<<JMPTABL_SHIFT2];
|
||||
#endif
|
||||
static uintptr_t** box64_jmptbldefault2[1<<JMPTABL_SHIFT2];
|
||||
static uintptr_t* box64_jmptbldefault1[1<<JMPTABL_SHIFT1];
|
||||
static uintptr_t box64_jmptbldefault0[1<<JMPTABL_SHIFT0];
|
||||
// lock addresses
|
||||
@@ -562,24 +562,57 @@ static uintptr_t defered_prot_p = 0;
|
||||
static size_t defered_prot_sz = 0;
|
||||
static uint32_t defered_prot_prot = 0;
|
||||
static mem_flag_t defered_prot_flags = MEM_ALLOCATED;
|
||||
static sigset_t critical_prot = {0};
|
||||
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
|
||||
#define LOCK_PROT() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
|
||||
#define LOCK_PROT_READ() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
|
||||
#define LOCK_PROT_FAST() mutex_lock(&mutex_prot)
|
||||
#define UNLOCK_PROT() if(defered_prot_p) { \
|
||||
uintptr_t p = defered_prot_p; size_t sz = defered_prot_sz; uint32_t prot = defered_prot_prot; mem_flag_t f = defered_prot_flags;\
|
||||
defered_prot_p = 0; \
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
setProtection_generic(p, sz, prot, f); \
|
||||
} else { \
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
}
|
||||
#define UNLOCK_PROT_READ() mutex_unlock(&mutex_prot); pthread_sigmask(SIG_SETMASK, &old_sig, NULL)
|
||||
#define UNLOCK_PROT_FAST() mutex_unlock(&mutex_prot)
|
||||
|
||||
#ifdef _WIN32
|
||||
void enter_critical_section(void) {}
|
||||
void leave_critical_section(void) {}
|
||||
#endif
|
||||
|
||||
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
|
||||
#define LOCK_PROT() \
|
||||
do { \
|
||||
enter_critical_section(); \
|
||||
mutex_lock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#define LOCK_PROT_READ() \
|
||||
do { \
|
||||
enter_critical_section(); \
|
||||
mutex_lock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#define LOCK_PROT_FAST() \
|
||||
do { \
|
||||
mutex_lock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#define UNLOCK_PROT() \
|
||||
do { \
|
||||
if (defered_prot_p) { \
|
||||
uintptr_t p = defered_prot_p; \
|
||||
size_t sz = defered_prot_sz; \
|
||||
uint32_t prot = defered_prot_prot; \
|
||||
mem_flag_t f = defered_prot_flags; \
|
||||
defered_prot_p = 0; \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
leave_critical_section(); \
|
||||
setProtection_generic(p, sz, prot, f); \
|
||||
} else { \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
leave_critical_section(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define UNLOCK_PROT_READ() \
|
||||
do { \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
leave_critical_section(); \
|
||||
} while (0)
|
||||
|
||||
#define UNLOCK_PROT_FAST() \
|
||||
do { \
|
||||
mutex_unlock(&mutex_prot); \
|
||||
} while (0)
|
||||
|
||||
#ifdef TRACE_MEMSTAT
|
||||
static uint64_t customMalloc_allocated = 0;
|
||||
@@ -1587,6 +1620,7 @@ void DelMmaplist(mmaplist_t* list)
|
||||
for(int i=0; i<list->size; ++i)
|
||||
if(list->chunks[i]->size) {
|
||||
cleanDBFromAddressRange((uintptr_t)list->chunks[i]->block, list->chunks[i]->size, 1);
|
||||
DeferFreeDynablockClearRange(list->chunks[i]->block, list->chunks[i]->size);
|
||||
rb_unset(rbt_dynmem, (uintptr_t)list->chunks[i]->block, (uintptr_t)list->chunks[i]->block+list->chunks[i]->size);
|
||||
// the blocklist_t "chunk" structure is port of the memory map, so grab info before freing the memory
|
||||
// also need to include back the blocklist_t that is excluded from the blocklist tracking
|
||||
@@ -1824,34 +1858,30 @@ void FreeDynarecMap(uintptr_t addr)
|
||||
|
||||
static uintptr_t getDBSize(uintptr_t addr, size_t maxsize, dynablock_t** db)
|
||||
{
|
||||
if(addr&0xffff000000000000ULL) {*db = NULL; return addr+maxsize;} // address beyond 48bits are not handled
|
||||
#ifdef JMPTABL_START4
|
||||
const uintptr_t idx4 = (addr>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
#endif
|
||||
const uintptr_t idx3 = (addr>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
#endif
|
||||
const uintptr_t idx2 = (addr>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
const uintptr_t idx1 = (addr>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
uintptr_t idx0 = addr&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_START4
|
||||
*db = *(dynablock_t**)(box64_jmptbl4[idx4][idx3][idx2][idx1][idx0]- sizeof(void*));
|
||||
#else
|
||||
*db = *(dynablock_t**)(box64_jmptbl3[idx3][idx2][idx1][idx0]- sizeof(void*));
|
||||
#else
|
||||
*db = *(dynablock_t**)(box64_jmptbl2[idx2][idx1][idx0]- sizeof(void*));
|
||||
#endif
|
||||
if(*db)
|
||||
return addr+1;
|
||||
#ifdef JMPTABL_START4
|
||||
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
|
||||
return ((idx4+1)<<JMPTABL_START4);
|
||||
if(box64_jmptbl4[idx4][idx3] == box64_jmptbldefault2)
|
||||
return (((addr>>JMPTABL_START3)+1)<<JMPTABL_START3);
|
||||
if(box64_jmptbl4[idx4][idx3][idx2] == box64_jmptbldefault1)
|
||||
return (((addr>>JMPTABL_START2)+1)<<JMPTABL_START2);
|
||||
uintptr_t* block = box64_jmptbl4[idx4][idx3][idx2][idx1];
|
||||
#else
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
|
||||
return ((idx3+1)<<JMPTABL_START3);
|
||||
return (((addr>>JMPTABL_START3)+1)<<JMPTABL_START3);
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
|
||||
return (((addr>>JMPTABL_START2)+1)<<JMPTABL_START2);
|
||||
uintptr_t* block = box64_jmptbl3[idx3][idx2][idx1];
|
||||
#else
|
||||
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
|
||||
return (((addr>>JMPTABL_START2)+1)<<JMPTABL_START2);
|
||||
uintptr_t* block = box64_jmptbl2[idx2][idx1];
|
||||
#endif
|
||||
if(block == box64_jmptbldefault0)
|
||||
return (((addr>>JMPTABL_START1)+1)<<JMPTABL_START1);
|
||||
@@ -1907,64 +1937,6 @@ int cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
|
||||
}
|
||||
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, uintptr_t idx2, uintptr_t idx3, uintptr_t idx4)
|
||||
{
|
||||
if(box64_jmptbl4[idx4] == box64_jmptbldefault3) {
|
||||
uintptr_t**** tbl = (uintptr_t****)customMalloc((1<<JMPTABL_SHIFT3)*sizeof(uintptr_t***));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i)
|
||||
tbl[i] = box64_jmptbldefault2;
|
||||
if(native_lock_storeifref(&box64_jmptbl4[idx4], tbl, box64_jmptbldefault3)!=tbl)
|
||||
customFree(tbl);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
else {
|
||||
jmptbl_allocated += (1<<JMPTABL_SHIFT3)*sizeof(uintptr_t***);
|
||||
++jmptbl_allocated4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(box64_jmptbl4[idx4][idx3] == box64_jmptbldefault2) {
|
||||
uintptr_t*** tbl = (uintptr_t***)customMalloc((1<<JMPTABL_SHIFT2)*sizeof(uintptr_t**));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i)
|
||||
tbl[i] = box64_jmptbldefault1;
|
||||
if(native_lock_storeifref(&box64_jmptbl4[idx4][idx3], tbl, box64_jmptbldefault2)!=tbl)
|
||||
customFree(tbl);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
else {
|
||||
jmptbl_allocated += (1<<JMPTABL_SHIFT2)*sizeof(uintptr_t**);
|
||||
++jmptbl_allocated3;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(for32bits) return NULL;
|
||||
if(box64_jmptbl4[idx4][idx3][idx2] == box64_jmptbldefault1) {
|
||||
uintptr_t** tbl = (uintptr_t**)customMalloc((1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
|
||||
tbl[i] = box64_jmptbldefault0;
|
||||
if(native_lock_storeifref(&box64_jmptbl4[idx4][idx3][idx2], tbl, box64_jmptbldefault1)!=tbl)
|
||||
customFree(tbl);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
else {
|
||||
jmptbl_allocated += (1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*);
|
||||
++jmptbl_allocated2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(box64_jmptbl4[idx4][idx3][idx2][idx1] == box64_jmptbldefault0) {
|
||||
uintptr_t* tbl = (uintptr_t*)customMalloc((1<<JMPTABL_SHIFT0)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
|
||||
tbl[i] = (uintptr_t)native_next;
|
||||
if(native_lock_storeifref(&box64_jmptbl4[idx4][idx3][idx2][idx1], tbl, box64_jmptbldefault0)!=tbl)
|
||||
customFree(tbl);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
else {
|
||||
jmptbl_allocated += (1<<JMPTABL_SHIFT0)*sizeof(uintptr_t);
|
||||
++jmptbl_allocated1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return &box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
|
||||
}
|
||||
#else
|
||||
static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, uintptr_t idx2, uintptr_t idx3)
|
||||
{
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2) {
|
||||
@@ -1980,6 +1952,7 @@ static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, u
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(for32bits) return NULL;
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) {
|
||||
uintptr_t** tbl = (uintptr_t**)customMalloc((1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
|
||||
@@ -1993,7 +1966,6 @@ static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, u
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(for32bits) return NULL;
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) {
|
||||
uintptr_t* tbl = (uintptr_t*)customMalloc((1<<JMPTABL_SHIFT0)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
|
||||
@@ -2009,189 +1981,218 @@ static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, u
|
||||
}
|
||||
return &box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
}
|
||||
#else
|
||||
static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, uintptr_t idx2)
|
||||
{
|
||||
if(box64_jmptbl2[idx2] == box64_jmptbldefault1) {
|
||||
uintptr_t** tbl = (uintptr_t**)customMalloc((1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
|
||||
tbl[i] = box64_jmptbldefault0;
|
||||
if(native_lock_storeifref(&box64_jmptbl2[idx2], tbl, box64_jmptbldefault1)!=tbl)
|
||||
customFree(tbl);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
else {
|
||||
jmptbl_allocated += (1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*);
|
||||
++jmptbl_allocated2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(for32bits) return NULL;
|
||||
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0) {
|
||||
uintptr_t* tbl = (uintptr_t*)customMalloc((1<<JMPTABL_SHIFT0)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
|
||||
tbl[i] = (uintptr_t)native_next;
|
||||
if(native_lock_storeifref(&box64_jmptbl2[idx2][idx1], tbl, box64_jmptbldefault0)!=tbl)
|
||||
customFree(tbl);
|
||||
#ifdef TRACE_MEMSTAT
|
||||
else {
|
||||
jmptbl_allocated += (1<<JMPTABL_SHIFT0)*sizeof(uintptr_t);
|
||||
++jmptbl_allocated1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return &box64_jmptbl2[idx2][idx1][idx0];
|
||||
}
|
||||
#endif
|
||||
|
||||
int addJumpTableIfDefault64(void* addr, void* jmp)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return 0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4;
|
||||
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
#endif
|
||||
uintptr_t idx3;
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
#endif
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, native_next)==native_next)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, native_next)==native_next)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2), jmp, native_next)==native_next)?1:0;
|
||||
#endif
|
||||
}
|
||||
void setJumpTableDefault64(void* addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4;
|
||||
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
|
||||
return;
|
||||
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
|
||||
#endif
|
||||
uintptr_t idx3;
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
|
||||
return;
|
||||
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
|
||||
#endif
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
|
||||
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
|
||||
return;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
|
||||
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
|
||||
return;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
native_lock_store_dd(&box64_jmptbl3[idx3][idx2][idx1][idx0], (uintptr_t)native_next);
|
||||
native_lock_store_dd(&box64_jmptbl2[idx2][idx1][idx0], (uintptr_t)native_next);
|
||||
}
|
||||
int setJumpTableDefaultIfRef64(void* addr, void* jmp)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return 0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4;
|
||||
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
|
||||
return 0;
|
||||
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
|
||||
#endif
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
|
||||
return 0;
|
||||
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
|
||||
#endif
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
|
||||
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
|
||||
return 0;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
|
||||
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
|
||||
return 0;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), native_next, jmp)==jmp)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), native_next, jmp)==jmp)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2), native_next, jmp)==jmp)?1:0;
|
||||
#endif
|
||||
}
|
||||
void setJumpTableDefaultRef64(void* addr, void* jmp)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4;
|
||||
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
|
||||
return;
|
||||
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
|
||||
#endif
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
|
||||
return;
|
||||
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
|
||||
#endif
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
|
||||
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
|
||||
return;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
|
||||
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
|
||||
return;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
native_lock_storeifref2(&box64_jmptbl3[idx3][idx2][idx1][idx0], native_next, jmp);
|
||||
native_lock_storeifref2(&box64_jmptbl2[idx2][idx1][idx0], native_next, jmp);
|
||||
}
|
||||
int setJumpTableIfRef64(void* addr, void* jmp, void* ref)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return 0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
uintptr_t idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
#endif
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, ref)==ref)?1:0;
|
||||
void* ret = native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, ref);
|
||||
#else
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, ref)==ref)?1:0;
|
||||
void* ret = native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2), jmp, ref);
|
||||
#endif
|
||||
return ((ret==ref) || (ret==jmp))?1:0;
|
||||
}
|
||||
int isJumpTableDefault64(void* addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return 0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4;
|
||||
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
|
||||
return 1;
|
||||
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
|
||||
#endif
|
||||
uintptr_t idx3;
|
||||
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
|
||||
return 1;
|
||||
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
|
||||
#endif
|
||||
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
|
||||
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
|
||||
return 1;
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
|
||||
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
|
||||
return 1;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
return (box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next)?1:0;
|
||||
return (box64_jmptbl2[idx2][idx1][idx0]==(uintptr_t)native_next)?1:0;
|
||||
}
|
||||
uintptr_t getJumpTable64()
|
||||
{
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (uintptr_t)box64_jmptbl4;
|
||||
#else
|
||||
return (uintptr_t)box64_jmptbl3;
|
||||
#else
|
||||
return (uintptr_t)box64_jmptbl2;
|
||||
#endif
|
||||
}
|
||||
uintptr_t getJumpTable48()
|
||||
{
|
||||
return (uintptr_t)box64_jmptbl_48;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (uintptr_t)box64_jmptbl3;
|
||||
#else
|
||||
return (uintptr_t)box64_jmptbl2;
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t getJumpTable32()
|
||||
{
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
create_jmptbl(1, 0, 0, 0, 0, 0);
|
||||
return (uintptr_t)box64_jmptbl4[0][0];
|
||||
#else
|
||||
create_jmptbl(1, 0, 0, 0, 0);
|
||||
return (uintptr_t)box64_jmptbl3[0][0];
|
||||
return (uintptr_t)box64_jmptbl3[0];
|
||||
#else
|
||||
create_jmptbl(1, 0, 0, 0);
|
||||
return (uintptr_t)box64_jmptbl2[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
uintptr_t getJumpTableAddress64(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return getJumpTableAddress64(0); // this should not happens
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
uintptr_t idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
#endif
|
||||
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = ((addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (uintptr_t)create_jmptbl(0, idx0, idx1, idx2, idx3, idx4);
|
||||
#else
|
||||
return (uintptr_t)create_jmptbl(0, idx0, idx1, idx2, idx3);
|
||||
#else
|
||||
return (uintptr_t)create_jmptbl(0, idx0, idx1, idx2);
|
||||
#endif
|
||||
}
|
||||
|
||||
dynablock_t* getDBBlock(uintptr_t addr, void** jblock)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
if((uintptr_t)addr&0xffff000000000000UL) return NULL;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
uintptr_t idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
#endif
|
||||
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = ((addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
|
||||
#else
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
#else
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl2[idx2][idx1][idx0];
|
||||
#endif
|
||||
if(jblock) *jblock = (void*)ret;
|
||||
|
||||
@@ -2224,18 +2225,17 @@ dynablock_t* getDBnoTest(uintptr_t addr)
|
||||
|
||||
uintptr_t getJumpAddress64(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
uintptr_t idx2, idx1, idx0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
uintptr_t idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
#endif
|
||||
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = ((addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (uintptr_t)box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
|
||||
#else
|
||||
return (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
#else
|
||||
return (uintptr_t)box64_jmptbl2[idx2][idx1][idx0];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2445,36 +2445,6 @@ void neverprotectDB(uintptr_t addr, size_t size, int mark)
|
||||
UNLOCK_PROT();
|
||||
}
|
||||
|
||||
// Remove the NEVERCLEAN flag for an adress range
|
||||
void unneverprotectDB(uintptr_t addr, size_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "unneverprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
|
||||
uintptr_t cur = addr&~(box64_pagesize-1);
|
||||
uintptr_t end = ALIGN(addr+size);
|
||||
|
||||
LOCK_PROT();
|
||||
while(cur!=end) {
|
||||
uint32_t prot = 0, oprot;
|
||||
uintptr_t bend = 0;
|
||||
if (!rb_get_end(memprot, cur, &prot, &bend)) {
|
||||
if(bend>=end) break;
|
||||
else {
|
||||
cur = bend;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
oprot = prot;
|
||||
if(bend>end)
|
||||
bend = end;
|
||||
prot &= ~PROT_NEVERCLEAN;
|
||||
if (prot != oprot)
|
||||
rb_set(memprot, cur, bend, prot);
|
||||
cur = bend;
|
||||
}
|
||||
UNLOCK_PROT();
|
||||
}
|
||||
|
||||
int isprotectedDB(uintptr_t addr, size_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "isprotectedDB %p -> %p => ", (void*)addr, (void*)(addr+size-1));
|
||||
@@ -2553,11 +2523,16 @@ void CheckHotPage(uintptr_t addr, uint32_t prot)
|
||||
{
|
||||
if(addr>=0x1000000000000LL) // more than 48bits
|
||||
return;
|
||||
if(prot&PROT_NEVERCLEAN && BOX64ENV(dynarec_dirty)==2)
|
||||
return;
|
||||
if(BOX64ENV(dynarec_nohotpage))
|
||||
if((prot&PROT_NEVERCLEAN) && BOX64ENV(dynarec_dirty)==2)
|
||||
return;
|
||||
uintptr_t page = addr>>12;
|
||||
if(BOX64ENV(dynarec_nohotpage)) {
|
||||
if(BOX64ENV(dynarec_dirty)==2) {
|
||||
dynarec_log(LOG_INFO, "Switching page at %p to NEVERCLEAN\n", (void*)(page<<12));
|
||||
neverprotectDB(page<<12, box64_pagesize, 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// look for idx
|
||||
int idx = IdxHotPage(page);
|
||||
if(idx!=-1 && (BOX64ENV(dynarec_dirty)>1)) {
|
||||
@@ -2614,6 +2589,9 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
LOCK_PROT();
|
||||
uintptr_t cur = addr & ~(box64_pagesize-1);
|
||||
uintptr_t end = ALIGN(cur+size);
|
||||
#ifdef DYNAREC
|
||||
int check = BOX64ENV(dynarec);
|
||||
#endif
|
||||
//rb_set(mapallmem, cur, cur+size, MEM_ALLOCATED);
|
||||
while (cur < end) {
|
||||
uintptr_t bend;
|
||||
@@ -2621,7 +2599,21 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
rb_get_end(memprot, cur, &oprot, &bend);
|
||||
if(bend>end) bend = end;
|
||||
uint32_t dyn=(oprot&PROT_DYN);
|
||||
uint32_t never = dyn&PROT_NEVERPROT;
|
||||
if (dyn & PROT_NOPROT) {
|
||||
cur = bend;
|
||||
continue;
|
||||
}
|
||||
uint32_t never = dyn & PROT_NEVERCLEAN;
|
||||
#ifdef DYNAREC
|
||||
if(check && ((prot ^ oprot) & PROT_EXEC) && !never) { // prot_exec changed
|
||||
if(prot & PROT_EXEC) {
|
||||
// no need to do anything
|
||||
/*if(!IsAddrMappingLoadAndClean(cur))
|
||||
addDBFromAddressRange(cur, bend-cur);*/
|
||||
} else
|
||||
cleanDBFromAddressRange(cur, bend-cur, (!prot)?1:0);
|
||||
}
|
||||
#endif
|
||||
if(!(never)) {
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
@@ -2774,6 +2766,15 @@ void loadProtectionFromMap()
|
||||
have48bits = 1;
|
||||
}
|
||||
}
|
||||
if(!have48bits && !box64_is32bits) {
|
||||
void* probe = InternalMmap((void*)0x7fff00000000LL, box64_pagesize, PROT_NONE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
|
||||
if(probe!=MAP_FAILED) {
|
||||
if((uintptr_t)probe>=0x7fff00000000LL)
|
||||
have48bits = 1;
|
||||
InternalMunmap(probe, box64_pagesize);
|
||||
}
|
||||
}
|
||||
static int shown48bits = 0;
|
||||
if(!shown48bits) {
|
||||
shown48bits = 1;
|
||||
@@ -2821,7 +2822,12 @@ uint32_t getProtection_fast(uintptr_t addr)
|
||||
|
||||
int getMmapped(uintptr_t addr)
|
||||
{
|
||||
return (rb_get(mapallmem, addr)&MEM_ALLOCATED); // will be ok for both MEM_ALLOCATED & MEM_MMAP
|
||||
return (rb_get(mapallmem, addr)&MEM_MMAP) == MEM_MMAP;
|
||||
}
|
||||
|
||||
int getMAllocated(uintptr_t addr)
|
||||
{
|
||||
return (rb_get(mapallmem, addr)&MEM_ALLOCATED);
|
||||
}
|
||||
|
||||
int memExist(uintptr_t addr)
|
||||
@@ -2834,13 +2840,22 @@ int memExist(uintptr_t addr)
|
||||
#define MEDIUM (void*)0x40000000
|
||||
#define HIGH (void*)0x60000000
|
||||
|
||||
// only track what brk added: re-tracking the whole heap would lose PROT_EXEC on
|
||||
// pages the guest made executable in it (like hook trampolines)
|
||||
static void catchup_brk_protection(void)
|
||||
{
|
||||
if(pbrk && cur_brk && *cur_brk!=old_brk) {
|
||||
uintptr_t prev = old_brk ? old_brk : pbrk;
|
||||
old_brk = *cur_brk;
|
||||
if(old_brk > prev)
|
||||
setProtection(prev, old_brk-prev, PROT_READ|PROT_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
void* find31bitBlockNearHint(void* hint_, size_t size, uintptr_t mask)
|
||||
{
|
||||
// first, check if program break as changed
|
||||
if(pbrk && cur_brk && *cur_brk!=old_brk) {
|
||||
old_brk = *cur_brk;
|
||||
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
|
||||
}
|
||||
catchup_brk_protection();
|
||||
uint32_t prot;
|
||||
uintptr_t hint = (uintptr_t)hint_;
|
||||
if(hint_<LOWEST) hint = (uintptr_t)WINE_LOWEST;
|
||||
@@ -2891,10 +2906,7 @@ void* find47bitBlock(size_t size)
|
||||
void* find47bitBlockNearHint(void* hint, size_t size, uintptr_t mask)
|
||||
{
|
||||
// first, check if program break as changed
|
||||
if(pbrk && cur_brk && *cur_brk!=old_brk) {
|
||||
old_brk = *cur_brk;
|
||||
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
|
||||
}
|
||||
catchup_brk_protection();
|
||||
uint32_t prot;
|
||||
if(hint<LOWEST) hint = LOWEST;
|
||||
uintptr_t bend = 0;
|
||||
@@ -3095,31 +3107,22 @@ void init_custommem_helper(box64context_t* ctx)
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
rb_set(blockstree, (uintptr_t)p_blocks[i].block, (uintptr_t)p_blocks[i].block+p_blocks[i].size, i);
|
||||
memprot = rbtree_init("memprot");
|
||||
sigfillset(&critical_prot);
|
||||
#ifdef DYNAREC
|
||||
if(BOX64ENV(dynarec)) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT4); ++i)
|
||||
box64_jmptbl4[i] = box64_jmptbldefault3;
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i) {
|
||||
box64_jmptbldefault3[i] = box64_jmptbldefault2;
|
||||
box64_jmptbl_48[i] = box64_jmptbldefault2;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i) {
|
||||
box64_jmptbl3[i] = box64_jmptbldefault2;
|
||||
}
|
||||
box64_jmptbl4[0] = box64_jmptbl_48;
|
||||
#else
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i) {
|
||||
box64_jmptbl3[i] = box64_jmptbldefault2;
|
||||
box64_jmptbl_48[i] = box64_jmptbldefault1;
|
||||
}
|
||||
box64_jmptbl3[0] = box64_jmptbl_48;
|
||||
#endif
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i)
|
||||
box64_jmptbldefault2[i] = box64_jmptbldefault1;
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
|
||||
box64_jmptbldefault1[i] = box64_jmptbldefault0;
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
|
||||
box64_jmptbldefault0[i] = (uintptr_t)native_next;
|
||||
}
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i)
|
||||
box64_jmptbldefault2[i] = box64_jmptbldefault1;
|
||||
#else
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i) {
|
||||
box64_jmptbl2[i] = box64_jmptbldefault1;
|
||||
}
|
||||
#endif
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
|
||||
box64_jmptbldefault1[i] = box64_jmptbldefault0;
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
|
||||
box64_jmptbldefault0[i] = (uintptr_t)native_next;
|
||||
lockaddress = kh_init(lockaddress);
|
||||
rbt_dynmem = rbtree_init("rbt_dynmem");
|
||||
#endif
|
||||
@@ -3137,32 +3140,29 @@ void fini_custommem_helper(box64context_t *ctx)
|
||||
#ifdef TRACE_MEMSTAT
|
||||
uintptr_t njmps = 0, njmps_in_lv1_max = 0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t**** box64_jmptbl3;
|
||||
for(uintptr_t idx4 = 0; idx4 < (1<< JMPTABL_SHIFT4); ++idx4) {
|
||||
if (box64_jmptbl4[idx4] == box64_jmptbldefault3) continue;
|
||||
box64_jmptbl3 = box64_jmptbl4[idx4];
|
||||
#endif
|
||||
for (uintptr_t idx3 = 0; idx3 < (1 << JMPTABL_SHIFT3); ++idx3) {
|
||||
uintptr_t*** box64_jmptbl2;
|
||||
for(uintptr_t idx3 = 0; idx3 < (1<< JMPTABL_SHIFT3); ++idx3) {
|
||||
if (box64_jmptbl3[idx3] == box64_jmptbldefault2) continue;
|
||||
for (uintptr_t idx2 = 0; idx2 < (1 << JMPTABL_SHIFT2); ++idx2) {
|
||||
if (box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) continue;
|
||||
for (uintptr_t idx1 = 0; idx1 < (1 << JMPTABL_SHIFT1); ++idx1) {
|
||||
if (box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) continue;
|
||||
uintptr_t njmps_in_cur_lv1 = 0;
|
||||
for (uintptr_t idx0 = 0; idx0 < (1 << JMPTABL_SHIFT0); ++idx0) {
|
||||
if (box64_jmptbl3[idx3][idx2][idx1][idx0] == (uintptr_t)native_next) continue;
|
||||
++njmps;
|
||||
++njmps_in_cur_lv1;
|
||||
}
|
||||
if (njmps_in_cur_lv1 > njmps_in_lv1_max) njmps_in_lv1_max = njmps_in_cur_lv1;
|
||||
box64_jmptbl3 = box64_jmptbl3[idx3];
|
||||
#endif
|
||||
for (uintptr_t idx2 = 0; idx2 < (1 << JMPTABL_SHIFT2); ++idx2) {
|
||||
if (box64_jmptbl2[idx2] == box64_jmptbldefault1) continue;
|
||||
for (uintptr_t idx1 = 0; idx1 < (1 << JMPTABL_SHIFT1); ++idx1) {
|
||||
if (box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0) continue;
|
||||
uintptr_t njmps_in_cur_lv1 = 0;
|
||||
for (uintptr_t idx0 = 0; idx0 < (1 << JMPTABL_SHIFT0); ++idx0) {
|
||||
if (box64_jmptbl2[idx2][idx1][idx0] == (uintptr_t)native_next) continue;
|
||||
++njmps;
|
||||
++njmps_in_cur_lv1;
|
||||
}
|
||||
if (njmps_in_cur_lv1 > njmps_in_lv1_max) njmps_in_lv1_max = njmps_in_cur_lv1;
|
||||
}
|
||||
}
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
}
|
||||
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 4, %lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated4, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#else
|
||||
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#else
|
||||
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#endif
|
||||
if(BOX64ENV(log)) testAllBlocks();
|
||||
#endif
|
||||
@@ -3182,29 +3182,25 @@ void fini_custommem_helper(box64context_t *ctx)
|
||||
box_free(head);
|
||||
}
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t**** box64_jmptbl3;
|
||||
for(int i4 = 0; i4 < (1<< JMPTABL_SHIFT4); ++i4)
|
||||
if (box64_jmptbl4[i4] != box64_jmptbldefault3) {
|
||||
box64_jmptbl3 = box64_jmptbl4[i4];
|
||||
uintptr_t*** box64_jmptbl2;
|
||||
for(int i3 = 0; i3 < (1<< JMPTABL_SHIFT3); ++i3)
|
||||
if (box64_jmptbl3[i3] != box64_jmptbldefault2) {
|
||||
box64_jmptbl2 = box64_jmptbl3[i3];
|
||||
#endif
|
||||
for (int i3=0; i3<(1<<JMPTABL_SHIFT3); ++i3)
|
||||
if(box64_jmptbl3[i3]!=box64_jmptbldefault2) {
|
||||
for (int i2=0; i2<(1<<JMPTABL_SHIFT2); ++i2)
|
||||
if(box64_jmptbl3[i3][i2]!=box64_jmptbldefault1) {
|
||||
for (int i1=0; i1<(1<<JMPTABL_SHIFT1); ++i1)
|
||||
if(box64_jmptbl3[i3][i2][i1]!=box64_jmptbldefault0) {
|
||||
customFree(box64_jmptbl3[i3][i2][i1]);
|
||||
}
|
||||
customFree(box64_jmptbl3[i3][i2]);
|
||||
for (int i2=0; i2<(1<<JMPTABL_SHIFT2); ++i2)
|
||||
if(box64_jmptbl2[i2]!=box64_jmptbldefault1) {
|
||||
for (int i1=0; i1<(1<<JMPTABL_SHIFT1); ++i1)
|
||||
if(box64_jmptbl2[i2][i1]!=box64_jmptbldefault0) {
|
||||
customFree(box64_jmptbl2[i2][i1]);
|
||||
}
|
||||
#ifndef JMPTABL_SHIFT4
|
||||
if(i3)
|
||||
if(i2)
|
||||
#endif
|
||||
customFree(box64_jmptbl3[i3]);
|
||||
customFree(box64_jmptbl2[i2]);
|
||||
}
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
if(i4)
|
||||
customFree(box64_jmptbl4[i4]);
|
||||
if(i3)
|
||||
customFree(box64_jmptbl3[i3]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -3293,6 +3289,12 @@ EXPORT void* box_mmap(void *addr, size_t length, int prot, int flags, int fd, ss
|
||||
}
|
||||
#endif
|
||||
void* ret = InternalMmap(addr, length, prot, new_flags, fd, offset);
|
||||
// io_uring doesn't support non-NULL address.
|
||||
// The optimal approach is to detect whether an fd is an io_uring instance,
|
||||
// but this is overly complex. So we simply retry the mmap call with the
|
||||
// original address here.
|
||||
if (ret == MAP_FAILED && old_addr == NULL && fd >= 0)
|
||||
ret = InternalMmap(old_addr, length, prot, new_flags, fd, offset);
|
||||
#if !defined(NOALIGN)
|
||||
if((ret!=MAP_FAILED) && (flags&MAP_32BIT) &&
|
||||
(((uintptr_t)ret>0xffffffffLL) || ((box64_wine) && ((uintptr_t)ret&0xffff) && (ret!=addr)))) {
|
||||
|
||||
@@ -1067,9 +1067,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, Ed, Id");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -1138,9 +1138,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gd, Ed, Ib");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -1842,7 +1842,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
POP1z(xFlags);
|
||||
MOV32w(x1, 0x3E7FD7);
|
||||
ANDw_REG(xFlags, xFlags, x1);
|
||||
@@ -2006,6 +2006,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
@@ -2058,11 +2062,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
STRB_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2071,6 +2079,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSD");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRxw_S9_postindex(x1, xRSI, rex.w?8:4);
|
||||
@@ -2086,11 +2098,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSD");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
LDRxw_U12(x1, xRSI, 0);
|
||||
STRxw_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2101,11 +2117,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ CMPSB");} else {INST_NAME("REPZ CMPSB");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRB_S9_postindex(x1, xRSI, 1);
|
||||
@@ -2128,12 +2148,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
INST_NAME("CMPSB");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
SMREAD();
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
LDRB_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2145,11 +2169,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ CMPSD");} else {INST_NAME("REPZ CMPSD");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRxw_S9_postindex(x1, xRSI, rex.w?8:4);
|
||||
@@ -2172,12 +2200,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
INST_NAME("CMPSD");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
SMREAD();
|
||||
LDRxw_U12(x1, xRSI, 0);
|
||||
LDRxw_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2200,6 +2232,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
@@ -2244,9 +2279,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSB");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
STRB_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2254,6 +2292,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSD");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
STRxw_S9_postindex(xRAX, xRDI, rex.w?8:4);
|
||||
@@ -2268,9 +2309,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSD");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
STRxw_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2286,8 +2330,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBZx_NEXT(xRCX);
|
||||
MARK;
|
||||
}
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
LDRB_U12(x2, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x1);
|
||||
ADDy_REG(xRSI, xRSI, x1);
|
||||
if(rex.rep) {
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
@@ -2305,8 +2352,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBZx_NEXT(xRCX);
|
||||
MARK;
|
||||
}
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
LDRxw_U12(xRAX, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x1);
|
||||
ADDy_REG(xRSI, xRSI, x1);
|
||||
if(rex.rep) {
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
@@ -2319,11 +2369,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ SCASB");} else {INST_NAME("REPZ SCASB");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
UBFXw(x1, xRAX, 0, 8);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
@@ -2345,10 +2398,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
INST_NAME("SCASB");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
UBFXw(x1, xRAX, 0, 8);
|
||||
LDRB_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2360,11 +2416,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ SCASD");} else {INST_NAME("REPZ SCASD");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRxw_S9_postindex(x2, xRDI, rex.w?8:4);
|
||||
@@ -2385,9 +2444,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
INST_NAME("SCASD");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
LDRxw_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2447,10 +2509,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Eb, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 1);
|
||||
u8 = F8&0x1f;
|
||||
emit_rol8c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_rol8c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EBBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -2461,10 +2523,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROR Eb, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 1);
|
||||
u8 = F8&0x1f;
|
||||
emit_ror8c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_ror8c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EBBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -2553,7 +2615,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
@@ -2572,7 +2634,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
@@ -3087,14 +3149,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Eb, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 0);
|
||||
emit_rol8c(dyn, ninst, ed, 1, x4, x5);
|
||||
emit_rol8c(dyn, ninst, ed, 1, x4, x5, 0);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Eb, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 0);
|
||||
emit_ror8c(dyn, ninst, ed, 1, x4, x5);
|
||||
emit_ror8c(dyn, ninst, ed, 1, x4, x5, 0);
|
||||
EBBACK;
|
||||
break;
|
||||
case 2:
|
||||
@@ -3341,7 +3403,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHL Eb, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -3356,7 +3418,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHR Eb, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -3371,7 +3433,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Eb, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -3465,9 +3527,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETED(0);
|
||||
UFLAG_IF {
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
}
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
WBACK;
|
||||
@@ -3486,9 +3546,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETED(0);
|
||||
UFLAG_IF {
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
}
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
WBACK;
|
||||
@@ -3498,7 +3556,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHL Ed, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.w) {
|
||||
@@ -3518,7 +3576,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHR Ed, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.w) {
|
||||
@@ -3538,7 +3596,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Ed, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.w) {
|
||||
@@ -3839,22 +3897,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//fpu_purgecache(dyn, ninst, 0, x1, x3, x4, 0);
|
||||
PUSH1z(x2);
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
if(can_continue && BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
STPx_S7_preindex(x4, x2, xSP, -16);
|
||||
} else {
|
||||
*ok = 0;
|
||||
@@ -3864,12 +3916,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
j64 = (uint32_t)(addr+i32);
|
||||
else
|
||||
j64 = addr+i32;
|
||||
j64 = (uintptr_t)getAlternate((void*)j64);
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
CALLRET_RET(can_continue);
|
||||
MARK;
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
if(dyn->need_reloc) {
|
||||
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
|
||||
@@ -4041,9 +4093,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL AL, Eb");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETEB(x1, 0);
|
||||
UXTBw(x2, xRAX);
|
||||
@@ -4071,9 +4123,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("IMUL AL, Eb");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETSEB(x1, 0);
|
||||
SXTBw(x2, xRAX);
|
||||
@@ -4102,7 +4154,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Eb");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
FORCE_DFNONE();
|
||||
GETEB(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
@@ -4140,7 +4192,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Eb");
|
||||
SKIPTEST(x1);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else if (BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
@@ -4200,9 +4252,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETED(0);
|
||||
if(rex.w) {
|
||||
@@ -4237,9 +4289,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETED(0);
|
||||
if(rex.w) {
|
||||
@@ -4273,7 +4325,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
FORCE_DFNONE();
|
||||
if(!rex.w) {
|
||||
GETED(0);
|
||||
@@ -4371,9 +4423,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Ed");
|
||||
SKIPTEST(x1);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else if (BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
if(!rex.w) {
|
||||
GETSEDw(0);
|
||||
@@ -4614,10 +4666,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
|
||||
@@ -1874,7 +1874,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
@@ -1964,7 +1964,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
@@ -2075,7 +2075,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.is32bits);
|
||||
MOV32w(x2, rex.is32bits);
|
||||
CALL(const_fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
@@ -2084,7 +2084,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.is32bits);
|
||||
MOV32w(x2, rex.is32bits);
|
||||
CALL(const_fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
@@ -2100,9 +2100,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -2421,7 +2421,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2459,7 +2459,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2671,7 +2671,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
|
||||
@@ -424,9 +424,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode==0x69)?2:1);
|
||||
@@ -787,7 +787,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SMREAD();
|
||||
POP1_16(x1);
|
||||
MOV32w(x2, 0x7FD7);
|
||||
@@ -883,6 +883,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
@@ -898,11 +902,15 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
STRH_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -915,10 +923,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
@@ -941,11 +953,15 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
INST_NAME("CMPSW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
LDRH_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -963,6 +979,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
STRH_S9_postindex(xRAX, xRDI, 2);
|
||||
@@ -977,9 +996,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
STRH_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -988,6 +1010,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP LODSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x2, xRSI, 2);
|
||||
@@ -1003,9 +1028,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("LODSW");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x2, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
BFIz(xRAX, x2, 0, 16);
|
||||
}
|
||||
break;
|
||||
@@ -1017,10 +1045,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
UXTHw(x1, xRAX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
@@ -1042,10 +1073,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
default:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
UXTHw(x1, xRAX);
|
||||
LDRH_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -1076,10 +1110,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -1089,10 +1123,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -1207,14 +1241,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
emit_rol16c(dyn, ninst, x1, 1, x5, x4);
|
||||
emit_rol16c(dyn, ninst, x1, 1, x5, x4, 0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
emit_ror16c(dyn, ninst, x1, 1, x5, x4);
|
||||
emit_ror16c(dyn, ninst, x1, 1, x5, x4, 0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
@@ -1405,7 +1439,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHL Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -1420,7 +1454,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHR Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -1435,7 +1469,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -1545,9 +1579,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
@@ -1576,9 +1610,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
SXTHw(x2, xRAX);
|
||||
@@ -1607,7 +1641,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
@@ -1647,9 +1681,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Ew");
|
||||
SKIPTEST(x1);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else if (BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
|
||||
@@ -304,7 +304,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
@@ -497,7 +497,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x17:
|
||||
INST_NAME("PTEST Gx, Ex");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
GETGX(v0, 0);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -1367,7 +1367,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETG;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
if((u8&0b1100)==0b1000) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
// this case is (un)signed word, equal each
|
||||
GETGX(v0, 0);
|
||||
GETEX(v1, 0, 1);
|
||||
@@ -2058,7 +2058,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
u8 = F8;
|
||||
GETGX_empty(v0);
|
||||
@@ -2485,7 +2485,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x2);
|
||||
@@ -2554,7 +2554,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x2);
|
||||
@@ -2593,9 +2593,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETSEW(x1, 0);
|
||||
@@ -2809,7 +2809,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2845,7 +2845,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2923,9 +2923,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
BFIx(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 0, 16);
|
||||
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
if (!(MODREG && wback == u8)) MOVx_REG(x6, ed);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
if (!(MODREG && wback == u8)) BFIx(u8, x6, 0, 16);
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
|
||||
@@ -49,7 +49,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
switch(opcode) {
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
@@ -85,7 +85,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
@@ -123,7 +123,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
|
||||
@@ -73,8 +73,8 @@ uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || dyn->need_dump) {
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || (dyn->need_dump && dyn->need_dump != 3) || BOX64ENV(dynarec_missing)))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || (dyn->need_dump && dyn->need_dump != 3)) {
|
||||
dynarec_log(LOG_NONE, " Dynarec unimplemented %s opcode size %d prefix %s map %s opcode %02X\n",
|
||||
vex.evex ? "EVEX" : "VEX", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("VCOMISS Gx, Ex");} else {INST_NAME("VUCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
|
||||
@@ -264,7 +264,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("VCOMISD Gx, Ex");} else {INST_NAME("VUCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
|
||||
@@ -1904,7 +1904,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -1920,8 +1923,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1944,7 +1947,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -1960,8 +1966,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1985,7 +1991,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -2001,8 +2010,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -2025,7 +2034,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -2041,8 +2053,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
|
||||
@@ -76,6 +76,8 @@ uintptr_t getConst(arm64_consts_t which)
|
||||
case const_native_fxtract: return (uintptr_t)native_fxtract;
|
||||
case const_direct_ftan: return (uintptr_t)direct_ftan;
|
||||
case const_direct_fpatan: return (uintptr_t)direct_fpatan;
|
||||
case const_native_fprem: return (uintptr_t)native_fprem;
|
||||
case const_native_fprem1: return (uintptr_t)native_fprem1;
|
||||
case const_direct_fcos: return (uintptr_t)direct_fcos;
|
||||
case const_direct_fsin: return (uintptr_t)direct_fsin;
|
||||
case const_native_fsincos: return (uintptr_t)native_fsincos;
|
||||
|
||||
@@ -39,6 +39,8 @@ typedef enum arm64_consts_s {
|
||||
const_native_fxtract,
|
||||
const_direct_ftan,
|
||||
const_direct_fpatan,
|
||||
const_native_fprem,
|
||||
const_native_fprem1,
|
||||
const_direct_fcos,
|
||||
const_direct_fsin,
|
||||
const_native_fsincos,
|
||||
|
||||
@@ -343,26 +343,42 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
FMULD(s0, s0, v2);
|
||||
FSUBD(v1, v1, s0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
i1 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(const_native_fprem1, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, i1);
|
||||
} else {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVxD(x4, v2);
|
||||
LSLx(x4, x4, 1); // remove sign bit
|
||||
RORx(x4, x4, 53); // put exponant in lower 12bits
|
||||
SUBx_U12(x4, x4, 0x7ff);// test is inifite
|
||||
CBNZx_MARK2(x4);
|
||||
MOV32w(x4, 0); // force q to 0
|
||||
B_MARK_nocond;
|
||||
MARK2;
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
FMSUB_64(v1, v1, s0, v2);
|
||||
MARK;
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
}
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -382,26 +398,42 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
FMULD(s0, s0, v2);
|
||||
FSUBD(v1, v1, s0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
if(!rex.is32bits || !BOX64ENV(dynarec_fastround)) {
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
i1 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(const_native_fprem, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, i1);
|
||||
} else {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVxD(x4, v2);
|
||||
LSLx(x4, x4, 1); // remove sign bit
|
||||
RORx(x4, x4, 53); // put exponant in lower 12bits
|
||||
SUBx_U12(x4, x4, 0x7ff);// test is inifite
|
||||
CBNZx_MARK2(x4);
|
||||
MOV32w(x4, 0); // force q to 0
|
||||
B_MARK_nocond;
|
||||
MARK2;
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
FMSUB_64(v1, v1, s0, v2);
|
||||
MARK;
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
}
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
@@ -456,7 +488,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_D(const_direct_fscale, v1, v1, v2, -1, -1);
|
||||
else
|
||||
u8 = 0;
|
||||
CALL_D(const_direct_fscale, v1, v1, v2, u8, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -466,7 +500,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_D(const_direct_fsin, v1, v1, -1, -1, -1);
|
||||
else
|
||||
u8 = 0;
|
||||
CALL_D(const_direct_fsin, v1, v1, -1, u8, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -476,7 +512,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_D(const_direct_fcos, v1, v1, -1, -1, -1);
|
||||
else
|
||||
u8 = 0;
|
||||
CALL_D(const_direct_fcos, v1, v1, -1, u8, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -145,7 +145,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
|
||||
@@ -159,7 +159,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
|
||||
@@ -312,7 +312,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) || !rex.is32bits) {
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
|
||||
@@ -98,7 +98,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
|
||||
@@ -113,7 +113,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
|
||||
|
||||
@@ -969,17 +969,18 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
}
|
||||
|
||||
// emit ROL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) {
|
||||
LSRw(s3, s1, 6);
|
||||
EORw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
LSRw(s3, s1, 6);
|
||||
EORw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
if(c&7) {
|
||||
int rc = 8-(c&7);
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
@@ -995,14 +996,14 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
}
|
||||
|
||||
// emit ROR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX(X_OF) {
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
EORw_REG_LSR(s3, s1, s1, 7);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
@@ -1023,14 +1024,14 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
}
|
||||
|
||||
// emit ROL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX2(X_OF, && c == 1) {
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
LSRw(s3, s1, 14);
|
||||
EORw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
@@ -1051,14 +1052,14 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
|
||||
// emit ROR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX2(X_OF, && c == 1) {
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
EORw_REG_LSR(s3, s1, s1, 15);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -667,7 +667,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
@@ -701,7 +701,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
|
||||
@@ -483,7 +483,7 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
if(((t==NEON_CACHE_XMMR) || (t==NEON_CACHE_XMMW)) && (cache_i2.xmm_unneeded&(1<<n))) { /* nothing*/}
|
||||
else if(((t==NEON_CACHE_YMMR) || (t==NEON_CACHE_YMMW)) && (cache_i2.ymm_unneeded&(1<<n))) { /* nothing*/}
|
||||
else
|
||||
else
|
||||
return 1;
|
||||
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
|
||||
if(n!=cache_i2.neoncache[i].n) { // not the same x64 reg
|
||||
@@ -776,6 +776,11 @@ static const char* df_status[] = {"unknown", "set", "none_pending", "none"};
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
if (dyn->need_dump == 3) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
if (!BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map))
|
||||
return;
|
||||
}
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) {
|
||||
/*zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
|
||||
if(dec && !OpcodeOK(dec, dyn->insts[ninst].x64.addr) && !strstr(name, "Illegal")) {
|
||||
@@ -805,8 +810,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
else
|
||||
length += sprintf(buf + length, " NF:%d", dyn->insts[ninst].nat_flags_op);
|
||||
}
|
||||
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags) {
|
||||
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
|
||||
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags || dyn->insts[ninst].nat_flags_in) {
|
||||
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx->%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].nat_flags_in, dyn->insts[ninst].need_nat_flags);
|
||||
}
|
||||
if (dyn->insts[ninst].invert_carry)
|
||||
length += sprintf(buf + length, " CI");
|
||||
@@ -880,7 +885,9 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
if (dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
length += sprintf(buf + length, " %s:%d/%d", dyn->insts[ninst].n.swapped ? "SWP" : "CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
}
|
||||
if (dyn->need_dump) {
|
||||
if(dyn->insts[ninst].x64.self_loop)
|
||||
length += sprintf(buf + length, " self-loop");
|
||||
if (dyn->need_dump && dyn->need_dump != 3) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, %s%s\n",
|
||||
(dyn->need_dump > 1) ? "\e[32m" : "",
|
||||
@@ -1108,6 +1115,7 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
//printf_log(LOG_INFO, " will use:%x, carry:%d, generate inverted carry:%d\n", used_flags, used_flags&NF_CF, dyn->insts[ninst].gen_inverted_carry);
|
||||
if(!used_flags) return; // the flags wont be used, so just cancel
|
||||
int nc = dyn->insts[ninst].gen_inverted_carry?0:1;
|
||||
int oldnc = nc;
|
||||
int carry = used_flags&NF_CF;
|
||||
// propagate
|
||||
while(ninst<dyn->size) {
|
||||
@@ -1143,6 +1151,10 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
return;
|
||||
} else
|
||||
++ninst;
|
||||
if(ninst<dyn->size) {
|
||||
dyn->insts[ninst].nat_flags_in |= used_flags&use_flags;
|
||||
if(carry) dyn->insts[ninst].normal_carry_in = oldnc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1353,7 +1365,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
}
|
||||
// we will stop there, not trying to guess too much thing
|
||||
if((usefull && (i+1)!=ninst)) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
@@ -1363,7 +1375,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
for(int pred=0; pred<dyn->insts[i].pred_sz; ++pred) {
|
||||
if(dyn->insts[i].pred[pred]<=last_fpu_used) {
|
||||
if(usefull && ((i+1)!=ninst)) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
@@ -1373,7 +1385,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
usefull = 1;
|
||||
}
|
||||
if(usefull) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
dyn->insts[last_fpu_used+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
}
|
||||
@@ -1524,7 +1536,7 @@ static int ymm_preload_reg(dynarec_arm_t* dyn, int ninst, int last, int ymm)
|
||||
while((ninst<last) && (i!=-1)) {
|
||||
// check if the reg is always free
|
||||
if(!(!dyn->insts[ninst].n.neoncache[i].v ||
|
||||
(dyn->insts[ninst].n.neoncache[i].n==ymm
|
||||
(dyn->insts[ninst].n.neoncache[i].n==ymm
|
||||
&& (dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_YMMR || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_YMMW))))
|
||||
i = -1; // nope
|
||||
else
|
||||
|
||||
@@ -517,6 +517,7 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
|
||||
rex_t dummy = {0};
|
||||
dummy.is32bits = is32bits;
|
||||
dummy.w = is64bits;
|
||||
TBNZ_MARK2(xFlags, F_TF);
|
||||
ret_to_next(dyn, ip, ninst, dummy);
|
||||
CLEARIP();
|
||||
MARK;
|
||||
@@ -530,6 +531,11 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
|
||||
else
|
||||
ADDx_U12(xRSP, xRSP, 4*3);
|
||||
CALL_S(const_native_priv, -1);
|
||||
MARK2;
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
ORRw_mask(x4, x4, 32-FLAGS_NO_TF, 0); //mask=1<<FLAGS_NO_TF
|
||||
STRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
}
|
||||
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
|
||||
@@ -665,13 +671,10 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
MOVx_REG(x4, xR8);
|
||||
MOVx_REG(x5, xR9);
|
||||
// native call
|
||||
if(dyn->need_reloc) {
|
||||
// fnc is indirect, to help with relocation (but PltResolver might be an issue here)
|
||||
TABLE64(16, (uintptr_t)fnc);
|
||||
LDRx_U12(16, 16, 0);
|
||||
} else {
|
||||
TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
|
||||
}
|
||||
TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
|
||||
// Note that if need_reloc is active, the TABLE64 will trigger cancel block,
|
||||
// because native function might be very different on a next run: different function address, different brick, different everything basicaly
|
||||
// and we don't have a relocation mecanism here, it's too complex
|
||||
BLR(16);
|
||||
// put return value in x64 regs
|
||||
if(w>0) {
|
||||
@@ -2314,7 +2317,7 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return;
|
||||
if(dyn->insts[jmp].f_exit==dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
if(dyn->insts[ninst].f_exit==dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
return;
|
||||
if(dyn->insts[jmp].df_notneeded)
|
||||
return;
|
||||
@@ -2458,47 +2461,61 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
|
||||
nativeFlagsTransform(dyn, ninst, x1, x2);
|
||||
}
|
||||
|
||||
static void flush_native_flags(dynarec_arm_t* dyn, int ninst, int s1, uint8_t flags, uint8_t ic)
|
||||
{
|
||||
// some flags disapear, and need to be saved
|
||||
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", flags);
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(flags&NF_EQ) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
}
|
||||
if(flags&NF_SF) {
|
||||
CSETw(s1, cMI);
|
||||
BFIw(xFlags, s1, F_SF, 1);
|
||||
}
|
||||
if(flags&NF_VF) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if(flags&NF_PF_V) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_PF, 1);
|
||||
}
|
||||
if(flags&NF_CF) {
|
||||
if(ic) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
else
|
||||
CSETw(s1, cCC);
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void additionnal_checks(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int s1 = x1;
|
||||
// check if a opcode generate partial flags that may clober existing native flags and see need to be "moved" to xFlags
|
||||
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before) {
|
||||
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before || (dyn->insts[ninst].nat_flags_in!=dyn->insts[ninst].need_nat_flags)) {
|
||||
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that will be generated
|
||||
uint8_t nat_flags_gen = dyn->insts[ninst].set_nat_flags;
|
||||
//TODO: does it need to fetch previous state with getPred?
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].before_nat_flags; //flags before the opcode, but it's only there when opcode also consume natflags
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
|
||||
uint8_t nat_flags_flush = nat_flags_before&~nat_flags_gen; // flags present before bu not after the operation and so that needs to be spared
|
||||
if(nat_flags_before && nat_flags_flush) {
|
||||
// some flags disapear, and need to be saved
|
||||
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", nat_flags_flush);
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(nat_flags_flush&NF_EQ) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_SF) {
|
||||
CSETw(s1, cMI);
|
||||
BFIw(xFlags, s1, F_SF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_VF) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_PF_V) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_PF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_CF) {
|
||||
if(nc_before) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
else
|
||||
CSETw(s1, cCC);
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
}
|
||||
if(nat_flags_before && nat_flags_flush)
|
||||
flush_native_flags(dyn, ninst, s1, nat_flags_flush, dyn->insts[ninst].normal_carry_in);
|
||||
}
|
||||
}
|
||||
|
||||
void flushNative(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int s1 = x1;
|
||||
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that is needed after
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
|
||||
uint8_t nat_flags_flush = nat_flags_before&~nat_flags; // flags present before bu not after the operation and so that needs to be spared
|
||||
if(nat_flags_flush)
|
||||
flush_native_flags(dyn, ninst, s1, nat_flags_flush, dyn->insts[ninst].normal_carry_in);
|
||||
}
|
||||
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_reflectcache(dyn, ninst, s1, s2, s3);
|
||||
@@ -2621,7 +2638,7 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
dyn->ymm_zero = dyn->insts[reset_n].ymm0_out;
|
||||
#endif
|
||||
#if STEP == 0
|
||||
if(dyn->need_dump && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
if(dyn->need_dump && dyn->need_dump != 3 && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
if(dyn->need_dump && 0) //disable for now, need more work
|
||||
|
||||
@@ -957,7 +957,7 @@
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -965,7 +965,7 @@
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -973,7 +973,7 @@
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1005,7 +1005,7 @@
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
} else if((A)==X_ALL) flushNative(dyn, ninst);
|
||||
#endif
|
||||
|
||||
#define GRABFLAGS(A) \
|
||||
@@ -1342,6 +1342,7 @@
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
#define additionnal_checks STEPNAME(additionnal_checks)
|
||||
#define flushNative STEPNAME(flushNative)
|
||||
|
||||
#define arm64_move32 STEPNAME(arm64_move32)
|
||||
#define arm64_move64 STEPNAME(arm64_move64)
|
||||
@@ -1445,10 +1446,10 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_rcl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
@@ -1509,6 +1510,7 @@ void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
|
||||
void additionnal_checks(dynarec_arm_t* dyn, int ninst);
|
||||
void flushNative(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
|
||||
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
|
||||
|
||||
@@ -16,7 +16,15 @@
|
||||
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f=status_none; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }}
|
||||
#define EMIT(A) dyn->native_size+=4
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
|
||||
#define JUMP(A, C) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.jmp = (uintptr_t)(A); \
|
||||
add_jump(dyn, ninst); \
|
||||
add_next(dyn, dyn->insts[ninst].x64.jmp); \
|
||||
SMEND(); \
|
||||
dyn->insts[ninst].x64.jmp_cond = C; \
|
||||
dyn->insts[ninst].x64.jmp_insts = 0; \
|
||||
} while (0)
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
|
||||
#define NEW_INST \
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
|
||||
// do not update dyn->f for SETFLAGS(..., SF_SET_PENDING) because it will use either DF_NONE or DF_SET anyway (similar to SF_SET_NODF)
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
|
||||
if(((B)&SF_SET_PENDING)!=SF_SET_PENDING) dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):((dyn->f==status_none)?status_none:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; }
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#define MESSAGE(A, ...) \
|
||||
do { \
|
||||
if (dyn->need_dump) dynarec_log_prefix(0, LOG_NONE, __VA_ARGS__); \
|
||||
if (dyn->need_dump && dyn->need_dump != 3) dynarec_log_prefix(0, LOG_NONE, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define ENDPREFIX dyn->insts[ninst].size2 = 0
|
||||
#define NEW_INST \
|
||||
|
||||
@@ -135,8 +135,10 @@ typedef struct instruction_arm64_s {
|
||||
uint8_t nat_flags_op_before:4;// what happens to native flags here
|
||||
uint8_t before_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t need_nat_flags;
|
||||
uint8_t nat_flags_in; // native flags at the entry of the opcode
|
||||
unsigned gen_inverted_carry:1;
|
||||
unsigned normal_carry:1;
|
||||
unsigned normal_carry_in:1;
|
||||
unsigned normal_carry_before:1;
|
||||
unsigned invert_carry:1; // this opcode force an inverted carry
|
||||
unsigned df_needed:1;
|
||||
|
||||
@@ -38,7 +38,7 @@ void* create_updateflags()
|
||||
dynarec_arm_t helper = {0};
|
||||
instruction_arm64_t insts[1] = {0};
|
||||
helper.insts = insts;
|
||||
helper.need_dump = BOX64ENV(dynarec_dump);
|
||||
helper.need_dump = BOX64ENV(dynarec_dump) == 3 ? 0 : BOX64ENV(dynarec_dump);
|
||||
helper.cap = 1;
|
||||
helper.f = status_none;
|
||||
helper.insts[0].x64.gen_flags = X_ALL;
|
||||
@@ -130,4 +130,4 @@ void* create_updateflags()
|
||||
|
||||
updaflags_arm64 = block;
|
||||
return block->block;
|
||||
}
|
||||
}
|
||||
+25
-12
@@ -75,6 +75,26 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
return db;
|
||||
}
|
||||
|
||||
static void DeferFreeDynablockMap(dynablock_t* db)
|
||||
{
|
||||
// enq for a deferred free so any threads still running in this block has a better chance to finish.
|
||||
if (my_context->db_zombie_count == DB_ZOMBIE_SIZE) {
|
||||
if(my_context->db_zombie[my_context->db_zombie_head])
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[my_context->db_zombie_head]->actual_block);
|
||||
} else {
|
||||
my_context->db_zombie_count++;
|
||||
}
|
||||
my_context->db_zombie[my_context->db_zombie_head] = db;
|
||||
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
|
||||
}
|
||||
|
||||
void DeferFreeDynablockClearRange(void* addr, size_t sz)
|
||||
{
|
||||
for(int i=0; i<my_context->db_zombie_count; ++i)
|
||||
if(my_context->db_zombie[i] && ((void*)my_context->db_zombie[i]>=addr) && ((void*)my_context->db_zombie[i]<(addr+sz)))
|
||||
my_context->db_zombie[i] = NULL;
|
||||
}
|
||||
|
||||
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
@@ -84,21 +104,15 @@ void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
uintptr_t db_size = db->x64_size;
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
if(db_size && my_context && BOX64ENV(dynarec_dirty)) {
|
||||
// need_lock is also used to check if db_size needs to be decremented...
|
||||
if(need_lock && db_size && my_context && BOX64ENV(dynarec_dirty)) {
|
||||
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
|
||||
if(!n && (db_size >= my_context->max_db_size)) {
|
||||
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
// enq for a deferred free so any threads still running in this block has a better chance to finish.
|
||||
if (my_context->db_zombie_count == DB_ZOMBIE_SIZE) {
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[my_context->db_zombie_head]->actual_block);
|
||||
} else {
|
||||
my_context->db_zombie_count++;
|
||||
}
|
||||
my_context->db_zombie[my_context->db_zombie_head] = db;
|
||||
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
|
||||
DeferFreeDynablockMap(db);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
@@ -130,14 +144,12 @@ void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
|
||||
DeferFreeDynablockMap(db);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
@@ -248,6 +260,7 @@ dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
|
||||
|
||||
dynarec_log(LOG_DEBUG, "Will call Fillblock64 for Alt %p\n", (void*)addr);
|
||||
dynablock_t* block = FillBlock64(addr, is32bits, MAX_INSTS, 0, 1);
|
||||
if(block && block->block) block->done = 1; // validate the alt block
|
||||
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
|
||||
+12
-14
@@ -244,22 +244,20 @@ void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
|
||||
}
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->flags.need_jmpbuf = 0;
|
||||
if(no_alt)
|
||||
{
|
||||
// the Dynarec will shadow the Entry Point, so using Intperter to enter the function
|
||||
#if defined(DYNAREC) && defined(HAVE_ALTJUMP)
|
||||
if(!BOX64ENV(dynarec))
|
||||
#endif
|
||||
no_alt = 0;
|
||||
skip = 1;
|
||||
}
|
||||
else
|
||||
#ifndef DYNAREC
|
||||
Run(emu, 0);
|
||||
#else
|
||||
if(no_alt) {
|
||||
// the Dynarec will shadow the Entry Point, so using Intperter to enter the function
|
||||
#if defined(DYNAREC) && defined(HAVE_ALTJUMP)
|
||||
if(!BOX64ENV(dynarec))
|
||||
#endif
|
||||
no_alt = 0;
|
||||
skip = 1;
|
||||
} else
|
||||
R_RIP = (uintptr_t)getAlternate((void*)R_RIP);
|
||||
#ifdef DYNAREC
|
||||
if(!BOX64ENV(dynarec) || !use_dynarec)
|
||||
#endif
|
||||
Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
int newis32bits = (emu->segs[_CS]==0x23);
|
||||
if(newis32bits!=is32bits) {
|
||||
@@ -281,7 +279,7 @@ void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
|
||||
#ifdef HAVE_ALTJUMP
|
||||
if(skip && no_alt) {
|
||||
block = getDBnoAlt(emu, R_RIP, is32bits);
|
||||
no_alt = 0;
|
||||
skip = no_alt = 0;
|
||||
}
|
||||
#endif
|
||||
if(!block || !block->block || !block->done || ACCESS_FLAG(F_TF)) {
|
||||
|
||||
@@ -59,6 +59,7 @@ extern void arm64_next_invalid();
|
||||
#include "la64/la64_printer.h"
|
||||
#include "la64/dynarec_la64_private.h"
|
||||
#include "la64/dynarec_la64_functions.h"
|
||||
#include "la64/dynarec_la64_arch.h"
|
||||
// Limit here is unconditionnal jump, that is signed 28bits
|
||||
#define MAXBLOCK_SIZE ((1 << 27) - 200)
|
||||
|
||||
@@ -67,17 +68,17 @@ extern void arm64_next_invalid();
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define POSTUPDATE_SPECIFICS(A)
|
||||
|
||||
#define ARCH_SIZE(A) 0
|
||||
#define ARCH_FILL(A, B, C) NULL
|
||||
#define ARCH_ADJUST(A, B, C, D) {}
|
||||
#define ARCH_SIZE(A) get_size_arch(A)
|
||||
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
|
||||
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
|
||||
#define STOP_NATIVE_FLAGS(A, B) {}
|
||||
#define ARCH_UNALIGNED(A, B) 0
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
extern uint32_t la64_crc(void* p, uint32_t len);
|
||||
extern void la64_crc_autocrc(); // same as la64_crc, but not using regular ABI
|
||||
#define ARCH_CRC(A, B) return la64_crc(A, B)
|
||||
|
||||
#define ARCH_NOP (0b0000001101<<22)
|
||||
#define ARCH_UDF 0b1010100
|
||||
#define ARCH_UDF 0x38600400
|
||||
|
||||
#define JMPNEXT_SIZE (4*sizeof(void*))
|
||||
#define ADDITIONNAL_CHECKS()
|
||||
|
||||
@@ -27,54 +27,53 @@
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT64(table64, uint32_t)
|
||||
KHASH_SET_INIT_INT64(nextset)
|
||||
KHASH_MAP_INIT_INT64(jumpaddr, int)
|
||||
|
||||
static kh_nextset_t* khnextset = NULL;
|
||||
static kh_jumpaddr_t* khjumpaddr = NULL;
|
||||
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
if (ip[0] == 0xcc && IsBridgeSignature(ip[1], ip[2])) {
|
||||
uintptr_t a = *(uintptr_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (dyn->need_dump>1)?"\e[01;33m":"", (void*)ip, (dyn->need_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (dyn->need_dump == 2)?"\e[01;33m":"", (void*)ip, (dyn->need_dump == 2)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (dyn->need_dump>1)?"\e[01;33m":"", (void*)ip, (void*)a, (dyn->need_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (dyn->need_dump == 2)?"\e[01;33m":"", (void*)ip, (void*)a, (dyn->need_dump == 2)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (dyn->need_dump > 1) ? "\e[01;33m" : "", ip, DecodeX64Trace(dec, inst->addr, 1));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (dyn->need_dump == 2) ? "\e[01;33m" : "", ip, DecodeX64Trace(dec, inst->addr, 1));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (dyn->need_dump>1)?"\e[01;33m":"", ip);
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (dyn->need_dump == 2)?"\e[01;33m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log_prefix(0, LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
dynarec_log_prefix(0, LOG_NONE, " %s", name);
|
||||
}
|
||||
// print Call function name if possible
|
||||
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
|
||||
if(dyn->need_dump != 3 && (ip[0]==0xE8 || ip[0]==0xE9)) { // Call / Jmp
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
|
||||
PrintFunctionAddr(nextaddr, "=> ");
|
||||
} else if(ip[0]==0xFF) {
|
||||
} else if(dyn->need_dump != 3 && ip[0]==0xFF) {
|
||||
if(ip[1]==0x25) {
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
|
||||
PrintFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
// end of line and colors
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_dump>1)?"\e[m":"");
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_dump == 2)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void add_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
if (!BOX64DRENV(dynarec_bigblock))
|
||||
return;
|
||||
// exist?
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
// put in a free slot
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(!dyn->next[i]) {
|
||||
dyn->next[i] = addr;
|
||||
return;
|
||||
}
|
||||
int ret;
|
||||
kh_put(nextset, khnextset, addr, &ret);
|
||||
if(!ret)
|
||||
return;
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
printf_log(LOG_NONE, "Warning, overallocating next\n");
|
||||
@@ -85,15 +84,19 @@ uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
// get closest, but no addresses before
|
||||
uintptr_t best = 0;
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
while(i<dyn->next_sz) {
|
||||
uintptr_t next = dyn->next[i];
|
||||
if(!next || next<addr) {
|
||||
if(next) {
|
||||
khint_t k = kh_get(nextset, khnextset, next);
|
||||
if(k != kh_end(khnextset))
|
||||
kh_del(nextset, khnextset, k);
|
||||
}
|
||||
dyn->next[i] = dyn->next[--dyn->next_sz];
|
||||
continue;
|
||||
}
|
||||
if((next<best) || !best)
|
||||
best = next;
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
@@ -104,6 +107,14 @@ void add_jump(dynarec_native_t *dyn, int ninst) {
|
||||
printf_log(LOG_NONE, "Warning, overallocating jmps\n");
|
||||
}
|
||||
dyn->jmps[dyn->jmp_sz++] = ninst;
|
||||
if(dyn->insts[ninst].x64.jmp) {
|
||||
if(!khjumpaddr)
|
||||
khjumpaddr = kh_init(jumpaddr);
|
||||
int ret;
|
||||
khint_t k = kh_put(jumpaddr, khjumpaddr, dyn->insts[ninst].x64.jmp, &ret);
|
||||
if(ret > 0)
|
||||
kh_value(khjumpaddr, k) = ninst;
|
||||
}
|
||||
}
|
||||
int get_first_jump(dynarec_native_t *dyn, int next) {
|
||||
if(next<0 || next>dyn->size)
|
||||
@@ -111,6 +122,14 @@ int get_first_jump(dynarec_native_t *dyn, int next) {
|
||||
return get_first_jump_addr(dyn, dyn->insts[next].x64.addr);
|
||||
}
|
||||
int get_first_jump_addr(dynarec_native_t *dyn, uintptr_t next) {
|
||||
if(khjumpaddr) {
|
||||
khint_t k = kh_get(jumpaddr, khjumpaddr, next);
|
||||
if(k != kh_end(khjumpaddr)) {
|
||||
int ninst = kh_value(khjumpaddr, k);
|
||||
if(ninst >= 0 && ninst < dyn->size && dyn->insts[ninst].x64.jmp == next)
|
||||
return ninst;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<dyn->jmp_sz; ++i)
|
||||
if(dyn->insts[dyn->jmps[i]].x64.jmp == next)
|
||||
return dyn->jmps[i];
|
||||
@@ -444,7 +463,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
}
|
||||
#else
|
||||
uintptr_t altjump = 0;
|
||||
#endif
|
||||
#endif
|
||||
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return BOX64ENV(nodynarec_delay)?NULL:CreateEmptyBlock(old_addr, is32bits, is_new);
|
||||
@@ -454,8 +473,9 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p as in a HotPage\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
uint32_t prot = getProtection_fast(addr);
|
||||
#ifndef _WIN32
|
||||
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
|
||||
if((prot&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
|
||||
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p because EXEC protection is missing\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
@@ -469,9 +489,17 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
}
|
||||
// protect the 1st page
|
||||
protectDB(addr, 1);
|
||||
if(box64_pagesize>4096)
|
||||
prot = getProtection_fast(addr); // update protection as it might got a NEVERCLEAN tag because of the protectDB for large pagesize
|
||||
// init the helper
|
||||
dynarec_native_t helper = {0};
|
||||
dynarec_native_t* dyn = &helper;
|
||||
if(!khnextset)
|
||||
khnextset = kh_init(nextset);
|
||||
kh_clear(nextset, khnextset);
|
||||
if(!khjumpaddr)
|
||||
khjumpaddr = kh_init(jumpaddr);
|
||||
kh_clear(jumpaddr, khjumpaddr);
|
||||
#ifdef GDBJIT
|
||||
helper.gdbjit_block = box_calloc(1, sizeof(gdbjit_block_t));
|
||||
#endif
|
||||
@@ -487,7 +515,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
helper.next_cap = MAX_INSTS;
|
||||
helper.table64 = NULL;
|
||||
helper.env = GetCurEnvByAddr(addr);
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
if(prot&PROT_NEVERCLEAN) {
|
||||
helper.always_test = 1;
|
||||
}
|
||||
ResetTable64(&helper);
|
||||
@@ -559,6 +587,8 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
}
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock shorten on pass0 at ninst=%d\n", helper.size);
|
||||
--helper.size;
|
||||
// preserve flags at the new block exit
|
||||
helper.insts[helper.size - 1].x64.need_after |= X_PEND;
|
||||
helper.abort = 0;
|
||||
}
|
||||
// basic checks
|
||||
@@ -662,6 +692,10 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
int pos = helper.size-1;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
#if defined(LA64)
|
||||
updateUpperLiveness(&helper);
|
||||
updateRspMerge(&helper, is32bits);
|
||||
#endif
|
||||
// remove fpu stuff on non-executed code
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
@@ -798,7 +832,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
|
||||
helper.callret_size = 0;
|
||||
helper.sep_size = 0;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(dyn->need_dump) {
|
||||
if(dyn->need_dump && dyn->need_dump != 3) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu, callrets=%zu, entry=%p)", (dyn->need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64", native_size, helper.table64size*sizeof(uint64_t), insts_rsize, arch_size, callret_size, helper.block);
|
||||
PrintFunctionAddr(helper.start, " => ");
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_dump>1)?"\e[m":"");
|
||||
|
||||
@@ -80,6 +80,11 @@ void native_fxtract(x64emu_t* emu)
|
||||
}
|
||||
void native_fprem(x64emu_t* emu)
|
||||
{
|
||||
if(STld(0).uref==ST0.q && STld(1).uref==ST1.q) {
|
||||
// try a full precision fpre alternative
|
||||
if(full_ld_fprem(emu))
|
||||
return;
|
||||
}
|
||||
double x = ST0.d, y = ST1.d;
|
||||
int64_t q = 0;
|
||||
if (isnan(x) || isnan(y)) {
|
||||
@@ -93,14 +98,18 @@ void native_fprem(x64emu_t* emu)
|
||||
q = 0;
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
q = (int64_t)trunc(x / y);
|
||||
ST0.d = x - (y * q);
|
||||
if(isinf(y))
|
||||
q = 0;
|
||||
else {
|
||||
q = (int64_t)trunc(x / y);
|
||||
ST0.d = x - (y * q);
|
||||
}
|
||||
#else
|
||||
ST0.d = fmod(x, y);
|
||||
q = (int64_t)trunc(x / y);
|
||||
#endif
|
||||
}
|
||||
q &= 7;
|
||||
//q &= 7; //why forcing all low bits (and so C0, C1 & C3) to 1?
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = q & 1;
|
||||
emu->sw.f.F87_C3 = (q >> 1) & 1;
|
||||
@@ -346,13 +355,17 @@ void native_fprem1(x64emu_t* emu)
|
||||
ST0.d = NAN;
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
q = (int)round(x / y);
|
||||
ST0.d = x - (y * q);
|
||||
if(isinf(y))
|
||||
q = 0;
|
||||
else {
|
||||
q = (int)round(x / y);
|
||||
ST0.d = x - (y * q);
|
||||
}
|
||||
#else
|
||||
ST0.d = remquo(x, y, &q);
|
||||
#endif
|
||||
}
|
||||
q &= 7;
|
||||
//q &= 7; //why forcing all low bits (and so C0, C1 & C3) to 1?
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = q & 1;
|
||||
emu->sw.f.F87_C3 = (q >> 1) & 1;
|
||||
|
||||
@@ -215,8 +215,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
|
||||
dyn->last_ip = 0; // reset IP if some jump are coming here
|
||||
#endif
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DUMP, "New Instruction %s:%p, native:%p\n", is32bits?"x86":"x64",(void*)addr, (void*)dyn->block);
|
||||
NEW_INST;
|
||||
#ifdef ARCH_NOP
|
||||
if(dyn->insts[ninst].x64.alive && dyn->insts[ninst].x64.self_loop)
|
||||
CALLRET_LOOP();
|
||||
@@ -237,7 +237,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
DMB_ISHST();
|
||||
#endif
|
||||
if (BOX64DRENV(dynarec_dump) && (!BOX64ENV(dynarec_dump_range_end) || (ip >= BOX64ENV(dynarec_dump_range_start) && ip < BOX64ENV(dynarec_dump_range_end)))) {
|
||||
dyn->need_dump = BOX64DRENV(dynarec_dump);
|
||||
dyn->need_dump = BOX64DRENV(dynarec_dump) == 3 && STEP != 3 ? 0 : BOX64DRENV(dynarec_dump);
|
||||
}
|
||||
if(BOX64ENV(dynarec_test) && (!BOX64ENV(dynarec_test_end) || (ip>=BOX64ENV(dynarec_test_start) && ip<BOX64ENV(dynarec_test_end)))) {
|
||||
int need_dump = dyn->need_dump;
|
||||
@@ -245,6 +245,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
MESSAGE(LOG_DUMP, "TEST STEP ----\n");
|
||||
extcache_native_t save;
|
||||
fpu_save_and_unwind(dyn, ninst, &save);
|
||||
#ifdef LA64
|
||||
UP32_READALL();
|
||||
#endif
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE(x64test_step, 1, x5);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
@@ -254,12 +257,14 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
else if(my_context->dec && BOX64ENV(dynarec_trace)) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
if(IsTraceAddr(ip)) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
#if defined (SPILL_NF_REGISTERS)
|
||||
if (BOX64ENV(dynarec_nativeflags)) SPILL_NF_REGISTERS;
|
||||
#endif
|
||||
#ifdef LA64
|
||||
UP32_READALL();
|
||||
#endif
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE(PrintTrace, 1, x5);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
// Using this in SETFLAGS macro automaticaly include a DF_NONE macro
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_SET_PENDING (SF_SET|SF_PENDING)
|
||||
@@ -25,8 +26,10 @@
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
#define SF_DF 8
|
||||
// That means the opcode will set df to something (but that might happens outside, in the C part)
|
||||
#define SF_SET_DF (SF_SET|SF_DF)
|
||||
#define SF_NODF 16
|
||||
// That means the opcode will not set DF directly (or it might use DFNONE() later)
|
||||
#define SF_SET_NODF (SF_SET|SF_NODF)
|
||||
|
||||
#define NAT_FLAGS_FUSION 0
|
||||
|
||||
+566
-253
File diff suppressed because it is too large.
Load diff
+218
-144
@@ -68,7 +68,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch (nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("XGETBV");
|
||||
BEQZ_MARK(xRCX);
|
||||
ZEROUP2(x1, xRCX);
|
||||
BEQZ_MARK(x1);
|
||||
EMIT(0); // Is there any assigned illegal instruction?
|
||||
MARK;
|
||||
MOV32w(xRAX, 0b111);
|
||||
@@ -193,8 +194,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
IF_UNALIGNED(ip) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 15, 0);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
VPICKVE2GR_BU(x4, v0, i);
|
||||
ST_B(x4, ed, fixedaddress + i);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -348,9 +357,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGX(v0, 1);
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFFINT_S_W(q0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VEXTRINS_D(v0, q0, VEXTRINS_IMM_4_0(0, 0));
|
||||
break;
|
||||
case 0x2B:
|
||||
@@ -397,7 +404,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
u8 = sse_setround(dyn, ninst, x4, x6);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
} else {
|
||||
@@ -430,7 +436,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
MARK3;
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
@@ -444,36 +449,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGX(d0, 0);
|
||||
GETEXSS(v0, 0, 0);
|
||||
CLEAR_FLAGS(x2);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_S(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_S(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_S(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
IFX (X_ALL) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
EMIT_COMIS_FLAGS(S, d0, v0, x2);
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
MARKREGd(xRAX);
|
||||
MARKREGd(xRDX);
|
||||
NOTEST(x1);
|
||||
if (box64_rdtsc) {
|
||||
CALL(const_readtsc, x3, 0, 0); // will return the u64 in x3
|
||||
@@ -481,10 +462,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
RDTIME_D(x3, xZR);
|
||||
}
|
||||
if (box64_rdtsc_shift) {
|
||||
SRLI_D(x3, x3, box64_rdtsc_shift);
|
||||
SLLI_D(x3, x3, box64_rdtsc_shift);
|
||||
}
|
||||
SRLI_D(xRDX, x3, 32);
|
||||
ZEROUP2(xRDX, x3);
|
||||
ZEROUP2(xRAX, x3);
|
||||
break;
|
||||
case 0x38:
|
||||
// SSE3
|
||||
@@ -501,8 +482,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VLDI(v0, 0b0000010000111); // broadcast 0b10000111 as byte
|
||||
VAND_V(v0, v0, q1);
|
||||
VMINI_BU(v0, v0, 0x1f);
|
||||
VXOR_V(v1, v1, v1);
|
||||
VSHUF_B(q0, v1, q0, v0);
|
||||
VSHUF_B(q0, VZERO, q0, v0);
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("PHADDW Gm, Em");
|
||||
@@ -639,40 +619,63 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VABSD_B(q0, q1, v0);
|
||||
VABSD_B(q0, q1, VZERO);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("PABSW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VABSD_H(q0, q1, v0);
|
||||
VABSD_H(q0, q1, VZERO);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PABSD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VABSD_W(q0, q1, v0);
|
||||
VABSD_W(q0, q1, VZERO);
|
||||
break;
|
||||
case 0xC8 ... 0xCD:
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("SHA1NEXTE Gx, Ex");
|
||||
u8 = nextop;
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VROTRI_W(d0, q0, 2);
|
||||
VADD_W(d0, d0, q1);
|
||||
if (q0 != q1) VOR_V(q0, q1, q1);
|
||||
VEXTRINS_W(q0, d0, VEXTRINS_IMM_4_0(3, 3));
|
||||
break;
|
||||
case 0xC9:
|
||||
INST_NAME("SHA1MSG1 Gx, Ex");
|
||||
u8 = nextop;
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VOR_V(d0, q0, q0);
|
||||
VPERMI_W(d0, q1, 0x4e);
|
||||
VXOR_V(q0, q0, d0);
|
||||
break;
|
||||
case 0xCA:
|
||||
INST_NAME("SHA1MSG2 Gx, Ex");
|
||||
u8 = nextop;
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VBSLL_V(d0, q1, 4);
|
||||
VXOR_V(d0, d0, q0);
|
||||
VROTRI_W(q0, d0, 31);
|
||||
VBSRL_V(d0, q0, 12);
|
||||
VROTRI_W(d0, d0, 31);
|
||||
VXOR_V(q0, q0, d0);
|
||||
break;
|
||||
case 0xCB ... 0xCD:
|
||||
u8 = nextop;
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
INST_NAME("SHA1NEXTE Gx, Ex");
|
||||
break;
|
||||
case 0xC9:
|
||||
INST_NAME("SHA1MSG1 Gx, Ex");
|
||||
break;
|
||||
case 0xCA:
|
||||
INST_NAME("SHA1MSG2 Gx, Ex");
|
||||
break;
|
||||
case 0xCB:
|
||||
INST_NAME("SHA256RNDS2 Gx, Ex");
|
||||
break;
|
||||
@@ -698,15 +701,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
sse_reflect_reg(dyn, ninst, 0);
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
CALL(const_sha1nexte, -1, x1, ed);
|
||||
break;
|
||||
case 0xC9:
|
||||
CALL(const_sha1msg1, -1, x1, ed);
|
||||
break;
|
||||
case 0xCA:
|
||||
CALL(const_sha1msg2, -1, x1, ed);
|
||||
break;
|
||||
case 0xCB:
|
||||
CALL(const_sha256rnds2, -1, x1, ed);
|
||||
break;
|
||||
@@ -721,7 +715,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
@@ -729,13 +723,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
REVB_D(gd, gd);
|
||||
} else {
|
||||
REVB_2W(gd, gd);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("MOVBE Ed, Gd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (rex.w)
|
||||
@@ -770,25 +764,86 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VEXTRINS_D(q0, d0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
#define EMIT_SHA1_F(MODE, VF, VB, VC, VD) \
|
||||
do { \
|
||||
switch (MODE) { \
|
||||
case 0: \
|
||||
VBITSEL_V(VF, VD, VC, VB); \
|
||||
break; \
|
||||
case 1: \
|
||||
case 3: \
|
||||
VXOR_V(VF, VB, VC); \
|
||||
VXOR_V(VF, VF, VD); \
|
||||
break; \
|
||||
case 2: \
|
||||
VXOR_V(VF, VB, VD); \
|
||||
VBITSEL_V(VF, VB, VC, VF); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
case 0xCC:
|
||||
INST_NAME("SHA1RNDS4 Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
wback = x2;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
}
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
MOV32w(x3, u8);
|
||||
CALL4(const_sha1rnds4, -1, x1, wback, x3, 0);
|
||||
static const uint32_t sha1_k[4] = {
|
||||
0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
|
||||
};
|
||||
int vA = fpu_get_scratch(dyn);
|
||||
int vB = fpu_get_scratch(dyn);
|
||||
int vC = fpu_get_scratch(dyn);
|
||||
int vD = fpu_get_scratch(dyn);
|
||||
int vM = fpu_get_scratch(dyn);
|
||||
// reuse q1 as vT if Ex is mem operand
|
||||
int vT = MODREG ? fpu_get_scratch(dyn) : q1;
|
||||
int vU = SCRATCH;
|
||||
|
||||
VSHUF4I_W(vA, q0, 0xff);
|
||||
VSHUF4I_W(vB, q0, 0xaa);
|
||||
VSHUF4I_W(vC, q0, 0x55);
|
||||
VSHUF4I_W(vD, q0, 0x00);
|
||||
MOV32w(x7, sha1_k[u8 & 3]);
|
||||
VREPLGR2VR_W(vM, x7);
|
||||
VADD_W(vM, q1, vM);
|
||||
|
||||
EMIT_SHA1_F(u8 & 3, q0, vB, vC, vD);
|
||||
VROTRI_W(vB, vB, 2);
|
||||
VROTRI_W(vT, vA, 2);
|
||||
EMIT_SHA1_F(u8 & 3, vU, vA, vB, vC);
|
||||
VADD_W(vU, vU, vD);
|
||||
|
||||
VREPLVEI_W(vD, vM, 3);
|
||||
VADD_W(q0, q0, vD);
|
||||
VREPLVEI_W(vD, vM, 2);
|
||||
VADD_W(vU, vU, vD);
|
||||
VROTRI_W(vA, vA, 27);
|
||||
VREPLVEI_W(vD, vM, 1);
|
||||
VADD_W(vC, vC, vD);
|
||||
VREPLVEI_W(vM, vM, 0);
|
||||
VADD_W(vA, vA, q0);
|
||||
|
||||
VROTRI_W(q0, vA, 27);
|
||||
EMIT_SHA1_F(u8 & 3, vD, vA, vT, vB);
|
||||
VADD_W(q0, q0, vU);
|
||||
VADD_W(vD, vD, vC);
|
||||
VADD_W(vB, vB, vM);
|
||||
|
||||
VROTRI_W(vA, vA, 2);
|
||||
VROTRI_W(vU, q0, 2);
|
||||
EMIT_SHA1_F(u8 & 3, vC, q0, vA, vT);
|
||||
VROTRI_W(vM, q0, 27);
|
||||
VADD_W(vC, vC, vB);
|
||||
VILVL_W(q0, vU, vA);
|
||||
VADD_W(vM, vM, vD);
|
||||
VEXTRINS_W(q0, vM, VEXTRINS_IMM_4_0(2, 0));
|
||||
VROTRI_W(vD, vM, 27);
|
||||
VADD_W(vD, vD, vC);
|
||||
VEXTRINS_W(q0, vD, VEXTRINS_IMM_4_0(3, 0));
|
||||
break;
|
||||
#undef EMIT_SHA1_F
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -804,9 +859,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
GETGDsd; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP(NATNO, 8); \
|
||||
} else { \
|
||||
@@ -816,7 +872,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
B##NO(tmp1, 8); \
|
||||
} \
|
||||
MV(gd, ed); \
|
||||
if (!rex.w) ZEROUP(gd); \
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, tmp2, tmp3, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
@@ -828,7 +884,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
B##NO(tmp1, 8); \
|
||||
} \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
if (!rex.w) ZEROUP(gd); \
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd); \
|
||||
}
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
@@ -839,7 +895,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("MOVMSPKPS Gd, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VMSKLTZ_W(q1, q0);
|
||||
MOVFR2GR_S(gd, q1);
|
||||
@@ -1153,6 +1209,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
MARKREGs(ed);
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(v0, ed);
|
||||
} else {
|
||||
@@ -1343,11 +1400,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGM(v0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
if (rex.w) {
|
||||
MOVFR2GR_D(ed, v0);
|
||||
} else {
|
||||
MOVFR2GR_S(ed, v0);
|
||||
ZEROUP(ed);
|
||||
if (NEED_ZEROUP(ed)) ZEROUP(ed);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
@@ -1372,6 +1430,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
|
||||
COMIS_JCC(I); \
|
||||
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
|
||||
i32_ = F32S; \
|
||||
if (rex.is32bits) \
|
||||
@@ -1379,7 +1438,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
else \
|
||||
j64 = addr + i32_; \
|
||||
JUMP(j64, 1); \
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (!COMIS_FUSED() && !dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
@@ -1389,13 +1448,15 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATNO, i32); \
|
||||
if (COMIS_FUSED()) { \
|
||||
COMIS_BRANCH_NOT_TAKEN(i32, ninst); \
|
||||
} else if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATNO, i32, ninst); \
|
||||
} else { \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ_safe(x1, i32); \
|
||||
BEQZ_safe(x1, i32, ninst); \
|
||||
else \
|
||||
B##NO##_safe(x1, i32); \
|
||||
B##NO##_safe(x1, i32, ninst); \
|
||||
} \
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
|
||||
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
|
||||
@@ -1409,13 +1470,15 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATYES, i32); \
|
||||
if (COMIS_FUSED()) { \
|
||||
COMIS_BRANCH_TAKEN(i32, dyn->insts[ninst].x64.jmp_insts); \
|
||||
} else if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATYES, i32, dyn->insts[ninst].x64.jmp_insts); \
|
||||
} else { \
|
||||
if (cpuext.lbt) \
|
||||
BNEZ_safe(tmp1, i32); \
|
||||
BNEZ_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
|
||||
else \
|
||||
B##YES##_safe(tmp1, i32); \
|
||||
B##YES##_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -1479,9 +1542,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGs(ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
@@ -1508,14 +1572,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHLD Ed, Gd, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 63 : 31)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
GETEDsd(1);
|
||||
GETGDs;
|
||||
u8 = F8 & (rex.w ? 63 : 31);
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
if (!rex.w && !rex.is32bits && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
@@ -1524,12 +1588,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETGDs;
|
||||
GETEDsd(0);
|
||||
if (!rex.w && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
|
||||
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
|
||||
CBZ_NEXT(x3);
|
||||
emit_shld32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
@@ -1553,9 +1617,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGsd(ed);
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1585,7 +1650,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
} else if (!rex.w && NEED_ZEROUP(ed)) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
@@ -1594,14 +1659,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 63 : 31)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
GETEDsd(1);
|
||||
GETGDs;
|
||||
u8 = F8 & (rex.w ? 63 : 31);
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
if (!rex.w && !rex.is32bits && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
@@ -1610,12 +1675,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETGDs;
|
||||
GETEDsd(0);
|
||||
if (!rex.w && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
|
||||
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
|
||||
CBZ_NEXT(x3);
|
||||
emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4, x6);
|
||||
@@ -1655,11 +1720,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
CALL(rex.is32bits ? const_fpu_fxrstor32 : const_fpu_fxrstor64, -1, ed, 0);
|
||||
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
/* LA <-> x86
|
||||
16/24 <-> 5 inexact
|
||||
@@ -1719,6 +1786,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
MOV32w(x2, rex.is32bits);
|
||||
CALL(const_fpu_xrstor, -1, ed, x2);
|
||||
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
@@ -1732,9 +1800,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
CLEAR_FLAGS(x3);
|
||||
if (rex.w) {
|
||||
@@ -1769,7 +1837,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
MUL_W(gd, gd, ed);
|
||||
}
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(x3, gd, rex.w ? 63 : 31);
|
||||
@@ -1783,9 +1851,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGsd(ed);
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1814,14 +1883,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
} else if (!rex.w && NEED_ZEROUP(ed)) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
SCRATCH_USAGE(0);
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
@@ -1842,7 +1911,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xB7:
|
||||
INST_NAME("MOVZX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BSTRPICK_D(gd, ed, 15, 0);
|
||||
@@ -1872,7 +1941,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
GETEDsd(1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
@@ -1885,7 +1954,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
} else if (!rex.w && NEED_ZEROUP(ed)) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
@@ -1893,7 +1962,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
GETEDsd(1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
@@ -1905,7 +1974,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
} else if (!rex.w && NEED_ZEROUP(ed)) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
@@ -1913,7 +1982,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
GETEDsd(1);
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 0x1f;
|
||||
BSTRPICK_D(x3, ed, u8, u8);
|
||||
@@ -1930,7 +1999,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
} else if (!rex.w && NEED_ZEROUP(ed)) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
@@ -1943,9 +2012,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGsd(ed);
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1972,7 +2042,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
} else if (!rex.w && NEED_ZEROUP(ed)) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
@@ -1981,13 +2051,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
CLEAR_FLAGS(x2);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
GETGDw;
|
||||
if (!rex.w && MODREG) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
@@ -2011,13 +2081,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
CLEAR_FLAGS(x2);
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
GETGDw;
|
||||
if (!rex.w && MODREG) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
@@ -2041,7 +2111,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
@@ -2058,12 +2128,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_B(gd, ed, fixedaddress);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
break;
|
||||
case 0xBF:
|
||||
INST_NAME("MOVSX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
EXT_W_H(gd, ed);
|
||||
@@ -2072,7 +2142,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_H(gd, ed, fixedaddress);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
break;
|
||||
case 0xC0:
|
||||
INST_NAME("XADD Eb, Gb");
|
||||
@@ -2090,7 +2160,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("XADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
if (ed != gd) MV(x7, ed);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x4, x5, x6);
|
||||
@@ -2117,9 +2187,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xC3:
|
||||
INST_NAME("MOVNTI Ed, Gd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
MVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
MVxw(ed, gd);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SDxw(gd, ed, fixedaddress);
|
||||
@@ -2144,7 +2216,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xC5:
|
||||
INST_NAME("PEXTRW Gd,Em,Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
if (MODREG) {
|
||||
GETEM(v0, 1);
|
||||
u8 = (F8) & 3;
|
||||
@@ -2201,6 +2273,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xCF:
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
MARKREGsd(gd);
|
||||
REVBxw(gd, gd);
|
||||
break;
|
||||
case 0xD1:
|
||||
@@ -2255,7 +2328,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xD7:
|
||||
nextop = F8;
|
||||
INST_NAME("PMOVMSKB Gd, Em");
|
||||
GETGD;
|
||||
GETGDd;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
GETEM(v1, 0);
|
||||
VMSKLTZ_B(v0, v1);
|
||||
@@ -2501,6 +2574,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xF7:
|
||||
INST_NAME("MASKMOVQ Gm, Em");
|
||||
nextop = F8;
|
||||
UP32_READ(xRDI);
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
|
||||
@@ -202,6 +202,17 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
if (!dyn->insts[ninst].x64.gen_flags) {
|
||||
if (!(i32 & 0xF000)) {
|
||||
ANDI(x1, xRAX, i32);
|
||||
} else {
|
||||
MOV32w(x2, i32);
|
||||
AND(x1, xRAX, x2);
|
||||
}
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(x1, xZR, x2, xZR);
|
||||
break;
|
||||
}
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
@@ -244,6 +255,20 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
if (!dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_HU(x2, wback, fixedaddress);
|
||||
ed = x2;
|
||||
}
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
XOR(x1, gd, ed);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
break;
|
||||
}
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_xor16(dyn, ninst, gd, ed, x3, x4, x5);
|
||||
GWBACK;
|
||||
@@ -392,7 +417,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("IMUL Gw, Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode == 0x69) ? 2 : 1);
|
||||
if (opcode == 0x69)
|
||||
@@ -528,6 +553,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("AND Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
if (MODREG && !dyn->insts[ninst].x64.gen_flags) {
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
else
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
if (!(u64 & 0xF000)) {
|
||||
ANDI(x1, wback, u64);
|
||||
} else {
|
||||
MOV64x(x5, u64);
|
||||
AND(x1, wback, x5);
|
||||
}
|
||||
BSTRINS_D(wback, x1, 15, 0);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(x1, xZR, x2, xZR);
|
||||
break;
|
||||
}
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -602,13 +643,13 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("(LOCK) XCHG Ew, Gw");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGD;
|
||||
GETGDw;
|
||||
GETED(0);
|
||||
MV(x1, gd);
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
BSTRINS_D(ed, x1, 15, 0);
|
||||
} else {
|
||||
GETGD;
|
||||
GETGDw;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
ANDI(x3, wback, 1);
|
||||
BEQ_MARK(x3, xZR);
|
||||
@@ -652,7 +693,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x89:
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
SCRATCH_USAGE(0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
@@ -666,7 +707,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDw;
|
||||
if (MODREG) {
|
||||
SCRATCH_USAGE(0);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
@@ -693,7 +734,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDw;
|
||||
if (MODREG) {
|
||||
INST_NAME("Invalid 8D");
|
||||
UDF();
|
||||
@@ -717,11 +758,12 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("MOV Seg, Ew");
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BSTRPICK_D(x2, ed, 15, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_HU(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
LD_HU(x2, wback, fixedaddress);
|
||||
ed = x2;
|
||||
}
|
||||
ST_H(ed, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
if ((u8 == _FS) || (u8 == _GS)) {
|
||||
@@ -789,7 +831,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SMREAD();
|
||||
POP1_16(x1);
|
||||
MOV32w(x2, 0x7FD7);
|
||||
@@ -848,9 +890,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
|
||||
break;
|
||||
case 0xA5:
|
||||
UP32_READ(xRSI);
|
||||
UP32_READ(xRDI);
|
||||
if (rex.rep) {
|
||||
UP32_READ(xRCX);
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZ_NEXT(xRCX);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRSI);
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
@@ -872,17 +921,31 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
GETDIR(x3, x1, 2);
|
||||
LD_H(x1, xRSI, 0);
|
||||
ST_H(x1, xRDI, 0);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRSI);
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
IF_UNALIGNED(ip) {
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
LD_BU(x1, xRSI, 1);
|
||||
ST_B(x1, xRDI, 1);
|
||||
} else {
|
||||
LD_H(x1, xRSI, 0);
|
||||
ST_H(x1, xRDI, 0);
|
||||
}
|
||||
ADD_D(xRSI, xRSI, x3);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xA7:
|
||||
UP32_READ(xRSI);
|
||||
UP32_READ(xRDI);
|
||||
switch (rex.rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
UP32_READ(xRCX);
|
||||
if (rex.rep == 1) {
|
||||
INST_NAME("REPNZ CMPSW");
|
||||
} else {
|
||||
@@ -890,10 +953,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
CBZ_NEXT(xRCX);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRSI);
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // DF==0
|
||||
@@ -928,6 +995,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("CMPSW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETDIR(x3, x1, 2);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRSI);
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
LD_HU(x1, xRSI, 0);
|
||||
LD_HU(x2, xRDI, 0);
|
||||
ADD_D(xRSI, xRSI, x3);
|
||||
@@ -945,9 +1016,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0xAB:
|
||||
UP32_READ(xRDI);
|
||||
if (rex.rep) {
|
||||
UP32_READ(xRCX);
|
||||
INST_NAME("REP STOSW");
|
||||
CBZ_NEXT(xRCX);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // Part with DF==0
|
||||
@@ -965,26 +1041,36 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
GETDIR(x3, x1, 2);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
ST_H(xRAX, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0xAD:
|
||||
UP32_READ(xRSI);
|
||||
if (rex.rep) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
INST_NAME("LODSW");
|
||||
GETDIR(x1, x2, 2);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRSI);
|
||||
}
|
||||
LD_HU(x2, xRSI, 0);
|
||||
ADD_D(xRSI, xRSI, x1);
|
||||
BSTRINSz(xRAX, x2, 15, 0);
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
UP32_READ(xRDI);
|
||||
if (rex.w) MARKREGs(xRAX);
|
||||
switch (rex.rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
UP32_READ(xRCX);
|
||||
if (rex.rep == 1) {
|
||||
INST_NAME("REPNZ SCASW");
|
||||
} else {
|
||||
@@ -992,11 +1078,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
CBZ_NEXT(xRCX);
|
||||
GETDIR(x3, x1, rex.w ? 8 : 2);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
if (rex.w) {
|
||||
MARK;
|
||||
LD_D(x2, xRDI, 0);
|
||||
@@ -1030,6 +1119,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETDIR(x3, x1, rex.w ? 8 : 2);
|
||||
if (rex.is67 && !rex.is32bits) {
|
||||
ZEROUP(xRDI);
|
||||
}
|
||||
if (rex.w) {
|
||||
LD_D(x2, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
@@ -1062,8 +1154,13 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
if (MODREG && u8 > 1) {
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
|
||||
} else {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5, x6);
|
||||
@@ -1075,8 +1172,13 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
if (MODREG && u8 > 1) {
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
|
||||
} else {
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
|
||||
@@ -1132,6 +1234,17 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (MODREG && !dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].nat_flags_fusion) {
|
||||
u8 = (F8) & 0x1f;
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if (u8 < 16) {
|
||||
BSTRPICK_D(x1, wback, 15, u8);
|
||||
BSTRINS_D(wback, x1, 15, 0);
|
||||
} else {
|
||||
BSTRINS_D(wback, xZR, 15, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_shr16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
@@ -1208,6 +1321,12 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 5:
|
||||
INST_NAME("SHR Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (MODREG && !dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].nat_flags_fusion) {
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BSTRPICK_D(x1, wback, 15, 1);
|
||||
BSTRINS_D(wback, x1, 15, 0);
|
||||
break;
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
emit_shr16c(dyn, ninst, x1, 1, x5, x4, x6);
|
||||
EWBACK;
|
||||
@@ -1238,7 +1357,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_OF | X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -1250,7 +1369,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_OF | X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -1264,7 +1383,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
READFLAGS(X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -1278,7 +1397,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
READFLAGS(X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -1289,9 +1408,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHR Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION); // some flags are left undefined
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -1303,9 +1422,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SHL Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION); // some flags are left undefined
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -1316,9 +1435,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SAR Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION); // some flags are left undefined
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
CBZ_NEXT(x2);
|
||||
GETSEW(x1, 0);
|
||||
@@ -1387,7 +1506,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
GETEW(x1, 0);
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
MUL_W(x1, x2, x1);
|
||||
@@ -1410,9 +1529,35 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
IFX (X_PF) emit_pf(dyn, ninst, xRAX, x3, x5);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
GETSEW(x1, 0);
|
||||
EXT_W_H(x2, xRAX);
|
||||
MUL_W(x1, x2, x1);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
SRLI_D(x3, x1, 16);
|
||||
BSTRINS_D(xRDX, x3, 15, 0);
|
||||
SET_DFNONE();
|
||||
CLEAR_FLAGS(x3);
|
||||
IFX (X_CF | X_OF) {
|
||||
SRAI_W(x2, x1, 15);
|
||||
SRAI_W(x3, x1, 31);
|
||||
XOR(x3, x3, x2);
|
||||
SNEZ(x3, x3);
|
||||
IFX (X_CF) BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
IFX (X_OF) BSTRINS_D(xFlags, x3, F_OF, F_OF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(x3, xRAX, 15);
|
||||
BSTRINS_D(xFlags, x3, F_SF, F_SF);
|
||||
}
|
||||
IFX (X_PF) emit_pf(dyn, ninst, xRAX, x3, x5);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 0);
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
@@ -1440,7 +1585,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
GETSEW(x1, 0);
|
||||
if (BOX64ENV(dynarec_div0)) {
|
||||
|
||||
@@ -280,7 +280,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
u8 = sse_setround(dyn, ninst, x4, x6);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINT_W_D(v0, v1, v1);
|
||||
} else {
|
||||
@@ -314,7 +313,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VEXTRINS_W(v0, q0, VEXTRINS_IMM_4_0(1, 0));
|
||||
MARK3;
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
@@ -324,37 +322,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
INST_NAME("UCOMISD Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGX(d0, 0);
|
||||
GETEXSD(v0, 0, 0);
|
||||
|
||||
CLEAR_FLAGS(x3);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_D(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_D(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_D(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
SPILL_EFLAGS();
|
||||
EMIT_COMIS_FLAGS(D, d0, v0, x3);
|
||||
break;
|
||||
case 0x38: // SSSE3 opcodes
|
||||
nextop = F8;
|
||||
@@ -369,8 +342,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VLDI(v0, 0b0000010001111); // broadcast 0b10001111 as byte
|
||||
VAND_V(v0, v0, q1);
|
||||
VMINI_BU(v0, v0, 0x1f);
|
||||
VXOR_V(v1, v1, v1);
|
||||
VSHUF_B(q0, v1, q0, v0);
|
||||
VSHUF_B(q0, VZERO, q0, v0);
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("PHADDW Gx, Ex");
|
||||
@@ -536,7 +508,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x17:
|
||||
INST_NAME("PTEST Gx, Ex");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
GETGX(q0, 0);
|
||||
GETEX(q1, 0, 0);
|
||||
if (!cpuext.lbt) {
|
||||
@@ -576,18 +548,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VABSD_B(q0, q1, v0);
|
||||
VABSD_B(q0, q1, VZERO);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("PABSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VABSD_H(q0, q1, v0);
|
||||
VABSD_H(q0, q1, VZERO);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PABSD Gx, Ex");
|
||||
@@ -845,12 +813,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_V(d0, q1, q1);
|
||||
} else
|
||||
d0 = -1;
|
||||
GETGX(q0, 1);
|
||||
la64_aese_lsx(dyn, ninst, q0);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -859,12 +827,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_V(d0, q1, q1);
|
||||
} else
|
||||
d0 = -1;
|
||||
GETGX(q0, 1);
|
||||
la64_aeselast_lsx(dyn, ninst, q0);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -873,12 +841,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_V(d0, q1, q1);
|
||||
} else
|
||||
d0 = -1;
|
||||
GETGX(q0, 1);
|
||||
la64_aesd_lsx(dyn, ninst, q0);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -887,19 +855,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETG;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_V(d0, q1, q1);
|
||||
} else
|
||||
d0 = -1;
|
||||
GETGX(q0, 1);
|
||||
la64_aesdlast_lsx(dyn, ninst, q0);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDw;
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_HU(x1, ed, fixedaddress);
|
||||
@@ -909,7 +877,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xF1:
|
||||
INST_NAME("MOVBE Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
REVB_2H(x1, gd);
|
||||
@@ -921,8 +889,8 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x3, X_CF); // CF pos is 0, no need SLLI
|
||||
} else {
|
||||
@@ -952,7 +920,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
ADDxw(x5, gd, ed);
|
||||
ADDxw(gd, x5, x3);
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -970,9 +938,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_S(q0, q1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_S(q0, q1, round_round[u8 & 3]);
|
||||
}
|
||||
@@ -985,9 +951,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_D(q0, q1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_D(q0, q1, round_round[u8 & 3]);
|
||||
}
|
||||
@@ -1000,9 +964,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_S(v1, q1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_S(v1, q1, round_round[u8 & 3]);
|
||||
}
|
||||
@@ -1016,9 +978,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_D(v1, q1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_D(v1, q1, round_round[u8 & 3]);
|
||||
}
|
||||
@@ -1139,6 +1099,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UP32_WRITE32(ed);
|
||||
u8 = (F8) & 15;
|
||||
VPICKVE2GR_BU(ed, q0, u8);
|
||||
} else {
|
||||
@@ -1156,6 +1117,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UP32_WRITE32(ed);
|
||||
u8 = (F8) & 7;
|
||||
VPICKVE2GR_HU(ed, q0, u8);
|
||||
} else {
|
||||
@@ -1178,6 +1140,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
u8 = F8;
|
||||
if (rex.w) {
|
||||
VPICKVE2GR_D(ed, q0, (u8 & 1));
|
||||
@@ -1203,6 +1166,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UP32_WRITE32(ed);
|
||||
u8 = F8 & 0b11;
|
||||
VPICKVE2GR_WU(ed, q0, u8);
|
||||
} else {
|
||||
@@ -1247,11 +1211,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(((u8 >> 4) & 3), 0)); // src index is zero when Ex is mem operand
|
||||
}
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
VXOR_V(q2, q2, q2);
|
||||
if (zmask) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (zmask & (1 << i)) {
|
||||
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(i, 0));
|
||||
VEXTRINS_W(q0, VZERO, VEXTRINS_IMM_4_0(i, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1277,12 +1240,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
VFMUL_S(v0, q0, q1);
|
||||
VXOR_V(v2, v2, v2);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(u8 & (1 << (4 + i)))) {
|
||||
VEXTRINS_W(v0, v2, (i << 4));
|
||||
VEXTRINS_W(v0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
VSHUF4I_W(v1, v0, 0b10110001); // v0[a,b,c,d] v1[b,a,d,c]
|
||||
@@ -1292,7 +1253,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VREPLVEI_W(q0, v0, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(u8 & (1 << i))) {
|
||||
VEXTRINS_W(q0, v2, (i << 4));
|
||||
VEXTRINS_W(q0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1304,12 +1265,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
VFMUL_D(v0, q0, q1);
|
||||
VXOR_V(v2, v2, v2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (!(u8 & (1 << (4 + i)))) {
|
||||
VEXTRINS_D(v0, v2, (i << 4));
|
||||
VEXTRINS_D(v0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
VSHUF4I_W(v1, v0, 0b01001110); // v0[a,b] v1[b,a]
|
||||
@@ -1317,7 +1276,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VREPLVEI_D(q0, v0, 0);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (!(u8 & (1 << i))) {
|
||||
VEXTRINS_D(q0, v2, (i << 4));
|
||||
VEXTRINS_D(q0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1341,6 +1300,62 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOV32w(x4, u8);
|
||||
CALL4(const_native_pclmul, -1, x1, x2, x3, x4);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PCMPESTRM Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
if (gd > 7) sse_reflect_reg(dyn, ninst, gd);
|
||||
ADDI_D(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (ed > 7) sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
ed = x1;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
}
|
||||
SEXT_W(x2, xRDX);
|
||||
SEXT_W(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL6(const_sse42_compare_string_explicit_len, x1, ed, x2, x3, x4, x5, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, 0);
|
||||
if (u8 & 0b1000000) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
switch (u8 & 1) {
|
||||
case 0b00:
|
||||
VREPLGR2VR_B(v0, x1);
|
||||
SRLI_D(x2, x1, 8);
|
||||
VREPLGR2VR_B(v1, x2);
|
||||
VEXTRINS_D(v0, v1, 0x10);
|
||||
MOV64x(x2, 0x0001020304050607);
|
||||
VREPLGR2VR_D(v1, x2);
|
||||
VSLL_B(v0, v0, v1);
|
||||
MOV32w(x2, 0x80);
|
||||
VREPLGR2VR_B(v1, x2);
|
||||
VAND_V(v0, v0, v1);
|
||||
VSRAI_B(v0, v0, 7);
|
||||
break;
|
||||
case 0b01:
|
||||
VREPLGR2VR_H(v0, x1);
|
||||
MOV64x(x2, 0x000C000D000E000F);
|
||||
VREPLGR2VR_D(v1, x2);
|
||||
MOV64x(x2, 0x00080009000A000B);
|
||||
VINSGR2VR_D(v1, x2, 1);
|
||||
VSLL_H(v0, v0, v1);
|
||||
MOV32w(x2, 0x80);
|
||||
VREPLGR2VR_B(v1, x2);
|
||||
VAND_V(v0, v0, v1);
|
||||
VSRAI_H(v0, v0, 15);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
VXOR_V(v0, v0, v0);
|
||||
VINSGR2VR_H(v0, x1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PCMPESTRI Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -1377,6 +1392,59 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
CTZ_W(xRCX, x1);
|
||||
}
|
||||
break;
|
||||
case 0x62:
|
||||
INST_NAME("PCMPISTRM Gx, Ex, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (gd > 7) sse_reflect_reg(dyn, ninst, gd);
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (ed > 7) sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
ed = x1;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
}
|
||||
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
CALL4(const_sse42_compare_string_implicit_len, x1, ed, x2, x3, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, 0);
|
||||
if (u8 & 0b1000000) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
switch (u8 & 1) {
|
||||
case 0b00:
|
||||
VREPLGR2VR_B(v0, x1);
|
||||
SRLI_D(x2, x1, 8);
|
||||
VREPLGR2VR_B(v1, x2);
|
||||
VEXTRINS_D(v0, v1, 0x10);
|
||||
MOV64x(x2, 0x0001020304050607);
|
||||
VREPLGR2VR_D(v1, x2);
|
||||
VSLL_B(v0, v0, v1);
|
||||
MOV32w(x2, 0x80);
|
||||
VREPLGR2VR_B(v1, x2);
|
||||
VAND_V(v0, v0, v1);
|
||||
VSRAI_B(v0, v0, 7);
|
||||
break;
|
||||
case 0b01:
|
||||
VREPLGR2VR_H(v0, x1);
|
||||
MOV64x(x2, 0x000C000D000E000F);
|
||||
VREPLGR2VR_D(v1, x2);
|
||||
MOV64x(x2, 0x00080009000A000B);
|
||||
VINSGR2VR_D(v1, x2, 1);
|
||||
VSLL_H(v0, v0, v1);
|
||||
MOV32w(x2, 0x80);
|
||||
VREPLGR2VR_B(v1, x2);
|
||||
VAND_V(v0, v0, v1);
|
||||
VSRAI_H(v0, v0, 15);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
VXOR_V(v0, v0, v0);
|
||||
VINSGR2VR_H(v0, x1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x63:
|
||||
INST_NAME("PCMPISTRI Gx, Ex, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
@@ -1433,7 +1501,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
GETGDw; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
} else { \
|
||||
@@ -1447,14 +1515,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
B##NO(x1, 4 + 4); \
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
GOCOND(0x40, "CMOV", "Gw, Ew");
|
||||
#undef GO
|
||||
|
||||
case 0x50:
|
||||
nextop = F8;
|
||||
INST_NAME("PMOVMSKD Gd, Ex");
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
VPICKVE2GR_D(x1, q0, 0);
|
||||
VPICKVE2GR_D(gd, q0, 1);
|
||||
SRLI_D(gd, gd, 62);
|
||||
@@ -1571,23 +1639,16 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCVT_S_D(q0, v1, v1);
|
||||
VXOR_V(v0, v0, v0);
|
||||
VEXTRINS_D(v0, q0, 0);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
if (v0 == v1 && !BOX64ENV(dynarec_fastround)) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VOR_V(v1, v0, v0);
|
||||
@@ -1607,7 +1668,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VSRLI_W(q0, q0, 31);
|
||||
VADD_W(v0, v0, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPD Gx, Ex");
|
||||
@@ -1829,6 +1889,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGs(ed);
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(v1, ed);
|
||||
} else {
|
||||
@@ -2098,6 +2159,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (rex.w) {
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
MOVFR2GR_D(ed, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
@@ -2107,8 +2169,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
MOVFR2GR_S(ed, v0);
|
||||
ZEROUP(ed);
|
||||
if (NEED_ZEROUP(ed)) ZEROUP(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_S(v0, ed, fixedaddress);
|
||||
@@ -2138,7 +2201,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
@@ -2179,9 +2242,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETGWEW(x1, x2, 0);
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
UFLAG_IF { CBZ_NEXT(x4); }
|
||||
@@ -2197,7 +2260,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
@@ -2247,9 +2310,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETGWEW(x1, x2, 0);
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
UFLAG_IF { CBZ_NEXT(x4); }
|
||||
@@ -2314,7 +2377,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
@@ -2475,7 +2538,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
@@ -2508,7 +2571,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gw, Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
IFX (X_ALL) CLEAR_FLAGS(x3);
|
||||
} else
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
@@ -2535,7 +2598,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gw, Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
IFX (X_ALL) CLEAR_FLAGS(x3);
|
||||
} else
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
@@ -2564,7 +2627,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDw;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
@@ -2592,7 +2655,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (rex.w) return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
|
||||
INST_NAME("MOVSX Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDw;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
@@ -2608,9 +2671,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGWEW(x1, x2, 0);
|
||||
BSTRINS_D(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 15, 0);
|
||||
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
if (!(MODREG && wback == u8)) MV(x7, ed);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
if (!(MODREG && wback == u8)) BSTRINS_D(u8, x7, 15, 0);
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
@@ -2648,7 +2713,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xC5:
|
||||
INST_NAME("PEXTRW Gd, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
if (MODREG) {
|
||||
GETEX(v0, 0, 1);
|
||||
u8 = (F8) & 7;
|
||||
@@ -2680,6 +2745,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
if (rex.w) {
|
||||
MARKREGsd(gd);
|
||||
REVB_D(gd, gd);
|
||||
} else {
|
||||
// undefined behaviour
|
||||
@@ -2794,7 +2860,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("PMOVMSKB Gd, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VMSKLTZ_B(v0, q0);
|
||||
MOVFR2GR_D(x1, v0);
|
||||
@@ -3071,6 +3137,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xF7:
|
||||
INST_NAME("MASKMOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
UP32_READ(xRDI);
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
|
||||
@@ -77,7 +77,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
ADD_D(x4, x1, x5);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
BSTRINS_D(x3, x4, 31, 16);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
@@ -120,7 +120,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
OR(x4, x1, x5);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
BSTRINS_D(x3, x4, 31, 16);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
@@ -145,7 +145,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
SRAI_D(x1, gd, 3);
|
||||
@@ -183,7 +183,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("LOCK CMPXCHG Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
BSTRPICK_D(x6, xRAX, 15, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
// Aligned
|
||||
@@ -231,7 +231,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
SRAI_D(x1, gd, 3);
|
||||
@@ -311,7 +311,6 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("LOCK BTR Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0xf);
|
||||
@@ -349,7 +348,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
INST_NAME("LOCK XADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDw;
|
||||
BSTRPICK_D(x5, gd, 15, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lam_bh) {
|
||||
@@ -374,7 +373,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
ADD_D(x4, x1, x5);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
BSTRINS_D(x3, x4, 31, 16);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
@@ -436,7 +435,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
ADD_D(x4, x1, x5);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
BSTRINS_D(x3, x4, 31, 16);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
@@ -488,7 +487,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
ADDI_D(x4, x1, 1);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
BSTRINS_D(x3, x4, 31, 16);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
@@ -534,7 +533,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
ADDI_D(x4, x1, -1);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
BSTRINS_D(x3, x4, 31, 16);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
|
||||
@@ -56,9 +56,9 @@ uintptr_t dynarec64_66F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
INST_NAME("CRC32 Gd, Ew");
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGD;
|
||||
GETGDsd;
|
||||
CRCC_W_H_W(gd, gd, ed);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -49,10 +49,10 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
switch (opcode) {
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDw;
|
||||
GETEW(x4, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VINSGR2VR_H(v0, ed, 0);
|
||||
@@ -72,7 +72,7 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -98,7 +98,7 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
|
||||
@@ -8,7 +8,6 @@ static inline void la64_subbytes_lsx(dynarec_la64_t* dyn, int ninst, int dst, in
|
||||
{
|
||||
(void)dyn;
|
||||
(void)ninst;
|
||||
VXOR_V(zero, zero, zero);
|
||||
VANDI_B(t0, dst, 0x0f);
|
||||
VSRLI_B(t1, dst, 4);
|
||||
VLD(tab, x5, 1 * 16);
|
||||
@@ -42,7 +41,6 @@ static inline void la64_subbytes_lasx(dynarec_la64_t* dyn, int ninst, int dst, i
|
||||
{
|
||||
(void)dyn;
|
||||
(void)ninst;
|
||||
XVXOR_V(zero, zero, zero);
|
||||
XVANDI_B(t0, dst, 0x0f);
|
||||
XVSRLI_B(t1, dst, 4);
|
||||
XVLD(tab, x5, 1 * 32);
|
||||
@@ -172,7 +170,7 @@ static inline void la64_aesimc_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
|
||||
static inline void la64_aeselast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
@@ -187,7 +185,7 @@ static inline void la64_aeselast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
|
||||
static inline void la64_aeselast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
@@ -202,43 +200,45 @@ static inline void la64_aeselast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
|
||||
static inline void la64_aese_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
int t3 = fpu_get_scratch(dyn);
|
||||
int tab = fpu_get_scratch(dyn);
|
||||
int tab_hi = fpu_get_scratch(dyn);
|
||||
|
||||
TABLE64C(x5, const_la64_vpaes_enc_tables);
|
||||
la64_subbytes_lsx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
|
||||
VLD(tab, x5, 6 * 16);
|
||||
VSHUF_B(dst, dst, dst, tab);
|
||||
VLD(tab, x5, 7 * 16);
|
||||
VLD(zero, x5, 8 * 16);
|
||||
la64_mixcolumns_xtime_lsx(dyn, ninst, dst, tab, zero, t0, t1, t2, t3);
|
||||
VLD(tab_hi, x5, 8 * 16);
|
||||
la64_mixcolumns_xtime_lsx(dyn, ninst, dst, tab, tab_hi, t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
static inline void la64_aese_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
int t3 = fpu_get_scratch(dyn);
|
||||
int tab = fpu_get_scratch(dyn);
|
||||
int tab_hi = fpu_get_scratch(dyn);
|
||||
|
||||
TABLE64C(x5, const_la64_vpaes_enc_tables_xv);
|
||||
la64_subbytes_lasx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
|
||||
XVLD(tab, x5, 6 * 32);
|
||||
XVSHUF_B(dst, dst, dst, tab);
|
||||
XVLD(tab, x5, 7 * 32);
|
||||
XVLD(zero, x5, 8 * 32);
|
||||
la64_mixcolumns_xtime_lasx(dyn, ninst, dst, tab, zero, t0, t1, t2, t3);
|
||||
XVLD(tab_hi, x5, 8 * 32);
|
||||
la64_mixcolumns_xtime_lasx(dyn, ninst, dst, tab, tab_hi, t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
static inline void la64_aesdlast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
@@ -249,7 +249,6 @@ static inline void la64_aesdlast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
TABLE64C(x5, const_la64_vpaes_dec_tables);
|
||||
VLD(tab, x5, 6 * 16);
|
||||
VSHUF_B(dst, dst, dst, tab);
|
||||
VXOR_V(zero, zero, zero);
|
||||
VXORI_B(dst, dst, 99);
|
||||
VANDI_B(t0, dst, 0x0f);
|
||||
VSRLI_B(t1, dst, 4);
|
||||
@@ -282,7 +281,7 @@ static inline void la64_aesdlast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
|
||||
static inline void la64_aesdlast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
@@ -293,7 +292,6 @@ static inline void la64_aesdlast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
TABLE64C(x5, const_la64_vpaes_dec_tables_xv);
|
||||
XVLD(tab, x5, 6 * 32);
|
||||
XVSHUF_B(dst, dst, dst, tab);
|
||||
XVXOR_V(zero, zero, zero);
|
||||
XVXORI_B(dst, dst, 99);
|
||||
XVANDI_B(t0, dst, 0x0f);
|
||||
XVSRLI_B(t1, dst, 4);
|
||||
@@ -326,7 +324,7 @@ static inline void la64_aesdlast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
|
||||
static inline void la64_aesd_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
@@ -337,7 +335,6 @@ static inline void la64_aesd_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
TABLE64C(x5, const_la64_vpaes_dec_tables);
|
||||
VLD(tab, x5, 6 * 16);
|
||||
VSHUF_B(dst, dst, dst, tab);
|
||||
VXOR_V(zero, zero, zero);
|
||||
VXORI_B(dst, dst, 99);
|
||||
VANDI_B(t0, dst, 0x0f);
|
||||
VSRLI_B(t1, dst, 4);
|
||||
@@ -367,13 +364,13 @@ static inline void la64_aesd_lsx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
VSHUF_B(t1, zero, tab, t3);
|
||||
VXOR_V(dst, t0, t1);
|
||||
VLD(tab, x5, 7 * 16);
|
||||
VLD(zero, x5, 8 * 16);
|
||||
la64_invmixcolumns_xtime_lsx(dyn, ninst, dst, tab, zero, t0, t1, t2, t3);
|
||||
VLD(t4, x5, 8 * 16);
|
||||
la64_invmixcolumns_xtime_lsx(dyn, ninst, dst, tab, t4, t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
static inline void la64_aesd_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
@@ -384,7 +381,6 @@ static inline void la64_aesd_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
TABLE64C(x5, const_la64_vpaes_dec_tables_xv);
|
||||
XVLD(tab, x5, 6 * 32);
|
||||
XVSHUF_B(dst, dst, dst, tab);
|
||||
XVXOR_V(zero, zero, zero);
|
||||
XVXORI_B(dst, dst, 99);
|
||||
XVANDI_B(t0, dst, 0x0f);
|
||||
XVSRLI_B(t1, dst, 4);
|
||||
@@ -414,13 +410,13 @@ static inline void la64_aesd_lasx(dynarec_la64_t* dyn, int ninst, int dst)
|
||||
XVSHUF_B(t1, zero, tab, t3);
|
||||
XVXOR_V(dst, t0, t1);
|
||||
XVLD(tab, x5, 7 * 32);
|
||||
XVLD(zero, x5, 8 * 32);
|
||||
la64_invmixcolumns_xtime_lasx(dyn, ninst, dst, tab, zero, t0, t1, t2, t3);
|
||||
XVLD(t4, x5, 8 * 32);
|
||||
la64_invmixcolumns_xtime_lasx(dyn, ninst, dst, tab, t4, t0, t1, t2, t3);
|
||||
}
|
||||
|
||||
static inline void la64_aeskeygenassist_lsx(dynarec_la64_t* dyn, int ninst, int dst, uint8_t imm)
|
||||
{
|
||||
int zero = fpu_get_scratch(dyn);
|
||||
int zero = VZERO;
|
||||
int t0 = fpu_get_scratch(dyn);
|
||||
int t1 = fpu_get_scratch(dyn);
|
||||
int t2 = fpu_get_scratch(dyn);
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "dynablock.h"
|
||||
#include "x64emu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "dynarec/dynablock_private.h"
|
||||
#include "dynarec_la64_arch.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
|
||||
typedef struct arch_arch_s
|
||||
{
|
||||
uint16_t unaligned:1;
|
||||
uint16_t seq:10; // how many instruction on the same values
|
||||
uint16_t up32; // GPRs with pending 32-bit zero-up at this instruction
|
||||
int16_t rsp; // pending rsp offset at this instruction
|
||||
} arch_arch_t;
|
||||
|
||||
typedef struct arch_build_s
|
||||
{
|
||||
uint8_t unaligned;
|
||||
uint16_t up32;
|
||||
int16_t rsp;
|
||||
} arch_build_t;
|
||||
|
||||
static int arch_build(dynarec_la64_t* dyn, int ninst, arch_build_t* arch)
|
||||
{
|
||||
memset(arch, 0, sizeof(arch_build_t));
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
// pending 32-bit zero-ups at this instruction
|
||||
arch->up32 = dyn->insts[ninst].up32_pending;
|
||||
arch->rsp = dyn->insts[ninst].rsp_entry;
|
||||
return arch->unaligned || arch->up32 || arch->rsp;
|
||||
}
|
||||
|
||||
size_t get_size_arch(dynarec_la64_t* dyn)
|
||||
{
|
||||
arch_build_t build = {0};
|
||||
arch_build_t previous = {0};
|
||||
size_t sz = 0;
|
||||
int seq = 0;
|
||||
int nseq = 0;
|
||||
int last = 0;
|
||||
if(!dyn->size) return 0;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
last = arch_build(dyn, i, &build);
|
||||
if((!memcmp(&build, &previous, sizeof(arch_build_t))) && (seq<((1<<10)-1)) && i) {
|
||||
// same sequence, increment
|
||||
++seq;
|
||||
} else {
|
||||
seq = 0;
|
||||
++nseq;
|
||||
memcpy(&previous, &build, sizeof(arch_build_t));
|
||||
sz+=sizeof(arch_arch_t);
|
||||
}
|
||||
}
|
||||
if(nseq==1 && !last)
|
||||
return 0; //empty, no flags, no nothing
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void build_next(arch_arch_t* arch, arch_build_t* build)
|
||||
{
|
||||
arch->unaligned = build->unaligned;
|
||||
arch->seq = 0;
|
||||
arch->up32 = build->up32;
|
||||
arch->rsp = build->rsp;
|
||||
}
|
||||
|
||||
void* populate_arch(dynarec_la64_t* dyn, void* p, size_t sz)
|
||||
{
|
||||
(void)sz;
|
||||
arch_build_t build = {0};
|
||||
arch_build_t previous = {0};
|
||||
arch_arch_t* arch = p;
|
||||
arch_arch_t* next = p;
|
||||
int seq = 0;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
arch_build(dyn, i, &build);
|
||||
if((!memcmp(&build, &previous, sizeof(arch_build_t))) && (seq<((1<<10)-1)) && i) {
|
||||
// same sequence, increment
|
||||
seq++;
|
||||
arch->seq = seq;
|
||||
} else {
|
||||
arch = next;
|
||||
build_next(arch, &build);
|
||||
seq = 0;
|
||||
memcpy(&previous, &build, sizeof(arch_build_t));
|
||||
next = (arch_arch_t*)((uintptr_t)arch+sizeof(arch_arch_t));
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int getX64AddressInst(dynablock_t* db, uintptr_t x64pc); // define is signal.c
|
||||
|
||||
static arch_arch_t* arch_for_ninst(dynablock_t* db, int ninst)
|
||||
{
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
int i = -1;
|
||||
while(i<ninst) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
next = (arch_arch_t*)((uintptr_t)next+sizeof(arch_arch_t));
|
||||
}
|
||||
return arch;
|
||||
}
|
||||
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
if(!db)
|
||||
return 0;
|
||||
if(!db->arch_size || !db->arch)
|
||||
return 0;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
if(ninst<0) {
|
||||
return 0;
|
||||
}
|
||||
// look for state at ninst
|
||||
arch_arch_t* arch = arch_for_ninst(db, ninst);
|
||||
return arch->unaligned;
|
||||
}
|
||||
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
{
|
||||
(void)p;
|
||||
if(!db) return;
|
||||
if(!db->arch_size || !db->arch) return;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
if(ninst < 0 || ninst >= db->isize) return;
|
||||
arch_arch_t* arch = arch_for_ninst(db, ninst);
|
||||
uint16_t up32 = arch->up32;
|
||||
while(up32) {
|
||||
int r = __builtin_ctz(up32);
|
||||
up32 &= up32 - 1;
|
||||
emu->regs[r].q[0] &= 0xffffffffULL;
|
||||
}
|
||||
if (arch->rsp) emu->regs[_SP].q[0] += arch->rsp;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef __DYNAREC_LA_ARCH_H__
|
||||
#define __DYNAREC_LA_ARCH_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include "x64emu.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
|
||||
// get size of arch specific info (can be 0)
|
||||
size_t get_size_arch(dynarec_la64_t* dyn);
|
||||
//populate the array
|
||||
void* populate_arch(dynarec_la64_t* dyn, void* p, size_t sz);
|
||||
//adjust flags and more (needed for signal handling)
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
|
||||
// get if instruction can be regenerated for unaligned access
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
|
||||
#endif // __DYNAREC_LA_ARCH_H__
|
||||
@@ -74,9 +74,9 @@ uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) {
|
||||
if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || (dyn->need_dump && dyn->need_dump != 3) || BOX64ENV(dynarec_missing)))
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || (dyn->need_dump && dyn->need_dump != 3)) {
|
||||
dynarec_log(LOG_NONE, " Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128 << vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@@ -237,44 +237,18 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
} else {
|
||||
INST_NAME("VUCOMISS Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGYx(d0, 0);
|
||||
GETEYSS(v0, 0, 0);
|
||||
CLEAR_FLAGS(x2);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_S(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_S(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_S(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
IFX (X_ALL) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
EMIT_COMIS_FLAGS(S, d0, v0, x2);
|
||||
break;
|
||||
case 0x50:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVMSKPS Gd, Ex");
|
||||
GETEYxy(v0, 0, 0);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVMSKLTZ_W(d1, v0);
|
||||
@@ -406,9 +380,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
GETEYSD(v1, 0, 0);
|
||||
}
|
||||
GETGYxy_empty(v0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if(vex.l) {
|
||||
XVFCVTH_D_S(d0, v1);
|
||||
@@ -417,9 +388,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
} else {
|
||||
VFCVTL_D_S(v0, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTDQ2PS Gx, Ex");
|
||||
@@ -506,14 +474,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (vex.v != 0) {
|
||||
UDF();
|
||||
} else {
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
XVXOR_V(q2, q2, q2);
|
||||
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
|
||||
if (dyn->lsx.avxcache[i].v != -1) {
|
||||
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256);
|
||||
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
|
||||
XVPERMI_Q(q1, VZERO, XVPERMI_IMM_4_0(0, 2));
|
||||
} else {
|
||||
VST(q2, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
VST(VZERO, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
}
|
||||
SMWRITE2();
|
||||
@@ -540,6 +506,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
INST_NAME("VLDMXCSR Md");
|
||||
GETED(0);
|
||||
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
/* LA <-> x86
|
||||
16/24 <-> 5 inexact
|
||||
|
||||
@@ -61,9 +61,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("ANDN Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDsd;
|
||||
ANDN(gd, ed, vd);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(gd, gd, 31, 0);
|
||||
@@ -90,7 +90,11 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("BLSR Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDsd;
|
||||
if (!rex.w) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_CF) {
|
||||
BNEZ(ed, 8);
|
||||
@@ -98,9 +102,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
ADDIxw(x3, ed, -1);
|
||||
AND(vd, ed, x3);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(vd, vd, 31, 0);
|
||||
}
|
||||
if (!rex.w) ZEROUP(vd);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(vd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
@@ -110,13 +112,20 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, vd, x3, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("BLSMSK Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDsd;
|
||||
if (!rex.w) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_CF) {
|
||||
BNEZ(ed, 8);
|
||||
@@ -124,21 +133,26 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
ADDIxw(x3, ed, -1);
|
||||
XOR(vd, ed, x3);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(vd, vd, 31, 0);
|
||||
}
|
||||
if (!rex.w) ZEROUP(vd);
|
||||
IFX (X_SF) {
|
||||
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, vd, x3, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("BLSI Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDsd;
|
||||
if (!rex.w) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_CF) {
|
||||
BEQZ(ed, 8);
|
||||
@@ -146,9 +160,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
SUBxw(x3, xZR, ed);
|
||||
AND(vd, ed, x3);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(vd, vd, 31, 0);
|
||||
}
|
||||
if (!rex.w) ZEROUP(vd);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(vd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
@@ -158,6 +170,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, vd, x3, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
default:
|
||||
@@ -169,9 +184,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("BZHI Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDs;
|
||||
CLEAR_FLAGS(x6);
|
||||
BSTRPICK_D(x4, vd, 7, 0);
|
||||
MOV64x(x5, rex.w ? 64 : 32);
|
||||
@@ -205,9 +220,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("BEXTR Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDs;
|
||||
BSTRPICK_D(x4, vd, 7, 0); // start
|
||||
BSTRPICK_D(x3, vd, 15, 8); // length
|
||||
XOR(x5, x5, x5);
|
||||
|
||||
@@ -231,43 +231,18 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
INST_NAME("VUCOMISD Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGYx(d0, 0);
|
||||
GETEYSD(v0, 0, 0);
|
||||
|
||||
CLEAR_FLAGS(x3);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_D(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_D(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_D(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
SPILL_EFLAGS();
|
||||
EMIT_COMIS_FLAGS(D, d0, v0, x3);
|
||||
break;
|
||||
case 0x50:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVMSKPD Gd, Ex");
|
||||
GETEYxy(v0, 0, 0);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVMSKLTZ_D(d1, v0);
|
||||
@@ -375,27 +350,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETEYxy(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFCVT_S_D(v0, d0, v1);
|
||||
XVFCVT_S_D(v0, VZERO, v1);
|
||||
XVPERMI_D(v0, v0, 0b11011000);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFCVT_S_D(d0, v1, v1);
|
||||
XVPICKVE_D(v0, d0, 0);
|
||||
}
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
if (vex.l) {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
@@ -425,7 +392,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VFTINT_W_S(v0, v1);
|
||||
}
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPD Gx, Vx, Ex");
|
||||
@@ -867,6 +833,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGYx(v0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
if (rex.w) {
|
||||
VPICKVE2GR_D(ed, v0, 0);
|
||||
} else {
|
||||
@@ -940,7 +907,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xC5:
|
||||
INST_NAME("VPEXTRW Gd, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
if (MODREG) {
|
||||
GETEYx(v0, 0, 1);
|
||||
u8 = (F8) & 7;
|
||||
@@ -1048,13 +1015,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VADDxy(D, v0, v1, v2);
|
||||
break;
|
||||
case 0xD5:
|
||||
INST_NAME("VPMULLW Gx, Ex");
|
||||
INST_NAME("VPMULLW Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VMULxy(H, v0, v1, v2);
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("VMOVD Ex, Gx");
|
||||
INST_NAME("VMOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
@@ -1070,7 +1037,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
INST_NAME("VPMOVMSKB Gd, Ex");
|
||||
GETEYxy(v0, 0, 0);
|
||||
GETGD;
|
||||
GETGDd;
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVMSKLTZ_B(d1, v0);
|
||||
@@ -1177,12 +1144,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETEYxy(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFTINTRZ_W_D(d1, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
XVFTINTRZ_W_D(d1, VZERO, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
@@ -1198,6 +1164,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
XVPERMI_D(v0, v0, 0b11011000);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFTINTRZ_W_D(d0, v1, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
@@ -1274,7 +1241,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VPXOR Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VXOR_Vxy(v0, v1, v2);
|
||||
XVXOR_V(v0, v1, v2);
|
||||
if (v0 == v1 && v0 == v2) YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0xF1:
|
||||
@@ -1341,6 +1308,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xF7:
|
||||
INST_NAME("VMASKMOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
UP32_READ(xRDI);
|
||||
GETEYx(v1, 0, 0);
|
||||
GETGYx(v0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
|
||||
@@ -63,12 +63,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VLDIxy(q0, 0b0000010001111); // broadcast 0b10001111 as byte
|
||||
VAND_Vxy(q0, q0, v2);
|
||||
VMINIxy(BU, q0, q0, 0x1f);
|
||||
VXOR_Vxy(q1, q1, q1);
|
||||
VSHUF_Bxy(v0, q1, v1, q0);
|
||||
VSHUF_Bxy(v0, VZERO, v1, q0);
|
||||
break;
|
||||
case 0x01:
|
||||
INST_NAME("VPHADDW Gx, Vx, Ex");
|
||||
@@ -346,25 +344,19 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
INST_NAME("VPABSB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
XVXOR_V(q0, q0, q0);
|
||||
VABSDxy(B, v0, v1, q0);
|
||||
VABSDxy(B, v0, v1, VZERO);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("VPABSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
XVXOR_V(q0, q0, q0);
|
||||
VABSDxy(H, v0, v1, q0);
|
||||
VABSDxy(H, v0, v1, VZERO);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("VPABSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
XVXOR_V(q0, q0, q0);
|
||||
VABSDxy(W, v0, v1, q0);
|
||||
VABSDxy(W, v0, v1, VZERO);
|
||||
break;
|
||||
case 0x20:
|
||||
INST_NAME("VPMOVSXBW Gx, Ex");
|
||||
@@ -498,32 +490,26 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
INST_NAME("VMASKMOVPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVSLTI_W(d1, v1, 0); // create all-one mask for negetive element.
|
||||
XVBITSEL_V(v0, d0, v2, d1);
|
||||
XVBITSEL_V(v0, VZERO, v2, d1);
|
||||
} else {
|
||||
VXOR_V(d0, d0, d0);
|
||||
VSLTI_W(d1, v1, 0); // create all-one mask for negetive element.
|
||||
VBITSEL_V(v0, d0, v2, d1);
|
||||
VBITSEL_V(v0, VZERO, v2, d1);
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VMASKMOVPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVSLTI_D(d1, v1, 0); // create all-one mask for negetive element.
|
||||
XVBITSEL_V(v0, d0, v2, d1);
|
||||
XVBITSEL_V(v0, VZERO, v2, d1);
|
||||
} else {
|
||||
VXOR_V(d0, d0, d0);
|
||||
VSLTI_D(d1, v1, 0); // create all-one mask for negetive element.
|
||||
VBITSEL_V(v0, d0, v2, d1);
|
||||
VBITSEL_V(v0, VZERO, v2, d1);
|
||||
}
|
||||
break;
|
||||
case 0x2E:
|
||||
@@ -698,7 +684,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
VMAXxy(WU, v0, v1, v2);
|
||||
break;
|
||||
case 0x40:
|
||||
INST_NAME("VPMULLD Gx, Ex");
|
||||
INST_NAME("VPMULLD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VMULxy(W, v0, v1, v2);
|
||||
@@ -836,24 +822,21 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
INST_NAME("VPMASKMOVD/Q Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
if (rex.w) {
|
||||
XVSLTI_D(d1, v1, 0);
|
||||
} else {
|
||||
XVSLTI_W(d1, v1, 0);
|
||||
}
|
||||
XVBITSEL_V(v0, d0, v2, d1);
|
||||
XVBITSEL_V(v0, VZERO, v2, d1);
|
||||
} else {
|
||||
VXOR_V(d0, d0, d0);
|
||||
if (rex.w) {
|
||||
VSLTI_D(d1, v1, 0);
|
||||
} else {
|
||||
VSLTI_W(d1, v1, 0);
|
||||
}
|
||||
VBITSEL_V(v0, d0, v2, d1);
|
||||
VBITSEL_V(v0, VZERO, v2, d1);
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
@@ -894,8 +877,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
int64_t i64 = F32S64;
|
||||
MOV64x(x5, i64);
|
||||
eb1 = x5;
|
||||
} else
|
||||
} else {
|
||||
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
|
||||
UP32_READ(eb1);
|
||||
}
|
||||
eb2 = ((u8 >> 3) & 7) + (rex.x << 3); // index
|
||||
if (nextop & 0x40)
|
||||
i32 = F8S;
|
||||
@@ -974,8 +959,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
int64_t i64 = F32S64;
|
||||
MOV64x(x5, i64);
|
||||
eb1 = x5;
|
||||
} else
|
||||
} else {
|
||||
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
|
||||
UP32_READ(eb1);
|
||||
}
|
||||
eb2 = ((u8 >> 3) & 7) + (rex.x << 3); // index
|
||||
if (nextop & 0x40)
|
||||
i32 = F8S;
|
||||
@@ -1312,7 +1299,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_Vxy(d0, q2, q2);
|
||||
} else
|
||||
d0 = -1;
|
||||
@@ -1331,7 +1318,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_Vxy(d0, q2, q2);
|
||||
} else
|
||||
d0 = -1;
|
||||
@@ -1350,7 +1337,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_Vxy(d0, q2, q2);
|
||||
} else
|
||||
d0 = -1;
|
||||
@@ -1369,7 +1356,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
|
||||
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d0 = SCRATCH;
|
||||
VOR_Vxy(d0, q2, q2);
|
||||
} else
|
||||
d0 = -1;
|
||||
@@ -1386,9 +1373,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF7:
|
||||
INST_NAME("SHLX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDs;
|
||||
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
|
||||
SLLxw(gd, ed, x5);
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int d0, d1;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
@@ -147,7 +147,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
XVXOR_V(v0, v0, v0);
|
||||
break;
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
uint8_t zero_low = (u8 & 0x8) >> 3;
|
||||
uint8_t zero_up = (u8 & 0x80) >> 7;
|
||||
uint8_t vec_lo = (u8 & 0x2) >> 1;
|
||||
@@ -165,13 +164,12 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
}
|
||||
break;
|
||||
}
|
||||
XVXOR_V(d0, d0, d0);
|
||||
if (zero_low) {
|
||||
XVORI_B(v0, vec_hi ? v2 : v1, 0);
|
||||
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(2 + index_hi, 0));
|
||||
XVPERMI_Q(v0, VZERO, XVPERMI_IMM_4_0(2 + index_hi, 0));
|
||||
} else {
|
||||
XVORI_B(v0, vec_lo ? v2 : v1, 0);
|
||||
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2 + index_lo));
|
||||
XVPERMI_Q(v0, VZERO, XVPERMI_IMM_4_0(0, 2 + index_lo));
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
@@ -180,13 +178,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
if (vex.l) {
|
||||
XVFRINT_S(v0, v1);
|
||||
} else {
|
||||
VFRINT_S(v0, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
if (vex.l) {
|
||||
XVFRINTRRD_S(v0, v1, round_round[u8 & 3]);
|
||||
@@ -201,13 +197,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
if (vex.l) {
|
||||
XVFRINT_D(v0, v1);
|
||||
} else {
|
||||
VFRINT_D(v0, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
if (vex.l) {
|
||||
XVFRINTRRD_D(v0, v1, round_round[u8 & 3]);
|
||||
@@ -225,9 +219,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_S(d0, v2);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_S(d0, v2, round_round[u8 & 3]);
|
||||
}
|
||||
@@ -243,9 +235,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_D(d0, v2);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_D(d0, v2, round_round[u8 & 3]);
|
||||
}
|
||||
@@ -381,6 +371,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UP32_WRITE32(ed);
|
||||
u8 = (F8) & 15;
|
||||
VPICKVE2GR_BU(ed, q0, u8);
|
||||
} else {
|
||||
@@ -397,6 +388,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UP32_WRITE32(ed);
|
||||
u8 = (F8) & 7;
|
||||
VPICKVE2GR_HU(ed, q0, u8);
|
||||
} else {
|
||||
@@ -417,6 +409,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
u8 = F8;
|
||||
if (rex.w) {
|
||||
VPICKVE2GR_D(ed, q0, (u8 & 1));
|
||||
@@ -440,6 +433,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGYx(v0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UP32_WRITE32(ed);
|
||||
u8 = F8 & 0b11;
|
||||
VPICKVE2GR_WU(ed, v0, u8);
|
||||
} else {
|
||||
@@ -507,26 +501,20 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETEYSD(v1, 1, 1);
|
||||
}
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x4, x5);
|
||||
} else {
|
||||
if (!(u8 & 4)) {
|
||||
MOVFCSR2GR(x4, FCSR3);
|
||||
ORI(x5, xZR, ((-(u8 & 3)) & 3) << 8);
|
||||
MOVGR2FCSR(FCSR3, x5);
|
||||
u8 = x4;
|
||||
}
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFCVT_H_S(v1, d0, v0);
|
||||
XVFCVT_H_S(v1, VZERO, v0);
|
||||
XVPERMI_D(v1, v1, 0b11011000);
|
||||
PUTEYx(v1);
|
||||
} else {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
VFCVT_H_S(v1, d0, v0);
|
||||
VFCVT_H_S(v1, VZERO, v0);
|
||||
PUTEYSD(v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!(u8 & 4)) x87_restoreround(dyn, ninst, x4);
|
||||
break;
|
||||
case 0x20:
|
||||
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
|
||||
@@ -573,10 +561,9 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
}
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
if (zmask) {
|
||||
VXOR_V(q1, q1, q1);
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (zmask & (1 << i)) {
|
||||
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0(i, 0));
|
||||
VEXTRINS_W(v0, VZERO, VEXTRINS_IMM_4_0(i, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -606,12 +593,10 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d2 = fpu_get_scratch(dyn);
|
||||
VFMULxy(S, d0, v1, v2);
|
||||
VXOR_Vxy(d2, d2, d2);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(u8 & (1 << (4 + i)))) {
|
||||
VEXTRINSxy(W, d0, d2, (i << 4));
|
||||
VEXTRINSxy(W, d0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
VSHUF4Ixy(W, d1, d0, 0b10110001); // v0[a,b,c,d] v1[b,a,d,c]
|
||||
@@ -621,7 +606,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
VREPLVEIxy(W, v0, d0, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(u8 & (1 << i))) {
|
||||
VEXTRINSxy(W, v0, d2, (i << 4));
|
||||
VEXTRINSxy(W, v0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -632,12 +617,10 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d2 = fpu_get_scratch(dyn);
|
||||
VFMULxy(D, d0, v1, v2);
|
||||
VXOR_Vxy(d2, d2, d2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (!(u8 & (1 << (4 + i)))) {
|
||||
VEXTRINSxy(D, d0, d2, (i << 4));
|
||||
VEXTRINSxy(D, d0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
VSHUF4Ixy(W, d1, d0, 0b01001110); // v0[a,b] v1[b,a]
|
||||
@@ -645,7 +628,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
VREPLVEIxy(D, v0, d0, 0);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (!(u8 & (1 << i))) {
|
||||
VEXTRINSxy(D, v0, d2, (i << 4));
|
||||
VEXTRINSxy(D, v0, VZERO, (i << 4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -117,9 +117,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d1, ed);
|
||||
FFINT_D_L(d1, d1);
|
||||
@@ -127,16 +124,13 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOVGR2FR_W(d1, ed);
|
||||
FFINT_D_W(d1, d1);
|
||||
}
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEYSD(q0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
@@ -165,13 +159,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEYSD(q0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
if (rex.w) {
|
||||
FTINT_L_D(d1, q0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
@@ -180,7 +173,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -202,9 +194,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FSQRT_D(d1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(d0, d0, d0);
|
||||
FCMP_D(fcc0, v2, d0, cLT);
|
||||
FCMP_D(fcc0, v2, VZERO, cLT);
|
||||
BCEQZ(fcc0, 4 + 4);
|
||||
FNEG_D(d1, d1);
|
||||
}
|
||||
@@ -270,13 +260,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
FCVT_S_D(d0, v2);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
XVINSVE0_W(v0, d0, 0);
|
||||
break;
|
||||
@@ -438,8 +422,8 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 1);
|
||||
GETGYx(v0, 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
u8 = F8;
|
||||
q0 = ((u8 & 0xf) == 0x0b) ? VZERO : fpu_get_scratch(dyn);
|
||||
switch (u8 & 0xf) {
|
||||
case 0x00: VFCMP_D(q0, v1, v2, cEQ); break; // Equal, not unordered
|
||||
case 0x01: VFCMP_D(q0, v1, v2, cLT); break; // Less than
|
||||
@@ -452,7 +436,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x08: VFCMP_D(q0, v1, v2, cUEQ); break; // Equal, or unordered
|
||||
case 0x09: VFCMP_D(q0, v1, v2, cULT); break; // Less than or unordered
|
||||
case 0x0a: VFCMP_D(q0, v1, v2, cULE); break; // Less or equal or unordered
|
||||
case 0x0b: VXOR_V(q0, q0, q0); break; // false
|
||||
case 0x0b: break; // false
|
||||
case 0x0c: VFCMP_D(q0, v1, v2, cNE); break; // Not Eual, ordered
|
||||
case 0x0d: VFCMP_D(q0, v2, v1, cLE); break; // Greater or Equal ordered
|
||||
case 0x0e: VFCMP_D(q0, v2, v1, cLT); break; // Greater ordered
|
||||
@@ -494,19 +478,17 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETEYxy(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
XVFTINT_L_D(q2, v1);
|
||||
XVFCMP_D(d1, v1, v1, cUN); // get NaN mask
|
||||
}
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
XVFTINT_W_D(v0, VZERO, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
MOV32w(x5, 0x7FFFFFFF);
|
||||
@@ -519,6 +501,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
XVPERMI_D(v0, v0, 0b11011000);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFTINT_W_D(d0, v1, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
@@ -538,7 +521,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
XVPICKVE_D(v0, d0, 0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("VLDDQU Gx, Ex");
|
||||
|
||||
@@ -60,8 +60,8 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF5:
|
||||
INST_NAME("PDEP Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETVD;
|
||||
GETGDd;
|
||||
GETVDs;
|
||||
GETED(0);
|
||||
if (gd == ed || gd == vd) {
|
||||
gb1 = gd;
|
||||
@@ -89,9 +89,10 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDsd;
|
||||
MARKREGs(xRDX);
|
||||
if (rex.w) {
|
||||
if ((gd == xRDX) || (gd == ed) || (gd == vd))
|
||||
gb1 = x3;
|
||||
@@ -111,9 +112,9 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF7:
|
||||
INST_NAME("SHRX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDs;
|
||||
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
|
||||
SRLxw(gd, ed, x5);
|
||||
break;
|
||||
|
||||
@@ -60,7 +60,7 @@ uintptr_t dynarec64_AVX_F2_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF0:
|
||||
INST_NAME("RORX Gd, Ed, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDsd;
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
ROTRIxw(gd, ed, u8 & (rex.w ? 0x3f : 0x1f));
|
||||
|
||||
@@ -107,9 +107,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d1, ed);
|
||||
FFINT_S_L(d1, d1);
|
||||
@@ -117,21 +114,17 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOVGR2FR_W(d1, ed);
|
||||
FFINT_S_W(d1, d1);
|
||||
}
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEYSS(d0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINTRZ_L_S(d1, d0);
|
||||
@@ -141,7 +134,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -157,12 +149,11 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEYSS(d0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINT_L_S(d1, d0);
|
||||
@@ -172,7 +163,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -194,9 +184,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FSQRT_S(d1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(d0, d0, d0);
|
||||
FCMP_S(fcc0, v2, d0, cLT);
|
||||
FCMP_S(fcc0, v2, VZERO, cLT);
|
||||
BCEQZ(fcc0, 4 + 4);
|
||||
FNEG_S(d1, d1);
|
||||
}
|
||||
@@ -475,8 +463,8 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 1);
|
||||
GETGYx(v0, 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
u8 = F8;
|
||||
q0 = ((u8 & 0xf) == 0x0b) ? VZERO : fpu_get_scratch(dyn);
|
||||
switch (u8 & 0xf) {
|
||||
case 0x00: VFCMP_S(q0, v1, v2, cEQ); break; // Equal, not unordered
|
||||
case 0x01: VFCMP_S(q0, v1, v2, cLT); break; // Less than
|
||||
@@ -489,7 +477,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x08: VFCMP_S(q0, v1, v2, cUEQ); break; // Equal, or unordered
|
||||
case 0x09: VFCMP_S(q0, v1, v2, cULT); break; // Less than or unordered
|
||||
case 0x0a: VFCMP_S(q0, v1, v2, cULE); break; // Less or equal or unordered
|
||||
case 0x0b: VXOR_V(q0, q0, q0); break; // false
|
||||
case 0x0b: break; // false
|
||||
case 0x0c: VFCMP_S(q0, v1, v2, cNE); break; // Not Eual, ordered
|
||||
case 0x0d: VFCMP_S(q0, v2, v1, cLE); break; // Greater or Equal ordered
|
||||
case 0x0e: VFCMP_S(q0, v2, v1, cLT); break; // Greater ordered
|
||||
|
||||
@@ -60,8 +60,8 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF5:
|
||||
INST_NAME("PEXT Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETVD;
|
||||
GETGDd;
|
||||
GETVDs;
|
||||
GETED(0);
|
||||
if (gd == ed || gd == vd) {
|
||||
gb1 = gd;
|
||||
@@ -90,9 +90,9 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0xF7:
|
||||
INST_NAME("SARX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
GETVDs;
|
||||
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
|
||||
SRAxw(gd, ed, x5);
|
||||
break;
|
||||
|
||||
@@ -120,7 +120,7 @@ uintptr_t dynarec64_DB(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xE8 ... 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop & 7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7));
|
||||
if (ST_IS_F(0)) {
|
||||
@@ -132,7 +132,7 @@ uintptr_t dynarec64_DB(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xF0 ... 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop & 7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7));
|
||||
if (ST_IS_F(0)) {
|
||||
|
||||
@@ -87,7 +87,7 @@ uintptr_t dynarec64_DF(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop & 7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7));
|
||||
|
||||
@@ -168,7 +168,7 @@ void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
X64_XOR_W(s1, s2);
|
||||
}
|
||||
XOR(s1, s1, s2);
|
||||
if (!rex.w && s1 != s2) ZEROUP(s1);
|
||||
if (s1 != s2 && NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -185,9 +185,7 @@ void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w && s1 != s2) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w && s1 != s2) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -231,9 +229,7 @@ void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
}
|
||||
XOR(s1, s1, s3);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -254,9 +250,7 @@ void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -412,16 +406,16 @@ void emit_and32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
AND(s1, s1, s2); // res = s1 & s2
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
} else if (!rex.w) ZEROUP(s1);
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
@@ -554,7 +548,7 @@ void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
@@ -607,7 +601,7 @@ void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
@@ -619,9 +613,7 @@ void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
|
||||
@@ -44,7 +44,7 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
X64_ADD_W(s1, s2);
|
||||
}
|
||||
ADDxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -55,17 +55,9 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (rex.w) {
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s5, s4);
|
||||
SRLI_D(s3, s1, 0x20);
|
||||
SRLI_D(s4, s2, 0x20);
|
||||
ADD_D(s4, s4, s3);
|
||||
SRLI_D(s5, s5, 0x20);
|
||||
ADD_D(s5, s5, s4); // hi
|
||||
SRAI_D(s5, s5, 0x20);
|
||||
BEQZ(s5, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
ADD_D(s5, s1, s2); // s5 = op1 + op2
|
||||
SLTU(s5, s5, s1); // carry = (s5 < op1) ? 1 : 0
|
||||
OR(xFlags, xFlags, s5);
|
||||
} else {
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
@@ -105,9 +97,7 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -159,7 +149,7 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
} else {
|
||||
ADDxw(s1, s1, s2);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND) SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -169,17 +159,9 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (rex.w) {
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s5, s4);
|
||||
SRLI_D(s3, s1, 0x20);
|
||||
SRLI_D(s4, s2, 0x20);
|
||||
ADD_D(s4, s4, s3);
|
||||
SRLI_D(s5, s5, 0x20);
|
||||
ADD_D(s5, s5, s4); // hi
|
||||
SRAI_D(s5, s5, 0x20);
|
||||
BEQZ(s5, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
ADD_D(s5, s1, s2); // s5 = op1 + op2
|
||||
SLTU(s5, s5, s1); // carry = (s5 < op1) ? 1 : 0
|
||||
OR(xFlags, xFlags, s5);
|
||||
} else {
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
@@ -223,9 +205,7 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -588,7 +568,7 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
X64_SUB_W(s1, s2);
|
||||
}
|
||||
SUBxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -610,9 +590,7 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
@@ -666,7 +644,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
} else {
|
||||
SUBxw(s1, s1, s2);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -693,9 +671,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
@@ -1015,7 +991,7 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
@@ -1048,9 +1024,7 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
@@ -1236,21 +1210,23 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (rex.w)
|
||||
ADC_D(s3, s1, s2);
|
||||
else
|
||||
ADC_W(s3, s1, s2);
|
||||
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
if (rex.w) {
|
||||
ADC_D(s3, s1, s2);
|
||||
X64_ADC_D(s1, s2);
|
||||
else
|
||||
MV(s1, s3);
|
||||
} else {
|
||||
ADC_W(s3, s1, s2);
|
||||
X64_ADC_W(s1, s2);
|
||||
ZEROUP2(s1, s3);
|
||||
}
|
||||
} else {
|
||||
if (rex.w)
|
||||
ADC_D(s1, s1, s2);
|
||||
else
|
||||
ADC_W(s1, s1, s2);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
}
|
||||
if (rex.w)
|
||||
MV(s1, s3);
|
||||
else
|
||||
ZEROUP2(s1, s3);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1318,9 +1294,7 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
@@ -1474,7 +1448,7 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
|
||||
ADDIxw(s1, s1, 1);
|
||||
if (cpuext.lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
@@ -1499,9 +1473,7 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
@@ -1640,7 +1612,7 @@ void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
}
|
||||
ADDIxw(s1, s1, -1);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ void emit_shl16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
} else IFX (X_ALL) {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
@@ -222,7 +222,7 @@ void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
X64_SET_EFLAGS(s3, (X_OF | X_AF));
|
||||
}
|
||||
SLL_D(s1, s1, s2);
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -286,7 +286,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
} else IFX (X_ALL) {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
@@ -302,8 +302,11 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
BSTRINS_D(s3, xZR, F_AF, F_AF);
|
||||
X64_SET_EFLAGS(s3, (X_OF | X_AF));
|
||||
}
|
||||
SLLIxw(s1, s1, c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (rex.w)
|
||||
SLLI_D(s1, s1, c);
|
||||
else
|
||||
SLLI_W(s1, s1, c);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -333,9 +336,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
SLTI(s3, s1, 0);
|
||||
BSTRINS_D(xFlags, s3, F_SF, F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -824,8 +825,11 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BSTRINS_D(s3, xZR, F_AF, F_AF);
|
||||
X64_SET_EFLAGS(s3, X_OF | X_AF);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (rex.w)
|
||||
SRL_D(s1, s1, s2);
|
||||
else
|
||||
SRL_W(s1, s1, s2);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -846,15 +850,16 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
SRL_D(s1, s1, s2);
|
||||
if (rex.w)
|
||||
SRL_D(s1, s1, s2);
|
||||
else
|
||||
SRL_W(s1, s1, s2);
|
||||
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1024,7 +1029,7 @@ void emit_sar16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
} else IFX (X_ALL) {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
@@ -1100,7 +1105,7 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
} else IFX (X_ALL) {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
@@ -1112,8 +1117,11 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
|
||||
IFXA ((X_AF | X_OF), BOX64DRENV(dynarec_safeflags)) X64_SET_EFLAGS(xZR, X_OF | X_AF);
|
||||
|
||||
SRAIxw(s1, s1, c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (rex.w)
|
||||
SRAI_D(s1, s1, c);
|
||||
else
|
||||
SRAI_W(s1, s1, c);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1146,9 +1154,7 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1182,8 +1188,11 @@ void emit_sar32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
|
||||
IFXA ((X_AF | X_OF), BOX64DRENV(dynarec_safeflags)) X64_SET_EFLAGS(xZR, X_OF | X_AF);
|
||||
|
||||
SRAxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (rex.w)
|
||||
SRA_D(s1, s1, s2);
|
||||
else
|
||||
SRA_W(s1, s1, s2);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1199,7 +1208,7 @@ void emit_sar32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
if (rex.w)
|
||||
SRA_D(s1, s1, s2);
|
||||
else
|
||||
else
|
||||
SRA_W(s1, s1, s2);
|
||||
|
||||
IFX (X_SF) {
|
||||
@@ -1226,47 +1235,61 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFXA ((X_CF | X_OF), cpuext.lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTRI_D(s1, c);
|
||||
else
|
||||
X64_ROTRI_W(s1, c);
|
||||
}
|
||||
int preserve_of = c > 1 && !(dyn->insts[ninst].x64.gen_flags & X_OF);
|
||||
|
||||
IFXA (X_CF | X_OF, !cpuext.lbt) {
|
||||
MOV64x(s4, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
|
||||
IFXA (X_OF, (!cpuext.lbt || BOX64DRENV(dynarec_safeflags))) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s1);
|
||||
if (cpuext.lbt) {
|
||||
if (cpuext.lbt && !preserve_of) {
|
||||
IFX (X_CF | X_OF) {
|
||||
if (rex.w)
|
||||
X64_ROTRI_D(s1, c);
|
||||
else
|
||||
X64_ROTRI_W(s1, c);
|
||||
}
|
||||
IFXA (X_OF, BOX64DRENV(dynarec_safeflags)) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s1);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
X64_SET_EFLAGS(s3, X_OF);
|
||||
} else
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (rex.w)
|
||||
ROTRI_D(s1, s1, c);
|
||||
else
|
||||
ROTRI_W(s1, s1, c);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (preserve_of) RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_CF) BSTRINS_D(xFlags, xZR, F_CF, F_CF);
|
||||
IFX (X_OF) BSTRINS_D(xFlags, xZR, F_OF, F_OF);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s1);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
if (rex.w)
|
||||
ROTRI_D(s1, s1, c);
|
||||
else
|
||||
ROTRI_W(s1, s1, c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_CF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit ROL8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_W(s3, s1, 6);
|
||||
@@ -1339,9 +1362,9 @@ void emit_rol8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_rol16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
|
||||
IFXA (X_OF, c == 1) {
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 14);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s4, s3);
|
||||
@@ -1403,7 +1426,6 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ROTR_W(s1, s1, s3);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
@@ -1446,12 +1468,12 @@ void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
} else {
|
||||
ROTR_W(s1, s1, s2);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
} else if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_CF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
@@ -1465,41 +1487,56 @@ void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFXA (X_CF | X_OF, !cpuext.lbt) {
|
||||
MOV64x(s3, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s3);
|
||||
}
|
||||
int preserve_of = c > 1 && !(dyn->insts[ninst].x64.gen_flags & X_OF);
|
||||
|
||||
IFXA ((X_CF | X_OF), cpuext.lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTLI_D(s1, c);
|
||||
else
|
||||
X64_ROTLI_W(s1, c);
|
||||
}
|
||||
|
||||
IFXA (X_OF, (!cpuext.lbt || BOX64DRENV(dynarec_safeflags))) {
|
||||
SRLIxw(s3, s1, rex.w ? 62 : 30);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
if (cpuext.lbt) {
|
||||
if (cpuext.lbt && !preserve_of) {
|
||||
IFX (X_CF | X_OF) {
|
||||
if (rex.w)
|
||||
X64_ROTLI_D(s1, c);
|
||||
else
|
||||
X64_ROTLI_W(s1, c);
|
||||
}
|
||||
IFXA (X_OF, BOX64DRENV(dynarec_safeflags)) {
|
||||
SRLIxw(s3, s1, rex.w ? 62 : 30);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
X64_SET_EFLAGS(s3, X_OF);
|
||||
} else
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (rex.w)
|
||||
ROTRI_D(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
else
|
||||
ROTRI_W(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
if (NEED_ZEROUP(s1)) ZEROUP(s1);
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (preserve_of) RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_CF) BSTRINS_D(xFlags, xZR, F_CF, F_CF);
|
||||
IFX (X_OF) BSTRINS_D(xFlags, xZR, F_OF, F_OF);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLIxw(s3, s1, rex.w ? 62 : 30);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
if (rex.w)
|
||||
ROTRI_D(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
else
|
||||
ROTRI_W(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_CF) {
|
||||
ANDI(s4, s1, 1 << F_CF);
|
||||
OR(xFlags, xFlags, s4);
|
||||
}
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
@@ -1534,9 +1571,7 @@ void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
SRLIxw(s1, s2, (rex.w ? 64 : 32) - c);
|
||||
OR(s1, s1, s3);
|
||||
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_SF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
BEQZ(s3, 8);
|
||||
@@ -1593,9 +1628,7 @@ void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
SLLIxw(s1, s2, (rex.w ? 64 : 32) - c);
|
||||
OR(s1, s1, s3);
|
||||
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_SF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
BEQZ(s3, 8);
|
||||
@@ -1647,9 +1680,7 @@ void emit_shrd32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
@@ -1878,7 +1909,6 @@ void emit_rcl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
OR(s1, s5, s4);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
@@ -1992,10 +2022,16 @@ void emit_rcr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ADDI_D(s5, s2, -1);
|
||||
IFX (X_CF) SRL_D(s3, s1, s5); // for later
|
||||
|
||||
SRLI_D(s4, s1, 1);
|
||||
if (rex.w)
|
||||
SRLI_D(s4, s1, 1);
|
||||
else
|
||||
SRLI_W(s4, s1, 1);
|
||||
BSTRINS_D(s4, xFlags, rex.w ? 63 : 31, rex.w ? 63 : 31); // insert cf
|
||||
BEQZ(s5, 4 + 4 * 5); // goto label
|
||||
SRL_D(s4, s4, s5);
|
||||
if (rex.w)
|
||||
SRL_D(s4, s4, s5);
|
||||
else
|
||||
SRL_W(s4, s4, s5);
|
||||
ADDI_D(s5, xZR, rex.w ? 65 : 33);
|
||||
SUB_D(s2, s5, s2);
|
||||
if (rex.w)
|
||||
@@ -2036,7 +2072,6 @@ void emit_rcr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
OR(s1, s3, s4);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, s5, F_CF, F_CF);
|
||||
}
|
||||
@@ -2048,7 +2083,7 @@ void emit_rcr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
// emit ROR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
@@ -2075,7 +2110,7 @@ void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
@@ -2103,8 +2138,8 @@ void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_ror16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFXA (X_OF, (c == 1)) {
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
XOR(s3, s3, s1);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
@@ -2379,7 +2414,7 @@ void emit_shrd16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit ROL16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
|
||||
ANDI(s2, s2, 0xf);
|
||||
IFX (X_OF) {
|
||||
@@ -2407,7 +2442,7 @@ void emit_rol16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit ROR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_ALL) RESTORE_EFLAGS(s3);
|
||||
|
||||
ANDI(s2, s2, 0xf);
|
||||
IFX (X_OF) {
|
||||
|
||||
@@ -437,12 +437,12 @@ void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
if (cpuext.lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_AND_B(s1, s2);
|
||||
}
|
||||
if (s1 == s2) {
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
int r = s1;
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
@@ -561,13 +561,13 @@ void emit_test16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_AND_H(s1, s2);
|
||||
}
|
||||
|
||||
if (s1 == s2) {
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
int r = s1;
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
@@ -630,6 +630,7 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
if (cpuext.lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
@@ -639,7 +640,6 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
}
|
||||
|
||||
if (s1 == s2) {
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
int r = s1;
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (!rex.w) {
|
||||
|
||||
@@ -77,7 +77,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -148,7 +148,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK OR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -197,7 +197,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
SRAI_D(x1, gd, 3);
|
||||
@@ -288,7 +288,8 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK CMPXCHG Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
MARKREGs(xRAX);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
UFLAG_IF { MVxw(x6, xRAX); }
|
||||
ANDI(x1, wback, (1 << (rex.w + 2)) - 1);
|
||||
@@ -339,7 +340,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
SRAI_D(x1, gd, 3);
|
||||
@@ -419,7 +420,6 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("LOCK BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
@@ -489,7 +489,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK XADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDsd;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -556,6 +556,10 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
}
|
||||
if (rex.w) {
|
||||
MARKREGsd(xRAX);
|
||||
MARKREGsd(xRDX);
|
||||
MARKREGs(xRBX);
|
||||
MARKREGs(xRCX);
|
||||
if (cpuext.scq) {
|
||||
MARKLOCK;
|
||||
LL_D(x2, wback, 0);
|
||||
@@ -613,6 +617,8 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
AMSWAP_DB_W(xZR, xZR, x6);
|
||||
}
|
||||
} else {
|
||||
UP32_READ(xRDX);
|
||||
UP32_READ(xRCX);
|
||||
BSTRINS_D(x3, xRAX, 31, 0);
|
||||
BSTRINS_D(x3, xRDX, 63, 32);
|
||||
BSTRINS_D(x4, xRBX, 31, 0);
|
||||
@@ -680,7 +686,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("LOCK ADC Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x7, X_CF);
|
||||
@@ -736,7 +742,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("LOCK SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x6, X_CF);
|
||||
@@ -823,7 +829,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -868,7 +874,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -915,7 +921,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK XOR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETGDs;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -1412,7 +1418,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*ok = 0;
|
||||
} else {
|
||||
INST_NAME("LOCK XCHG Ed, Gd");
|
||||
GETGD;
|
||||
GETGDsd;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -1446,6 +1452,41 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MVxw(gd, x1);
|
||||
}
|
||||
break;
|
||||
case 0xF6:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 2:
|
||||
if (MODREG) {
|
||||
INST_NAME("Invalid LOCK");
|
||||
UDF();
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
} else {
|
||||
INST_NAME("LOCK NOT Eb");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lamcas) {
|
||||
LD_BU(x3, wback, 0);
|
||||
MARKLOCK2;
|
||||
MV(x2, x3);
|
||||
XORI(x1, x3, 0xff);
|
||||
AMCAS_DB_B(x3, x1, wback);
|
||||
BSTRPICK_D(x3, x3, 7, 0);
|
||||
BNE_MARKLOCK2(x3, x2);
|
||||
} else {
|
||||
ANDI(x2, wback, 3);
|
||||
SLLI_D(x2, x2, 3);
|
||||
MV(x3, wback);
|
||||
BSTRINS_D(x3, xZR, 1, 0);
|
||||
ADDI_D(x1, xZR, 0xff);
|
||||
SLL_W(x1, x1, x2);
|
||||
AMXOR_DB_W(x4, x1, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
|
||||
@@ -98,9 +98,6 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d1, ed);
|
||||
FFINT_D_L(d1, d1);
|
||||
@@ -108,15 +105,12 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOVGR2FR_W(d1, ed);
|
||||
FFINT_D_W(d1, d1);
|
||||
}
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
@@ -128,9 +122,8 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
FTINTRZ_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -146,22 +139,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
if (rex.w) {
|
||||
FTINT_L_D(d1, q0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINT_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -182,21 +173,23 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("CRC32 Gd, Eb");
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGD;
|
||||
GETGDw;
|
||||
UP32_WRITE32(gd);
|
||||
CRCC_W_B_W(gd, gd, ed);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP32(gd)) ZEROUP(gd);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("CRC32 Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGDw;
|
||||
UP32_WRITE32(gd);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (rex.w) {
|
||||
CRCC_W_D_W(gd, gd, ed);
|
||||
} else {
|
||||
CRCC_W_W_W(gd, gd, ed);
|
||||
}
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP32(gd)) ZEROUP(gd);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -272,13 +265,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
FCVT_S_D(d1, d0);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5C:
|
||||
@@ -520,7 +507,6 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINT_W_D(v0, v1, v1);
|
||||
} else {
|
||||
@@ -535,7 +521,6 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VSHUF4I_W(q1, q1, 0b00001000);
|
||||
VBITSEL_V(v0, d0, q0, q1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VINSGR2VR_D(v0, xZR, 1);
|
||||
break;
|
||||
case 0xF0:
|
||||
|
||||
@@ -105,23 +105,17 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_D(d1, ed);
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
}
|
||||
if (rex.w) {
|
||||
FFINT_S_L(d1, d1);
|
||||
} else {
|
||||
FFINT_S_W(d1, d1);
|
||||
}
|
||||
if (BOX64ENV(dynarec_fastround) <= 1) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
@@ -133,7 +127,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
FTINTRZ_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
@@ -152,12 +146,11 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (addr >= 0x1033f98d && addr <= 0x1033f98d + 8)
|
||||
EMIT(0);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETGDd;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINT_L_S(d1, d0);
|
||||
@@ -165,9 +158,8 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
FTINT_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -188,8 +180,8 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
READFLAGS(X_OF);
|
||||
SETFLAGS(X_OF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x3, X_OF);
|
||||
SRLI_D(x3, x3, F_OF);
|
||||
@@ -221,7 +213,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
ADDxw(x5, gd, ed);
|
||||
ADDxw(gd, x5, x3);
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -239,9 +231,10 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
GETGDsd; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP(NATNO, 8); \
|
||||
} else { \
|
||||
@@ -251,7 +244,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
B##NO(tmp1, 8); \
|
||||
} \
|
||||
MV(gd, ed); \
|
||||
if (!rex.w) ZEROUP(gd); \
|
||||
if (NEED_ZEROUP(gd)) ZEROUP(gd); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, tmp2, tmp3, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
@@ -513,8 +506,16 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
|
||||
VOR_V(v1, v0, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
IF_UNALIGNED(ip) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 15, 0);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
VPICKVE2GR_BU(x4, v0, i);
|
||||
ST_B(x4, ed, fixedaddress + i);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
VST(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -550,6 +551,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("RDFSBASE");
|
||||
}
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGd(ed);
|
||||
int seg = _FS + ((nextop >> 3) & 7);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
MVxw(ed, x4);
|
||||
@@ -568,6 +570,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("WRFSBASE");
|
||||
}
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MARKREGs(ed);
|
||||
int seg = _FS + ((nextop >> 3) & 7) - 2;
|
||||
if (!rex.w) {
|
||||
ZEROUP2(x4, ed);
|
||||
@@ -593,22 +596,16 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
GETED(0);
|
||||
if (rex.w) {
|
||||
VINSGR2VR_D(v1, ed, 0);
|
||||
} else {
|
||||
VINSGR2VR_W(v1, ed, 0);
|
||||
}
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
if (rex.w) {
|
||||
VINSGR2VR_D(v1, ed, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLDxw(v1, ed, fixedaddress);
|
||||
VINSGR2VR_W(v1, ed, 0);
|
||||
}
|
||||
if (rex.w) {
|
||||
VPCNT_D(v1, v1);
|
||||
@@ -633,11 +630,15 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
@@ -658,11 +659,15 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGDsd;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
|
||||
@@ -35,7 +35,12 @@
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_la64_t* dyn)
|
||||
{
|
||||
return SCRATCH0 + dyn->lsx.fpu_scratch++; // return an Sx
|
||||
int ret = SCRATCH0 + dyn->lsx.fpu_scratch++; // return an Sx
|
||||
if (ret >= SCRATCH_LIMIT) {
|
||||
dyn->abort = 1;
|
||||
ret = SCRATCH_LIMIT - 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_la64_t* dyn)
|
||||
@@ -605,6 +610,10 @@ static const char* df_status[] = { "unknown", "set", "none_pending", "none" };
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
if (dyn->need_dump == 3) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
if (!BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
}
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
|
||||
static char buf[4096];
|
||||
@@ -652,8 +661,10 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
length += sprintf(buf + length, " X87:%d/%d(+%d/-%d)%d", dyn->lsx.stack, dyn->insts[ninst].lsx.stack_next, dyn->insts[ninst].lsx.stack_push, dyn->insts[ninst].lsx.stack_pop, dyn->insts[ninst].lsx.x87stack);
|
||||
if (dyn->insts[ninst].lsx.combined1 || dyn->insts[ninst].lsx.combined2)
|
||||
length += sprintf(buf + length, " %s:%d/%d", dyn->insts[ninst].lsx.swapped ? "SWP" : "CMB", dyn->insts[ninst].lsx.combined1, dyn->insts[ninst].lsx.combined2);
|
||||
if(dyn->insts[ninst].x64.self_loop)
|
||||
length += sprintf(buf + length, " self-loop");
|
||||
|
||||
if (dyn->need_dump) {
|
||||
if (dyn->need_dump && dyn->need_dump != 3) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, %s%s\n",
|
||||
(dyn->need_dump > 1) ? "\e[32m" : "",
|
||||
@@ -812,27 +823,48 @@ void fpu_unwind_restore(dynarec_la64_t* dyn, int ninst, lsxcache_t* cache)
|
||||
memcpy(&dyn->insts[ninst].lsx, cache, sizeof(lsxcache_t));
|
||||
}
|
||||
|
||||
static int hasLinearPredecessor(const dynarec_la64_t* dyn, int ninst)
|
||||
{
|
||||
return ninst > 0 && dyn->insts[ninst].pred_sz == 1 && dyn->insts[ninst].pred[0] == ninst - 1;
|
||||
}
|
||||
|
||||
void updateNativeFlags(dynarec_la64_t* dyn)
|
||||
{
|
||||
if (!BOX64ENV(dynarec_nativeflags))
|
||||
return;
|
||||
for (int i = 1; i < dyn->size; ++i)
|
||||
for (int i = 0; i < dyn->size; ++i) {
|
||||
if (dyn->insts[i].nat_flags_fusion) {
|
||||
int j = i - 1;
|
||||
int found = 0;
|
||||
if (dyn->insts[i].pred_sz == 1 && dyn->insts[i].pred[0] == j) {
|
||||
int last_fused = 0;
|
||||
if (hasLinearPredecessor(dyn, i)) {
|
||||
while (j >= 0) {
|
||||
if (dyn->insts[j].x64.set_flags && (dyn->insts[i].x64.use_flags & dyn->insts[j].x64.set_flags) == dyn->insts[i].x64.use_flags) {
|
||||
int needsign = (dyn->insts[i].x64.use_flags & X_SF) ? 1 : 0;
|
||||
int needunsigned = (dyn->insts[i].x64.use_flags & X_CF) ? 1 : 0;
|
||||
if (dyn->insts[j].nat_flags_fusion && ((needsign && dyn->insts[j].nat_flags_needunsigned) || (needunsigned && dyn->insts[j].nat_flags_needsign)))
|
||||
break; // not compatible, stop here
|
||||
dyn->insts[j].nat_flags_fusion = 1;
|
||||
if (dyn->insts[i].x64.use_flags & X_SF) {
|
||||
if (needsign)
|
||||
dyn->insts[j].nat_flags_needsign = 1;
|
||||
}
|
||||
if (needunsigned)
|
||||
dyn->insts[j].nat_flags_needunsigned = 1;
|
||||
dyn->insts[i].x64.use_flags = 0;
|
||||
dyn->insts[j].nat_next_inst = i;
|
||||
if (last_fused) {
|
||||
dyn->insts[last_fused].nat_next_inst = i;
|
||||
} else {
|
||||
uint16_t* next = &dyn->insts[j].nat_next_inst;
|
||||
while (*next) next = &dyn->insts[*next].nat_next_inst;
|
||||
*next = i;
|
||||
}
|
||||
dyn->insts[i].up32_read |= dyn->insts[j].up32_write32;
|
||||
found = 1;
|
||||
break;
|
||||
} else if (j && dyn->insts[j].pred_sz == 1 && dyn->insts[j].pred[0] == j - 1
|
||||
&& dyn->insts[j].no_scratch_usage && !dyn->insts[j].x64.set_flags && !dyn->insts[j].x64.use_flags) {
|
||||
} else if (hasLinearPredecessor(dyn, j) && dyn->insts[j].nat_flags_fusion && dyn->insts[j].x64.jmp && !dyn->insts[j].x64.set_flags && !dyn->insts[j].x64.use_flags) {
|
||||
// already fused Jcc consumer
|
||||
if (!last_fused) last_fused = j;
|
||||
j -= 1;
|
||||
} else if (hasLinearPredecessor(dyn, j) && dyn->insts[j].no_scratch_usage && !dyn->insts[j].x64.set_flags && !dyn->insts[j].x64.use_flags) {
|
||||
j -= 1;
|
||||
} else
|
||||
break;
|
||||
@@ -840,6 +872,30 @@ void updateNativeFlags(dynarec_la64_t* dyn)
|
||||
}
|
||||
if (!found) dyn->insts[i].nat_flags_fusion = 0;
|
||||
}
|
||||
|
||||
int fusion = dyn->insts[i].comis_fusion;
|
||||
if (fusion < 0)
|
||||
continue;
|
||||
int found = 0;
|
||||
int j = i - 1;
|
||||
if (hasLinearPredecessor(dyn, i)) {
|
||||
while (j >= 0) {
|
||||
instruction_la64_t* inst = &dyn->insts[j];
|
||||
if (inst->comis_mark) {
|
||||
inst->comis_fusion = fusion;
|
||||
dyn->insts[i].x64.use_flags = 0;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (!hasLinearPredecessor(dyn, j) || inst->x64.jmp || inst->x64.barrier
|
||||
|| inst->x64.has_callret || inst->host_call
|
||||
|| inst->x64.set_flags || inst->x64.use_flags)
|
||||
break;
|
||||
--j;
|
||||
}
|
||||
}
|
||||
if (!found) dyn->insts[i].comis_fusion = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void get_free_scratch(dynarec_la64_t* dyn, int ninst, uint8_t* tmp1, uint8_t* tmp2, uint8_t* tmp3, uint8_t s1, uint8_t s2, uint8_t s3, uint8_t s4, uint8_t s5)
|
||||
@@ -883,7 +939,7 @@ void tryEarlyFpuBarrier(dynarec_la64_t* dyn, int last_fpu_used, int ninst)
|
||||
}
|
||||
// we will stop there, not trying to guess too much thing
|
||||
if ((usefull && (i + 1) != ninst)) {
|
||||
if (BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log) > 1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i + 1, ninst);
|
||||
if ((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log) > 1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i + 1, ninst);
|
||||
dyn->insts[i + 1].x64.barrier |= BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
@@ -893,7 +949,7 @@ void tryEarlyFpuBarrier(dynarec_la64_t* dyn, int last_fpu_used, int ninst)
|
||||
for (int pred = 0; pred < dyn->insts[i].pred_sz; ++pred) {
|
||||
if (dyn->insts[i].pred[pred] <= last_fpu_used) {
|
||||
if (usefull && ((i + 1) != ninst)) {
|
||||
if (BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log) > 1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i + 1, ninst);
|
||||
if ((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log) > 1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i + 1, ninst);
|
||||
dyn->insts[i + 1].x64.barrier |= BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
@@ -903,7 +959,7 @@ void tryEarlyFpuBarrier(dynarec_la64_t* dyn, int last_fpu_used, int ninst)
|
||||
usefull = 1;
|
||||
}
|
||||
if (usefull) {
|
||||
if (BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log) > 1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
if ((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log) > 1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
dyn->insts[last_fpu_used + 1].x64.barrier |= BARRIER_FLOAT;
|
||||
}
|
||||
}
|
||||
@@ -922,4 +978,166 @@ void propagateFpuBarrier(dynarec_la64_t* dyn)
|
||||
last_fpu_used = -1; // reset the last_fpu_used...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateUpperLiveness(dynarec_la64_t* dyn)
|
||||
{
|
||||
int n = dyn->size;
|
||||
if (n <= 0)
|
||||
return;
|
||||
|
||||
size_t uint16_size = (size_t)n * sizeof(uint16_t);
|
||||
size_t uint8_size = (size_t)n * sizeof(uint8_t);
|
||||
size_t int_size = (size_t)n * sizeof(int);
|
||||
void* buffer = malloc(int_size + 3 * uint16_size + uint8_size);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
int* work = (int*)buffer;
|
||||
uint16_t* in = (uint16_t*)((char*)work + int_size);
|
||||
uint16_t* out = (uint16_t*)((char*)in + uint16_size);
|
||||
uint16_t* pending_may = (uint16_t*)((char*)out + uint16_size);
|
||||
uint8_t* on_list = (uint8_t*)((char*)pending_may + uint16_size);
|
||||
|
||||
memset(in, 0, uint16_size);
|
||||
memset(out, 0, uint16_size);
|
||||
memset(on_list, 0, uint8_size);
|
||||
int sp = 0;
|
||||
for (int i = n - 1; i >= 0; --i) {
|
||||
if (dyn->insts[i].x64.alive) {
|
||||
work[sp++] = i;
|
||||
on_list[i] = 1;
|
||||
}
|
||||
}
|
||||
// backward analysis
|
||||
while (sp > 0) {
|
||||
int i = work[--sp];
|
||||
on_list[i] = 0;
|
||||
const instruction_la64_t* inst = &dyn->insts[i];
|
||||
if (!inst->x64.alive)
|
||||
continue;
|
||||
uint16_t o = 0;
|
||||
if (inst->x64.has_next && i + 1 < n && dyn->insts[i + 1].x64.alive)
|
||||
o |= in[i + 1];
|
||||
if (inst->x64.jmp) {
|
||||
if (inst->x64.jmp_insts >= 0 && inst->x64.jmp_insts < n)
|
||||
o |= in[inst->x64.jmp_insts];
|
||||
else
|
||||
o |= 0xFFFF;
|
||||
}
|
||||
int has_internal_jump = inst->x64.jmp && inst->x64.jmp_insts >= 0 && inst->x64.jmp_insts < n;
|
||||
if ((inst->x64.has_next && i == n - 1) || (!inst->x64.has_next && !has_internal_jump))
|
||||
o |= 0xFFFF;
|
||||
out[i] = o;
|
||||
uint16_t ii = inst->up32_read | (o & (uint16_t)~inst->up32_write64);
|
||||
if (ii != in[i]) {
|
||||
in[i] = ii;
|
||||
for (int p = 0; p < inst->pred_sz; ++p) {
|
||||
int j = inst->pred[p];
|
||||
if (!on_list[j]) {
|
||||
work[sp++] = j;
|
||||
on_list[j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
dyn->insts[i].up32_skip = dyn->insts[i].up32_write32 & (uint16_t)~out[i];
|
||||
|
||||
memset(pending_may, 0, uint16_size);
|
||||
memset(on_list, 0, uint8_size);
|
||||
sp = 0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (dyn->insts[i].x64.alive) {
|
||||
work[sp++] = i;
|
||||
on_list[i] = 1;
|
||||
}
|
||||
}
|
||||
// forward analysis
|
||||
|
||||
// NOTE: This is not perfect. At a merge, a register may be dirty on one path
|
||||
// but hold a real 64-bit value on another. adjust_arch cannot know which
|
||||
// path was taken, so it may clear the upper bits of a value it should
|
||||
// have kept. But only a signal handler reading raw registers can notice:
|
||||
// the program itself never reads those bits, otherwise the zero-up would
|
||||
// not have been skipped. We accept this rare case because it lets us
|
||||
// remove many more zero-ups from hot loops and also make the analysis cheaper.
|
||||
while (sp > 0) {
|
||||
int i = work[--sp];
|
||||
on_list[i] = 0;
|
||||
if (!dyn->insts[i].x64.alive)
|
||||
continue;
|
||||
|
||||
uint16_t may = 0;
|
||||
for (int p = 0; p < dyn->insts[i].pred_sz; ++p) {
|
||||
int j = dyn->insts[i].pred[p];
|
||||
may |= (pending_may[j] & (uint16_t)~dyn->insts[j].up32_write64) | dyn->insts[j].up32_skip;
|
||||
}
|
||||
|
||||
if (may != pending_may[i]) {
|
||||
pending_may[i] = may;
|
||||
if (dyn->insts[i].x64.has_next && i + 1 < n && dyn->insts[i + 1].x64.alive && !on_list[i + 1]) {
|
||||
work[sp++] = i + 1;
|
||||
on_list[i + 1] = 1;
|
||||
}
|
||||
if (dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts >= 0 && dyn->insts[i].x64.jmp_insts < n) {
|
||||
int j = dyn->insts[i].x64.jmp_insts;
|
||||
if (dyn->insts[j].x64.alive && !on_list[j]) {
|
||||
work[sp++] = j;
|
||||
on_list[j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
dyn->insts[i].up32_pending = pending_may[i];
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void updateRspMerge(dynarec_la64_t* dyn, int is32bits)
|
||||
{
|
||||
const int delta = is32bits ? 4 : 8;
|
||||
int pending = 0;
|
||||
int last_pushpop = -1;
|
||||
for (int i = 0; i < dyn->size; ++i) {
|
||||
instruction_la64_t* inst = &dyn->insts[i];
|
||||
inst->rsp_entry = 0;
|
||||
inst->rsp_flush = 0;
|
||||
inst->rsp_merge = 0;
|
||||
// Note: trace with rsp merge is allowed on purpose.
|
||||
int class = (inst->x64.alive && !BOX64ENV(dynarec_test)) ? inst->rsp_class : RSP_CLASS_BARRIER;
|
||||
if (pending && (class == RSP_CLASS_BARRIER || (i == 0) || (inst->pred_sz != 1) || (inst->pred[0] != i - 1))) {
|
||||
dyn->insts[last_pushpop].rsp_flush = pending;
|
||||
pending = 0;
|
||||
last_pushpop = -1;
|
||||
}
|
||||
switch (class) {
|
||||
case RSP_CLASS_PUSH:
|
||||
if (pending - delta < -2048) {
|
||||
dyn->insts[last_pushpop].rsp_flush = pending;
|
||||
pending = 0;
|
||||
}
|
||||
inst->rsp_entry = pending;
|
||||
inst->rsp_merge = 1;
|
||||
pending -= delta;
|
||||
last_pushpop = i;
|
||||
break;
|
||||
case RSP_CLASS_POP:
|
||||
if (pending + delta > 2047) {
|
||||
dyn->insts[last_pushpop].rsp_flush = pending;
|
||||
pending = 0;
|
||||
}
|
||||
inst->rsp_entry = pending;
|
||||
inst->rsp_merge = 1;
|
||||
pending += delta;
|
||||
last_pushpop = i;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pending) dyn->insts[last_pushpop].rsp_flush = pending;
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
#include "../dynarec_native_functions.h"
|
||||
|
||||
#define SCRATCH0 24
|
||||
#define SCRATCH0 24
|
||||
#define VZERO 30
|
||||
#define SCRATCH 31
|
||||
#define SCRATCH_LIMIT VZERO
|
||||
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynarec_la64_s dynarec_la64_t;
|
||||
@@ -67,4 +70,7 @@ int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st);
|
||||
void propagateFpuBarrier(dynarec_la64_t* dyn);
|
||||
void updateNativeFlags(dynarec_la64_t* dyn);
|
||||
void get_free_scratch(dynarec_la64_t* dyn, int ninst, uint8_t* tmp1, uint8_t* tmp2, uint8_t* tmp3, uint8_t s1, uint8_t s2, uint8_t s3, uint8_t s4, uint8_t s5);
|
||||
|
||||
void updateUpperLiveness(dynarec_la64_t* dyn);
|
||||
void updateRspMerge(dynarec_la64_t* dyn, int is32bits);
|
||||
#endif //__DYNAREC_LA64_FUNCTIONS_H__
|
||||
@@ -24,8 +24,9 @@
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
#define SCRATCH 31
|
||||
static_assert(offsetof(x64emu_t, mxcsr) == EMU_MXCSR, "EMU_MXCSR out of sync with x64emu_t");
|
||||
|
||||
/* setup r2 to address pointed by ED, also fixaddress is an optionnal delta in the range [-absmax, +absmax], with delta&mask==0 to be added to ed for LDR/STR */
|
||||
uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, uint8_t scratch, int64_t* fixaddress, rex_t rex, int* l, int i12, int delta)
|
||||
@@ -44,6 +45,14 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if (rex.is32bits && rex.is67)
|
||||
return geted16(dyn, addr, ninst, nextop, ed, hint, scratch, fixaddress, rex, i12);
|
||||
|
||||
if ((nextop & 7) == 4) {
|
||||
uint8_t sib = PK(0);
|
||||
if (((sib & 7) != 5) || ((nextop & 0xC0) != 0)) UP32_READ(TO_NAT((sib & 7) + (rex.b << 3)));
|
||||
if ((((sib >> 3) & 7) + (rex.x << 3)) != 4) UP32_READ(TO_NAT(((sib >> 3) & 7) + (rex.x << 3)));
|
||||
} else if (((nextop & 7) != 5) || ((nextop & 0xC0) != 0)) {
|
||||
UP32_READ(TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
}
|
||||
|
||||
uint8_t ret = x2;
|
||||
*fixaddress = 0;
|
||||
if (hint > 0) ret = hint;
|
||||
@@ -205,7 +214,14 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
ADDIy(ret, scratch, i64);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
} else {
|
||||
MOV64y(scratch, i64);
|
||||
int64_t lo12 = ((i64 & 0xFFF) ^ 0x800) - 0x800;
|
||||
int64_t hi20 = i64 - lo12;
|
||||
if (i12 && lo12 <= maxval && hi20 >= -0x80000000LL && hi20 <= 0x7FFFF000LL) {
|
||||
LU12I_W(scratch, hi20 >> 12);
|
||||
*fixaddress = lo12;
|
||||
} else {
|
||||
MOV64y(scratch, i64);
|
||||
}
|
||||
SCRATCH_USAGE(1);
|
||||
if ((nextop & 7) == 4) {
|
||||
if (sib_reg != 4) {
|
||||
@@ -375,7 +391,7 @@ static int indirect_lookup(dynarec_la64_t* dyn, int ninst, int is32bits, int s1,
|
||||
MAYUSE(dyn);
|
||||
if (!is32bits) {
|
||||
SRLI_D(s1, xRIP, 48);
|
||||
BNEZ_safe(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
|
||||
BNEZ_safe_(s1, (intptr_t)dyn->jmp_next - (intptr_t)dyn->block);
|
||||
if (dyn->need_reloc) {
|
||||
TABLE64C(s2, const_jmptbl48);
|
||||
} else {
|
||||
@@ -461,49 +477,87 @@ void ret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
|
||||
void iret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
|
||||
{
|
||||
int64_t j64;
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(j64);
|
||||
MESSAGE(LOG_DUMP, "IRet to next\n");
|
||||
SMEND();
|
||||
SET_DFNONE();
|
||||
// POP IP
|
||||
NOTEST(x2);
|
||||
if (is64bits) {
|
||||
POP1(xRIP);
|
||||
POP1(x1);
|
||||
POP1(x2);
|
||||
POP1(xFlags);
|
||||
POP1(x3);
|
||||
} else {
|
||||
POP1_32(xRIP);
|
||||
POP1_32(x1);
|
||||
POP1_32(x2);
|
||||
POP1_32(xFlags);
|
||||
POP1_32(x3);
|
||||
}
|
||||
|
||||
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
// segfault if CS is NULL
|
||||
BEQZ_MARK3(x2);
|
||||
// clean EFLAGS
|
||||
RESTORE_EFLAGS(x1);
|
||||
MOV32w(x1, 0x3E7FD7); // also mask RF
|
||||
AND(xFlags, xFlags, x1);
|
||||
ORI(xFlags, xFlags, 0x2);
|
||||
SPILL_EFLAGS();
|
||||
CHECK_DFNONE(0);
|
||||
MOV32w(x4, 0x3E7FD7); // also mask RF
|
||||
AND(x3, x3, x4);
|
||||
ORI(x3, x3, 0x2);
|
||||
FORCE_DFNONE();
|
||||
if (is32bits) {
|
||||
ANDI(x4, x2, 0xff);
|
||||
// check if return segment is 64bits, then restore rsp too
|
||||
MOV32w(x5, 0x23);
|
||||
BEQ_MARKSEG(x4, x5);
|
||||
}
|
||||
// POP RSP
|
||||
if (is64bits) {
|
||||
POP1(x3); // rsp
|
||||
POP1(x2); // ss
|
||||
POP1(x4); // rsp
|
||||
POP1(x5); // ss
|
||||
} else {
|
||||
POP1_32(x3); // rsp
|
||||
POP1_32(x2); // ss
|
||||
POP1_32(x4); // rsp
|
||||
POP1_32(x5); // ss
|
||||
}
|
||||
// check if SS is NULL
|
||||
BEQZ_MARK(x5);
|
||||
// POP SS
|
||||
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
ST_H(x5, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
// set new RSP
|
||||
MV(xRSP, x3);
|
||||
MV(xRSP, x4);
|
||||
MARKSEG;
|
||||
// x2 is CS, x1 is IP, x3 is eFlags
|
||||
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
MV(xRIP, x1);
|
||||
MV(xFlags, x3);
|
||||
SPILL_EFLAGS();
|
||||
// Ret....
|
||||
rex_t dummy = { 0 };
|
||||
dummy.is32bits = is32bits;
|
||||
dummy.w = is64bits;
|
||||
ANDI(x1, xFlags, 1 << F_TF);
|
||||
BNEZ_MARK2(x1);
|
||||
ret_to_next(dyn, ip, ninst, dummy);
|
||||
CLEARIP();
|
||||
MARK;
|
||||
if (is64bits)
|
||||
ADDI_D(xRSP, xRSP, 8 * 2);
|
||||
else
|
||||
ADDI_D(xRSP, xRSP, 4 * 2);
|
||||
MARK3;
|
||||
if (is64bits)
|
||||
ADDI_D(xRSP, xRSP, 8 * 3);
|
||||
else
|
||||
ADDI_D(xRSP, xRSP, 4 * 3);
|
||||
CALL_S(const_native_priv, -1, 0);
|
||||
MARK2;
|
||||
LD_WU(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
ORI(x4, x4, 1 << FLAGS_NO_TF);
|
||||
ST_W(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
}
|
||||
|
||||
void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret, int saveflags, int savereg, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
UP32_READALL();
|
||||
CHECK_DFNONE(1);
|
||||
if (savereg == 0)
|
||||
savereg = x87pc;
|
||||
@@ -535,7 +589,10 @@ void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret,
|
||||
if (arg5) MV(A5, arg5);
|
||||
if (arg6) MV(A6, arg6);
|
||||
MV(A0, xEmu);
|
||||
if (!dyn->x87round_active) MOVGR2FCSR(FCSR3, xZR);
|
||||
JIRL(xRA, reg, 0);
|
||||
LA64_RESTORE_VZERO();
|
||||
if (!dyn->x87round_active) sse_fcsr3_from_mxcsr(dyn, ninst, x2);
|
||||
if (ret >= 0) {
|
||||
MV(ret, A0);
|
||||
}
|
||||
@@ -573,11 +630,18 @@ void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret,
|
||||
void call_n(dynarec_la64_t* dyn, int ninst, void* fnc, int w)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
UP32_READALL();
|
||||
CHECK_DFNONE(1);
|
||||
fpu_pushcache(dyn, ninst, x3, 1);
|
||||
ST_D(xRSP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
ST_D(xRBP, xEmu, offsetof(x64emu_t, regs[_BP]));
|
||||
ST_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
|
||||
int nfp = (abs(w) & 15) - 1;
|
||||
if (nfp > 0)
|
||||
for (int i = 0; i < nfp; ++i)
|
||||
sse_get_reg(dyn, ninst, x3, i, w);
|
||||
if (w < 0) sse_get_reg_empty(dyn, ninst, x3, 0);
|
||||
// check if additional sextw needed
|
||||
int sextw_mask = ((w > 0 ? w : -w) >> 4) & 0b111111;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
@@ -586,14 +650,14 @@ void call_n(dynarec_la64_t* dyn, int ninst, void* fnc, int w)
|
||||
}
|
||||
}
|
||||
// native call
|
||||
if (dyn->need_reloc) {
|
||||
// fnc is indirect, to help with relocation (but PltResolver might be an issue here)
|
||||
TABLE64(x3, (uintptr_t)fnc);
|
||||
LD_D(x3, x3, 0);
|
||||
} else {
|
||||
TABLE64_(x3, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
|
||||
}
|
||||
TABLE64_(x3, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
|
||||
// Note that if need_reloc is active, the TABLE64 will trigger cancel block,
|
||||
// because native function might be very different on a next run: different function address, different brick, different everything basicaly
|
||||
// and we don't have a relocation mecanism here, it's too complex
|
||||
MOVGR2FCSR(FCSR3, xZR);
|
||||
JIRL(xRA, x3, 0x0);
|
||||
LA64_RESTORE_VZERO();
|
||||
sse_fcsr3_from_mxcsr(dyn, ninst, x2);
|
||||
// put return value in x64 regs
|
||||
if (w > 0) {
|
||||
MV(xRAX, A0);
|
||||
@@ -842,6 +906,7 @@ int x87_setround(dynarec_la64_t* dyn, int ninst, int s1, int s2)
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(s1);
|
||||
MAYUSE(s2);
|
||||
dyn->x87round_active = 1;
|
||||
LD_W(s1, xEmu, offsetof(x64emu_t, cw));
|
||||
BSTRPICK_W(s1, s1, 11, 10);
|
||||
// MMX/x87 Round mode: 0..3: Nearest, Down, Up, Chop
|
||||
@@ -856,25 +921,20 @@ int x87_setround(dynarec_la64_t* dyn, int ninst, int s1, int s2)
|
||||
return s2;
|
||||
}
|
||||
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_la64_t* dyn, int ninst, int s1, int s2)
|
||||
// Sync FCSR3 round mode from emu->mxcsr, destroying s1
|
||||
// MMX/x87 Round mode: 0..3: Nearest, Down, Up, Chop
|
||||
// LA64: 0..3: Nearest, TowardZero, TowardsPositive, TowardsNegative
|
||||
// 0->0, 1->3, 2->2, 3->1
|
||||
void sse_fcsr3_from_mxcsr(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(s1);
|
||||
MAYUSE(s2);
|
||||
LD_W(s1, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
BSTRPICK_W(s1, s1, 14, 13);
|
||||
// MMX/x87 Round mode: 0..3: Nearest, Down, Up, Chop
|
||||
// LA64: 0..3: Nearest, TowardZero, TowardsPositive, TowardsNegative
|
||||
// 0->0, 1->3, 2->2, 3->1
|
||||
SUB_W(s1, xZR, s1);
|
||||
ANDI(s1, s1, 3);
|
||||
// done
|
||||
SLLI_D(s1, s1, 8);
|
||||
MOVFCSR2GR(s2, FCSR3);
|
||||
MOVGR2FCSR(FCSR3, s1); // exchange RM with current
|
||||
return s2;
|
||||
MOVGR2FCSR(FCSR3, s1);
|
||||
}
|
||||
|
||||
int lsxcache_st_coherency(dynarec_la64_t* dyn, int ninst, int a, int b)
|
||||
@@ -1271,6 +1331,7 @@ void x87_restoreround(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(s1);
|
||||
dyn->x87round_active = 0;
|
||||
MOVGR2FCSR(FCSR3, s1);
|
||||
}
|
||||
|
||||
@@ -1415,11 +1476,11 @@ void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (dyn->lsx.avxcache[i].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
VST(VZERO, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
fpu_free_reg(dyn, dyn->lsx.avxcache[i].reg);
|
||||
dyn->lsx.avxcache[i].v = -1;
|
||||
} else if (dyn->lsx.lsxcache[dyn->lsx.ssecache[i].reg].t == LSX_CACHE_XMMW) {
|
||||
@@ -1508,8 +1569,10 @@ int avx_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a, int width)
|
||||
dyn->lsx.avxcache[a].dirty = width == LSX_AVX_WIDTH_128;
|
||||
return dyn->lsx.avxcache[a].reg;
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
|
||||
dyn->lsx.ssecache[a].v = -1;
|
||||
if (dyn->lsx.ssecache[a].v != -1) {
|
||||
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
|
||||
dyn->lsx.ssecache[a].v = -1;
|
||||
}
|
||||
dyn->lsx.avxcache[a].v = 0;
|
||||
dyn->lsx.avxcache[a].reg = fpu_get_reg_ymm(dyn, LSX_CACHE_YMMW, a);
|
||||
dyn->lsx.avxcache[a].write = 1;
|
||||
@@ -1538,11 +1601,11 @@ void avx_forget_reg(dynarec_la64_t* dyn, int ninst, int a)
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
if (dyn->lsx.avxcache[a].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
VST(VZERO, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->lsx.avxcache[a].reg);
|
||||
dyn->lsx.avxcache[a].v = -1;
|
||||
@@ -1557,12 +1620,12 @@ void avx_reflect_reg(dynarec_la64_t* dyn, int ninst, int a)
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
if (dyn->lsx.avxcache[a].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[a].reg, SCRATCH, 0b00000010);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[a].reg, VZERO, 0b00000010);
|
||||
VST(VZERO, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
dyn->lsx.avxcache[a].dirty = 0;
|
||||
}
|
||||
}
|
||||
@@ -1578,8 +1641,7 @@ void avx_cleancache(dynarec_la64_t* dyn, int ninst)
|
||||
MESSAGE(LOG_DUMP, "\tClean AVX Cache ------\n");
|
||||
++old;
|
||||
}
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, 0b00000010);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[i].reg, VZERO, 0b00000010);
|
||||
dyn->lsx.avxcache[i].dirty = 0;
|
||||
}
|
||||
}
|
||||
@@ -1602,11 +1664,11 @@ static void avx_purgecache(dynarec_la64_t* dyn, int ninst, int next, int s1)
|
||||
}
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (dyn->lsx.avxcache[i].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
VST(VZERO, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\tAVX Cache for YMM%d is not write, no need to store back %d\n", i, dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t);
|
||||
}
|
||||
@@ -1685,6 +1747,8 @@ void fpu_popcache(dynarec_la64_t* dyn, int ninst, int s1, int not07)
|
||||
if (!dyn->lsx.avxcache[i].dirty) {
|
||||
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, XVPERMI_IMM_4_0(0, 2));
|
||||
} else {
|
||||
XVPERMI_Q(dyn->lsx.avxcache[i].reg, VZERO, XVPERMI_IMM_4_0(0, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1747,7 +1811,7 @@ void fpu_reset_cache(dynarec_la64_t* dyn, int ninst, int reset_n)
|
||||
dyn->lsx = dyn->insts[reset_n].lsx;
|
||||
#endif
|
||||
#if STEP == 0
|
||||
if (dyn->need_dump && dyn->lsx.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->lsx.x87stack, ninst, reset_n);
|
||||
if (dyn->need_dump && dyn->need_dump != 3 && dyn->lsx.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->lsx.x87stack, ninst, reset_n);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP > 2)
|
||||
if (dyn->need_dump && 0) // disable for now
|
||||
@@ -2205,7 +2269,7 @@ static void flagsCacheTransform(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if (jmp < 0)
|
||||
return;
|
||||
if (dyn->insts[jmp].f_exit == dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
if (dyn->insts[ninst].f_exit == dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go_fetch = 0;
|
||||
@@ -2241,6 +2305,7 @@ static void flagsCacheTransform(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
}
|
||||
TABLE64C(s1, const_updateflags_la64);
|
||||
JIRL(xRA, s1, 0);
|
||||
LA64_RESTORE_VZERO();
|
||||
MARKF2;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Flags fetch\n");
|
||||
@@ -2295,6 +2360,7 @@ void checkCRC(dynarec_la64_t* dyn, int ninst)
|
||||
LD_D(x1, x6, offsetof(dynablock_t, x64_addr));
|
||||
LD_WU(x2, x6, offsetof(dynablock_t, x64_size));
|
||||
JIRL(xRA, x3, 0x0);
|
||||
LA64_RESTORE_VZERO();
|
||||
// done, result in x1, load the stored hash (sign extended, as the crc will also be sign extended)
|
||||
LD_W(x2, x6, offsetof(dynablock_t, hash));
|
||||
// compare computed crc with stored one, jump to continue is equal
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
#include "la64_emitter.h"
|
||||
#include "../emu/x64primop.h"
|
||||
#include "dynarec_la64_consts.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
#define LA64_RESTORE_VZERO() \
|
||||
do { \
|
||||
if (cpuext.lasx) \
|
||||
XVXOR_V(VZERO, VZERO, VZERO); \
|
||||
else \
|
||||
VXOR_V(VZERO, VZERO, VZERO); \
|
||||
} while (0)
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F8S *(int8_t*)(addr++)
|
||||
@@ -39,10 +48,223 @@
|
||||
// LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
|
||||
#if STEP == 0
|
||||
#define UP32_READ(r) \
|
||||
do { \
|
||||
if (IS_GPR(r)) dyn->insts[ninst].up32_read |= (uint16_t)(1 << (TO_X64(r))); \
|
||||
} while (0)
|
||||
#define UP32_WRITE64(r) \
|
||||
do { \
|
||||
if (IS_GPR(r)) dyn->insts[ninst].up32_write64 |= (uint16_t)(1 << (TO_X64(r))); \
|
||||
} while (0)
|
||||
#define UP32_WRITE32(r) \
|
||||
do { \
|
||||
if (IS_GPR(r)) { \
|
||||
UP32_WRITE64(r); \
|
||||
dyn->insts[ninst].up32_write32 |= (uint16_t)(1 << (TO_X64(r))); \
|
||||
} \
|
||||
} while (0)
|
||||
#define UP32_READALL() \
|
||||
do { \
|
||||
dyn->insts[ninst].up32_read |= (uint16_t)0xFFFF; \
|
||||
} while (0)
|
||||
#else
|
||||
#define UP32_READ(r) ((void)(r))
|
||||
#define UP32_WRITE64(r) ((void)(r))
|
||||
#define UP32_WRITE32(r) ((void)(r))
|
||||
#define UP32_READALL() ((void)0)
|
||||
#endif
|
||||
|
||||
#define COMIS_FCC fcc7
|
||||
|
||||
static inline int comis_fuse_cond(int condition)
|
||||
{
|
||||
switch (condition) {
|
||||
case X64_JMP_JC:
|
||||
case X64_JMP_JNC:
|
||||
case X64_JMP_JZ:
|
||||
case X64_JMP_JNZ:
|
||||
case X64_JMP_JBE:
|
||||
case X64_JMP_JNBE:
|
||||
case X64_JMP_JP:
|
||||
case X64_JMP_JNP: return condition;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int comis_fuse_fcmp(int condition)
|
||||
{
|
||||
switch (condition) {
|
||||
case X64_JMP_JC:
|
||||
case X64_JMP_JNC: return cULT;
|
||||
case X64_JMP_JZ:
|
||||
case X64_JMP_JNZ: return cUEQ;
|
||||
case X64_JMP_JBE:
|
||||
case X64_JMP_JNBE: return cULE;
|
||||
default: return cUN;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int comis_fuse_inverted(int condition)
|
||||
{
|
||||
switch (condition) {
|
||||
case X64_JMP_JNC:
|
||||
case X64_JMP_JNZ:
|
||||
case X64_JMP_JNBE:
|
||||
case X64_JMP_JNP: return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if STEP == 0
|
||||
#define COMIS_MARK() \
|
||||
do { \
|
||||
dyn->insts[ninst].comis_mark = BOX64ENV(dynarec_nativeflags); \
|
||||
} while (0)
|
||||
|
||||
#define COMIS_JCC(I) \
|
||||
do { \
|
||||
if (BOX64ENV(dynarec_nativeflags)) \
|
||||
dyn->insts[ninst].comis_fusion = comis_fuse_cond(I); \
|
||||
} while (0)
|
||||
|
||||
#define COMIS_FUSED() 0
|
||||
#else
|
||||
#define COMIS_MARK() ((void)0)
|
||||
#define COMIS_JCC(I) ((void)(I))
|
||||
#define COMIS_FUSED() (dyn->insts[ninst].comis_fusion >= 0)
|
||||
#endif
|
||||
|
||||
#define COMIS_BRANCH_NOT_TAKEN(offset, jmp) \
|
||||
do { \
|
||||
if (comis_fuse_inverted(dyn->insts[ninst].comis_fusion)) \
|
||||
BCNEZ_safe(COMIS_FCC, offset, jmp); \
|
||||
else \
|
||||
BCEQZ_safe(COMIS_FCC, offset, jmp); \
|
||||
} while (0)
|
||||
#define COMIS_BRANCH_TAKEN(offset, jmp) \
|
||||
do { \
|
||||
if (comis_fuse_inverted(dyn->insts[ninst].comis_fusion)) \
|
||||
BCEQZ_safe(COMIS_FCC, offset, jmp); \
|
||||
else \
|
||||
BCNEZ_safe(COMIS_FCC, offset, jmp); \
|
||||
} while (0)
|
||||
|
||||
#define COMIS_SPILL_S() \
|
||||
IFX (X_ALL) { SPILL_EFLAGS(); }
|
||||
#define COMIS_SPILL_D() SPILL_EFLAGS()
|
||||
#define EMIT_COMIS_FLAGS(type, lhs, rhs, tmp) \
|
||||
do { \
|
||||
COMIS_MARK(); \
|
||||
if (COMIS_FUSED()) \
|
||||
FCMP_##type(COMIS_FCC, lhs, rhs, comis_fuse_fcmp(dyn->insts[ninst].comis_fusion)); \
|
||||
if (!COMIS_FUSED() || dyn->insts[ninst].x64.gen_flags) { \
|
||||
CLEAR_FLAGS(tmp); \
|
||||
IFX (X_ZF | X_PF | X_CF) { \
|
||||
FCMP_##type(fcc0, lhs, rhs, cUN); \
|
||||
BCEQZ_MARK(fcc0); \
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF)); \
|
||||
B_MARK3_nocond; \
|
||||
} \
|
||||
MARK; \
|
||||
IFX (X_CF) { \
|
||||
FCMP_##type(fcc1, lhs, rhs, cLT); \
|
||||
BCEQZ_MARK2(fcc1); \
|
||||
ORI(xFlags, xFlags, 1 << F_CF); \
|
||||
B_MARK3_nocond; \
|
||||
} \
|
||||
MARK2; \
|
||||
IFX (X_ZF) { \
|
||||
FCMP_##type(fcc2, lhs, rhs, cEQ); \
|
||||
BCEQZ_MARK3(fcc2); \
|
||||
ORI(xFlags, xFlags, 1 << F_ZF); \
|
||||
} \
|
||||
MARK3; \
|
||||
COMIS_SPILL_##type(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MARKREGd(r) \
|
||||
do { \
|
||||
if (rex.w) \
|
||||
UP32_WRITE64(r); \
|
||||
else \
|
||||
UP32_WRITE32(r); \
|
||||
} while (0)
|
||||
|
||||
#define MARKREGdz(r) \
|
||||
do { \
|
||||
if (!rex.is32bits) \
|
||||
UP32_WRITE64(r); \
|
||||
else \
|
||||
UP32_WRITE32(r); \
|
||||
} while (0)
|
||||
|
||||
#define MARKREGs(r) \
|
||||
do { \
|
||||
if (rex.w) UP32_READ(r); \
|
||||
} while (0)
|
||||
|
||||
#define MARKREGsz(r) \
|
||||
do { \
|
||||
if (!rex.is32bits) UP32_READ(r); \
|
||||
} while (0)
|
||||
|
||||
#define MARKREGsd(r) \
|
||||
do { \
|
||||
MARKREGs(r); \
|
||||
MARKREGd(r); \
|
||||
} while (0)
|
||||
|
||||
#define MARKREGsdz(r) \
|
||||
do { \
|
||||
MARKREGsz(r); \
|
||||
MARKREGdz(r); \
|
||||
} while (0)
|
||||
|
||||
#define NEED_ZEROUP32(r) \
|
||||
(!(IS_GPR(r)) || !((dyn->insts[ninst].up32_skip >> (TO_X64(r))) & 1))
|
||||
#define NEED_ZEROUP(r) (!rex.w && NEED_ZEROUP32(r))
|
||||
|
||||
#ifndef IF_UNALIGNED
|
||||
#define IF_UNALIGNED(A) if(dyn->insts[ninst].unaligned)
|
||||
#endif
|
||||
#ifndef IF_ALIGNED
|
||||
#define IF_ALIGNED(A) if(!dyn->insts[ninst].unaligned)
|
||||
#endif
|
||||
|
||||
// GETGD get x64 register in gd
|
||||
#define GETGD gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
// GETVD get x64 register in vd
|
||||
#define GETVD vd = TO_NAT(vex.v)
|
||||
#define GETGDw \
|
||||
do { \
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); \
|
||||
} while (0)
|
||||
#define GETGDs \
|
||||
do { \
|
||||
GETGDw; \
|
||||
MARKREGs(gd); \
|
||||
} while (0)
|
||||
#define GETGD GETGDs
|
||||
#define GETGDd \
|
||||
do { \
|
||||
GETGDw; \
|
||||
MARKREGd(gd); \
|
||||
} while (0)
|
||||
#define GETGDsd \
|
||||
do { \
|
||||
GETGDs; \
|
||||
MARKREGd(gd); \
|
||||
} while (0)
|
||||
#define GETVDs \
|
||||
do { \
|
||||
vd = TO_NAT(vex.v); \
|
||||
if (rex.w) MARKREGs(vd); \
|
||||
} while(0)
|
||||
|
||||
#define GETVDsd \
|
||||
do { \
|
||||
vd = TO_NAT(vex.v); \
|
||||
if (rex.w) MARKREGsd(vd); \
|
||||
} while(0)
|
||||
|
||||
// GETGW extract x64 register in gd, that is i
|
||||
#define GETGW(i) \
|
||||
@@ -54,6 +276,7 @@
|
||||
#define GETED(D) \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -62,9 +285,16 @@
|
||||
ed = x1; \
|
||||
}
|
||||
|
||||
#define GETEDsd(D) \
|
||||
do { \
|
||||
GETED(D); \
|
||||
if (MODREG) MARKREGd(ed); \
|
||||
} while (0)
|
||||
|
||||
#define GETEDz(D) \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -77,6 +307,7 @@
|
||||
#define GETEDH(hint, ret, D) \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -87,6 +318,7 @@
|
||||
#define GETEDW(hint, ret, D) \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
MV(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
@@ -129,6 +361,7 @@
|
||||
#define GETSED(D) \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
MARKREGs(ed); \
|
||||
wback = 0; \
|
||||
if (!rex.w) { \
|
||||
ADD_W(x1, ed, xZR); \
|
||||
@@ -802,6 +1035,10 @@
|
||||
#define CBNZ_MARKSEG(reg) \
|
||||
j64 = GETMARKSEG - (dyn->native_size); \
|
||||
BNEZ(reg, j64);
|
||||
// Branch to MARKSEG if reg1==reg2 (use j64)
|
||||
#define BEQ_MARKSEG(reg1, reg2) \
|
||||
j64 = GETMARKSEG - (dyn->native_size); \
|
||||
BEQ(reg1, reg2, j64);
|
||||
|
||||
#define IFX(A) if ((dyn->insts[ninst].x64.gen_flags & (A)))
|
||||
#define IFXA(A, B) if ((dyn->insts[ninst].x64.gen_flags & (A)) && (B))
|
||||
@@ -931,7 +1168,7 @@
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->lsx.x87stack == 8) || (dyn->lsx.pushed == 8)) { \
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->lsx.x87stack, dyn->lsx.pushed, ninst); \
|
||||
if (dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->lsx.x87stack, dyn->lsx.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -939,7 +1176,7 @@
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->lsx.x87stack == 8) || (dyn->lsx.pushed == 8)) { \
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->lsx.x87stack, dyn->lsx.pushed, ninst); \
|
||||
if (dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->lsx.x87stack, dyn->lsx.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -947,7 +1184,7 @@
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->lsx.x87stack == -8) || (dyn->lsx.poped == 8)) { \
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->lsx.x87stack, dyn->lsx.poped, ninst); \
|
||||
if (dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->lsx.x87stack, dyn->lsx.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -955,12 +1192,13 @@
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if ((A) != X_PEND \
|
||||
&& (dyn->f == status_unk)) { \
|
||||
TABLE64C(x6, const_updateflags_la64); \
|
||||
JIRL(xRA, x6, 0); \
|
||||
dyn->f = status_none; \
|
||||
#define READFLAGS(A) \
|
||||
if ((A) != X_PEND \
|
||||
&& (dyn->f == status_unk)) { \
|
||||
TABLE64C(x6, const_updateflags_la64); \
|
||||
JIRL(xRA, x6, 0); \
|
||||
LA64_RESTORE_VZERO(); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -976,18 +1214,36 @@
|
||||
READFLAGS(A)
|
||||
#endif
|
||||
|
||||
#define NAT_FLAGS_OPS(op1, op2, s1, s2) \
|
||||
do { \
|
||||
dyn->insts[dyn->insts[ninst].nat_next_inst].nat_flags_op1 = op1; \
|
||||
dyn->insts[dyn->insts[ninst].nat_next_inst].nat_flags_op2 = op2; \
|
||||
if (dyn->insts[ninst + 1].no_scratch_usage && IS_GPR(op1)) { \
|
||||
MV(s1, op1); \
|
||||
dyn->insts[dyn->insts[ninst].nat_next_inst].nat_flags_op1 = s1; \
|
||||
} \
|
||||
if (dyn->insts[ninst + 1].no_scratch_usage && IS_GPR(op2)) { \
|
||||
MV(s2, op2); \
|
||||
dyn->insts[dyn->insts[ninst].nat_next_inst].nat_flags_op2 = s2; \
|
||||
} \
|
||||
#define NAT_FLAGS_OPS(op1, op2, s1, s2) \
|
||||
do { \
|
||||
int nat_op1 = op1; \
|
||||
int nat_op2 = op2; \
|
||||
int nat_next = dyn->insts[ninst].nat_next_inst; \
|
||||
int nat_last = nat_next; \
|
||||
while (nat_last && dyn->insts[nat_last].nat_next_inst) \
|
||||
nat_last = dyn->insts[nat_last].nat_next_inst; \
|
||||
int nat_copy = 0; \
|
||||
for (int nat_i = ninst + 1; nat_i < nat_last; ++nat_i) \
|
||||
if (dyn->insts[nat_i].no_scratch_usage) \
|
||||
nat_copy = 1; \
|
||||
if (nat_copy && IS_GPR(nat_op1)) { \
|
||||
if (dyn->insts[ninst].up32_read & (1 << TO_X64(nat_op1))) \
|
||||
MV(s1, nat_op1); \
|
||||
else \
|
||||
ZEROUP2(s1, nat_op1); \
|
||||
nat_op1 = s1; \
|
||||
} \
|
||||
if (nat_copy && IS_GPR(nat_op2)) { \
|
||||
if (dyn->insts[ninst].up32_read & (1 << TO_X64(nat_op2))) \
|
||||
MV(s2, nat_op2); \
|
||||
else \
|
||||
ZEROUP2(s2, nat_op2); \
|
||||
nat_op2 = s2; \
|
||||
} \
|
||||
for (int nat_i = nat_next; nat_i; nat_i = dyn->insts[nat_i].nat_next_inst) { \
|
||||
dyn->insts[nat_i].nat_flags_op1 = nat_op1; \
|
||||
dyn->insts[nat_i].nat_flags_op2 = nat_op2; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define NAT_FLAGS_ENABLE_CARRY() dyn->insts[ninst].nat_flags_carry = 1
|
||||
@@ -999,6 +1255,7 @@
|
||||
&& ((dyn->f == status_unk) || (dyn->f == status_set))) { \
|
||||
TABLE64C(x6, const_updateflags_la64); \
|
||||
JIRL(xRA, x6, 0); \
|
||||
LA64_RESTORE_VZERO(); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
|
||||
@@ -1313,7 +1570,7 @@
|
||||
#define x87_unreflectcount STEPNAME(x87_unreflectcount)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define sse_fcsr3_from_mxcsr STEPNAME(sse_fcsr3_from_mxcsr)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_purge07cache STEPNAME(sse_purge07cache)
|
||||
@@ -1517,8 +1774,7 @@ void fpu_reflectcache(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_unreflectcache(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_pushcache(dynarec_la64_t* dyn, int ninst, int s1, int not07);
|
||||
void fpu_popcache(dynarec_la64_t* dyn, int ninst, int s1, int not07);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_la64_t* dyn, int ninst, int s1, int s2);
|
||||
void sse_fcsr3_from_mxcsr(dynarec_la64_t* dyn, int ninst, int s1);
|
||||
|
||||
// SSE/SSE2 helpers
|
||||
// purge the XMM0..XMM7 cache (before function call)
|
||||
@@ -1721,13 +1977,13 @@ uintptr_t dynarec64_DF(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break
|
||||
|
||||
// Dummy macros
|
||||
#define B__safe(a, b, c) XOR(xZR, xZR, xZR)
|
||||
#define B_(a, b, c) XOR(xZR, xZR, xZR)
|
||||
#define S_(a, b, c) XOR(xZR, xZR, xZR)
|
||||
#define MV_(a, b, c, d) XOR(xZR, xZR, xZR)
|
||||
#define B__safe(a, b, c, d) XOR(xZR, xZR, xZR)
|
||||
#define B_(a, b, c) XOR(xZR, xZR, xZR)
|
||||
#define S_(a, b, c) XOR(xZR, xZR, xZR)
|
||||
#define MV_(a, b, c, d) XOR(xZR, xZR, xZR)
|
||||
|
||||
#define NATIVEJUMP_safe(COND, val) \
|
||||
B##COND##_safe(dyn->insts[ninst].nat_flags_op1, dyn->insts[ninst].nat_flags_op2, val);
|
||||
#define NATIVEJUMP_safe(COND, val, jmp) \
|
||||
B##COND##_safe(dyn->insts[ninst].nat_flags_op1, dyn->insts[ninst].nat_flags_op2, val, jmp);
|
||||
|
||||
#define NATIVEJUMP(COND, val) \
|
||||
B##COND(dyn->insts[ninst].nat_flags_op1, dyn->insts[ninst].nat_flags_op2, val);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define READFLAGS_FUSION(A, s1, s2, s3, s4, s5) \
|
||||
if (BOX64ENV(dynarec_nativeflags) && ninst > 0) { \
|
||||
int prev = ninst - 1; \
|
||||
while (prev && dyn->insts[prev].no_scratch_usage) \
|
||||
while (prev && (dyn->insts[prev].no_scratch_usage || dyn->insts[prev].nat_flags_fusion)) \
|
||||
prev -= 1; \
|
||||
if (!dyn->insts[prev].nat_flags_nofusion) { \
|
||||
if ((A) == (X_ZF)) \
|
||||
@@ -33,31 +33,38 @@
|
||||
} \
|
||||
READFLAGS(A);
|
||||
|
||||
#define SETFLAGS(A, B, FUSION) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B) & ~SF_DF; \
|
||||
dyn->f = ((B) & SF_SET) ? (((B) == SF_SET_NODF) ? status_none : status_none_pending) : (((B) & SF_SET_PENDING) ? status_set : status_none_pending); \
|
||||
if (!BOX64ENV(dynarec_df)) { \
|
||||
dyn->f = status_none; \
|
||||
if ((A) == SF_PENDING) { \
|
||||
printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); \
|
||||
SET_BOX64ENV(dynarec_df, 1); \
|
||||
} \
|
||||
} \
|
||||
dyn->insts[ninst].nat_flags_nofusion = (FUSION); \
|
||||
/* Do not update dyn->f for SF_SET_PENDING: it will use either DF_NONE or DF_SET, similar to SF_SET_NODF. */
|
||||
#define SETFLAGS(A, B, FUSION) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B) & ~SF_DF; \
|
||||
if (((B) & SF_SET_PENDING) != SF_SET_PENDING) { \
|
||||
dyn->f = ((B) & SF_SET) ? (((B) == SF_SET_NODF) ? dyn->f : status_none_pending) \
|
||||
: ((dyn->f == status_none) ? status_none : status_none_pending); \
|
||||
} \
|
||||
if (!BOX64ENV(dynarec_df)) { \
|
||||
dyn->f = status_none; \
|
||||
if ((A) == SF_PENDING) { \
|
||||
printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); \
|
||||
SET_BOX64ENV(dynarec_df, 1); \
|
||||
} \
|
||||
} \
|
||||
dyn->insts[ninst].nat_flags_nofusion = (FUSION); \
|
||||
} while (0)
|
||||
|
||||
#define EMIT(A) dyn->native_size += 4
|
||||
#define JUMP(A, C) \
|
||||
add_jump(dyn, ninst); \
|
||||
add_next(dyn, (uintptr_t)A); \
|
||||
SMEND(); \
|
||||
dyn->insts[ninst].x64.jmp = A; \
|
||||
dyn->insts[ninst].x64.jmp_cond = C; \
|
||||
dyn->insts[ninst].x64.jmp_insts = 0
|
||||
#define JUMP(A, C) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.jmp = (uintptr_t)(A); \
|
||||
add_jump(dyn, ninst); \
|
||||
add_next(dyn, dyn->insts[ninst].x64.jmp); \
|
||||
SMEND(); \
|
||||
dyn->insts[ninst].x64.jmp_cond = C; \
|
||||
dyn->insts[ninst].x64.jmp_insts = 0; \
|
||||
} while (0)
|
||||
#define BARRIER(A) \
|
||||
if (A != BARRIER_MAYBE) { \
|
||||
UP32_READALL(); \
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); \
|
||||
dyn->insts[ninst].x64.barrier = A; \
|
||||
} else \
|
||||
@@ -69,6 +76,14 @@
|
||||
dyn->lsx.combined1 = dyn->lsx.combined2 = 0; \
|
||||
dyn->lsx.swapped = 0; \
|
||||
dyn->lsx.barrier = 0; \
|
||||
dyn->insts[ninst].up32_read = 0; \
|
||||
dyn->insts[ninst].up32_write64 = 0; \
|
||||
dyn->insts[ninst].up32_write32 = 0; \
|
||||
dyn->insts[ninst].up32_skip = 0; \
|
||||
dyn->insts[ninst].up32_pending = 0; \
|
||||
dyn->insts[ninst].comis_fusion = -1; \
|
||||
dyn->insts[ninst].comis_mark = 0; \
|
||||
dyn->insts[ninst].host_call = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if (ninst) { dyn->insts[ninst - 1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst - 1].x64.addr; } \
|
||||
AREFLAGSNEEDED()
|
||||
@@ -101,3 +116,7 @@
|
||||
do { \
|
||||
dyn->insts[ninst].no_scratch_usage = !usage; \
|
||||
} while (0)
|
||||
|
||||
// mark opcode as "unaligned" possible only if the current address is marked as already unaligned
|
||||
#define IF_UNALIGNED(A) if((dyn->insts[ninst].unaligned = is_addr_unaligned(A)))
|
||||
#define IF_ALIGNED(A) if(!(dyn->insts[ninst].unaligned = is_addr_unaligned(A)))
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#define MESSAGE(A, ...) \
|
||||
do { \
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, __VA_ARGS__); \
|
||||
if (dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define NEW_INST \
|
||||
if (ninst) { \
|
||||
|
||||
@@ -88,6 +88,10 @@ typedef enum flagcache_s {
|
||||
typedef struct callret_s callret_t;
|
||||
typedef struct sep_s sep_t;
|
||||
|
||||
#define RSP_CLASS_BARRIER 0
|
||||
#define RSP_CLASS_PUSH 1
|
||||
#define RSP_CLASS_POP 2
|
||||
|
||||
typedef struct instruction_la64_s {
|
||||
instruction_x64_t x64;
|
||||
uintptr_t address; // (start) address of the arm emitted instruction
|
||||
@@ -119,15 +123,29 @@ typedef struct instruction_la64_s {
|
||||
uint8_t nat_flags_sign:1;
|
||||
uint8_t nat_flags_sf:1;
|
||||
uint8_t nat_flags_needsign:1;
|
||||
uint8_t nat_flags_needunsigned:1;
|
||||
uint8_t no_scratch_usage : 1; // this opcode does not use scratch register
|
||||
uint8_t nat_flags_op1;
|
||||
uint8_t nat_flags_op2;
|
||||
uint8_t x87precision:1; // this opcode can handle x87pc
|
||||
uint8_t unaligned:1; // this opcode can be re-generated for unaligned special case
|
||||
unsigned mmx_used:1; // no fine tracking, just a global "any reg used"
|
||||
unsigned x87_used:1; // no fine tracking, just a global "any reg used"
|
||||
unsigned fpu_used:1; // any xmm/ymm/x87/mmx reg used
|
||||
unsigned fpupurge:1; // this opcode will purge all fpu regs
|
||||
uint16_t nat_next_inst;
|
||||
uint16_t nat_next_inst; // for producer: first consumer; for consumer: next consumer
|
||||
uint16_t up32_read; // bitmask of GPRs whose upper 32 bits are read by this instruction
|
||||
uint16_t up32_write64; // bitmask of GPRs written as 64-bit by this instruction (upper 32 become defined)
|
||||
uint16_t up32_write32; // bitmask of GPRs written as 32-bit by this instruction
|
||||
uint16_t up32_skip; // bitmask of GPRs where the implicit zero-up after a 32-bit write can be skipped
|
||||
uint16_t up32_pending; // bitmask of GPRs whose upper 32 bits are stale at entry to this instruction
|
||||
int8_t comis_fusion;
|
||||
uint8_t comis_mark:1;
|
||||
uint8_t host_call:1;
|
||||
int16_t rsp_entry; // pending rsp offset at entry
|
||||
int16_t rsp_flush; // rsp offset to emit right after this push/pop
|
||||
uint8_t rsp_merge : 1; // this push/pop is emitted with merged rsp offset
|
||||
uint8_t rsp_class : 2; // RSP_* of this opcode (marked by the opcode handler)
|
||||
flagcache_t f_exit; // flags status at end of instruction
|
||||
lsxcache_t lsx; // lsxcache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
@@ -181,6 +199,7 @@ typedef struct dynarec_la64_s {
|
||||
uint8_t is_file_mapped:1;
|
||||
void* gdbjit_block;
|
||||
uint32_t need_x87check; // x87 low precision check
|
||||
int x87round_active; // we are in the middle of x87_setround and x87_restoreround
|
||||
uint32_t need_dump; // need to dump the block
|
||||
int need_reloc; // does the dynablock need relocations
|
||||
int reloc_size;
|
||||
@@ -229,6 +248,8 @@ void CreateJmpNext(void* addr, void* next);
|
||||
} while(0);
|
||||
|
||||
#define GO_TRACE(A, B, s0) \
|
||||
if(cpuext.lbt) \
|
||||
RESTORE_EFLAGS(s0); \
|
||||
GETIP(addr, s0); \
|
||||
MV(x1, xRIP); \
|
||||
STORE_XEMU_CALL(); \
|
||||
|
||||
+265
-14
@@ -152,6 +152,8 @@
|
||||
|
||||
// DBAR hint
|
||||
#define DBAR(hint) EMIT(type_hint(0b00111000011100100, hint))
|
||||
// IBAR hint
|
||||
#define IBAR(hint) EMIT(type_hint(0b00111000011100101, hint))
|
||||
|
||||
#define DBAR_RW_RW() DBAR(0b10000)
|
||||
#define DBAR_R_RW() DBAR(0b10100)
|
||||
@@ -187,8 +189,8 @@
|
||||
|
||||
#define BREAK() EMIT(0b1010100)
|
||||
|
||||
// there is no UDF instruction, use BREAK instead is an acceptable offer
|
||||
#define UDF() BREAK()
|
||||
// there is no UDF instruction, use AMSWAP_W($r0, $r1, $r0) like gcc
|
||||
#define UDF() AMSWAP_W(0, 1, 0)
|
||||
|
||||
// tmp = SLL(GR[rj][31:0], GR[rk][4:0])
|
||||
// GR[rd] = SignExtend(tmp[31:0], GRLEN)
|
||||
@@ -564,7 +566,10 @@
|
||||
#define B(imm28) EMIT(type_I26(0b010100, ((imm28) >> 2)))
|
||||
#define B__(reg1, reg2, imm28) B(imm28)
|
||||
|
||||
#define BEQ_safe(rj, rd, imm) \
|
||||
#define NEAR_JUMP_INSTS 100
|
||||
#define NEAR_JUMPZ_INSTS 300
|
||||
|
||||
#define BEQ_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BEQ(rj, rd, imm); \
|
||||
@@ -575,7 +580,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BNE_safe(rj, rd, imm) \
|
||||
#define BEQ_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BEQ_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BEQ(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BEQ(rj, rd, imm); \
|
||||
else \
|
||||
BEQ_safe_(rd, rj, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BNE_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BNE(rj, rd, imm); \
|
||||
@@ -586,7 +604,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BLT_safe(rj, rd, imm) \
|
||||
#define BNE_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BNE_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BNE(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BNE(rj, rd, imm); \
|
||||
else \
|
||||
BNE_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BLT_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BLT(rj, rd, imm); \
|
||||
@@ -597,7 +628,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BGE_safe(rj, rd, imm) \
|
||||
#define BLT_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BLT_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BLT(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BLT(rj, rd, imm); \
|
||||
else \
|
||||
BLT_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BGE_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BGE(rj, rd, imm); \
|
||||
@@ -608,7 +652,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BLTU_safe(rj, rd, imm) \
|
||||
#define BGE_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BGE_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BGE(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BGE(rj, rd, imm); \
|
||||
else \
|
||||
BGE_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BLTU_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BLTU(rj, rd, imm); \
|
||||
@@ -619,7 +676,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BGEU_safe(rj, rd, imm) \
|
||||
#define BLTU_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BLTU_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BLTU(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BLTU(rj, rd, imm); \
|
||||
else \
|
||||
BLTU_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BGEU_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BGEU(rj, rd, imm); \
|
||||
@@ -630,7 +700,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BGT_safe(rj, rd, imm) \
|
||||
#define BGEU_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BGEU_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BGEU(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BGEU(rj, rd, imm); \
|
||||
else \
|
||||
BGEU_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BGT_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BGT(rj, rd, imm); \
|
||||
@@ -641,7 +724,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BLE_safe(rj, rd, imm) \
|
||||
#define BGT_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BGT_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BGT(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BGT(rj, rd, imm); \
|
||||
else \
|
||||
BGT_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BLE_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BLE(rj, rd, imm); \
|
||||
@@ -652,7 +748,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BGTU_safe(rj, rd, imm) \
|
||||
#define BLE_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BLE_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BLE(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BLE(rj, rd, imm); \
|
||||
else \
|
||||
BLE_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BGTU_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BGTU(rj, rd, imm); \
|
||||
@@ -663,7 +772,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BLEU_safe(rj, rd, imm) \
|
||||
#define BGTU_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BGTU_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BGTU(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BGTU(rj, rd, imm); \
|
||||
else \
|
||||
BGTU_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BLEU_safe_(rj, rd, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x20000 && (imm) < 0x20000) { \
|
||||
BLEU(rj, rd, imm); \
|
||||
@@ -674,7 +796,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BEQZ_safe(rj, imm) \
|
||||
#define BLEU_safe(rj, rd, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x20000) \
|
||||
BLEU_safe_(rj, rd, imm); \
|
||||
else \
|
||||
BLEU(rj, rd, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMP_INSTS) \
|
||||
BLEU(rj, rd, imm); \
|
||||
else \
|
||||
BLEU_safe_(rj, rd, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BEQZ_safe_(rj, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x70000 && (imm) < 0x70000) { \
|
||||
BEQZ(rj, imm); \
|
||||
@@ -685,7 +820,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BNEZ_safe(rj, imm) \
|
||||
#define BEQZ_safe(rj, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x70000) \
|
||||
BEQZ_safe_(rj, imm); \
|
||||
else \
|
||||
BEQZ(rj, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMPZ_INSTS) \
|
||||
BEQZ(rj, imm); \
|
||||
else \
|
||||
BEQZ_safe_(rj, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BNEZ_safe_(rj, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x70000 && (imm) < 0x70000) { \
|
||||
BNEZ(rj, imm); \
|
||||
@@ -696,6 +844,67 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BNEZ_safe(rj, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x70000) \
|
||||
BNEZ_safe_(rj, imm); \
|
||||
else \
|
||||
BNEZ(rj, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMPZ_INSTS) \
|
||||
BNEZ(rj, imm); \
|
||||
else \
|
||||
BNEZ_safe_(rj, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BCEQZ_safe_(rj, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x70000 && (imm) < 0x70000) { \
|
||||
BCEQZ(rj, imm); \
|
||||
NOP(); \
|
||||
} else { \
|
||||
BCNEZ(rj, 8); \
|
||||
B((imm) - 4); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BCEQZ_safe(rj, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x70000) \
|
||||
BCEQZ_safe_(rj, imm); \
|
||||
else \
|
||||
BCEQZ(rj, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMPZ_INSTS) \
|
||||
BCEQZ(rj, imm); \
|
||||
else \
|
||||
BCEQZ_safe_(rj, imm); \
|
||||
} while (0)
|
||||
|
||||
#define BCNEZ_safe_(rj, imm) \
|
||||
do { \
|
||||
if ((imm) > -0x70000 && (imm) < 0x70000) { \
|
||||
BCNEZ(rj, imm); \
|
||||
NOP(); \
|
||||
} else { \
|
||||
BCEQZ(rj, 8); \
|
||||
B((imm) - 4); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BCNEZ_safe(rj, imm, jmp) \
|
||||
do { \
|
||||
if (jmp < ninst) { \
|
||||
if ((imm) < -0x70000) \
|
||||
BCNEZ_safe_(rj, imm); \
|
||||
else \
|
||||
BCNEZ(rj, imm); \
|
||||
} else if (jmp - ninst < NEAR_JUMPZ_INSTS) \
|
||||
BCNEZ(rj, imm); \
|
||||
else \
|
||||
BCNEZ_safe_(rj, imm); \
|
||||
} while (0)
|
||||
|
||||
// vaddr = GR[rj] + SignExtend(imm12, GRLEN)
|
||||
// AddressComplianceCheck(vaddr)
|
||||
// paddr = AddressTranslation(vaddr)
|
||||
@@ -1259,6 +1468,10 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
#define VROTR_H(vd, vj, vk) EMIT(type_3R(0b01110000111011101, vk, vj, vd))
|
||||
#define VROTR_W(vd, vj, vk) EMIT(type_3R(0b01110000111011110, vk, vj, vd))
|
||||
#define VROTR_D(vd, vj, vk) EMIT(type_3R(0b01110000111011111, vk, vj, vd))
|
||||
#define VROTRI_B(vd, vj, imm3) EMIT(type_2RI3(0b111001010100000001, imm3, vj, vd))
|
||||
#define VROTRI_H(vd, vj, imm4) EMIT(type_2RI4(0b11100101010000001, imm4, vj, vd))
|
||||
#define VROTRI_W(vd, vj, imm5) EMIT(type_2RI5(0b1110010101000001, imm5, vj, vd))
|
||||
#define VROTRI_D(vd, vj, imm6) EMIT(type_2RI6(0b111001010100001, imm6, vj, vd))
|
||||
#define VSRLR_B(vd, vj, vk) EMIT(type_3R(0b01110000111100000, vk, vj, vd))
|
||||
#define VSRLR_H(vd, vj, vk) EMIT(type_3R(0b01110000111100001, vk, vj, vd))
|
||||
#define VSRLR_W(vd, vj, vk) EMIT(type_3R(0b01110000111100010, vk, vj, vd))
|
||||
@@ -2717,6 +2930,44 @@ LSX instruction starts with V, LASX instruction starts with XV.
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PUSH1mz(reg) \
|
||||
do { \
|
||||
if ((reg) != xRSP) \
|
||||
dyn->insts[ninst].rsp_class = RSP_CLASS_PUSH; \
|
||||
if (dyn->insts[ninst].rsp_merge) { \
|
||||
if (rex.is32bits) { \
|
||||
ST_W(reg, xRSP, dyn->insts[ninst].rsp_entry - 4); \
|
||||
} else { \
|
||||
ST_D(reg, xRSP, dyn->insts[ninst].rsp_entry - 8); \
|
||||
} \
|
||||
if (dyn->insts[ninst].rsp_flush) \
|
||||
ADDI_D(xRSP, xRSP, dyn->insts[ninst].rsp_flush); \
|
||||
} else if (rex.is32bits) { \
|
||||
PUSH1_32(reg); \
|
||||
} else { \
|
||||
PUSH1(reg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define POP1mz(reg) \
|
||||
do { \
|
||||
if ((reg) != xRSP) \
|
||||
dyn->insts[ninst].rsp_class = RSP_CLASS_POP; \
|
||||
if (dyn->insts[ninst].rsp_merge) { \
|
||||
if (rex.is32bits) { \
|
||||
LD_WU(reg, xRSP, dyn->insts[ninst].rsp_entry); \
|
||||
} else { \
|
||||
LD_D(reg, xRSP, dyn->insts[ninst].rsp_entry); \
|
||||
} \
|
||||
if (dyn->insts[ninst].rsp_flush) \
|
||||
ADDI_D(xRSP, xRSP, dyn->insts[ninst].rsp_flush); \
|
||||
} else if (rex.is32bits) { \
|
||||
POP1_32(reg); \
|
||||
} else { \
|
||||
POP1(reg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VAND_Vxy(vd, vj, vk) \
|
||||
do { \
|
||||
if (vex.l) { \
|
||||
|
||||
Loaded 100 of 339 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user