1389 Commits
Author SHA1 Message Date
ptitSeb 5368285be0 Bumped version to v0.2.4 2021-11-19 21:57:50 +01:00
ptitSeb 096ff18ee8 Update CHANGELOG.md 2021-11-19 21:41:31 +01:00
ptitSeb 2cde569916 [DYNAREC] Small cosmetic change 2021-11-19 21:41:15 +01:00
ptitSeb f0afcb2e62 [DOC] Small change to COMPILE.md, especially for i386 build 2021-11-19 15:39:12 +01:00
ptitSeb 5b606a785d [DYNAREC] Added an option to simulate Strong Memory Model, and auto activate it when libmonobdgcw-2.0.so is detected 2021-11-19 15:34:57 +01:00
ptitSeb 6bfa4a390c [DYNAREC] Disable BigBlock when libmonobdwgc-2.0.so is loaded 2021-11-19 13:48:53 +01:00
ptitSeb 1b91e9d614 [TRACE] Fixed trace on function from a dlopen library not triggering properly 2021-11-19 13:46:30 +01:00
ptitSeb bff458d636 [DYNAREC] Change mutex locks a bit on Dynablock / Memorymap handling (backported from box64) 2021-11-19 13:44:40 +01:00
ptitSeb 8814b73eb3 [DYNAREC] Improved cancelling of FillBlock (backported from box64) 2021-11-19 13:02:23 +01:00
ptitSeb d116855eb8 [DYNAREC] Added an option to disable BigBlock building (backported from box64) 2021-11-19 12:10:47 +01:00
ptitSeb 5dd4a31f17 Merge pull request #501 from Seas0/tokitori2+fix
Adding missing macro for Tokitori 2+ patch to fix compile error …
2021-11-19 10:39:52 +01:00
ptitSeb a32bf25289 Update CMakeLists.txt 2021-11-19 10:38:02 +01:00
Seas0 eac21c4f59 Adding missing macro for Tokitori 2+ patch to fix compile error for RK3288 and etc. 2021-11-19 17:23:52 +08:00
ptitSeb f4f5cb2e80 Merge pull request #500 from Seas0/master
chores: adding auto build via Github Action and some typo fix
2021-11-19 10:16:59 +01:00
Seas0 f559a75353 fix typo (GAMEHELL -> GAMESHELL) 2021-11-19 17:04:30 +08:00
Seas0 aff26ce1c0 Adding Github Action auto build 2021-11-19 16:59:25 +08:00
ptitSeb 49717bf706 Added tokitori2+ patch to Oyra/Pandora/RK3288 and GO Advanced clones 2021-11-15 17:44:52 +01:00
ptitSeb 283eecadd6 Added some missing Vulkan wrapped function (now dxvk 1.9.2 works with wine on Radeon mesa driver) 2021-11-14 14:08:12 +01:00
ptitSeb 9069f56a9d [TRACE] Improve symbol name in LOG=2 (backported for box64) 2021-11-14 12:08:00 +01:00
ptitSeb 422c095ebf [TRACE] reduce code under mutex for x86int3 trace 2021-11-14 11:33:03 +01:00
ptitSeb 8373bee595 Fixed ResolveFile, so execvp doesn't sefgfault when executale is not found (help Wine when ntl_auth is not found) 2021-11-14 10:42:20 +01:00
ptitSeb a474c66e26 [DYNAREC] Optimzed ROR Eb, 1 and ROL Eb, 1 opcodes 2021-11-09 18:45:58 +01:00
ptitSeb b933efedd1 [DYNAREC] Fixed shrd32 optimization 2021-11-09 18:38:33 +01:00
ptitSeb 8719e9a857 [DYNAREC] Fixed SUBSET flags handling again (fixes sound in zsnes) 2021-11-08 18:38:06 +01:00
ptitSeb 2995c5312e [DYNAREC] Optimized shrd32 opcode 2021-11-07 20:36:07 +01:00
ptitSeb 0bed0d5b9c [DYNAREC] Fixed rare case or ROR and ROL with u8=0 2021-11-07 18:41:28 +01:00
ptitSeb 4e4d4515d0 [DYNAREC] Optimized RCR Ed, 1 opcode 2021-11-07 18:35:29 +01:00
ptitSeb 6b46117211 [DYNAREC] Optimized 66 F7/6 DIV opcode 2021-11-07 18:00:10 +01:00
ptitSeb 679dbafc9e Fixed some borderline cases with CMPSS opcode ([DYNAREC] too) 2021-11-07 09:15:05 +01:00
ptitSeb f6415a746c Added a few more gtk3 and co wrapped functions 2021-11-06 16:54:05 +01:00
ptitSeb b5623128b2 Merge pull request #494 from rajdakin/printerfix
Fixed some ARM instructions in the printer
2021-11-04 11:38:50 +01:00
rajdakin cdcf85bdfa Fixed some issues 2021-11-04 11:31:51 +01:00
rajdakin 41f301c3c4 Fixed some ARM instructions in the printer 2021-11-04 11:18:11 +01:00
ptitSeb 2641c5b274 Fixed RK3288 profile (for #493) 2021-11-03 21:28:58 +01:00
ptitSeb 9f4c37104a [DYNAREC] Optimized fxam 2021-11-02 21:19:42 +01:00
ptitSeb 428d59a1b0 [DYNAREC] More changes to flags optimisations 2021-11-01 17:52:49 +01:00
ptitSeb f3532ccb99 [DYNAREC] Math on ESP don't needs X_PEND or X_ALL flags 2021-11-01 14:08:06 +01:00
ptitSeb 64f7ff5880 [DYNAREC] Fixed LOCK prefix with Memory Barrier (speedup Wine D3D games) 2021-10-31 12:20:47 +01:00
ptitSeb 79fd8562bf [DYNAREC] Added DMB emitter 2021-10-31 11:10:18 +01:00
ptitSeb b2aab80ef0 [DYNAREC] Simplified Flag propagation 2021-10-31 11:02:34 +01:00
ptitSeb cb9698a5b0 Added wrapped libtbbmalloc 2021-10-30 22:50:37 +02:00
ptitSeb 3c0ac75fc7 Merge pull request #490 from Moldytzu/master
compiling instructions for Tinker Board 1/1S
2021-10-30 22:46:40 +02:00
ptitSeb 00c7e88da0 Added procision on building with ARM_DYNAREC without hardware profile (for #489 and #487) 2021-10-30 22:45:18 +02:00
Alex e26d7981b0 compiling instructions for Tinker Board 1/1S 2021-10-30 23:45:13 +03:00
ptitSeb 2d184211bf Merge pull request #488 from Danct12/a64
Add A64 profile
2021-10-30 19:39:52 +02:00
Danct12 1d7072bf86 Add A64 to docs/COMPILE.md 2021-10-30 22:35:53 +07:00
Danct12 33401074e7 Add A64 profile 2021-10-30 22:33:59 +07:00
ptitSeb 35fcd0b269 Added DATAVM macro for wrapped functions 2021-10-30 16:48:03 +02:00
ptitSeb 6ce9ba83df [DYNAREC] Added FPU in some CFLAGS and ASMFLAGS (to help #487) 2021-10-30 15:33:19 +02:00
ptitSeb 0ee881cf0d Added Phytium paragraph to COMPILE.md 2021-10-30 12:11:56 +02:00
ptitSeb 9bf5db778b Better wrapping for xmlParseChunk (should help #486) 2021-10-30 12:09:08 +02:00
ptitSeb bcdeff5217 [DYNAREC] Force architecture to armv7 if using DYNAREC without any hardware profile (may help #487) 2021-10-30 10:11:19 +02:00
ptitSeb 4a7c16c336 Fixed wrapped __pthread_mutex_destroy that was exported 2021-10-28 19:28:38 +02:00
ptitSeb fa4b5fe75a Aligned one more Vk structure 2021-10-27 22:23:41 +02:00
ptitSeb 7cf983f765 Updated the CHANGELOG 2021-10-27 19:43:30 +02:00
ptitSeb 102e0a8ab3 Added a comment, internal note of a todo 2021-10-27 19:43:30 +02:00
ptitSeb 754d7fc8a6 Detect box64 and export 64bits system if present 2021-10-24 19:08:58 +02:00
ptitSeb 79d355668f Optimized (and small fixes) to custom allocator ([DYNAREC] Speedup long launch time) 2021-10-24 19:06:36 +02:00
ptitSeb 189cd84c41 Wrapped libtcmalloc.so.0 the same as libtcmalloc_minimum.so.4 2021-10-23 17:16:45 +02:00
ptitSeb a5b13f592b Better wrpaping for g_initable_new 2021-10-23 10:29:46 +02:00
ptitSeb 987c87595a Fixed a warning 2021-10-23 10:26:29 +02:00
ptitSeb dc26964fd2 Added libdl as a dependancy for libX11 2021-10-22 19:56:38 +02:00
ptitSeb 5a94979c69 Added one more cairo function (for steam) 2021-10-22 10:29:11 +02:00
ptitSeb 028f700093 Merge pull request #484 from Heasterian/patch-4
Update CMakeLists.txt
2021-10-21 20:19:43 +02:00
Heasterian e782ffc98d Update CMakeLists.txt
Fix SD845 building without dynarec.
2021-10-21 21:06:24 +03:00
ptitSeb 6675da0661 Added a few symbol in wrapped libcairo 2021-10-21 10:43:26 +02:00
ptitSeb ba965fce28 Proper fix for link issue on glibc 2.34+ (for #479) 2021-10-20 23:51:42 +02:00
ptitSeb aeca17a36f Merge pull request #480 from Heasterian/patch-3
Add Snapdragon 845 compilation
2021-10-17 22:18:27 +02:00
Heasterian 0e64848623 Update COMPILE.md
Changes about compilation on Snapdragon 845 devices
2021-10-17 21:42:59 +03:00
Heasterian 52bf1907c5 Update CMakeLists.txt
Adding configuration for Snapdragon 845 devices.
2021-10-17 21:39:47 +03:00
ptitSeb 40a2e18034 [TRAVIS] Change to use graviton2 for arm build 2021-10-14 21:15:50 +02:00
ptitSeb 535db78525 Improved ucomiss test17 with minss and maxss testing 2021-10-10 20:11:01 +02:00
ptitSeb aee4ee9430 [DYNAREC] Changed trace a bit to be more explicit for ST as float 2021-10-10 17:03:57 +02:00
ptitSeb 20fd7e5b23 [DYNAREC] Another small optim for FSTP STx, ST0 opcode 2021-10-10 16:48:50 +02:00
ptitSeb 1cf3dd1cb1 [DYNAREC] Small optim for UCOMI-typed opcodes 2021-10-10 16:19:38 +02:00
ptitSeb a9a88c2f6e [DYNAREC] Small fix to FNSTSW AX and optim to FNSTSW mem opcodes 2021-10-10 16:01:06 +02:00
ptitSeb 1b8dd6fa19 [DYNAREC] Optim: don't insert a barrier for conditionnal jump that goes out of the block 2021-10-10 15:09:37 +02:00
ptitSeb cffafe8b65 [DYNAREC] Now that pass0 create insts on the fly, remove all insts existance tests 2021-10-10 10:44:58 +02:00
ptitSeb 1d2752a0be [DYNAREC] Small optim on FSTP Stx, ST0 opccode 2021-10-10 10:27:31 +02:00
ptitSeb 6151667c84 [DYNAREC] Small cosmetic change 2021-10-10 10:18:21 +02:00
ptitSeb d87c72298f [DYNAREC] x87 use float when possible 2021-10-10 10:14:45 +02:00
ptitSeb 2e1b3d23dc [DYNAREC] Pass0 now doing jump/barrier instead of pass 1 2021-10-08 09:07:40 +02:00
ptitSeb 1955c22501 [DYNAREC] Added a few more F32 emiters 2021-10-07 20:08:13 +02:00
ptitSeb 6378359fd8 [DYNAREC] Track of neon cache per intruction block now 2021-10-07 17:48:11 +02:00
ptitSeb fe83210938 [DYNAREC] Fixed some VCTV printer 2021-10-07 17:47:22 +02:00
ptitSeb aae0a76d2b Added a few more libc wraped functions (for #472, but still some symbols missing) 2021-10-07 17:46:42 +02:00
ptitSeb 34d7177768 [DYNAREC] New tracking of neon regs cache (1st step: improve trace) 2021-10-07 08:14:01 +02:00
ptitSeb 28131360b2 Added a new x87 test 2021-10-07 08:11:59 +02:00
ptitSeb 7e0f3af5a0 Small fix to elfloader (fixed ut99 4.51 that was broken for a long time, didn't broke CMR) 2021-10-04 23:44:04 +02:00
ptitSeb cb6c9e8ceb Added a few more vkalign structs 2021-10-04 22:08:23 +02:00
ptitSeb b30a071783 Fixed a warning 2021-10-02 22:35:15 +02:00
ptitSeb 0e8ab73e49 Added some hack so d3dadapter9 is loaded automaticaly when asked 2021-10-02 15:30:51 +02:00
ptitSeb 7475e7f68d More work on Vulkan alignment 2021-10-02 14:23:37 +02:00
ptitSeb 25902550fa Added VK_EXT_tooling_info to vulkan 2021-10-02 12:42:09 +02:00
ptitSeb 883b7bf054 Added VK_NV_coverage_reduction_mode to vulkan 2021-10-02 12:40:00 +02:00
ptitSeb b3077791b2 Added VK_KHR_fragment_shading_rate to vulkan 2021-10-02 12:37:36 +02:00
ptitSeb 46fbe2a9a8 Added VK_NV_cooperative_matrix to vulkan 2021-10-02 12:34:29 +02:00
ptitSeb d5fab7c7b1 More changes to how vkInstanceGetProcAddr is handled 2021-10-02 12:31:37 +02:00
ptitSeb 860a404cb1 Better debug info for vulkan wrapper 2021-10-02 11:53:06 +02:00
ptitSeb 0fa9c01549 One more vulkan extension 2021-10-02 11:51:12 +02:00
ptitSeb b34652d862 Added 2 more wrapped Vulkan functions 2021-10-02 11:06:47 +02:00
ptitSeb fcd7578b9a Added Phytium profile 2021-10-02 09:58:25 +02:00
ptitSeb f5e0c61d12 Do not enable box64 in box86 yet 2021-09-29 19:21:48 +02:00
ptitSeb 92d2d2c638 Added more gtk3 wrapped functions 2021-09-29 19:07:33 +02:00
ptitSeb 79a1dc0564 Improved gtk3 wrapping(ePSXe runs now 2021-09-28 21:53:19 +02:00
ptitSeb a22c0d3343 Small fix to GSourceFuncs wrapping 2021-09-28 20:03:33 +02:00
ptitSeb 46114235f9 Added handling of GDBusObjectManagerClientClass wrapping 2021-09-26 18:26:22 +02:00
ptitSeb 2bb62e419d More work on gtk wrapping 2021-09-25 13:33:18 +02:00
ptitSeb ac6f71b188 Added wrapping of GtkTable and GtkFixed structures 2021-09-25 13:17:55 +02:00
ptitSeb a438985c8c Added minimum wrapped libsecret-1 2021-09-25 13:08:08 +02:00
ptitSeb 9f310e6be2 More simplifation of some wrapped files 2021-09-25 11:27:45 +02:00
ptitSeb edfb61a452 Simplifed wrappedglibc2 2021-09-25 10:41:27 +02:00
ptitSeb 3b30a559b6 Added wrapped g_signal_connect_object and simplified wrappedgobject2 2021-09-25 10:37:20 +02:00
ptitSeb 497d4dc804 Fixed SDL_vsnprintf signature (for #469) 2021-09-24 18:41:12 +02:00
ptitSeb 631856ae54 Added tantative 0F 00 /1 STR opcode (for #406) 2021-09-23 19:58:32 +02:00
ptitSeb 8b887c7714 Improved elfload and mmap (should help #467) 2021-09-22 08:53:11 +02:00
ptitSeb 852f6af362 Added more wrapped function and wrapped libs to nss3+friends (for #466, but still unstable) 2021-09-21 20:58:50 +02:00
ptitSeb cd6cb2352f This should help for alternate handling 2021-09-21 20:56:21 +02:00
ptitSeb 5bc7a1bf4f Small cosmetic change 2021-09-21 20:54:10 +02:00
ptitSeb 844566a78a Added empty wrapped libgconf-2 2021-09-20 21:53:14 +02:00
ptitSeb 2320c0de77 Fixed a small bug with gtk wrapping 2021-09-20 21:52:30 +02:00
ptitSeb 6afddae6d8 [DYNAREC] Improved 0F 0B UD2 opcode handling 2021-09-18 18:35:50 +02:00
ptitSeb 5de22d4ce1 Fixed execvp wrapping 2021-09-18 17:58:52 +02:00
ptitSeb 3162ae83b4 Added wrapped libnspr4, libsmime3, libnssutil3 and libnss3 2021-09-18 16:19:53 +02:00
ptitSeb e5bcae6e43 Forgot to export my_modify_ldt 2021-09-18 12:51:20 +02:00
ptitSeb a110b60a2a Try to use mmap first when loading elf file into memory 2021-09-18 08:36:46 +02:00
ptitSeb 9190a20ca1 Added better vsyscall support, and fixed some issues with alternate address handling 2021-09-12 13:40:00 +02:00
ptitSeb 7a7f746782 Fixed a warning in a wrapped libc function 2021-09-12 10:04:09 +02:00
ptitSeb 6c148b77a1 Small adjustment in one SDL2 function signature 2021-09-12 09:54:14 +02:00
ptitSeb e30eae7652 [README] Added a precision on 64bis build and box64 existance (for #459) 2021-09-11 15:44:52 +02:00
ptitSeb 811ffe83f8 Merge pull request #458 from Heasterian/patch-2
Note for Tegra users
2021-09-11 12:26:54 +02:00
Heasterian ae8d61c3a3 Note for Tegra users 2021-09-11 13:23:22 +03:00
ptitSeb 0e54aaf70f Merge pull request #455 from JohnnyonFlame/goa_clone_pr
General fixes and definitions for GO Advance clones
2021-09-05 15:52:26 +02:00
ptitSeb 4498f216a0 [TRAVIS] Remove ctest for armhf 2021-09-05 15:50:13 +02:00
ptitSeb 3b4a1e6861 [TRAVIS] nope, adding armhf arch using dpkg didn't changed anything 2021-09-05 15:40:21 +02:00
ptitSeb 83a9f96f20 [TRAVIS] try to add 32bits archs 2021-09-05 15:30:29 +02:00
JohnnyonFlame dad2601f0d Provide a fake passwd struct on getpwuid failure.
Fixes Chowdren games dereferencing an offset of a NULL pointer on 351ELEC when getpwuid fails and Chowdren fails to gracefully recover.
2021-09-05 10:27:28 -03:00
JohnnyonFlame fb79a9eb22 Added variable BOX86_FORCE_ES to force a specific OpenGL ES Context version on SDL_CreateWindow calls. 2021-09-05 10:27:28 -03:00
JohnnyonFlame 5fded645fb Added SDL_DYNAPI_entry wrapper. 2021-09-05 10:27:28 -03:00
ptitSeb 84f16804bb [TRAVIS] and added libgcc1-i386-cross on amd64 platform 2021-09-05 15:19:11 +02:00
ptitSeb e6969267e9 [TRAVIS] Added build badge on README 2021-09-05 15:13:52 +02:00
ptitSeb 1655a98997 [TRAVIS] and added some gcc-multilib on amd64 platform 2021-09-05 15:11:28 +02:00
ptitSeb 4444bd2286 [TRAVIS] disable ctest on arm build, arm64 VM doesn't seems capable of running armhf code 2021-09-05 15:07:44 +02:00
ptitSeb fe402954f8 [TRAVIS] Try to add i386 multi arch for amd64 build 2021-09-05 14:58:59 +02:00
ptitSeb 9ae3543879 [TRAVIS] Yet another fix for script syntax 2021-09-05 14:56:17 +02:00
ptitSeb e88fa9ab45 [TRAVIS] Another fix for script syntax 2021-09-05 14:52:41 +02:00
ptitSeb c707150666 [TRAVIS] Fix script syntax 2021-09-05 14:49:41 +02:00
ptitSeb c2e5f60526 [TRAVIS] Try some travis build (arm and x86) 2021-09-05 14:46:00 +02:00
JohnnyonFlame 395629f678 Added GOA_CLONE definitions.
Sets compilation definitions for GO Advance clones, such as the RG351p/v, Gameforce Chi, RGB10 and other such devices.
2021-09-05 08:32:27 -03:00
ptitSeb f77b80899d Added major contributor list in README 2021-09-05 11:28:31 +02:00
ptitSeb 5720619bd2 [DYNAREC] Fixed (again) 16bits and 32bits BTR/BTS/BTC with imm8==0 (help steam) 2021-09-04 12:12:21 +02:00
ptitSeb e33ac88379 Merge pull request #454 from ye-yeshun/master
fix LDS and LES
2021-09-02 08:05:30 +02:00
ye-yeshun 96c9bf168e Merge branch 'ptitSeb:master' into master 2021-09-02 13:24:15 +08:00
Yeshun Ye 3711622f66 fix: fix errors of 'LDS' and 'LES'.
Signed-off-by: Yeshun Ye <[email protected]>
2021-09-02 13:06:05 +08:00
ptitSeb a3cd9f7de7 Added 64 39 opcode ([DYNAREC] too) 2021-09-01 20:22:48 +02:00
ptitSeb 389927dc1d Added 65 31 opcode ([DYNAREC] too) (for #425) 2021-08-29 18:18:38 +02:00
ptitSeb ff63fa7437 [DYNAREC] Small fix for 8bits ror/rol when imm8!=0 and imm8&7==0 2021-08-29 16:02:22 +02:00
ptitSeb b480d6856b [DYNAREC] Fixed 16bits BTS/BTR/BTC with imm8==0 (helps EWJ SE Win95, probably other too) 2021-08-29 15:15:19 +02:00
ptitSeb 76786e9e43 [DYNAREC] Fixed BTS/BTR/BTC with imm8==0 (helps EWJ SE Win95, probably other too) 2021-08-29 14:50:46 +02:00
ptitSeb aa9ff80137 [DYNAREC] Small optim on flag for BTC/BTR/BTS/BSF/BSR opcodes 2021-08-29 10:38:26 +02:00
ptitSeb 2e60a6b6e7 [DYNAREC] Added a YIELD opcode for F3 90 PAUSE opocde (instead of nothing) 2021-08-29 09:01:23 +02:00
ptitSeb f24684f478 [DYNAREC] Small optim for LOCK opcodes with fixed addresses 2021-08-28 19:12:50 +02:00
ptitSeb f43a507e91 Allow older version of python to be used 2021-08-27 16:02:42 +02:00
ptitSeb 25f7283af9 Redone some of the wrapping of freetype to be consistant with other wrapping 2021-08-27 10:01:21 +02:00
ptitSeb ea29d3f6df Merge pull request #451 from ye-yeshun/master
add 'palignr' 'psignw' 'lzcnt' instructions.
2021-08-27 08:52:19 +02:00
ptitSeb 1592f9246b Merge pull request #450 from wannacu/master
use GOM to wrap FT_Outline_Decompose (libfreetype)
2021-08-27 08:45:02 +02:00
ptitSeb b481c25ee5 Merge branch 'master' into master 2021-08-27 08:44:54 +02:00
ptitSeb e6fa77b3c0 Fix build on ARM platform 2021-08-27 08:39:01 +02:00
ptitSeb 3da5f56257 Merge pull request #449 from rajdakin/rebuild_wrappers
Upgrade of the rebuild_wrappers script (and a bit more)
2021-08-27 07:55:54 +02:00
Yeshun Ye d97dfa768a Add 'LZCNT' instruction.
Signed-off-by: Yeshun Ye <[email protected]>
2021-08-27 11:41:58 +08:00
Yeshun Ye 1d671b104b Add 'PSIGNW' instruction.
Signed-off-by: Yeshun Ye <[email protected]>
2021-08-27 11:40:33 +08:00
Yeshun Ye d7cb28a66b Add 'palignr' instruction.
Signed-off-by: Yeshun Ye <[email protected]>
2021-08-27 11:38:28 +08:00
rajdakin d153456653 Bug fixes and version bump 2021-08-27 01:12:12 +02:00
rajdakin ad77202a05 Last step in upgrading the rebuild_wrappers script 2021-08-27 00:39:29 +02:00
rajdakin 20ffd3681e Fixed the same minor issue as in box64 2021-08-27 00:30:41 +02:00
rajdakin d66c1f4510 Added GOWM, GOWS, GOW2 support 2021-08-27 00:29:42 +02:00
rajdakin fcdd6f7947 Fixed bz2's stream unwrapping 2021-08-27 00:01:19 +02:00
rajdakin 1b54190c15 First step at upgrading the script 2021-08-26 23:23:49 +02:00
rajdakin 7550203dc9 Fixed some wrapper headers 2021-08-26 23:20:08 +02:00
wannacu 380e9fa09e use GOM to wrap FT_Outline_Decompose (libfreetype) 2021-08-26 23:03:11 +08:00
ptitSeb c04aeec3e5 Fixed wine/vulkan paragraph in README (for #445) 2021-08-23 10:28:04 +02:00
ptitSeb b758d842c4 Added some precisions to Vulkan support in README 2021-08-22 09:20:07 +02:00
ptitSeb ff9da0c850 Merge pull request #444 from chunky-milk/master
move LICENSE back to root
2021-08-22 09:11:44 +02:00
Ryan Fortner 87681ffcaa move LICENSE back to root 2021-08-21 14:04:53 -04:00
ptitSeb 47c33cd5a9 cancelFillBlock is DYNAREC only (for #443) 2021-08-21 17:44:49 +02:00
ptitSeb ea9e9da829 Improved handling of default version symbol (HalfLife, and probably other, works now) 2021-08-12 17:22:40 +02:00
ptitSeb 0ffcfcb0c0 Added a few more gnutls wrapped functions 2021-08-12 10:11:14 +02:00
ptitSeb 132d2dc3fc Added one gnutls function 2021-08-12 09:33:17 +02:00
ptitSeb de61c33093 Fixed BOX86_JITGDB=2 not working 2021-08-11 17:06:12 +02:00
ptitSeb 38b12c9773 Small fixes to some thread wrapped functions 2021-08-11 12:09:26 +02:00
ptitSeb 2734536fa7 [DYNAREC] Added handling of Segfault triggered while FillBlock is running, to just cancel the dynablock and use interpretor there 2021-08-11 10:46:08 +02:00
ptitSeb d4e7852598 Small adjustment with vorbisfile wrapping 2021-08-10 10:17:46 +02:00
ptitSeb fd3da6af08 Change lock order in relock function, just in case 2021-08-10 10:15:45 +02:00
ptitSeb de3ec8e7af Small fix to longjump inside signal handling 2021-08-09 13:55:21 +02:00
ptitSeb 2256560985 Some more work on signal handling to try avoid deadlock 2021-08-09 12:00:53 +02:00
ptitSeb 342ee45558 Added 65 D0/D2 opcodes 2021-08-07 20:04:03 +02:00
ptitSeb c207597409 Some more small changes to signal handling, again 2021-08-07 19:49:40 +02:00
ptitSeb 2f5198eb9f Check protection status before recomputing a hask of a block (not sure it's really usefull) 2021-08-07 19:49:19 +02:00
ptitSeb 96fb201246 Added test about longjmp in singal handling 2021-08-05 07:49:57 +02:00
ptitSeb ff36508548 Change Signal handling to always use sigaction, and improve longjmp in signal handler handling 2021-08-04 18:07:36 +02:00
ptitSeb 02612749c8 Merge pull request #434 from piz-ewing/master
Fixed INC/DEC (for lazy flags)
2021-08-04 08:33:14 +02:00
piz-ewing 7648cd9a56 Fixed INC/DEC (for lazy flags) 2021-08-04 14:28:23 +08:00
ptitSeb 95feb02d97 Add a precision for PI4 on 64bits OS in COMPILE.md 2021-08-03 15:00:09 +02:00
ptitSeb 36a49e135e Merge pull request #432 from wannacu/master
[DYNAREC] Added 66 0F 38 06 opcode
2021-08-03 08:28:37 +02:00
Zhipeng Zhao 8fe7b90daa [DYNAREC] Added 66 0F 38 06 opcode 2021-08-03 14:09:13 +08:00
ptitSeb 238103a5e0 Added wrapped modify_ldt to libc (for #424) 2021-08-01 08:24:55 +02:00
ptitSeb 72e0d80af9 Merge pull request #427 from lifning/master
Add a couple stubs for SDL 2.0.14 & Fix ld-linux.so wrapper for ppcle
2021-07-29 23:26:48 +02:00
lifning 21b61f07da Add SDL_GameControllerHasLED and SDL_GameControllerHasSensor stubs from SDL 2.0.14 (used by recent versions of FNA) 2021-07-29 12:29:13 -07:00
lifning 1d67fb050c Use proper ld-linux.so ALTNAME2 on little-endian PowerPC 2021-07-29 12:28:04 -07:00
ptitSeb 40eaacc33b Added /lib/box86 and /usr/lib/box86 to default BOX86_LD_LIBRARY_PATH 2021-07-28 21:51:06 +02:00
ptitSeb 4b47e699f5 Added many libGL extension (from box64) 2021-07-28 21:49:40 +02:00
ptitSeb d845f048ea Added 65 29 opcode ([DYNAREC] too) (for #425) 2021-07-28 14:27:24 +02:00
ptitSeb e70dc0af56 Added 65 D1/D3 opcodes ([DYNAREC] too) (for #425) 2021-07-28 14:16:40 +02:00
ptitSeb 3c3c64f3c7 [DYNAREC] Fixed 65 0F AF opcode (for #425) 2021-07-28 12:11:34 +02:00
ptitSeb 87a9ce334a Added 65 0F AF opcode ([DYNAREC] too) (for #425) 2021-07-28 11:36:38 +02:00
ptitSeb ace58063e4 Added 65 21 opcode ([DYNAREC] too) (for #425) 2021-07-28 11:18:58 +02:00
ptitSeb 33ef14cd5d Added 65 23 opcode ([DYNAREC] too) (for #425) 2021-07-27 13:35:54 +02:00
ptitSeb 4f6196b330 Merge pull request #422 from icecream95/vtable_internal
Set the internal vtable for D3D9 structs
2021-07-23 09:58:42 +02:00
Icecream95 fbe1ff93e9 Set the internal vtable for D3D9 structs 2021-07-23 10:23:01 +12:00
ptitSeb b2581fccaa Merge pull request #420 from Jai-JAP/aur
Update archlinux/*
2021-07-22 14:40:37 +02:00
Jai-JAP 056e29c9a8 Rename archlinux/ to pkgbuilds/ 2021-07-22 17:44:53 +05:30
Jai A P 0bf409fc10 Update archlinux/* 2021-07-22 17:38:22 +05:30
ptitSeb 6d2a3883ac Change email address in PKGBUILD header 2021-07-22 13:30:39 +02:00
ptitSeb d7dcb56105 Fixed status of C2 x87 flags after sin, cos, sincos and tan function ([DYNCAREC] too) (for #158, thnk @icecream95 for the debugging) 2021-07-21 12:04:18 +02:00
ptitSeb a62a9f6c75 Added wrapped function gtk_input_add_full to gtk2 2021-07-17 15:40:53 +02:00
ptitSeb b4c32dd56b Added a few more gtk2 progress wrapped functions 2021-07-17 14:43:03 +02:00
ptitSeb 3a323abc9a [DYNAREC] Fix potential deadlock (for #417, thx for the hint) 2021-07-16 10:49:17 +02:00
ptitSeb 1fefd5c82c Change COMPILE.md to remove the '-j4' on Pi build instruction, as it can fail depending the amount of memory available, but added a comment for those who wants to use it 2021-07-13 21:57:09 +02:00
ptitSeb e470a28bda Small changes on MOV Ed, Seg and CALL FAR opcodes 2021-07-13 16:45:39 +02:00
ptitSeb 435f1c2a16 Small change to not try to fetch bock at new thread if dynarec is disabled 2021-07-13 16:45:39 +02:00
ptitSeb e9f72c1e33 Merge pull request #411 from WheezyE/patch-1
Update COMPILE.md
2021-07-13 07:35:26 +02:00
Eric Wiessner (KI7POL) f8d8c6c7a4 Update COMPILE.md
just wanted to clarify the info about which flags to use for aarch64 builds a little bit
2021-07-12 17:44:22 -06:00
ptitSeb 0c7022a756 Fixed ELF Signature detection 2021-07-12 22:18:52 +02:00
ptitSeb 7254e5558b Fixed some memory issue when launching box64 from box86 main 2021-07-12 14:29:32 -05:00
ptitSeb 17cdb30ab1 Use box64 to launch x64 binary (if box64 is present in same folder as box86) 2021-07-12 12:38:08 -05:00
ptitSeb db743b1226 Name Trace build as box86 (remove the trailing t) 2021-07-12 11:39:27 -05:00
ptitSeb e9cc8d43a9 Re-splitted mmx and x87 regs (not sure why, but this fixes the Shaking Cam issue in The Witcher 2 for windows) 2021-07-11 16:12:31 +02:00
ptitSeb 4dd9bf74d9 Fixed BOX86_LOG=2 for mmap 2021-07-10 18:33:51 +02:00
ptitSeb 722909a9cf Fixed an issue with memory protection introduced on 1/1/21... 2021-07-10 16:59:14 +02:00
ptitSeb 13287a114c Refined .deb build script with arch naming and postinst 2021-07-10 10:08:15 +02:00
ptitSeb 1a6659d577 Fixed small issue in 66 0F BA opcode 2021-07-10 10:08:15 +02:00
ptitSeb 3a7cc57fde Merge pull request #409 from wannacu/master
Added wrapped libv4l2.so.0
2021-07-09 16:22:42 +02:00
wannacu c093f18d20 Added wrapped libv4l2.so.0 2021-07-09 22:10:54 +08:00
ptitSeb f2ebd77ace First try at building .deb package using cmake CPack 2021-07-09 14:31:54 +02:00
ptitSeb ad55a85b89 Refined handling od flag 0x4 for wrapped dlopen 2021-07-09 11:24:06 +02:00
ptitSeb 779e0bdc50 Handling flag 0x4 for wrapped dlopen 2021-07-09 10:29:05 +02:00
ptitSeb 80c4d80952 Fix non-dynarec build 2021-07-08 09:35:02 +02:00
ptitSeb 42e54c0241 Improved Handling of some TLS Reloc 2021-07-06 19:29:43 +02:00
ptitSeb b393356b4b Removed mutex per bridge and use a global one (remove chance of freeze on fork) 2021-07-06 19:08:04 +02:00
ptitSeb f65555c810 Try to speedup a bit FindR386COPYRel 2021-07-06 18:49:39 +02:00
ptitSeb 174bf29f28 [DYNAREC] Improved CMPSS and CMPSD ocpodes (backported from box64) 2021-07-06 18:42:14 +02:00
ptitSeb 1776027e63 Fixed some potential crash with emulated RW on SDL1 2021-07-06 18:34:32 +02:00
ptitSeb 4018df12cd Try to fix compilation on old libc 2021-07-06 18:33:15 +02:00
ptitSeb c400cd5f61 Added some wrapped function to libXext 2021-07-05 17:50:27 +02:00
ptitSeb 4710c4777e Update README.md 2021-07-03 10:58:21 +02:00
ptitSeb a872136418 [DYNAREC] Improved FILD/FISTP i64 hack 2021-07-03 10:54:00 +02:00
ptitSeb da15c9619a [DYNAREC] Improved PSHUFD opcode 2021-07-03 10:53:11 +02:00
ptitSeb a67b510cae Improved README 2021-07-03 10:52:21 +02:00
ptitSeb c84d1a827e Small changes around wine, wine64 and box86 exitting process 2021-07-03 10:52:05 +02:00
ptitSeb 0e2cac5505 Added pthread_mutexattr_getprotocol wrapped function 2021-07-03 10:51:04 +02:00
ptitSeb aa4f39a51b [DYNAREC] Added some small optim for SSE XOR on same reg 2021-06-29 15:14:41 +02:00
ptitSeb 3c0b7830de Added ucomiss test 2021-06-29 14:35:16 +02:00
ptitSeb 25f43108fe [DYNAREC] Fixed DF /5 FILD opcode, and optimized FILD/FISTP i64 sequence (fixes #404) 2021-06-29 11:46:08 +02:00
ptitSeb da64e491bb Added 66 0F 01 /4 dummy opcode (always 0), for #404 2021-06-28 09:52:09 +02:00
ptitSeb 23fe11278c Merge pull request #403 from WheezyE/patch-2
Update X86WINE.md with cosmetic edits
2021-06-26 22:30:24 +02:00
Eric Wiessner (KI7POL) f27361bf17 Update X86WINE.md with cosmetic edits
Just trying to rearrange and consolidate some info for clarity & brevity.  I added some notes that we will assume users are using the default wine 5.13 version unless otherwise specified.  I also wanted to put the Twister OS FAQ Wine install as the top example since I think it looks more approachable to beginners users and will install a more standard version of wine for bug reports.
2021-06-26 14:12:50 -06:00
ptitSeb 91e0120780 Merge pull request #402 from JinShil/patch-1
Fix typo in README
2021-06-26 08:21:32 +02:00
Mike e4f2af21c3 Fix typo in README 2021-06-26 13:54:45 +09:00
ptitSeb 2edb0ed1e3 [DYNAREC] Another fix for D9 F3 opcode (fixing Neverwinter Night issue #401) 2021-06-23 20:53:39 +02:00
ptitSeb e317c61084 [DYNAREC] Fix D9 F3 opcode (fixing Neverwinter Night issue #401) 2021-06-23 16:24:14 +02:00
ptitSeb 5506dbbc77 Added wrapping of MetaFrames in gtkclasses 2021-06-23 09:45:47 +02:00
ptitSeb 2ed175ee3b Fixed signature for a libXi function 2021-06-23 09:45:19 +02:00
ptitSeb 2a2631075e Try to add some workaround for libs with embedded libtccmalloc (for #400) 2021-06-23 08:35:59 +02:00
ptitSeb 406226bd2b More improvement to elfloader (fixing hlds for #385 and Unreal linux that was broken since elfloader last changes) 2021-06-22 18:40:05 +02:00
ptitSeb 6f105f0720 Added some more detailled trace for 2 wprintf functions 2021-06-22 17:40:39 +02:00
ptitSeb e30430be48 [DYNAREC] Added an inline version of FISTP i64, but disabled for now: it's awfully complex, not sure it's really worth it 2021-06-21 14:43:29 +02:00
ptitSeb 3a52af11bd [DYNAREC] Added optimized MUL 8bits opcode 2021-06-21 11:22:07 +02:00
ptitSeb c73b427d42 Added a few more gtk3 wrapped function (for #398) 2021-06-21 11:16:24 +02:00
ptitSeb 85f5a619ab Added syscall 328 (for #398) 2021-06-20 14:52:51 +02:00
ptitSeb a6d94027db Added some symbol to wrapped gtk3 (for #398) 2021-06-20 14:50:23 +02:00
ptitSeb 45a3044a61 [DYNAREC] Small optim on Purge SSE Cache 2021-06-20 14:48:14 +02:00
ptitSeb d25b3a307e Minor cosmetic chnge to wrapped libc 2021-06-20 14:47:28 +02:00
ptitSeb d5e3bc9ceb [ANDROID] Fixed build (still for #395) 2021-06-18 14:23:39 +02:00
ptitSeb cd8f2997ca [ANDROID] Added wrapped of libandroid-shmem.so (and added some libX11 .so synonym), for #395 2021-06-18 11:03:54 +02:00
ptitSeb df65e97491 Remove Discord link, use github discussion istead 2021-06-17 08:21:22 +02:00
ptitSeb abbb60a4fa Fixed and added a wrapped function to libc 2021-06-17 08:18:51 +02:00
ptitSeb ff05035bc0 Added some more libcrypto wrapped functions 2021-06-16 17:57:05 +02:00
ptitSeb 71d9d78ed5 Added a wrapped function to libSSL 2021-06-16 17:27:35 +02:00
ptitSeb d8b2e96552 Disabled, this is not ready yet 2021-06-16 15:19:41 +02:00
ptitSeb c974ce057e Improved emulated library loader, to not stop at first binary found even if not at the correct architecture 2021-06-16 15:18:30 +02:00
ptitSeb ddbe50c5ef Better wrapping for __snprintf_chk function 2021-06-16 15:08:22 +02:00
ptitSeb 2aaf87bbcf Fixed SDL_HasIntersection signature (fixing To The Moon blank screen) 2021-06-16 15:07:56 +02:00
ptitSeb 8c74fde404 Added some hack to try detect SDL_sound custom build for SDL2 and use emulated one first (fixing some sound in To The Moon) 2021-06-16 15:07:44 +02:00
ptitSeb dbe5afeaba Better trace for soem snprintf functions 2021-06-16 15:06:41 +02:00
ptitSeb 9bf035539b Added even more libcrypto wrapped functions 2021-06-15 16:10:10 +02:00
ptitSeb 5cb73d58cd Added some more libcrypto wrapped functions 2021-06-15 16:07:57 +02:00
ptitSeb 1e3eba1b5b More help for building on old system 2021-06-15 15:35:04 +02:00
ptitSeb 87af935494 Various small warning fixes 2021-06-15 14:52:33 +02:00
ptitSeb 86cc204693 [DYNAREC] Fixed softfp build 2021-06-15 13:40:03 +02:00
ptitSeb d1e6d744ae Minor adjustment to some wrapped libc functions signature 2021-06-15 13:36:39 +02:00
ptitSeb cea3dcea67 [DYNAREC] Fixed detection of softfp float-abi 2021-06-15 13:35:42 +02:00
ptitSeb 72a896a95a Forced BOX86_NOGTK=1 when detecting steam 2021-06-15 08:44:28 +02:00
ptitSeb 9ca0c429bf [DYNAREC] Small fix to shld32c emiter 2021-06-15 08:44:09 +02:00
ptitSeb 681e06ce73 [DYNAREC] Added (U/S)DIV printer 2021-06-12 20:27:36 +02:00
ptitSeb 3a3e393d20 [DYNAREC] Added ror8c emiter, and fixed rol8c 2021-06-12 17:06:36 +02:00
ptitSeb 6b86cb7d1e [DYNAREC] Added rol8c emiter 2021-06-12 16:44:58 +02:00
ptitSeb 4a772f1bb6 [DYNAREC] Remove Need Optim mark for IMUL 16bits 2021-06-12 16:21:33 +02:00
ptitSeb d8309595cf [DYNAREC] Fix previous commit 2021-06-12 16:08:17 +02:00
ptitSeb 6000f4f25c [DYNAREC] Added inline version of FILD i64 opcode 2021-06-12 16:00:49 +02:00
ptitSeb 3cabeb4f27 [DYNAREC] Marked opcode that can use optimizion in DUMP 2021-06-12 14:02:13 +02:00
ptitSeb 53b525d758 [DYNAREC] Added more IDIV handling for ARM DIV (when available) 2021-06-12 13:25:53 +02:00
ptitSeb 06ebc4cb03 [DYNAREC] Fixed detection for DIV / IDIV opcode to alow ARM DIV use (if present) 2021-06-12 12:22:08 +02:00
ptitSeb 25245e2a46 [DYNAREC] More changes on Flags handling, fixing some border cases (like with CLC or other opcode that only do SUBSET of flags) 2021-06-12 11:46:28 +02:00
ptitSeb 4d8adae071 [DYNAREC] Saved xFlags when doing a direct math call in x87 opcodes 2021-06-11 18:50:27 +02:00
ptitSeb d65216df76 Added special opcode handling on signal to regular signal 2021-06-11 18:49:47 +02:00
ptitSeb 155c4ba1f9 [DYNAREC] Fixed XCHG 16bits version opcode 2021-06-11 18:49:12 +02:00
ptitSeb f6ff832e51 [DYNAREC] Added Special case opcode detection for signal, when occur in speiciific palces to adjust registers value (REP MOVS/D/B) and REP(Z/NZ) CMPS(B/D) for now) 2021-06-11 15:36:00 +02:00
ptitSeb 0b4045ffb1 [DYNAREC] Potential fix for rare case of opcode with SUBSET Flags and need for PEND 2021-06-11 15:34:40 +02:00
ptitSeb 677d9feb87 Added a bit more function to wrapped gtk2 2021-06-10 21:16:01 +02:00
ptitSeb 043ac1fdab [DYNAREC] Try to optimize some of the complex x87 opcodes 2021-06-10 17:16:00 +02:00
ptitSeb dacd75ca7e [DYNAREC] Small optim on Native function call (and small fix on stack alignment) 2021-06-10 11:44:18 +02:00
ptitSeb 3e5352f79c [DYNAREC] Try to use IDIV when available 2021-06-09 16:23:15 +02:00
ptitSeb 2f56a667f3 Cpuid now also export HT extension 2021-06-09 16:10:51 +02:00
ptitSeb cefa19ec6a [DYNAREC] Added another special case for SIGSEGV du to heavy multitasking issue with memory protection mapping 2021-06-09 14:27:21 +02:00
ptitSeb ab2ab88581 [DYNAREC] Use ARM 32bits DIV when possible 2021-06-09 12:35:00 +02:00
ptitSeb a5c28c6020 Flags are undefined after a div operation 2021-06-09 12:34:25 +02:00
ptitSeb ac3ddc134e [DYNAREC] Added unsupported 0F AE /5 opcode, to avoid dynablock break 2021-06-09 11:09:27 +02:00
ptitSeb 86659b40bd Some small improvments in signal handling 2021-06-06 17:48:45 +02:00
ptitSeb fd7c7e356c [DYNAREC] Fixed end handling in dynablock construction 2021-06-06 17:48:45 +02:00
ptitSeb 10c4e0323a [DYNAREC] Fixed potential issue with longjmp native function call 2021-06-06 17:48:45 +02:00
ptitSeb 53a647af56 Merge pull request #391 from WheezyE/patch-1
Fix bolded 'Notes about Wine' section in readme
2021-06-05 19:10:16 +02:00
Eric Wiessner (KI7POL) 026185da74 Fix bolded 'Notes about Wine' section in readme 2021-06-05 09:52:10 -06:00
ptitSeb 951a85d3b7 Improved getopt handling 2021-06-05 15:05:15 +02:00
ptitSeb d6db825ec3 [DYNAREC] Various small fixes to flags handling 2021-06-05 10:23:20 +02:00
ptitSeb d9ab158b97 Fixed BT/BTC/BTR/BTS opcodes ([DYNAREC] too) (helped KaM Rmake, probably other) 2021-06-04 21:51:53 +02:00
ptitSeb f9305d58e8 [DYNAREC] Fixed DD C0..C7 FFREE opcode 2021-06-04 16:47:15 +02:00
ptitSeb 8da827d06f Added an option to use stderr for logs 2021-06-04 16:46:43 +02:00
ptitSeb 4ee29a6d57 Improve trace when fpu_stack is incoherent 2021-06-04 16:42:54 +02:00
ptitSeb e060e060af Fixed SDL_JoystickGetGUIDString function signature 2021-06-04 13:14:44 +02:00
ptitSeb 81a63edcbc Improved unloading of libs (helps wine) 2021-06-04 11:06:24 +02:00
ptitSeb 8b1ca1330f Added EE opcode 2021-06-03 23:03:29 +02:00
ptitSeb 7bc1a6d7c7 [DYNAREC] Improve handling of SMC (should help autoextractible/encrypted programs) 2021-06-03 18:04:50 +02:00
ptitSeb 9e24a71225 [DYNAREC] Fixed C0 ROL/ROR opcode (help some versions of WeChat) 2021-06-03 18:03:52 +02:00
ptitSeb 8d89e7efdb Some fine-tunning on wrapped lubncurses and friends 2021-06-03 16:15:13 +02:00
ptitSeb 4ca4e84878 Improved elfloader with COPY and GLOBAL reloc with version 2021-06-03 16:15:06 +02:00
ptitSeb 9461f7d24e Added Global symbol workaround for libtinfo/libncurses 2021-06-03 14:51:22 +02:00
ptitSeb e29ba9e43e Improved PltResolver to search a no version symbol if ver=0 one is not found 2021-06-03 14:50:50 +02:00
ptitSeb a875a16c92 Fixed special case for FSCALE opcode, thx to PCem developper ([DYNAREC] too) 2021-06-03 13:08:20 +02:00
ptitSeb de92a8a41b Added wrapped libpanel and mvprintw function to libncurses 2021-06-02 17:38:10 +02:00
ptitSeb d719809440 Added some more wrapped libGL functions (help apitrace) 2021-06-01 11:06:45 +02:00
ptitSeb 656e7552b5 Improved custom named libGL handling 2021-06-01 11:02:52 +02:00
ptitSeb 9715a2fef6 Added dummy SGDT 0F 01 /0 opcode 2021-05-31 19:04:52 +02:00
ptitSeb 268166b20a Added dummy SLDT 0F 00 /0 opcode 2021-05-31 18:39:08 +02:00
ptitSeb f03fb651c2 Added dummy 0F 01 /1 SIDT opcode 2021-05-31 18:22:51 +02:00
ptitSeb 6b05e42582 Some adjustements to elfloader needed libs loading 2021-05-31 17:49:46 +02:00
ptitSeb 0d42b42459 Added alternate name for libSDL2_image, libSDL2_ttf and libexpat 2021-05-30 20:35:08 +02:00
ptitSeb 2159d407ee Improve handling of freetype FTC_Manager (help wine dwrite font manager) 2021-05-30 10:32:44 +02:00
ptitSeb 2b9645e3a6 Small fixes after big elfloader rework 2021-05-29 18:23:20 +02:00
ptitSeb 5d0d1e4eb2 Fixed some old issue with env. var. parsing, and a bit more help on new BOX86_DUMP one 2021-05-28 11:57:10 +02:00
ptitSeb 0d82e52aa6 Updated docs with the elfloader rework 2021-05-28 11:25:10 +02:00
ptitSeb 28cfc17bb6 Added 2 more wrapped function to pthread 2021-05-28 08:04:39 +02:00
ptitSeb 5c8d387c27 Large refactoring of elfloader 2021-05-27 19:55:17 +02:00
ptitSeb 213f51c14b Wrapped GLX_NV_vertex_array_range functions 2021-05-27 18:45:18 +02:00
ptitSeb d2e5f715a9 Started a new dev. cycle 2021-05-27 18:44:16 +02:00
ptitSeb bedacef673 Bumped version to v0.2.2 2021-05-24 10:44:00 +02:00
ptitSeb 78bafd8b33 [DYNAREC] Forgot this file on previous commit 2021-05-24 10:30:56 +02:00
ptitSeb 6ae9b28325 [DYNAREC] Added 65 69/81/83 opcodes 2021-05-24 09:53:52 +02:00
ptitSeb 68f01f4267 Merge pull request #388 from rajdakin/master
Fixed rpaths for tests 15 and 16
2021-05-23 21:58:55 +02:00
rajdakin d9f953ec82 Added copies of output for failed runs 2021-05-23 21:35:05 +02:00
rajdakin d06795e979 Fixed rpaths for tests 15 and 16 2021-05-23 21:20:11 +02:00
ptitSeb 979ce28de9 Merge pull request #387 from rajdakin/master
Added two linking tests
2021-05-23 21:04:24 +02:00
rajdakin 4aa2a95b59 Added two linking tests 2021-05-23 20:29:01 +02:00
ptitSeb b588709ad9 Changed the way Mutex are check for lock on Signal handling (should help with freeze) 2021-05-21 18:17:41 +02:00
ptitSeb ca95cdcb91 Added 0F FB opcodes ([DYNAREC] too) 2021-05-20 14:07:19 +02:00
ptitSeb bf046a68c4 Added signal mask handling in setjmp/longjmp functions 2021-05-18 11:12:59 +02:00
ptitSeb 490a4ab31c [DYNAREC] Fix unaligned LOCK INC/DEC opcodes 2021-05-17 16:01:59 +02:00
ptitSeb 205133554f [DYNAREC] Fixed some issue were x87 cache is not purged correctly 2021-05-16 15:22:09 +02:00
ptitSeb 4df9b9ac6f [DYNAREC] Force separation of x87 and mmx cache usage 2021-05-16 13:43:48 +02:00
ptitSeb 0b5a943799 Set theme jekyll-theme-hacker 2021-05-16 10:40:16 +02:00
ptitSeb ede0e9d4c3 Added wrapped libexpat (minium symbols for torchlight2) 2021-05-16 10:32:37 +02:00
ptitSeb d33d231120 Small hack to elfloader, so dosbox, unity3d and torchlight2 all seems to works now 2021-05-16 10:05:06 +02:00
ptitSeb 0c1ee23f55 Better log for my_open64 2021-05-12 10:34:03 +02:00
ptitSeb f5554dec6e [DYNAREC] Small fixes for BTC/BSR/BSF opcodes 2021-05-10 10:30:22 +02:00
ptitSeb 6239168118 [DYNAREC] Better race when jumping to nowhere for Trace enabled build 2021-05-10 10:29:31 +02:00
ptitSeb fe9fea0807 [DYNAREC] Small optim on NOT reg8bits opcode 2021-05-10 10:27:53 +02:00
ptitSeb d33917421b [DYNAREC] Fixed 66 0F C8..CF BSWAP opcode 2021-05-09 09:36:35 +02:00
ptitSeb 7c0b11e5e0 [DYNAREC] Added support for unaligned LOCK INC/DEC Ed opcode 2021-05-03 10:15:08 +02:00
ptitSeb 6a84e2eee9 Added support for unaligned LOCK INC/DEC Ed opcode 2021-05-03 10:07:59 +02:00
ptitSeb 26bad84244 Changed canary to have last byte NULL (not randomly placed) 2021-04-25 11:43:05 +02:00
ptitSeb eafd7081f3 Added some tips for winetricks desktop shortcut (for #380) 2021-04-25 10:30:00 +02:00
ptitSeb 2ad2851b2c Added basic support for Symbol Versionning (only consume, not generate yet), and use SymbolVersion on old pthread_cond* functions 2021-04-23 13:51:21 +02:00
ptitSeb f4924f6fd3 [DYNAREC] Added 66 0F F7 opcode 2021-04-23 08:24:36 +02:00
ptitSeb 78920a61ad Fixed some crash with wrapped libSDL_sound 2021-04-22 12:00:05 +02:00
ptitSeb 160f9f964f Added somesupport for R_386_TLS_TPOFF32 reloc (not sure it's 100% correct) 2021-04-22 11:36:55 +02:00
ptitSeb f81435cc2e Added 2 curl wrapped functions 2021-04-22 08:13:32 +02:00
ptitSeb 62df3cbe98 Added 1 more funciton to libSDL2 2021-04-21 15:29:58 +02:00
ptitSeb b0b000a3f2 Added Syscall 331 2021-04-20 20:39:04 +02:00
ptitSeb 9e244e068d Added some more gtk wrapped functions 2021-04-20 18:58:19 +02:00
ptitSeb 4a8d19da78 Another small change to custommem MaxFreeblock handling 2021-04-20 12:17:20 +02:00
ptitSeb 5a0fbcd7ba Fixed a typo in libatk-bridge-2.0.so.0 wrapping 2021-04-19 19:40:44 +02:00
ptitSeb 1ca20269b7 Improvments to ElfLoader Reloc handling 2021-04-19 14:44:26 +02:00
ptitSeb 5b3eb577fc Fixed a small issue with Custom Mem handler and MexFreeBlock calculation 2021-04-19 14:44:09 +02:00
ptitSeb 337d08d466 Added a few more FreeType wrapped functions 2021-04-18 10:40:44 +02:00
ptitSeb e784c34cb4 [DYNAREC] Try to fix some problem when re-loading a lib 2021-04-17 18:09:27 +02:00
ptitSeb 525c54a035 Added wrapped libXft 2021-04-17 17:12:30 +02:00
ptitSeb 65cc054c9c Fixed signature for wrapped function syslog 2021-04-17 16:46:13 +02:00
ptitSeb 64639ae623 Better handling of long double 2021-04-17 13:21:24 +02:00
ptitSeb 74fb70a675 [DYNAREC] Hack for sequence of FLD / FSTP tbytes 2021-04-17 13:20:58 +02:00
ptitSeb ca142fbc56 Use actual curl4 wrapping for curl3 2021-04-16 15:34:28 +02:00
ptitSeb af498728b0 Better trace for semop 2021-04-16 15:34:08 +02:00
ptitSeb a68c5dc00e Added DF D0..D7 opcodes 2021-04-16 08:10:24 +02:00
ptitSeb 7e279e1963 Added 65 40..4F opcodes 2021-04-15 16:20:50 +02:00
ptitSeb 01395347ce Added F3 C0/D0 ocpodes 2021-04-15 16:20:28 +02:00
ptitSeb b5493c779f [DYNAREC] fixed x86size of dynablock sons 2021-04-15 14:11:34 +02:00
ptitSeb 919b071990 Small improvement on custommem handlier 2021-04-15 14:11:02 +02:00
ptitSeb 46a9718d29 Fixed the unload of libs at exit 2021-04-15 13:08:30 +02:00
ptitSeb 82e3fbfbad Better wrapping and trace for __vsprintf_chk 2021-04-15 11:22:35 +02:00
ptitSeb 9004d2b80f Update FUNDING.yml 2021-04-15 10:48:20 +02:00
ptitSeb ddb91106c2 Merge pull request #377 from rajdakin/libFreeOrder
Libraries free order fix
2021-04-14 20:19:55 +02:00
rajdakin 9d7505a61c Fixed the exit crash... 2021-04-14 20:12:09 +02:00
rajdakin e1140c0401 (Hopefully) fixed the library freeing ordering (avoid crash) 2021-04-14 20:06:21 +02:00
ptitSeb 76a0d9bfa3 Also handle internal mutex in my_sighandler 2021-04-14 18:05:44 +02:00
ptitSeb a015c7a368 [DYNAREC] Fixed MVN emitter 2021-04-14 17:36:04 +02:00
ptitSeb 329ed0bb5b Merge pull request #376 from rajdakin/fix11
Stabilized test 11
2021-04-14 11:16:00 +02:00
rajdakin c3bc2808e9 Stabilized test 11 2021-04-14 10:42:50 +02:00
ptitSeb 584586dea8 Added wrapped libSDL_net-1.2.so 2021-04-14 08:53:03 +02:00
ptitSeb 8f84f73162 Added wrapped libSDL2_net-2.0.so (backported from box64) 2021-04-14 08:41:05 +02:00
ptitSeb ce3bf7151a Added wrapped libSDL_sound-1.0.so.1 2021-04-14 08:36:24 +02:00
ptitSeb 5cb5eb296d Merge pull request #375 from rajdakin/addDoc
Added documentation to the python scripts
2021-04-14 07:51:12 +02:00
rajdakin 336b0a42e9 Added a pseudo-documentation for the second generator 2021-04-13 22:32:13 +02:00
ptitSeb a32af2cf76 Adjusted Youtube channels comment on README 2021-04-13 22:21:34 +02:00
rajdakin 307a4f5010 Automated libbz2 and libcrypto 2021-04-13 22:15:11 +02:00
rajdakin 5320b4f22f Added some documentation 2021-04-13 22:14:41 +02:00
ptitSeb 70a1d452f3 Merge pull request #374 from rajdakin/mergeBox64
Improved box86 a bit, added an automation
2021-04-13 21:26:05 +02:00
rajdakin 61869a91c7 Re-added AuxVec 32 (vsyscall) 2021-04-13 21:12:26 +02:00
rajdakin 68bc003fd2 Improved box86 a bit, added an automation 2021-04-13 20:59:32 +02:00
ptitSeb f29912620d Fixed Non-Android build 2021-04-13 18:22:02 +02:00
ptitSeb 4a780af9fe Merge pull request #372 from io12/android
Initial Android support attempt
2021-04-13 17:56:47 +02:00
Benjamin Levy 6b6e6c874b Initial Android support attempt 2021-04-13 10:46:28 -04:00
ptitSeb d42d067945 Enable TokiTori2+ patch for RK3399 too 2021-04-13 11:46:24 +02:00
ptitSeb 17e80a3a09 Added a few syscall around inotify 2021-04-13 10:53:09 +02:00
ptitSeb 674c5b5819 Added wrapped libatk-bridge-2.0.so 2021-04-13 09:36:37 +02:00
ptitSeb 01629e1faf Some function signatures changes and fixed (backported from box64) 2021-04-12 18:34:36 +02:00
ptitSeb 38a33ab15b Fixed 0F E3 opcode 2021-04-11 16:38:08 +02:00
ptitSeb 2163365115 Improvement in internal mutex handling on signal, and [DYNAREC] multitasking changes to the JmpTable 2021-04-11 12:04:41 +02:00
ptitSeb f67902f098 Added F3 A0/E0 opcodes 2021-04-11 08:49:03 +02:00
ptitSeb bfe47b408d Removed a useless definition 2021-04-10 16:12:35 +02:00
ptitSeb aa2bea2d84 Fixed non-Dynarec build 2021-04-10 16:12:20 +02:00
ptitSeb 40c5b1b8d3 Added F3 80 opcode ([DYNAREC] too) 2021-04-10 08:13:35 +02:00
ptitSeb ee714259df Added wrapped GtkWindowClass 2021-04-08 14:26:42 +02:00
ptitSeb aa7b620d8e Some add/changes to libcrypto (for 1.0.2 on 1.1 emulation) 2021-04-07 15:24:59 +02:00
ptitSeb 794c16644b [DYNAREC] Ok, need to save D8..D15 in prolog / restaor them in epilog, they are callee saved 2021-04-07 13:20:02 +02:00
ptitSeb dda64c5b5e And another fix for potential deadlock (after a fork) 2021-04-06 11:55:55 +02:00
ptitSeb 6784a79db0 Fixed SDL AudioSpec structure definition 2021-04-06 11:01:53 +02:00
ptitSeb 564dfea143 Fixed some potentiel deadlock with bridge creation 2021-04-06 08:16:05 +02:00
ptitSeb 7e9f514d8b Removed a debug leftover 2021-04-05 18:38:23 +02:00
ptitSeb 68809a753d Added some more GL wrapped functions 2021-04-05 17:45:02 +02:00
ptitSeb 4ba390abd6 [DYNAREC] On useless test, store the values so defered flags can be computed 2021-04-05 17:44:42 +02:00
ptitSeb fe2b4cb8f3 Improve end of a program (backported frm box64) 2021-04-05 17:43:48 +02:00
ptitSeb dbef73bd75 Fix potential issue on GL when used via SDL2 only 2021-04-05 15:14:37 +02:00
ptitSeb ec19cc1e41 Removed a debugg leftover 2021-04-05 11:06:40 +02:00
ptitSeb 63e099a912 [DYNAREC] Added 66 87 and 66 0F C1/C8..CF opcodes 2021-04-05 11:04:57 +02:00
ptitSeb 282309ee9b Ignore a segfault on access when everything seems fine (probably a multitask glitch, makes linux Terraria works 2021-04-04 22:33:15 +02:00
ptitSeb bd48cae19f Simplified signal handling and [DYNAREC] Simplified dynablock/memory handling (backported from box64) 2021-04-04 18:17:24 +02:00
ptitSeb b2d8a5ceb8 Ooops, this typo must have broken some multitrheads apps 2021-04-04 15:17:48 +02:00
ptitSeb 438677e61a Small changes, mostly cosmetics ([DYNAREC] too) 2021-04-04 15:17:23 +02:00
ptitSeb 44a7535791 Added wrapped FcFreeTypeCharIndex to libfontconfig 2021-04-01 21:57:44 +02:00
ptitSeb 2117a62dc1 Added libdl.so as a dependancy to libGL.so 2021-04-01 21:06:25 +02:00
ptitSeb 99c27bed99 Added wrapped FcCharSetCount function to libfontconfig 2021-04-01 21:03:49 +02:00
ptitSeb 161cd9dc3f [DYNAREC] Change dlog level of this message (to much spam on LOG_INFO) 2021-04-01 18:57:00 +02:00
ptitSeb 0228fcd7d3 Added wrapped FcNameRegisterObjectTypes function to libfontconfig 2021-04-01 16:23:34 +02:00
ptitSeb 3da4e03ddc Merge pull request #367 from rajdakin/fix_rootc
[CMAKE] Fixed builds with '.c' in the path
2021-03-28 20:05:11 +02:00
rajdakin 8030af55b8 [CMAKE] Fixed builds with '.c' in the path 2021-03-28 20:01:56 +02:00
ptitSeb ee757c117c Use a simple pthread_exit wrapping, to not mess with pthread cancel stuff 2021-03-28 17:30:11 +02:00
ptitSeb a93665abf4 Fixed a warning 2021-03-28 14:05:24 +02:00
ptitSeb e3c39f4f97 Better handling of Stacks 2021-03-28 14:03:50 +02:00
ptitSeb 9bf5c20a9a Reworked README a bit 2021-03-27 19:48:55 +01:00
ptitSeb c02a069c5e Fixed aio_suspend64 function signature (fixing file transfert for TeamSpeak Server) 2021-03-27 19:15:08 +01:00
ptitSeb e5bf05c5c2 [DYNAREC] Better handling of bridge 2021-03-27 19:14:17 +01:00
ptitSeb 017d82d16e [DYNAREC] Removed lock on Memory Protection, and change Dynarec generation to have anticiped ending if a block already exist for next address (should help C# and Unity3D softwares) 2021-03-27 12:50:20 +01:00
ptitSeb 5f6d75da12 Added libudev1 as alternative to libudev0 2021-03-27 08:29:07 +01:00
ptitSeb 633919dd74 Small changes t libc and libdbus 2021-03-27 08:00:56 +01:00
ptitSeb e83a119cbb Added one more symbol from libfontconfig 2021-03-26 14:21:49 +01:00
ptitSeb 00ac8ec1aa Added some symbols from SDL2.0.12 and 2.0.14 2021-03-26 14:21:05 +01:00
ptitSeb 491f111caf [DYNAREC] Fixed F3 0F BC opcode 2021-03-25 15:07:52 +01:00
ptitSeb 8e92453f4c Cosmetic changes to some wrapped function signatures from libresolv 2021-03-25 13:58:06 +01:00
ptitSeb bc198c37d7 Improve shutdown sequence 2021-03-25 11:48:46 +01:00
ptitSeb 5ab84a6e78 Minor cosmetic changes to some libc wrapped functions signatures 2021-03-25 11:48:31 +01:00
ptitSeb 334080dfd0 Merge pull request #363 from Jai-JAP/patch-1
Add RPI4ARM64 compiling instructions.
2021-03-25 07:56:06 +01:00
Jai-JAP 46012a6a8c Update COMPILE.md
Add RPI4ARM64 compiling instructions.
2021-03-25 10:45:40 +05:30
ptitSeb 3b546a6048 Smale cosmetic changes 2021-03-24 19:28:52 +01:00
ptitSeb 522b8d5fc0 Fix non-Dynarec build that would crash at start 2021-03-24 19:28:52 +01:00
ptitSeb 74d3bb76da Various small (cosmetics) fixes 2021-03-24 11:42:28 +01:00
ptitSeb a28080e065 Better mecanism for pthreard_once callback handling 2021-03-24 11:42:09 +01:00
ptitSeb 638b341ba5 Avoid potential deadlock on bridge creation with dynarec (may help #217) 2021-03-18 14:26:05 +01:00
ptitSeb c254dc3121 Made the mutex for memory protection recursive, to try mitigate lock on #217 2021-03-17 08:43:43 +01:00
ptitSeb fe0778656b [DYNAREC] cosmetic change 2021-03-17 08:42:42 +01:00
ptitSeb e478b99307 [DYNAREC] Fixed NEON used reg push/pop when calling C function from dynablock 2021-03-15 13:47:59 +01:00
ptitSeb 9d2cd89a7c [DYNAREC] Fixed comment on dynarec on CMake project 2021-03-15 13:47:15 +01:00
ptitSeb be82ccbfcd Merged MMX and x87 regs (like in actual hardware) 2021-03-13 19:13:30 +01:00
ptitSeb 18dfbb61b4 Fixed a few minor leaks 2021-03-13 16:43:29 +01:00
ptitSeb 0f8e39d785 Another batch of various fix, mostly cosmetics 2021-03-13 14:36:02 +01:00
ptitSeb c4fdf490a2 Improve handling of rounding of SSE ([DYNAREC] too) 2021-03-13 08:56:10 +01:00
ptitSeb 55764011db Fixed png16 wrapped png_create_read_struct function signature 2021-03-13 08:51:03 +01:00
ptitSeb 9a483890b6 Merge pull request #360 from WheezyE/patch-3
Update X86WINE.md
2021-03-11 21:35:01 +01:00
Eric Wiessner (KI7POL) 4421377624 Update X86WINE.md
Fixed a typo in the example code section (downloaded libfaudio twice).  Also made more small cosmetic changes.
2021-03-11 13:32:55 -07:00
ptitSeb f817d06e14 Added a workaround for the '...' of g_set_error wrapped function 2021-03-11 17:37:46 +01:00
ptitSeb 6b0b389a69 Merge pull request #359 from Itai-Nelken/patch-1
Improve X86WINE.md
2021-03-10 20:33:07 +01:00
Itai Nelken 496899ffe3 Update X86WINE.md 2021-03-10 21:28:07 +02:00
ptitSeb 7a05331e76 Merge pull request #358 from WheezyE/patch-1
Update X86WINE.md
2021-03-10 19:58:34 +01:00
ptitSeb e7e725cb5e Merge pull request #357 from WheezyE/patch-2
Update README.md
2021-03-10 19:57:39 +01:00
Eric Wiessner (KI7POL) 8385f6ad4e Update README.md
Added Wine installation instructions
2021-03-10 11:19:18 -07:00
Eric Wiessner (KI7POL) aeb3f7a438 Update X86WINE.md
Moved things around a little for readability
2021-03-10 11:13:28 -07:00
ptitSeb d9fa04d2ed Merge pull request #356 from meveric/master
working on glib2 and png16
2021-03-10 11:29:03 +01:00
meveric d4b5e585d1 fixing typos 2021-03-10 10:09:02 +00:00
meveric 8579037bb1 copied symbols from png12 to png16 2021-03-10 09:59:48 +00:00
ptitSeb 13cce1a4dd Various (mostly cosmetics) adjustments to wrapped functions signature 2021-03-09 21:52:07 +01:00
meveric 5724dfad87 wrapped g_cond_init, g_cond_clear, g_cond_wait of glib2 2021-03-09 20:02:53 +00:00
ptitSeb f370bf77a8 [DYNAREC] Better handling of SMC dynablocks 2021-03-08 14:52:17 +01:00
ptitSeb fc3540ac08 Fixed libGLU callback wrapped function, and added libalure wrapped (was ready for a long time in fact) 2021-03-07 18:17:59 +01:00
ptitSeb c16f361c4a Refined .gitignore for TwisterOS Armbian 2021-03-07 17:14:49 +01:00
ptitSeb 92a0f507af Small cosmetics changes in signal handler 2021-03-07 16:54:28 +01:00
ptitSeb 6bb7cdbdd4 Some small improvment on interpretor fow a few MMX opcodes 2021-03-07 16:34:07 +01:00
ptitSeb 1809a2bac3 Small adjustments to pthread cancel handling and a few libc functions signatures 2021-03-07 14:20:44 +01:00
ptitSeb 430658c1a4 Merge pull request #353 from WheezyE/patch-1
Update X86WINE.md
2021-03-07 07:54:17 +01:00
Eric Wiessner (KI7POL) 746383b72b Update X86WINE.md
Just tidying things up a bit more.
2021-03-06 19:52:25 -07:00
ptitSeb d244151ca2 Added 65 13 ADC Gd,GS:Ed opcode (for #349) 2021-03-06 09:20:42 +01:00
ptitSeb e4c1626638 Fix a build error with NOALIGN 2021-03-06 09:20:11 +01:00
ptitSeb c07cee0d01 Merge pull request #350 from WheezyE/patch-1
Create X86WINE.md
2021-03-06 09:16:23 +01:00
Eric Wiessner (KI7POL) 43132bd9b0 Create X86WINE.md
Installation and use of x86 Wine for Box86
2021-03-05 23:37:21 -07:00
ptitSeb ed982e1d2c [DYNAREC] Fixed NotEqual on float/double SSE flag handling (help ut99 build 469) 2021-03-05 16:18:35 +01:00
ptitSeb 7420ea052d Small fix on atol function signature 2021-03-05 15:02:10 +01:00
ptitSeb 044326d337 Added 65 0F B6 opcode 2021-03-03 20:07:42 +01:00
ptitSeb 96c126bbcc Update Zydis header to latest version 2021-03-03 18:55:26 +01:00
ptitSeb ba0e524805 Merge pull request #348 from mobilegmYT/patch-1
Move install instructions higher up and add pi-apps mention
2021-03-02 19:40:57 +01:00
RPI News ba19f56338 Add RPI to pi-apps 2021-03-02 11:26:59 -07:00
RPI News 14df602fa4 Moved install instructions higher up and added pi-apps 2021-03-01 20:06:47 -07:00
ptitSeb d972e205ac Fixed jpeg62 compress issue (should help #343, WeChat and other Wine app that create jpeg with windowscodec) 2021-02-27 16:31:04 +01:00
ptitSeb 114f2b8cd2 Wrapped libtiff.so.5 (minimal set of functions for Wine) 2021-02-27 16:31:04 +01:00
ptitSeb 87f8830d16 [DYNAREC] Fixed DD /1 FISTTP opcode (fixed WK issue) 2021-02-26 11:21:43 +01:00
ptitSeb a0afe05995 [DYNAREC] Added new option BOX86_NODYNAREC to forbid creation of Dynablock in an interval range (to debug difference between Dynarec and Interpretor) 2021-02-26 10:16:35 +01:00
ptitSeb ddd4d37ad1 Merge pull request #345 from SpacingBat3/patch-2
Fixed link to "x86primop.c".
2021-02-25 20:53:14 +01:00
SpacingBat3 ede296ef01 Fixed link to "x86primop.c".
It seems that original link has been broken earlier and I haven't checked that earlier.
This commit should change that.
2021-02-25 20:07:29 +01:00
ptitSeb 1307ce364d [DYNAREC] Small fix for previous commit, adjusting ARM PC 2021-02-25 13:54:34 +01:00
ptitSeb 37fa84d762 [DYNAREC] Get a warning on trace build when jump to NULL address (with some info of the origin of the jump) 2021-02-25 13:46:06 +01:00
ptitSeb b3e984bd22 More fixes to elfloader when hinted memory is not satisfied 2021-02-23 18:43:26 +01:00
ptitSeb 7da5b9b7eb Added some log for elfloader with ET_DYN and hinted addr 2021-02-23 18:36:30 +01:00
ptitSeb 55b979f656 More try at fixing elfloader with ET_DYN that have hinted vaddr 2021-02-23 18:04:18 +01:00
ptitSeb 815a6c3ade More fixes to elfloader for ET_DYN type of elf 2021-02-23 16:04:01 +01:00
ptitSeb 33db7a8005 New change on elfloader and mmap handling 2021-02-23 15:18:49 +01:00
ptitSeb 963ac3039e Deactivated wine_prereserve if not wine_preloaded 2021-02-23 12:09:37 +01:00
ptitSeb 552db005b1 [DYNAREC] Fixed a compilation warning 2021-02-23 09:49:47 +01:00
ptitSeb 2d1e8cf1f2 Deactivated wine_preload again, the order between lib load and wine_preload doesn't seem correct 2021-02-23 07:51:30 +01:00
ptitSeb 8e44e8bf13 Fixed elfloader when using wine_preload (which need MAP_FIXED on mmap) 2021-02-22 22:02:56 +01:00
ptitSeb e7cc7b3409 [DYNAREC] quick fix to the ARM->x87 flags conversion improvment 2021-02-22 20:12:11 +01:00
ptitSeb 4e5473150a Use mmap for custommem (hardcoded optionnal for now), and improve JMPTABLE, DYNAMAP and MEMPROT memory handling 2021-02-22 19:10:09 +01:00
ptitSeb e8e7597c62 Reactivated and improved wine_loader detection and wine_prereserve mecanism 2021-02-22 19:10:09 +01:00
ptitSeb f9b03600d1 Added an error if elfloader mmap are not at the requested address 2021-02-22 19:10:09 +01:00
ptitSeb 88a8ebb1dc Removed the MAP_FIXED flag to elfloader mmap (maybe need to add a warning if allocated mem is at a different location?) 2021-02-22 19:10:09 +01:00
ptitSeb 4445785ee1 [DYNAREC] Improved the CALL 0 hack to make it more generic 2021-02-22 19:10:09 +01:00
ptitSeb 3b3460cbba [DYNAREC] Removed a useless opcode in FNSTSW AX opcode 2021-02-22 19:10:09 +01:00
ptitSeb 7eb6789a25 [DYNAREC] Fixed a warning 2021-02-22 19:10:09 +01:00
ptitSeb 870fed75ad [DYNAREC] Fixed ARM->x87/SSE flag conversion 2021-02-22 19:10:09 +01:00
ptitSeb 833c2809d9 Merge pull request #340 from SpacingBat3/patch-1
Some documentation fixes and improvements.
2021-02-22 09:55:25 +01:00
SpacingBat3 24ec881fe5 Update COMPILE.md
Use "make" command with a parallel jobs limited to the number of the CPU threads for "ODROID", "Other ARM Linux platforms" and "x86 Linux" (which should speed up compiling process for these platforms).
2021-02-20 13:31:06 +01:00
SpacingBat3 d7d7bc91a2 A fix for broken link in README.md
There was one broken link (pointing to `docs/src/` instead to `docs/`).
2021-02-20 12:43:58 +01:00
ptitSeb 1ea8dc828a Merge pull request #339 from SpacingBat3/master
Moved the documentation to "docs/" folder.
2021-02-19 11:53:32 +01:00
ptitSeb ade7d82e52 Test for mutex alignment on pthread_cond_timedwait and pthread_cond_wait 2021-02-18 11:45:31 +01:00
ptitSeb fa5c6652b6 [DYNAREC] Small change to LOCK XADD 2021-02-18 11:44:41 +01:00
ptitSeb a5ab6b1520 Added better way to generate SIGILL (and added 0F 3F Illegal Opcode) 2021-02-18 09:41:28 +01:00
ptitSeb bf74640917 [DYNAREC] Some speedup of signal handling, to help C# and Mono stuffs 2021-02-17 18:18:04 +01:00
ptitSeb 420d309db6 Some more fixes to elfloader (to get both CMR and Potatoman running) 2021-02-17 18:17:13 +01:00
ptitSeb c4d170ebb8 Added 3 data in glib2 wrapped lib 2021-02-17 17:54:06 +01:00
ptitSeb 9cc69095d5 Some fixes to elfloader (fixes SuperHexagon, maybe more) 2021-02-16 14:42:33 +01:00
SpacingBat3 eb5dd2c005 Moved the icon/logo to the "docs/img/" folder. 2021-02-16 14:21:44 +01:00
SpacingBat3 39fbbe61a3 Moved documentation to "docs/" folder. 2021-02-16 14:01:57 +01:00
ptitSeb ba71080fb2 Fixed a warning on threads 2021-02-15 11:41:44 +01:00
ptitSeb db176ad3e3 Update CHANGELOG.md 2021-02-11 21:08:29 +01:00
ptitSeb 002638ef96 Added _pthread_cleanup_pop and _pthread_cleanup_push wrapped function to pthreads lib 2021-02-10 14:33:55 +01:00
ptitSeb 22b74477ac Fixed vfprintf wrapped function for non POWERPCLE build 2021-02-10 14:33:16 +01:00
ptitSeb 9c5a9ebba7 [DYNAREC] Don't allocate too much memory blindly 2021-02-09 16:56:58 +01:00
ptitSeb fce3f38e3a [DYNAREC] Fixed previous optim on mem protectio handling for some special cases 2021-02-09 16:09:05 +01:00
ptitSeb aabb600aed [DYNAREC] Some optimisation with memory protection managment 2021-02-09 14:41:29 +01:00
ptitSeb a062a8efa6 Fixed many SDL2 issue with RWops 2021-02-08 20:18:58 +01:00
ptitSeb 9b690667dc Fixed a warning 2021-02-08 16:18:26 +01:00
ptitSeb de7897c5c2 Wrapped custom mremap to handle memory protection 2021-02-08 14:20:21 +01:00
ptitSeb d3d431d5b1 Improve memory protection managment and multi-threads 2021-02-08 14:19:49 +01:00
ptitSeb 6409f5d40a Merge branch 'master' of https://github.com/ptitSeb/box86 2021-02-08 13:09:11 +01:00
ptitSeb aeab3c815e Improved handling of R_386_COPY and R_386_GLOB_DAT reloc in elfloader (helps c++ progs) 2021-02-08 13:08:36 +01:00
ptitSeb 4837797fae Merge branch 'master' of https://github.com/ptitSeb/box86 2021-02-08 09:59:51 +01:00
ptitSeb 0ffc8682b1 Wrapped libcrypt.so.1 2021-02-07 16:21:01 +01:00
ptitSeb cb35a8d85c Merge branch 'master' of https://github.com/ptitSeb/box86 2021-02-06 14:11:07 +01:00
ptitSeb 5999255b5d Merge pull request #328 from rajdakin/rbit_clz
Added the CLZ and RBIT opcodes
2021-02-06 13:42:30 +01:00
rajdakin a7654c6a80 [PRINTER] Added the CLZ and RBIT opcodes 2021-02-06 13:39:10 +01:00
ptitSeb 2b3791f701 Fixed 2 wrapped functions signature from libudev.so.1 2021-02-06 13:31:42 +01:00
ptitSeb 7f52a18fac Simplified (again?) cancel thread handling 2021-02-05 12:36:44 +01:00
ptitSeb ff8bb3b2e4 [DYNAREC] Changed a bit how arm_lock_storeifnull works 2021-02-05 12:35:23 +01:00
ptitSeb 5b7cc6d4de Improved detection of non-libc header when building elfload_dump.c (should help #327) 2021-02-05 11:37:50 +01:00
ptitSeb 1d9774c913 [DYNAREC] Fixed shrd32c and shld32c emiter when used with c > 0x1f (helps WeChat #324) 2021-02-04 13:28:17 +01:00
ptitSeb 8b13ba26d7 [DYNAREC] Removed a useless opcode on 0F C0 XADD 2021-02-04 13:27:05 +01:00
ptitSeb 8730f4daa6 Merge pull request #325 from MichaIng/patch-1
Update notes about Steam
2021-02-03 12:03:15 +01:00
MichaIng 52f4d2a1a6 Update notes about Steam
The "Remember password" feature works only if libnm is installed, otherwise the next starts hang infinite.

Steam can be started with the small mode mini games list opened directly by using the "+open steam://open/minigameslist" command line arguments.

The Steam for Linux issues have been sorted into a listing, to get a better overview and separation between each issues. The Steam for Windows note has been mode below the list.

A few minor spelling and wording fixes have been applied: "Steam" always with capital S, full sentences, aligned package install instruction on Debian.

Signed-off-by: MichaIng <[email protected]>
2021-02-03 11:39:25 +01:00
ptitSeb 6a498c373c Creation of new bridge is now protected by a mutex 2021-02-02 15:49:03 +01:00
ptitSeb 007c7a887e Added 64 9C PUSHFD opcode (ignoring 64 prefix) 2021-02-02 09:44:28 +01:00
ptitSeb 922a8864e8 [DYNAREC] Optimized 0F BA opcodes 2021-02-01 17:17:24 +01:00
ptitSeb 16383f4577 [DYNAREC] Added 66 0F BA BT/BTS/BTR/BTC Ew, Ib opcodes 2021-02-01 17:17:06 +01:00
ptitSeb bc66bb5be9 [DYNAREC] Added handling of null-sized Dynablock (fixed avgn, maybe other too) 2021-02-01 15:13:32 +01:00
ptitSeb 84360f24c1 Another change on Elfloader to help loading c++ programs 2021-01-31 10:36:34 +01:00
ptitSeb cad160205f Fixed wrapped libusb transfert callbacks (should help #323) 2021-01-30 13:16:05 +01:00
ptitSeb 807519e3c4 Small change to elfloader to help Unity3D games, hopefully without breaking something else 2021-01-29 16:31:54 +01:00
ptitSeb 425ffb6e68 Added an empty crashhandler wrapped lib specific to steam (should help steam stability a bit) 2021-01-28 16:59:43 +01:00
ptitSeb 0ede6b8fa5 Various small fixes are warning removal (especialy for non-dynarec build) 2021-01-28 15:38:39 +01:00
ptitSeb 381d723462 Added preloaded libasan handling (same as libtcmalloc_minimum) 2021-01-28 15:31:05 +01:00
ptitSeb cad8de8cd8 [DYNAREC] Pre-calc entry point for thread only if dynarec is activated 2021-01-28 09:40:19 +01:00
ptitSeb 7d7d275e7e [DYNAREC] Sligtly improved dynarec log at DEBUG level 2021-01-28 09:39:29 +01:00
ptitSeb 80db7d9a21 [DYNAREC] Free all dynablockslist when exiting 2021-01-28 09:38:38 +01:00
ptitSeb d8943af79a [DYNAREC] Changed log level of the Wild block appear warning 2021-01-27 14:51:45 +01:00
ptitSeb bcbf9360af Small leak fix in pathcoll sources 2021-01-27 14:51:13 +01:00
ptitSeb 6320b0928e Improved handling of RPATH 2021-01-27 08:20:35 +01:00
ptitSeb 74afa2551a [DYNAREC] Fixed PF flag computation for TEST opcode that was broken a few commit ago 2021-01-26 15:34:40 +01:00
ptitSeb dd733c4128 [DYNAREC] Some more fixes for special cases in the handling of memory protection (should help #227) 2021-01-25 20:09:12 +01:00
ptitSeb 0eaa1b6c5e Added F3 50..62 opcodes 2021-01-24 16:45:24 +01:00
ptitSeb f595859cf0 [DYNAREC] Small optim on LL/GE/LE/G flahs handling 2021-01-24 16:26:10 +01:00
ptitSeb 85e0d01451 Some fixes for some BOX86_LOG=2 function call details 2021-01-24 15:24:53 +01:00
ptitSeb ec57e035d6 [DYNAREC] Small optim to avoidDefered flag handling when doing ADD/SUB on ESP with a constant 2021-01-24 13:54:21 +01:00
ptitSeb 0d0b4d7364 [DYNAREC] More work on logic and shift emiters and PF flag handling 2021-01-24 12:19:38 +01:00
ptitSeb aeb91fce74 [DYNAREC] Small optim of CF and ZF flag handling on emiters 2021-01-23 12:18:57 +01:00
ptitSeb e163bd842e [DYNAREC] Small optim on MOV32 pseudo arm opcode 2021-01-23 11:45:07 +01:00
ptitSeb 2ff7bd1bc7 [DYNAREC] Small optim on AND32c emiter 2021-01-23 10:45:22 +01:00
ptitSeb 533c703b0d [DYNAREC] Remove workaround for Unreal FMOD SMC code in 81 CMP i32 opcode as it's not more needed 2021-01-23 10:05:25 +01:00
ptitSeb 1d1a82f529 [DYNAREC] Small optim to LEA opcode 2021-01-23 09:50:29 +01:00
ptitSeb 911b95a505 [DYNAREC] Remove dynarec linker mecanism and use generic TableJump instead (also all memory that have a dynablock is protected now, should improve compatibility with C# and program taht use SelfModifyCode) 2021-01-22 16:16:12 +01:00
ptitSeb 8209cf8398 [DYNAREC] Fix a bug when freeing a large dynablock allocation 2021-01-21 18:35:21 +01:00
ptitSeb 02423d4a2d [DYNAREC] Small optim on JumpTable reset function 2021-01-21 16:10:47 +01:00
ptitSeb ba5c13fb6c [DYNAREC] Fixed previous commit, PvZ work again now 2021-01-21 15:58:33 +01:00
ptitSeb ddd13bcab0 [DYNAREC] Removed CALL/RET optimization and replace it with a generic JumpTable mecaniism (get a 10% speedup minimum, probably much more on Wine software) 2021-01-21 11:23:45 +01:00
ptitSeb 3b6800e38e Fixed some warning in RunFS66 function 2021-01-20 12:19:15 +01:00
ptitSeb 6c2ebf91c0 [DYNAREC] Change log level for the Call to 0x0 Warning 2021-01-20 12:09:16 +01:00
ptitSeb a64d1de7cd Added a workaround for glXSwapIntervalMESA to have a stub function if it's not exposed 2021-01-20 10:05:56 +01:00
ptitSeb d6ce7f5c16 Some small changes and trace improvement around glXGetProcAddress and Int 3 2021-01-20 09:00:56 +01:00
ptitSeb 1fe29c512f Added some code to check alignment on mutex and use a aligned one if needed (it's good 99% of the time) 2021-01-19 13:43:24 +01:00
ptitSeb e76176b663 Changed a bit how 66 64 prefix is handled 2021-01-18 16:39:39 +01:00
ptitSeb acbe0527d7 Small improvment to Unimplemented Opcode log 2021-01-18 16:39:21 +01:00
ptitSeb 81d8f2f5c3 Changed 660F opcodes back to a switch (no reason to keep the array of label here) 2021-01-18 14:46:37 +01:00
ptitSeb 8976e77109 Various small improvments to 64 and 65 prefixed opcodes 2021-01-18 14:30:47 +01:00
ptitSeb 31bd7ebfbc Added support for FO 0F BA/5 BTS opcode ([DYNAREC] Too) and fixed some F0 opcodes too (helps #314) 2021-01-18 11:41:30 +01:00
ptitSeb 487b979842 Added some F4 HLT opcode implementation, not sure if it's the best way to do it 2021-01-17 17:12:28 +01:00
ptitSeb efd1408809 Improved log on Double Segfault 2021-01-16 15:30:10 +01:00
ptitSeb 867e8aaa00 Small change in signal handling to allow multiple time a memory protection on same address 2021-01-16 15:28:54 +01:00
ptitSeb e3e5fd7568 Added 65 06 and 65 07 opcodes 2021-01-15 20:08:34 +01:00
ptitSeb 7e6b012a08 Fixed 66 F0 xx opcodes 2021-01-15 18:43:13 +01:00
ptitSeb 546fe18836 Added F0 66 83 ocpcode (only 66 F0 83 was there before) 2021-01-15 16:09:37 +01:00
ptitSeb 1cb7683636 Merge pull request #311 from heavygabriel/master
Clarified a bit more documentation, fixed a lot of typos and removed some redundant codes.
2021-01-14 23:14:00 +01:00
heavygabriel f89c7faf3c Changed documentation per PtitSeb's code review. 2021-01-14 15:12:02 -05:00
heavygabriel cf36c668b3 Merge pull request #1 from ptitSeb/master
sync fork with box86
2021-01-14 14:38:24 -05:00
ptitSeb dd41352392 Added 64 67 3B opcode (for #304) 2021-01-13 19:36:16 +01:00
ptitSeb ec42322f23 Start of a new dev. cycle 2021-01-13 19:35:27 +01:00
heavygabriel 3b8a9b5cc5 Fixed a few typos in README.md 2021-01-12 17:12:12 -05:00
heavygabriel 6d3b2fe902 Simplified some code. 2021-01-12 17:04:27 -05:00
heavygabriel 819ec41320 Updated Copyright year 2021-01-12 16:42:48 -05:00
heavygabriel 40fd950b40 Reworded a bunch of stuff, added consistent formatting and fixed typos. 2021-01-12 16:34:08 -05:00
heavygabriel 4f64c106a7 Removed a bunch of typos, reformulated a big batch of sentences. 2021-01-12 14:32:33 -05:00
ptitSeb b2d5587ea1 Bumped to v0.2.0 2021-01-12 19:44:14 +01:00
ptitSeb 4b020ab4f5 Merge pull request #309 from heavygabriel/master
Simplified code
2021-01-11 19:43:05 +01:00
heavygabriel 088a85c125 Update COMPILE.md 2021-01-11 11:45:54 -05:00
heavygabriel 2bf60dc00d Removed some typos. 2021-01-11 11:39:04 -05:00
unknown b5ffa0e92a Simplified a bunch of ifs and elses 2021-01-11 10:21:01 -05:00
ptitSeb 258f7f9b50 Added BOX86_NOVULKAN to disable loading of vulkan libs 2021-01-10 11:24:55 +01:00
ptitSeb 07c403243d Added 66 CB opcode 2021-01-10 11:03:19 +01:00
ptitSeb 709de6a858 Fix compilation for build without Dynarec 2021-01-09 19:35:41 +01:00
ptitSeb dfed557f61 [DYNAREC] Fixed SAKF opcode, and improved a but flag handling (fixing regression on GIG Installer from Dec. 30th commit) 2021-01-09 17:36:27 +01:00
ptitSeb f143771be8 Merge pull request #303 from heavygabriel/master
Remove the //TODO: in USAGE.md
2021-01-08 19:20:00 +01:00
heavygabriel fc20c410c0 Delete TROUBLESHOOTING.md 2021-01-08 10:23:37 -05:00
heavygabriel 677205a288 Update USAGE.md
removed //TODO:
2021-01-08 09:17:37 -05:00
heavygabriel abb9acfd42 Create TROUBLESHOOTING.md
Information on how to solve specific problems.
2021-01-08 09:16:29 -05:00
ptitSeb 75dca68db0 Fixed custom allocator for memory block >= 256k (should help old 32bits Factorio, and maybe #274) 2021-01-08 09:53:03 +01:00
ptitSeb 5c1a8ad128 Fixed USAGE.md, default log is now 0 2021-01-08 09:51:44 +01:00
ptitSeb e4cf8f8c94 Merge pull request #302 from heavygabriel/master
Updated documentation
2021-01-08 07:49:19 +01:00
heavygabriel 30968917a4 Merge pull request #7 from heavygabriel/patch-7
Update USAGE.md
2021-01-07 18:59:11 -05:00
heavygabriel 84ea9e3301 Merge branch 'master' into patch-7 2021-01-07 18:59:02 -05:00
heavygabriel 1f9c046919 Merge pull request #6 from heavygabriel/patch-8
Update USAGE.md
2021-01-07 18:48:28 -05:00
heavygabriel cefe210184 Merge pull request #5 from heavygabriel/patch-9
Update USAGE.md
2021-01-07 18:47:29 -05:00
heavygabriel 02aa791fd9 Merge pull request #4 from heavygabriel/patch-10
Update COMPILE.md
2021-01-07 18:45:58 -05:00
heavygabriel d8c1341068 Merge pull request #2 from heavygabriel/patch-2
Patch 2
2021-01-07 18:45:14 -05:00
heavygabriel ca648ea128 Merge pull request #3 from heavygabriel/patch-3
Patch 3
2021-01-07 18:43:43 -05:00
heavygabriel daf5a9d91d Merge pull request #1 from heavygabriel/patch-1
Patch 1
2021-01-07 18:43:02 -05:00
heavygabriel 16b95f2088 Update COMPILE.md
Added further clarifications, fixed typos ,etc.
2021-01-07 18:38:26 -05:00
heavygabriel 41dfcb559a Update USAGE.md
Added a bit of documentation, fixed things, etc. (This really needs some love, can anyone better suited for the task contribute? thanks.
2021-01-07 18:32:11 -05:00
heavygabriel 37c871ec2e Update USAGE.md
Added a bit of documentation, fixed things, etc. (This really needs some love, can anyone better suited for the task contribute? thanks.
2021-01-07 18:31:18 -05:00
heavygabriel 34bd1ff42f Update USAGE.md
Added a bit of documentation, fixed things, etc. (This really needs some love, can anyone better suited for the task contribute? thanks.
2021-01-07 18:30:34 -05:00
heavygabriel e0f1d4fecf Update README.md
Changed how things are worded (again again+3 ) . Added some new clarification in the documentation (Need to see how to reword the box86 discord mentionning thingy) etc.
2021-01-07 18:16:37 -05:00
heavygabriel c94d992ef6 Update README.md
Changed how things are worded (again again+3 ) . Added some new clarification in the documentation (Need to see how to reword the box86 discord mentionning thingy) etc.
2021-01-07 18:16:34 -05:00
ptitSeb bfe83d827d Fixed a potential BUSERROR on 66 0F 12 opcode 2021-01-07 19:44:06 +01:00
ptitSeb 1c45795828 Merge pull request #298 from heavygabriel/patch-1
Update README.md
2021-01-07 16:09:30 +01:00
heavygabriel 8dc5c164d8 Update README.md
again, updated typos.
2021-01-07 09:34:47 -05:00
heavygabriel 326032aa23 Update README.md
Changed the notes for raspberry pi a bit, changed how the unity section is worded and generally changed small little typos and things.
2021-01-07 09:24:25 -05:00
ptitSeb b79e234da2 Merge pull request #297 from kalashnikovdmitryv/patch-1
Add flag for RPI4 with arm64+armhf multiatch
2021-01-06 20:32:50 +01:00
kalashnikovdmitryv 5bc6962a9d Update CMakeLists.txt 2021-01-06 22:23:21 +03:00
ptitSeb 168717a90a Added some more functions t wrapped libxslt 2021-01-06 20:02:56 +01:00
ptitSeb dd6b0f6c9a [DYNAREC] Tiny optim on dynablock creation 2021-01-05 22:04:27 +01:00
ptitSeb 0a3c678877 Fixed compilation on non Dynarec build 2021-01-04 18:57:26 +01:00
ptitSeb e2df6f6ce0 Added 66 F0 81/83 opcodes 2021-01-04 08:35:25 +01:00
ptitSeb e58ebdac18 [TRACE] Fix build when trace is enabled 2021-01-03 18:16:10 +01:00
ptitSeb 537312a91f Use Custom allocator for all hash map 2021-01-03 16:39:58 +01:00
ptitSeb 11c08acd6c [DYNAREC] Need to improve this optimization, reverting for now (help Unity3D games) 2021-01-03 15:40:48 +01:00
ptitSeb cf9a38fb02 [DYNBAREC] Try to make dynarec more resiliant on heavily multi-threaded program 2021-01-03 11:20:56 +01:00
ptitSeb 83dff2bf25 Merge branch 'master' of https://github.com/ptitSeb/box86 2021-01-03 10:43:03 +01:00
ptitSeb 49694f300a Fixed a warning on wrapped libdl 2021-01-03 10:21:10 +01:00
ptitSeb daddc8246e Small fixes in xcb wrapped functions signature 2021-01-03 10:20:14 +01:00
ptitSeb 9f92377edc Small change to some pthread wrapped functions 2021-01-02 16:18:21 +01:00
ptitSeb 1ce392d968 Fixed the added flags in O_* converters 2021-01-02 15:03:46 +01:00
ptitSeb bf730b43e2 Add a few more flags in O_* converters 2021-01-02 14:57:38 +01:00
ptitSeb a4adb47caf Various small changes in some libc functions signature 2021-01-02 14:47:19 +01:00
ptitSeb 9317572874 Minor changes to O_* flags handling and conversion 2021-01-02 13:13:58 +01:00
ptitSeb eca39e6a8f Improve Signal and Memory protection Handling on multi-thread program, and added BOX86_JITGDB=2 (Should help #273, KSP old linux32 version now works, should also help .net programs) 2021-01-01 18:32:18 +01:00
ptitSeb 4639dc8ffd Minor signature changes for some libpulse functions 2021-01-01 18:32:18 +01:00
ptitSeb 5a9b34f54b Added log for waitpid 2021-01-01 18:32:18 +01:00
ptitSeb dc07d477de Added syscall 318 getcpu (should help #217) 2021-01-01 18:09:53 +01:00
ptitSeb db5efa8908 Fix compile on non-Dynarec build 2021-01-01 11:12:38 +01:00
ptitSeb 7d462dd837 Try to detect Excution error on Signal handling, to help .net programs 2021-01-01 10:37:56 +01:00
ptitSeb 76010f63c0 Fixed BOX86_LOG=2 on some wrapped libc functions 2021-01-01 09:40:17 +01:00
ptitSeb be7f72808b Merge pull request #292 from Hacker1245/patch-1
Fix a typo
2020-12-31 16:27:01 +01:00
ptitSeb 25f1e8e6fa Fixed some lib pulse callback (should help both #193 and #293 and maybe other pulseaudio apps) 2020-12-31 16:25:10 +01:00
ptitSeb 047df311f0 Added xcb_send_request_with_fds64 to wrapped lib xcb 2020-12-31 16:23:24 +01:00
ptitSeb bcdd99328c [DYNAREC] Fixed a samll issue with Logs 2020-12-31 16:22:40 +01:00
ptitSeb 5cc76a0071 [DYNAREC] Another small optim on flags handling 2020-12-31 12:53:55 +01:00
ptitSeb dee55a9ac2 [DYNAREC] Fixed a potential segfault 2020-12-31 08:59:04 +01:00
ptitSeb 9ff20da9bb Added more slots for pulse audio callback (should help #293) 2020-12-30 22:56:42 +01:00
Hacker1245 0520f5abcd Fix a typo 2020-12-30 22:07:19 +01:00
ptitSeb e1201ff0de [DYNAREC] Optimize test emiter to avoid BFI/UBFX when possible 2020-12-30 18:13:32 +01:00
ptitSeb bc2d7e7396 [DYNAREC] Optimize shift emiter to avoid BFI/UBFX when possible 2020-12-30 17:50:58 +01:00
ptitSeb 9a058a2416 [DYNAREC] Optimize logic emiter to avoid BFI/UBFX when possible 2020-12-30 17:29:51 +01:00
ptitSeb 49fea86b28 [DYNAREC] Optimized math emiter to avoid UBFX/BFI when possible 2020-12-30 16:52:34 +01:00
ptitSeb 1617439d37 Flags are only handled in packed form now, removed Unpacked array 2020-12-30 15:58:07 +01:00
ptitSeb 540459cb78 [DYNAREC] Now used r14 (so lr) instead of r12 for EIP/scratch register 2020-12-29 20:02:12 +01:00
ptitSeb 54b8522df6 [DYNAREC] Added SHLD32c emiter 2020-12-29 16:27:27 +01:00
ptitSeb bf65e606d3 [DYNAREC] Minor reordering of operation in DB E2 opcode 2020-12-29 16:27:01 +01:00
ptitSeb 5335a641df [DYNAREC] Fixed 66 99 CWD opcode 2020-12-29 16:26:16 +01:00
ptitSeb 323ece7417 [DYNAREC] Added amiter for SHRD32c 2020-12-29 13:37:57 +01:00
ptitSeb ca1fc0ffad [DYNAREC] Fix a potential memory corruption on exit 2020-12-29 11:18:30 +01:00
ptitSeb c0706e227e [DYNAREC] Removed a warning 2020-12-29 09:40:48 +01:00
ptitSeb 995e4a9b68 [DYNAREC] Switch POP/PUSH from STM/LDM to LDR/STR, so there is no alignment constraint anymore 2020-12-29 08:43:56 +01:00
ptitSeb 7f53379552 Don't printf Segfault handler message if custom handler is setuped on LOG_NONE level 2020-12-28 16:12:26 +01:00
ptitSeb 3e17299a34 Made 8F opcode consistant on segfault ([DYNAREC] too) 2020-12-28 16:11:06 +01:00
ptitSeb c63cdc9506 Added 66 CC opcode, and handling of CC by using raise(SIGTRAP) if SIGTRAP is handled ([DYNAREC] too) 2020-12-28 10:26:09 +01:00
ptitSeb 7965186817 Added TSC flag to CPUID cpu capabilities 2020-12-28 07:57:35 +01:00
ptitSeb f107612753 Force PROT_REAT when PROT_WRITE is set, as it's implicit on i386 2020-12-28 07:40:45 +01:00
ptitSeb 2295f7bb8b Added 66 0F D0 opcode ([DYNAREC] too) 2020-12-28 05:48:57 +01:00
ptitSeb cc0845a9d3 Added wrapped function glib_check_version 2020-12-27 15:22:31 +01:00
ptitSeb e9019461b7 [DYNAREC] Added 0F E1/E2/E3 opcodes 2020-12-27 15:22:07 +01:00
ptitSeb a19e3ed3dd [DYNAREC] Small optim on new memory protection tracker 2020-12-27 16:11:37 +01:00
ptitSeb 10ec424e96 More separation between POWERPC and ARM 2020-12-27 15:58:15 +01:00
ptitSeb b838c8a7d0 [DYNAREC] Fixed new memory protection tracking 2020-12-27 15:15:24 +01:00
ptitSeb 0331af0643 Track memory protection also on mmap/munmap/mprotect syscall 2020-12-27 12:38:24 +01:00
ptitSeb 24561fc37c [WINE] Removed wine_prereserve handling, it seems to be working better without it 2020-12-27 11:41:35 +01:00
ptitSeb d4ad5334b8 [DYNAREC] Some fixes to new memory protection tracking 2020-12-26 18:30:34 +01:00
ptitSeb 7fe3299282 Refined POWERPC support to less impact ARM 2020-12-26 18:27:21 +01:00
ptitSeb 23fef75ed5 [DYNAREC] Fixed FISTTP opcode 2020-12-26 09:55:10 +01:00
ptitSeb 62722b0618 Merge pull request #279 from eerykitty/master
Basic support for little-endian PowerPC and POWER9.
2020-12-25 09:29:10 +01:00
Joseph Allen e810dba2c9 Fixes semctl and a number of variadic functions. 2020-12-24 22:47:23 -06:00
Joseph Allen 7dfe545161 Basic support for little-endian PowerPC and POWER9. 2020-12-24 15:14:50 -06:00
ptitSeb a5f3966b44 Merge pull request #275 from SpacingBat3/master
Updated the PKGBUILDS
2020-12-24 09:38:53 +01:00
ptitSeb 886573ed8b Merge pull request #276 from RickAndTired/patch-1
Typo fix
2020-12-24 09:38:27 +01:00
RickAndTired 2758c1c955 Typo fix
Line 105 typo: kernle
2020-12-23 21:56:13 -08:00
ptitSeb 591bafe8c3 [DYNAREC] Try to improve the marking mecanism to include blocks that are shadowed by others 2020-12-23 09:21:50 +01:00
ptitSeb 211a8f42db Small cosmetic changes to wrapped libsdl2 2020-12-22 22:01:44 +01:00
ptitSeb fbc9029a8e [DYNAREC] Removed unused fiel in dynablocklist structure 2020-12-22 20:01:57 +01:00
ptitSeb ceb4b8b06d Removed a debug leftover 2020-12-22 15:13:29 +01:00
ptitSeb b88dda442f [DYNAREC] Improved block extender mecanism 2020-12-22 14:42:57 +01:00
ptitSeb 6e8163bded [DYNAREC] Moved fakeed function for helper to functions 2020-12-22 13:32:36 +01:00
ptitSeb 9b253abb53 More jpeg62 compress function wrapping (should help #271) 2020-12-22 11:31:09 +01:00
ptitSeb e5e51e3ea3 [DYNAREC] Fix a potential SIGBUS on 66 0F 12 opcode 2020-12-21 17:37:29 +01:00
ptitSeb 6a2d9d7663 Try to avoid a segfault on quit with libpulse 2020-12-21 17:36:51 +01:00
ptitSeb 0546b1e212 Try to fix wrapped Compress functions of libjpeg62 (for #271) 2020-12-21 11:17:03 +01:00
ptitSeb 320e6dae72 [DYNAREC] Reworked a bit the unaligned stack handling workaround to limit console spam 2020-12-21 10:47:16 +01:00
ptitSeb 96f944c804 More fixes to build new memory tracking whithout dynarec 2020-12-20 23:53:40 +01:00
ptitSeb fd0e2195f7 Fix build of memory tracking whithout dynarec 2020-12-20 23:49:31 +01:00
ptitSeb d2f130a834 Memory protection tracking is not only with Dynarec ON now 2020-12-20 23:38:32 +01:00
ptitSeb a3459712ce Fix 66 F0 0F B1 opcode 2020-12-20 23:37:57 +01:00
ptitSeb 8bf2e49164 Reorganised 8F POP Ed opcode to better handle Ed referencing ESP ([DYNAREC] too) 2020-12-20 15:35:57 +01:00
ptitSeb 0f5cd39a64 [DYNAREC] Refined the SIGBUS recovery to limit to push/pop/call/ret opcode (as FPU/SIMD regs are not saved/restored from Signal for now) 2020-12-20 14:13:24 +01:00
ptitSeb e0ed0076f2 [DYNAREC] When a SIGBUS occurs in a dynablock, invalidate the block at that address and try again with interpretor (fix MapleLegends Setup with its strangely aligned stack) 2020-12-20 12:09:51 +01:00
ptitSeb bfd4ad39af [DYNAREC] Fixed some issue with the memory protection mecanism 2020-12-20 11:06:31 +01:00
ptitSeb a8ff7d8769 [DYNAREC] Improved Memory Protection Tracking 2020-12-20 10:30:37 +01:00
ptitSeb 39c77beb1c Fixed Signal handling for PAGEFAULT with Write Error (helps Wine) 2020-12-20 10:11:59 +01:00
ptitSeb d576f7af39 Cleaner version of TEST Eb, Ib and TEST Ed, Id opcodes 2020-12-20 10:10:10 +01:00
ptitSeb 74c3f43f75 [DYNAREC] Better hanling of memory protection for elf memory 2020-12-20 10:09:12 +01:00
ptitSeb ecacace01d [DYNAREC] Added some handlng of protection for malloc'd memory 2020-12-20 10:08:21 +01:00
ptitSeb a3b0149a84 Added 66 1F opcode 2020-12-19 18:18:04 +01:00
ptitSeb 63111577ec Added 64 66 8B opcode 2020-12-19 17:45:55 +01:00
ptitSeb eb68520709 [DYNAREC] Some fixes to improved Memory protection tracker 2020-12-19 17:09:35 +01:00
ptitSeb a7bf2c6cc3 Fixed a potential SIGBUS on 66 0F 13 ocpode 2020-12-19 14:46:57 +01:00
ptitSeb 190788efd9 Added gss_wrap_iov function to wraped libgssapi_krb5 (still for wine) 2020-12-19 13:42:47 +01:00
ptitSeb 2592a6a342 Added gss_wrap function to wraped libgssapi_krb5 (still for wine) 2020-12-19 12:17:01 +01:00
ptitSeb 16ee4c348d [RK3399] Fixed a warning 2020-12-19 12:02:37 +01:00
ptitSeb 8389097cd3 [DYNAREC] Improved memory protection tractick 2020-12-19 11:44:02 +01:00
ptitSeb 79a885c15e Set theme jekyll-theme-hacker 2020-12-19 10:24:18 +01:00
ptitSeb eb7c683a6d Also added gss_verify_mic to libgssapi_krb5 2020-12-18 16:42:26 +01:00
ptitSeb 95b2b314f6 Wrapped libkrb5 and libgssapi_krb5 (minimum functions for wine) 2020-12-18 15:55:34 +01:00
ptitSeb 07eb0aa5cd [DYNAREC] Don't free dynarec elf memory durring elf unloading, it will be free later anyway 2020-12-18 13:56:09 +01:00
ptitSeb fdce28590a Added alternate way to handle some vaarg wrapped functions 2020-12-18 12:24:10 +01:00
ptitSeb 572613e377 Fixed wrapping of Compress structure on libjpeg62 (for #271) 2020-12-18 11:14:42 +01:00
ptitSeb 29e597b4ed Fixed another potential SIGBUS, in CMPXCHG this time 2020-12-17 21:39:23 +01:00
ptitSeb 981c464c36 Fixed a potential SIGBUS with XADD Gd, Ed opcode 2020-12-17 20:52:48 +01:00
ptitSeb d406c5717c Wrapping Compress functions callbacks for libjpeg.so.62 (shoudl help #271) 2020-12-17 10:44:37 +01:00
ptitSeb 92208efd24 Start of a new dev. cycle 2020-12-17 10:43:31 +01:00
ptitSeb 3c98cbccbe Bumped to v0.1.8 2020-12-16 07:58:23 +01:00
ptitSeb 3a5c6751e2 Many fixes to Double->Int x87 opcodes ([DYNAREC] too) 2020-12-15 15:53:38 +01:00
ptitSeb 002d3d7b9b This also fixes 66 D9 and 66 DD opcodes 2020-12-15 15:52:53 +01:00
ptitSeb e57a66da04 [DYNAREC] Fixed AAD opcode 2020-12-15 15:51:13 +01:00
ptitSeb b1ecad2d49 Fixed 66 D9 and 66 DD opcodes 2020-12-15 15:50:18 +01:00
ptitSeb 658a107f60 Better log for FE xx and FF xx Illegal Instructions on interpretor 2020-12-15 15:49:39 +01:00
ptitSeb 7b419ce5f1 Fix a callback for pulse audio (help #268, seems to be working now) 2020-12-15 15:40:58 +01:00
ptitSeb 367df08989 Fix Zoom hack for libturbojpeg.so (for #268) 2020-12-15 07:59:04 +01:00
ptitSeb 2004006a9d Added Zoom detection and hack to first try to use system libturbojpeg.so if loaded (still for #268) 2020-12-14 21:45:57 +01:00
ptitSeb bed0f24f2b Wrapped libturbojpeg.so.0 with a small set of functions (should help #268) 2020-12-14 20:48:56 +01:00
ptitSeb 7995dfc70a Fixed a potential SIGBUS on DF /7 FISTP opcode 2020-12-14 14:12:43 +01:00
ptitSeb b29d569f6b Reworked libpulse wrappers (should be more stable and little tad faster) 2020-12-14 12:22:39 +01:00
ptitSeb 3c166c438a [DYNAREC] Added BOX86_DYNAREC_SAFEMMAP (can be usefull to speedup Wine progs, but may also introduce crash) 2020-12-13 20:25:55 +01:00
ptitSeb 03dac0ef6a [DYNAREC] Use a table read that is not thread safe in linker (I don't think thread safe is a must-have in this case) 2020-12-13 19:26:31 +01:00
ptitSeb 27cb5219ae [DYNAREC] Various simplifications 2020-12-13 19:24:27 +01:00
ptitSeb 97a7459f5d [DYNAREC] Small optims 2020-12-13 16:12:17 +01:00
ptitSeb 1eac337e59 [DYNAREC] Don't flush dynarec_log 2020-12-13 16:11:59 +01:00
ptitSeb 1613358927 [DYNAREC] Fixed a type is FS: Cache handling (should give back some speed on Wine stuff) 2020-12-13 15:38:32 +01:00
ptitSeb 2f0da26f14 [DYNAREC] Presize dblists 2020-12-13 14:21:05 +01:00
ptitSeb 45fa32cb9d [DYNAREC] Small fixes for cancelled dynablock 2020-12-13 14:19:56 +01:00
ptitSeb 9e9f2a37be [DYNAREC] Precalc exact instsize array size 2020-12-13 14:19:04 +01:00
ptitSeb 7b37bb6825 [DYNAREC] simplify this structure 2020-12-13 14:18:36 +01:00
ptitSeb 081378a178 Added empty wrapped libnsl.so 2020-12-13 10:05:28 +01:00
ptitSeb ff72343429 [DYNAREC] Removed a debug leftover 2020-12-13 10:04:57 +01:00
ptitSeb b0b8a2ca1c Fixed a warning 2020-12-13 09:09:35 +01:00
ptitSeb 55be6835b8 Removed a debug leftover (should help #227 and box-compatibility-list/#46) 2020-12-13 08:38:43 +01:00
ptitSeb c465e1de21 [VULKAN] fixed SDL2 wrapping of SDL_Vulkan_GetVkGetInstanceProcAddr 2020-12-12 19:50:04 +01:00
ptitSeb 0f255de201 Made box86context_t lighter for easier debugging (also reorganised member order) 2020-12-12 19:50:04 +01:00
ptitSeb deb04610b5 Revert commit 31a108b685, previous method seems better 2020-12-12 19:25:53 +01:00
ptitSeb a9887fe471 Fixed an old type on Bridge handling 2020-12-12 17:09:35 +01:00
ptitSeb 4b3c5a7f6f [DYNAREC] Reworked Dynablock memory manager 2020-12-12 15:24:05 +01:00
ptitSeb 0058d3563d Added 66 F0 0F B1 opcode 2020-12-12 10:18:13 +01:00
ptitSeb 52a4808f2c Added a few more function to wrapped libfontconfig 2020-12-12 10:09:17 +01:00
ptitSeb 7a0874165f Added 1 wrapped function to libfontconfig 2020-12-12 09:37:44 +01:00
ptitSeb 7c7acd134b Small wrapped libmpg123 and pulse change 2020-12-11 22:27:43 +01:00
ptitSeb ddd4874baa [DYNAREC] Some small optim on support function for the Dynarec 2020-12-11 21:04:11 +01:00
ptitSeb 23f91b1a0d [DYNAREC] All Interpretor to switch back to Dynarec on more opcodes 2020-12-11 20:47:23 +01:00
ptitSeb b8c32d580b [DYNAREC] If a block wasn't created because executable memory was not allocated, delete the whole dynablocks to try again later 2020-12-11 20:35:39 +01:00
ptitSeb c0e67004d5 [DYNAREC] Reworked the dynarec signal handling, to improve its performances 2020-12-11 20:25:24 +01:00
ptitSeb 38a557b7e9 [DYNAREC] Don't try to create 0 sized Map block 2020-12-11 17:28:32 +01:00
ptitSeb 7d6d5d673d [DYNAREC] added 64 A2 opcode 2020-12-11 17:27:23 +01:00
ptitSeb 2cf067f004 [DYNAREC] Don't try to a free a 0 sized of NULL pos Map 2020-12-11 17:27:08 +01:00
ptitSeb 92d9bc525f [DYNAREC] Try to avoid some deadlock with dynarec that could happens in some specific cases involving signals 2020-12-11 16:43:25 +01:00
ptitSeb dca91b1efc added 64 A0 opcode ([DYNAREC] too) 2020-12-11 16:32:14 +01:00
ptitSeb 6bf1ea7539 [DYNAREC] Remove some old code behind ifdefs 2020-12-11 14:23:18 +01:00
ptitSeb 670b13595b Improved the PltRelocator detection of elfloader 2020-12-10 17:14:17 +01:00
ptitSeb dcbb8b29de Added some X11 wrapped functions 2020-12-10 17:12:40 +01:00
ptitSeb 7284c817b2 And more libxcb* wrapped functions 2020-12-10 17:05:54 +01:00
ptitSeb b16912132f Added some xcb_xrandr wrapped functions 2020-12-10 15:44:53 +01:00
ptitSeb 9805ad7f3a Initialize context as soon as possible in library (should help #265 and #266) 2020-12-10 15:11:26 +01:00
ptitSeb 4e7e0f6aab Added a few libdrm wrapped function 2020-12-10 13:56:24 +01:00
ptitSeb c905ebfdd2 Added wrapped libSDL2_ttf-2.0.so.0 (copy if the sdl1 version) 2020-12-10 13:51:31 +01:00
ptitSeb b5c787938c Fixed commented code, in case it gets uncommented someday 2020-12-10 13:38:59 +01:00
ptitSeb 69ca5351b4 Added a bunch of wrapped xcb* functions 2020-12-10 12:35:52 +01:00
ptitSeb 3f42372603 Added liblcms2 wrapped lib (partial wrapping, just enough for wine) 2020-12-09 15:54:33 +01:00
ptitSeb 595028e9ec Reworked Exit, to avoid segfault and lockup and end of execution 2020-12-09 11:25:14 +01:00
ptitSeb 7358a049ef Huge refactoring (again), completly removed old Callback mecanism (working to have only 1 x86emu_t structure per thread, almost there) 2020-12-08 22:38:51 +01:00
ptitSeb 792aeda72e Be more smart to when to apply PltRelacator or not (fix SuperHexagon's libGLEW loading) 2020-12-08 21:44:21 +01:00
ptitSeb 53bf2d277b Added wrapped libldap_r and liblber 2020-12-08 08:10:02 +01:00
ptitSeb 0cbc55ba24 Fix potential build error on old system (at least with old headers) 2020-12-08 07:56:18 +01:00
ptitSeb 7b0d228972 Added a few XTandr wrapped functions 2020-12-08 07:54:40 +01:00
ptitSeb 8ac0b66836 Improved Segment offset Cache, and enable GS: caching (some speed boost on Linux apps) 2020-12-07 13:56:29 +01:00
ptitSeb 2756b1b9dd [DYNAREC] fixed some warning and a typo from last commit 2020-12-06 22:31:15 +01:00
ptitSeb e3f44bae26 [DYNAREC] Huge refactor to simplify Dynablock handling 2020-12-06 21:52:27 +01:00
ptitSeb 1963589186 Mooore Thread Cancel slots 2020-12-06 21:14:38 +01:00
ptitSeb a5c9675b84 [DYNAREC] Removed Mark mecanism (it needs mutex to run properly, so it's too heavy) 2020-12-06 15:13:40 +01:00
ptitSeb 76747d5c38 [DYNAREC] Immprove log for SMC debugging option 2020-12-06 15:12:36 +01:00
ptitSeb 59bfeb9fb2 [DYNAREC] This barrier optimization seems to break Mono on Linux, so reverting it for now 2020-12-06 13:15:09 +01:00
ptitSeb c40669b429 [DYNAREC] Optimized AddMark function to not redo what is already done 2020-12-05 23:22:09 +01:00
ptitSeb d83cdbfeeb Fixed a potential segfault 2020-12-05 23:21:29 +01:00
ptitSeb d8773e96d6 Not sure if awesomium_process needs or not emulated libpng12. Commenting for now 2020-12-05 20:59:24 +01:00
ptitSeb 78571698c2 Some improvements in wrapped libpng handling 2020-12-05 19:43:52 +01:00
ptitSeb 77282f1ff1 Added one more wrapped function to libglib2 2020-12-05 17:07:57 +01:00
ptitSeb 953fcb7f1b Fixed handling of TLS object with a 0 offset (help Garry's Mod, probably a few other too) 2020-12-05 16:59:08 +01:00
SpacingBat3 edef6d7f99 Updated the PKGBUILDS
Improved old PKGBUILDs and added the PKGBUILD for the RK3399 targets.
2020-12-05 16:43:47 +01:00
ptitSeb 1905e4a7f6 Better handling of libtcmalloc_minimum.so.4 2020-12-05 16:15:35 +01:00
ptitSeb 31e6ae0705 Improved the BOX86_NOBANNER behaviour 2020-12-05 12:49:17 +01:00
ptitSeb 31a108b685 Change method used for Thread Cancel registeration 2020-12-04 21:47:39 +01:00
ptitSeb b122c68b16 Improved a bit XImage handling 2020-12-04 21:47:04 +01:00
ptitSeb 0efae1fdf5 Added BOX86_NOGTK to disable use of wrapped gtk libs (can be used with Steam) 2020-12-04 19:52:10 +01:00
ptitSeb 0850180861 Fixed and improved wrapped libdbus-1 2020-12-04 19:49:25 +01:00
ptitSeb 528478b379 Improved a bit wrapped libusb-1 2020-12-04 17:55:30 +01:00
ptitSeb 65302010db Small remork on cancel tread registration mecanism (should fix memory leaks) 2020-12-03 12:01:07 +01:00
ptitSeb 6b32440347 Small fix (mostly cosmetic) in a pthread wrapped function signature 2020-12-03 12:00:32 +01:00
ptitSeb 5a0b6c419e [DYNAREC] Fixed some memory leak 2020-12-03 11:59:43 +01:00
ptitSeb 94c5d0205b fixed some warning 2020-12-03 11:58:49 +01:00
ptitSeb 0f2998a672 More libxml2 wrapping improvment for wine 2020-12-02 21:39:27 +01:00
ptitSeb 1ba7936ef7 Improve wrapping of libxml2 (especially for wine msxml3.dll.so) 2020-12-02 21:16:19 +01:00
ptitSeb 5192aacb22 [RPI] Added runtime hack to get TokiTori2+ running on Pi 2020-12-01 15:13:22 +01:00
ptitSeb ac2adcaf52 A bit more logs when function name is not found 2020-12-01 15:01:12 +01:00
ptitSeb 1b3e707f62 Added SDL_LogGetOutputFunction to wrapped libsdl2 and refactored remaining callback functions 2020-12-01 08:59:01 +01:00
ptitSeb 925fc67c66 Fixed a typo in wrapped libxml2 2020-12-01 08:33:47 +01:00
ptitSeb 54ce6deb1c Wrapped libxslt (should help #259) 2020-11-30 20:02:57 +01:00
ptitSeb 754859d28a Wrapped libxml2 (should help #259) 2020-11-30 18:42:09 +01:00
ptitSeb 269bc9e289 [DYNAREC] Disable one of the new optim, it breaks some installer 2020-11-29 17:26:54 +01:00
ptitSeb 35c768c040 [DYNAREC] Fixed an issue with an optimisation that was too agressive 2020-11-29 13:51:11 +01:00
ptitSeb ff45cfed83 [DYNAREC] Various fixes on some dynarec optimisation mecanism 2020-11-28 16:07:04 +01:00
ptitSeb 38c5c1c17a [DYNAREC] Added 64 FF /2 CALL FS:Ed opcode 2020-11-28 15:32:22 +01:00
ptitSeb 423b301596 Added syscal 356 (and code to emulate it if not present) 2020-11-28 12:26:40 +01:00
ptitSeb 000c11f9ea [PANDORA] Added basic implementation of renameat2 2020-11-28 12:17:12 +01:00
ptitSeb cea4a02ad9 Fixed RPATH handling when a list of path was set 2020-11-28 11:10:01 +01:00
ptitSeb 4e9bc39381 [DYNAREC] Some rework on dynablock management 2020-11-27 17:40:16 +01:00
ptitSeb ad084da13d Start a new dev. cycle with v0.1.7 2020-11-27 10:18:13 +01:00
ptitSeb 27e5262f1d Bumped to v0.1.6 2020-11-26 09:43:33 +01:00
ptitSeb 363464092e [DYNAREC] Added 66 60/61 16bits PUSHA/POPA opcodes 2020-11-25 12:04:47 +01:00
ptitSeb b2cab70427 [DYNAREC] Improved 16bits immediate PUSH opcodes 2020-11-25 12:04:46 +01:00
ptitSeb 44d5301244 [DYNAREC] Improved 16bits PUSH/POP opcodes 2020-11-25 12:04:46 +01:00
ptitSeb 8e4f4feb3c Updated CHANGELOG 2020-11-25 12:04:46 +01:00
ptitSeb e9f6f8824c [DYNAREC] Fixed a potential SIGBUS with int64->double loading 2020-11-24 12:04:03 +01:00
ptitSeb be6f9870d0 Added 64 01/03/11/2B opcodes 2020-11-23 18:41:20 +01:00
ptitSeb bb086223c7 Update README.md 2020-11-23 13:33:36 +01:00
ptitSeb be6a3bff3f Fixed 2 wrapped functions signature in libappindicator (help Steam) 2020-11-22 20:42:49 +01:00
ptitSeb adfc5fda2e Fixed a SEGBUS on RK339 build 2020-11-22 20:31:33 +01:00
ptitSeb d833f136a0 Enable the 'GOG Linux install hack' also for RK3399 platforms 2020-11-22 18:41:37 +01:00
ptitSeb 1703e9d1b7 Refined CMakeList a bit 2020-11-22 18:41:05 +01:00
ptitSeb 011b9f93e4 [DYNAREC] Fixed 66 0F EA/EE opcodes (should fix #253 this time) 2020-11-22 17:30:30 +01:00
ptitSeb e449a4e247 Launch natively program if elf is not recognised as an i386, or not an elf 2020-11-22 14:08:11 +01:00
ptitSeb fe7f0ff842 Fixed potential BUSERROR with LOCK CMPXCHG8B opcode on interpretor 2020-11-22 13:52:44 +01:00
ptitSeb 2033e5764d Fixed potential segfault when using BOX86_LOG=2 2020-11-22 13:05:28 +01:00
ptitSeb 55175263ac [DYNAREC] Added 0F BA /5 and /7 opcodes 2020-11-22 10:52:40 +01:00
ptitSeb c484221cd6 Remove the 'suspicious segment' left over debug code 2020-11-22 10:21:55 +01:00
ptitSeb e9862cb30d [DYNAREC] Fix potential issue when multiple similar thread are launched at the same time (will help #253) 2020-11-21 20:32:52 +01:00
ptitSeb 0c7b99cbc6 [DYNAREC] Changed how opcodes 66 0F 38 08/09/0A are coded (this fixes the md5 error in #253) 2020-11-21 18:36:55 +01:00
ptitSeb 824f39e4db [DYNAREC] Potential fix for 66 0F 38 1C/1D/1E when Gx==Ex and Gx is not cached yet (help #253, but still some issues) 2020-11-21 15:31:27 +01:00
ptitSeb 66a5ce1e52 [DYNAREC] Fixed 66 0F 38 1C/1D/1E opcode (for #253, still not ok, how many opcodes are borked?) 2020-11-21 15:18:22 +01:00
ptitSeb f39637a652 [DYNAREC] Fixed 66 0F EE opcode (for #253, but still not enough) 2020-11-21 15:10:03 +01:00
ptitSeb eaf7d0a277 [DYNAREC] Fixed 66 0F 38 08/09/0A opcode (should help #253 a bit) 2020-11-21 14:54:25 +01:00
ptitSeb b61bb908a2 Improve handling of signals with threads or functions call 2020-11-21 11:06:16 +01:00
ptitSeb 2e891b807c [DYNAREC] Added 66 0F 38 08/09/0A opcodes (for #253 again) 2020-11-20 21:44:47 +01:00
ptitSeb f0b236df88 [DYNAREC] Added 66 0F 38 1C/1D/1E opcodes (still for #253) 2020-11-20 21:18:42 +01:00
ptitSeb 08904dbe0d [DYNAREC] Added 66 0F E4/E5/EA/EE opcodes (should help #253) 2020-11-20 21:04:45 +01:00
ptitSeb c9c4e226af Added 0F DA PMINUB and 0F DE PMAXUB opcodes ([DYNAREC] too) 2020-11-18 21:21:42 +01:00
ptitSeb ab3dc70145 Added 2 clipboard function to gtk2 wrapped lib 2020-11-18 20:50:06 +01:00
ptitSeb 4d8c841f3f [DYNAREC] Fix potential BUSERROR of F3 0F 2C and F3 0F 2D opcode, and fixed a typo on F3 0F E6 opcode 2020-11-18 20:44:38 +01:00
ptitSeb a8b247cde9 More improvments and fixes to signal handler 2020-11-18 19:29:52 +01:00
ptitSeb 416e161285 Added F2 0F D0 ADDSUBPS Gx, Ex opcode 2020-11-18 15:28:21 +01:00
ptitSeb cc8d1f9bf2 Better handling of signals 2020-11-18 09:58:55 +01:00
ptitSeb ae95f1b0e5 One more wrapped func tion with callback to gtk2 2020-11-17 10:35:29 +01:00
ptitSeb c10441bec4 Added g_timeout_* wrapped functions to libglib2 2020-11-17 10:27:43 +01:00
ptitSeb 6ab334fc34 Fixed a nasty typo in wrapped libgobject2 2020-11-17 10:27:20 +01:00
ptitSeb 10e849ce60 Fixed a warning in generated wrapper.c 2020-11-17 10:03:35 +01:00
ptitSeb c2206f5452 Aligned most of GValue handling in gtk libs 2020-11-17 09:41:18 +01:00
ptitSeb 3b66cd3cee Merge branch 'master' of https://github.com/ptitSeb/box86 2020-11-16 22:20:11 +01:00
ptitSeb 731a083bb7 Merge pull request #251 from daitj/makemkvtest
added few more wrapper for libcrypto (for #250)
2020-11-16 22:18:25 +01:00
Binay Devkota d35c6ab864 added more wrapper function for #250 2020-11-16 22:51:28 +02:00
Binay Devkota e9cade872c fixed previous commit as i am blind 2020-11-16 20:42:46 +02:00
Binay Devkota b2a8146851 added missing wrapped function for libcrypto #250 2020-11-16 20:15:53 +02:00
ptitSeb 6fd3d6c452 Improved handling of 'marshal' function in gobject2 2020-11-16 19:06:25 +01:00
ptitSeb bc3e72a87d Added a few more wrapped function to libcrypto (for #250) 2020-11-16 17:28:18 +01:00
ptitSeb e50e050aa9 Added some AES_* wrapped funciton to libcrypto (for #250) 2020-11-16 16:45:36 +01:00
ptitSeb c1a75607fa Fixed 'Alternate' autobridge on Interpretor 2020-11-16 14:57:37 +01:00
ptitSeb b203cd2af3 Added system 242 and 241 (for #250) 2020-11-16 14:39:39 +01:00
ptitSeb 84063f026f Added gtk_recent_filter_* wrapped function to gtk2 2020-11-16 14:39:12 +01:00
ptitSeb 3ec1ce25d7 [DYNAREC] Remove a leftover of debug trace 2020-11-16 14:35:54 +01:00
ptitSeb 0e70c543ee Added 'Aternate' solution for Gtk Classes functions beeing called in x86 code 2020-11-16 14:19:16 +01:00
ptitSeb e4d522a8d2 Refactored Gtk Class wrapping code 2020-11-16 10:25:32 +01:00
ptitSeb 272ecbd8ff More gtk class wrapping 2020-11-16 09:44:01 +01:00
ptitSeb 369fa03f9b Better handling of gtk signals 2020-11-15 18:28:25 +01:00
ptitSeb 1675ea3ba2 Added 2 functions wrapped libX11 2020-11-15 17:12:43 +01:00
ptitSeb 5b7a1bb9e6 Added phtread_spin handling 2020-11-15 17:07:07 +01:00
ptitSeb ace3effa2d Improved GCallback handling and fixed g_action_group_add_actions 2020-11-15 17:04:07 +01:00
ptitSeb bd0a14b3ce Added g_list_find_custom wrapped function to libglib2 2020-11-15 16:21:55 +01:00
ptitSeb 29a82f83c5 Added g_queue_find_custom to wrapped libglib2 2020-11-15 16:13:17 +01:00
ptitSeb f7232f09de Fixed a warning 2020-11-15 16:12:47 +01:00
ptitSeb f3eeae9edd Implemented gtk_builder_connect_signals to wrapped gtk2 2020-11-15 15:29:44 +01:00
ptitSeb 874468ca07 Added gtk_cell_layout_set_cell_data_func to gtk2 wrapped lib 2020-11-15 13:49:59 +01:00
ptitSeb 7a972af610 Fixed potential issue with gobject2 signal handler 2020-11-15 12:57:37 +01:00
ptitSeb 4ed42c38c9 Added wrapping of GtkLabel class to gtk2/3 libs 2020-11-15 12:55:31 +01:00
ptitSeb 6a73719a6b One more wrapped function to gtk2 2020-11-15 12:29:58 +01:00
ptitSeb 6efcfc6b93 Added 2 more g_list_ function to wrapped libglib2 2020-11-15 12:28:38 +01:00
ptitSeb 25f30c220e Added gtk_viewport_* wrapped function to gtk2 2020-11-15 12:24:42 +01:00
ptitSeb 2e9665f10e One more glib2 wrapped function 2020-11-15 12:22:23 +01:00
ptitSeb 197881b430 Fixed g_build_path wrapped function 2020-11-15 12:20:37 +01:00
ptitSeb 96fe98d71f Added gtk_cell_renderer_* wrapped function to gtk2 2020-11-15 11:54:35 +01:00
ptitSeb d1ecd4c933 Added g_build_path wrapped function to libglib2 2020-11-15 11:44:15 +01:00
ptitSeb fad25caa08 Added g_content_type_* function to wrapped libgio2 2020-11-15 11:34:25 +01:00
ptitSeb 98c481e045 Added gtk_tree_store wrapped functions to gtk2 lib 2020-11-15 11:29:48 +01:00
ptitSeb 6082e655e6 Added g_slist_sort and g_slist_sort_with_data to wrapped libglib2 2020-11-15 11:11:44 +01:00
ptitSeb 6a97367242 Made GetNativeFnc smarter, and should find more native funcs now 2020-11-15 11:05:07 +01:00
ptitSeb bbcfffdab9 Added gtk_container_foreach and fixed gtk_binding_entry_add_signal when n is 0 in wrapped gtk2 2020-11-15 10:28:22 +01:00
ptitSeb 2dfb6c1012 Added g_regex function to wrapped libglib2 2020-11-15 10:11:12 +01:00
ptitSeb 82317343aa Added GtkAction wrapped functions 2020-11-15 09:58:55 +01:00
ptitSeb 0ea0d0ec98 Better handling of custom gtk class, plus a bunch of gtk wrapeed functions 2020-11-15 09:48:10 +01:00
ptitSeb 33aa27c590 Added GtkAction Class handling (gtk2 and gtk3, hopefully it's the same) 2020-11-14 16:17:04 +01:00
ptitSeb c31f990183 Added F3 0F 12 MOVSLDUP Ex, Gx opcode ([DYNAREC] too) 2020-11-14 15:11:52 +01:00
ptitSeb 791956bee0 More wrapped function to gtk2 lib 2020-11-14 15:03:57 +01:00
ptitSeb 6cebf4f6fd Added more wrapped functions to gtk2 lib 2020-11-14 14:46:02 +01:00
ptitSeb 1782136e02 Added F3 0F 16 MOVSHDUP Ex, Gx opcode ([DYNAREC] too) 2020-11-14 14:30:44 +01:00
ptitSeb 2f381192dd Added some queue wrapped function to libglib2 2020-11-14 13:30:51 +01:00
ptitSeb dac2009cab Added the random functions to wrapped libglib2 2020-11-14 12:39:17 +01:00
ptitSeb d592af694f Added some more wrapped functions to libglib2 2020-11-14 12:18:56 +01:00
ptitSeb e5ea3f9e49 Added g_set_print_handler and g_set_printerr_handler to wrapped libglib2 2020-11-14 11:55:01 +01:00
ptitSeb f0af865401 Fix potential crash on exit for app using Pulse (fixes Iconoclash crash on exit) 2020-11-14 11:37:30 +01:00
ptitSeb 1e20a9effe Improved and simplifiex SDL2_mixer wrapped library 2020-11-13 22:33:34 +01:00
ptitSeb ce968f7756 Added some precision on 32bits build over 64bits OS 2020-11-12 17:43:03 +01:00
ptitSeb 00aaf316ef Added RK3399 target and compilation guide (plus some restructuration in CMake project 2020-11-11 18:08:16 +01:00
ptitSeb 3ad9a0ca73 [DYNAREC] Added ability to track exact x86 address in dynablocks for signal handling 2020-11-11 14:08:53 +01:00
ptitSeb 14a2d24fba [DYNAREC] Better way to prevent difference in emited dynablock between pass2 and pass3 2020-11-10 19:13:07 +01:00
ptitSeb e374886fcf AddedF0 90..97 opcode, simply ignoring F0 LOCK prefix ([DYNREC] too) 2020-11-09 15:09:43 +01:00
ptitSeb e25b373f00 Fixed gtk_menu_item_set_use_underline wrapped function signature 2020-11-09 12:06:57 +01:00
ptitSeb 6fbd270d24 [DYNAREC] cosmetic change 2020-11-08 13:40:40 +01:00
ptitSeb 6adb55a9c4 [DYNAREC] Try to fix the randow issue were a block have a different emited size between pass2 and pass3 2020-11-08 13:40:14 +01:00
ptitSeb 16aa5cac04 Fixed a warning with wrapped posix_spawnp 2020-11-08 13:39:06 +01:00
ptitSeb dca0009df5 [DYNAREC] Fix 66 0F 16 MOVHPD opcode and improved 66 0F C6 SHUFPD 2020-11-08 13:32:28 +01:00
ptitSeb 1cae441cbc More glib2 wrapped functions 2020-11-07 11:27:28 +01:00
ptitSeb 8b21d8f74a [DYNAREC] Added some dump of block when incosistancy between pass2 and pass3 is detected 2020-11-07 11:26:40 +01:00
ptitSeb ff141e30ee Added handling of environ instead of envv for box86 called with spawnp 2020-11-07 11:25:54 +01:00
ptitSeb 2c970a1b8d Added wrapped posix_spawnp function 2020-11-07 11:25:12 +01:00
ptitSeb b433f8194e Improved a bit the fork wrapped function 2020-11-06 17:47:53 +01:00
ptitSeb 7b2f5e5de0 Improved some BOX86_LOG=2 traces 2020-11-06 17:47:26 +01:00
ptitSeb 3d1400e347 Added preliminary gtk3/gdk3 wrapped lib (based on gtk2/gdk2 wrapping) 2020-11-06 14:08:10 +01:00
ptitSeb 8b5d68f79b Use std=gnu11 to avoid some warning when using clang 2020-11-05 14:01:32 +01:00
ptitSeb ded4b461b4 Some more check to help build on some Linux on Android env. 2020-11-05 12:48:44 +01:00
ptitSeb 13a7be57f2 Check some define to help build on some Linux on Android env. 2020-11-05 12:21:55 +01:00
ptitSeb e8fdcd5c06 Added a bunch of gtk wrapped functions 2020-11-05 11:34:11 +01:00
ptitSeb b8e263d7e6 Removed a warning in wrapped SDL_mixer 2020-11-05 11:33:50 +01:00
ptitSeb b76d17e7b9 Update ChangeLog 2020-11-04 13:15:57 +01:00
ptitSeb ce3151b256 Fixed some (XX)printf alignement issue when formating have %+ or %- command 2020-11-02 16:19:39 +01:00
ptitSeb dd0c3ac51e [VULKAN] More work on vulkan wrapper 2020-11-02 13:32:38 +01:00
ptitSeb f06c5897db Merge pull request #245 from linkmauve/patch-1
Fix install target after previous change
2020-11-02 12:51:14 +01:00
linkmauve 7dac72f796 Fix install target after previous change
#244 broke the install target because system/box86.conf should
now be taken from the build directory, sorry for that.
2020-11-02 12:10:29 +01:00
ptitSeb e5a55114b7 Merge pull request #239 from SpacingBat3/master
PKGBUILDs for Arch Linux.
2020-11-02 12:02:57 +01:00
ptitSeb a66d0b3d39 Merge pull request #244 from linkmauve/fix-binfmt-path
Generate binfmt so it points to the correct path
2020-11-02 12:00:29 +01:00
Emmanuel Gil Peyrot b01ad69ba1 Generate binfmt so it points to the correct path
CMake’s templating language is suitable for this kind of generation, as
it knows about all of the variables that have been set at configure-
time.
2020-11-02 10:52:25 +00:00
ptitSeb bbe183e8d4 Do not try to run winedbg 2020-11-01 23:29:20 +01:00
ptitSeb f6c9e5079a Small improvement on BOX86_LOG=2 2020-11-01 23:28:54 +01:00
ptitSeb 0b8408d50a [VULKAN] Fixed vkGetPhysicalDeviceImageFormatProperties signature 2020-11-01 22:42:20 +01:00
ptitSeb 51682eac11 [VULKAN] Fixed vkalignStruct/vkunalignStruct (and now Sascha-willems samples start working) 2020-11-01 21:34:23 +01:00
ptitSeb aea38c682c [VULKAN] More vulka wrapping work 2020-11-01 21:12:56 +01:00
ptitSeb 6edbe97290 Added the last function not wrapped in SDL1_mixer, and redid the wrapping of the callback (for #243) 2020-11-01 20:11:23 +01:00
ptitSeb 304eaab4d2 [VULKAN] Fixed a warning 2020-11-01 17:11:53 +01:00
ptitSeb f4e5839931 [VULKAN] Morework on wrapped functions 2020-11-01 15:35:53 +01:00
ptitSeb 4bac9ea9d5 [VULKAN] More work on vulkan wrapper 2020-11-01 10:04:30 +01:00
ptitSeb 64c9b21849 [VULKAN] Alignment of many structures. Now a simple TriangleDrawing windows App works 2020-10-31 22:58:58 +01:00
SpacingBat3 34828b66a2 Added a PKGBUILDs for other platforms. 2020-10-31 17:35:06 +01:00
SpacingBat3 957ba00723 Added a PKGBUILD for other raspberries.
Added a unified PKGBUILD to install box86 on all RPi-based machines (that are fully supported by box86) and did some changes to README.md.
2020-10-31 17:32:45 +01:00
SpacingBat3 d548ee48c1 Added a RPI4B PKGBUILD.
It is possible now to install the `box86` using the PKBUILD providen in the repository.
2020-10-31 16:57:09 +01:00
ptitSeb d0e93a22a2 Better vulkan log 2020-10-31 09:55:49 +01:00
ptitSeb fe6c1e260b Added one more vulkan extension 2020-10-31 09:55:33 +01:00
ptitSeb 1e5add91d3 Fixed many vulkan wrapped function (and now vulkaninfo works) 2020-10-30 22:12:55 +01:00
ptitSeb f4c7329c30 Forgotten in previous commit 2020-10-30 22:12:11 +01:00
ptitSeb b1742ccb8e Added some minimum wrapped libwayland-client 2020-10-30 22:11:37 +01:00
ptitSeb 870a0d8361 [VULKAN] Fixed library not found even if present 2020-10-30 17:52:44 +01:00
ptitSeb 1f0adf92d4 Added 64 8E MOV Seg, FS:Ed opcode (for #241) 2020-10-30 16:15:45 +01:00
ptitSeb 18ce562698 Wrapping of vulkan (untested yet) 2020-10-30 16:08:46 +01:00
ptitSeb 77af926336 Added 64 8C MOV FS:Ed, Seg opcode (for #241) 2020-10-30 10:44:32 +01:00
ptitSeb 33f2269896 [DYNAREC] removes some compile warning 2020-10-30 10:43:52 +01:00
ptitSeb c477e14a04 [DYNAREC] Minor chenges to some 67 xx opcodes 2020-10-30 10:10:36 +01:00
ptitSeb 373494094a [DYNAREC] Forgot that file on previous commit 2020-10-30 10:08:46 +01:00
ptitSeb 72ca666007 [DYNAREC] Added 65 80/82 opcodes 2020-10-30 10:07:47 +01:00
ptitSeb 5be299b897 [DYNAREC] Cosmetic change 2020-10-30 10:06:55 +01:00
ptitSeb 49afd5077b [DYNAREC] Fixed some function that needs flags before CALL (fixed some ESP not properly preserved on some Windows programs) 2020-10-30 10:05:47 +01:00
ptitSeb e7336de8a7 Change COMPILE.md for Pi4: make -j4 is enough 2020-10-30 10:03:10 +01:00
ptitSeb 5b0f4f5b94 Start a new developpement cycle 2020-10-30 10:02:17 +01:00
ptitSeb 0edc037441 Bumped version to v0.1.4 2020-10-24 15:34:34 +02:00
ptitSeb d4a7f7e658 Simplified glib2 wrapped lib 2020-10-24 12:38:28 +02:00
ptitSeb fcf9668e8b Fixed wrapped g_variant_get function 2020-10-24 12:36:17 +02:00
ptitSeb 76e53e0869 Fixed execvp wrapped function to use PATH / BOX86_PATH to look for binary if needed 2020-10-24 10:47:59 +02:00
ptitSeb 74764253b4 Fixed pango_attribute_init wrapped function 2020-10-24 00:12:35 +02:00
ptitSeb c029c6c152 [DYNAREC] Avoid potential SIGBUS on 66 0F 13MOVLPD and 66 0F 16/17 MOVHPD opcodes 2020-10-24 00:11:44 +02:00
ptitSeb bb4b0d5f92 [DYNAREC] Avoid potential SIGBUS on F3 0F E6 CVTDQ2PD opcode 2020-10-24 00:10:04 +02:00
ptitSeb a355cf941b [DYNAREC] cosmetic changes on dynarec_arm_dd.c 2020-10-24 00:07:32 +02:00
ptitSeb e7c5ef1cca Added some wrapped function to lib pango and pangoft2 2020-10-23 20:03:07 +02:00
ptitSeb 09d0f7a3cb Fixed GVariant creation on wrapped glib2 2020-10-23 20:02:28 +02:00
ptitSeb 3e7dd07b4c Added a libpangoft2-1.0.so as wrapped too 2020-10-23 20:02:02 +02:00
ptitSeb c536eed349 [DYNAREC] Changed a bit how comon dynablock is selected 2020-10-23 20:00:29 +02:00
ptitSeb 93948021e6 Added DE D0..D7 FCOMP ([DYNAREC] too) 2020-10-23 19:59:40 +02:00
ptitSeb 77317f87c0 Simplify SDL2 Event Handler 2020-10-23 19:58:37 +02:00
ptitSeb b091ea9c6d Fixed wrapped lib appindicator 2020-10-23 14:36:56 +02:00
ptitSeb 208493da88 It seems mpg123 use 64bits off_t 2020-10-23 13:04:00 +02:00
ptitSeb 7015745c4f Silence a warning, and don't create a fake /sys/devices/system/cpu/cpuX/topology/core_id file if it exist 2020-10-22 23:50:59 +02:00
ptitSeb 41a5c72d46 [PANDORA] put all define at the same place (for #233) 2020-10-22 23:48:04 +02:00
ptitSeb 2b428641fb [PANDORA] forgot to close the ifdef (for #233) 2020-10-22 23:43:00 +02:00
ptitSeb 4ebb1e60db [PANDORA] Fix potential build issue (for #233) 2020-10-22 23:31:56 +02:00
ptitSeb 5e4c1feed1 [DYNAREC] Fixed the Free of Dynablock that weren't always sane (fixes RGPMaker 2000, among aother things) 2020-10-22 19:24:11 +02:00
ptitSeb d13e1da1a7 [DYNAREC] Added undocummented BOX86_DYNAREC_SMC to detect special case of SMC (slow things down, so use wizely) 2020-10-22 19:24:11 +02:00
ptitSeb 9f57cff43b [README] Fixed address of 86box github project (still for #232) 2020-10-22 17:40:56 +02:00
ptitSeb b9d9776d5c Added 86box precision on README, plus PILab Discord channel link (to mitigate #232) 2020-10-22 16:52:02 +02:00
ptitSeb b57ab8470d [DYNAREC] Some more small optims to some of the LOCK opcodes 2020-10-21 19:08:29 +02:00
ptitSeb fe402d2faa [DYNAREC] Use posix_memalign instead of mmap to for Dynarec block memory 2020-10-21 18:58:50 +02:00
ptitSeb 3d38210752 Improved (once more) signal handling 2020-10-21 17:52:42 +02:00
ptitSeb 6c4b047b58 Changed slightly the win prereserve mecanism 2020-10-20 11:00:22 +02:00
ptitSeb e861d3415a Changed, once again, the loading position of box86 2020-10-20 10:59:55 +02:00
ptitSeb cb251fe88b [DYNAREC] Fixed F0 0F B0 LOCK CMPXCHG Eb, Gb opcode (help KaM Remake) 2020-10-19 21:28:11 +02:00
ptitSeb b1e594f4d7 More work on signal handling 2020-10-19 11:04:45 +02:00
ptitSeb f9505f3c9f Improved a bit wrappedlibc 2020-10-19 11:03:02 +02:00
ptitSeb 52ee2bb769 A bit more logs when using BOX86_LOG=2 2020-10-19 11:01:45 +02:00
ptitSeb f0471fac14 Merge pull request #231 from icecream95/nine-2
Create a fake IDirect3D9 object instead of changing the vtable
2020-10-19 09:57:26 +02:00
Icecream95 7baac98959 Create a fake Direct3D9 object instead of changing the vtable
This means both x86 and ARM code can have the right function pointers
at the same time, allowing a hack in Gallium Nine to be removed.
2020-10-19 20:02:49 +13:00
ptitSeb 9119443c2a [DYNAREC] Go back to X_PEND (as it's more optimized) on end of block (now PvZ still works, thanks to previous commit) 2020-10-17 17:29:38 +02:00
ptitSeb c9c33929f0 [DYNAREC] Fixed (and optimized a bit) some Math emiter 2020-10-17 17:27:16 +02:00
ptitSeb 60717d38d4 Added wrapped libcups with a few functions 2020-10-17 15:21:27 +02:00
ptitSeb 858757f8d1 Merge pull request #230 from mogwa1/master
Fix presumable typo in wrappedlibncurses files
2020-10-17 09:38:22 +02:00
Bart De Vries f15a22a3cb Fix presumable typo in wrappedlibncurses files
A call to vmprintw is made, which is a non-existent function.
Presumably, vwprintw is meant to be called.
2020-10-17 09:34:24 +02:00
ptitSeb f6022de7d3 Don't try to alloc elf section that have so read/write/execute flags 2020-10-16 13:19:17 +02:00
ptitSeb 8214301231 Added handling of /sys/devices/system/cpu/cpuX/topology/core_id file 2020-10-16 13:17:59 +02:00
ptitSeb a4745098c5 Don't inject PLTResolver if it's not needed (should help #195) 2020-10-15 11:04:00 +02:00
ptitSeb 647b06a615 Fixed an issue with box86 shutdown 2020-10-15 10:51:49 +02:00
ptitSeb a7cbafee07 Added libssl.so.1.1 as a alt name for wrapped libssl 2020-10-14 21:18:32 +02:00
ptitSeb ee0eb2345c Added libcrytpo.so.1.1 as a alt name for wrapped libcrypto 2020-10-14 21:16:50 +02:00
ptitSeb d37c42761d Don't try to use XSAVE/XRSTR yet on signal handling 2020-10-14 20:06:05 +02:00
ptitSeb d4984fd0ee New attemps at improving Signal Handling 2020-10-14 17:43:08 +02:00
ptitSeb c770ea1859 Added an option to disable the loading of pulse audio libs 2020-10-14 09:29:59 +02:00
ptitSeb 4d1307e223 Improve signal handling, again (to help windows exception managers) 2020-10-12 22:16:23 +02:00
ptitSeb e9308c11ba [DYNAREC] Added 67 64 xx opcode (copy of 64 67 xx, need to factorise all this) 2020-10-12 21:50:48 +02:00
ptitSeb 5206ec0fcb Fixed 1 wrapped function signature in libXext 2020-10-12 21:50:12 +02:00
ptitSeb c65671a6f9 Added more libXext wrapped functions (for #226) 2020-10-12 10:40:33 +02:00
ptitSeb ec99203dc6 Better log for FF illegzal opcode 2020-10-12 10:22:05 +02:00
ptitSeb 1cdde047ff Added more ncurses wrapped function (for #215) 2020-10-12 08:35:30 +02:00
ptitSeb 2375d70782 [DYNAREC] Fixed a typo in 8D LEA Gd, Ed opcode 2020-10-11 22:10:44 +02:00
ptitSeb 5b0c395293 Added a even more wrapped libcrypto functions 2020-10-11 20:47:36 +02:00
ptitSeb ea0c1abb0b Added a few more wrapped libcrypto functions 2020-10-11 20:13:37 +02:00
ptitSeb cc841812ce Added 1 wrapped function to libcrypto 2020-10-11 19:07:48 +02:00
ptitSeb 5104bce7bb [DYNAREC] Added (fake) F2/F3 EB opcode 2020-10-11 18:28:45 +02:00
ptitSeb 357ce483a8 [DYNAREC] Added a workaround for some SMC trick using PUSH Id followed by RET (help RPGMaker RunTime) 2020-10-11 18:21:17 +02:00
ptitSeb 1a40b4b984 [DYNAREC] Added D9 F6/F7 FDECSTP/FINCSTP opcode 2020-10-11 15:30:02 +02:00
ptitSeb cdd0e542f1 Added (faked) XACQURE/XRELEASE prefix 2020-10-11 14:21:20 +02:00
ptitSeb a9d87a938d Added (fake?) 63 ARPL Ed, Gd opcode 2020-10-10 18:30:22 +02:00
ptitSeb 549ff980a3 [DYNAREC] Added FPREM1 opcode 2020-10-10 16:33:46 +02:00
ptitSeb 545af93972 [DYNAREC] Added FBSTSW opcode 2020-10-10 16:33:10 +02:00
ptitSeb 72b9ed9f54 Even more libjpeg.so.62 improvements 2020-10-10 15:01:27 +02:00
ptitSeb 536c7dd04b Big improvement in libjpeg.so.62 handling 2020-10-10 13:46:04 +02:00
ptitSeb 274d5d1e75 Also trap SIGILL now, like SIGSEGV and SIGBUS 2020-10-10 10:42:47 +02:00
ptitSeb 7b478e42c0 Improved libjpeg.so.8 and libjpeg.so.62 handling 2020-10-10 10:31:27 +02:00
ptitSeb d0ac1e61d4 Added libjpeg.so.62 as for wrapped libjpeg 2020-10-09 20:13:58 +02:00
ptitSeb 31d73927a3 [README] Added a Steam paragraph (for #223) 2020-10-09 17:38:45 +02:00
ptitSeb 7713bd042a Added wcsnlen wrapped function to libc 2020-10-08 12:00:16 +02:00
ptitSeb 664dab76e3 Fixed improved signal handler. It seems to work a bit now 2020-10-07 21:38:38 +02:00
ptitSeb 6e2c33866d Add DB E1 FDISI8087_NOP as NOP ([DYNAREC] too) 2020-10-07 20:03:43 +02:00
ptitSeb 7b6dd6765e Rermoved a forgotten debug trace 2020-10-07 19:57:50 +02:00
ptitSeb d55d2d0303 [DYNAREC] Added D5 Ib AAM and D6 Ib AAD opcodes 2020-10-07 19:37:40 +02:00
ptitSeb 4df7bec913 Some fixes to new signal handling functions 2020-10-07 19:15:44 +02:00
ptitSeb 4ddab1b691 Made fork to reset the main hread emu if needed 2020-10-07 19:14:54 +02:00
ptitSeb b0c0e96fca [DYNAREC] Added D6 SALC opcode 2020-10-07 19:12:34 +02:00
ptitSeb aeee2fc391 Try to better handle Signals when signal handler change any context value 2020-10-07 12:07:52 +02:00
ptitSeb 4f28cb5617 Added wrapped funciton logl to libm (help KeeperRL) 2020-10-07 11:42:46 +02:00
ptitSeb a442a841f2 Added wrapped function curl_free to libcurl (help KeeperRL) 2020-10-07 11:42:10 +02:00
ptitSeb 9201170ab8 [DYNAREC] Fixed and optimized F3 0F E6 CVTDQ2PD opcode 2020-10-06 23:12:32 +02:00
ptitSeb 4f06cfa0da [DYNAREC] Added F3 0F E6 CVTDQ2PD Gx, Ex opcode 2020-10-06 16:19:25 +02:00
ptitSeb fe03daa01f [DYNAREC] Cosmetic change in one of the emmiter 2020-10-06 16:18:57 +02:00
ptitSeb b64c4f6043 Better handling of path with space (for #220, but seriously, space in folder name are evil) 2020-10-06 13:04:07 +02:00
ptitSeb 5884c78b56 Use CMAKE_SOURCE_DIR instead of CMAKE_HOME_DIRECTORY as recommended in cmake documentation 2020-10-06 11:59:33 +02:00
ptitSeb b01b7373ac [DYNAREC] Added workaround for unaligned LOCK XADD Ed, Gd 2020-10-06 11:53:28 +02:00
ptitSeb 3cc9482a08 [DYNAREC] Added a workaround for unaligned LOCK SUB Ed, Id/Ib 2020-10-06 11:12:16 +02:00
ptitSeb 83c6b01fae Added a NOGIT option to build from sources that are not a git clone (should help #220) 2020-10-06 10:59:20 +02:00
ptitSeb 1f169bc67e [DYNAREC] Added a workaround for unaligned LOCK ADD Ed, Id/Ib and also fix potential issues when an opcode have internal jump 2020-10-06 08:05:40 +02:00
ptitSeb ea25675264 Merge pull request #221 from Botspot/patch-1
Optimize compilation & full install commands
2020-10-06 07:59:29 +02:00
Botspot c302cd680c Optimize compilation & full install commands 2020-10-05 18:28:43 -05:00
ptitSeb ebf46d0cfd Added a few more symbols and dependancies to gtk wrapped libs (should help #193) 2020-10-05 22:38:28 +02:00
ptitSeb 2c9b504688 Improve dlsym mecanism (should help #193) 2020-10-05 21:13:45 +02:00
ptitSeb 41d3de565c Added 2 symbols in wrapped libgtk-x11 2020-10-05 20:15:25 +02:00
ptitSeb 88430d845d Fixed an issue with a log of wrapped dlopen 2020-10-05 20:15:24 +02:00
ptitSeb c6e5e5d27e Added wrapped libxcb-present (partial) 2020-10-05 15:20:26 +02:00
ptitSeb cd673028b7 Added wrapped libxcb-dri2 and libxcb-dri3 (partial) 2020-10-05 14:29:56 +02:00
ptitSeb 2cafe12e4f Default to BOX86_LOG=NONE (use BOX86_LOG=1 to get previous behaviour) 2020-10-05 11:54:55 +02:00
ptitSeb febbaca66b Added BOX86_NOBANNER env. var. plus default to printing box86 version and build number at start 2020-10-05 11:53:46 +02:00
ptitSeb e410ca748a Merge pull request #219 from icecream95/nine
Wrap Gallium Nine
2020-10-05 10:02:15 +02:00
ptitSeb 524c04296e Fixed FXSR opcodes (should help #218) 2020-10-05 09:52:06 +02:00
Icecream95 ef360bf93e Add a final NULL to environment variables
Fixes Wine crashes with certain numbers of environment variables present.
2020-10-05 14:44:50 +13:00
Icecream95 bd4f7a4783 Update generated functions 2020-10-05 14:44:50 +13:00
Icecream95 3c2c242225 Add wrapping for d3d9 2020-10-05 14:44:50 +13:00
Icecream95 a8e657c86e Add some headers for d3d9 wrapping 2020-10-05 14:44:50 +13:00
Icecream95 70e103af49 Wrap some more libxcb functions 2020-10-05 14:44:50 +13:00
ptitSeb 006f7a79b4 Added C4 LES Gd, Ed opcode 2020-10-04 22:08:02 +02:00
ptitSeb c7a4dbe84b Fixed __res_state that is wrapped function and not a data in libc 2020-10-04 18:29:27 +02:00
ptitSeb 31c0c52d7f Added a few more wrapped function to libdbus 2020-10-04 17:28:07 +02:00
ptitSeb a4590d3771 Fix for commit 85dd704f86 2020-10-04 16:58:32 +02:00
ptitSeb 02b5e39c39 Improved signal handling 2020-10-04 16:23:11 +02:00
ptitSeb 85dd704f86 Don't protect executable memory until it's actually executed 2020-10-04 16:22:55 +02:00
ptitSeb b4d4efd40c Added 2 more wrapped functions to libdbus 2020-10-04 16:18:13 +02:00
ptitSeb 8745b0f31a Small changes in thread handling ([DYNAREC] Pre-compute first dynarec of thread function before creating a thread) 2020-10-04 10:59:36 +02:00
ptitSeb 3787b3bbfc Minor changein trace handling 2020-10-04 10:58:42 +02:00
ptitSeb 765e1b1231 [DYNAREC] Changed __builtin___clear_cache with __clear_cache 2020-10-04 10:58:09 +02:00
ptitSeb 2a2e2bf957 Improved a bit SIGSEGV/SIGBUS log message 2020-10-04 10:57:32 +02:00
ptitSeb c93913732b Added C5 LDS Gd, Ed opcode (not sure it's correct) 2020-10-04 10:54:11 +02:00
ptitSeb f5bbc99d7d Change how LD2D works, to avoid potential BusError 2020-10-03 21:42:54 +02:00
ptitSeb 27ce42b9b0 Added g_log_set_default_handler to wrapped glib2 lib 2020-10-03 09:10:43 +02:00
ptitSeb 008d51aeec Added in6addr_loopback data to wrapped libc 2020-10-03 09:10:06 +02:00
ptitSeb 8d0d264c0f Add some data to wrapped ncurses libs (should help #215) 2020-10-03 08:06:47 +02:00
ptitSeb 28717352b4 Improved detail when using BOX86_DLSYM_ERROR=1 2020-10-02 15:52:28 +02:00
ptitSeb f9e492dfdc Added FXSR in the CPU ID flags 2020-10-02 15:51:48 +02:00
ptitSeb a8e029f0e0 [DYNAREC] Added DF C0..C7 FFREEP opcode 2020-10-01 10:13:46 +02:00
ptitSeb f5be4503c5 Added DF C0..C7 FREEP opcode 2020-10-01 10:13:19 +02:00
ptitSeb cd1d3f5026 Added tputs wrapped function to libtsinfo.so.5 and libtsinfo.so.6 (for #211) 2020-10-01 09:38:46 +02:00
ptitSeb 4f55733bdd Added msgctl wrapped function to libc 2020-09-30 18:14:38 +02:00
ptitSeb 81819d04e8 Added msgsnd and msgrcv wrapped function to libc 2020-09-30 17:57:55 +02:00
ptitSeb 4d4adea6eb Added msgget wrapped function to libc 2020-09-30 17:36:08 +02:00
ptitSeb ca981fbc8e [DYNAREC] Added 66 0F 38 01/02/03/05 opcodes 2020-09-30 17:25:12 +02:00
ptitSeb b4c64abd1e Added 66 0F 38 03 PHADDSW opcode 2020-09-30 17:24:18 +02:00
ptitSeb a8787330d8 [DYNAREC] Added F2 0F F0 LDDQU opcode 2020-09-30 17:20:18 +02:00
ptitSeb 7725234b69 Added F2 0F F0 LDDQ opcode 2020-09-30 17:19:50 +02:00
ptitSeb 062d897fb1 Added 66 0F 38 05 PHSUBW opcode 2020-09-30 16:50:59 +02:00
ptitSeb e1ed95a638 Added a few more xcb wrapped functions 2020-09-30 16:35:08 +02:00
ptitSeb 7ffa5d076c Changed a bit FF /6 opcode to avoid potential issues with Ed with ESP 2020-09-30 16:32:51 +02:00
ptitSeb 1ae0ae630a Fixed some typo on some segments opcode ([DYNAREC] too) 2020-09-30 11:05:11 +02:00
ptitSeb d3e8daa9b5 Removed workaround that disabled SSSE3 for Steam, it's not needed anymore 2020-09-30 10:20:19 +02:00
ptitSeb 5f8be26b73 Added xcb_setup_roots_length wrapped function to libxcb (for #193) 2020-09-30 08:24:21 +02:00
ptitSeb 0eb575b472 Fixed some wrapped libXRandr functions 2020-09-28 15:03:47 +02:00
ptitSeb 1888d905a4 Try to handle SIGBUS like SIGSEGV 2020-09-28 15:03:18 +02:00
ptitSeb 3bc4dc8450 Fixed handling of file not found at start 2020-09-28 10:21:12 +02:00
ptitSeb 78719df8d4 Try to implement sigset wrapped function (for #211) 2020-09-27 15:03:17 +02:00
ptitSeb d3616b335f Improved wrapped ncurses / tsinfo symbols (for #209 and #211) 2020-09-27 14:38:40 +02:00
ptitSeb e72cd086b4 Better handling of /proc/PID/xxx in wrapped files open function (for #202) 2020-09-27 14:14:31 +02:00
ptitSeb c82e67c39a Added 66 0F 38 08/09/0A PSIGN(B/W/D) opcode 2020-09-27 14:02:38 +02:00
ptitSeb 9885cf6f10 [DYNAREC] Assorted fix and optim for some SSE2/SSSE3 opcodes 2020-09-27 13:42:26 +02:00
ptitSeb d923b5bc0f [DYNAREC] better log for unimplemented opcode 2020-09-27 09:39:25 +02:00
ptitSeb 611d2fcaff Assorted interpretor fixes for some SSE2 opcodes 2020-09-27 09:38:58 +02:00
ptitSeb 9b2b312719 Merge branch 'master' of https://github.com/ptitSeb/box86 2020-09-26 19:18:49 +02:00
ptitSeb f84161dafc Merge pull request #210 from rajdakin/printerFix
Fixed some instructions printer
2020-09-26 19:16:14 +02:00
rajdakin 8546a0d0bd [PRINTER] Fixed some instructions printer 2020-09-26 18:43:02 +02:00
ptitSeb 09f5873806 Fixed 66 0F E8 PSUBSB opcode 2020-09-26 13:49:14 +02:00
ptitSeb 18dc905a8c [DYNAREC] Various small optimisations, mainly SSE oriented 2020-09-26 11:48:19 +02:00
ptitSeb 30d64a0aa5 Small fix on 66 0F 67 PACKSSDW opcode 2020-09-26 10:24:46 +02:00
ptitSeb 8359c9e19f [DYNAREC] Added D9 /6 FNSTENV opcode 2020-09-26 10:23:48 +02:00
ptitSeb 571f0c0564 Small optim on D9 /6 FNSTENV opcode 2020-09-26 10:23:21 +02:00
ptitSeb 736a9ef442 Fixed 66 0F 67 PACKUSWB when EX and GX are the same 2020-09-25 13:49:43 +02:00
ptitSeb aee94b0e14 A bit more work on cpow(f) wrapped function 2020-09-25 12:08:54 +02:00
ptitSeb 4cfed0d394 [DYNAREC] Fixed 66 0F 38 04 PMADDUBSW opcode 2020-09-25 10:51:11 +02:00
ptitSeb c714d5d881 Fixed 0F 38 00 PSHUFB to use MM regs instead of XMM 2020-09-25 10:35:34 +02:00
ptitSeb 1c2d07ee56 [DYNAREC] Change implementation for 66 0F 6E MOVD Gx, Ex opcode 2020-09-25 08:25:06 +02:00
ptitSeb 96f7f3d88f Change implementation for 66 0F 3A 0F PALIGNR opcode 2020-09-25 08:24:17 +02:00
ptitSeb c743577369 Added 0F C3 MOVNTI opcode ([DYNAREC] too) 2020-09-25 08:21:28 +02:00
ptitSeb e5ea60fe88 Added more complex functions to wrapped libm 2020-09-24 21:39:05 +02:00
ptitSeb 330d93f335 Fixed wrapped libm function taht return float complex, plus added a few complex functions 2020-09-24 19:42:10 +02:00
ptitSeb f4936144d0 0F 38 01/02 PHADD(W/D) opcode 2020-09-24 19:41:33 +02:00
ptitSeb bbaa5dde92 Refactored gigantic Run function to create Run660F and try speedup build a bit 2020-09-24 17:45:37 +02:00
ptitSeb e6b46151ec Added (66) 0F 38 1C/1D/1E PABS(B/W/D) opcode 2020-09-24 17:23:12 +02:00
ptitSeb 655a8de652 Added 66 0F 7C HADDPD opcode 2020-09-24 16:53:44 +02:00
ptitSeb 771d69f38b [DYNAREC] Some (S)SSE2/3 opcodes fixes 2020-09-24 16:35:14 +02:00
ptitSeb 2a46dbf149 A bit more (S)SSE3 opcodes fixes 2020-09-24 16:34:49 +02:00
ptitSeb 95a0535462 Try to fix 0F 38 0B PMULHRSW opcode 2020-09-24 16:34:10 +02:00
ptitSeb 041758fead Fixed (66) 0F 38 04 PMULHRSW opcode 2020-09-24 11:59:20 +02:00
ptitSeb d6bb723c6a [DYNAREC] Added 0F E0 PAVGB Gm, Em opcode 2020-09-24 11:58:43 +02:00
ptitSeb 95f97e1c9f [DYNAREC] Added (66) 0F 38 0B PMULHRSW opcodes 2020-09-24 10:56:42 +02:00
ptitSeb b029292dd2 Added 0F 38 0B PMULHRSW Gm, Em opcode 2020-09-24 10:56:15 +02:00
ptitSeb 82ba663c24 [DYNAREC] Fixed 0F 38 00 opcode 2020-09-24 10:17:46 +02:00
ptitSeb fabd5b9d32 Added 0F 38 00 PSHUFB opcode ([DYNAREC] too) 2020-09-24 08:39:28 +02:00
ptitSeb 58736b707d [DYNAREC] Added workaround for unaligned LOCK CMPXCHG and LOCK CMPXCHG8B (fixes Unity Games and Steam) 2020-09-23 22:10:06 +02:00
ptitSeb 9219384650 [DYNAREC] Changed the method used on ARM to simulate LOCK prefix 2020-09-23 20:22:44 +02:00
ptitSeb 14a904cfa9 Added all 64 67 opcodes to 67 64 ... 2020-09-23 10:24:17 +02:00
ptitSeb e73f7a9c10 Added 67 64 FF /6 PUSH FS:Ew16 opcode 2020-09-23 07:50:24 +02:00
ptitSeb 09acd36c08 [DYNAREC] Make end of block need a X_ALL, but end because recursive loop need X_PEND (helps PvZ) 2020-09-22 18:11:19 +02:00
ptitSeb 69a6f44b8b Refined .gitignore for TwisterOS 2020-09-22 18:11:08 +02:00
ptitSeb 3ee8fd4ec6 [DYNAREC] Try to optimize runtime speed a bit 2020-09-22 12:21:55 +02:00
ptitSeb 4f6c0b45f8 [DYNAREC] Avoid deleting block that are not supposed to be volatile 2020-09-22 11:38:50 +02:00
ptitSeb 06a756a5eb [DYNAREC] Small optimization for 64 A1 and 64 A3 opcodes 2020-09-22 11:17:01 +02:00
ptitSeb b312df3b53 Bugfixe on Interpretor for some 64, 65, 66 and 67 prefixed opcodes 2020-09-22 11:16:18 +02:00
ptitSeb 8e4b2a90a4 [DYNAREC] Fixed 64 67 8F POP FS:Ew16 opcode 2020-09-21 23:03:23 +02:00
ptitSeb 85b3091b8a [DYNAREC] Added 64 67 A1 MOV EAX, FS:Ow opcode 2020-09-21 18:16:58 +02:00
ptitSeb 3838fc3d22 [DYNAREC] Added 64 67 8F POP FS:Ew16 opcode 2020-09-21 18:14:45 +02:00
ptitSeb 0f4722d580 Improved (f)open(64) wrapped function a bit more 2020-09-21 15:37:53 +02:00
ptitSeb 4241258158 Added a workaround for steam requieremnt checker 2020-09-21 15:37:23 +02:00
ptitSeb 13c446c918 Wrapped libappindicator (seems to fix Steam starting issues) 2020-09-21 06:17:08 -05:00
ptitSeb 9255026b84 [DYNAREC] Fix build 2020-09-21 11:56:32 +02:00
ptitSeb 119eb57a38 Added an option to Launch GDB when a Segfault occur (JIT Debugging) 2020-09-21 09:41:20 +02:00
ptitSeb 731f379bed Fixed a bug in FindDynablockDynablocklist(...) function, making message on segfault with dynarec more precise 2020-09-20 21:43:00 +02:00
ptitSeb bedcf304e1 Added 65 EB and 65 E9 opcode (also [DYNAREC]) 2020-09-20 16:50:33 +02:00
ptitSeb a4655484cb Added 64 EB and 64 E9 opcode (also [DYNAREC]) 2020-09-20 16:44:40 +02:00
ptitSeb babc5aba4f Added a few more wrapped functions to libc (for #204) 2020-09-20 09:45:55 +02:00
ptitSeb 763a6f8b02 Added syscall handling for syscall 11: execve (for #203) 2020-09-20 08:15:03 +02:00
ptitSeb b08960d4b9 Fixed some rounding issues with x87 interpretor (thx @pale) 2020-09-19 22:12:56 +02:00
ptitSeb 2c6e91622f Try to handle NULL argv and NULL envp in execv(e) wrapped function (still for #203) 2020-09-19 18:12:09 +02:00
ptitSeb 4679977612 Small optims on x87 interpretor 2020-09-19 18:03:18 +02:00
ptitSeb 0e387904b0 More work on execv(e) wrapped functions (still for #203) 2020-09-19 15:01:53 +02:00
ptitSeb f4238621a6 Handling of /proc/self/exe in execv(p) function (for #203) 2020-09-19 14:23:27 +02:00
ptitSeb 2fa19e8cae Handling of /proc/self/exe in (f)open(64) (for #202) 2020-09-19 14:13:41 +02:00
ptitSeb ab644d0638 Made same hacks for fopen64 as for fopen 2020-09-19 12:48:58 +02:00
ptitSeb 8d1db88e1a [DYNAREC] Free of dynablock log level is now DEBUG instead of INFO 2020-09-18 18:00:58 +02:00
ptitSeb 12215ac5dd Removed FLOAT build (was not compatible with Dynarec anyway) 2020-09-18 17:52:28 +02:00
ptitSeb 97d0b386ba Added more mpg123 wrapped functions 2020-09-16 08:33:47 +02:00
ptitSeb f8526be667 Reworked FPREM, FPREM1 and FXTRACT opcodes 2020-09-15 14:47:44 +02:00
ptitSeb 22624f6a29 Added g_pattern_spec_* wrapped functions to glib2.0 2020-09-15 10:39:31 +02:00
ptitSeb e70584e7fc Added some wrapped function to mpg123 2020-09-15 10:35:43 +02:00
ptitSeb ebd2346f3e Added some GLib2 wrapped functions 2020-09-15 10:08:38 +02:00
ptitSeb 03ce553620 Added 66 0F 38 0B PMULHRSW Gx, Ex opcode 2020-09-15 08:45:46 +02:00
ptitSeb 9418a37846 Added (F2) EB opcode 2020-09-14 08:01:23 +02:00
ptitSeb 4f186dec68 g_variant_new_va use va_list* and not just va_list... 2020-09-13 20:57:41 +02:00
ptitSeb 5867fd9912 Added D6 SACL opcode 2020-09-12 18:46:27 +02:00
ptitSeb cd327cfc5a Fixed a message when detecting Steam thta was obsolete 2020-09-11 15:06:21 +02:00
ptitSeb a3f95871b2 Fix loading of elf that have no header sections at all 2020-09-11 15:05:57 +02:00
ptitSeb 53021b770b Added 66 0F DA PMINUB Gx, Ex opcode ([DYNAREC] too) 2020-09-10 16:47:38 +02:00
ptitSeb 7f93731d0c [DYNAREC] Added 66 0F 50 MOVMSKPD Gd, Ex opcode 2020-09-10 16:30:44 +02:00
ptitSeb 570f82d7f8 Improved trace with pid when using fork 2020-09-10 11:27:59 +02:00
ptitSeb 2c8a069f47 Improved LOCK opcodes and locking on dynarec dumper 2020-09-09 20:19:19 +02:00
ptitSeb bbf23be1f3 Merge pull request #201 from rajdakin/NEONprinter_fix
Forgot to add those files
2020-09-08 23:15:56 +02:00
rajdakin accca4e700 [PRINTER] Also fixed VRSHL, VQSHL and VQRSHL 2020-09-08 23:11:40 +02:00
rajdakin ecc8ebef6a [PRINTER] Forgot to add those files 2020-09-08 19:04:35 +02:00
ptitSeb 6c8a807c8c Merge pull request #200 from rajdakin/NEONprinter_fix
Various printer fixes
2020-09-08 18:59:22 +02:00
rajdakin dfb2d5eaaa [PRINTER] Fixed the VMOV.<dt> R, D[imm] instruction printer 2020-09-08 18:52:12 +02:00
rajdakin 71c7ec6fed [PRINTER] Fixed a class of var. size opcodes printer 2020-09-08 18:30:35 +02:00
ptitSeb 55d216f024 [DYNAREC] Thoses fixes to 8bits and 16bits opcodes should have been pushed yesterday already 2020-09-08 08:35:30 +02:00
ptitSeb 5e22febd54 Fixed 0F BA /6 BTS opcode (thx @hmilyyang) 2020-09-08 08:34:21 +02:00
ptitSeb 436d871ea9 Reorganized a bit FreeBox86Context function 2020-09-08 08:33:20 +02:00
ptitSeb 02099912c5 [DYNAREC] Fixed (66) 0F D7 PMOVMSKB for good this time 2020-09-07 19:51:48 +02:00
ptitSeb 601aedb25a More improved to env. var. and other misc. attributes 2020-09-07 10:49:36 +02:00
ptitSeb c65aa3d507 Improvment to Env Var handling 2020-09-07 10:24:27 +02:00
ptitSeb 9b02837d5a Another small improvement to wrapped X11 2020-09-07 10:24:06 +02:00
ptitSeb dbbff7b833 Some fixes to some wrapped X11 function callbacks 2020-09-07 08:10:04 +02:00
ptitSeb e306db4d0c Added F2 25 opcode 2020-09-07 07:29:17 +02:00
ptitSeb 985266fc77 Small cosmetic change to one xcb wrapped function 2020-09-07 07:29:03 +02:00
ptitSeb a3f771cc7c Added a bunch of X11 / Xext / FontConfig wrapped functions 2020-09-06 17:05:09 +02:00
ptitSeb 71a1bea9c7 A few more xcb wrapped functions 2020-09-06 14:26:49 +02:00
ptitSeb 565543fbba Added a few more xcb wrapped functions 2020-09-06 12:20:19 +02:00
ptitSeb 9193194596 Less alarming error message on default log level when loading libraries 2020-09-06 11:03:54 +02:00
ptitSeb 83ea28ded7 Made BOX86_LOG=2 a bit less chatty 2020-09-06 10:55:35 +02:00
ptitSeb 1a69782f51 Added more libSSL/libcrypto wrapped functions 2020-09-05 21:10:48 +02:00
ptitSeb 394ea0f3d3 Added more xcb* wrapped functions 2020-09-05 16:09:27 +02:00
ptitSeb 0241bbdbc0 Added xcb_connect to wrapped libxcb 2020-09-05 14:51:14 +02:00
ptitSeb 5e00739776 Added more pulseaudio wrapped functions 2020-09-05 13:22:21 +02:00
ptitSeb 5d214ac965 Added some more libasound wrapped functions 2020-09-05 12:11:32 +02:00
ptitSeb d35ae51fbb Oops, fixed libxrandr and libxcb-randr private mixup 2020-09-05 11:19:29 +02:00
ptitSeb 717f319dc7 Fixed CPUID command 0 Max basic command supported 2020-09-05 11:18:56 +02:00
ptitSeb fbd2f52da2 Added a few xcb_*_id to xcb-* wrapped libs 2020-09-05 10:57:08 +02:00
ptitSeb 853d89ca9c Added (stub) mcount to wrapped libc 2020-09-05 10:56:44 +02:00
ptitSeb 9c9e3cef29 Added getentropy to wrapped libc 2020-09-05 10:46:46 +02:00
ptitSeb 2237afceff Some fixes to the new empty xcb-* wrapped libs 2020-09-05 10:34:10 +02:00
ptitSeb 180d036fd4 Added some empty xcb-* wrapped lib 2020-09-04 23:57:12 +02:00
ptitSeb 7248ee7ed2 Update README.md 2020-09-04 23:56:57 +02:00
ptitSeb d1e7944ad2 Fix shrd16/shld16 opcode (thx to @hmilyyang) 2020-09-03 13:28:04 +02:00
ptitSeb 2f53752e05 Added a workaround for Unreal, to avoid segfault when launching it whithout leading './' 2020-09-03 10:41:13 +02:00
ptitSeb 3c0de68a00 Fixes to PMOVMSKB opcode ([DYNREC] too, avoiding a segfault) 2020-09-02 14:09:32 +02:00
ptitSeb ef22236f35 [DYNAREC] Another attempt to fix 66 0F D7 PMOVMSKB opcode 2020-09-02 10:19:42 +02:00
ptitSeb 563fc27eae [DYNAREC] Try to fix 66 0F D7 PMOVMSKB opcode 2020-09-02 08:48:59 +02:00
ptitSeb d453e120c8 Added F2 0F 80..8F (BND) Jxx opcodes 2020-09-01 22:29:08 +02:00
ptitSeb 57bd72f147 [DYNAREC] Added 66 0F F1/F2/F3 PSLL(W/D/Q) opcodes 2020-09-01 18:42:23 +02:00
ptitSeb 298c62e00b [DYNAREC] 66 0F D7 PMOVMSKB Gd, Ex opcode 2020-09-01 18:41:31 +02:00
ptitSeb 3d4abfeba2 [DYNAREC] Fix(?) 0F D7 PMOVMSKB Gd, Em opcode 2020-09-01 18:40:43 +02:00
ptitSeb b412118a79 [DYNAREC] Added 66 0F D3 PSRLQ Gx, Ex opcode 2020-09-01 18:05:42 +02:00
ptitSeb c2b5c32a14 Added CB FAR RET opcode 2020-08-31 10:45:11 +02:00
ptitSeb 06cd0a518f Added 64 67 8F POP FS:Ew16 opcode 2020-08-29 21:21:58 +02:00
ptitSeb 947dcc3f3d Added 0F 1A NOP / BNDLDX (ignored) opcode 2020-08-28 17:04:26 +02:00
ptitSeb fa5eb23cae Added 0F 1B NOP / BNDSTX (ignored) opcode 2020-08-28 10:55:45 +02:00
ptitSeb c43895b602 Update CHANGELOG.md 2020-08-27 22:07:18 +02:00
ptitSeb 18cb2a2047 [DYNAREC] Added 64 67 89 MOV Gd, FS:Ew16 opcode 2020-08-26 18:07:18 +02:00
ptitSeb 91637c7b11 [DYNAREC] Added 66 9C PUSHF and 66 9D POPF opcodes 2020-08-26 17:50:24 +02:00
ptitSeb 7b70e987ba [DYNAREC] Added 64 67 FF /6 PUSH FS:Ew16 2020-08-26 16:56:26 +02:00
ptitSeb 74dfef3424 [DYNAREC] Added 64 67 8B MOV Gd, FS:Ew16 and 64 67 A3 MOV FS:Ow, EAX opcodes 2020-08-26 16:26:28 +02:00
ptitSeb 65255edec5 [DYNAREC] Added 66 F8 CLC and 66 F9 STC opcodes 2020-08-26 15:11:29 +02:00
ptitSeb 5b00412ba0 [DYNAREC] Added D7 XLAT opcode 2020-08-26 15:05:51 +02:00
ptitSeb ef43e3f8a0 [DYNAREC] Added 0F EA PMINPS Gm, Em opcode 2020-08-26 14:24:29 +02:00
ptitSeb 3fa06d865a [DYNAREC] Added 66 99 CWD opcode 2020-08-26 14:01:15 +02:00
ptitSeb 96f2f12dec [DYNAREC] Added 66 EE PMAXW Gm, Em opcode 2020-08-26 13:43:06 +02:00
ptitSeb 972079532c [DYNAREC] Added 0F 74 PCMPEQB opcode 2020-08-26 13:11:02 +02:00
ptitSeb 996d4efa32 [DYNAREC] Added PADDUSW opcode 2020-08-25 13:55:45 +02:00
ptitSeb 4704bfb7e6 Added 66 0F DD PADDUSW opcode 2020-08-24 17:58:33 +02:00
ptitSeb 5d3b237854 [DYNAREC] Don't delete volatile dynablock (just invalidate) when memory block loose it's eXecutable flag 2020-08-24 14:00:17 +02:00
ptitSeb dca290b3f0 [DYNAREC] Fixed potential bus error on 0F 13 MOVLPS and 0F 17 MOVHPS opcodes 2020-08-23 15:55:44 +02:00
ptitSeb a84473036d [DYNAREC] End of block now provoque an X_PEND flags instead of X_ALL, also, removed the hl_linux workaround (and made C3 RET also needing an X_PEND flags) 2020-08-23 15:17:48 +02:00
ptitSeb 1b3cb7abb5 Merge pull request #191 from rajdakin/ubfx_fix
[DYNAREC] Fixed the UBFX and others instructions
2020-08-23 14:05:44 +02:00
rajdakin 7dd99ae13e [DYNAREC] Fixed the UBFX and others instructions 2020-08-23 13:54:16 +02:00
ptitSeb 7af511b01a Added 66 0F E4 PMULHUW Gx, Ex opcode 2020-08-23 11:41:58 +02:00
ptitSeb bb3dc2d889 Added 66 0F BA /7 BTC Ew, Ib 2020-08-22 11:05:57 +02:00
ptitSeb 76268c41bc Added 66 0F BA /5 BTS Ew, Ib 2020-08-22 10:24:54 +02:00
ptitSeb b6963ba7c6 Added 66 0F C8..CF BSWAP Reg16 opcode 2020-08-22 04:21:20 +02:00
ptitSeb bd3ff8f828 [DYNAREC] Add a temporary workaround to have HalfLife 2 Engine running correctly 2020-08-20 13:47:30 +02:00
ptitSeb 385326f3a8 [DYNAREC] Fixed RETN with N on 2 bytes (should help #188) 2020-08-19 15:21:07 +02:00
ptitSeb d896fd9106 Merge pull request #186 from shahidali55/patch-1
Removed backslash which was breaking ccmake
2020-08-18 10:06:28 +02:00
shahidali55 9c18afee35 Removed backslash which was breaking ccmake 2020-08-18 13:23:58 +05:30
ptitSeb f0b87c8312 Try to fix the gtk_display workaround when using gtk-1.2 instead of gtk-2.0 2020-08-17 20:24:10 +02:00
ptitSeb 297b7d548a [DYNAREC] Added a few GS: and FS opcodes 2020-08-17 17:07:49 +02:00
ptitSeb 7c406e8f8a [DYNAREC] Fixed CF flag for SHL32c emiter (fixed Sega Rally with Dynarec) 2020-08-16 20:55:23 +02:00
ptitSeb f458d8dc39 [DYNAREC] Optimized a bit BT Ed, Ib opcode 2020-08-16 20:54:47 +02:00
ptitSeb 66ed78cf4d [TRACE][DYNAREC] Small cosmetic changes to block that generate trace 2020-08-16 20:53:56 +02:00
ptitSeb f6205182b9 [TRACE] Fix trace that was disabled at first signal handling 2020-08-16 20:53:11 +02:00
ptitSeb a661016824 Avoid a BUSERROR on FISTP Ed, ST0 (help Sega Rally with Interpretor) 2020-08-16 20:52:28 +02:00
ptitSeb 448afcea7a [DYNAREC] Don't optimize flags on C3 RET opcode, some app count on it (help PlantsVsZombies and GOG Setup under wine, maybe more, #183) 2020-08-16 12:17:58 +02:00
ptitSeb 23881ad861 [DYNAREC] Avoid potential BUSERROR on FIST(P)64 2020-08-16 12:16:40 +02:00
ptitSeb 9d41f49741 {DYNAREC] Fixed a crash that can occur on multithreaded apps (fix regression on NFS2SE) 2020-08-16 10:58:00 +02:00
ptitSeb b302ebfbb5 [DYNAREC] Added F2/F3 9C PUSHF 2020-08-16 09:35:40 +02:00
ptitSeb 88d428f03c Added F2/F3 9C PUSHF opcode 2020-08-16 09:25:58 +02:00
ptitSeb 7396b30615 Fixed some '67' opcodes 2020-08-15 19:27:14 +02:00
ptitSeb 6fe1cc9ed7 [DYNAREC] Fixed 66 0F 5B CVTPS2DQ opcode 2020-08-15 19:25:52 +02:00
ptitSeb 7622959657 Generate git_head.h (and so build build_info.c) only when something else needs to be built 2020-08-15 17:44:34 +02:00
ptitSeb 6f94fdf133 [DYNAREC] Changed PUSHAD to have ESP always up-to-date 2020-08-15 14:49:18 +02:00
ptitSeb b348ce3660 Fixed git_head.h no generated at every build (it's build 2 times now with Dynrarec) 2020-08-15 14:23:37 +02:00
ptitSeb f8638fef92 Added 0F 01 /4 SMSW (dummy) opcode 2020-08-15 14:22:56 +02:00
ptitSeb 9e895da7ed Added wrapped gnutls_check_version function 2020-08-15 13:00:37 +02:00
ptitSeb cb659fef0d Added 66 0F B7 MOVZX Gw, Ew ([DYNAREC] too) 2020-08-15 12:53:13 +02:00
ptitSeb 1a9042c8d1 [DYNAREC] Simplified and optimized Dynablocklist Hash 2 Direct handling 2020-08-15 12:33:10 +02:00
ptitSeb aac8cb9775 [DYNAREC] Optimized dynablock handling 2020-08-15 12:31:37 +02:00
ptitSeb 99962a68b6 [DYNAREC] Removed dynablocks from elfheader, only using global one now 2020-08-15 10:56:39 +02:00
ptitSeb 8ce6d7f369 [DYNAREC] The 'volatile' dynablocks are now 4096 bytes of size, like a page (instead of 65536) 2020-08-15 09:48:59 +02:00
ptitSeb 3bc5a586fa Started v0.1.3 dev. cycle 2020-08-15 09:47:49 +02:00
868 changed files with 72365 additions and 18536 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: ptitSeb
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
+88
View File
@@ -0,0 +1,88 @@
### Auto build Box86 and release its binary with Github Action
name: Build and Release Box86
on:
workflow_dispatch:
release:
push:
paths:
- "**/*.c"
- "**/*.h"
- "**/*.S"
- "**/*.py"
- "CMakeList.txt"
- "**/*.yml"
pull_request:
types: [assigned, opened, synchronize, reopened]
paths:
- "**/*.c"
- "**/*.h"
- "**/*.S"
- "**/*.py"
- "CMakeList.txt"
- "**/*.yml"
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM]
type: [Release, Trace]
runs-on: ubuntu-latest
steps:
- name: "Checkout Box86 Repository"
uses: actions/checkout@v2
- name: "Environment preparation"
run: |
sudo apt-get update
if [[ ${{ matrix.platform }} != 'I386' && ${{ matrix.platform }} != 'OTHER_ARM' ]]; then
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
else
if [[ ${{ matrix.platform }} == 'I386' ]]; then
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
ls /bin/*gcc*
else
echo BOX86_PLATFORM_MARCRO="-DARM_DYNAREC=ON -DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
fi
fi
if [[ ${{ matrix.type }} == 'Release' ]]; then
echo BOX86_BUILD_TYPE=Release >> $GITHUB_ENV
echo BOX86_HAVE_TRACE=0 >> $GITHUB_ENV
else
echo BOX86_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
echo BOX86_HAVE_TRACE=1 >> $GITHUB_ENV
fi
- name: "Display Build info"
run: |
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
echo "Build type: ${{ env.BOX86_BUILD_TYPE }}"
echo "Trace Enabled: ${{ env.BOX86_HAVE_TRACE }}"
- name: "Build Box86"
run: |
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }} -DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }} -DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
make -j$(nproc) VERBOSE=1
- name: "Upload Artifact"
uses: actions/upload-artifact@v2
with:
name: box86-${{ matrix.platform }}-${{ matrix.type }}
path: build/box86
+3
View File
@@ -3,3 +3,6 @@ build*/
.vscode
.gdb_history
src/git_head.h
backup/
box86_update.sh
restore_backup.sh
Executable
+26
View File
@@ -0,0 +1,26 @@
language: c
arch:
- arm64-graviton2
- amd64
os: linux
dist: focal
addons:
apt:
packages:
- python3
compiler:
- gcc
#Build steps
before_script:
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then sudo dpkg --add-architecture armhf ; else sudo dpkg --add-architecture i386 ; fi
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then sudo apt-get -y install gcc-arm-linux-gnueabihf ; else sudo apt-get -y install gcc-multilib libc6-dev:i386 libgcc1:i386 ; fi
- mkdir build
- cd build
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; else CFLAGS="-m32" cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; fi
script:
- make
- if [ "$TRAVIS_CPU_ARCH" != "arm64" ]; then ctest --output-on-failure ; fi
-58
View File
@@ -1,58 +0,0 @@
v0.1.2
======
* The Dynarec now handle JIT code
* Added support for Unity games (not perfect yet)
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it
* Added support for Steam (not perfect yet). Note that steam have limited functionnalities on 32bits (only mini-mode is available)
* More wrapped libs
* Added support for "PltResolver", so order of library is less important and many symbol are resolved at runtime
* Added an option to build box86 as a lib (to wrapped dynamic library)
* Better Signal handling (not perfect yet)
* More opcodes added, more opcode fixes.
* More Dynarec opcodes.
* Added support for FS:, and creating custom selector (needed by Wine)
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling)
* Box86 now have a logo!
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
v0.1.0
=======
* Dynarec!!! Only for ARM (note that dynarec doesn't support JITed code for now)
* Added real support for getcontext/set/context/makecontext/swapcontext
* Preliminary signal handling
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others
* Added wrapped gtk support (still ongoing, many libs involved)
* Make loading of libs more configurable
* If a wrapped native libs is not found, try to use emulated one
* Add en env. var. to force use of emulated lib for certain libs
* Add an env. var. to define wich libGL to use
* Added Install / Uninstall target (using systemd binfmt)
* Added more hardware target (RPis, GameShell...)
* Wrapped more libs (including FreeType, smpeg, ncurses, sndfile...)
v0.0.4
=======
* Improved the Init of dependant Libs. More things work now.
* Added a lot of wrapped functions.
* Added a few wrapped libs (like libz or some other x11 related libs)
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better)
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now)
* FTL 1.6.9 still have corrupted music, but older 1.5.13 seems fine (different set of libs)
v0.0.2
=======
* A full commercial games runs fine on the Pandora: Airline Tycoon Deluxe
* Implemented all planed subpart of Box86 except JIT
* CPU Emulation is at 75%, roughly, including x87 and SSE/SSE2. MMX is barely implemented, but barely used anyway
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as native libm is used)
* No Signal handling yet
* ELF Loader is crude and probably full of bug. Also, the Init of libs is defered after all symbols are resolved for now.
* Wrapped lib include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
* Most wrapped libs are still partially implemented (SDL1 & GL should be complete)
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world
* WorldOfGoo works, but painfully slow on th Pandora (too much double math, and lack of JIT)
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
* Limbo launch but crash before main menu
+298 -107
View File
@@ -1,25 +1,39 @@
cmake_minimum_required(VERSION 2.6)
project(box86)
enable_testing()
enable_language(C)
cmake_minimum_required(VERSION 3.0)
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
option(RPI2 "Set to ON if targeting an RaspberryPI2 device" ${RPI2})
option(RPI3 "Set to ON if targeting an RaspberryPI3 device" ${RPI3})
option(RPI4 "Set to ON if targeting an RaspberryPI4 device" ${RPI4})
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
option(GOA_CLONE "Set to ON if targeting GO Advance clones, like RG351p/v, Gameforce Chi, RGB10..." ${GOA_CLONE})
option(RK3288 "Set to ON if targeting an Rockchip RK3288 based device" ${RK3288})
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
option(POWER9 "Set to ON if targeting a POWER9 processor" ${POWER9})
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
option(A64 "Set to ON if targeting an Allwinner A64 based device" ${A64})
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
set(LD80BITS OFF CACHE BOOL "")
set(NOALIGN OFF CACHE BOOL "")
set(ARM_DYNAREC ON CACHE BOOL "")
endif()
if(ANDROID)
set(NOLOADADDR ON CACHE BOOL "")
endif()
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
option(USE_FLOAT "Set to ON to use only float, no double, in all x87 Emulation" ${USE_FLOAT})
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation (WIP, don't use yet)" ${ARM_DYNAREC})
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
option(POWERPCLE "Set to ON if targeting a little-endian PowerPC device" ${POWERPCLE})
option(SYSV_VARARG "Set to ON if host device uses SysVR4 vararg calling convention" ${SYSV_VARARG})
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
find_package(PythonInterp 3)
@@ -37,6 +51,16 @@ else()
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
endif()
if(RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
#set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as) #will use gcc in fact
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
endif()
project(box86 C ASM)
enable_testing()
set(default_build_type "RelwithDebInfo")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
@@ -44,69 +68,88 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
# Pandora
if(PANDORA)
add_definitions(-DPANDORA)
#add_definitions(-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -fsingle-precision-constant -ffast-math)
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
# Gameshell
if(GAMESHELL)
elseif(GAMESHELL)
add_definitions(-DGAMESHELL)
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
if(PYRA)
elseif(PYRA)
add_definitions(-DPYRA)
add_definitions(-mcpu=cortex-a15 -mfpu=neon -mfloat-abi=hard -marm)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a15 -mfpu=neon -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
if(RPI2)
elseif(RPI2)
add_definitions(-DRPI)
add_definitions(-DRPI2)
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
if(RPI3)
elseif(RPI3)
add_definitions(-DRPI)
add_definitions(-DRPI3)
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
if(RPI4)
elseif(RPI4)
add_definitions(-DRPI)
add_definitions(-DRPI3)
add_definitions(-DRPI4)
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
endif()
if(ODROID)
elseif(RPI4ARM64)
add_definitions(-DRPI)
add_definitions(-DRPI4ARM64)
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
elseif(ODROID)
add_definitions(-DODROID)
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard")
set(ARM_DYNAREC ON)
set(LD80BITS OFF)
set(NOALIGN OFF)
elseif(RK3288)
add_definitions(-DRK3288)
add_definitions(-mcpu=cortex-a17 -mfpu=neon -mfloat-abi=hard -marm)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a17 -mfpu=neon -mfloat-abi=hard")
elseif(SD845)
add_definitions(-DSD845)
add_definitions(-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
elseif(A64)
add_definitions(-DA64)
add_definitions(-marm -march=armv8-a+crc+simd+crypto -mcpu=cortex-a53+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc+simd+crypto -mcpu=cortex-a53+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
elseif(GOA_CLONE)
add_definitions(-DGOA_CLONE)
add_definitions(-marm -mcpu=cortex-a35 -mfpu=neon-vfpv3 -march=armv8-a+crc+simd+crypto -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a35 -mfpu=neon-vfpv3 -march=armv8-a+crc+simd+crypto -mfloat-abi=hard")
elseif(RK3399)
add_definitions(-DRK3399)
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
elseif(PHYTIUM)
add_definitions(-DPHYTIUM)
add_definitions(-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
elseif(ARM_DYNAREC)
#if DYNAREC is selected alone, without any arch
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
endif()
set(BOX86_ELF_ADDRESS "0x02800000")
if(POWER9)
add_definitions(-mcpu=power9 -mtune=power9)
endif()
if(NOGIT)
add_definitions(-DNOGIT)
endif()
if(BOX86LIB)
set(BOX86 box86)
elseif(HAVE_TRACE)
set(BOX86 box86)
else()
set(BOX86 box86)
endif()
set(BOX86_ELF_ADDRESS "0x62800000")
if(LD80BITS)
add_definitions(-DHAVE_LD80BITS)
@@ -120,10 +163,6 @@ if(HAVE_TRACE)
add_definitions(-DHAVE_TRACE)
endif()
if(USE_FLOAT)
add_definitions(-DUSE_FLOAT)
endif()
if(ARM_DYNAREC)
add_definitions(-DDYNAREC)
add_definitions(-DARM)
@@ -131,6 +170,14 @@ if(ARM_DYNAREC)
enable_language(ASM)
endif()
if(POWERPCLE)
add_definitions(-DPOWERPCLE)
endif()
if(SYSV_VARARG)
add_definitions(-DSYSV_VARARG)
endif()
if(NOGETCLOCK)
add_definitions(-DNOGETCLOCK)
endif()
@@ -145,11 +192,11 @@ if(BOX86LIB)
message(FATAL_ERROR "BOX86_ROOT not set when build as lib")
endif()
else()
set(BOX86_ROOT ${CMAKE_HOME_DIRECTORY})
set(BOX86_ROOT ${CMAKE_SOURCE_DIR})
endif()
add_definitions(-std=gnu99 -funwind-tables -fvisibility=hidden)
add_definitions(-std=gnu11 -funwind-tables -fvisibility=hidden)
if(USE_CCACHE)
find_program(CCACHE_FOUND ccache)
@@ -165,18 +212,17 @@ include_directories(
"${BOX86_ROOT}/src/wrapped/generated"
)
add_custom_command(
OUTPUT "${BOX86_ROOT}/src/git_head.h"
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\"\>${BOX86_ROOT}/src/git_head.h"
DEPEND "${BOX86_ROOT}/src/build_info.c"
VERBATIM
)
# git_head.h is a generated file
set_source_files_properties(
"${BOX86_ROOT}/src/git_head.h"
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
set(ELFLOADER_SRC
"${BOX86_ROOT}/src/git_head.h"
"${BOX86_ROOT}/src/main.c"
"${BOX86_ROOT}/src/box86context.c"
"${BOX86_ROOT}/src/build_info.c"
"${BOX86_ROOT}/src/custommem.c"
"${BOX86_ROOT}/src/tools/bridge.c"
"${BOX86_ROOT}/src/tools/pathcoll.c"
"${BOX86_ROOT}/src/tools/fileutils.c"
@@ -190,9 +236,13 @@ set(ELFLOADER_SRC
"${BOX86_ROOT}/src/elfs/elfload_dump.c"
"${BOX86_ROOT}/src/librarian/library.c"
"${BOX86_ROOT}/src/librarian/librarian.c"
"${BOX86_ROOT}/src/librarian/dictionnary.c"
"${BOX86_ROOT}/src/librarian/symbols.c"
"${BOX86_ROOT}/src/librarian/globalsymbols.c"
"${BOX86_ROOT}/src/emu/x86emu.c"
"${BOX86_ROOT}/src/emu/x86run.c"
"${BOX86_ROOT}/src/emu/x86run66.c"
"${BOX86_ROOT}/src/emu/x86run660f.c"
"${BOX86_ROOT}/src/emu/x86run_private.c"
"${BOX86_ROOT}/src/emu/x86syscall.c"
"${BOX86_ROOT}/src/emu/x86primop.c"
@@ -205,14 +255,17 @@ set(ELFLOADER_SRC
"${BOX86_ROOT}/src/libtools/myalign.c"
"${BOX86_ROOT}/src/libtools/myalign64.c"
"${BOX86_ROOT}/src/libtools/myfts.c"
"${BOX86_ROOT}/src/libtools/obstack.c"
"${BOX86_ROOT}/src/libtools/sdl1rwops.c"
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
"${BOX86_ROOT}/src/libtools/signals.c"
"${BOX86_ROOT}/src/libtools/threads.c"
"${BOX86_ROOT}/src/libtools/vkalign.c"
"${BOX86_ROOT}/src/dynarec/dynarec.c"
"${BOX86_ROOT}/src/wrapped/generated/wrapper.c"
)
if(NOT ANDROID)
list(APPEND ELFLOADER_SRC "${BOX86_ROOT}/src/libtools/obstack.c")
endif()
set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
@@ -226,11 +279,15 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibm.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1mixer.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1net.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1image.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1sound.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl1ttf.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2mixer.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2net.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2image.c"
"${BOX86_ROOT}/src/wrapped/wrappedsdl2ttf.c"
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg2.c"
"${BOX86_ROOT}/src/wrapped/wrappedvorbisfile.c"
@@ -245,6 +302,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibxfixes.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcursor.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxrender.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxft.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxi.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxss.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxpm.c"
@@ -252,6 +310,16 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibxdmcp.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibx11xcb.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcb.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbxfixes.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbshape.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbshm.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbrandr.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbimage.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbkeysyms.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbxtest.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbdri2.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbdri3.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbpresent.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxtst.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxt.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibxcomposite.c"
@@ -259,8 +327,8 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibxmu.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibz.c"
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
"${BOX86_ROOT}/src/wrapped/wrappedalure.c"
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
@@ -269,6 +337,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibdrm.c"
"${BOX86_ROOT}/src/wrapped/wrappedcrypto.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibssl.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibcrypt.c"
"${BOX86_ROOT}/src/wrapped/wrappedutil.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibuuid.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibresolv.c"
@@ -278,6 +347,7 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedfontconfig.c"
"${BOX86_ROOT}/src/wrapped/wrappedfreetype.c"
"${BOX86_ROOT}/src/wrapped/wrappedbz2.c"
"${BOX86_ROOT}/src/wrapped/wrappedexpat.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibsm.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibice.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibusb1.c"
@@ -285,20 +355,26 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibformw.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibpanel.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses6.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo6.c"
"${BOX86_ROOT}/src/wrapped/wrappedgtkx112.c"
"${BOX86_ROOT}/src/wrapped/wrappedgdkx112.c"
"${BOX86_ROOT}/src/wrapped/wrappedgtk3.c"
"${BOX86_ROOT}/src/wrapped/wrappedgdk3.c"
"${BOX86_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
"${BOX86_ROOT}/src/wrapped/wrappedgio2.c"
"${BOX86_ROOT}/src/wrapped/wrappedgmodule2.c"
"${BOX86_ROOT}/src/wrapped/wrappedgobject2.c"
"${BOX86_ROOT}/src/wrapped/wrappedglib2.c"
"${BOX86_ROOT}/src/wrapped/wrappedgconf2.c"
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
"${BOX86_ROOT}/src/wrapped/wrappedpangocairo.c"
"${BOX86_ROOT}/src/wrapped/wrappedgthread2.c"
@@ -310,12 +386,50 @@ set(WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
"${BOX86_ROOT}/src/wrapped/wrappedmpg123.c"
"${BOX86_ROOT}/src/wrapped/wrappedgnutls.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibcups.c"
"${BOX86_ROOT}/src/wrapped/wrappedd3dadapter9.c"
"${BOX86_ROOT}/src/wrapped/wrappedvulkan.c"
"${BOX86_ROOT}/src/wrapped/wrappedwaylandclient.c"
"${BOX86_ROOT}/src/wrapped/wrappedxml2.c"
"${BOX86_ROOT}/src/wrapped/wrappedxslt.c"
"${BOX86_ROOT}/src/wrapped/wrappedldapr.c"
"${BOX86_ROOT}/src/wrapped/wrappedlber.c"
"${BOX86_ROOT}/src/wrapped/wrappednsl.c"
"${BOX86_ROOT}/src/wrapped/wrappedlcms2.c"
"${BOX86_ROOT}/src/wrapped/wrappedkrb5.c"
"${BOX86_ROOT}/src/wrapped/wrappedgssapikrb5.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibtiff.c"
"${BOX86_ROOT}/src/wrapped/wrappedldlinux.c"
"${BOX86_ROOT}/src/wrapped/wrappedcrashhandler.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibv4l2.c"
"${BOX86_ROOT}/src/wrapped/wrappednspr4.c"
"${BOX86_ROOT}/src/wrapped/wrappedsmime3.c"
"${BOX86_ROOT}/src/wrapped/wrappednssutil3.c"
"${BOX86_ROOT}/src/wrapped/wrappednss3.c"
"${BOX86_ROOT}/src/wrapped/wrappedplds4.c"
"${BOX86_ROOT}/src/wrapped/wrappedplc4.c"
"${BOX86_ROOT}/src/wrapped/wrappedssl3.c"
"${BOX86_ROOT}/src/wrapped/wrappedsecret1.c"
"${BOX86_ROOT}/src/wrapped/wrappedtbbmalloc.c"
)
if(ANDROID)
list(APPEND WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedandroidshmem.c"
)
else()
list(APPEND WRAPPEDS
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg62.c"
"${BOX86_ROOT}/src/wrapped/wrappedturbojpeg.c"
)
endif()
set(WRAPPEDS_HEAD "")
# If BOX86_ROOT contains a ".c", the build breaks...
string(REPLACE ".c" "_private.h" MODROOT ${BOX86_ROOT})
set(WRAPPEDS_HEAD "${BOX86_ROOT}/src/wrapped/wrappedd3dadapter9_genvate.h")
foreach(A ${WRAPPEDS})
string(REPLACE ".c" "_private.h" B ${A})
string(REPLACE ".c" "_private.h" C ${A})
string(REPLACE "${MODROOT}" "${BOX86_ROOT}" B ${C})
set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
endforeach()
@@ -324,7 +438,10 @@ set(WRAPPER "${BOX86_ROOT}/src/wrapped/generated/wrapper.c" "${BOX86_ROOT}/src/w
add_custom_command(
OUTPUT "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt"
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py" "${BOX86_ROOT}" "PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "USE_FLOAT" "--" ${WRAPPEDS_HEAD}
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py"
"${BOX86_ROOT}"
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "--"
${WRAPPEDS_HEAD}
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
BYPRODUCTS ${WRAPPER}
@@ -341,9 +458,6 @@ add_custom_command(
add_custom_target(WRAPPERS DEPENDS "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt")
add_custom_target(PRINTER DEPENDS "${BOX86_ROOT}/src/dynarec/last_run.txt")
#this is to force build_info.c to be rebuilt all the time
set_source_files_properties("${BOX86_ROOT}/src/build_info.c" PROPERTIES OBJECT_OUTPUTS "dummy.c")
if(ARM_DYNAREC)
set(DYNAREC_SRC
"${BOX86_ROOT}/src/dynarec/dynablock.c"
@@ -354,8 +468,8 @@ if(ARM_DYNAREC)
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
"${BOX86_ROOT}/src/dynarec/arm_linker.S"
"${BOX86_ROOT}/src/dynarec/arm_table.S"
"${BOX86_ROOT}/src/dynarec/arm_next.S"
"${BOX86_ROOT}/src/dynarec/arm_lock_helper.S"
)
set(DYNAREC_PASS
@@ -409,40 +523,59 @@ if(ARM_DYNAREC)
$<TARGET_OBJECTS:arm_pass2>
$<TARGET_OBJECTS:arm_pass3>
)
endif()
# creates git_head.h
if(ARM_DYNAREC)
add_custom_command(
OUTPUT "${BOX86_ROOT}/src/git_head.h"
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
VERBATIM)
else()
add_custom_command(
OUTPUT "${BOX86_ROOT}/src/git_head.h"
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
VERBATIM)
endif()
if(BOX86LIB)
#build a static or dynamic lib...
if(BOX86DYNAMIC)
add_library(box86 SHARED ${ELFLOADER_SRC} ${WRAPPEDS})
add_library(box86 SHARED ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
else()
add_library(box86 OBJECT ${ELFLOADER_SRC} ${WRAPPEDS})
add_library(${BOX86} OBJECT ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
endif()
if(ARM_DYNAREC)
target_link_libraries(box86 dynarec m dl rt pthread)
if(ANDROID)
target_link_libraries(${BOX86} dynarec m dl)
else()
target_link_libraries(${BOX86} dynarec m dl rt pthread)
endif()
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.13")
set_target_properties(box86 PROPERTIES LINK_FLAGS -rdynamic)
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS -rdynamic)
else()
target_link_options(box86 PUBLIC -rdynamic)
target_link_options(${BOX86} PUBLIC -rdynamic)
endif()
add_dependencies(box86 WRAPPERS)
add_dependencies(box86 PRINTER)
add_dependencies(${BOX86} WRAPPERS)
add_dependencies(${BOX86} PRINTER)
add_custom_target(buildinfo ${BOX86}
DEPENDS dynarec ${BOX86} )
else(BOX86LIB)
if(USE_FLOAT)
set(BOX86 box86f)
elseif(HAVE_TRACE)
set(BOX86 box86t)
else()
set(BOX86 box86)
endif()
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS})
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
add_dependencies(${BOX86} WRAPPERS)
add_dependencies(${BOX86} PRINTER)
target_link_libraries(${BOX86} m dl rt pthread)
if(ANDROID)
target_link_libraries(${BOX86} m dl)
else()
target_link_libraries(${BOX86} m dl rt pthread)
endif()
if(ARM_DYNAREC)
target_link_libraries(${BOX86} dynarec)
endif()
@@ -462,11 +595,14 @@ endif()
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "armhf" _armhf)
if(NOT _x86 AND NOT _x86_64)
install(TARGETS ${BOX86}
RUNTIME DESTINATION bin)
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
configure_file(system/box86.conf.cmake system/box86.conf)
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
@@ -482,76 +618,131 @@ if(NOT TARGET uninstall)
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
set(CPACK_PACKAGE_CONTACT "[email protected]")
set(CPACK_PACKAGE_DESCRIPTION "Box86 - Linux Userspace x86 Emulator with a twist")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_MAJOR\\s*")
string(REGEX REPLACE "BOX86_MAJOR" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX86_MAJOR ${TEMP_STRING})
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_MINOR\\s*")
string(REGEX REPLACE "BOX86_MINOR" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX86_MINOR ${TEMP_STRING})
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_REVISION\\s*")
string(REGEX REPLACE "BOX86_REVISION" "" TEMP_STRING ${TEMP_STRING})
string(REGEX MATCH "[0-9]" BOX86_REVISION ${TEMP_STRING})
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX86_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${BOX86_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${BOX86_REVISION})
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
if(_aarch64 OR _armhf)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf")
elseif(_x86_64 OR _x86)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "i386")
else()
#probably wrong...
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
endif()
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
INCLUDE(CPack)
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(test14 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME ucomiss COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME longjumpInSignals COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.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)
-64
View File
@@ -1,64 +0,0 @@
Compiling
----
#### for Pandora
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Pyra
`mkdir build; cd build; cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Gameshell
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for RaspberryPI
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
`mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
_For Pi4. Change to RPI2 or RPI3 for other models._
#### for ODROID
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Other ARM Linux
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for x86 Linux
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### use ccmake
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
#### Customize your build
*use ccache if you have it*
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
*have some debug info*
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument make a build that is both optimized for speed, and have debug information embedded. That way, if you have a crash or try to analyse performances, you'll have some symbols.
*to have a Trace Enabled build*
To have a trace enabled build (warning, it will be slower), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system lib folders.
*to have ARM Dynarec*
The Dynarec is only avaiable on ARM Cpu. Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
----
Testing
----
A few tests are included.
They can be launched with `ctest`
They are very basic and don't test much for now.
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2018-2019 Sebastien Chevalier ("ptitSeb")
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
-90
View File
@@ -1,90 +0,0 @@
# box86
![Official logo](Box86Logo.png "Official Logo")
Linux Userspace x86 Emulator with a twist
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only support 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized).
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use, and performance can be surprisingly high in some cases.
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary.
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter.
Many games already work, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine (there a long list, among them are UNDERTALE, A Risk of Rain, and Cook Server Delicious)
If you are serious about developing Box86, you should install ccache and activate its support in the cmake project (use ccmake for example)
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/x86primop.c) for copyright details
Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" running on a gigahertz OpenPandora (the second one use the dynarec), and the next 2 of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
[![Play on Youtube](https://img.youtube.com/vi/bLt0hMoFDLk/3.jpg)](https://www.youtube.com/watch?v=bLt0hMoFDLk) [![Play on Youtube](https://img.youtube.com/vi/MM7kWYts7IA/3.jpg)](https://www.youtube.com/watch?v=MM7kWYts7IA) [![Play on Youtube](https://img.youtube.com/vi/8hr71S029Hg/1.jpg)](https://www.youtube.com/watch?v=8hr71S029Hg) [![Play on Youtube](https://img.youtube.com/vi/B4YN37z3-ws/1.jpg)](https://www.youtube.com/watch?v=B4YN37z3-ws) [![Play on Youtube](https://img.youtube.com/vi/xk8Q30mxqPg/1.jpg)](https://www.youtube.com/watch?v=xk8Q30mxqPg) [![Play on Youtube](https://img.youtube.com/vi/_QMRMVvYrqU/1.jpg)](https://www.youtube.com/watch?v=_QMRMVvYrqU)
You can find many more Box86 video on [PI Lab Channel](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) [![PI Lab Channel](https://yt3.ggpht.com/a/AATXAJyMeWrgCjs78gr6To6yX4KtDPUCS7hsbX1rRA=s100-c-k-c0xffffffff-no-rj-mo)](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g).
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
<img src="Box86Icon.png" width="96" height="96">
Logo and Icon made by @grayduck, thanks!
----
Compiling
----
Compilation instructions can be found [here](COMPILE.md)
----
Usage
----
There are a few environment variables avaiable to control the behaviour of Box86.
See [here](USAGE.md) for all variables and what they do.
Note that now the Dynarec of Box86 uses a mecanism with Memory Protection and a SegFault signal handler to handle JIT code. That means if you want to use gdb to debug running a program that use JIT'd code (like mono/Unity3D), you will have many "normal" segfaults triggering. I suggest you use something like `handle SIGSEGV nostop` in gdb to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
----
Version history
----
The change log is available [here](CHANGELOG.md)
----
A note about 64-bit platforms
----
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
Also note that, even if, on day, there is a Box86_64, this one will only be able to run x86_64 binaries on 64-bit platforms. You will still need Box86 (and see 32-bit chroot) to run x86 binaries (in fact, the same is the case on actual x86_64 Linux).
----
A note about Unity game emulation
----
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with he new "protected memory" mechanism implemented it is running with correct performance now.
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
TL;DR: Not all Mono games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
----
A note about Wine
----
Wine is now partly supported. Wine integreted program all runs, annd some windows program and games now run fine. Don't forget most Windows games use Direct3D, that may require a complete OpenGL driver and as high profile as possible (and gl4es with ES2 backend have issue with Wine for now). Also, vulkan is not wrapped on box86, so vk3d is not usable yet, even if supported by the hardware.
----
Final words
----
(If you use Box86 in your project, please don't forget to mention Box86)
-132
View File
@@ -1,132 +0,0 @@
Usage
----
There are many environment variable to control Box86 behaviour.
##### BOX86_LOG
Controls the Verbose level of the log
* 0
* NONE : No message (except some fatal error)
* 1
* INFO : Current default. Show some log
* 2
* DEBUG : Verbose a lot of stuffs (like relocations or function called)
* 3
* DUMP : All DEBUG plus DUMP of all ELF Info
#### BOX86_LD_LIBRARY_PATH
Controls the folder scanned to look for x86 libs. Default is current folder and `lib` in current folder.
Also `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exists
#### BOX86_PATH
Controls the folder scanned to look for x86 executable. Default is current folder and `bin` in current folder.
#### BOX86_DLSYM_ERROR
* 0 : default. Don't log `dlsym` error
* 1 : Log dlsym error
#### BOX86_TRACE_FILE
Send all log and trace to a file instead of `stdout`
Also, if name contains `%pid` then this is replaced by actual PID of box86 instance
#### BOX86_TRACE
Only on build with trace enabled. Trace allow the logging of all instruction execute, along with register dump
* 0 : No trace
* 1 : Trace enabled. The trace start after the init of all depending libs is done
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found)
* 0xXXXXXXX-0xYYYYYYY : trace only between the 2 addresses
#### BOX86_TRACE_INIT
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before init of Libs and main program
* 0 : No trace
* 1 : Trace enabled. The trace start with the init of all depending libs is done
#### BOX86_TRACE_START
Only on build with trace enabled.
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`)
#### BOX86_TRACE_XMM
Only on build with trace enabled.
* 0 : Default, the XMM (i.e. SSE/SSE2) register will not be logged with the general and x87 registers
* 1 : Dump the XMM registers
#### BOX86_LOAD_ADDR
Try to load at 0xXXXXXX main binaray (if binary is a PIE)
* 0xXXXXXXXX the load address (only active on PIE programs)
#### BOX86_NOSIGSEGV
To disable handling of SigSEGV (to ease debugging mainly)
* 0 : default, let x86 program set sighandler for SEGV
* 1 : disable handling of SigSEGV
#### BOX86_NOSIGILL
To disable handling of SigILL (to ease debugging mainly)
* 0 : default, let x86 program set sighandler for Illegal Instruction
* 1 : disable handling of SigILL
#### BOX86_X11COLOR16
PANDORA only: to try convert X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows
* 0 : default, don't touch X11 colors
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC
#### BOX86_X11THREADS
To call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)
* 0 : default, don't force call XInitThreads
* 1 : Call XInitThreads as soon as libX11 is loaded
#### BOX86_X11GLX
To Force libX11 GLX extension to be present
* 0 : Disable the force.
* 1 : default, GLX will always be present when using XQueryExtension
#### BOX86_DYNAREC_DUMP
* 0 : Disable Dynarec blocks dump (default)
* 1 : Enable Dynarec blocks dump
* 2 : Enable Dynarec blocks dump with some colors
#### BOX86_DYNAREC_LOG
Set level of DynaRec log
* 0 :
* NONE : No Log for DynaRec
* 1 :
* INFO : Minimum Dynarec Log (only unimplemented OpCode)
* 2 :
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
* 3 :
* VERBOSE : All above plus more
#### BOX86_DYNAREC
* 0 : Disable Dynarec
* 1 : Enable Dynarec (default)
#### BOX86_DYNAREC_LINKER
* 0 : Disable Dynarec Linker (use that on debug, with dynarec log >= 2, to have detail on wich block get executed)
* 1 : Enable Dynarec Linker (default)
#### BOX86_DYNAREC_TRACE
* 0 : Disable trace for generated code (default)
* 1 : Enable trace for generated code (like regular Trace, this will slow down a lot and generate huge logs)
#### BOX86_LIBGL
* libXXXX set the name for libGL (default to libGL.so.1)
* /PATH/TO/libGLXXX set the name and path for libGL
You can also use SDL_VIDEO_GL_DRIVER
#### BOX86_LD_PRELOAD
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
#### BOX86_EMULATED_LIBS
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
Some games use old version of some lib, with an ABI incompatible with native version.
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
#### BOX86_ALLOWMISSINGLIBS
Allow box86 to continue even if a lib is missing
* 0 : default, stop if a lib cannot be loaded
* 1 : continue even if a needed lib cannot be loaded. Unadvised, this will, in most cases, crash later on.
#### BOX86_FIX_64BIT_INODES
* 0 : Don't fix 64bit inodes (default)
* 1 : Fix 64bit inodes. Helps when running on filesystems with 64bit inodes, the program uses API functions which don't support it and the program doesn't use inodes information.
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-hacker
+153
View File
@@ -0,0 +1,153 @@
v0.2.4
======
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
* Introduce BOX86_DYNAREC_STRONGMEM, like with box64 (not found any program that needs that yet)
* More vulkan wrapped function (so dkvk works, at least with RX550)
* Reworked Elfloader part, with better handling of versionned symbols
* Improve speed for x87 code (by avoiding many float<->double conversion)
* Improve speed of the custom allocator used by dynarec and Hash (speedup loading)
* Added a detection of box64 in uname call, to expose an x86_64 system instead of i386 one
* Added a fix for linking box86 on system using glibc 2.34+
* A few more wrapped libs
* More ARM hardware option in CMake (Phytium, SD845)
* Changed a bit struture of Dynarec, switching some operations from Pass1 to Pass0
* Small fixes to elfloader
* Some fixes and improvments on wrapped libs (mainly gtk2, gtk3 and d3dadpter)
* Better VSyscall implementation
* Fixed the "Alternate" handling (address shadowing on x86 side)
* A few opcodes border case fixes
* Improved wrapper helpers (from rajdakin)
* Added a mecanism to cancel a Dynarec block construction if it triggers a segfault (instead of a crash)
* Improvment to the handling of longjmp inside signal handlers
v0.2.2
======
* Reworked some elfloader relocation mecanism
* Removed old "smart linker" and replace with a simple "jump table"
* Also removed CALL/RET optomisation from Dynarec, simple Jump Table is faster
* Reworked all memory protection tracking
* A few more wrapped libs and wrapped functions
* A few more opcodes
* A few more dynarec opcodes
* Some optimisation in Dynarec around ZF and CF flags handlings, and LL/GE/LE/G conditionnal opcodes
* Some changes to the "cancel threads" handling
* Some changes to the "thread once" handling
v0.2.0
======
* Improvements on x86 Flags handling.
* A few more opcode has been added.
* A few potential BusError are now fixed.
* Added the BOX86_NOVULKAN en. var. . This is used to disable the wrapping of vulkan libraries.
* Improvments on libc O_XXXX flags handling.
* Box86 now uses a custom allocator for Dynarec and Hash tables.
* Improved the wrapping of pulse audio.
* Optimisation to a few Dynarec opcode (like SHRD/SHLD).
* Improved the tracking of memory protection.
* A few more wrapping of libraries (like libgssapi_krb5).
* More function wrapping on libturbojpeg
* Preliminary support for POWER9 (ppcle) build
* Many contributions to remove typos and rephrase the README, COMPILE and USAGE documents
v0.1.8
======
* Fixes on some float to int x86 convertions opcodes.
* Reworked all callback mecanisms.
* Added libturbojpeg wrapping (and a hack for zoom to force using native one).
* Added the BOX86_SAFEMMAP env. var.
* Reworked Dynarec's memory manager.
* Added a few opcodes.
* Improve elfloader to not force PltResolver all the time (fixing SuperHexagon and maybe other)
* Reworked Exet and Cancel Thread mecanism.
* Added wrapped libldap_r and liblber library (used by wine)
* Reworked Dynarec block handling, and remove the "AddMark" mecanism that wasn't efficient enough
* Added TokiTori 2+ detection and runtime patch on the Raspberry Pi platform
* Fixes on elfloader with TLS object.
v0.1.6
======
* Changes in Dynarec to make flags optimizations before CALL and RET opcode less aggressive.
* Added a Vulkan wrapper.
* Improved wrapping of SDL_mixer/ SDL2_mixer libraries.
* Improved wrapping of some GTK structures.
* Added a quick and dirty wrapping of GTK3 (based on current GTK2).
* Improved the signal handling, should be more stable now (the signal handler from syscall still need some works).
* Added the RK3399 profile, and some hints to build 32bits box86 on 64bits OS.
* Fixed some wrapped printf formating not handled correctly.
* Fixed some buserror with the new LOCK mecanism handling.
* A few more Dynarec opcodes added.
* If winedbg is tried to be launched, exit without launching it (it doesn't work anyways).
v0.1.4
======
* Change in Dynarec's memory handling, to simplify it (and hopefully optimized it).
* Even more opcodes added.
* And some more Dynarec opcodes.
* Fixed some issue were PltResolver was injected but should not be.
* Fixed many Dynarec and non dynarec opcodes.
* Improved Signal handling.
* Added a few more wrapped libraries (like curl).
* Gallium9 is now wrapped (thx @icecream95).
* Fixed and simplied many wrapped functions (especialy the one where a callback is involved).
* Fixed Dynarec "freeing" a Dynablock sometimes causing a corruption of the heap (generally happens in case of JIT code).
* Optimized the way LOCK prefix work when using Dynarec on ARM.
* improvements to the ARM opcode Printer (for dumping Dynarec blocks) improvement (thx @rajdakin).
v0.1.2
======
* The Dynarec now handle JIT code
* Added support for Unity games (not perfect yet).
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it.
* Added support for Steam (not perfect yet). Note that Steam have limited functionalities on 32bits (only mini-mode is available).
* More wrapped libs
* Added support for the "PltResolver". This makes the order of libraries less important and many symbols are now resolved at runtime.
* Added an option to build Box86 as a library (to wrap dynamic library).
* Better Signal handling (not perfect yet).
* More opcodes added, more opcode fixes.
* More Dynarec opcodes.
* Added support for FS:, and creating custom selector (needed by Wine).
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling).
* Box86 now has a logo!
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
v0.1.0
=======
* Dynarec!!! Only for ARM (note that Dynarec doesn't support JITed code for now).
* Added real support for getcontext/set/context/makecontext/swapcontext.
* Preliminary signal handling.
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage.
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others.
* Added wrapped GTK support (still ongoing, many libraries involved).
* Make loading of libraries more configurable.
* If a wrapped native library is not found, try to use an emulated one.
* Added an env. var. to force the use of emulated libraries for certain libraries.
* Added an env. var. to precise which libGL to use.
* Added Install / Uninstall target (using systemd binfmt).
* Added more hardware targets (RPis, GameShell...).
* Wrapped more libraries (including FreeType, smpeg, ncurses, sndfile...).
v0.0.4
=======
* Improved the initialisation of dependent libraries. More things work now.
* Added a lot of wrapped functions.
* Added a few wrapped libraries (like libz or some other x11 related library).
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better).
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now).
* FTL 1.6.9 still has corrupted music, but older 1.5.13 seems fine (different set of libraries).
v0.0.2
=======
* A full commercial games runs fine on the Pandora platform: Airline Tycoon Deluxe.
* Implemented all planned subparts of Box86 except JIT support.
* CPU Emulation is at roughly 75%. This includes x87 and SSE/SSE2. MMX is barely implemented (but barely used anyway).
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as the native libm library is used)
* No Signal handling yet
* ELF Loader is crude and probably full of bugs. Also, the initialisation of libraries are defered after all symbols are resolved for now.
* Wrapped libraries include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
* Most wrapped libraries are still partially implemented ( the SDL1 & GL libraries should be complete).
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world.
* WorldOfGoo works, but is painfully slow on the Pandora platform (there is too much double math, and lack of JIT).
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
* Limbo launches but crashes before main menu.
+120
View File
@@ -0,0 +1,120 @@
Compiling
----
#### for Pandora
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Pyra
`mkdir build; cd build; cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Gameshell
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
#### for Raspberry Pi
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
```
git clone https://github.com/ptitSeb/box86
cd box86
mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make
sudo make install
sudo systemctl restart systemd-binfmt
```
Note that you can use `make -j2` or more to speed up 1st build, but beware of the memory requirement if you go to high.
#### for Raspberry Pi on 64bits OS
_For Pi4. Change to RPI2 or RPI3 for other models. Change `-DRPI4=1` to `-DRPI4ARM64=1` for compiling on arm64. (armhf multiarch or chroot required alongside armhf gcc. Install it with 'sudo apt install gcc-arm-linux-gnueabihf'.)_
```
git clone https://github.com/ptitSeb/box86
cd box86
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j2
sudo make install
sudo systemctl restart systemd-binfmt
```
#### for ODROID
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
#### for RK3399
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
#### for Tinker Board (1/1S) or RK3288
`mkdir build; cd build; cmake .. -DRK3288=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
#### for Allwinner A64
`mkdir build; cd build; cmake .. -DA64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
As most Allwinner A64 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
#### for Snapdragon 845
`mkdir build; cd build; cmake .. -DSD845=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
As most Snapdragon 845 device run AARCH64 OS, in most cases you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
#### for Phytium
`mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian/ubuntu, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
#### for Other ARM Linux platforms
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
#### for x86 Linux
`mkdir build; cd build; cmake .. -DCMAKE_C_FLAGS="-m32" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
#### use ccmake
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
#### Customize your build
*use ccache if you have it*
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
*have some debug info*
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
*to have a Trace Enabled build*
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
*to have ARM Dynarec*
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode). Note that compiling with `ARM_DYNAREC` but without hardware profile is not advise. If you get error building that "target CPU does not support ARM mode", then try to pick hardware profile (like ODROID for armv7 or PI4 for armv8). Also, if you are using a 64bits with armhf multiarch, it's much easier to pick one of the hardware profile like `RPI4ARM64`, `RK3399`, `PHYTIUM` or `SD845`.
*not building from a git clone*
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
----
Testing
----
A few tests are included.
They can be launched with `ctest`
They are very basic and don't test much for now.
----
Note about devices with Tegra X1 and newer.
Nvidia don't provide armhf libraries for their GPU drivers at this moment so there is no special variable to compile it for them as it would be missleading for many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. As instalation of Mesa can break Nvidia driver, safest option is usage of chroot.
Executable
+126
View File
@@ -0,0 +1,126 @@
# box86
![Official logo](img/Box86Logo.png "Official Logo")
Linux Userspace x86 Emulator with a twist
[![Build Status](https://app.travis-ci.com/ptitSeb/box86.svg?branch=master)](https://app.travis-ci.com/ptitSeb/box86)
----
Compiling/Installation
----
> Compilation instructions can be found [here](COMPILE.md)
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary. (Most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android).)
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter. Some high level information on how the Dynarec work can be found [here](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/).
Many games already work without much tweaking, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine. (there's a long list, among them are UNDERTALE, A Risk of Rain, and Cook Serve Delicious)
If you are serious about developing Box86, you should install ccache and build Box86 with it. (Use ccmake for example.)
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
[![Play on Youtube](https://img.youtube.com/vi/bLt0hMoFDLk/3.jpg)](https://www.youtube.com/watch?v=bLt0hMoFDLk) [![Play on Youtube](https://img.youtube.com/vi/MM7kWYts7IA/3.jpg)](https://www.youtube.com/watch?v=MM7kWYts7IA) [![Play on Youtube](https://img.youtube.com/vi/8hr71S029Hg/1.jpg)](https://www.youtube.com/watch?v=8hr71S029Hg) [![Play on Youtube](https://img.youtube.com/vi/B4YN37z3-ws/1.jpg)](https://www.youtube.com/watch?v=B4YN37z3-ws) [![Play on Youtube](https://img.youtube.com/vi/xk8Q30mxqPg/1.jpg)](https://www.youtube.com/watch?v=xk8Q30mxqPg) [![Play on Youtube](https://img.youtube.com/vi/_QMRMVvYrqU/1.jpg)](https://www.youtube.com/watch?v=_QMRMVvYrqU)
You can find many more Box86 video on Youtube in the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) Channels
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
<img src="img/Box86Icon.png" width="96" height="96">
Logo and Icon made by @grayduck, thanks!
Note that this project is not to be mistaken with [86box](https://github.com/86Box/86Box), a nice "Full system" emulator specialized in early (to fairly recent) PC hardware.
----
Usage
----
There are a few environment variables to control the behaviour of Box86.
See [here](USAGE.md) for all environment variables and what they do.
Note: Box86's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
----
Version history
----
The change log is available [here](CHANGELOG.md)
----
Notes about 64-bit platforms
----
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
If you look at a 64bits version of box86, look at [Box64](https://github.com/ptitSeb/box64): this one is able to run x86_64 binaries on 64-bit platforms. But note that you still need Box86 (and a 32-bit chroot) to run x86 binaries (as it also happens on actual x86_64 Linux that need x86 libs and binary on multiarch to run).
----
Notes about Unity game emulation
----
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with the new "protected memory" mechanism implemented it should be running with correct performance now.
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
----
Notes about Steam
----
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works:
- First problem is Steam crashing after the sign-in window, if you encounter this issue, you may need to add libappindicator. To install it on Debian, run `sudo apt install libappindicator1`.
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm intalled. To install it on Debian, run `sudo apt install libnm0`.
- Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode". This is because some Steam components used in the browser view are only 64-bit now. So go in the "View" menu and switch to "Small view", else the list will stay empty. Alternatively, Steam can be started in small mode directly by using `+open steam://open/minigameslist` command line arguments.
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
Steam for Windows installs fine but doesn't work yet.
----
Notes about Wine
----
Wine is now supported. Wine integrated program all runs, and many windows programs and games also runs fine. Don't forget most Windows games use Direct3D, this may require a complete OpenGL driver and a as high profile as possible (and gl4es with ES2 backend have issue with Wine for now).
Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those models use a default OS that have a kernel with a 2/2 Split (meaning 2G of space for user program, and 2G of space for the Kernel). This is not compatible with Wine programs that needs to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split.
----
Notes about Vulkan
----
Box86 already wrap vulikan. If your system has a 32bits vulkan driver, box86 will use it when needed. Note that vulkan wrapping has not been tested much, due to the limited vulkan support on the hardware I currently own. Profile 1.0 and 1.1, whith some extension, should be OK. 1.2 is not really wrapped. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardxware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
----
Final word
----
I want to thank everyone who has contributed to box86 developpement.
There are many ways to contribute: code, financial, hardware and advertisement!
So, in no particular order, I want to thank:
* For their major code contribution: rajdakin, icecream95, M-HT
* For their major financial contribution: FlyingFathead, stormchaser3000
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
* For their continous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
And I also thank the many other people who participated even once in the project.
(If you use Box86 in your project, please don't forget to mention it!)
Executable
+178
View File
@@ -0,0 +1,178 @@
Usage
----
There are many environment variables to control Box86 behaviour.
#### BOX86_LOG
Controls the Verbosity level of the logs
* 0: NONE : No message (except some fatal error). (Default.)
* 1: INFO : Show some minimum log (Example: librairies not found)
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
* 3: DUMP : All DEBUG plus DUMP of all ELF Info (so same as `BOX86_LOG=2 BOX86_DUMP=1`)
#### BOX86_DUMP
Controls the Dump of elf content
* 0: No dump of elf information (Default)
* 1: Dump elf sections and relocations and other information (also active if using `BOX86_LOG=3`)
#### BOX86_NOBANNER
Disables Box86 printing its version and build
* 0 : Enable printing its banner. (Default.)
* 1 : Disable printing its banner.
#### BOX86_LD_LIBRARY_PATH
Path to look for x86 libraries. Default is current folder and `lib` in current folder.
Also, `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exist.
#### BOX86_PATH
Path to look for x86 executable. Default is current folder and `bin` in current folder.
#### BOX86_DLSYM_ERROR
Enables/Disables the logging of `dlsym` errors.
* 0 : Don't log `dlsym` errors. (Default.)
* 1 : Log dlsym errors.
#### BOX86_TRACE_FILE
Send all log and trace to a file instead of `stdout`
Also, if name contains `%pid` then this is replaced by the actual PID of box86 instance
Use `stderr` to use this instead of default `stdout`
#### BOX86_TRACE
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
* 0 : No trace. (Default.)
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
#### BOX86_TRACE_INIT
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
* 0 : No trace. (Default.)
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
#### BOX86_TRACE_START
Only on builds with trace enabled.
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
#### BOX86_TRACE_XMM
Only on builds with trace enabled.
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
* 1 : Dump the XMM registers.
#### BOX86_LOAD_ADDR
Try to load at 0xXXXXXX main binary (if binary is a PIE)
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
#### BOX86_NOSIGSEGV
Disable handling of SigSEGV. (Very useful for debugging.)
* 0 : Let the x86 program set sighandler for SEGV (Default.)
* 1 : Disable the handling of SigSEGV.
#### BOX86_NOSIGILL
Disable handling of SigILL (to ease debugging mainly).
* 0 : Let x86 program set sighandler for Illegal Instruction
* 1 : Disables the handling of SigILL
#### BOX86_X11COLOR16
PANDORA only: Try converting X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows).
* 0 : Don't touch X11 colors. (Default.)
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC.
#### BOX86_X11THREADS
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
* 0 : Don't force call XInitThreads. (Default.)
* 1 : Call XInitThreads as soon as libX11 is loaded.
#### BOX86_X11GLX
Force libX11's GLX extension to be present.
* 0 : Do not force libX11's GLX extension to be present.
* 1 : GLX will always be present when using XQueryExtension. (Default.)
#### BOX86_DYNAREC_DUMP
Enables/disables Box86's Dynarec's dump.
* 0 : Disable Dynarec's blocks dump. (Default.)
* 1 : Enable Dynarec's blocks dump.
* 2 : Enable Dynarec's blocks dump with some colors.
#### BOX86_DYNAREC_LOG
Set the level of DynaRec's logs.
* 0 : NONE : No Logs for DynaRec. (Default.)
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
* 3 : VERBOSE : All of the above plus more.
#### BOX86_DYNAREC
Enables/Disables Box86's Dynarec.
* 0 : Disables Dynarec.
* 1 : Enable Dynarec. (Default.)
#### BOX86_DYNAREC_TRACE
Enables/Disables trace for generated code.
* 0 : Disable trace for generated code. (Default.)
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
#### BOX86_NODYNAREC
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
#### BOX86_DYNAREC_BIGBLOCK
Enables/Disables Box86's Dynarec building BigBlock.
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
* 1 : Build Dynarec block as big as possible (Default.)
#### BOX86_DYNAREC_STRONGMEM
Enable/Disable simulation of Strong Memory model
* 0 : Don't try anything special (Default.)
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
#### BOX86_LIBGL
* libXXXX set the name for libGL (defaults to libGL.so.1).
* /PATH/TO/libGLXXX : Sets the name and path for libGL
You can also use SDL_VIDEO_GL_DRIVER
#### BOX86_LD_PRELOAD
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
#### BOX86_EMULATED_LIBS
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
Some games uses an old version of some libraries, with an ABI incompatible with native version.
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
#### BOX86_ALLOWMISSINGLIBS
Allow Box86 to continue even if a library is missing.
* 0 : Box86 will stop if a library cannot be loaded. (Default.)
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
#### BOX86_NOPULSE
Disables the load of pulseaudio libraries.
* 0 : Load pulseaudio libraries if found. (Default.)
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
#### BOX86_NOGTK
Disables the loading of wrapped GTK libraries.
* 0 : Load wrapped GTK libraries if found. (Default.)
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
#### BOX86_NOVULKAN
Disables the load of vulkan libraries.
* 0 : Load vulkan libraries if found.
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
#### BOX86_FIX_64BIT_INODES
Fix/Don't fix 64bit inodes
* 0 : Don't fix 64bit inodes. (Default.)
* 1 : Fix 64bit inodes. Helps when running on Filesystems with 64bit inodes. Is useful when a program uses API functions which doesn't support it and the program doesn't use inodes information.
#### BOX86_JITGDB
* 0 : Just print the Segfault message on segfault (default)
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
When in gdb, you need to find the correct thread yourself (the one with `my_box86signalhandler` in is stack)
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box86signalhandler`,
just before the printf of the Segfault message. Then simply
`set waiting=0` to exit the infinite loop.
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
Use `gdb /PATH/TO/box86` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX86_JITGDB=1`.
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
+137
View File
@@ -0,0 +1,137 @@
# Installing Wine (and winetricks)
_TwisterOS users: Wine, winetricks, and Box86 are already installed in TwisterOS. You do not have to install anything._
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 already has a 3G/1G split kernel and works with Wine, but **the Pi 3B+ and earlier models have a 2G/2G kernel and require a custom-compiled 3G/1G kernel to get Wine working.**_
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
See installation steps below (in the [Examples](#examples) section).
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM devices other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
Installation files for Wine can be found in the [WineHQ repository](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/), the [TwisterOS FAQ](https://twisteros.com/faq.html) page, or the [PlayOnLinux website repository](https://www.playonlinux.com/wine/). Box86 requires the "i386" (x86) version of Wine even though we are installing it on an ARM processor.
## Overview
The general procedure for installing Wine for Box86 is to...
- Download all the install files (.deb, .zip, or even .pol files) for the version of Wine you wish to install
- Unzip or dpkg the install files into one folder
- Move that folder to the directory that you wish Wine to run from (in TwisterOS, this is `~/wine/` by default)
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries (`wine`, `winecfg`, and `wineserver`).
- Boot wine to create a new wineprefix (`wine wineboot`).
- Download winetricks (which is simply a very complicated bash script), make it executable, then copy it to `/usr/local/bin`.
## Examples
### Installing Wine for Box86 on Raspberry Pi OS from Twister OS FAQ .tgz files
_Links from the [TwisterOS FAQ](https://twisteros.com/faq.html)_
This installs Wine v5.13 (which is the version of Wine that comes pre-installed in TwisterOS). When submitting bug reports, other Box86 users may assume you are using this version of Wine unless you specify otherwise.
```
# Backup any old wine installations
sudo mv ~/wine ~/wine-old
sudo mv ~/.wine ~/.wine-old
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
# Download, extract wine, and install wine (last I checked, the Twister OS FAQ page had Wine 5.13-devel)
wget https://twisteros.com/wine.tgz -O ~/wine.tgz
tar -xzvf ~/wine.tgz
rm ~/wine.tgz # clean up
# Install shortcuts (make launcher & symlinks. Credits: grayduck, Botspot)
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
# Boot wine (make fresh wineprefix in ~/.wine )
wine wineboot
```
### Installing Wine for Box86 on Raspberry Pi OS Buster from WineHQ .deb files
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/)_
This install method allows you to install different versions of Wine. You may install any version and any branch of Wine that you wish (wine-devel, wine-stable, or wine-staging).
```
# Backup any old wine installations
sudo mv ~/wine ~/wine-old
sudo mv ~/.wine ~/.wine-old
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
# Download, extract wine, and install wine
# (Replace the links/versions below with links/versions from the WineHQ site for the version of wine you wish to install. Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.)
# (Pick an i386 version of wine-devel, wine-staging, or wine-stable)
cd ~/Downloads
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel-i386_5.21~buster_i386.deb # NOTE: Replace this link with the version you want
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel_5.21~buster_i386.deb # NOTE: Also replace this link with the version you want
dpkg-deb -xv wine-devel-i386_5.21~buster_i386.deb wine-installer # NOTE: Make sure these dpkg command matches the filename of the deb package you just downloaded
dpkg-deb -xv wine-devel_5.21~buster_i386.deb wine-installer
mv ~/Downloads/wine-installer/opt/wine* ~/wine
rm wine*.deb # clean up
rm -rf wine-installer # clean up
# Install shortcuts (make 32bit launcher & symlinks. Credits: grayduck, Botspot)
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
# These packages are needed for running wine-staging on RPi 4 (Credits: chills340)
sudo apt install libstb0 -y
cd ~/Downloads
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
sudo cp -TRv libfaudio/usr/ /usr/
rm libfaudio0_*~bpo10+1_i386.deb # clean up
rm -rf libfaudio # clean up
# Boot wine (make fresh wineprefix in ~/.wine )
wine wineboot
```
## Installing winetricks
Winetricks is a bash script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs. You can either install it with `apt`, or manually using the steps below.
```
sudo apt-get install cabextract -y # winetricks needs this installed
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old # Backup old winetricks
cd ~/Downloads && wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks # Download
sudo chmod +x winetricks && sudo mv winetricks /usr/local/bin/ # Install
```
Whenever we run winetricks, we must tell Box86 to supress its info banner, otherwise winetricks will crash. Box86's info banner can be suppressed using the `BOX86_NOBANNER=1` environment variable before invoking winetricks (example: `BOX86_NOBANNER=1 winetricks`).
If `apt` installed a desktop menu shortcut for winetricks (or if you make your own desktop shortcut for winetricks) then you may need to edit that shortcut to include Box86's BOX86_NOBANNER=1 env var. With your favorite text editor, edit `/usr/share/applications/winetricks.desktop` and change `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`.
## Example commands
Here is an example of how we should run a winetricks command with box86:
`BOX86_NOBANNER=1 winetricks -q corefonts vcrun2010 dotnet20sp1`
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
Whenever we run winetricks, we must suppress Box86's banner by typing `BOX86_NOBANNER=1` to prevent winetricks from crashing. Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will also cause winetricks to crash. (If Box86 logging is necessary though, we can patch winetricks to avoid these crashes - see the *Troubleshooting* section) # future work.
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
## Other notes
### Wineprefixes (and Wine initialization)
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable. For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
### Transplanting wineprefixes (side-loading)
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
### Swapping out different versions of Wine
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will migrate a wineprefix from an older version of Wine to be usable by the newer version of Wine you just installed. You can check which version of Wine you're running with the `wine --version` command.
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-hacker
File renamed without changes.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-arm-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-arm-git}-git" "${pkgname%-arm-git}")
conflicts=("${pkgname%-git}" "${pkgname%-arm-git}-git" "${pkgname%-arm-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-arm-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-arm-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-arm-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-arm-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-gameshell-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
conflicts=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-gameshell-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-gameshell-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-gameshell-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-gameshell-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-odroid-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
conflicts=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-odroid-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-odroid-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-odroid-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-odroid-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-pandora-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
conflicts=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-pandora-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-pandora-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-pandora-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-pyra-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
conflicts=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-pyra-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-pyra-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-pyra-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-pyra-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+59
View File
@@ -0,0 +1,59 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-rpi-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
pkgver() {
cd "$srcdir/${pkgname%-rpi-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rpi-git}"
# Check for Pi version number
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
_piversion=4
elif [[ ${_pimodel} =~ "Raspberry Pi 3" ]]; then
_piversion=3
elif [[ ${_pimodel} =~ "Raspberry Pi 2" ]]; then
_piversion=2
else
# This RPI is not supported or this device is not a pi.
# We should cancel then the build.
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported yet).\033[00m"
exit 1
fi
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-rpi-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-rpi-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+44
View File
@@ -0,0 +1,44 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-rk3399-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('armv7h')
url="https://github.com/ptitSeb/box86"
license=('MIT')
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-rk3399-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-rk3399-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-rk3399-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-arm-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+43
View File
@@ -0,0 +1,43 @@
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
# Author: Sebastien Chevalier <[email protected]>
pkgname=box86-x86-git
pkgver=3494.bedacef
pkgrel=1
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
arch=('i386')
url="https://github.com/ptitSeb/box86"
license=('MIT')
makedepends=('git' 'cmake' 'make')
provides=("${pkgname%-git}" "${pkgname%-x86-git}-git" "${pkgname%-x86-git}")
conflicts=("${pkgname%-git}" "${pkgname%-x86-git}-git" "${pkgname%-x86-git}")
source=('git+https://github.com/ptitSeb/box86')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/${pkgname%-x86-git}"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
prepare() {
cd "${srcdir}/${pkgname%-x86-git}"
if [[ ! -d ./build ]]; then
mkdir build && cd build
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
fi
}
build() {
cd "$srcdir/${pkgname%-x86-git}/build"
make -j$(nproc)
}
package() {
cd "$srcdir/${pkgname%-x86-git}/build"
make DESTDIR="${pkgdir}/" install
# /usr/local/bin isn't in PATH by the default,
# we should move it to /usr/bin
cd ${pkgdir}
mv usr/local/bin/ usr/bin/
# cleanup when dir is empty
rmdir usr/local || exit 0
}
+24
View File
@@ -0,0 +1,24 @@
# The directory containing all PKGBUILDs for BOX86
## FAQ
### 1. How to use it?
Just download the `PKGBUILD-<your-platform>` (no need to download the whole repository), go to directory where you downloaded and type:
```sh
mv ./PKGBUILD-<your-platform> ./PKGBUILD
cd ..
makepkg -si
```
This will copy the PKGBUILD for your platform (where you type your platform name instead of `<your-platform>`), build it and install the PKGBUILD on 32-bit Archlinux ARM.
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
### 2. What platforms are currently supported.
All specified in [COMPILE.md](../COMPILE.md).
### 3. Any advantages with that sollution?
This might give you some advantages like those:
- automatic updates (with some AUR frontends like [`pamac-aur`](https://aur.archlinux.org/packages/pamac-aur/) or [`yay`](https://aur.archlinux.org/packages/yay));
- easily uninstall with `pacman -R` when no needed (no need other scripts nor Makefile to do this);
- your `box86` installation is recognized as a package (where it wasn't when installing with `make install`).
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box86 to .deb or .rpm installer files.
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
systemctl restart systemd-binfmt
+303 -294
View File
@@ -5,6 +5,13 @@ import re
import sys
from math import ceil
"""
Generates src/dynarec/arm_printer.c
===
See src/dynarec/arm_instructions.txt (the input file) for the syntax documentation.
"""
# Helper class to avoid displaying '\x1b[' on errors
class string(str):
def __repr__(self):
@@ -172,13 +179,6 @@ def main(root, ver, __debug_forceAllDebugging=False):
- specifics is an array of arrays the same length as positions that contains a tuple (mask, correctBit)
that is at position positions[current_pos]
"""
if len(positions) != len(specifics):
fail(
AssertionError,
"generate_bin_tests requires the same length for positions ({}) and specifics ({})!".format(
len(positions), len(specifics)
)
)
if specifics == []:
append("if ((opcode & " + arr2hex(mask) + ") == " + arr2hex(correctBits) + ") {\n")
@@ -194,8 +194,9 @@ def main(root, ver, __debug_forceAllDebugging=False):
if any(map(lambda s: len(s) != l, specifics)):
fail(
AssertionError,
"generate_bin_tests requires the same length for positions ({}) and specifics ({})!".format(
len(positions), len(specifics)
"generate_bin_tests requires the same length for positions ({}) and each element "
"of the specifics array ({})!".format(
len(positions), [len(s) for s in specifics]
)
)
@@ -290,7 +291,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
# Custom ifs
# Also, requires only a single '='
if eq != "=":
fail(ValueError, "Too many '=' switches (!@ modifier)")
fail(ValueError, "Too many '=' switches (@@ modifier)")
# Extract the statements
statements = []
@@ -575,11 +576,11 @@ def main(root, ver, __debug_forceAllDebugging=False):
append("int rot = (opcode >> " + str(variables["r"]) + ") & 3;\nchar tmprot[8] = {0};\n")
append("if (rot) {\nsprintf(tmprot, \" ror %d\", rot * 8);\n}\n")
if variables["sb"][0] != -1:
append("int lsb = (opcode >> " + str(variables["sb"][0]) + ") & 0xF;\n")
append("int lsb = (opcode >> " + str(variables["sb"][0]) + ") & 0x1F;\n")
if variables["sb"][1] != -1:
append("int msb = (opcode >> " + str(variables["sb"][1]) + ") & 0xF;\n")
append("int msb = (opcode >> " + str(variables["sb"][1]) + ") & 0x1F;\n")
if variables["sb"][2] != -1:
append("int widthm1 = (opcode >> " + str(variables["sb"][2]) + ") & 0xF;\n")
append("int widthm1 = (opcode >> " + str(variables["sb"][2]) + ") & 0x1F;\n")
if variables["reglist16"] != -1:
append("int reglist = (opcode >> " + str(variables["reglist16"]) + ") & 0xFFFF;\n")
if imms != []:
@@ -620,7 +621,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
skiprbr = False
if idx % 2:
if text == "c":
if variables["cond"] != -1:
if variables["cond"] >= 0:
append("%s")
printf_args = printf_args + ", cond"
elif text == "Rd":
@@ -1105,7 +1106,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
l = len(imms) == 2
if l:
append("uint8_t l = (opcode >> " + str(imms[1][1]) + ") & 0x1;\n")
append("uint8_t l = (opcode >> " + str(imms[1][0]) + ") & 0x1;\n")
immssz = 6
append("uint8_t imm6 = (opcode >> " + str(imms[0][0]) + ") & 0x3F;\n")
@@ -1653,7 +1654,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
# No C variable since we're invalidating!
# Now print the invalidation, numerote if debugging
# Now print the invalidation, number if debugging
if numberInvalids:
append("strcpy(ret, \"??? #" + str(invalidationCount) + "\");\n} else ")
invalidationCount = invalidationCount + 1
@@ -1674,301 +1675,309 @@ def main(root, ver, __debug_forceAllDebugging=False):
# Now the files rebuilding part
# File header and guard
header = """/*****************************************************************
* File automatically generated by rebuild_printer.py (v{version})
*****************************************************************/
"""
files_header = {
"arm_printer.c": """#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "arm_printer.h"
// conditions
#define cEQ (0b0000<<28)
#define cNE (0b0001<<28)
#define cCS (0b0010<<28)
#define cCC (0b0011<<28)
#define cMI (0b0100<<28)
#define cPL (0b0101<<28)
#define cVS (0b0110<<28)
#define cVC (0b0111<<28)
#define cHI (0b1000<<28)
#define cLS (0b1001<<28)
#define cGE (0b1010<<28)
#define cLT (0b1011<<28)
#define cGT (0b1100<<28)
#define cLE (0b1101<<28)
#define c__ (0b1110<<28) // means all
static const char* conds[16] = {
"EQ", "NE", "CS", "CC",
"MI", "PL", "VS", "VC",
"HI", "LS", "GE", "LT",
"GT", "LE", "", "##"
};
static const char* regname[16] = {
"r0", "r1", "r2", "r3", "r4",
"r5", "r6", "r7", "r8", "r9",
"r10", "r11", "r12", "SP", "LR", "PC"
};
// Single precision are V_:_
// Double and quad precision are _:V_
// So we always use _:V_ and invert the corresponding single-precision (cleaner? code)
static const char* vecname[96] = {
"S0", "S2", "S4", "S6", "S8", "S10", "S12", "S14",
"S16", "S18", "S20", "S22", "S24", "S26", "S28", "S30",
"S1", "S3", "S5", "S7", "S9", "S11", "S13", "S15",
"S17", "S19", "S21", "S23", "S25", "S27", "S29", "S31",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
"D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
"D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
"Q0", "!!!", "Q1", "!!!", "Q2", "!!!", "Q3", "!!!",
"Q4", "!!!", "Q5", "!!!", "Q6", "!!!", "Q7", "!!!",
"Q8", "!!!", "Q9", "!!!", "Q10", "!!!", "Q11", "!!!",
"Q12", "!!!", "Q13", "!!!", "Q14", "!!!", "Q15", "!!!"
};
static const char* dts[16] = {
"S8", "S16", "S32", "S64",
"U8", "U16", "U32", "U64",
"I8", "I16", "I32", "I64",
"F8", "F16", "F32", "F64"
};
static const char* shift_type[4] = {
"lsl ", "lsr ", "asr ", "ror "
};
const char* print_shift(int shift, int comma) {
static __thread char ret[20];
ret[0] = '\\0';
int sh_op = (shift >> 1) & 3;
if(shift & 1) {
int rs = shift >> 4;
sprintf(ret, "%s%s%s", (comma ? ", " : ""), shift_type[sh_op], regname[rs]);
} else {
uint8_t amount = shift >> 3;
if (!amount) {
switch (sh_op) {
case 0b00:
break;
case 0b01:
case 0b10:
sprintf(ret, "%s%s#32", (comma ? ", " : ""), shift_type[sh_op]);
break;
case 0b11:
sprintf(ret, "%srrx", (comma ? ", " : ""));
break;
}
} else {
sprintf(ret, "%s%s#%u", (comma ? ", " : ""), shift_type[sh_op], amount);
}
}
return ret;
}
#define print_modified_imm_ARM(imm12) (((imm12 & 0xFF) >> (imm12 >> 8)) | ((imm12 & 0xFF) << (32 - (imm12 >> 8))))
const char* print_register_list(int list, int size) {
int last = -2;
int cnt = 0;
static __thread char ret[68];
ret[0] = '{';
ret[1] = '\\0';
for (int i = 0; i < size; ++i) {
if (list & (1 << i)) {
if (last >= 0) {
++cnt;
"arm_printer.c": """
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "arm_printer.h"
// conditions
#define cEQ (0b0000<<28)
#define cNE (0b0001<<28)
#define cCS (0b0010<<28)
#define cCC (0b0011<<28)
#define cMI (0b0100<<28)
#define cPL (0b0101<<28)
#define cVS (0b0110<<28)
#define cVC (0b0111<<28)
#define cHI (0b1000<<28)
#define cLS (0b1001<<28)
#define cGE (0b1010<<28)
#define cLT (0b1011<<28)
#define cGT (0b1100<<28)
#define cLE (0b1101<<28)
#define c__ (0b1110<<28) // means all
static const char* conds[16] = {
"EQ", "NE", "CS", "CC",
"MI", "PL", "VS", "VC",
"HI", "LS", "GE", "LT",
"GT", "LE", "", "##"
};
static const char* regname[16] = {
"r0", "r1", "r2", "r3", "r4",
"r5", "r6", "r7", "r8", "r9",
"r10", "r11", "r12", "SP", "LR", "PC"
};
// Single precision are V_:_
// Double and quad precision are _:V_
// So we always use _:V_ and invert the corresponding single-precision (cleaner? code)
static const char* vecname[96] = {
"S0", "S2", "S4", "S6", "S8", "S10", "S12", "S14",
"S16", "S18", "S20", "S22", "S24", "S26", "S28", "S30",
"S1", "S3", "S5", "S7", "S9", "S11", "S13", "S15",
"S17", "S19", "S21", "S23", "S25", "S27", "S29", "S31",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
"D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
"D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
"Q0", "!!!", "Q1", "!!!", "Q2", "!!!", "Q3", "!!!",
"Q4", "!!!", "Q5", "!!!", "Q6", "!!!", "Q7", "!!!",
"Q8", "!!!", "Q9", "!!!", "Q10", "!!!", "Q11", "!!!",
"Q12", "!!!", "Q13", "!!!", "Q14", "!!!", "Q15", "!!!"
};
static const char* dts[16] = {
"S8", "S16", "S32", "S64",
"U8", "U16", "U32", "U64",
"I8", "I16", "I32", "I64",
"F8", "F16", "F32", "F64"
};
static const char* shift_type[4] = {
"lsl ", "lsr ", "asr ", "ror "
};
const char* print_shift(int shift, int comma) {
static __thread char ret[20];
ret[0] = '\\0';
int sh_op = (shift >> 1) & 3;
if(shift & 1) {
int rs = shift >> 4;
sprintf(ret, "%s%s%s", (comma ? ", " : ""), shift_type[sh_op], regname[rs]);
} else {
if (last == -1)
strcat(ret, ", ");
strcat(ret, regname[i]);
last = i;
uint8_t amount = shift >> 3;
if (!amount) {
switch (sh_op) {
case 0b00:
break;
case 0b01:
case 0b10:
sprintf(ret, "%s%s#32", (comma ? ", " : ""), shift_type[sh_op]);
break;
case 0b11:
sprintf(ret, "%srrx", (comma ? ", " : ""));
break;
}
} else {
sprintf(ret, "%s%s#%u", (comma ? ", " : ""), shift_type[sh_op], amount);
}
}
return ret;
}
#define print_modified_imm_ARM(imm12) (((imm12 & 0xFF) >> (2*(imm12 >> 8))) | ((imm12 & 0xFF) << (32 - 2*(imm12 >> 8))))
const char* print_register_list(int list, int size) {
int last = -2;
int cnt = 0;
static __thread char ret[68];
ret[0] = '{';
ret[1] = '\\0';
for (int i = 0; i < size; ++i) {
if (list & (1 << i)) {
if (last >= 0) {
++cnt;
} else {
if (last == -1)
strcat(ret, ", ");
strcat(ret, regname[i]);
last = i;
}
} else {
if (cnt) {
strcat(ret, "-");
strcat(ret, regname[i - 1]);
}
if (last != -2) last = -1;
cnt = 0;
}
}
} else {
if (cnt) {
strcat(ret, "-");
strcat(ret, regname[i - 1]);
strcat(ret, regname[size - 1]);
}
if (last != -2) last = -1;
cnt = 0;
strcat(ret, "}");
return ret;
}
}
if (cnt) {
strcat(ret, "-");
strcat(ret, regname[size - 1]);
}
strcat(ret, "}");
return ret;
}
const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_prec) {
static __thread char ret[68];
// Assume VFPSmallRegisterBank(), so no D16 and no S32 (and above)
if (start + (double_prec + 1) * size > 32) {
return "!!!";
}
if (size == 0) {
return "!!!";
}
if (double_prec && (size % 2 == 1)) {
strcpy(ret, "!! {");
} else {
ret[0] = '{';
ret[1] = '\\0';
}
char regChr;
if (double_prec) {
regChr = 'D';
size /= 2;
} else {
regChr = 'S';
start = (start >> 4) + ((start & 0xF) << 1);
}
char tmp[6];
for (int cur = start; cur < start + size - 1; ++cur) {
sprintf(tmp, "%c%d, ", regChr, cur);
strcat(ret, tmp);
}
sprintf(tmp, "%c%d}", regChr, start + size - 1);
strcat(ret, tmp);
return ret;
}
static const char* _print_modified_imm_I64_bytes[2] = {"00", "FF"};
const char* print_modified_imm_NEON(int op_cmode, int imm) {
static __thread char ret[34] = "???\\0-"; // [dt: 4][imm: 30]
strcpy(&ret[4], "UNPREDICTABLE");
switch (op_cmode) {
case 0b00000: // VMOV.I32
case 0b00001: // VORR.I32
case 0b10000: // VMVN.I32
case 0b10001: // VBIC.I32
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X", imm);
break;
case 0b00010: // VMOV.I32
case 0b00011: // VORR.I32
case 0b10010: // VMVN.I32
case 0b10011: // VBIC.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X00", imm);
const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_prec) {
static __thread char ret[68];
// Assume VFPSmallRegisterBank(), so no D16 and no S32 (and above)
if (start + (double_prec + 1) * size > 32) {
return "!!!";
}
if (size == 0) {
return "!!!";
}
if (double_prec && (size % 2 == 1)) {
strcpy(ret, "!! {");
} else {
ret[0] = '{';
ret[1] = '\\0';
}
char regChr;
if (double_prec) {
regChr = 'D';
size /= 2;
} else {
regChr = 'S';
start = (start >> 4) + ((start & 0xF) << 1);
}
char tmp[6];
for (int cur = start; cur < start + size - 1; ++cur) {
sprintf(tmp, "%c%d, ", regChr, cur);
strcat(ret, tmp);
}
sprintf(tmp, "%c%d}", regChr, start + size - 1);
strcat(ret, tmp);
return ret;
}
break;
case 0b00100: // VMOV.I32
case 0b00101: // VORR.I32
case 0b10100: // VMVN.I32
case 0b10101: // VBIC.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X0000", imm);
static const char* _print_modified_imm_I64_bytes[2] = {"00", "FF"};
const char* print_modified_imm_NEON(int op_cmode, int imm) {
static __thread char ret[34] = "???\\0-"; // [dt: 4][imm: 30]
strcpy(&ret[4], "UNPREDICTABLE");
switch (op_cmode) {
case 0b00000: // VMOV.I32
case 0b00001: // VORR.I32
case 0b10000: // VMVN.I32
case 0b10001: // VBIC.I32
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X", imm);
break;
case 0b00010: // VMOV.I32
case 0b00011: // VORR.I32
case 0b10010: // VMVN.I32
case 0b10011: // VBIC.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X00", imm);
}
break;
case 0b00100: // VMOV.I32
case 0b00101: // VORR.I32
case 0b10100: // VMVN.I32
case 0b10101: // VBIC.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X0000", imm);
}
break;
case 0b00110: // VMOV.I32
case 0b00111: // VORR.I32
case 0b10110: // VMVN.I32
case 0b10111: // VBIC.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X000000", imm);
}
break;
case 0b01000: // VMOV.I16
case 0b01001: // VORR.I16
case 0b11000: // VMVN.I16
case 0b11001: // VBIC.I16
strcpy(ret, "I16");
sprintf(&ret[4], "0x%02X", imm);
break;
case 0b01010: // VMOV.I16
case 0b01011: // VORR.I16
case 0b11010: // VMVN.I16
case 0b11011: // VBIC.I16
if (imm) {
strcpy(ret, "I16");
sprintf(&ret[4], "0x%02X00", imm);
}
break;
case 0b01100: // VMOV.I32
case 0b11100: // VMVN.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02XFF", imm);
}
break;
case 0b01101: // VMOV.I32
case 0b11101: // VMVN.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02XFFFF", imm);
}
break;
case 0b01110: // VMOV.I8
strcpy(ret, "I8");
sprintf(&ret[4], "0x%02X", imm);
break;
case 0b01111: // VMOV.F32
strcpy(ret, "F32");
sprintf(&ret[4], "%e", (imm & 0x80 ? -1 : 1) * (1 << (((imm >> 4) & 0x7) ^ 0b100)) * (float) (16 + (imm & 0xF)) / 128.);
break;
case 0b11110: // VMOV.I64
{
strcpy(ret, "I64");
sprintf(&ret[4], "#0x%s%s%s%s%s%s%s%s",
_print_modified_imm_I64_bytes[(imm >> 7) & 1], _print_modified_imm_I64_bytes[(imm >> 6) & 1],
_print_modified_imm_I64_bytes[(imm >> 5) & 1], _print_modified_imm_I64_bytes[(imm >> 4) & 1],
_print_modified_imm_I64_bytes[(imm >> 3) & 1], _print_modified_imm_I64_bytes[(imm >> 2) & 1],
_print_modified_imm_I64_bytes[(imm >> 1) & 1], _print_modified_imm_I64_bytes[(imm >> 0) & 1]);
}
break;
case 0b11111: // V???.-
default:
strcpy(ret, "-");
strcpy(&ret[4], "UNDEFINED");
break;
}
return ret;
}
break;
case 0b00110: // VMOV.I32
case 0b00111: // VORR.I32
case 0b10110: // VMVN.I32
case 0b10111: // VBIC.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02X000000", imm);
}
break;
case 0b01000: // VMOV.I16
case 0b01001: // VORR.I16
case 0b11000: // VMVN.I16
case 0b11001: // VBIC.I16
strcpy(ret, "I16");
sprintf(&ret[4], "0x%02X", imm);
break;
case 0b01010: // VMOV.I16
case 0b01011: // VORR.I16
case 0b11010: // VMVN.I16
case 0b11011: // VBIC.I16
if (imm) {
strcpy(ret, "I16");
sprintf(&ret[4], "0x%02X00", imm);
}
break;
case 0b01100: // VMOV.I32
case 0b11100: // VMVN.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02XFF", imm);
}
break;
case 0b01101: // VMOV.I32
case 0b11101: // VMVN.I32
if (imm) {
strcpy(ret, "I32");
sprintf(&ret[4], "0x%02XFFFF", imm);
}
break;
case 0b01110: // VMOV.I8
strcpy(ret, "I8");
sprintf(&ret[4], "0x%02X", imm);
break;
case 0b01111: // VMOV.F32
strcpy(ret, "F32");
sprintf(&ret[4], "%e", (imm & 0x80 ? -1 : 1) * (1 << (((imm >> 4) & 0x7) ^ 0b100)) * (float) (16 + (imm & 0xF)) / 128.);
break;
case 0b11110: // VMOV.I64
const char* arm_print(uint32_t opcode) {
static __thread char ret[100];
memset(ret, 0, sizeof(ret));
"""
}
files_guard = {
"arm_printer.c": """
{
strcpy(ret, "I64");
sprintf(&ret[4], "#0x%s%s%s%s%s%s%s%s",
_print_modified_imm_I64_bytes[(imm >> 7) & 1], _print_modified_imm_I64_bytes[(imm >> 6) & 1],
_print_modified_imm_I64_bytes[(imm >> 5) & 1], _print_modified_imm_I64_bytes[(imm >> 4) & 1],
_print_modified_imm_I64_bytes[(imm >> 3) & 1], _print_modified_imm_I64_bytes[(imm >> 2) & 1],
_print_modified_imm_I64_bytes[(imm >> 1) & 1], _print_modified_imm_I64_bytes[(imm >> 0) & 1]);
strcpy(ret, "???");
}
return ret;
}
break;
case 0b11111: // V???.-
default:
strcpy(ret, "-");
strcpy(&ret[4], "UNDEFINED");
break;
"""
}
return ret;
}
const char* arm_print(uint32_t opcode) {
static __thread char ret[100];
memset(ret, 0, sizeof(ret));
"""
}
files_guard = {"arm_printer.c": """{
strcpy(ret, "???");
}
return ret;
}
"""}
banner = "/*******************************************************" + ('*'*len(ver)) + "***\n" \
" * File automatically generated by rebuild_printer.py (v" + ver + ") *\n" \
" *******************************************************" + ('*'*len(ver)) + "***/\n"
trim = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
# Yes, the for loops are inverted. This is because both dicts should have the same keys.
for fhdr in files_guard:
files_header[fhdr] = banner + trim(files_header[fhdr])
for fhdr in files_header:
files_guard[fhdr] = trim(files_guard[fhdr])
for f in files_header:
# Save the string for the next iteration, writing was successful
with open(os.path.join(root, "src", "dynarec", f), 'w') as file:
file.write(header.format(version = ver))
file.write(files_header[f])
file.write(output)
file.write(files_guard[f])
# Save the string for the next iteration, writing was successful
with open(os.path.join(root, "src", "dynarec", "last_run.txt"), 'w') as file:
file.write('\n'.join(insts))
@@ -1979,6 +1988,6 @@ if __name__ == '__main__':
for i, v in enumerate(sys.argv):
if v == "--":
limit.append(i)
if main(sys.argv[1], "1.1.0.04") != 0:
if main(sys.argv[1], "1.2.0.05") != 0:
exit(2)
exit(0)
+1323 -368
View File
File diff suppressed because it is too large. Load diff
+8 -1
View File
@@ -13,6 +13,7 @@ if( NOT TEST_REFERENCE )
endif( NOT TEST_REFERENCE )
set(ENV{BOX86_LOG} 0)
set(ENV{BOX86_NOBANNER} 1)
if( EXISTS ${CMAKE_SOURCE_DIR}/x86lib )
# we are inside box86 folder
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x86lib)
@@ -31,17 +32,23 @@ execute_process(
# if the return value is !=0 bail out
if( TEST_RESULT )
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
endif( TEST_RESULT )
# now compare the output with the reference
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_OUTPUT} ${TEST_REFERENCE}
COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUTPUT}" "${TEST_REFERENCE}"
RESULT_VARIABLE TEST_RESULT
)
# again, if return value is !=0 scream and shout
if( TEST_RESULT )
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
endif( TEST_RESULT )
+146 -283
View File
@@ -19,201 +19,16 @@
#include "threads.h"
#include "x86trace.h"
#include "signals.h"
#ifdef DYNAREC
#include <sys/mman.h>
#include "custommem.h"
#include "dictionnary.h"
#ifdef DYNAREC
#include "dynablock.h"
#define MMAPSIZE (4*1024*1024) // allocate 4Mo sized blocks
#define MMAPBLOCK 256 // minimum size of a block
typedef struct mmaplist_s {
void* block;
uint8_t map[MMAPSIZE/(8*MMAPBLOCK)]; // map of allocated sub-block
} mmaplist_t;
// get first subblock free in map, stating at start. return -1 if no block, else first subblock free, filling size (in subblock unit)
static int getFirstBlock(mmaplist_t *map, int start, int maxsize, int* size)
{
#define ISFREE(A) (((map->map[(A)>>3]>>((A)&7))&1)?0:1)
if(start<0) start = 0;
while(start<MMAPSIZE/(8*MMAPBLOCK)) { // still a chance...
if(ISFREE(start)) {
// free, now get size...
int end = start+1;
while(end<MMAPSIZE/(8*MMAPBLOCK)) {
if(!ISFREE(end) || (end-start==maxsize)) {
if(size) *size = end-start;
return start;
}
++end;
}
if(size) *size = end-start;
return start;
}
++start;
}
return -1;
}
static void allocBlock(mmaplist_t *map, int start, int size)
{
for(int i=0; i<size; ++i) {
map->map[start/8]|=(1<<(start&7));
++start;
}
}
static void freeBlock(mmaplist_t *map, int start, int size)
{
for(int i=0; i<size; ++i) {
map->map[start/8]&=~(1<<(start&7));
++start;
}
}
uintptr_t AllocDynarecMap(int size, int nolinker)
{
if(size>MMAPSIZE) {
void* p = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(p==MAP_FAILED) {
dynarec_log(LOG_DEBUG, "Cannot create dynamic map of %d bytes\n", size);
return 0;
}
return (uintptr_t)p;
}
pthread_mutex_lock(&my_context->mutex_mmap);
int bsize = (size+MMAPBLOCK-1)/MMAPBLOCK;
// look for free space
for(int i=0; i<my_context->mmapsize; ++i) {
int rsize = 0;
int start = 0;
do {
start = getFirstBlock(my_context->mmaplist+i, start, bsize, &rsize);
if(start!=-1 && rsize>=bsize) {
allocBlock(my_context->mmaplist+i, start, bsize);
uintptr_t ret = (uintptr_t)my_context->mmaplist[i].block + start*MMAPBLOCK;
pthread_mutex_unlock(&my_context->mutex_mmap);
return ret;
}
if(start!=-1)
start += rsize;
} while (start!=-1);
}
// no luck, add a new one !
int i = my_context->mmapsize++; // yeah, useful post incrementation
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", my_context->mmapsize);
my_context->mmaplist = (mmaplist_t*)realloc(my_context->mmaplist, my_context->mmapsize*sizeof(mmaplist_t));
void* p = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(p==MAP_FAILED) {
dynarec_log(LOG_DEBUG, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
--my_context->mmapsize;
pthread_mutex_unlock(&my_context->mutex_mmap);
return 0;
}
my_context->mmaplist[i].block = p;
memset(my_context->mmaplist[i].map, 0, sizeof(my_context->mmaplist[i].map));
allocBlock(my_context->mmaplist+i, 0, bsize);
pthread_mutex_unlock(&my_context->mutex_mmap);
return (uintptr_t)p;
}
void FreeDynarecMap(uintptr_t addr, uint32_t size)
{
if(size>MMAPSIZE) {
munmap((void*)addr, size);
return;
}
pthread_mutex_lock(&my_context->mutex_mmap);
int bsize = (size+MMAPBLOCK-1)/MMAPBLOCK;
// look for free space
for(int i=0; i<my_context->mmapsize; ++i) {
if(addr>=(uintptr_t)my_context->mmaplist[i].block && ((uintptr_t)my_context->mmaplist[i].block+MMAPSIZE)>=addr+size) {
int start = (addr - (uintptr_t)my_context->mmaplist[i].block) / MMAPBLOCK;
freeBlock(my_context->mmaplist+i, start, bsize);
pthread_mutex_unlock(&my_context->mutex_mmap);
return;
}
}
pthread_mutex_unlock(&my_context->mutex_mmap);
}
// each dynmap is 64k of size
dynablocklist_t* getDBFromAddress(uintptr_t addr)
{
int idx = (addr>>16);
if(!my_context->dynmap[idx]) {
return NULL;
}
return my_context->dynmap[idx]->dynablocks;
}
void addDBFromAddressRange(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>16);
uintptr_t end = ((addr+size-1)>>16);
for (uintptr_t i=idx; i<=end; ++i) {
if(!my_context->dynmap[i]) {
my_context->dynmap[i] = (dynmap_t*)calloc(1, sizeof(dynmap_t));
my_context->dynmap[i]->dynablocks = NewDynablockList(i<<16, i<<16, 1<<16, 1, 0);
}
}
protectDB(addr, size);
}
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
{
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
uintptr_t idx = (addr>box86_dynarec_largest && !destroy)?((addr-box86_dynarec_largest)>>16):(addr>>16);
uintptr_t end = ((addr+size-1)>>16);
for (uintptr_t i=idx; i<=end; ++i) {
dynmap_t* dynmap = my_context->dynmap[i];
if(dynmap) {
uintptr_t startdb = StartDynablockList(dynmap->dynablocks);
uintptr_t enddb = EndDynablockList(dynmap->dynablocks);
uintptr_t startaddr = addr;
if(startaddr<startdb) startaddr = startdb;
uintptr_t endaddr = addr + size - 1;
if(endaddr>enddb) endaddr = enddb;
if(startaddr==startdb && endaddr==enddb) {
if(destroy) {
my_context->dynmap[i] = NULL;
FreeDynablockList(&dynmap->dynablocks);
free(dynmap);
} else
MarkDynablockList(&dynmap->dynablocks);
} else
if(destroy)
FreeRangeDynablock(dynmap->dynablocks, startaddr, endaddr-startaddr+1);
else
MarkRangeDynablock(dynmap->dynablocks, startaddr, endaddr-startaddr+1);
}
}
}
// Remove the Write flag from an adress range, so DB can be executed
// no log, as it can be executed inside a signal handler
void protectDB(uintptr_t addr, uintptr_t size)
{
uintptr_t start = (addr)&~(box86_pagesize-1);
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
// should get "end" according to last block inside the window
mprotect((void*)start, end-start, PROT_READ|PROT_EXEC);
}
// Add the Write flag from an adress range, and mark all block as dirty
// no log, as it can be executed inside a signal handler
void unprotectDB(uintptr_t addr, uintptr_t size)
{
uintptr_t start = (addr)&~(box86_pagesize-1);
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
// should get "end" according to last block inside the window
mprotect((void*)start, end-start, PROT_READ|PROT_WRITE|PROT_EXEC);
cleanDBFromAddressRange(start, end-start, 0);
}
#include "dynarec/arm_lock_helper.h"
#endif
EXPORTDYN
void initAllHelpers(box86context_t* context)
{
@@ -222,18 +37,21 @@ void initAllHelpers(box86context_t* context)
return;
my_context = context;
init_pthread_helper();
init_signal_helper();
init_bridge_helper();
init_signal_helper(context);
inited = 1;
}
EXPORTDYN
void finiAllHelpers()
void finiAllHelpers(box86context_t* context)
{
static int finied = 0;
if(finied)
return;
fini_pthread_helper();
fini_pthread_helper(context);
fini_signal_helper();
fini_bridge_helper();
fini_custommem_helper(context);
finied = 1;
}
@@ -244,11 +62,11 @@ int getrand(int maxval)
{
if(maxval<1024) {
return ((random()&0x7fff)*maxval)/0x7fff;
} else {
}
uint64_t r = random();
r = (r*maxval) / RAND_MAX;
return r;
}
}
void free_tlsdatasize(void* p)
@@ -260,6 +78,79 @@ void free_tlsdatasize(void* p)
free(p);
}
int unlockMutex()
{
int ret = unlockCustommemMutex();
int i;
#define GO(A, B) \
i = checkUnlockMutex(&A); \
if(i) { \
ret|=(1<<B); \
}
GO(my_context->mutex_once, 5)
GO(my_context->mutex_once2, 6)
GO(my_context->mutex_trace, 7)
#ifdef DYNAREC
GO(my_context->mutex_dyndump, 8)
#else
GO(my_context->mutex_lock, 8)
#endif
GO(my_context->mutex_tls, 9)
GO(my_context->mutex_thread, 10)
GO(my_context->mutex_bridge, 11)
#undef GO
return ret;
}
void relockMutex(int locks)
{
#define GO(A, B) \
if(locks&(1<<B)) \
pthread_mutex_lock(&A); \
GO(my_context->mutex_once, 5)
GO(my_context->mutex_once2, 6)
GO(my_context->mutex_trace, 7)
#ifdef DYNAREC
GO(my_context->mutex_dyndump, 8)
#else
GO(my_context->mutex_lock, 8)
#endif
GO(my_context->mutex_tls, 9)
GO(my_context->mutex_thread, 10)
GO(my_context->mutex_bridge, 11)
#undef GO
relockCustommemMutex(locks);
}
static void init_mutexes(box86context_t* context)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&context->mutex_once, &attr);
pthread_mutex_init(&context->mutex_once2, &attr);
pthread_mutex_init(&context->mutex_trace, &attr);
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_dyndump, &attr);
#else
pthread_mutex_init(&context->mutex_lock, &attr);
#endif
pthread_mutex_init(&context->mutex_tls, &attr);
pthread_mutex_init(&context->mutex_thread, &attr);
pthread_mutex_init(&context->mutex_bridge, &attr);
pthread_mutexattr_destroy(&attr);
}
static void atfork_child_box64context(void)
{
// (re)init mutex if it was lock before the fork
init_mutexes(my_context);
}
EXPORTDYN
box86context_t *NewBox86Context(int argc)
{
@@ -270,18 +161,24 @@ box86context_t *NewBox86Context(int argc)
}
#endif
// init and put default values
box86context_t *context = (box86context_t*)calloc(1, sizeof(box86context_t));
box86context_t *context = my_context = (box86context_t*)calloc(1, sizeof(box86context_t));
#ifdef BUILD_LIB
context->deferedInit = 0;
#else
context->deferedInit = 1;
#endif
context->sel_serial = 1;
init_custommem_helper(context);
context->maplib = NewLibrarian(context, 1);
context->local_maplib = NewLibrarian(context, 1);
context->versym = NewDictionnary();
context->system = NewBridge();
// create vsyscall
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
context->vsyscall = AddBridge(context->system, iFEv, x86Syscall, 0, NULL);
addAlternate((void*)0xffffe400, (void*)context->vsyscall);
#ifdef BUILD_LIB
context->box86lib = RTLD_DEFAULT; // not ideal
#else
@@ -289,28 +186,18 @@ box86context_t *NewBox86Context(int argc)
#endif
context->dlprivate = NewDLPrivate();
context->callbacks = NewCallbackList();
context->argc = argc;
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
pthread_mutex_init(&context->mutex_once, NULL);
pthread_mutex_init(&context->mutex_once2, NULL);
pthread_mutex_init(&context->mutex_trace, NULL);
pthread_mutex_init(&context->mutex_lock, NULL);
pthread_mutex_init(&context->mutex_thread, NULL);
init_mutexes(context);
pthread_atfork(NULL, NULL, atfork_child_box64context);
pthread_key_create(&context->tlskey, free_tlsdatasize);
#ifdef DYNAREC
pthread_mutex_init(&context->mutex_blocks, NULL);
pthread_mutex_init(&context->mutex_mmap, NULL);
context->dynablocks = NewDynablockList(0, 0, 0, 0, 0);
#endif
InitFTSMap(context);
for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255);
context->canary[getrand(4)] = 0;
context->canary[/*getrand(4)*/0] = 0;
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
initAllHelpers(context);
@@ -333,6 +220,12 @@ void FreeBox86Context(box86context_t** context)
box86context_t* ctx = *context; // local copy to do the cleanning
if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib, NULL);
if(ctx->maplib)
FreeLibrarian(&ctx->maplib, NULL);
FreeDictionnary(&ctx->versym);
for(int i=0; i<ctx->elfsize; ++i) {
FreeElfHeader(&ctx->elfs[i]);
}
@@ -340,29 +233,6 @@ void FreeBox86Context(box86context_t** context)
FreeFTSMap(ctx);
if(ctx->maplib)
FreeLibrarian(&ctx->maplib);
if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib);
#ifdef DYNAREC
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
if(ctx->dynablocks)
FreeDynablockList(&ctx->dynablocks);
for (int i=0; i<ctx->mmapsize; ++i)
if(ctx->mmaplist[i].block)
munmap(ctx->mmaplist[i].block, MMAPSIZE);
free(ctx->mmaplist);
pthread_mutex_destroy(&ctx->mutex_blocks);
pthread_mutex_destroy(&ctx->mutex_mmap);
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
cleanDBFromAddressRange(0, 0xffffffff, 1);
#endif
*context = NULL; // bye bye my_context
CleanStackSize(ctx);
FreeCollection(&ctx->box86_path);
FreeCollection(&ctx->box86_ld_lib);
FreeCollection(&ctx->box86_emulated_libs);
@@ -375,6 +245,27 @@ void FreeBox86Context(box86context_t** context)
if(ctx->deferedInitList)
free(ctx->deferedInitList);
free(ctx->argv);
for (int i=0; i<ctx->envc; ++i)
free(ctx->envv[i]);
free(ctx->envv);
if(ctx->atfork_sz) {
free(ctx->atforks);
ctx->atforks = NULL;
ctx->atfork_sz = ctx->atfork_cap = 0;
}
for(int i=0; i<MAX_SIGNAL; ++i)
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
signal(i, SIG_DFL);
}
*context = NULL; // bye bye my_context
CleanStackSize(ctx);
#ifndef BUILD_LIB
if(ctx->box86lib)
dlclose(ctx->box86lib);
@@ -382,13 +273,7 @@ void FreeBox86Context(box86context_t** context)
FreeDLPrivate(&ctx->dlprivate);
free(ctx->argv);
for (int i=0; i<ctx->envc; ++i)
free(ctx->envv[i]);
free(ctx->envv);
free(ctx->stack);
// free(ctx->stack); // don't free the stack, it's owned by main emu!
free(ctx->fullpath);
free(ctx->box86path);
@@ -398,8 +283,6 @@ void FreeBox86Context(box86context_t** context)
freeGLProcWrapper(ctx);
freeALProcWrapper(ctx);
FreeCallbackList(&ctx->callbacks);
void* ptr;
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
free_tlsdatasize(ptr);
@@ -417,29 +300,24 @@ void FreeBox86Context(box86context_t** context)
}
}
pthread_mutex_destroy(&ctx->mutex_once);
pthread_mutex_destroy(&ctx->mutex_once2);
pthread_mutex_destroy(&ctx->mutex_trace);
pthread_mutex_destroy(&ctx->mutex_lock);
pthread_mutex_destroy(&ctx->mutex_thread);
free_neededlib(&ctx->neededlibs);
if(ctx->atfork_sz) {
free(ctx->atforks);
ctx->atforks = NULL;
ctx->atfork_sz = ctx->atfork_cap = 0;
}
for(int i=0; i<MAX_SIGNAL; ++i)
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
signal(i, SIG_DFL);
}
if(ctx->emu_sig)
FreeX86Emu(&ctx->emu_sig);
finiAllHelpers();
finiAllHelpers(ctx);
pthread_mutex_destroy(&ctx->mutex_once);
pthread_mutex_destroy(&ctx->mutex_once2);
pthread_mutex_destroy(&ctx->mutex_trace);
#ifdef DYNAREC
pthread_mutex_destroy(&ctx->mutex_dyndump);
#else
pthread_mutex_destroy(&ctx->mutex_lock);
#endif
pthread_mutex_destroy(&ctx->mutex_tls);
pthread_mutex_destroy(&ctx->mutex_thread);
pthread_mutex_destroy(&ctx->mutex_bridge);
free(ctx);
}
@@ -463,27 +341,12 @@ int AddTLSPartition(box86context_t* context, int tlssize) {
context->tlsdata = realloc(context->tlsdata, context->tlssize);
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
// clean GS segment for current emu
if(my_context) {
ResetSegmentsCache(thread_get_emu());
if(!(++context->sel_serial))
++context->sel_serial;
}
return -context->tlssize; // negative offset
}
void add_neededlib(needed_libs_t* needed, library_t* lib)
{
if(!needed)
return;
if(needed->size == needed->cap) {
needed->cap += 8;
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
}
needed->libs[needed->size++] = lib;
}
void free_neededlib(needed_libs_t* needed)
{
if(!needed)
return;
needed->cap = 0;
needed->size = 0;
if(needed->libs)
free(needed->libs);
needed->libs = NULL;
}
+2 -2
View File
@@ -2,7 +2,7 @@
#define __BOX86_VERSION_H_
#define BOX86_MAJOR 0
#define BOX86_MINOR 1
#define BOX86_REVISION 2
#define BOX86_MINOR 2
#define BOX86_REVISION 4
#endif //__BOX86_VERSION_H_
+5 -6
View File
@@ -1,11 +1,15 @@
#include <stdio.h>
#include "debug.h"
#include "box86version.h"
#ifdef NOGIT
#define GITREV "nogit"
#else
#include "git_head.h"
#endif
void PrintBox86Version()
{
printf("Box86%s%s%s v%d.%d.%d %s built on %s %s\n",
printf("Box86%s%s v%d.%d.%d %s built on %s %s\n",
#ifdef HAVE_TRACE
" with trace",
#else
@@ -15,11 +19,6 @@ void PrintBox86Version()
" with Dynarec",
#else
"",
#endif
#ifdef USE_FLOAT
" (float only)",
#else
"",
#endif
BOX86_MAJOR, BOX86_MINOR, BOX86_REVISION,
GITREV,
+824
View File
@@ -0,0 +1,824 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <signal.h>
#include "box86context.h"
#include "elfloader.h"
#include "debug.h"
#include "x86trace.h"
#include "x86emu.h"
#include "librarian.h"
#include "bridge.h"
#include "library.h"
#include "callback.h"
#include "wrapper.h"
#include "myfts.h"
#include "threads.h"
#include "x86trace.h"
#include "signals.h"
#include <sys/mman.h>
#include "custommem.h"
#include "threads.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "dynarec/arm_lock_helper.h"
#include "khash.h"
#define USE_MMAP
// init inside dynablocks.c
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
static dynablocklist_t* dynmap[DYNAMAP_SIZE]; // 4G of memory mapped by 4K block
static mmaplist_t *mmaplist = NULL;
static int mmapsize = 0;
static int mmapcap = 0;
static kh_dynablocks_t *dblist_oversized; // store the list of oversized dynablocks (normal sized are inside mmaplist)
static uintptr_t *box86_jumptable[JMPTABL_SIZE];
static uintptr_t box86_jmptbl_default[1<<JMPTABL_SHIFT];
#endif
#define MEMPROT_SHIFT 12
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
static int inited = 0;
typedef struct blocklist_s {
void* block;
int maxfree;
size_t size;
} blocklist_t;
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
static pthread_mutex_t mutex_blocks;
static int n_blocks = 0; // number of blocks for custom malloc
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
typedef union mark_s {
struct {
unsigned int size:31;
unsigned int fill:1;
};
uint32_t x32;
} mark_t;
typedef struct blockmark_s {
mark_t prev;
mark_t next;
} blockmark_t;
#define NEXT_BLOCK(b) (blockmark_t*)((uintptr_t)(b) + (b)->next.size + sizeof(blockmark_t))
#define PREV_BLOCK(b) (blockmark_t*)(((uintptr_t)(b) - (b)->prev.size) - sizeof(blockmark_t))
#define LAST_BLOCK(b, s) (blockmark_t*)(((uintptr_t)(b)+(s))-sizeof(blockmark_t))
static void printBlock(blockmark_t* b, void* start)
{
printf_log(LOG_INFO, "========== Block is:\n");
do {
printf_log(LOG_INFO, "%c%p, fill=%d, size=0x%x (prev=%d/0x%x)\n", b==start?'*':' ', b, b->next.fill, b->next.size, b->prev.fill, b->prev.size);
b = NEXT_BLOCK(b);
} while(b->next.x32);
printf_log(LOG_INFO, "===================\n");
}
// get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size
static void* getFirstBlock(void* block, size_t maxsize, size_t* size, void* start)
{
// get start of block
blockmark_t *m = (blockmark_t*)((start)?start:block);
while(m->next.x32) { // while there is a subblock
if(!m->next.fill && m->next.size>=maxsize) {
*size = m->next.size;
return m;
}
m = NEXT_BLOCK(m);
}
return NULL;
}
static size_t getMaxFreeBlock(void* block, size_t block_size, void* start)
{
// get start of block
if(start) {
blockmark_t *m = (blockmark_t*)start;
int maxsize = 0;
while(m->next.x32) { // while there is a subblock
if(!m->next.fill && m->next.size>maxsize) {
maxsize = m->next.size;
}
m = NEXT_BLOCK(m);
}
return (maxsize>=sizeof(blockmark_t))?maxsize:0;
} else {
blockmark_t *m = LAST_BLOCK(block, block_size); // start with the end
int maxsize = 0;
while(m->prev.x32) { // while there is a subblock
if(!m->prev.fill && m->prev.size>maxsize) {
maxsize = m->prev.size;
if((uintptr_t)block+maxsize>(uintptr_t)m)
return (maxsize>=sizeof(blockmark_t))?maxsize:0; // no block large enough left...
}
m = PREV_BLOCK(m);
}
return (maxsize>=sizeof(blockmark_t))?maxsize:0;
}
}
static void* allocBlock(void* block, void *sub, size_t size, void** pstart)
{
(void)block;
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = NEXT_BLOCK(s);
s->next.fill = 1;
// check if a new mark is worth it
if(s->next.size>size+2*sizeof(blockmark_t))
s->next.size = size;
blockmark_t *m = NEXT_BLOCK(s); // this is new n
m->prev.fill = 1;
if(n!=m) {
// new mark
m->prev.size = s->next.size;
m->next.fill = 0;
m->next.size = ((uintptr_t)n - (uintptr_t)m) - sizeof(blockmark_t);
n->prev.fill = 0;
n->prev.size = m->next.size;
}
if(pstart && sub==*pstart) {
// get the next free block
m = (blockmark_t*)*pstart;
while(m->next.fill)
m = NEXT_BLOCK(m);
*pstart = (void*)m;
}
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
}
static size_t freeBlock(void *block, void* sub, void** pstart)
{
blockmark_t *m = (blockmark_t*)block;
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = NEXT_BLOCK(s);
if(block!=sub)
m = PREV_BLOCK(s);
s->next.fill = 0;
n->prev.fill = 0;
// check if merge with previous
if (s->prev.x32 && !s->prev.fill) {
// remove s...
m->next.size += s->next.size + sizeof(blockmark_t);
n->prev.size = m->next.size;
s = m;
}
// check if merge with next
if(n->next.x32 && !n->next.fill) {
blockmark_t *n2 = NEXT_BLOCK(n);
//remove n
s->next.size += n->next.size + sizeof(blockmark_t);
n2->prev.size = s->next.size;
}
if(pstart && (uintptr_t)*pstart>(uintptr_t)sub) {
*pstart = (void*)s;
}
// return free size at current block (might be bigger)
return s->next.size;
}
// return 1 if block has been expanded to new size, 0 if not
static int expandBlock(void* block, void* sub, size_t newsize)
{
(void)block;
newsize = (newsize+3)&~3;
blockmark_t *s = (blockmark_t*)sub;
blockmark_t *n = NEXT_BLOCK(s);
if(s->next.size>=newsize)
// big enough, no shrinking...
return 1;
if(s->next.fill)
return 0; // next block is filled
// unsigned bitfield of this length gets "promoted" to *signed* int...
if((size_t)(s->next.size + n->next.size + sizeof(blockmark_t)) < newsize)
return 0; // free space too short
// ok, doing the alloc!
if((s->next.size+n->next.size+sizeof(blockmark_t))-newsize<2*sizeof(blockmark_t))
s->next.size += n->next.size+sizeof(blockmark_t);
else
s->next.size = newsize+sizeof(blockmark_t);
blockmark_t *m = NEXT_BLOCK(s); // this is new n
m->prev.fill = 1;
m->prev.size = s->next.size;
if(n!=m) {
// new mark
m->prev.fill = 1;
m->prev.size = s->next.size;
m->next.fill = 0;
m->next.size = (uintptr_t)n - (uintptr_t)m;
n->prev.fill = 0;
n->prev.size = m->next.size;
}
return 1;
}
// return size of block
static size_t sizeBlock(void* sub)
{
blockmark_t *s = (blockmark_t*)sub;
return s->next.size;
}
void* customMalloc(size_t size)
{
// look for free space
void* sub = NULL;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if(p_blocks[i].maxfree>=size) {
size_t rsize = 0;
sub = getFirstBlock(p_blocks[i].block, size, &rsize, NULL);
if(sub) {
void* ret = allocBlock(p_blocks[i].block, sub, size, NULL);
if(rsize==p_blocks[i].maxfree)
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
pthread_mutex_unlock(&mutex_blocks);
return ret;
}
}
}
// add a new block
int i = n_blocks++;
p_blocks = (blocklist_t*)realloc(p_blocks, n_blocks*sizeof(blocklist_t));
size_t allocsize = MMAPSIZE;
if(size+2*sizeof(blockmark_t)>allocsize)
allocsize = size+2*sizeof(blockmark_t);
#ifdef USE_MMAP
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
memset(p, 0, allocsize);
#else
void* p = calloc(1, allocsize);
#endif
p_blocks[i].block = p;
p_blocks[i].size = allocsize;
// setup marks
blockmark_t* m = (blockmark_t*)p;
m->prev.x32 = 0;
m->next.fill = 0;
m->next.size = allocsize-2*sizeof(blockmark_t);
blockmark_t* n = NEXT_BLOCK(m);
n->next.x32 = 0;
n->prev.fill = 0;
n->prev.size = m->next.size;
// alloc 1st block
void* ret = allocBlock(p_blocks[i].block, p, size, NULL);
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
pthread_mutex_unlock(&mutex_blocks);
return ret;
}
void* customCalloc(size_t n, size_t size)
{
size_t newsize = n*size;
void* ret = customMalloc(newsize);
memset(ret, 0, newsize);
return ret;
}
void* customRealloc(void* p, size_t size)
{
if(!p)
return customMalloc(size);
uintptr_t addr = (uintptr_t)p;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if ((addr>(uintptr_t)p_blocks[i].block)
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
if(expandBlock(p_blocks[i].block, sub, size)) {
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
pthread_mutex_unlock(&mutex_blocks);
return p;
}
pthread_mutex_unlock(&mutex_blocks);
void* newp = customMalloc(size);
memcpy(newp, p, sizeBlock(sub));
customFree(p);
return newp;
}
}
pthread_mutex_unlock(&mutex_blocks);
if(n_blocks)
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for realloc, malloc'ing again without free\n", (void*)addr);
return customMalloc(size);
}
void customFree(void* p)
{
if(!p)
return;
uintptr_t addr = (uintptr_t)p;
pthread_mutex_lock(&mutex_blocks);
for(int i=0; i<n_blocks; ++i) {
if ((addr>(uintptr_t)p_blocks[i].block)
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
size_t newfree = freeBlock(p_blocks[i].block, sub, NULL);
if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree;
pthread_mutex_unlock(&mutex_blocks);
return;
}
}
pthread_mutex_unlock(&mutex_blocks);
if(n_blocks)
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for Free\n", (void*)addr);
}
#ifdef DYNAREC
typedef struct mmaplist_s {
void* block;
int maxfree;
size_t size;
kh_dynablocks_t* dblist;
uint8_t* helper;
void* first; // first free block, to speed up things
int locked; // don't try to add stuff on locked block
} mmaplist_t;
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
{
// look for free space
void* sub = NULL;
for(int i=0; i<mmapsize; ++i) {
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t) && !mmaplist[i].locked) {
mmaplist[i].locked = 1;
int rsize = 0;
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
if(sub) {
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
if(rsize==mmaplist[i].maxfree) {
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
}
kh_dynablocks_t *blocks = mmaplist[i].dblist;
if(!blocks) {
blocks = mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int r;
k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r);
kh_value(blocks, k) = db;
int size255=(size<256)?size:255;
for(size_t j=0; j<size255; ++j)
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = j;
if(size!=size255)
memset(&mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+256], -1, size-255);
mmaplist[i].locked = 0;
return ret;
} else {
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info?\n", i);
if(box86_log >= LOG_DEBUG)
printBlock(mmaplist[i].block, mmaplist[i].first);
}
}
}
return 0;
}
uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
{
int i = mmapsize++; // yeah, useful post incrementation
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%zu/%zu\n", mmapsize, mmapcap);
if(mmapsize>mmapcap) {
mmapcap += 32;
mmaplist = (mmaplist_t*)realloc(mmaplist, mmapcap*sizeof(mmaplist_t));
}
#ifndef USE_MMAP
void *p = NULL;
if(posix_memalign(&p, box86_pagesize, MMAPSIZE)) {
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
--mmapsize;
return 0;
}
mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
#else
void* p = mmap(NULL, MMAPSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(p==(void*)-1) {
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
--mmapsize;
return 0;
}
#endif
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
mmaplist[i].locked = 1;
mmaplist[i].block = p;
mmaplist[i].size = MMAPSIZE;
mmaplist[i].helper = (uint8_t*)calloc(1, MMAPSIZE);
mmaplist[i].first = p;
// setup marks
blockmark_t* m = (blockmark_t*)p;
m->prev.x32 = 0;
m->next.fill = 0;
m->next.size = MMAPSIZE-2*sizeof(blockmark_t);
blockmark_t* n = NEXT_BLOCK(m);
n->next.x32 = 0;
n->prev.fill = 0;
n->prev.size = m->next.size;
// alloc 1st block
uintptr_t sub = (uintptr_t)allocBlock(mmaplist[i].block, p, size, &mmaplist[i].first);
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
kh_dynablocks_t *blocks = mmaplist[i].dblist = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)sub, &ret);
kh_value(blocks, k) = db;
for(int j=0; j<size; ++j)
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block + j] = (j<256)?j:255;
mmaplist[i].locked = 0;
return sub;
}
void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
{
if(!addr || !size)
return;
for(int i=0; i<mmapsize; ++i) {
if ((addr>(uintptr_t)mmaplist[i].block)
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
void* sub = (void*)(addr-sizeof(blockmark_t));
size_t newfree = freeBlock(mmaplist[i].block, sub, &mmaplist[i].first);
if(mmaplist[i].maxfree < newfree) mmaplist[i].maxfree = newfree;
kh_dynablocks_t *blocks = mmaplist[i].dblist;
if(blocks) {
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)sub);
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
memset(&mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block], 0, size);
}
if(mmaplist[i].locked) {
printf_log(LOG_INFO, "BOX86: Warning, Free a chunk in a locked mmaplist[%d]\n", i);
++mmaplist[i].locked;
}
return;
}
}
if(mmapsize)
dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size);
}
dynablock_t* FindDynablockFromNativeAddress(void* addr)
{
// look in actual list
for(int i=0; i<mmapsize; ++i) {
if ((uintptr_t)addr>=(uintptr_t)mmaplist[i].block
&& ((uintptr_t)addr<(uintptr_t)mmaplist[i].block+mmaplist[i].size)) {
if(!mmaplist[i].helper)
return FindDynablockDynablocklist(addr, mmaplist[i].dblist);
else {
uintptr_t p = (uintptr_t)addr - (uintptr_t)mmaplist[i].block;
while(mmaplist[i].helper[p]) p -= mmaplist[i].helper[p];
khint_t k = kh_get(dynablocks, mmaplist[i].dblist, (uintptr_t)mmaplist[i].block + p);
if(k!=kh_end(mmaplist[i].dblist))
return kh_value(mmaplist[i].dblist, k);
return NULL;
}
}
}
// look in oversized
return FindDynablockDynablocklist(addr, dblist_oversized);
}
uintptr_t AllocDynarecMap(dynablock_t* db, int size)
{
if(!size)
return 0;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
#ifndef USE_MMAP
void *p = NULL;
if(posix_memalign(&p, box86_pagesize, size)) {
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
return 0;
}
mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
#else
void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if(p==(void*)-1) {
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
return 0;
}
#endif
setProtection((uintptr_t)p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
kh_dynablocks_t *blocks = dblist_oversized;
if(!blocks) {
blocks = dblist_oversized = kh_init(dynablocks);
kh_resize(dynablocks, blocks, 64);
}
khint_t k;
int ret;
k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
kh_value(blocks, k) = db;
return (uintptr_t)p;
}
uintptr_t ret = FindFreeDynarecMap(db, size);
if(!ret)
ret = AddNewDynarecMap(db, size);
return ret;
}
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
{
if(!addr || !size)
return;
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
#ifndef USE_MMAP
free((void*)addr);
#else
munmap((void*)addr, size);
#endif
kh_dynablocks_t *blocks = dblist_oversized;
if(blocks) {
khint_t k = kh_get(dynablocks, blocks, addr);
if(k!=kh_end(blocks))
kh_del(dynablocks, blocks, k);
}
return;
}
ActuallyFreeDynarecMap(db, addr, size);
}
dynablocklist_t* getDB(uintptr_t idx)
{
return dynmap[idx];
}
// each dynmap is 64k of size
void addDBFromAddressRange(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
if(!dynmap[i]) {
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
FreeDynablockList(&p);
}
}
}
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
{
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
uintptr_t idx = (addr>>DYNAMAP_SHIFT);
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
dynablocklist_t* dblist = dynmap[i];
if(dblist) {
if(destroy)
FreeRangeDynablock(dblist, addr, size);
else
MarkRangeDynablock(dblist, addr, size);
}
}
}
#ifdef ARM
void arm_next(void);
#endif
void addJumpTableIfDefault(void* addr, void* jmp)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = (uintptr_t)arm_next;
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
}
void setJumpTableDefault(void* addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
return;
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
box86_jumptable[idx][off] = (uintptr_t)arm_next;
}
int isJumpTableDefault(void* addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
return 1;
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
return (box86_jumptable[idx][off]==(uintptr_t)arm_next)?1:0;
}
uintptr_t getJumpTable()
{
return (uintptr_t)box86_jumptable;
}
uintptr_t getJumpTableAddress(uintptr_t addr)
{
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
if(box86_jumptable[idx] == box86_jmptbl_default) {
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
tbl[i] = (uintptr_t)arm_next;
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
free(tbl);
}
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
return (uintptr_t)&box86_jumptable[idx][off];
}
// Remove the Write flag from an adress range, so DB can be executed
// no log, as it can be executed inside a signal handler
void protectDB(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i];
if(!(prot&PROT_DYNAREC)) {
if(!prot)
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
memprot[i] = prot|PROT_DYNAREC;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
}
}
}
// Add the Write flag from an adress range, and mark all block as dirty
// no log, as it can be executed inside a signal handler
void unprotectDB(uintptr_t addr, uintptr_t size)
{
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t idx = (addr>>MEMPROT_SHIFT);
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t prot = memprot[i];
if(prot&PROT_DYNAREC) {
memprot[i] = prot&~PROT_DYNAREC;
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
}
}
}
#endif
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
uint32_t dyn=(memprot[i]&PROT_DYNAREC);
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
memprot[i] = prot|dyn;
}
}
void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
memprot[i] = prot;
}
}
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
for (uintptr_t i=idx; i<=end; ++i) {
memprot[i] = prot;
}
}
uint32_t getProtection(uintptr_t addr)
{
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
uint32_t ret = memprot[idx];
return ret;
}
int unlockCustommemMutex()
{
int ret = 0;
int i = 0;
#define GO(A, B) \
i = checkUnlockMutex(&A); \
if(i) { \
ret|=(1<<B); \
}
GO(mutex_blocks, 0)
#undef GO
return ret;
}
void relockCustommemMutex(int locks)
{
#define GO(A, B) \
if(locks&(1<<B)) \
pthread_mutex_lock(&A); \
GO(mutex_blocks, 0)
#undef GO
}
static void init_mutexes(void)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&mutex_blocks, &attr);
pthread_mutexattr_destroy(&attr);
}
static void atfork_child_custommem(void)
{
// (re))init mutex if it was lock before the fork
init_mutexes();
}
void init_custommem_helper(box86context_t* ctx)
{
if(inited) // already initialized
return;
inited = 1;
init_mutexes();
#ifdef DYNAREC
#ifdef ARM
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
box86_jmptbl_default[i] = (uintptr_t)arm_next;
for(int i=0; i<JMPTABL_SIZE; ++i)
box86_jumptable[i] = box86_jmptbl_default;
#else
#error Unsupported architecture!
#endif
#endif
pthread_atfork(NULL, NULL, atfork_child_custommem);
}
void fini_custommem_helper(box86context_t *ctx)
{
if(!inited)
return;
inited = 0;
#ifdef DYNAREC
if(box86_dynarec) {
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
for (int i=0; i<mmapsize; ++i) {
if(mmaplist[i].block)
#ifdef USE_MMAP
munmap(mmaplist[i].block, mmaplist[i].size);
#else
free(mmaplist[i].block);
#endif
if(mmaplist[i].dblist) {
kh_destroy(dynablocks, mmaplist[i].dblist);
mmaplist[i].dblist = NULL;
}
if(mmaplist[i].helper) {
free(mmaplist[i].helper);
mmaplist[i].helper = NULL;
}
}
if(dblist_oversized) {
kh_destroy(dynablocks, dblist_oversized);
dblist_oversized = NULL;
}
mmapsize = 0;
mmapcap = 0;
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
uintptr_t idx = 0;
uintptr_t end = ((0xFFFFFFFF)>>DYNAMAP_SHIFT);
for (uintptr_t i=idx; i<=end; ++i)
if(dynmap[i])
FreeDynablockList(&dynmap[i]);
free(mmaplist);
for (int i=0; i<DYNAMAP_SIZE; ++i)
if(box86_jumptable[i]!=box86_jmptbl_default)
free(box86_jumptable[i]);
}
#endif
for(int i=0; i<n_blocks; ++i)
#ifdef USE_MMAP
munmap(p_blocks[i].block, p_blocks[i].size);
#else
free(p_blocks[i].block);
#endif
free(p_blocks);
pthread_mutex_destroy(&mutex_blocks);
}
+220 -33
View File
@@ -21,12 +21,13 @@ Op is 20-27
#define xEBP 9
#define xESI 10
#define xEDI 11
#define xEIP 12
#define xFlags 12
#define xEIP 14
// scratch registers
#define x1 1
#define x2 2
#define x3 3
#define x12 12
#define x14 14
// emu is r0
#define xEmu 0
// ARM SP is r13
@@ -77,13 +78,17 @@ Op is 20-27
// movt dst, #imm16
#define MOVT(dst, imm16) EMIT(0xe3400000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
// pseudo insruction: mov reg, #imm with imm a 32bits value
#define MOV32(dst, imm32) \
MOVW(dst, ((uint32_t)imm32)&0xffff); \
if (((uint32_t)(imm32))>>16) { \
MOVT(dst, (((uint32_t)imm32)>>16)); }
#define MOV32(dst, imm32) \
if((~(uint32_t)(imm32))<0x100) { \
MVN_IMM8(dst, ~(uint32_t)(imm32), 0); \
} else { \
MOVW(dst, ((uint32_t)imm32)&0xffff); \
if (((uint32_t)(imm32))>>16) { \
MOVT(dst, (((uint32_t)imm32)>>16));} \
}
// pseudo insruction: mov reg, #imm with imm a 32bits value, fixed size
#define MOV32_(dst, imm32) \
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
#define MOV32_(dst, imm32) \
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
MOVT(dst, (((uint32_t)(imm32))>>16))
// movw.cond dst, #imm16
#define MOVW_COND(cond, dst, imm16) EMIT(cond | 0x03000000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
@@ -96,10 +101,14 @@ Op is 20-27
#define MOV_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
// mov dst, src lsr imm5
#define MOV_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
// mov.cond dst, src lsr imm5
#define MOV_REG_LSR_IMM5_COND(cond, dst, src, imm5) EMIT(cond | 0x01a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
// mov dst, src asr imm5
#define MOV_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
// mov dst, src ror imm5
#define MOV_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
// mov dst, src rrx (1)
#define MOV_REG_RRX(dst, src) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((0)<<7))
// mov.s dst, src lsl imm5
#define MOVS_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
// mov.s dst, src lsr imm5
@@ -108,9 +117,17 @@ Op is 20-27
#define MOVS_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
// mov.s dst, src ror imm5
#define MOVS_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
// mov.s dst, src rrx (1)
#define MOVS_REG_RRX(dst, src) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((0)<<7))
// mov.s dst, src lsl rs
#define MOVS_REG_LSL_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
// mov.s dst, src lsr rs
#define MOVS_REG_LSR_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
// mov dst, src lsl rs
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
// mov.cond dst, src lsl rs
#define MOV_REG_LSL_REG_COND(cond, dst, src, rs) EMIT(cond | 0x01a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
// mov dst, src lsr rs
#define MOV_REG_LSR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
// mov dst, src asr rs
@@ -122,7 +139,7 @@ Op is 20-27
#define SUB_IMM8(dst, src, imm8) \
EMIT(0xe2400000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// sub cond dst, src, #(imm8)
#define SUB_COND_IMM8(dst, src, imm8) \
#define SUB_COND_IMM8(cond, dst, src, imm8) \
EMIT((cond) | 0x02400000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// sub.s dst, src, #(imm8)
#define SUBS_IMM8(dst, src, imm8) \
@@ -156,6 +173,9 @@ Op is 20-27
// rsb cond dst, src, #(imm8)
#define RSB_COND_IMM8(cond, dst, src, imm8) \
EMIT((cond) | 0x02600000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// rsc dst, src, #(imm8)
#define RSC_IMM8(dst, src, imm8) \
EMIT(0xe2E00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// and dst, src1, src2, lsl #imm
#define AND_REG_LSL_IMM5(dst, src1, src2, imm5) \
@@ -169,15 +189,21 @@ Op is 20-27
// and dst, src, #(imm8)
#define AND_IMM8(dst, src, imm8) \
EMIT(0xe2000000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// and dst, src1, #imm ror rot*2
#define AND_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe2000000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// and.s dst, src, #(imm8)
#define ANDS_IMM8(dst, src, imm8) \
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// and.s dst, src1, #imm ror rot*2
#define ANDS_IMM8_ROR(src, imm8, rot) \
#define ANDS_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// add dst, src, #(imm8)
#define ADD_IMM8(dst, src, imm8) \
EMIT(0xe2800000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// add dst, src, #imm8 ror rot*2
#define ADD_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe2800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM((imm8)) )
// add.s dst, src, #(imm8)
#define ADDS_IMM8(dst, src, imm8) \
EMIT(0xe2900000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
@@ -207,9 +233,18 @@ Op is 20-27
// cmp.s dst, src1, src2, lsl #imm
#define CMPS_REG_LSL_IMM5(src1, src2, imm5) \
EMIT(0xe1500000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// cmp.cond.s dst, src1, src2, lsl #imm
#define CMPS_REG_LSL_IMM5_COND(cond, src1, src2, imm5) \
EMIT((cond) | 0x01500000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// cmp.s dst, src, #imm
#define CMPS_IMM8_COND(cond, src, imm8) \
EMIT((cond) | 0x03500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// cmp.s dst, src, #imm
#define CMPS_IMM8(src, imm8) \
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// cmn.s dst, src, #imm
#define CMNS_IMM8_COND(cond, src, imm8) \
EMIT((cond) | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
// tst.s dst, src1, src2, lsl #imm
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
@@ -225,13 +260,25 @@ Op is 20-27
// orr.s dst, src1, src2, lsl #imm
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// orr dst, src1, src2, lsr #imm
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
// orr.s dst, src1, src2, lsr #imm
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
// orr.s dst, src1, src2, lsl rs
#define ORRS_REG_LSL_REG(dst, src1, src2, rs) \
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
// orr dst, src1, #imm8
#define ORR_IMM8(dst, src, imm8, rot) \
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr.s dst, src1, #imm8
#define ORRS_IMM8(dst, src, imm8, rot) \
EMIT(0xe3900000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr dst, src1, src2, lsl #rs
// orr.cond dst, src1, #imm8 ror rot*2
#define ORR_IMM8_COND(cond, dst, src, imm8, rot) \
EMIT((cond) | 0x03800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// orr dst, src1, src2, lsl rs
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
// xor dst, src1, src2, lsl #imm
@@ -247,6 +294,9 @@ Op is 20-27
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
#define XORS_IMM8(dst, src, imm8) \
EMIT(0xe2300000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
// xor dst, src, #(imm8 ror rot*2)
#define XOR_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// xor.cond dst, src, #(imm8)
#define XOR_IMM8_COND(cond, dst, src, imm8) \
EMIT(cond | 0x02200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
@@ -256,12 +306,21 @@ Op is 20-27
// xor dst, src1, src2, lsl #imm
#define XOR_REG_LSR_IMM8(dst, src1, src2, imm8) \
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
// xor.cond dst, src1, src2, lsl #imm
#define XOR_REG_LSR_IMM8_COND(cond, dst, src1, src2, imm8) \
EMIT(cond | 0x00200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
// bic dst, src1, src2, lsl #imm
#define BIC_REG_LSL_IMM5(dst, src1, src2, imm5) \
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
// bic dst, src, IMM8
// bic dst, src, IMM8 ror rot*2
#define BIC_IMM8(dst, src, imm8, rot) \
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// bic.cond dst, src, IMM8
#define BIC_IMM8_COND(cond, dst, src, imm8, rot) \
EMIT((cond) | 0x03c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
// bic dst, src1, #imm ror rot*2
#define BIC_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
// bic.s dst, src1, #imm ror rot*2
#define BICS_IMM8_ROR(dst, src, imm8, rot) \
EMIT(0xe3d00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
@@ -272,8 +331,8 @@ Op is 20-27
#define MVN_REG_LSL_IMM5(dst, rm, imm5) \
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
// mvn dst, src, IMM8
#define MVN_IMM8(dst, src, imm8, rot) \
EMIT(0xe3e00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
#define MVN_IMM8(dst, imm8, rot) \
EMIT(0xe3e00000 | ((dst) << 12) | (rot)<<8 | ((imm8)&0xff) )
// mvn dst, src1, src2, lsr #imm
#define MVN_REG_LSR_IMM8(dst, rm, imm8) \
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSR(imm8, rm) )
@@ -284,9 +343,6 @@ Op is 20-27
#define MVN_COND_REG_LSL_IMM5(cond, dst, rm, imm5) \
EMIT(cond | 0x01e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
// Single data transfert construction
#define SDT_REG(Cond, P, U, B, W, L, Rn, Rd, ShiftRm) (Cond | (0b00<<26) | (1<<25) | (P<<24) | (U<<23) | (B<<22) | (U<<23) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | ShiftRm)
#define SDT_OFF(Cond, P, U, B, W, L, Rn, Rd, Imm12) (Cond | (0b00<<26) | (0<<25) | (P<<24) | (U<<23) | (B<<22) | (U<<23) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | Imm12)
// ldr reg, [addr, #+/-imm9]
#define LDR_IMM9(reg, addr, imm9) EMIT(0xe5100000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// ldrxx reg, [addr, #+/-imm9]
@@ -316,6 +372,10 @@ Op is 20-27
// str reg, [addr, #+/-imm9]
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str with cond reg, [addr, #+/-imm9]
#define STR_IMM9_COND(cond, reg, addr, imm9) EMIT(cond | 0x05000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str reg, [addr, #+/-imm9]!
#define STR_IMM9_W(reg, addr, imm9) EMIT(0xe5200000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// strb reg, [addr, #+/-imm9]
#define STRB_IMM9(reg, addr, imm9) EMIT(0xe5400000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
// str reg, [addr], #+/-imm9
@@ -353,10 +413,16 @@ Op is 20-27
// all | const |pre-index| subs | no PSR |writeback| store | base |reg list
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
// push reg to xESP
#define PUSH1(reg) STR_IMM9_W(reg, xESP, -4)
// pop reg!, {list}
// all | const |postindex| add | no PSR |writeback| load | base |reg list
#define POP(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (1<<21) | (1<<20) | ((reg)<<16) | (list))
// pop reg from xESP
#define POP1(reg) LDRAI_IMM9_W(reg, xESP, 4)
// STMDB reg, {list}
// all | const |pre-index| subs | no PSR | no wb | store | base |reg list
#define STMDB(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
@@ -382,8 +448,14 @@ Op is 20-27
#define LDRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 1, addr, reg, 0, 1, rm))
#define STRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 0, addr, reg, 0, 1, rm))
#define LDRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 1, addr, reg, 0, 1, rm))
#define STRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 0, addr, reg, 0, 1, rm))
#define LDRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 1, addr, reg, 0, 1, rm))
#define STRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 0, addr, reg, 0, 1, rm))
#define LDRHB_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 1, 1, addr, reg, 0, 1, abs(imm8)))
#define LDRHA_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 0, (((imm8)<0)?0:1), 0, 1, addr, reg, 0, 1, abs(imm8)))
#define STRHB_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 1, 0, addr, reg, 0, 1, abs(imm8)))
#define STRHA_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 0, (((imm8)<0)?0:1), 0, 0, addr, reg, 0, 1, abs(imm8)))
#define PUSH16(reg, addr) EMIT(HWS_OFF(c__, 1, 0, 1, 0, addr, reg, 0, 1, 2))
#define POP16(reg, addr) EMIT(HWS_OFF(c__, 0, 1, 0, 1, addr, reg, 0, 1, 2))
// Mul Long construction
#define MULLONG(Cond, U, A, S, RdHi, RdLo, Rs, Rm) (Cond | 0b00001<<23 | (U)<<22 | (A)<<21 | (S)<<20 | (RdHi)<<16 | (RdLo)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
@@ -395,6 +467,10 @@ Op is 20-27
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | 0b000000<<22 | (A)<<21 | (S)<<20 | (Rd)<<16 | (Rn)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
#define MUL(Rd, Rm, Rn) EMIT(MULMULA(c__, 0, 0, (Rd), 0, (Rm), (Rn)))
#define MLS_gen(Cond, Rd, Ra, Rm, Rn) (Cond | 0b00000110<<20 | (Rd)<<16 | (Ra)<<12 | (Rm)<<8 | 0b1001<<4 | (Rn))
//MLS : Rd = Ra - Rm*Rn
#define MLS(Rd, Rm, Rn, Ra) EMIT(MLS_gen(c__, Rd, Ra, Rm, Rn))
#define SMUL_16_gen(cond, Rd, Rm, M, N, Rn) (cond | 0b00010110<<20 | (Rd)<<16 | (Rm)<<8 | 1<<7 | (M)<<6 | (N)<<5 | (Rn))
// Signed Mul between Rn[0..15] * Rm[0..15] => Rd
#define SMULBB(Rd, Rn, Rm) EMIT(SMUL_16_gen(c__, Rd, Rm, 0, 0, Rn))
@@ -410,18 +486,30 @@ Op is 20-27
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
#define UBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
// SBFX: Signed Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
#define SBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111101<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
// BFI: Bit Field Insert: copy any number of low order bit from Rn to any position of Rd
#define BFI(rd, rn, lsb, width) EMIT(c__ | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | (rn))
// BFI_COND: Bit Field Insert with condition: copy any number of low order bit from Rn to any position of Rd
#define BFI_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | (rn))
// BFC: Bit Field Clear: clear any number of adjacent bit from Rd
#define BFC(rd, lsb, width) EMIT(c__ | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
// BFC_COND: Bit Field Clear with condition: clear any number of adjacent bit from Rd
#define BFC_COND(cond, rd, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
// REV: Reverse byte of a 32bits word
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
// REV16: Reverse byte of a 16bits word
#define REV16(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b1011<<4) | (rm))
#define SSAT_gen(cond, sat_imm, Rd, imm5, sh, Rn) (cond | 0b0110101<<21 | (sat_imm)<<16 | (Rd)<<12 | (imm5)<<7 | (sh)<<6 | 0b01<<4 | (Rn))
// Signed Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
#define SSAT_REG_LSL_IMM5(Rd, saturate_to, Rn, shift) EMIT(SSAT_gen(c__, (saturate_to)-1, Rd, shift, 0, Rn))
// Signed Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
#define SSAT_REG_LSL_IMM5_COND(cond, Rd, saturate_to, Rn, shift) EMIT(SSAT_gen((cond), (saturate_to)-1, Rd, shift, 0, Rn))
#define USAT_gen(cond, sat_imm, Rd, imm5, sh, Rn) (cond | 0b0110111<<21 | (sat_imm)<<16 | (Rd)<<12 | (imm5)<<7 | (sh)<<6 | 0b01<<4 | (Rn))
// Unsigned Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
#define USAT_REG_LSL_IMM5(Rd, saturate_to, Rn, shift) EMIT(SSAT_gen(c__, (saturate_to), Rd, shift, 0, Rn))
@@ -438,11 +526,33 @@ Op is 20-27
#define LDREXD_gen(cond, Rn, Rt) (cond | 0b000<<25 | 0b11011<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
// Load Exclusive Rt/Rt+1 from Rn (tagging the memory)
#define LDREXD(Rn, Rt) EMIT(LDREXD_gen(c__, Rn, Rt))
#define LDREXD(Rt, Rn) EMIT(LDREXD_gen(c__, Rn, Rt))
#define LDREXD_COND(cond, Rt, Rn) EMIT(LDREXD_gen(cond, Rn, Rt))
#define STREXD_gen(cond, Rd, Rn, Rt) (cond | 0b000<<25 | 0b11010<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
// Store Exclusive Rt/Rt+1 to Rn, with result in Rd if tag is ok (Rd!=Rn && Rd!=Rt && Rd!=Rt+1), Rd==1 if store failed
#define STREXD(Rd, Rn, Rt) EMIT(STREXD_gen(c__, Rd, Rn, Rt))
#define STREXD(Rd, Rt, Rn) EMIT(STREXD_gen(c__, Rd, Rn, Rt))
#define STREXD_COND(cond, Rd, Rt, Rn) EMIT(STREXD_gen(cond, Rd, Rn, Rt))
#define LDREX_gen(cond, Rn, Rt) (cond | 0b0001100<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
// Load Exclusive Rt from Rn (tagging the memory)
#define LDREX(Rt, Rn) EMIT(LDREX_gen(c__, Rn, Rt))
#define LDREX_COND(cond, Rt, Rn) EMIT(LDREX_gen(cond, Rn, Rt))
#define STREX_gen(cond, Rd, Rn, Rt) (cond | 0b0001100<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
// Store Exclusive Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
#define STREX(Rd, Rt, Rn) EMIT(STREX_gen(c__, Rd, Rn, Rt))
#define STREX_COND(cond, Rd, Rt, Rn) EMIT(STREX_gen(cond, Rd, Rn, Rt))
#define LDREXB_gen(cond, Rn, Rt) (cond | 0b0001110<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
// Load Exclusive Byte Rt from Rn (tagging the memory)
#define LDREXB(Rt, Rn) EMIT(LDREXB_gen(c__, Rn, Rt))
#define LDREXB_COND(cond, Rt, Rn) EMIT(LDREXB_gen(cond, Rn, Rt))
#define STREXB_gen(cond, Rd, Rn, Rt) (cond | 0b0001110<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
// Store Exclusive byte Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
#define STREXB(Rd, Rt, Rn) EMIT(STREXB_gen(c__, Rd, Rn, Rt))
#define STREXB_COND(cond, Rd, Rt, Rn) EMIT(STREXB_gen(cond, Rd, Rn, Rt))
// Count leading 0 bit of Rm, store result in Rd
#define CLZ(Rd, Rm) EMIT(c__ | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
@@ -455,6 +565,10 @@ Op is 20-27
// Preload Cache Rn-Rm
#define PLDn(Rn, Rm) EMIT(PLD_gen(0, 1, Rn, 0, 0, Rm))
#define DMB_gen(opt) (0b1111<<28 | 0b01010111<<20 | 0b1111<<16 | 0b1111<<12 | 0b0000<<8 | 0b0101<<4 | (opt))
// Data memory barrier Inner Sharable
#define DMB_ISH() EMIT(DMB_gen(0b1011))
#define SWP_gen(cond, B, Rn, Rt, Rt2) (cond | 0b0001<<24 | (B)<<22 | (Rn)<<16 | (Rt)<<12 | 0b1001<<4 | (Rt2))
// SWAP (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2
#define SWP(Rt, Rt2, Rn) EMIT(SWP_gen(c__, 0, Rn, Rt, Rt2))
@@ -463,14 +577,17 @@ Op is 20-27
#define SDIV_gen(cond, Rd, Rm, Rn) (cond | 0b0111<<24 | 0b0001<<20 | (Rd)<<16 | 0b1111<<12 | (Rm)<<8 | 0b0001<<4 | (Rn))
// Signed Div Rd <- Rn/Rm
#define SDIV(Rd, Rm, Rn) EMIT(SDIV_gen(c__, Rd, Rm, Rn))
#define SDIV(Rd, Rn, Rm) EMIT(SDIV_gen(c__, Rd, Rm, Rn))
#define UDIV_gen(cond, Rd, Rm, Rn) (cond | 0b0111<<24 | 0b0011<<20 | (Rd)<<16 | 0b1111<<12 | (Rm)<<8 | 0b0001<<4 | (Rn))
// Unsigned Div Rd <- Rn/Rm
#define UDIV(Rd, Rm, Rn) EMIT(UDIV_gen(c__, Rd, Rm, Rn))
#define UDIV(Rd, Rn, Rm) EMIT(UDIV_gen(c__, Rd, Rm, Rn))
// VFPU
#define TRANSFERT64(C, op) ((0b1100<<24) | (0b010<<21) | (0b101<<9) | ((C)<<8) | ((op)<<4))
// Yield
#define YIELD(cond) EMIT(cond | 0b00110010<<20 | 0b1111<<12 | 1)
// UDF
#define UDF(imm16) EMIT(0b1110<<28 | 0b011<<25 | 0b11111<<20 | (((imm16)>>4)&0xfff) | 0b1111<<4 | ((imm16)&0xf))
// Move from FPSCR to Arm register
#define VMRS(Rt) EMIT(c__ | (0b1110<<24) | (0b1111<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
@@ -504,6 +621,8 @@ Op is 20-27
#define VMOVcond_32(cond, Sd, Sm) EMIT(cond | (0b11101<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15))
// Move between Sd and Imm
#define VMOV_i_32(Sd, Imm8) EMIT(c__ | (0b11101<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Imm8)>>4)&0xf)<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b00<<6) | ((Imm8)&15))
// Move between Dd and Imm
#define VMOV_i_64(Dd, Imm8) EMIT(c__ | (0b11101<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | ((((Imm8)>>4)&0xf)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b00<<6) | ((Imm8)&15))
#define VMOVtoDx_gen(Vd, D, Rt, opc1, opc2) (0b1110<<24 | 0<<23 | (opc1)<<21 | (Vd)<<16 | (Rt)<<12 | 0b1011<<8 | (D)<<7 | (opc2)<<5 | 1<<4)
// Move between Rt and Dm[x]
@@ -542,10 +661,14 @@ Op is 20-27
// Convert from double Dm to int32 Sd, with Round toward Zero mode
#define VCVT_S32_F64(Sd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (1<<8) | (1<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Convert from double Dm to uint32 Sd, with Round toward Zero mode
#define VCVT_U32_F64(Sd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b100<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (1<<8) | (1<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Convert from double Dm to int32 Sd, with Round selection from FPSCR
#define VCVTR_S32_F64(Sd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Convert from int32 Sm to double Dd
#define VCVT_F64_S32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b111<<19) | (0b000<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (1<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
// Convert from uint32 Sm to double Dd
#define VCVT_F64_U32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b111<<19) | (0b000<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
// Convert from single Sm to int32 Sd, with Round toward Zero mode
#define VCVT_S32_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (1<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
// Convert from single Sm to int32 Sd, with Round selection from FPSCR
@@ -553,9 +676,9 @@ Op is 20-27
// Convert from int32 Sm to single Dd
#define VCVT_F32_S32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b000<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (1<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
#define VCVT_16_gen(cond, D, op, U, Vd, sf, sx, i, imm4) (cond | 0b1110<<24 | 1<<23 | (D)<<22 | 0b11<<20 | 1<<19 | (op)<<18 | 1<<17 | (U)<<16 | (Vd)<<12 | 0b101<<9 | (sf)<<8 | (sx)<<7 | 1<<6 | (i)<<5 | (imm4))
#define VCVT_FP_gen(cond, D, op, U, Vd, sf, sx, i, imm4) (cond | 0b1110<<24 | 1<<23 | (D)<<22 | 0b11<<20 | 1<<19 | (op)<<18 | 1<<17 | (U)<<16 | (Vd)<<12 | 0b101<<9 | (sf)<<8 | (sx)<<7 | 1<<6 | (i)<<5 | (imm4))
// Inplace convert from F64 to S16. Rounding is not selectable
#define VCVT_S16_F64(Dd) EMIT(VCVT_16_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
#define VCVT_S16_F64(Dd) EMIT(VCVT_FP_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
// Mutiply F64 Dd = Dn*Dm
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
@@ -592,6 +715,10 @@ Op is 20-27
// Neg F64 Dd = - Dm
#define VNEG_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Neg F64 Dd = - Dm
#define VNEG_F64_cond(cond, Dd, Dm) EMIT((cond) | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// Neg F32 Dd = - Dm
#define VNEG_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
// Sqrt F64 Dd = - Dm
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
@@ -600,6 +727,13 @@ Op is 20-27
// Abs Dd = |Dm|
#define VABS_F64(Dd, Dm) EMIT(c__ | (0b11101<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15))
// Abs Dd = |Dm|
#define VABS_F32(Sd, Sm) EMIT(c__ | (0b11101<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15))
// MLS Dd = Dd - Dn*Dm
#define VMLS_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | 1<<6 | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// MLA Dd = Dd + Dn*Dm
#define VMLA_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | 0<<6 | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
// NEON
@@ -658,16 +792,26 @@ Op is 20-27
#define VEORQ(Dd, Dn, Dm) EMIT(VEOR_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VMOVL_gen(U, D, imm3, Vd, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 1<<23 | (D)<<22 | (imm3)<<19 | (Vd)<<12 | 0b1010<<8 | (M)<<5 | 1<<4 | (Vm))
#define VMOVL_S8(Dd, Dm) EMIT(VMOVL_gen(0, ((Dd)>>4)&1, 0b001, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VMOVL_U8(Dd, Dm) EMIT(VMOVL_gen(1, ((Dd)>>4)&1, 0b001, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VMOVL_S32(Dd, Dm) EMIT(VMOVL_gen(0, ((Dd)>>4)&1, 0b100, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VMOVL_U32(Dd, Dm) EMIT(VMOVL_gen(1, ((Dd)>>4)&1, 0b100, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VMOV_gen(D,Vd, M, Vm, Q) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | 0b10<<20 | (Vm)<<16 | (Vd)<<12 | 0b0001<<8 | (M)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
#define VMOVD(Dd, Dm) EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 0))
#define VMOVQ(Dd, Dm) EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 1))
#define VMOVD(Dd, Dm) if((Dd)!=(Dm)) {EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 0));}
#define VMOVQ(Dd, Dm) if((Dd)!=(Dm)) {EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 1));}
#define VMOV_igen(i, D, imm3, Vd, cmode, Q, op, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | (op)<<5 | 1<<4 | (imm4))
#define VMOV_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 0, (imm)&15))
#define VMOVQ_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 1, 0, (imm)&15))
// Dd <= imm8 in high bits
#define VMOV_H32(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b0110, 0, 0, (imm8)&15))
// Dd <= imm8 in high bits
#define VMOV_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 0, 0, (imm8)&15))
// Qd <= imm8 in high bits
#define VMOVQ_H32(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b0110, 1, 0, (imm8)&15))
// Qd <= imm8 in high bits
#define VMOVQ_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 1, 0, (imm8)&15))
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
@@ -732,6 +876,14 @@ Op is 20-27
#define VCEQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCEQQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCEQ_0_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b010<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VCEQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCEQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCEQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCEQQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCEQQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCEQQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCGT_I_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VCGT_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCGTQ_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
@@ -757,6 +909,15 @@ Op is 20-27
#define VCGE_F32(Dd, Dn, Dm) EMIT(VCGE_F_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCGEQ_F32(Dd, Dn, Dm) EMIT(VCGE_F_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCLT_0_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b100<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VCLT_0_8(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCLT_0_16(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCLT_0_32(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VCLTQ_0_8(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCLTQ_0_16(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VCLTQ_0_32(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VSHR_gen(U, D, imm6, Vd, L, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 1<<23 | (D)<<22 | (imm6)<<16 | (Vd)<<12 | (L)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
#define VSHR_U8(Dd, Dm, imm3) EMIT(VSHR_gen(1, ((Dd)>>4)&1, 0b001<<3 | (8-(imm3)), (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VSHR_S8(Dd, Dm, imm3) EMIT(VSHR_gen(0, ((Dd)>>4)&1, 0b001<<3 | (8-(imm3)), (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
@@ -803,6 +964,11 @@ Op is 20-27
#define VSHLQ_S32(Dd, Dm, Dn) EMIT(VSHLR_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VSHLQ_S64(Dd, Dm, Dn) EMIT(VSHLR_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VSHRN_gen(D, imm6, Vd, M, Vm) (0b1111<<28 | 0b0010<<24 | 1<<23 | (D)<<22 | (imm6)<<16 | (Vd)<<12 | 1<<11 | (M)<<5 | 1<<4 | (Vm))
#define VSHRN_16(Dd, Dm, imm3) EMIT(VSHRN_gen(((Dd)>>4)&1, 0b001<<3 | (8-(imm3)), (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VSHRN_32(Dd, Dm, imm4) EMIT(VSHRN_gen(((Dd)>>4)&1, 0b01<<4 | (16-(imm4)), (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VSHRN_64(Dd, Dm, imm5) EMIT(VSHRN_gen(((Dd)>>4)&1, 0b1<<5 | (32-(imm5)), (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
#define VTRN_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b10<<16 | (Vd)<<12 | 0b0000<<8 | 1<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VTRN_32(Dd, Dm) EMIT(VTRN_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
@@ -855,8 +1021,8 @@ Op is 20-27
#define VMUL_16(Dd, Dn, Dm) EMIT(VMUL_NEON_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VEXT_gen(D, Vn, Vd, imm4, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (Vn)<<16 | (Vd)<<12 | (imm4)<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VEXT_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4), ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VEXTQ_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4), ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VEXT_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4)&0xf, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VEXTQ_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4)&0xf, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VMVN_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b1011<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
#define VMVNQ(Dd, Dm) EMIT(VMVN_gen(((Dd)>>4)&1, 0, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
@@ -1062,7 +1228,7 @@ Op is 20-27
#define VPADD_Fgen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1101<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
// Add pair of F32, store result in F32
#define VPADD_F32(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VPADD_F32(Dd, Dn, Dm) EMIT(VPADD_Fgen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VMINMAX_gen(U, D, size, Vn, Vd, N, Q, M, op, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b110<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (op)<<4 | (Vm))
#define VMIN_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
@@ -1113,4 +1279,25 @@ Op is 20-27
#define VRHADDQ_S16(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VRHADDQ_S32(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VQRDMULH_gen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011 <<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
// Dd <= (2*Dn*Dm + 1<<(size-1))>>size
#define VQRDMULH_S16(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VQRDMULH_S32(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VQRDMULHQ_S16(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VQRDMULHQ_S32(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
#define VDUP_sgen(D, imm4, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (imm4)<<16 | (Vd)<<12 | 0b1100<<8 | (Q)<<6 | (M)<<5 | (Vm))
// Dd <= Dup(Dm[x])
#define VDUP_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
#define VABS_vgen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b110<<7 | (Q)<<6 | (M)<<5 | (Vm))
#define VABS_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VABS_S16(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 1, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VABS_S8(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 0, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
#define VABS_F(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
#define VABSQ_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VABSQ_S16(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VABSQ_S8(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
#define VABSQ_F(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
#endif //__ARM_EMITTER_H__
+5 -5
View File
@@ -10,10 +10,10 @@
arm_epilog:
//update register -> emu
//pop {r0}
stm r0, {r4-r12} // put back reg value in emu, including EIP (so r12 must be EIP now)
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (so r14 must be Flags now)
//restore all used register
//vpop {d8-d15}
pop {r4-r11, pc}
vpop {d8-d15}
pop {r4-r12, pc}
//end, return...
//bx lr
@@ -21,7 +21,7 @@ arm_epilog:
.global arm_epilog_fast
arm_epilog_fast:
//restore all used register
//vpop {d8-d15}
pop {r4-r11, pc}
vpop {d8-d15}
pop {r4-r12, pc}
//end, return...
//bx lr
+128 -67
View File
@@ -73,12 +73,19 @@
! VMOV is VORR constrained -> (removed VORR)
! VEOR, VBSL, VBIT, VBIF differ only depending on 2 bits: 0/1 0/1 ... VEOR -> @<2> ... @ ... @ V\op\ (field, switchable var, assembly)
! Three registers of different lengths (when having L and W variants): op (field) -> Q (field)
! MRS: always APSR since program is always in userspace
! DBG: option (field and assembly) -> imm (field and assembly)
; ========== BEGINNING OF REGISTERED INSTRUCTIONS =========
# This instruction changes the instruction set to Thumb! Disabled (but valid)
#ARM_ 1 1 1 1 1 0 1 @<1> imm24 @ set imm24 = (imm24 << 2) + (param << 1)@ @ BLX <label>
# CPS marked as invalid (in userspace, treated as NOP)
;INVALIDATE 1 1 1 1 0 0 0 1 0 0 0 0 <4> <8> <2> 0 <1> <4>
ARM_ 1 1 1 1 0 0 0 1 0 0 0 0 (0) (0) (0) 1 (0) (0) (0) (0) (0) (0) @<1> (0) 0 0 0 0 (0) (0) (0) (0) SETEND \%cparam ? 'B' : 'L'\E
;INVALIDATE 1 1 1 1 0 0 0 1 0 0 1 0 <4> <8> 0 1 1 1 <4>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 op 0 N Q M 0 Vm VH\(op ? "SUB" : "ADD")\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 0 N Q M 1 Vm VQADD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 1 N Q M 0 Vm VRHADD<c>.<dt> <Qd>, <Qn>, <Qm>
@@ -89,10 +96,10 @@ NEON 1 1 1 1 0 0 1 0 0 D 1 1 Vn Vd 0 0 0 1 N Q M 1 Vm VORN<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D @<2> Vn Vd 0 0 0 1 N Q M 1 Vm @ param=0b00=0b01=0b10 const char* op op,"EOR","BSL","BIT","BIF"@ @ V\op\<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 0 N Q M 1 Vm VQSUB<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 1 N Q M op Vm @ op=0 const char* strict strict,"T","E"@ @ VCG\strict\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 0 Vm VABD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 1 Vm VABA<c>.<dt> <Qd>, <Qn>, <Qm>
@@ -135,12 +142,12 @@ NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=1110 0 Q op/=1 1 imm4 VMOV<c>.<dt>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <11> 0 <2> 1 <4>
# Special case for VMOVL (harder to do it on the documented place)
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 0 L Q M 1 Vm VSHR<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 1 L Q M 1 Vm VSRA<c>.<dt> <Qd>, <Qm>, #<imm>
@@ -150,7 +157,7 @@ NEON 1 1 1 1 0 0 1 1 1 D imm6 Vd 0 1 0 0 L Q M 1 Vm VSRI<c>.<size> <Qd>, <Qm>, #
NEON 1 1 1 1 0 0 1 0 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSHL<c>.I<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSLI<c>.<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 0 1 1 op L Q M 1 Vm VQSHL\((u & op) ? "U" : "")\<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm @ set ++size@ @ VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 1 M 1 Vm VRSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 0 M 1 Vm VQSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 1 M 1 Vm VQRSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
@@ -194,7 +201,7 @@ NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 0 Q M 0 Vm VUZP<c>.\%d8 &l&l si
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 1 Q M 0 Vm VZIP<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 0 M 0 Vm VMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 1 M 0 Vm VQMOVUN<c>.S\%d16 &l&l size\ <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set u = 1 - u@ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 0 Vm VSHLL<c>.I\%d8 &l&l size\ <Qd>, <Dm>, #\%d8 &l&l size\
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 0 0 0 M 0 Vm VCVT<c>.F16.F32 <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 1 0 0 M 0 Vm VCVT<c>.F32.F16 <Qd>, <Dm>
@@ -237,107 +244,141 @@ NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQRDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 0 <1> 0 0 <22>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <20>
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 0 0 <20>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 0 <1> 1 0 <22>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 0 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 0 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 0 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <2> 1 1 <6>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <2> 0 0 <1> 1 <4>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 1 0 <3> 1 <4>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
;INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <20>
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 1 0 <20>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 0 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 1 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> Rm VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 <3> 0 <20>
ARM_ 1 1 1 1 0 1 0 0 @<1> 0 0 1 Rn @<8> @<4> @<4> 'NOP'
ARM_ 1 1 1 1 0 1 0 0 U 1 0 1 Rn (1) (1) (1) (1) imm12 PLI [<Rn>, #+/-<imm12>]
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 1 1 <4> <8> <4> <4>
ARM_ 1 1 1 1 0 1 0 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm12 PLD\param ? "W" : ""\ [<Rn>, #+/-<imm12>]
ARM_ 1 1 1 1 0 1 0 1 U (1) 0 1 1 1 1 1 (1) (1) (1) (1) imm12 PLD [PC, #+/-<imm>]
;INVALIDATE 1 1 1 1 0 1 0 1 0 0 1 1 <4> <8> <4> <4>
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 0 0 0 0 <4>
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 (1) (1) (1) (1) CLREX
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 0 0 1 <1> <4>
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 0 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DSB \option\
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 1 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DMB \option\
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 1 0 @<4> @ param=0b1111 const char* option option,"SY","!!!"@ @ ISB \option\
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 0 1 1 1 <4>
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 1 <3> <4>
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> <4> <4>
;INVALIDATE 1 1 1 1 0 1 0 1 1 <1> 1 1 <4> <8> <4> <4>
ARM_ 1 1 1 1 0 1 1 0 @<1> 0 0 1 Rn @<8> @<3> 0 @<4> 'NOP'
ARMs 1 1 1 1 0 1 1 0 U 1 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLI [<Rn>, +/-<Rm>{, <shift>}]
ARMs 1 1 1 1 0 1 1 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLD\param ? "W" : ""\ [<Rn>, +/-<Rm>{, <shift>}]
;INVALIDATE 1 1 1 1 0 1 1 <3> 1 1 <4> <8> <3> 0 <4>
# Permanently undefined
INVALIDATE 1 1 1 1 0 1 1 1 1 1 1 1 <4> <8> 1 1 1 1 <4>
;INVALIDATE 1 1 1 1 0 <7> <4> <8> <4> <4>
; ===== No more 1 1 1 1 ..., so invalidate all of them ====
INVALIDATE 1 1 1 1 <28>
@@ -390,12 +431,15 @@ ARMS cond 0 0 0 1 0 0 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TST<c> <Rn>, <Rm>{,
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 0 0 0 0 (1) (1) (1) (1) Rd (0) (0) 0 (0) 0 0 0 0 (0) (0) (0) (0) MRS<c> <Rd>, APSR
ARM_ cond 0 0 0 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) (0) (0) 0 (0) 0 0 0 0 Rn @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, <Rn>
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 0 1 Rm BX<c> <Rm>
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 0 Rm BXJ<c> <Rm>
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 1 Rm BLX<c> <Rm>
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
ARM_ cond 0 0 0 1 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
@@ -436,6 +480,18 @@ ARM_ cond 0 0 1 0 1 1 1 S Rn Rd imm12 RSC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 0 0 imm4 Rd imm12 MOVW<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 0 0 1 Rn (0) (0) (0) (0) imm12 TST<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 0 NOP<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 1 YIELD<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 1 0 WFE<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 1 1 WFI<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 1 0 0 SEV<c>
ARM_ cond/=1110 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 0 1 0 0 CSDB<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 1 1 1 1 imm4 DBG<c> #<imm>
INVALIDATE <4> 0 0 1 1 0 0 1 0 0 0 0 0 <8> <8>
ARM_ cond 0 0 1 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) imm12 @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, #<imm>
# MSR in system level is invalid/useless in application level
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 0 1 <8> <8>
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 1 <1> <8> <8>
INVALIDATE <4> 0 0 1 1 0 1 1 0 <4> <8> <8>
ARM_ cond 0 0 1 1 0 0 1 1 Rn (0) (0) (0) (0) imm12 TEQ<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 1 0 0 imm4 Rd imm12 MOVT<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 1 0 1 Rn (0) (0) (0) (0) imm12 CMP<c> <Rn>, #<const>
@@ -482,6 +538,7 @@ ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
@@ -493,6 +550,8 @@ ARMs cond 0 1 1 0 U 1 0 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>], +/-<Rm>{, <
ARMs cond 0 1 1 0 U 1 0 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 0 Rn Rt imm5 type 0 Rm STRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 1 Rn Rt imm5 type 0 Rm LDRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARM_ cond 0 1 1 1 0 0 0 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn SDIV<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 1 0 0 1 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn UDIV<c> <Rd>, <Rn>, <Rm>
ARMs cond 0 1 1 1 U 0 W 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 0 W 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 1 W 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
@@ -502,6 +561,7 @@ ARM_ cond 0 1 1 1 1 0 0 0 Rd Ra Rm 0 0 0 1 Rn USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 1 1 1 1 BFC<c> <Rd>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 Rn BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 1 widthm1 Rd lsb 1 0 1 Rn UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond/=1110 0 1 1 1 1 1 1 1 imm12 1 1 1 1 imm4 UDF<c> #<imm16>
ARM_ cond 1 0 0 0 0 0 W 0 Rn/=1101 register_list STMED<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 0 Rn register_list STMDA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 1 Rn/=1101 register_list LDMED<c> <Rn>{!}, <registers>
@@ -535,14 +595,14 @@ INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTMX<c> <LIst>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 sz imm8 VPUSH<c> <list>
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 @ set imm8*=4@ @ VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 sz imm8 VSTM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDMX<c> <LIst>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 sz imm8 VPOP<c> <list>
VFPU cond 1 1 0 1 0 D 0 1 1 1 1 1 Vd 1 0 1 sz 0 0 0 0 0 0 0 0 VLDR<c> <Dd>, [PC, #-0]
VFPU cond 1 1 0 1 U D 0 1 1 1 1 1 Vd 1 0 1 sz imm8 VLDR<c> <Dd>, <label>
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 @ set imm8*=4@ @ VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 sz imm8 VLDM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
INVALIDATE <4> 1 1 0 <25>
@@ -556,8 +616,9 @@ VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.32 <Qd>,
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 1 1 (0) (0) (0) (0) VDUP<c>.16 <Qd>, <Rt>
VFPU cond 1 1 1 0 1 1 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.8 <Qd>, <Rt>
VFPU cond 1 1 1 0 0 0 0 1 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Rt>, <Sn>
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt/=1111 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> APSR_nzcv, FPSCR
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> <Rt>, FPSCR
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 3) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 4) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 1 <4>
VFPU cond 1 1 1 0 0 D 0 0 Vn Vd 1 0 1 sz N op M 0 Vm VML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
@@ -585,7 +646,7 @@ VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 0 1 1 M 0 Vm VCVT<c>.F64.F32 <Dd>, <S
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 1 1 1 M 0 Vm VCVT<c>.F32.F64 <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCVT<c>.F\(size ? "64" : "32")\.\(op ? "S" : "U")\32 <Dd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.F\(size ? "64" : "32")\.\Td\ <Dd>, <Dd>, #<imm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 0 U Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 U 1 Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
;INVALIDATE <4> 1 1 1 0 1 <1> 1 1 <8> 1 0 1 <4> 0 <4>
;INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 0 <4>
-25
View File
@@ -1,25 +0,0 @@
//arm update linker table for dynarec
//called with pointer to emu as 1st parameter
//and address of table to as 2nd parameter
//ip is at r12
.text
.align 4
.extern UpdateLinkTable
.global arm_linker
arm_linker:
// emu is r0
stm r0, {r4-r12} // put back reg value in emu, including EIP (easier debugging, and safer)
// table offset is r1
// IP address is r12
push {r0, r1, r12}
mov r2, r12
// call the function
bl UpdateLinkTable
// return offset is jump address
mov r3, r0
pop {r0, r1, r12}
bx r3
+115
View File
@@ -0,0 +1,115 @@
// arm lock helper
// there is 2 part: read and write
// write return 0 on success, 1 on fail (value has been changed)
.text
.align 4
.global arm_lock_read_b
.global arm_lock_write_b
.global arm_lock_read_h
.global arm_lock_write_h
.global arm_lock_read_d
.global arm_lock_write_d
.global arm_lock_read_dd
.global arm_lock_write_dd
.global arm_lock_xchg
.global arm_lock_storeifnull
.global arm_lock_storeifref
arm_lock_read_b:
// address is r0, return is r0
dmb ish
ldrexb r0, [r0]
bx lr
arm_lock_write_b:
// address is r0, value is r1, return is r0
mov r2, r0
strexb r0, r1, [r2]
bx lr
arm_lock_read_h:
// address is r0, return is r0
dmb ish
ldrexh r0, [r0]
bx lr
arm_lock_write_h:
// address is r0, value is r1, return is r0
mov r2, r0
strexh r0, r1, [r2]
bx lr
arm_lock_read_d:
// address is r0, return is r0
// r0 needs to be aligned
dmb ish
ldrex r0, [r0]
bx lr
arm_lock_write_d:
// address is r0, value is r1, return is r0
// r0 needs to be aligned
mov r2, r0
strex r0, r1, [r2]
bx lr
arm_lock_read_dd:
// address is r2, return is r0, r1
dmb ish
ldrexd r2, r3, [r2]
str r2, [r0]
str r3, [r1]
bx lr
arm_lock_write_dd:
// address is r2, value is r0, r1, return is r0
// r0 needs to be aligned
strexd r3, r0, r1, [r2]
mov r0, r3
bx lr
arm_lock_xchg:
// address is r0, value is r1, return old value in r0
// r0 needs to be aligned
dmb ish
ldrex r2, [r0]
strex r3, r1, [r0]
cmp r3, #1
beq arm_lock_xchg
mov r0, r2
bx lr
arm_lock_storeifnull:
// address is r0, value is r1, r1 store to r0 only if [r0] is 0. return new [r0] value (so r1 or old value)
// r0 needs to be aligned
dmb ish
ldrex r2, [r0]
cmp r2, #0
bne arm_lock_storeifnull_exit
mov r2, r1
strex r3, r2, [r0]
cmp r3, #1
beq arm_lock_storeifnull
arm_lock_storeifnull_exit:
mov r0, r2
bx lr
arm_lock_storeifref:
push {r4}
dmb ish
arm_lock_storeifref_loop:
// address is r0, value is r1, r1 store to r0 only if [r0] is r2. return new [r0] value (so r1 or old value)
ldrex r3, [r0]
cmp r3, r2
bne arm_lock_storeifref_exit
mov r3, r1
strex r4, r3, [r0]
cmp r4, #1
beq arm_lock_storeifref_loop
arm_lock_storeifref_exit:
mov r0, r3
pop {r4}
bx lr
+34
View File
@@ -0,0 +1,34 @@
#ifndef __ARM_LOCK_HELPER__H__
#define __ARM_LOCK_HELPER__H__
#include <stdint.h>
// LDREXB of ADDR
extern uint8_t arm_lock_read_b(void* addr);
// STREXB of ADDR, return 0 if ok, 1 if not
extern int arm_lock_write_b(void* addr, uint8_t val);
// LDREXH of ADDR
extern uint16_t arm_lock_read_h(void* addr);
// STREXH of ADDR, return 0 if ok, 1 if not
extern int arm_lock_write_h(void* addr, uint16_t val);
// LDREX of ADDR
extern uint32_t arm_lock_read_d(void* addr);
// STREX of ADDR, return 0 if ok, 1 if not
extern int arm_lock_write_d(void* addr, uint32_t val);
// LDREXD of ADDR
extern void arm_lock_read_dd(uint32_t* a, uint32_t* b, void* addr);
// STREX of ADDR, return 0 if ok, 1 if not
extern int arm_lock_write_dd(uint32_t a, uint32_t b, void* addr);
// Atomically exchange value at [p] with val, return old p
extern uintptr_t arm_lock_xchg(void* p, uintptr_t val);
// Atomically store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
extern void* arm_lock_storeifnull(void* p, void* val);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
#endif //__ARM_LOCK_HELPER__H__
+23
View File
@@ -0,0 +1,23 @@
//arm update linker table for dynarec
//called with pointer to emu as 1st parameter
//and address of table to as 2nd parameter
//ip is at r12
.text
.align 4
.extern LinkNext
.global arm_next
arm_next:
// emu is r0
//stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug
// IP address is r1
push {r0, r1, r12, r14}
// call the function
bl LinkNext
// return offset is jump address
mov r3, r0
pop {r0, r1, r12, r14}
bx r3
+1255 -822
View File
File diff suppressed because it is too large. Load diff
+3 -3
View File
@@ -9,11 +9,11 @@
.global arm_prolog
arm_prolog:
//save all used register
push {r4-r11, lr}
//vpush {d8-d15}
push {r4-r12, lr}
vpush {d8-d15}
//setup emu -> register
//push {r0}
ldm r0, {r4-r11} // all 8 register in direct access, no EIP (so r12 can be used as scratch)
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
//TODO
//jump to function
bx r1
-19
View File
@@ -1,19 +0,0 @@
//arm try to update linker table for dynarec
//and address of table to as 1st parameter
//jump addres as second and ip as third
// don't retry if failed to write...
.text
.align 4
.global arm_tableupdate
arm_tableupdate:
// jump address is r0 and IP address is r1
// table offset is r2
push {r4, r5}
ldrexd r4, r5, [r2]
strexd r3, r0, r1, [r2]
pop {r4, r5}
mov r0, r3
bx lr
+236 -375
View File
@@ -2,6 +2,8 @@
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include <setjmp.h>
#include "debug.h"
#include "box86context.h"
@@ -20,16 +22,15 @@
#include "elfloader.h"
#ifdef ARM
#include "dynarec_arm.h"
#include "arm_lock_helper.h"
#else
#error Unsupported architecture!
#endif
#include "custommem.h"
#include "khash.h"
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
KHASH_SET_INIT_INT(mark)
uint32_t X31_hash_code(void* addr, int len)
{
if(!len) return 0;
@@ -39,27 +40,33 @@ uint32_t X31_hash_code(void* addr, int len)
return (uint32_t)h;
}
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz, int nolinker, int direct)
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
{
if(!textsz) {
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
return NULL;
}
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
ret->blocks = (nolinker && direct)?NULL:kh_init(dynablocks);
ret->base = base;
ret->text = text;
ret->textsz = textsz;
ret->nolinker = nolinker;
pthread_rwlock_init(&ret->rwlock_blocks, NULL);
if(direct && textsz) {
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
}
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
return ret;
}
void FreeDynablock(dynablock_t* db)
void FreeDynablock(dynablock_t* db, int need_lock)
{
if(db) {
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, tablesz=%d, %swith %d son(s)\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->tablesz, db->marks?"with marks, ":"", db->sons_size);
if(db->gone)
return; // already in the process of deletion!
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
db->done = 0;
db->gone = 1;
// remove from direct if there
uintptr_t startdb = db->parent->text;
uintptr_t enddb = db->parent->text + db->parent->textsz;
@@ -68,53 +75,23 @@ void FreeDynablock(dynablock_t* db)
if(addr>=startdb && addr<enddb)
db->parent->direct[addr-startdb] = NULL;
}
// remove from hash if there
if (db->parent->blocks) {
khint_t kdb;
kdb = kh_get(dynablocks, db->parent->blocks, (uintptr_t) db->x86_addr - db->parent->base);
if(kdb!=kh_end(db->parent->blocks))
kh_del(dynablocks, db->parent->blocks, kdb);
}
if(db->marks) {
// Follow mark and set arm_linker instead
khint_t k;
kh_foreach_key(db->marks, k,
void** p = (void**)(uintptr_t)k;
dynarec_log(LOG_DEBUG, " -- resettable(%p)\n", p);
resettable(p);
);
// free mark
kh_destroy(mark, db->marks);
db->marks = NULL;
}
for(int i=0; i<db->tablesz; i+=4) {
dynablock_t* p = (dynablock_t*)db->table[i+3];
dynarec_log(LOG_DEBUG, " -- table[%d+3] = %p ", i, p);
if(p && p!=db && p->marks) {
khint_t kd = kh_get(mark, p->marks, (uintptr_t)(&db->table[i+0]));
if(kd!=kh_end(p->marks)) {
kh_del(mark, p->marks, kd);
dynarec_log(LOG_DEBUG, "cleaned");
}
else {dynarec_log(LOG_DEBUG, "not found");}
}
dynarec_log(LOG_DEBUG, "\n");
}
// remove jumptable
setJumpTableDefault(db->x86_addr);
// remove and free the sons
for (int i=0; i<db->sons_size; ++i) {
dynablock_t *son = db->sons[i];
db->sons[i] = NULL;
FreeDynablock(son);
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
FreeDynablock(son, 0);
}
// only the father free the DynarecMap
if(!db->father) {
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
FreeDynarecMap((uintptr_t)db->block, db->size);
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
free(db->sons);
free(db->instsize);
}
free(db->sons);
free(db->table);
free(db);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
}
@@ -124,31 +101,15 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_INFO, "Free %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %s\n", (*dynablocks)->blocks?kh_size((*dynablocks)->blocks):0, (*dynablocks)->blocks?kh_n_buckets((*dynablocks)->blocks):0, (*dynablocks)->nolinker, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynablock_t* db;
if((*dynablocks)->blocks) {
// create a list of the parent db to delete (because there are sons in the middle that will be invalid if father is removed)
dynablock_t** list = (dynablock_t**)calloc(kh_size((*dynablocks)->blocks), sizeof(dynablock_t*));
int n = 0;
kh_foreach_value((*dynablocks)->blocks, db,
if(!db->father) list[n++] = db;
);
for (int i=0; i<n; ++i)
FreeDynablock(list[i]);
kh_destroy(dynablocks, (*dynablocks)->blocks);
(*dynablocks)->blocks = NULL;
free(list);
}
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
FreeDynablock((*dynablocks)->direct[i]);
FreeDynablock((*dynablocks)->direct[i], my_context?1:0);
}
free((*dynablocks)->direct);
}
(*dynablocks)->direct = 0;
pthread_rwlock_destroy(&(*dynablocks)->rwlock_blocks);
(*dynablocks)->direct = NULL;
free(*dynablocks);
*dynablocks = NULL;
@@ -159,103 +120,12 @@ void MarkDynablock(dynablock_t* db)
if(db) {
if(db->father)
db = db->father; // mark only father
if(db->marks && !db->need_test) {
// Follow mark and set arm_linker instead
khint_t k;
kh_foreach_key(db->marks, k,
void** p = (void**)(uintptr_t)k;
resettable(p);
);
// free mark
kh_clear(mark, db->marks);
}
if(db->need_test)
return; // already done
db->need_test = 1;
}
}
void ProtectDynablock(dynablock_t* db)
{
if(db) {
if(db->father)
return; // protect only father, child(ren) will be automatically
protectDB((uintptr_t)db->x86_addr, db->x86_size);
}
}
void RemoveMark(void** table)
{
// remove old value if any
dynablock_t *old = (dynablock_t*)table[3];
if(old && old->father)
old = old->father;
if(old && old->marks) {
khint_t kd = kh_get(mark, old->marks, (uintptr_t)table);
if(kd!=kh_end(old->marks))
kh_del(mark, old->marks, kd);
}
table[3] = NULL;
}
// source is linked to dest (i.e. source->table[x] = dest->block), so add a "mark" in dest, add a "linked" info to source
void AddMark(dynablock_t* source, dynablock_t* dest, void** table)
{
int ret;
// remove old value if any
dynablock_t *old = (dynablock_t*)table[3];
if(old && old->father)
old = old->father;
if(old && old->marks) {
khint_t kd = kh_get(mark, old->marks, (uintptr_t)table);
if(kd!=kh_end(old->marks))
kh_del(mark, old->marks, kd);
}
// add mark if needed
if(dest->father)
dest = dest->father;
if(dest->marks) {
kh_put(mark, dest->marks, (uintptr_t)table, &ret);
table[3] = (void*)dest;
} else
table[3] = NULL;
}
void MarkDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Marked %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %p:0x%x %s\n", (*dynablocks)->blocks?(kh_size((*dynablocks)->blocks)):0, (*dynablocks)->blocks?(kh_n_buckets((*dynablocks)->blocks)):0, (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynablock_t* db;
if((*dynablocks)->blocks) {
kh_foreach_value((*dynablocks)->blocks, db,
MarkDynablock(db);
);
}
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
MarkDynablock((*dynablocks)->direct[i]);
}
}
}
void ProtectkDynablockList(dynablocklist_t** dynablocks)
{
if(!dynablocks)
return;
if(!*dynablocks)
return;
dynarec_log(LOG_DEBUG, "Protect %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %p:0x%x %s\n", (*dynablocks)->blocks?(kh_size((*dynablocks)->blocks)):0, (*dynablocks)->blocks?(kh_n_buckets((*dynablocks)->blocks)):0, (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
dynablock_t* db;
if((*dynablocks)->blocks) {
kh_foreach_value((*dynablocks)->blocks, db,
ProtectDynablock(db);
);
}
if((*dynablocks)->direct) {
for (int i=0; i<(*dynablocks)->textsz; ++i) {
ProtectDynablock((*dynablocks)->direct[i]);
}
setJumpTableDefault(db->x86_addr);
for(int i=0; i<db->sons_size; ++i)
setJumpTableDefault(db->sons[i]->x86_addr);
}
}
@@ -268,320 +138,311 @@ uintptr_t StartDynablockList(dynablocklist_t* db)
uintptr_t EndDynablockList(dynablocklist_t* db)
{
if(db)
return db->text+db->textsz;
return db->text+db->textsz-1;
return 0;
}
void FreeDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
{
if(!dynablocks)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t start = addr;
uintptr_t end = addr+size;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i)
if(dynablocks->direct[i-startdb]) {
FreeDynablock(dynablocks->direct[i-startdb]);
}
if(start1 > end2 || start2 > end1)
return 0;
return 1;
}
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t start = addr;
uintptr_t end = addr+size;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i)
if(dynablocks->direct[i-startdb]) {
MarkDynablock(dynablocks->direct[i-startdb]);
}
}
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
if(!dynablocks->direct)
return;
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t enddb = startdb + dynablocks->textsz -1;
uintptr_t start = addr;
uintptr_t end = addr+size;
uintptr_t end = addr+size-1;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
dynablock_t *db;
if(end>startdb && start<enddb)
protectDB(start, end-start); //no +1; as end/enddb is exclusive and not inclusive
for(uintptr_t i = start; i<end; ++i)
if((db=dynablocks->direct[i-startdb]))
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
MarkDynablock(db);
}
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(dynablocks->direct)
FreeDirectDynablock(dynablocks, addr, size);
if(dynablocks->blocks) {
if(dynablocks->direct) {
dynablock_t* db;
uintptr_t s, e;
kh_foreach_value(dynablocks->blocks, db,
s = (uintptr_t)db->x86_addr;
e = (uintptr_t)db->x86_addr+db->x86_size-1;
if((s>=addr && s<(addr+size)) || (e>=addr && e<(addr+size)))
ProtectDynablock(db);
int ret;
khint_t k;
kh_dynablocks_t *blocks = kh_init(dynablocks);
// copy in a temporary list
if(dynablocks->direct) {
uintptr_t startdb = dynablocks->text;
uintptr_t enddb = startdb + dynablocks->textsz;
uintptr_t start = addr;
uintptr_t end = addr+size;
if(start<startdb)
start = startdb;
if(end>enddb)
end = enddb;
if(end>startdb && start<enddb)
for(uintptr_t i = start; i<end; ++i) {
db = (dynablock_t*)arm_lock_xchg(&dynablocks->direct[i-startdb], 0);
if(db) {
if(db->father)
db = db->father;
if(db->parent==dynablocks) {
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
kh_value(blocks, k) = db;
}
}
}
}
// purge the list
kh_foreach_value(blocks, db,
FreeDynablock(db, 1);
);
kh_destroy(dynablocks, blocks);
}
}
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
{
if(!dynablocks)
return;
if(dynablocks->direct)
MarkDirectDynablock(dynablocks, addr, size);
if(dynablocks->blocks) {
dynablock_t* db;
uintptr_t s, e;
kh_foreach_value(dynablocks->blocks, db,
s = (uintptr_t)db->x86_addr;
e = (uintptr_t)db->x86_addr+db->x86_size-1;
if((s>=addr && s<(addr+size)) || (e>=addr && e<(addr+size)))
MarkDynablock(db);
);
if(dynablocks->direct) {
uintptr_t new_addr = addr - dynablocks->maxsz;
uintptr_t new_size = size + dynablocks->maxsz;
MarkDirectDynablock(dynablocks, new_addr, new_size);
// the blocks check before
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
MarkDirectDynablock(getDB(idx), new_addr, new_size);
}
}
dynablock_t* FindDynablockDynablocklist(void* addr, dynablocklist_t* dynablocks)
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
{
if(!dynablocks)
return NULL;
if(dynablocks->direct)
for(int i=0; i<dynablocks->textsz; ++i) {
if(dynablocks->direct[i]) {
dynablock_t* db = dynablocks->direct[i];
uintptr_t s = (uintptr_t)db->block;
uintptr_t e = (uintptr_t)db->block+db->size;
if(s>=(uintptr_t)addr && e<(uintptr_t)addr)
return db->father?db->father:db;
}
}
if(dynablocks->blocks) {
dynablock_t* db;
uintptr_t s, e;
kh_foreach_value(dynablocks->blocks, db,
s = (uintptr_t)db->block;
e = (uintptr_t)db->block+db->size;
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
return db->father?db->father:db;
);
}
dynablock_t* db;
kh_foreach_value(dynablocks, db,
const uintptr_t s = (uintptr_t)db->block;
const uintptr_t e = (uintptr_t)db->block+db->size;
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
return db->father?db->father:db;
)
return NULL;
}
dynablock_t* FindDynablockFromNativeAddress(void* addr)
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
{
// unoptimized search through all dynablockslist for the dynablock that contains native addr (NULL if not found)
// search "volatile" dynarec first
dynablock_t *ret = NULL;
for(int idx=0; idx<65536 && !ret; ++idx)
if(my_context->dynmap[idx])
ret = FindDynablockDynablocklist(addr, my_context->dynmap[idx]->dynablocks);
if(ret)
return ret;
// search elfs
for(int idx=0; idx<my_context->elfsize && !ret; ++idx)
ret = FindDynablockDynablocklist(addr, GetDynablocksFromElf(my_context->elfs[idx]));
// last, search context dynablocks
if(my_context->dynablocks)
ret = FindDynablockDynablocklist(addr, my_context->dynablocks);
return ret;
const int idx = (addr>>DYNAMAP_SHIFT);
return getDB(idx);
}
void ConvertHash2Direct(dynablocklist_t* dynablocks)
{
if(dynablocks->textsz==0 || dynablocks->text==0 || !dynablocks->blocks)
return; // nothing to do
// create the new set
dynablock_t **direct = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
kh_dynablocks_t *blocks = kh_init(dynablocks);
// transfert
int ret;
khint_t k;
dynablock_t* db;
uintptr_t key;
uintptr_t start = dynablocks->text;
uintptr_t end = start + dynablocks->textsz;
kh_foreach(dynablocks->blocks, key, db,
key += dynablocks->base;
if(key>=start && key<end)
direct[key-start] = db;
else {
k = kh_put(dynablocks, blocks, key-dynablocks->base, &ret);
if(ret) { // don't try to insert if already done...
kh_value(blocks, k) = db;
}
}
);
// destroy old and do the swap (should swap before destroy, but hash access is always behind mutex)
kh_destroy(dynablocks, dynablocks->blocks);
dynablocks->blocks = blocks;
dynablocks->direct = direct;
}
#define MAGIC_SIZE 256
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int with_marks, int* created)
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
{
if(!dynablocks) {
dynarec_log(LOG_INFO, "Warning: Ask to create a dynblock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
*created = 0;
return NULL;
}
khint_t k;
int ret;
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
// this should be useless
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
//*created = 0;
//return NULL;
return AddNewDynablock(getDBFromAddress(addr), addr, created);
}
dynablock_t* block = NULL;
// first, check if it exist in direct access mode
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
if(dynablocks->direct) {
block = dynablocks->direct[addr-dynablocks->text];
if(block) {
dynarec_log(LOG_DUMP, "Block already exist in Direct Map\n");
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
*created = 0;
return block;
}
}
if(dynablocks->blocks) {
pthread_rwlock_rdlock(&dynablocks->rwlock_blocks);
// check if the block exist
khint_t k;
k = kh_get(dynablocks, dynablocks->blocks, addr-dynablocks->base);
if(k!=kh_end(dynablocks->blocks)) {
block = kh_value(dynablocks->blocks, k);
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
dynarec_log(LOG_DUMP, "Block already exist in Hash Map\n");
*created = 0;
return block;
}
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
}
if (!*created)
return block;
// Lock as write now!
pthread_rwlock_wrlock(&dynablocks->rwlock_blocks);
// create and add new block
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
block = dynablocks->direct[addr-dynablocks->text] = (dynablock_t*)calloc(1, sizeof(dynablock_t));
} else {
if(dynablocks->nolinker && ((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz)))) {
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
//*created = 0;
//return NULL;
return AddNewDynablock(getDBFromAddress(addr), addr, with_marks, created);
}
k = kh_put(dynablocks, dynablocks->blocks, addr-dynablocks->base, &ret);
if(!ret) {
// Ooops, block is already there? retreive it and bail out
dynarec_log(LOG_DUMP, "Block already exist in Hash Map\n");
block = kh_value(dynablocks->blocks, k);
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
*created = 0;
return block;
}
block = kh_value(dynablocks->blocks, k) = (dynablock_t*)calloc(1, sizeof(dynablock_t));
// check if size of hash map == magic size, if yes, convert to direct before unlocking
if(!dynablocks->direct && kh_size(dynablocks->blocks)==MAGIC_SIZE)
ConvertHash2Direct(dynablocks);
pthread_mutex_lock(&my_context->mutex_dyndump);
if(!dynablocks->direct) {
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
free(p); // someone already create the direct array, too late...
}
block->parent = dynablocks;
// add mark if needed
if(with_marks)
block->marks = kh_init(mark);
// create an empty block first, so if other thread want to execute the same block, they can, but using interpretor path
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
// create and add new block
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
block->parent = dynablocks;
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
pthread_mutex_unlock(&my_context->mutex_dyndump);
if(tmp != block) {
// a block appeard!
free(block);
*created = 0;
return tmp;
}
*created = 1;
return block;
}
//TODO: move this to dynrec_arm.c and track allocated structure to avoid memory leak
static __thread struct __jmp_buf_tag dynarec_jmpbuf;
void cancelFillBlock()
{
longjmp(&dynarec_jmpbuf, 1);
}
/*
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t* current)
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
{
// try the quickest way first: get parent of current and check if ok!
dynablocklist_t *dynablocks = NULL;
dynablock_t* block = NULL;
if(current) {
dynablocks = current->parent;
if(!(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
dynablocks = current->parent;
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
dynablocks = NULL;
else if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
block = dynablocks->direct[addr-dynablocks->text];
if(block)
return block;
}
}
// nope, lets do the long way
if(!dynablocks)
dynablocks = GetDynablocksFromAddress(emu->context, addr);
if(!dynablocks)
return NULL;
if(!dynablocks) {
dynablocks = getDBFromAddress(addr);
if(!dynablocks) {
dynablocks = GetDynablocksFromAddress(emu->context, addr);
if(!dynablocks)
return NULL;
}
}
// check direct first, without lock
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz)))
block = dynablocks->direct[addr-dynablocks->text];
if(block)
return block;
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
if((block = dynablocks->direct[addr-dynablocks->text]))
return block;
int created = create;
block = AddNewDynablock(dynablocks, addr, (dynablocks->nolinker)&&(dynablocks->direct), &created);
if(!created || !create)
block = AddNewDynablock(dynablocks, addr, &created);
if(!created)
return block; // existing block...
if(box86_dynarec_dump)
pthread_mutex_lock(&my_context->mutex_lock);
// fill the block
block->x86_addr = (void*)addr;
FillBlock(block);
if(box86_dynarec_dump)
pthread_mutex_unlock(&my_context->mutex_lock);
if(need_lock)
pthread_mutex_lock(&my_context->mutex_dyndump);
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
return NULL;
}
void* ret = FillBlock(block, filladdr);
if(need_lock)
pthread_mutex_unlock(&my_context->mutex_dyndump);
if(!ret) {
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
if(old!=block && old) { // put it back in place, strange things are happening here!
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
// Doing nothing else, the block has not been written
}
free(block);
block = NULL;
}
// check size
if(block && block->x86_size) {
int blocksz = block->x86_size;
if(dynablocks->maxsz<blocksz) {
dynablocks->maxsz = blocksz;
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
dynablocklist_t* dblist;
if((dblist = getDB(idx)))
if(dblist->maxsz<blocksz)
dblist->maxsz = blocksz;
}
}
//protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock
// but check if it already need test
if(block->need_test || (block->father && block->father->need_test))
return NULL;
// fill-in jumptable
addJumpTableIfDefault(block->x86_addr, block->block);
for(int i=0; i<block->sons_size; ++i)
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
}
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, %swith %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+block->x86_size), block->block, block->size, block->marks?"with Marks, ":"", block->sons_size);
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
return block;
}
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
{
dynablock_t *db = internalDBGetBlock(emu, addr, create, *current);
if(db && (db->need_test || (db->father && db->father->need_test))) {
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
return NULL;
dynablock_t *father = db->father?db->father:db;
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
if(hash!=father->hash) {
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X)%s with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->marks?" with Mark,":"", father->sons_size);
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
// no more current if it gets invalidated too
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
*current = NULL;
// Free father, it's now invalid!
FreeDynablock(father);
FreeDynablock(father, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, create, *current);
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
} else {
father->need_test = 0;
protectDB((uintptr_t)father->x86_addr, father->x86_size);
// fill back jumptable
addJumpTableIfDefault(father->x86_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
}
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
return db;
}
dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
{
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
int create = 1;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
return NULL;
dynablock_t *father = db->father?db->father:db;
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
if(hash!=father->hash) {
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
// Free father, it's now invalid!
FreeDynablock(father, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
} else {
father->need_test = 0;
protectDB((uintptr_t)father->x86_addr, father->x86_size);
// fill back jumptable
addJumpTableIfDefault(father->x86_addr, father->block);
for(int i=0; i<father->sons_size; ++i)
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
}
pthread_mutex_unlock(&my_context->mutex_dyndump);
}
return db;
}
+13 -13
View File
@@ -2,35 +2,35 @@
#define __DYNABLOCK_PRIVATE_H_
typedef struct dynablocklist_s dynablocklist_t;
typedef struct kh_dynablocks_s kh_dynablocks_t;
typedef struct kh_mark_s kh_mark_t;
typedef struct instsize_s {
unsigned int x86:4;
unsigned int nat:4;
} instsize_t;
typedef struct dynablock_s {
dynablocklist_t* parent;
kh_mark_t* marks; // List of blocks that marked this block
void* block;
int size;
void* x86_addr;
int x86_size;
uintptr_t x86_size;
uint32_t hash;
int need_test;
uintptr_t* table;
int tablesz;
int done;
uint8_t need_test;
uint8_t done;
uint8_t gone;
uint8_t dummy;
int isize;
dynablock_t** sons; // sons (kind-of dummy dynablock...)
int sons_size;
dynablock_t* father; // set only in the case of a son
instsize_t* instsize;
} dynablock_t;
typedef struct dynablocklist_s {
kh_dynablocks_t *blocks;
pthread_rwlock_t rwlock_blocks;
uintptr_t base;
uintptr_t text;
int textsz;
int nolinker; // in case this dynablock can disapear (also, block memory are allocated with a temporary scheme)
dynablock_t **direct; // direct mapping (waste of space, so not always there)
int maxsz; // maxblock size (for this block or previous block)
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
} dynablocklist_t;
#endif //__DYNABLOCK_PRIVATE_H_
+107 -57
View File
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <setjmp.h>
#include "debug.h"
#include "box86context.h"
@@ -14,84 +15,87 @@
#include "callback.h"
#include "emu/x86run_private.h"
#include "x86trace.h"
#include "threads.h"
#ifdef DYNAREC
#include "dynablock.h"
#include "dynablock_private.h"
#include "bridge.h"
#endif
#ifdef ARM
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
void arm_epilog() EXPORTDYN;
void arm_epilog_fast() EXPORTDYN;
void arm_linker() EXPORTDYN;
int arm_tableupdate(void* jump, uintptr_t addr, void** table) EXPORTDYN;
#endif
void tableupdate(void* jumpto, uintptr_t ref, void** table)
{
#ifdef ARM
if(arm_tableupdate(jumpto, ref, table))
#endif
{
table[0] = jumpto;
table[1] = (void*)ref;
}
}
void resettable(void** table)
{
void* p = table[1];
#ifdef ARM
tableupdate(arm_linker, (uintptr_t)p, table);
#endif
//table[2] = own_dynablock // unchanged
table[3] = NULL; // removed "linked" information
}
#ifdef DYNAREC
void* UpdateLinkTable(x86emu_t* emu, void** table, uintptr_t addr)
#ifdef HAVE_TRACE
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
#endif
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
{
dynablock_t* current = (dynablock_t*)table[2];
if(current->father)
current = current->father;
#ifdef HAVE_TRACE
if(!addr) {
x2-=8; // actual PC is 2 instructions ahead
dynablock_t* db = FindDynablockFromNativeAddress(x2);
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
}
#endif
dynablock_t* current = NULL;
void * jblock;
dynablock_t* block = DBGetBlock(emu, addr, 1, &current);
if(!current) { // current has been invalidated, stop running it...
//dynarec_log(LOG_DEBUG, "--- Current invalidated while linking.\n");
return arm_epilog_fast;
}
if(table[3]) {
//dynarec_log(LOG_DEBUG, "--- Remove mark from %p (%p)\n", current, table[3]);
RemoveMark(table);
}
if(!block) {
// no block, don't try again, ever
tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
// no block, let link table as is...
if(hasAlternate((void*)addr)) {
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
addr = (uintptr_t)getAlternate((void*)addr);
R_EIP = addr;
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
block = DBGetBlock(emu, addr, 1, &current);
}
if(!block) {
#ifdef HAVE_TRACE
dynablock_t* db = FindDynablockFromNativeAddress(x2);
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p)\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
#endif
//tableupdate(arm_epilog, addr, table);
return arm_epilog;
}
}
if(!block->done) {
// not finished yet... leave linker
//tableupdate(arm_linker, addr, table);
return arm_epilog_fast;
return arm_epilog;
}
if(!block->block) {
if(!(jblock=block->block)) {
// null block, but done: go to epilog, no linker here
tableupdate(arm_epilog, addr, table);
return arm_epilog_fast;
return arm_epilog;
}
dynablock_t *father = block->father?block->father:block;
if(!block->parent->nolinker || (current && father->marks)) {
//dynarec_log(LOG_DEBUG, "--- Linking %p/%p to %p (table=%p[%p/%p/%p/%p])\n", block, block->block, current, table, table[0], table[1], table[2], table[3]);
// only update block if linker is allowed or if marks is possibe
if(current && father->marks && current!=father)
AddMark(current, father, table);
tableupdate(block->block, addr, table);
}
return block->block;
//dynablock_t *father = block->father?block->father:block;
return jblock;
}
#endif
void DynaCall(x86emu_t* emu, uintptr_t addr)
{
// prepare setjump for signal handling
emu_jmpbuf_t *ejb = NULL;
int jmpbuf_reset = 0;
if(emu->type == EMUTYPE_MAIN) {
ejb = GetJmpBuf();
if(!ejb->jmpbuf_ok) {
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
jmpbuf_reset = 1;
int a;
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
addr = R_EIP; // not sure if it should still be inside DynaCall!
if(a==2)
Run(emu, 1); // "single step" next instruction that is doing auto-smc
}
}
}
#ifdef DYNAREC
if(!box86_dynarec)
#endif
@@ -111,14 +115,14 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, &current);
current = (block && !block->parent->nolinker)?block:NULL;
current = block;
if(!block || !block->block || !block->done) {
// no block, of block doesn't have DynaRec content (yet, temp is not null)
// Use interpreter (should use single instruction step...)
dynarec_log(LOG_DEBUG, "Calling Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) of %d x86 instructions (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize ,block->parent->nolinker, block->father, emu);
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
CHECK_FLAGS(emu);
// block is here, let's run it!
#ifdef ARM
@@ -130,6 +134,16 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
emu->quit = 0;
emu->fork = 0;
emu = x86emu_fork(emu, forktype);
if(emu->type == EMUTYPE_MAIN) {
ejb = GetJmpBuf();
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
jmpbuf_reset = 1;
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
addr = R_EIP;
}
}
}
}
emu->quit = 0; // reset Quit flags...
@@ -146,10 +160,35 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
}
}
#endif
// clear the setjmp
if(ejb && jmpbuf_reset)
ejb->jmpbuf_ok = 0;
}
int DynaRun(x86emu_t* emu)
{
// prepare setjump for signal handling
emu_jmpbuf_t *ejb = NULL;
#ifdef DYNAREC
int jmpbuf_reset = 1;
#endif
if(emu->type == EMUTYPE_MAIN) {
ejb = GetJmpBuf();
if(!ejb->jmpbuf_ok) {
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
int a;
#ifdef DYNAREC
jmpbuf_reset = 1;
#endif
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
if(a==2)
Run(emu, 1); // "single step" next instruction that is doing auto-smc
}
}
}
#ifdef DYNAREC
if(!box86_dynarec)
#endif
@@ -160,14 +199,14 @@ int DynaRun(x86emu_t* emu)
dynablock_t* current = NULL;
while(!emu->quit) {
block = DBGetBlock(emu, R_EIP, 1, &current);
current = (block && !block->parent->nolinker)?block:NULL;
current = block;
if(!block || !block->block || !block->done) {
// no block, of block doesn't have DynaRec content (yet, temp is not null)
// Use interpreter (should use single instruction step...)
dynarec_log(LOG_DEBUG, "Running Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
Run(emu, 1);
} else {
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) of %d x86 insts (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize, block->parent->nolinker, block->father, emu);
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
// block is here, let's run it!
#ifdef ARM
arm_prolog(emu, block->block);
@@ -178,9 +217,20 @@ int DynaRun(x86emu_t* emu)
emu->quit = 0;
emu->fork = 0;
emu = x86emu_fork(emu, forktype);
if(emu->type == EMUTYPE_MAIN) {
ejb = GetJmpBuf();
ejb->emu = emu;
ejb->jmpbuf_ok = 1;
jmpbuf_reset = 1;
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
}
}
}
}
// clear the setjmp
if(ejb && jmpbuf_reset)
ejb->jmpbuf_ok = 0;
return 0;
#endif
}
+325 -86
View File
@@ -6,6 +6,7 @@
#include "debug.h"
#include "box86context.h"
#include "custommem.h"
#include "dynarec.h"
#include "emu/x86emu_private.h"
#include "tools/bridge_private.h"
@@ -19,6 +20,7 @@
#include "dynablock_private.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "dynarec_arm_functions.h"
#include "elfloader.h"
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
@@ -56,13 +58,15 @@ void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const cha
}
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
if(!box86_dynarec_bigblock)
return;
for(int i=0; i<dyn->next_sz; ++i)
if(dyn->next[i]==addr)
return;
if(dyn->next_sz == dyn->next_cap) {
dyn->next_cap += 16;
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
}
for(int i=0; i<dyn->next_sz; ++i)
if(dyn->next[i]==addr)
return;
dyn->next[dyn->next_sz++] = addr;
}
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
@@ -81,9 +85,9 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
}
return best;
}
#define PK(A) (*((uint8_t*)(addr+(A))))
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
{
#define PK(A) (*((uint8_t*)(addr+(A))))
if(!n)
return 1;
if(PK(0)==0x90)
@@ -109,84 +113,232 @@ int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
return is_nops(dyn, addr+8, n-8);
return 0;
#undef PK
}
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
// return size of next instuciton, -1 is unknown
// not all instrction are setup
int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
{
if(ninst == dyn->size || (recurse==5))
return X_ALL; // no more instructions, or too many jmp loop, stop
uint32_t needed = dyn->insts[ninst].x86.use_flags;
if(needed) {
setf &= ~needed;
if(!setf) // all flags already used, no need to continue
return needed;
uint8_t opcode = PK(0);
uint8_t nextop;
switch (opcode) {
case 0x66:
opcode = PK(1);
switch(opcode) {
case 0x90:
return 2;
}
break;
case 0x81:
nextop = PK(1);
return fakeed(dyn, addr+2, 0, nextop)-addr + 4;
case 0x83:
nextop = PK(1);
return fakeed(dyn, addr+2, 0, nextop)-addr + 1;
case 0x84:
case 0x85:
case 0x88:
case 0x89:
case 0x8A:
case 0x8B:
case 0x8C:
case 0x8D:
case 0x8E:
case 0x8F:
nextop = PK(1);
return fakeed(dyn, addr+2, 0, nextop)-addr;
case 0x50:
case 0x51:
case 0x52:
case 0x53:
case 0x54:
case 0x55:
case 0x56:
case 0x57:
case 0x58:
case 0x59:
case 0x5A:
case 0x5B:
case 0x5C:
case 0x5D:
case 0x5E:
case 0x5F:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97:
case 0x98:
case 0x99:
case 0x9B:
case 0x9C:
case 0x9D:
case 0x9E:
case 0x9F:
return 1;
case 0xA0:
case 0xA1:
case 0xA2:
case 0xA3:
return 5;
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
return 2;
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF:
return 5;
case 0xFF:
nextop = PK(1);
switch((nextop>>3)&7) {
case 0: // INC Ed
case 1: //DEC Ed
case 2: // CALL Ed
case 4: // JMP Ed
case 6: // Push Ed
return fakeed(dyn, addr+2, 0, nextop)-addr;
}
break;
default:
break;
}
return -1;
}
#undef PK
if(!needed && !dyn->insts[ninst].x86.set_flags && !dyn->insts[ninst].x86.jmp_insts) {
int start = ninst;
int end = ninst;
while(end<dyn->size && !dyn->insts[end].x86.use_flags && !dyn->insts[end].x86.set_flags && !dyn->insts[end].x86.jmp_insts)
++end;
needed = needed_flags(dyn, end, setf, recurse);
for(int i=start; i<end; ++i)
dyn->insts[i].x86.need_flags = needed;
return needed;
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
{
int i = 0;
while(i<n) {
int j=next_instruction(dyn, addr+i);
if(j<=0) return 0;
i+=j;
}
if(dyn->insts[ninst].x86.set_flags && (dyn->insts[ninst].x86.state_flags!=SF_MAYSET)) {
if((setf & ~dyn->insts[ninst].x86.set_flags) == 0)
return needed; // all done, gives all the flags needed
setf |= dyn->insts[ninst].x86.set_flags; // add new flags to continue
}
int jinst = dyn->insts[ninst].x86.jmp_insts;
if(dyn->insts[ninst].x86.jmp) {
dyn->insts[ninst].x86.need_flags = (jinst==-1)?X_PEND:needed_flags(dyn, jinst, setf, recurse+1);
if(dyn->insts[ninst].x86.use_flags) // conditionnal jump
dyn->insts[ninst].x86.need_flags |= needed_flags(dyn, ninst+1, setf, recurse);
} else
dyn->insts[ninst].x86.need_flags = needed_flags(dyn, ninst+1, setf, recurse);
if(dyn->insts[ninst].x86.state_flags==SF_MAYSET)
needed |= dyn->insts[ninst].x86.need_flags;
else
needed |= (dyn->insts[ninst].x86.need_flags & ~dyn->insts[ninst].x86.set_flags);
if(needed == (X_PEND|X_ALL))
needed = X_ALL;
return needed;
return (i==n)?1:0;
}
void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
{
// x86 instruction is <16 bytes
int toadd;
if(x86_size>arm_size)
toadd = 1 + x86_size/15;
else
toadd = 1 + arm_size/15;
if((*size)+toadd>(*cap)) {
*cap = (*size)+toadd;
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
}
while(toadd) {
if(x86_size>15)
insts[*size].x86 = 15;
else
insts[*size].x86 = x86_size;
x86_size -= insts[*size].x86;
if(arm_size>15)
insts[*size].nat = 15;
else
insts[*size].nat = arm_size;
arm_size -= insts[*size].nat;
++(*size);
--toadd;
}
return insts;
}
void* FillBlock(dynablock_t* block) {
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
__thread void* current_helper = NULL;
void CancelBlock()
{
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
current_helper = NULL;
if(!helper)
return;
free(helper->next);
free(helper->insts);
free(helper->sons_x86);
free(helper->sons_arm);
if(helper->dynablock && helper->dynablock->block)
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
}
void* FillBlock(dynablock_t* block, uintptr_t addr) {
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
return NULL;
}
if(!isJumpTableDefault((void*)addr)) {
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
return NULL;
}
// init the helper
uintptr_t addr = (uintptr_t)block->x86_addr;
dynarec_arm_t helper = {0};
helper.nolinker = box86_dynarec_linker?(block->parent->nolinker):1;
current_helper = &helper;
helper.dynablock = block;
helper.start = addr;
arm_pass0(&helper, addr);
uintptr_t start = addr;
helper.cap = 64; // needs epilog handling
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
// pass 0, addresses, x86 jump addresses, overall size of the block
uintptr_t end = arm_pass0(&helper, addr);
// no need for next anymore
free(helper.next);
helper.next_sz = helper.next_cap = 0;
helper.next = NULL;
// basic checks
if(!helper.size) {
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
block->done = 1;
free(helper.next);
CancelBlock();
return (void*)block;
}
helper.cap = helper.size+3; // needs epilog handling
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
// pass 1, addresses, x86 jump addresses, flags
arm_pass1(&helper, addr);
// already protect the block and compute hash signature
protectDB(addr, end-addr); //end is 1byte after actual end
uint32_t hash = X31_hash_code((void*)addr, end-addr);
// Compute flag_need, without taking into account any barriers
uint32_t last_need = X_PEND;
for(int i = helper.size; i-- > 0;) {
last_need |= helper.insts[i].x86.use_flags;
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
if (last_need == (X_PEND | X_ALL)) {
last_need = X_ALL;
}
helper.insts[i].x86.need_flags = last_need;
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
if (last_need & X_PEND) {
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
} else {
last_need &= ~helper.insts[i].x86.set_flags;
}
}
}
// calculate barriers
uintptr_t start = helper.insts[0].x86.addr;
uintptr_t end = helper.insts[helper.size].x86.addr+helper.insts[helper.size].x86.size;
for(int i=0; i<helper.size; ++i)
if(helper.insts[i].x86.jmp) {
uintptr_t j = helper.insts[i].x86.jmp;
if(j<start || j>=end)
if(j<start || j>=end) {
helper.insts[i].x86.jmp_insts = -1;
else {
} else {
// find jump address instruction
int k=-1;
for(int i2=0; i2<helper.size && k==-1; ++i2) {
@@ -198,58 +350,140 @@ void* FillBlock(dynablock_t* block) {
helper.insts[i].x86.jmp_insts = k;
}
}
for(int i=0; i<helper.size; ++i)
if(helper.insts[i].x86.set_flags && !helper.insts[i].x86.need_flags) {
helper.insts[i].x86.need_flags = needed_flags(&helper, i+1, helper.insts[i].x86.set_flags, 0);
if((helper.insts[i].x86.need_flags&X_PEND) && (helper.insts[i].x86.state_flags==SF_MAYSET))
helper.insts[i].x86.need_flags = X_ALL;
// check for the optionnal barriers now
for(int i=helper.size-1; i>=0; --i) {
if(helper.insts[i].x86.barrier==3)
if(helper.insts[i].x86.jmp_insts == -1) {
if(i==helper.size-1 || helper.insts[i+1].x86.barrier)
helper.insts[i].x86.barrier=2; // nope, end of block or barrier just after
else
helper.insts[i].x86.barrier=0; // ok, no need for a barrier here after all
} else
helper.insts[i].x86.barrier=2;
}
// check to remove useless barrier, in case of jump when destination doesn't needs flags
for(int i=helper.size-1; i>=0; --i) {
if(helper.insts[i].x86.jmp
&& helper.insts[i].x86.jmp_insts>=0
&& helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1) {
int k = helper.insts[i].x86.jmp_insts;
//TODO: optimize FPU barrier too
if((!helper.insts[k].x86.need_flags)
||(helper.insts[k].x86.set_flags==X_ALL
&& helper.insts[k].x86.state_flags==SF_SET)
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
helper.insts[k].x86.barrier = 4; // remove barrier (keep FPU barrier, and still reset state flag)
}
}
}
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
for(int i = helper.size; i-- > 0;) {
if(helper.insts[i].x86.barrier==1)
// immediate barrier
helper.insts[i].x86.use_flags |= X_PEND;
else if(helper.insts[i].x86.jmp
&& helper.insts[i].x86.jmp_insts>=0
) {
if(helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1)
// jumpto barrier
helper.insts[i].x86.use_flags |= X_PEND;
else
helper.insts[i].x86.use_flags |= helper.insts[helper.insts[i].x86.jmp_insts].x86.need_flags;
}
}
for(int i = helper.size; i-- > 0;)
helper.insts[i].x86.need_flags = 0;
last_need = X_PEND;
for(int i = helper.size; i-- > 0;) {
helper.insts[i].x86.need_flags = last_need;
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
if (last_need & X_PEND) {
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
} else {
last_need &= ~helper.insts[i].x86.set_flags;
}
}
last_need |= helper.insts[i].x86.use_flags;
if (last_need == (X_PEND | X_ALL)) {
last_need = X_ALL;
}
}
// pass 1, float optimisations
arm_pass1(&helper, addr);
// pass 2, instruction size
arm_pass2(&helper, addr);
// ok, now allocate mapped memory, with executable flag on
int sz = helper.arm_size;
void* p = (void*)AllocDynarecMap(sz, block->parent->nolinker);
void* p = (void*)AllocDynarecMap(block, sz);
if(p==NULL) {
free(helper.insts);
free(helper.next);
return (void*)block;
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
CancelBlock();
return NULL;
}
helper.block = p;
helper.arm_start = (uintptr_t)p;
helper.tablesz = helper.tablei;
if(helper.tablesz)
helper.table = (uintptr_t*)calloc(helper.tablesz, sizeof(uintptr_t));
if(helper.sons_size) {
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
}
// pass 3, emit (log emit arm opcode)
if(box86_dynarec_dump) {
dynarec_log(LOG_NONE, "%sEmitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", helper.arm_size, helper.isize);
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
printFunctionAddr(helper.start, " => ");
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
}
helper.arm_size = 0;
arm_pass3(&helper, addr);
if(sz!=helper.arm_size) {printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);}
if(sz!=helper.arm_size) {
printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);
uint8_t *dump = (uint8_t*)helper.start;
printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size);
for(int i=0; i<helper.size; ++i) {
printf_log(LOG_NONE, "%p:", dump);
for(; dump<(uint8_t*)helper.insts[i+1].x86.addr; ++dump)
printf_log(LOG_NONE, " %02X", *dump);
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
}
printf_log(LOG_NONE, " ------------\n");
}
// all done...
__builtin___clear_cache(p, p+sz); // need to clear the cache before execution...
__clear_cache(p, p+sz); // need to clear the cache before execution...
// keep size of instructions for signal handling
{
size_t cap = 1;
for(int i=0; i<helper.size; ++i)
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
size_t size = 0;
block->instsize = (instsize_t*)calloc(cap, sizeof(instsize_t));
for(int i=0; i<helper.size; ++i)
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
}
// ok, free the helper now
free(helper.insts);
helper.insts = NULL;
free(helper.next);
block->table = helper.table;
block->tablesz = helper.tablesz;
for (int i=0; i<helper.tablesz/4; ++i)
block->table[i*4+2] = (uintptr_t)block;
helper.next = NULL;
block->size = sz;
block->isize = helper.size;
block->block = p;
block->need_test = 0;
block->x86_addr = (void*)start;
//block->x86_addr = (void*)start;
block->x86_size = end-start;
if(box86_dynarec_largest<block->x86_size)
box86_dynarec_largest = block->x86_size;
block->hash = (helper.nolinker)?X31_hash_code(block->x86_addr, block->x86_size):0;
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
// Check if something changed, to abbort if it as
if(block->hash != hash) {
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
CancelBlock();
return NULL;
}
// fill sons if any
dynablock_t** sons = NULL;
int sons_size = 0;
@@ -257,8 +491,8 @@ void* FillBlock(dynablock_t* block) {
sons = (dynablock_t**)calloc(helper.sons_size, sizeof(dynablock_t*));
for (int i=0; i<helper.sons_size; ++i) {
int created = 1;
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], 0, &created);
if(created) { // avoid breaking a working block! also, block could be outside this parent...
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
if(created) { // avoid breaking a working block!
son->block = helper.sons_arm[i];
son->x86_addr = (void*)helper.sons_x86[i];
son->x86_size = end-helper.sons_x86[i];
@@ -266,6 +500,8 @@ void* FillBlock(dynablock_t* block) {
son->father = block;
son->done = 1;
sons[sons_size++] = son;
if(!son->parent)
son->parent = block->parent;
}
}
if(sons_size) {
@@ -274,8 +510,11 @@ void* FillBlock(dynablock_t* block) {
} else
free(sons);
}
if(block->parent->nolinker)
protectDB((uintptr_t)block->x86_addr, block->x86_size);
free(helper.sons_x86);
helper.sons_x86 = NULL;
free(helper.sons_arm);
helper.sons_arm = NULL;
current_helper = NULL;
block->done = 1;
return (void*)block;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+215 -37
View File
@@ -25,71 +25,207 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
{
uint8_t opcode = F8;
uint8_t nextop;
int32_t i32;
int32_t i32, j32;
uint32_t u32;
uint8_t gd, ed;
uint8_t wback;
int fixedaddress;
MAYUSE(j32);
switch(opcode) {
case 0x33:
INST_NAME("XOR Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
case 0x03:
INST_NAME("ADD Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_xor32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_add32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x2B:
INST_NAME("SUB Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
emit_sub32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x33:
INST_NAME("XOR Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
emit_xor32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x39:
INST_NAME("CMP FS:Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
emit_cmp32(dyn, ninst, ed, gd, x3, x14);
break;
case 0x3B:
INST_NAME("CMP Gd, FS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_fsdata(dyn, addr, ninst, x12);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x67:
// reduced EA size...
opcode = F8;
switch(opcode) {
case 0x89:
INST_NAME("MOV FS:Ew16, Gw");
nextop = F8;
grab_fsdata(dyn, addr, ninst, x14);
GETGD; // don't need GETGW here
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
if(ed!=gd) {
BFI(ed, gd, 0, 16);
}
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STRH_REG(gd, x14, ed);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x14);
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(gd, xEAX+(nextop&7));
} else { // mem <= reg
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8F:
INST_NAME("POP FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x14);
if((nextop&0xC0)==0xC0) {
POP1(xEAX+(nextop&7)); // 67 ignored
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, x1, x14, 0);
}
break;
case 0xA1:
INST_NAME("MOV EAX, FS:Ow");
grab_fsdata(dyn, addr, ninst, x1);
u32 = F16;
if(u32) {
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
}
LDR_IMM9(xEAX, x1, 0);
break;
case 0xA3:
INST_NAME("MOV FS:Ow, EAX");
grab_fsdata(dyn, addr, ninst, x1);
u32 = F16;
if(u32) {
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
}
STR_IMM9(xEAX, x1, 0);
break;
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH FS:Ew");
if((nextop&0xC0)==0xC0) { // reg
DEFAULT;
} else { // mem <= i32
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
break;
case 0x89:
INST_NAME("MOV FS:Ed, Gd");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(xEAX+(nextop&7), gd);
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STR_REG_LSL_IMM5(gd, ed, x12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
STR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ed");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(gd, xEAX+(nextop&7));
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8F:
INST_NAME("POP FS:Ed");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop = F8;
if((nextop&0xC0)==0xC0) {
POP(xESP, (1<<(xEAX+(nextop&7))));
POP1(xEAX+(nextop&7));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP(xESP, (1<<x2));
STR_REG_LSL_IMM5(x2, ed, x12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, ed, x14, 0);
}
break;
case 0xA0:
INST_NAME("MOV AL, FS:Id");
grab_fsdata(dyn, addr, ninst, x1);
i32 = F32S;
if(i32>-4096 && i32<4096) {
LDRB_IMM9(xEAX, x1, i32);
} else {
MOV32(x2, i32);
LDRB_REG_LSL_IMM5(xEAX, x1, x2, 0);
}
break;
case 0xA1:
INST_NAME("MOV EAX, FS:Id");
grab_fsdata(dyn, addr, ninst, x1);
@@ -98,48 +234,90 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
LDR_IMM9(xEAX, x1, i32);
} else {
MOV32(x2, i32);
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
LDR_IMM9(xEAX, x1, 0);
LDR_REG_LSL_IMM5(xEAX, x1, x2, 0);
}
break;
case 0xA2:
INST_NAME("MOV FS:Od, AL");
grab_fsdata(dyn, addr, ninst, x1);
i32 = F32S;
if(i32>-4096 && i32<4096) {
STRB_IMM9(xEAX, x1, i32);
} else {
MOV32(x2, i32);
STRB_REG_LSL_IMM5(xEAX, x1, x2, 0);
}
break;
case 0xA3:
INST_NAME("MOV FS:Od, EAX");
grab_fsdata(dyn, addr, ninst, x1);
u32 = F32;
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
STR_IMM9(xEAX, x2, 0);
i32 = F32S;
if(i32>-4096 && i32<4096) {
STR_IMM9(xEAX, x1, i32);
} else {
MOV32(x2, i32);
STR_REG_LSL_IMM5(xEAX, x2, x1, 0);
}
break;
case 0xC7:
INST_NAME("MOV FS:Ed, Id");
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
nextop=F8;
if((nextop&0xC0)==0xC0) { // reg <= i32
i32 = F32S;
ed = xEAX+(nextop&7);
MOV32(ed, i32);
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
i32 = F32S;
MOV32(x3, i32);
STR_REG_LSL_IMM5(x3, ed, x12, 0);
STR_REG_LSL_IMM5(x3, ed, x14, 0);
}
break;
case 0xE9:
case 0xEB:
INST_NAME("(ignored) FS:");
--addr;
break;
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x12);
grab_fsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 2: // CALL Ed
INST_NAME("CALL FS:Ed");
PASS2IF(ninst && dyn->insts[ninst-1].x86.set_flags, 1) {
READFLAGS(X_PEND); // that's suspicious
} else {
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
}
if((nextop&0xC0)==0xC0) { // reg
MOV_REG(xEIP, xEAX+(nextop&7));
} else { // mem
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
}
BARRIER(1);
BARRIER_NEXT(1);
if(!dyn->insts || ninst!=dyn->size-1) {
} else {
*need_epilog = 0;
*ok = 0;
}
MOV32(x2, addr);
PUSH1(x2);
jump_to_next(dyn, 0, xEIP, ninst);
break;
case 6: // Push Ed
INST_NAME("PUSH Ed");
INST_NAME("PUSH FS:Ed");
if((nextop&0xC0)==0xC0) { // reg
DEFAULT;
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
PUSH(xESP, 1<<x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
+505 -23
View File
@@ -25,65 +25,356 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
{
uint8_t opcode = F8;
uint8_t nextop;
int32_t i32;
int32_t i32, j32;
uint32_t u32;
uint8_t gd, ed;
uint8_t wback;
uint8_t wback, wb1, wb2, wb;
uint8_t u8;
int fixedaddress;
MAYUSE(j32);
MAYUSE(wback);
MAYUSE(wb2);
switch(opcode) {
case 0x03:
INST_NAME("ADD Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_add32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_add32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x0F: // more opcodes
opcode = F8;
switch(opcode) {
case 0xAF:
INST_NAME("IMUL Gd, Ed");
SETFLAGS(X_ALL, SF_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
UFLAG_IF {
SMULL(x3, gd, gd, ed);
UFLAG_OP1(x3);
UFLAG_RES(gd);
UFLAG_DF(x3, d_imul32);
} else {
MUL(gd, gd, ed);
}
break;
default:
DEFAULT;
}
break;
case 0x21:
INST_NAME("AND Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO2(x14);
emit_and32(dyn, ninst, ed, gd, x3, x14);
WBACK;
break;
case 0x23:
INST_NAME("AND Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
emit_and32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x29:
INST_NAME("SUB GS:Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO2(x14);
emit_sub32(dyn, ninst, ed, gd, x3, x14);
WBACK;
break;
case 0x2B:
INST_NAME("SUB Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_sub32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_sub32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x31:
INST_NAME("XOR GS:Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO2(x14);
emit_xor32(dyn, ninst, gd, ed, x3, x14);
WBACK;
break;
case 0x33:
INST_NAME("XOR Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET);
grab_tlsdata(dyn, addr, ninst, x12);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x12);
emit_xor32(dyn, ninst, gd, ed, x3, x12);
GETEDO(x14);
emit_xor32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x3B:
INST_NAME("CMP Gd, GS:Ed");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
break;
case 0x69:
INST_NAME("IMUL Gd, GS:Ed, Id");
SETFLAGS(X_ALL, SF_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
GETGD;
GETEDO(x14);
i32 = F32S;
MOV32(x14, i32);
UFLAG_IF {
SMULL(x3, gd, x14, ed);
UFLAG_OP1(x3);
UFLAG_RES(gd);
UFLAG_DF(x3, d_imul32);
} else {
MUL(gd, ed, x14);
}
break;
case 0x80:
case 0x82:
nextop = F8;
switch((nextop>>3)&7) {
case 0: //ADD
INST_NAME("ADD GS:Eb, Ib");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_add8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 1: //OR
INST_NAME("OR GS:Eb, Ib");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_or8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 2: //ADC
INST_NAME("ADC GS:Eb, Ib");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_adc8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 3: //SBB
INST_NAME("SBB GS:Eb, Ib");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_sbb8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 4: //AND
INST_NAME("AND GS:Eb, Ib");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_and8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 5: //SUB
INST_NAME("SUB GS:Eb, Ib");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_sub8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 6: //XOR
INST_NAME("XOR GS:Eb, Ib");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
emit_xor8c(dyn, ninst, x1, u8, x2, x14);
EBBACK;
break;
case 7: //CMP
INST_NAME("CMP GS:Eb, Ib");
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x1);
GETEBO(x1);
u8 = F8;
if(u8) {
MOVW(x2, u8);
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
} else {
emit_cmp8_0(dyn, ninst, x1, x3, x14);
}
break;
}
break;
case 0x81:
case 0x83:
nextop = F8;
switch((nextop>>3)&7) {
case 0: //ADD
if(opcode==0x81) {
INST_NAME("ADD Ed, Id");
} else {
INST_NAME("ADD Ed, Ib");
}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_add32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 1: //OR
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_or32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 2: //ADC
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 3: //SBB
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 4: //AND
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_and32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 5: //SUB
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 6: //XOR
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
WBACK;
break;
case 7: //CMP
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
SETFLAGS(X_ALL, SF_SET_PENDING);
grab_tlsdata(dyn, addr, ninst, x14);
GETEDO2(x14);
if(opcode==0x81) i32 = F32S; else i32 = F8S;
if(i32) {
MOV32(x2, i32);
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
} else {
emit_cmp32_0(dyn, ninst, ed, x3, x14);
}
break;
}
break;
case 0x89:
INST_NAME("MOV GS:Ed, Gd");
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(xEAX+(nextop&7), gd);
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STR_REG_LSL_IMM5(gd, ed, x12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
STR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8B:
INST_NAME("MOV Gd, GS:Ed");
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop=F8;
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
MOV_REG(gd, xEAX+(nextop&7));
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
}
break;
case 0x8F:
INST_NAME("POP GS:Ed");
grab_tlsdata(dyn, addr, ninst, x14);
nextop = F8;
if((nextop&0xC0)==0xC0) {
POP1((xEAX+(nextop&7)));
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, ed, x14, 0);
}
break;
@@ -111,17 +402,208 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("MOV GS:Ed, Id");
grab_tlsdata(dyn, addr, ninst, x12);
grab_tlsdata(dyn, addr, ninst, x14);
nextop=F8;
if((nextop&0xC0)==0xC0) { // reg <= i32
i32 = F32S;
ed = xEAX+(nextop&7);
MOV32(ed, i32);
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
i32 = F32S;
MOV32(x3, i32);
STR_REG_LSL_IMM5(x3, ed, x12, 0);
STR_REG_LSL_IMM5(x3, ed, x14, 0);
}
break;
case 0xD1:
nextop = F8;
grab_tlsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 0:
INST_NAME("ROL Ed, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETEDO2(x14);
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
case 1:
INST_NAME("ROR Ed, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET);
GETEDO2(x14);
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
case 2:
INST_NAME("RCL Ed, 1");
MESSAGE(LOG_DUMP, "Need Optimization\n");
READFLAGS(X_CF);
SETFLAGS(X_OF|X_CF, SF_SET);
MOVW(x2, 1);
GETEDO2(x14);
wb = ed;
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
CALL_(rcl32, ed, (1<<x14));
SBACK(wb);
break;
case 3:
INST_NAME("RCR Ed, 1");
MESSAGE(LOG_DUMP, "Need Optimization\n");
READFLAGS(X_CF);
SETFLAGS(X_OF|X_CF, SF_SET);
MOVW(x2, 1);
wb = ed;
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
CALL_(rcr32, ed, (1<<x14));
SBACK(wb);
break;
case 4:
case 6:
INST_NAME("SHL Ed, 1");
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
GETEDO2(x14);
emit_shl32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
case 5:
INST_NAME("SHR Ed, 1");
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
GETEDO2(x14);
emit_shr32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
case 7:
INST_NAME("SAR Ed, 1");
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
GETEDO2(x14);
emit_sar32c(dyn, ninst, ed, 1, x3, x14);
WBACK;
break;
}
break;
case 0xD3:
nextop = F8;
grab_tlsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 0:
INST_NAME("ROL Ed, CL");
SETFLAGS(X_OF|X_CF, SF_SUBSET);
AND_IMM8(x3, xECX, 0x1f);
TSTS_REG_LSL_IMM5(x3, x3, 0);
B_MARK2(cEQ);
RSB_IMM8(x3, x3, 0x20);
GETEDO2(x14);
MOV_REG_ROR_REG(ed, ed, x3);
WBACK;
UFLAG_IF { // calculate flags directly
CMPS_IMM8(x3, 31);
B_MARK(cNE);
MOV_REG_LSR_IMM5(x1, ed, 31);
ADD_REG_LSL_IMM5(x1, x1, ed, 0);
BFI(xFlags, x1, F_OF, 1);
MARK;
BFI(xFlags, ed, F_CF, 1);
UFLAG_DF(x2, d_none);
}
MARK2;
break;
case 1:
INST_NAME("ROR Ed, CL");
SETFLAGS(X_OF|X_CF, SF_SUBSET);
AND_IMM8(x3, xECX, 0x1f);
TSTS_REG_LSL_IMM5(x3, x3, 0);
B_MARK2(cEQ);
GETEDO2(x14);
MOV_REG_ROR_REG(ed, ed, x3);
WBACK;
UFLAG_IF { // calculate flags directly
CMPS_IMM8(x3, 1);
B_MARK(cNE);
MOV_REG_LSR_IMM5(x2, ed, 30); // x2 = d>>30
XOR_REG_LSR_IMM8(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
BFI(xFlags, x2, F_OF, 1);
MARK;
MOV_REG_LSR_IMM5(x2, ed, 31);
BFI(xFlags, x2, F_CF, 1);
UFLAG_DF(x2, d_none);
}
MARK2;
break;
case 2:
INST_NAME("RCL Ed, CL");
MESSAGE(LOG_DUMP, "Need Optimization\n");
READFLAGS(X_CF);
SETFLAGS(X_OF|X_CF, SF_SET);
AND_IMM8(x2, xECX, 0x1f);
wb = ed;
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
CALL_(rcl32, ed, (1<<x14));
SBACK(wb);
break;
case 3:
INST_NAME("RCR Ed, CL");
MESSAGE(LOG_DUMP, "Need Optimization\n");
READFLAGS(X_CF);
SETFLAGS(X_OF|X_CF, SF_SET);
AND_IMM8(x2, xECX, 0x1f);
wb = ed;
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
CALL_(rcr32, ed, (1<<x14));
SBACK(wb);
break;
case 4:
case 6:
INST_NAME("SHL Ed, CL");
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
AND_IMM8(x3, xECX, 0x1f);
GETEDO2(x14);
emit_shl32(dyn, ninst, ed, x3, x3, x14);
WBACK;
break;
case 5:
INST_NAME("SHR Ed, CL");
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
AND_IMM8(x3, xECX, 0x1f);
GETEDO2(x14);
emit_shr32(dyn, ninst, ed, x3, x3, x14);
WBACK;
break;
case 7:
INST_NAME("SAR Ed, CL");
SETFLAGS(X_ALL, SF_PENDING);
AND_IMM8(x3, xECX, 0x1f);
GETEDO2(x14);
UFLAG_OP12(ed, x3);
MOV_REG_ASR_REG(ed, ed, x3);
WBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_sar32);
break;
}
break;
case 0xE9:
case 0xEB:
INST_NAME("(ignored) GS:");
--addr;
break;
case 0xFF:
nextop = F8;
grab_tlsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH GS:Ed");
if((nextop&0xC0)==0xC0) { // reg
DEFAULT;
} else { // mem <= i32
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
DEFAULT;
}
break;
+229 -122
View File
@@ -20,6 +20,7 @@
#include "arm_printer.h"
#include "dynarec_arm_helper.h"
#include "dynarec_arm_functions.h"
uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
@@ -27,7 +28,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
uint8_t opcode = F8;
uint8_t nextop, u8;
uint32_t u32;
int32_t i32;
int32_t i32, j32;
int16_t i16;
uint16_t u16;
uint8_t gd, ed;
@@ -35,34 +36,35 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
int fixedaddress;
MAYUSE(u16);
MAYUSE(u8);
MAYUSE(j32);
while(opcode==0x66) opcode = F8; // "unlimited" 0x66 as prefix for variable sized NOP
if(opcode==0x2E) opcode = F8; // cs: is ignored
switch(opcode) {
case 0x01:
INST_NAME("ADD Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_add16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_add16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x03:
INST_NAME("ADD Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_add16(dyn, ninst, x1, x2, x3, x12, 0);
emit_add16(dyn, ninst, x1, x2, x3, x14, 0);
GWBACK;
break;
case 0x05:
INST_NAME("ADD AX, Iw");
SETFLAGS(X_ALL, SF_PENDING);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_add16c(dyn, ninst, x1, i32, x3, x12);
emit_add16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x06:
@@ -81,33 +83,33 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
STRH_IMM8(x2, x1, 0);
ADD_IMM8(xESP, xESP, 2);
MOVW(x1, 0);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, segs_clean[_ES]));
STR_IMM9(x1, xEmu, offsetof(x86emu_t, segs_serial[_ES]));
break;
case 0x09:
INST_NAME("OR Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_or16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_or16(dyn, ninst, x1, x2, x14, x2);
EWBACK;
break;
case 0x0B:
INST_NAME("OR Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_or16(dyn, ninst, x1, x2, x12, x3, 0);
emit_or16(dyn, ninst, x1, x2, x14, x3);
GWBACK;
break;
case 0x0D:
INST_NAME("OR AX, Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_or16c(dyn, ninst, x1, i32, x3, x12);
emit_or16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
@@ -117,88 +119,87 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x11:
INST_NAME("ADC Ew, Gw");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_adc16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_adc16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x13:
INST_NAME("ADC Gw, Ew");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_adc16(dyn, ninst, x1, x2, x12, x3, 0);
emit_adc16(dyn, ninst, x1, x2, x14, x3, 0);
GWBACK;
break;
case 0x15:
INST_NAME("ADC AX, Iw");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_adc16c(dyn, ninst, x1, i32, x3, x12);
emit_adc16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x19:
INST_NAME("SBB Ew, Gw");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_sbb16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_sbb16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x1B:
INST_NAME("SBB Gw, Ew");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_sbb16(dyn, ninst, x1, x2, x12, x3, 0);
emit_sbb16(dyn, ninst, x1, x2, x14, x3, 0);
GWBACK;
break;
case 0x1D:
INST_NAME("SBB AX, Iw");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
i32 = F16;
MOV32(x2, i32);
SETFLAGS(X_ALL, SF_SET_PENDING);
i16 = F16;
UXTH(x1, xEAX, 0);
emit_sbb16c(dyn, ninst, x1, i32, x3, x12);
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x21:
INST_NAME("AND Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_and16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_and16(dyn, ninst, x1, x2, x14, x2);
EWBACK;
break;
case 0x23:
INST_NAME("AND Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_and16(dyn, ninst, x1, x2, x3, x12, 0);
emit_and16(dyn, ninst, x1, x2, x3, x14);
GWBACK;
break;
case 0x25:
INST_NAME("AND AX, Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_and16c(dyn, ninst, x1, i32, x3, x12);
emit_and16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x26:
@@ -208,81 +209,81 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x29:
INST_NAME("SUB Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_sub16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_sub16(dyn, ninst, x1, x2, x14, x3, (wb1 && (wback==x3))?1:0);
EWBACK;
break;
case 0x2B:
INST_NAME("SUB Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_sub16(dyn, ninst, x1, x2, x3, x12, 0);
emit_sub16(dyn, ninst, x1, x2, x3, x14, 0);
GWBACK;
break;
case 0x2D:
INST_NAME("SUB AX, Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_sub16c(dyn, ninst, x1, i32, x3, x12);
emit_sub16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x31:
INST_NAME("XOR Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_xor16(dyn, ninst, x1, x2, x12, x3, (wb1 && (wback==x3))?1:0);
emit_xor16(dyn, ninst, x1, x2, x14, x2);
EWBACK;
break;
case 0x33:
INST_NAME("XOR Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_xor16(dyn, ninst, x1, x2, x3, x12, 0);
emit_xor16(dyn, ninst, x1, x2, x3, x14);
GWBACK;
break;
case 0x35:
INST_NAME("XOR AX, Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
UXTH(x1, xEAX, 0);
emit_xor16c(dyn, ninst, x1, i32, x3, x12);
emit_xor16c(dyn, ninst, x1, i32, x3, x14);
BFI(xEAX, x1, 0, 16);
break;
case 0x39:
INST_NAME("CMP Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x2);
GETEW(x1);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x3B:
INST_NAME("CMP Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETGW(x1);
GETEW(x2);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x3D:
INST_NAME("CMP AX, Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
i32 = F16;
MOVW(x2, i32);
UXTH(x1, xEAX, 0);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x40:
@@ -297,7 +298,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
gd = xEAX+(opcode&7);
UXTH(x1, gd, 0);
emit_inc16(dyn, ninst, x1, x3, x12);
emit_inc16(dyn, ninst, x1, x3, x14);
BFI(gd, x1, 0, 16);
break;
case 0x48:
@@ -312,7 +313,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
gd = xEAX+(opcode&7);
UXTH(x1, gd, 0);
emit_dec16(dyn, ninst, x1, x3, x12);
emit_dec16(dyn, ninst, x1, x3, x14);
BFI(gd, x1, 0, 16);
break;
case 0x50:
@@ -324,8 +325,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x56:
case 0x57:
INST_NAME("PUSH Reg16");
SUB_IMM8(xESP, xESP, 2);
STRH_IMM8(xEAX+(opcode&7), xESP, 0); //TODO: use a single STRH pre-decrement instruction
PUSH16(xEAX+(opcode&7), xESP);
break;
case 0x58:
case 0x59:
@@ -336,17 +336,45 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x5E:
case 0x5F:
INST_NAME("POP Reg16");
LDRH_IMM8(x1, xESP, 0); //TODO: use a single LDRH post-increment instruction
POP16(x1, xESP);
BFI(xEAX+(opcode&7), x1, 0, 16);
ADD_IMM8(xESP, xESP, 2);
break;
case 0x60:
INST_NAME("PUSHA");
MOV_REG(x1, xESP);
PUSH16(xEAX, xESP);
PUSH16(xECX, xESP);
PUSH16(xEDX, xESP);
PUSH16(xEBX, xESP);
PUSH16(x1, xESP);
PUSH16(xEBP, xESP);
PUSH16(xESI, xESP);
PUSH16(xEDI, xESP);
break;
case 0x61:
INST_NAME("POPA");
POP16(x1, xESP);
BFI(xEDI, x1, 0, 16);
POP16(x1, xESP);
BFI(xESI, x1, 0, 16);
POP16(x1, xESP);
BFI(xEBP, x1, 0, 16);
ADD_IMM8(xESP, xESP, 2); //POP16(xESP, xESP);
POP16(x1, xESP);
BFI(xEBX, x1, 0, 16);
POP16(x1, xESP);
BFI(xEDX, x1, 0, 16);
POP16(x1, xESP);
BFI(xECX, x1, 0, 16);
POP16(x1, xESP);
BFI(xEAX, x1, 0, 16);
break;
case 0x68:
INST_NAME("PUSH Iw");
u16 = F16;
MOVW(x2, u16);
SUB_IMM8(xESP, xESP, 2);
STRH_IMM8(x2, xESP, 0);
PUSH16(x2, xESP);
break;
case 0x69:
INST_NAME("IMUL Gw,Ew,Iw");
@@ -364,8 +392,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("PUSH Ib");
i16 = F8S;
MOVW(x2, i16);
SUB_IMM8(xESP, xESP, 2);
STRH_IMM8(x2, xESP, 0);
PUSH16(x2, xESP);
break;
case 0x6B:
INST_NAME("IMUL Gw,Ew,Ib");
@@ -390,83 +417,114 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
} else {
INST_NAME("ADD Ew, Ib");
}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_add16c(dyn, ninst, ed, i16, x2, x12);
emit_add16c(dyn, ninst, ed, i16, x2, x14);
EWBACK;
break;
case 1: //OR
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_or16c(dyn, ninst, x1, i16, x2, x12);
emit_or16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 2: //ADC
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_adc16c(dyn, ninst, x1, i16, x2, x12);
emit_adc16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 3: //SBB
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_sbb16c(dyn, ninst, x1, i16, x2, x12);
emit_sbb16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 4: //AND
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_and16c(dyn, ninst, x1, i16, x2, x12);
emit_and16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 5: //SUB
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_sub16c(dyn, ninst, x1, i16, x2, x12);
emit_sub16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 6: //XOR
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
emit_xor16c(dyn, ninst, x1, i16, x2, x12);
emit_xor16c(dyn, ninst, x1, i16, x2, x14);
EWBACK;
break;
case 7: //CMP
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(i16) {
MOVW(x2, i16);
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
} else
emit_cmp16_0(dyn, ninst, x1, x3, x12);
emit_cmp16_0(dyn, ninst, x1, x3, x14);
break;
}
break;
case 0x85:
INST_NAME("TEST Ew, Gw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
nextop = F8;
GETEW(x1);
GETGW(x2);
emit_test16(dyn, ninst, x1, x2, x3, x12);
emit_test16(dyn, ninst, x1, x2, x3, x14);
break;
case 0x87:
INST_NAME("XCHG Ew, Gw");
nextop = F8;
if((nextop&0xC0)==0xC0) {
GETGD;
UXTH(x14, gd, 0);
ed = xEAX + (nextop&7);
UXTH(x1, ed, 0);
// do the swap 14 -> ed, 1 -> gd
BFI(gd, x1, 0, 16);
BFI(ed, x14, 0, 16);
} else {
GETGD;
UXTH(x14, gd, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
#if 0
MARKLOCK;
// do the swap with exclusive locking
LDREXH(x1, ed);
// do the swap 14 -> strb(ed), 1 -> gd
STREXH(x3, x14, ed);
CMPS_IMM8(x3, 0);
B_MARKLOCK(cNE);
#else
LDRH_IMM8(x1, ed, fixedaddress);
STRH_IMM8(x14, ed, fixedaddress);
#endif
BFI(gd, x1, 0, 16);
}
break;
case 0x89:
@@ -479,7 +537,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
BFI(ed, gd, 0, 16);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
STRH_IMM8(gd, ed, fixedaddress);
}
break;
@@ -493,7 +551,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
BFI(gd, ed, 0, 16);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
LDRH_IMM8(x1, ed, fixedaddress);
BFI(gd, x1, 0, 16);
}
@@ -501,13 +559,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0x8C:
INST_NAME("MOV Ew,Seg");
nextop = F8;
MOV32(x2, offsetof(x86emu_t, segs[(nextop&38)>>3]));
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
LDRH_REG(x1, xEmu, x2);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
BFI(ed, x1, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
STRH_IMM8(x1, ed, fixedaddress);
}
break;
@@ -517,16 +575,16 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
nextop = F8;
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
MOV32(x2, offsetof(x86emu_t, segs[(nextop&38)>>3]));
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
STRH_REG(ed, xEmu, x2);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
LDRH_IMM8(x1, ed, fixedaddress);
MOV32(x2, offsetof(x86emu_t, segs[(nextop&38)>>3]));
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
STRH_REG(x1, xEmu, x2);
}
MOVW(x1, 0);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, segs_clean[(nextop&38)>>3]));
STR_IMM9(x1, xEmu, offsetof(x86emu_t, segs_serial[(nextop&0x38)>>3]));
break;
case 0x90:
@@ -545,12 +603,33 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
BFI(xEAX, gd, 0, 16);
BFI(gd, x2, 0, 16);
break;
case 0x98:
INST_NAME("CBW");
SXTB(x1, xEAX, 0);
BFI(xEAX, x1, 0, 16);
break;
case 0x99:
INST_NAME("CWD");
SXTH(x1, xEAX, 0);
MOV_REG_LSR_IMM5(x1, x1, 16);
BFI(xEDX, x1, 0, 16);
break;
case 0x9C:
INST_NAME("PUSHF (16b)");
READFLAGS(X_ALL);
STRHB_IMM8(xFlags, xESP, -2);
break;
case 0x9D:
INST_NAME("POPF (16b)");
SETFLAGS(X_ALL, SF_SET); // lower 16bits is all flags handled in dynarec
LDRHA_IMM8(x2, xESP, 2);
MOV32(x1, 0x7FD7);
AND_REG_LSL_IMM5(x2, x2, x1, 0);
ORR_IMM8(x2, x2, 2, 0);
BFI(xFlags, x2, 0, 16);
SET_DFNONE(x1);
break;
case 0xA1:
INST_NAME("MOV, AX, Od");
@@ -573,20 +652,20 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xA7:
INST_NAME("CMPSW");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETDIR(x3, 2);
LDRHAI_REG_LSL_IMM5(x1, xESI, x3);
LDRHAI_REG_LSL_IMM5(x2, xEDI, x3);
CALL(cmp16, -1, 0);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0xA9:
INST_NAME("TEST AX,Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
u16 = F16;
MOVW(x2, u16);
UBFX(x1, xEAX, 0, 16);
emit_test16(dyn, ninst, x1, x2, x3, x12);
emit_test16(dyn, ninst, x1, x2, x3, x14);
break;
case 0xAB:
@@ -605,7 +684,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
GETDIR(x3, 2);
UXTH(x1, xEAX, 0);
LDRHAI_REG_LSL_IMM5(x2, xEDI, x3);
CALL(cmp16, -1, 0);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0xB8:
@@ -712,7 +791,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MOVW(x1, u16);
BFI(ed, x1, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
u16 = F16;
MOVW(x1, u16);
STRH_IMM8(x1, ed, fixedaddress);
@@ -771,15 +850,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 6:
if(opcode==0xD1) {
INST_NAME("SHL Ew, 1");
MOVW(x12, 1);
MOVW(x14, 1);
} else {
INST_NAME("SHL Ew, CL");
AND_IMM8(x12, xECX, 0x1f);
AND_IMM8(x14, xECX, 0x1f);
}
SETFLAGS(X_ALL, SF_PENDING);
GETEW(x1);
UFLAG_OP12(ed, x12)
MOV_REG_LSL_REG(ed, ed, x12);
UFLAG_OP12(ed, x14)
MOV_REG_LSL_REG(ed, ed, x14);
EWBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_shl16);
@@ -787,15 +866,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 5:
if(opcode==0xD1) {
INST_NAME("SHR Ew, 1");
MOVW(x12, 1);
MOVW(x14, 1);
} else {
INST_NAME("SHR Ew, CL");
AND_IMM8(x12, xECX, 0x1f);
AND_IMM8(x14, xECX, 0x1f);
}
SETFLAGS(X_ALL, SF_PENDING);
GETEW(x1);
UFLAG_OP12(ed, x12)
MOV_REG_LSR_REG(ed, ed, x12);
UFLAG_OP12(ed, x14)
MOV_REG_LSR_REG(ed, ed, x14);
EWBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_shr16);
@@ -803,15 +882,15 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 7:
if(opcode==0xD1) {
INST_NAME("SAR Ew, 1");
MOVW(x12, 1);
MOVW(x14, 1);
} else {
INST_NAME("SAR Ew, CL");
AND_IMM8(x12, xECX, 0x1f);
AND_IMM8(x14, xECX, 0x1f);
}
SETFLAGS(X_ALL, SF_PENDING);
GETSEW(x1);
UFLAG_OP12(ed, x12)
MOV_REG_ASR_REG(ed, ed, x12);
UFLAG_OP12(ed, x14)
MOV_REG_ASR_REG(ed, ed, x14);
EWBACK;
UFLAG_RES(ed);
UFLAG_DF(x3, d_sar16);
@@ -869,7 +948,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MARK2;
SUB_IMM8(xECX, xECX, 1);
MARK3;
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
case 0xAB:
@@ -905,7 +984,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MARK2;
SUB_IMM8(xECX, xECX, 1);
MARK3;
emit_cmp16(dyn, ninst, x1, x2, x3, x12);
emit_cmp16(dyn, ninst, x1, x2, x3, x14);
break;
default:
DEFAULT;
@@ -918,11 +997,11 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0:
case 1:
INST_NAME("TEST Ew, Iw");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
u16 = F16;
MOVW(x2, u16);
emit_test16(dyn, ninst, x1, x2, x3, x12);
emit_test16(dyn, ninst, x1, x2, x3, x14);
break;
case 2:
INST_NAME("NOT Ew");
@@ -932,13 +1011,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 3:
INST_NAME("NEG Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_PENDING);
GETEW(x1);
emit_neg16(dyn, ninst, ed, x2, x12);
emit_neg16(dyn, ninst, ed, x2, x14);
EWBACK;
break;
case 4:
INST_NAME("MUL AX, Ew");
MESSAGE(LOG_DUMP, "Need Optimization\n");
SETFLAGS(X_ALL, SF_PENDING);
GETEW(x1);
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
@@ -958,14 +1038,27 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 6:
INST_NAME("DIV Ew");
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
CALL(div16, -1, 0);
LDM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
if(arm_div) {
GETEW(x1);
SETFLAGS(X_ALL, SF_SET);
UXTH(x2, xEAX, 0);
ORR_REG_LSL_IMM5(x2, x2, xEDX, 16);
UDIV(x3, x2, ed);
MLS(x14, x3, ed, x2); // x14 = x2 mod ed (i.e. x2 - x3*ed)
BFI(xEAX, x3, 1, 16);
BFI(xEDX, x14, 1, 16);
} else {
MESSAGE(LOG_DUMP, "Need Optimization\n");
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
CALL(div16, -1, 0);
LDM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
}
break;
case 7:
INST_NAME("IDIV Ew");
MESSAGE(LOG_DUMP, "Need Optimization\n");
SETFLAGS(X_ALL, SF_SET);
GETEW(x1);
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
@@ -974,6 +1067,20 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
}
break;
case 0xF8:
INST_NAME("CLC");
SETFLAGS(X_CF, SF_SUBSET);
SET_DFNONE(x1);
BFC(xFlags, F_CF, 1);
break;
case 0xF9:
INST_NAME("STC");
SETFLAGS(X_CF, SF_SUBSET);
SET_DFNONE(x1);
MOVW(x1, 1);
BFI(xFlags, x1, F_CF, 1);
break;
case 0xFF:
nextop = F8;
switch((nextop>>3)&7) {
@@ -981,14 +1088,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
INST_NAME("INC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEW(x1);
emit_inc16(dyn, ninst, x1, x2, x12);
emit_inc16(dyn, ninst, x1, x2, x14);
EWBACK;
break;
case 1:
INST_NAME("DEC Ew");
SETFLAGS(X_ALL&~X_CF, SF_SET);
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
GETEW(x1);
emit_dec16(dyn, ninst, x1, x2, x12);
emit_dec16(dyn, ninst, x1, x2, x14);
EWBACK;
break;
default:
File diff suppressed because it is too large. Load diff
+109 -11
View File
@@ -21,26 +21,126 @@
#include "dynarec_arm_helper.h"
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop;
uint8_t nextop, opcode;
int8_t i8;
int32_t i32;
int32_t i32, j32;
uint32_t u32;
uint8_t gd, ed;
int fixedaddress;
MAYUSE(i32);
MAYUSE(j32);
nextop = F8;
switch(nextop) {
#define GO(NO, YES) \
BARRIER(2); \
JUMP(addr+i8);\
case 0x64:
// reduced EA size...
opcode = F8;
switch(opcode) {
case 0x89:
INST_NAME("MOV FS:Ew16, Gw");
nextop = F8;
grab_fsdata(dyn, addr, ninst, x14);
GETGD; // don't need GETGW here
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
if(ed!=gd) {
BFI(ed, gd, 0, 16);
}
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
STRH_REG(gd, x14, ed);
}
break;
case 0x8B:
INST_NAME("MOV Gd, FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x14);
GETGD;
if((nextop&0xC0)==0xC0) { // reg <= reg
ed = xEAX+(nextop&7);
if(ed!=gd) {
BFI(gd, ed, 0, 16);
}
} else { // mem <= reg
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(gd, x14, ed, 0);
}
break;
case 0x8F:
INST_NAME("POP FS:Ew16");
nextop=F8;
grab_fsdata(dyn, addr, ninst, x14);
if((nextop&0xC0)==0xC0) {
POP1(xEAX+(nextop&7)); // 67 ignored
} else {
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
POP1(x2);
STR_REG_LSL_IMM5(x2, x14, ed, 0);
}
break;
case 0xA1:
INST_NAME("MOV EAX, FS:Ow");
grab_fsdata(dyn, addr, ninst, x1);
u32 = F16;
if(u32) {
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
}
LDR_IMM9(xEAX, x1, 0);
break;
case 0xA3:
INST_NAME("MOV FS:Ow, EAX");
grab_fsdata(dyn, addr, ninst, x1);
u32 = F16;
if(u32) {
MOV32(x2, u32);
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
}
STR_IMM9(xEAX, x1, 0);
break;
case 0xFF:
nextop = F8;
grab_fsdata(dyn, addr, ninst, x14);
switch((nextop>>3)&7) {
case 6: // Push Ed
INST_NAME("PUSH FS:Ew");
if((nextop&0xC0)==0xC0) { // reg
DEFAULT;
} else { // mem <= i32
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
PUSH1(x3);
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
break;
#define GO(NO, YES) \
BARRIER(2); \
JUMP(addr+i8, 1); \
if(dyn->insts) { \
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
/* out of the block */ \
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
Bcond(NO, i32); \
jump_to_linker(dyn, addr+i8, 0, ninst); \
jump_to_next(dyn, addr+i8, 0, ninst); \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
@@ -55,8 +155,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SUBS_IMM8(x1, x1, 1);
BFI(xECX, x1, 0, 16);
B_NEXT(cEQ); // CX is 0, no LOOP
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_ZF);
GO(cNE, cEQ);
break;
case 0xE1:
@@ -67,8 +166,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
SUBS_IMM8(x1, x1, 1);
BFI(xECX, x1, 0, 16);
B_NEXT(cEQ); // CX is 0, no LOOP
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
TSTS_IMM8(xFlags, 1<<F_ZF);
GO(cEQ, cNE);
break;
case 0xE2:
+122 -58
View File
@@ -50,9 +50,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FADD ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VADD_F64(v1, v1, v2);
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)) {
VADD_F32(v1, v1, v2);
} else {
VADD_F64(v1, v1, v2);
}
break;
case 0xC8:
case 0xC9:
@@ -63,9 +67,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCE:
case 0xCF:
INST_NAME("FMUL ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMUL_F64(v1, v1, v2);
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)) {
VMUL_F32(v1, v1, v2);
} else {
VMUL_F64(v1, v1, v2);
}
break;
case 0xD0:
case 0xD1:
@@ -76,9 +84,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD6:
case 0xD7:
INST_NAME("FCOM ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
break;
case 0xD8:
@@ -90,11 +102,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDE:
case 0xDF:
INST_NAME("FCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
@@ -105,9 +121,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE6:
case 0xE7:
INST_NAME("FSUB ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v1, v1, v2);
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)) {
VSUB_F32(v1, v1, v2);
} else {
VSUB_F64(v1, v1, v2);
}
break;
case 0xE8:
case 0xE9:
@@ -118,9 +138,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEE:
case 0xEF:
INST_NAME("FSUBR ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v1, v2, v1);
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)) {
VSUB_F32(v1, v2, v1);
} else {
VSUB_F64(v1, v2, v1);
}
break;
case 0xF0:
case 0xF1:
@@ -131,9 +155,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF6:
case 0xF7:
INST_NAME("FDIV ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v1, v1, v2);
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)) {
VDIV_F32(v1, v1, v2);
} else {
VDIV_F64(v1, v1, v2);
}
break;
case 0xF8:
case 0xF9:
@@ -144,143 +172,179 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFE:
case 0xFF:
INST_NAME("FDIVR ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v1, v2, v1);
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)) {
VDIV_F32(v1, v2, v1);
} else {
VDIV_F64(v1, v2, v1);
}
break;
default:
switch((nextop>>3)&7) {
case 0:
INST_NAME("FADD ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VADD_F64(v1, v1, d1);
if(ST_IS_F(0)) {
VADD_F32(v1, v1, s0);
} else {
VCVT_F64_F32(d1, s0);
VADD_F64(v1, v1, d1);
}
break;
case 1:
INST_NAME("FMUL ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VMUL_F64(v1, v1, d1);
if(ST_IS_F(0)) {
VMUL_F32(v1, v1, s0);
} else {
VCVT_F64_F32(d1, s0);
VMUL_F64(v1, v1, d1);
}
break;
case 2:
INST_NAME("FCOM ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
if(ST_IS_F(0)) {
VCMP_F32(v1, s0);
} else {
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
}
FCOM(x1, x2);
break;
case 3:
INST_NAME("FCOMP ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
if(ST_IS_F(0)) {
VCMP_F32(v1, s0);
} else {
VCVT_F64_F32(d1, s0);
VCMP_F64(v1, d1);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FSUB ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VSUB_F64(v1, v1, d1);
if(ST_IS_F(0)) {
VSUB_F32(v1, v1, s0);
} else {
VCVT_F64_F32(d1, s0);
VSUB_F64(v1, v1, d1);
}
break;
case 5:
INST_NAME("FSUBR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VSUB_F64(v1, d1, v1);
if(ST_IS_F(0)) {
VSUB_F32(v1, s0, v1);
} else {
VCVT_F64_F32(d1, s0);
VSUB_F64(v1, d1, v1);
}
break;
case 6:
INST_NAME("FDIV ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VDIV_F64(v1, v1, d1);
if(ST_IS_F(0)) {
VDIV_F32(v1, v1, s0);
} else {
VCVT_F64_F32(d1, s0);
VDIV_F64(v1, v1, d1);
}
break;
case 7:
INST_NAME("FDIVR ST0, float[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
s0 = fpu_get_scratch_single(dyn);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
VMOVtoV(s0, ed);
}
VCVT_F64_F32(d1, s0);
VDIV_F64(v1, d1, v1);
if(ST_IS_F(0)) {
VDIV_F32(v1, s0, v1);
} else {
VCVT_F64_F32(d1, s0);
VDIV_F64(v1, d1, v1);
}
break;
default:
DEFAULT;
+304 -90
View File
@@ -23,13 +23,16 @@
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
static double d_1 = 1.0;
static double d_l2t = L2T;
static double d_l2e = L2E;
static double d_pi = PI;
static double d_lg2 = LG2;
static double d_ln2 = LN2;
static double d_0 = 0.0;
static const double d_l2t = L2T;
static const double d_l2e = L2E;
static const double d_pi = PI;
static const double d_lg2 = LG2;
static const double d_ln2 = LN2;
static const float f_l2t = L2T;
static const float f_l2e = L2E;
static const float f_pi = PI;
static const float f_lg2 = LG2;
static const float f_ln2 = LN2;
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
@@ -40,11 +43,13 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
int v1, v2;
int s0;
int i1, i2, i3;
int j32;
int parity;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(j32);
switch(nextop) {
@@ -57,9 +62,13 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FLD STx");
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
v2 = x87_do_push(dyn, ninst);
VMOV_64(v2, v1);
v2 = x87_do_push(dyn, ninst, x3, X87_ST(nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
if(ST_IS_F(0)) {
VMOV_32(v2, v1);
} else {
VMOV_64(v2, v1);
}
break;
case 0xC8:
@@ -72,11 +81,17 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCF:
INST_NAME("FXCH STx");
// swap the cache value, not the double value itself :p
i1 = x87_get_cache(dyn, ninst, x1, x2, nextop&7);
i2 = x87_get_cache(dyn, ninst, x1, x2, 0);
i1 = x87_get_cache(dyn, ninst, 1, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
i3 = dyn->x87cache[i1];
dyn->x87cache[i1] = dyn->x87cache[i2];
dyn->x87cache[i2] = i3;
// swap those too
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
i3 = dyn->n.neoncache[i1].v;
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
dyn->n.neoncache[i2].v = i3;
break;
case 0xD0:
@@ -85,78 +100,184 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE0:
INST_NAME("FCHS");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
VNEG_F64(v1, v1);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
VNEG_F32(v1, v1);
} else {
VNEG_F64(v1, v1);
}
break;
case 0xE1:
INST_NAME("FABS");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
VABS_F64(v1, v1);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
VABS_F32(v1, v1);
} else {
VABS_F64(v1, v1);
}
break;
case 0xE4:
INST_NAME("FTST");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
VCMP_F64_0(v1);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
VCMP_F32_0(v1);
} else {
VCMP_F64_0(v1);
}
FCOM(x1, x2); // same flags...
break;
case 0xE5:
INST_NAME("FXAM");
#if 1
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
// value put in x14
if(i1==-1) {
// not in cache, so check Empty status and load it
// x14 will be the actual top
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
i2 = -dyn->x87stack;
if(i2) {
if(i2<0) {
SUB_IMM8(x14, x14, -i2);
} else {
ADD_IMM8(x14, x14, i2);
}
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
}
ADD_REG_LSL_IMM5(x1, xEmu, x14, 3);
LDRD_IMM8(x2, x1, offsetof(x86emu_t, x87)); // load r2/r3 with ST0 anyway, for sign extraction
ADD_REG_LSL_IMM5(x1, xEmu, x14, 2);
LDR_IMM9(x1, x1, offsetof(x86emu_t, p_regs));
CMPS_IMM8(x1, 0b11);
MOVW_COND(cEQ, x14, 0b100000100000000); // empty: C3,C2,C0 = 101
B_MARK3(cEQ);
} else {
// simply move from cache reg to r2/r3
v1 = dyn->x87reg[i1];
VMOVfrV_D(x2, x3, v1);
}
// get exponant in r1
MOV_REG_LSR_IMM5(x1, x3, 20);
MOVW(x14, 0x7ff);
ANDS_REG_LSL_IMM5(x1, x1, x14, 0);
B_MARK(cNE); // not zero or denormal
BIC_IMM8_ROR(x1, x3, 0b10, 1); // remove sign bit
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
MOVW_COND(cEQ, x14, 0b100000000000000); // Zero: C3,C2,C0 = 100
MOVW_COND(cNE, x14, 0b100010000000000); // Denormal: C3,C2,C0 = 110
B_MARK3(c__);
MARK;
CMPS_REG_LSL_IMM5(x1, x14, 0); // infinite/NaN?
MOVW_COND(cNE, x14, 0b000010000000000); // normal: C3,C2,C0 = 010
B_MARK3(cNE);
ORR_IMM8(x1, x1, 0x08, 12); //prepare mask, 0x7ff | 0x800 => 0xfff
BIC_REG_LSL_IMM5(x1, x3, x1, 20);
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
MOVW_COND(cEQ, x14, 0b000010100000000); // infinity: C3,C2,C0 = 011
MOVW_COND(cNE, x14, 0b000000100000000); // NaN: C3,C2,C0 = 001
MARK3;
// Extract signa & Update SW
MOV_REG_LSR_IMM5(x1, x3, 31);
BFI(x14, x1, 9, 1); //C1
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
BIC_IMM8(x1, x1, 0b01000111, 12);
ORR_REG_LSL_IMM5(x14, x14, x1, 0);
STRH_IMM8(x14, xEmu, offsetof(x86emu_t, sw));
#else
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_refresh(dyn, ninst, x1, x2, 0);
CALL(fpu_fxam, -1, 0); // should be possible inline, but is it worth it?
#endif
break;
case 0xE8:
INST_NAME("FLD1");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_1));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
VMOV_i_32(v1, 0b01110000);
} else {
VMOV_i_64(v1, 0b01110000);
}
break;
case 0xE9:
INST_NAME("FLDL2T");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_l2t));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
MOV32(x2, (&f_l2t));
VLDR_32(v1, x2, 0);
} else {
MOV32(x2, (&d_l2t));
VLDR_64(v1, x2, 0);
}
break;
case 0xEA:
INST_NAME("FLDL2E");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_l2e));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
MOV32(x2, (&f_l2e));
VLDR_32(v1, x2, 0);
} else {
MOV32(x2, (&d_l2e));
VLDR_64(v1, x2, 0);
}
break;
case 0xEB:
INST_NAME("FLDPI");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_pi));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
MOV32(x2, (&f_pi));
VLDR_32(v1, x2, 0);
} else {
MOV32(x2, (&d_pi));
VLDR_64(v1, x2, 0);
}
break;
case 0xEC:
INST_NAME("FLDLG2");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_lg2));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
MOV32(x2, (&f_lg2));
VLDR_32(v1, x2, 0);
} else {
MOV32(x2, (&d_lg2));
VLDR_64(v1, x2, 0);
}
break;
case 0xED:
INST_NAME("FLDLN2");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_ln2));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
MOV32(x2, (&f_ln2));
VLDR_32(v1, x2, 0);
} else {
MOV32(x2, (&d_ln2));
VLDR_64(v1, x2, 0);
}
break;
case 0xEE:
INST_NAME("FLDZ");
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_0));
VLDR_64(v1, x2, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0)) {
VMOV_8(v1/2, 0); // float is *2...
} else {
VMOV_8(v1, 0); // cannot use VMOV_i_F64
}
break;
case 0xFA:
INST_NAME("FSQRT");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
VSQRT_F64(v1, v1);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
if(ST_IS_F(0)) {
VSQRT_F32(v1, v1);
} else {
VSQRT_F64(v1, v1);
}
break;
case 0xFC:
INST_NAME("FRNDINT");
MESSAGE(LOG_DUMP, "Need Optimization\n");
// use C helper for now, nothing staightforward is available
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_frndint, -1, 0);
@@ -174,71 +295,142 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 0xF0:
INST_NAME("F2XM1");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_f2xm1, -1, 0);
break;
case 0xF1:
INST_NAME("FYL2X");
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fyl2x, -1, 0);
x87_do_pop(dyn, ninst);
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);
VMOV_64(0, v1); // prepare call to log2
CALL_1D(log2, 0);
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d)*ST(1).d
x87_do_pop(dyn, ninst, x3);
break;
case 0xF2:
INST_NAME("FTAN");
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_ftan, -1, 0);
v1 = x87_do_push(dyn, ninst);
MOV32(x2, (&d_1));
VLDR_64(v1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
VMOV_64(0, v1); // prepare call to tan
CALL_1D(tan, 0);
VMOV_64(v1, 0);
//emu->sw.f.F87_C2 = 0;
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
BFC(x1, 10, 1); //C2 = 0
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
// and want 1.0 = 0x3ff0000000000000
// so 00111111 11110000 00000000 00000000....
// a = 0, b = 1, c = 1, d = 1, efgh=0
// 0b01110000
VMOV_i_64(v2, 0b01110000);
break;
case 0xF3:
INST_NAME("FPATAN");
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fpatan, -1, 0);
x87_do_pop(dyn, ninst);
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);
VMOV_64(0, v2); // prepare call to atan2
VMOV_64(1, v1);
CALL_2D(atan2, 0);
VMOV_64(v2, 0); //ST(1).d = atan2(ST1.d, ST0.d);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF4:
INST_NAME("FXTRACT");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_do_push_empty(dyn, ninst, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fxtract, -1, 0);
break;
case 0xF5:
INST_NAME("FPREM1");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fprem1, -1, 0);
break;
case 0xF6:
INST_NAME("FDECSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
SUB_IMM8(x2, x2, 1);
AND_IMM8(x2, x2, 7);
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
break;
case 0xF7:
INST_NAME("FINCSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
ADD_IMM8(x2, x2, 1);
AND_IMM8(x2, x2, 7);
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
break;
case 0xF8:
INST_NAME("FPREM");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fprem, -1, 0);
break;
case 0xF9:
INST_NAME("FYL2XP1");
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fyl2xp1, -1, 0);
x87_do_pop(dyn, ninst);
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);
VMOV_i_64(0, 0b01110000); // D0 = 1.0
VADD_F64(0, 0, v1); // prepare call to log2
CALL_1D(log2, 0);
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
x87_do_pop(dyn, ninst, x3);
break;
case 0xFB:
INST_NAME("FSINCOS");
x87_do_push_empty(dyn, ninst, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fsincos, -1, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
VMOV_64(0, v1);
CALL_1D(sin, 0);
VSWP(v1, 0);
CALL_1D(cos, 0);
VMOV_64(v2, 0);
//emu->sw.f.F87_C2 = 0;
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
BFC(x1, 10, 1); //C2 = 0
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
break;
case 0xFD:
INST_NAME("FSCALE");
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(arm_fscale, -1, 0);
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);
//if(ST0.d!=0.0)
// ST0.d *= exp2(trunc(ST1.d));
VCMP_F64_0(v1);
VMRS_APSR();
B_NEXT(cEQ);
VMOV_64(0, v2);
CALL_1DD(trunc, exp2, 0);
VMUL_F64(v1, v1, 0);
break;
case 0xFE:
INST_NAME("FSIN");
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_fsin, -1, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
VMOV_64(0, v1); // prepare call to sin
CALL_1D(sin, 0);
VMOV_64(v1, 0);
//emu->sw.f.F87_C2 = 0;
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
BFC(x1, 10, 1); //C2 = 0
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
break;
case 0xFF:
INST_NAME("FCOS");
x87_forget(dyn, ninst, x1, x2, 0);
CALL(arm_fcos, -1, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
VMOV_64(0, v1); // prepare call to cos
CALL_1D(cos, 0);
VMOV_64(v1, 0);
//emu->sw.f.F87_C2 = 0;
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
BFC(x1, 10, 1); //C2 = 0
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
break;
@@ -260,9 +452,6 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE6:
case 0xE7:
case 0xEF:
case 0xF5:
case 0xF6:
case 0xF7:
DEFAULT;
break;
@@ -270,54 +459,68 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD ST0, float[ED]");
v1 = x87_do_push(dyn, ninst);
s0 = fpu_get_scratch_single(dyn);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else
s0 = fpu_get_scratch_single(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
LDR_IMM9(x2, ed, fixedaddress);
VMOVtoV(s0, x2);
}
VCVT_F64_F32(v1, s0);
if(!ST_IS_F(0)) {
VCVT_F64_F32(v1, s0);
}
break;
case 2:
INST_NAME("FST float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, v1);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else {
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, v1);
}
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VSTR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
}
break;
case 3:
INST_NAME("FSTP float[ED], ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, v1);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
if(ST_IS_F(0))
s0 = v1;
else {
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, v1);
}
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VSTR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
VMOVfrV(x2, s0);
STR_IMM9(x2, ed, fixedaddress);
}
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FLDENV Ed");
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {
MOV_REG(x1, ed);
}
@@ -331,9 +534,20 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
UBFX(x1, x1, 10, 2); // extract round
STR_IMM9(x1, xEmu, offsetof(x86emu_t, round));
break;
case 6:
INST_NAME("FNSTENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {
MOV_REG(x1, ed);
}
MOVW(x2, 0);
CALL(fpu_savenv, -1, 0);
break;
case 7:
INST_NAME("FNSTCW Ew");
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
ed = x1;
wb1 = 1;
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw));
+52 -37
View File
@@ -26,7 +26,7 @@
uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t nextop = F8;
int32_t i32;
int32_t j32;
uint8_t ed;
uint8_t wback;
int v1, v2;
@@ -39,7 +39,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(ed);
MAYUSE(i32);
MAYUSE(j32);
switch(nextop) {
case 0xC0:
@@ -52,11 +52,14 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("FCMOVB ST0, STx");
READFLAGS(X_CF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cNE, v1, v2); // F_CF==1
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));
TSTS_IMM8(xFlags, 1<<F_CF);
if(ST_IS_F(0)) {
VMOVcond_32(cNE, v1, v2); // F_CF==1
} else {
VMOVcond_64(cNE, v1, v2); // F_CF==1
}
break;
case 0xC8:
case 0xC9:
@@ -68,11 +71,14 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCF:
INST_NAME("FCMOVE ST0, STx");
READFLAGS(X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cNE, v1, v2); // F_ZF==1
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));
TSTS_IMM8(xFlags, 1<<F_ZF);
if(ST_IS_F(0)) {
VMOVcond_32(cNE, v1, v2); // F_ZF==1
} else {
VMOVcond_64(cNE, v1, v2); // F_ZF==1
}
break;
case 0xD0:
case 0xD1:
@@ -84,12 +90,14 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD7:
INST_NAME("FCMOVBE ST0, STx");
READFLAGS(X_CF|X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
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));
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
if(ST_IS_F(0)) {
VMOVcond_32(cNE, v1, v2); // F_CF==1 | F_ZF==1
} else {
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
}
break;
case 0xD8:
case 0xD9:
@@ -101,20 +109,27 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDF:
INST_NAME("FCMOVU ST0, STx");
READFLAGS(X_PF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cNE, v1, v2); // F_PF==1
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));
TSTS_IMM8(xFlags, 1<<F_PF);
if(ST_IS_F(0)) {
VMOVcond_32(cNE, v1, v2); // F_PF==1
} else {
VMOVcond_64(cNE, v1, v2); // F_PF==1
}
break;
case 0xE9:
INST_NAME("FUCOMPP ST0, ST1");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
VCMP_F64(v1, v2);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, 1, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE4:
@@ -134,7 +149,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FIADD ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -144,7 +159,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 1:
INST_NAME("FIMUL ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -154,7 +169,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 2:
INST_NAME("FICOM ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -165,7 +180,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 3:
INST_NAME("FICOMP ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -173,11 +188,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
VCVT_F64_S32(d0, s0);
VCMP_F64(v1, d0);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FISUB ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -187,7 +202,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 5:
INST_NAME("FISUBR ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -197,7 +212,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 6:
INST_NAME("FIDIV ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
@@ -207,7 +222,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 7:
INST_NAME("FIDIVR ST0, Ed");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
GETED;
d0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
+93 -54
View File
@@ -26,7 +26,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
{
uint8_t nextop = F8;
uint8_t u8;
int32_t i32;
int32_t j32;
uint8_t ed;
uint8_t wback;
int v1, v2;
@@ -37,7 +37,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
MAYUSE(s0);
MAYUSE(v1);
MAYUSE(v2);
MAYUSE(i32);
MAYUSE(j32);
switch(nextop) {
case 0xC0:
@@ -50,11 +50,14 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC7:
INST_NAME("FCMOVNB ST0, STx");
READFLAGS(X_CF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cEQ, v1, v2); // F_CF==0
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));
TSTS_IMM8(xFlags, 1<<F_CF);
if(ST_IS_F(0)) {
VMOVcond_32(cEQ, v1, v2); // F_CF==0
} else {
VMOVcond_64(cEQ, v1, v2); // F_CF==0
}
break;
case 0xC8:
case 0xC9:
@@ -66,11 +69,14 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCF:
INST_NAME("FCMOVNE ST0, STx");
READFLAGS(X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
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));
TSTS_IMM8(xFlags, 1<<F_ZF);
if(ST_IS_F(0)) {
VMOVcond_32(cEQ, v1, v2); // F_ZF==0
} else {
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
}
break;
case 0xD0:
case 0xD1:
@@ -82,12 +88,14 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD7:
INST_NAME("FCMOVNBE ST0, STx");
READFLAGS(X_CF|X_ZF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
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));
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
if(ST_IS_F(0)) {
VMOVcond_32(cEQ, v1, v2); // F_CF==0 & F_ZF==0
} else {
VMOVcond_64(cEQ, v1, v2); // F_CF==0 & F_ZF==0
}
break;
case 0xD8:
case 0xD9:
@@ -99,23 +107,30 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDF:
INST_NAME("FCMOVNU ST0, STx");
READFLAGS(X_PF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
TSTS_REG_LSL_IMM5(x1, x1, 0);
VMOVcond_64(cEQ, v1, v2); // F_PF==0
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));
TSTS_IMM8(xFlags, 1<<F_PF);
if(ST_IS_F(0)) {
VMOVcond_32(cEQ, v1, v2); // F_PF==0
} else {
VMOVcond_64(cEQ, v1, v2); // F_PF==0
}
break;
case 0xE1:
INST_NAME("FDISI8087_NOP"); // so.. NOP?
break;
case 0xE2:
INST_NAME("FNCLEX");
MOVW(x1, 0);
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
MOVW(x1, 0);
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
BFI(x2, x1, 15, 1); // B
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
break;
case 0xE3:
INST_NAME("FNINIT");
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
CALL(reset_fpu, -1, 0);
break;
case 0xE8:
@@ -128,9 +143,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEF:
INST_NAME("FUCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOMI(x1, x2);
break;
case 0xF0:
@@ -143,14 +162,17 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF7:
INST_NAME("FCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOMI(x1, x2);
break;
case 0xE0:
case 0xE1:
case 0xE4:
case 0xE5:
case 0xE6:
@@ -162,11 +184,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FILD ST0, Ed");
v1 = x87_do_push(dyn, ninst);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch_single(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
GETED;
@@ -176,18 +198,18 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 1:
INST_NAME("FISTTP Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
ed = x1;
}
s0 = fpu_get_scratch_single(dyn);
MSR_nzcvq_0();
VMRS(x12); // Get FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x12, 0b001, 6); // enable exceptions
VMRS(x14); // Get FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
VCVT_S32_F64(s0, v1);
@@ -196,18 +218,18 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
TSTS_IMM8_ROR(x3, 0b00000001, 0);
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
WBACK;
VMSR(x12); // put back values
x87_do_pop(dyn, ninst);
VMSR(x14); // put back values
x87_do_pop(dyn, ninst, x3);
break;
case 2:
INST_NAME("FIST Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
ed = x1;
}
s0 = fpu_get_scratch_single(dyn);
@@ -226,13 +248,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 3:
INST_NAME("FISTP Ed, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
if((nextop&0xC0)==0xC0) {
ed = xEAX+(nextop&7);
wback = 0;
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
ed = x1;
}
s0 = fpu_get_scratch_single(dyn);
@@ -247,27 +269,44 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
TSTS_IMM8_ROR(x3, 0b00000001, 0);
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
WBACK;
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
x87_restoreround(dyn, ninst, u8);
break;
case 5:
INST_NAME("FLD tbyte");
x87_do_push_empty(dyn, ninst, x1);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {
MOV_REG(x1, ed);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
// the FLD is immediatly followed by an FSTP
LDR_IMM9(x2, ed, 0);
LDR_IMM9(x3, ed, 4);
LDRH_IMM8(x14, ed, 8);
// no persistant scratch register, so unrool both instruction here...
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
nextop = F8; //0xDB
nextop = F8; //modrm
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
STR_IMM9(x2, ed, 0);
STR_IMM9(x3, ed, 4);
STRH_IMM8(x14, ed, 8);
} else {
MESSAGE(LOG_DUMP, "Need Optimization\n");
if(ed!=x1) {
MOV_REG(x1, ed);
}
x87_do_push_empty(dyn, ninst, x3);
CALL(arm_fld, -1, 0);
}
CALL(arm_fld, -1, 0);
break;
case 7:
INST_NAME("FSTP tbyte");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x1, x3, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {
MOV_REG(x1, ed);
}
CALL(arm_fstp, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
default:
DEFAULT;
+82 -50
View File
@@ -46,9 +46,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FADD STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VADD_F64(v1, v1, v2);
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VADD_F32(v1, v1, v2);
} else {
VADD_F64(v1, v1, v2);
}
break;
case 0xC8:
case 0xC9:
@@ -59,9 +63,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCE:
case 0xCF:
INST_NAME("FMUL STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMUL_F64(v1, v1, v2);
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VMUL_F32(v1, v1, v2);
} else {
VMUL_F64(v1, v1, v2);
}
break;
case 0xD0:
case 0xD1:
@@ -72,9 +80,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD6:
case 0xD7:
INST_NAME("FCOM ST0, STx"); //yep
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
break;
case 0xD8:
@@ -86,11 +98,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDE:
case 0xDF:
INST_NAME("FCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
@@ -101,9 +117,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE6:
case 0xE7:
INST_NAME("FSUBR STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v1, v2, v1);
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VSUB_F32(v1, v2, v1);
} else {
VSUB_F64(v1, v2, v1);
}
break;
case 0xE8:
case 0xE9:
@@ -114,9 +134,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEE:
case 0xEF:
INST_NAME("FSUB STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v1, v1, v2);
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VSUB_F32(v1, v1, v2);
} else {
VSUB_F64(v1, v1, v2);
}
break;
case 0xF0:
case 0xF1:
@@ -127,9 +151,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF6:
case 0xF7:
INST_NAME("FDIVR STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v1, v2, v1);
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VDIV_F32(v1, v2, v1);
} else {
VDIV_F64(v1, v2, v1);
}
break;
case 0xF8:
case 0xF9:
@@ -140,22 +168,26 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFE:
case 0xFF:
INST_NAME("FDIV STx, ST0");
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v1, v1, v2);
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
if(ST_IS_F(0)) {
VDIV_F32(v1, v1, v2);
} else {
VDIV_F64(v1, v1, v2);
}
break;
default:
switch((nextop>>3)&7) {
case 0:
INST_NAME("FADD ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
@@ -164,14 +196,14 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 1:
INST_NAME("FMUL ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
@@ -180,14 +212,14 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 2:
INST_NAME("FCOM ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
@@ -197,32 +229,32 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 3:
INST_NAME("FCOMP ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
}
VCMP_F64(v1, d1);
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FSUB ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
@@ -231,14 +263,14 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 5:
INST_NAME("FSUBR ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
@@ -247,14 +279,14 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 6:
INST_NAME("FDIV ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
@@ -263,14 +295,14 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 7:
INST_NAME("FDIVR ST0, double[ED]");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
d1 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 2);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
VLDR_64(d1, wback, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, wback, fixedaddress);
LDR_IMM9(x3, wback, fixedaddress+4);
VMOVtoV_D(d1, x2, x3);
+81 -45
View File
@@ -31,6 +31,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
int parity;
uint8_t ed;
int v1, v2;
int i1, i2, i3;
MAYUSE(v2);
MAYUSE(v1);
@@ -45,7 +46,10 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FFREE STx");
break; // not handling Tag...
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
MOVW(x1, nextop&7);
CALL(fpu_do_free, -1, 0);
break;
case 0xD0:
case 0xD1:
case 0xD2:
@@ -55,13 +59,17 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xD6:
case 0xD7:
INST_NAME("FST ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMOV_64(v2, v1);
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)) {
VMOV_32(v2, v1);
} else {
VMOV_64(v2, v1);
}
break;
case 0xD8:
INST_NAME("FSTP ST0, ST0");
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xD9:
case 0xDA:
@@ -71,10 +79,19 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xDE:
case 0xDF:
INST_NAME("FSTP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMOV_64(v2, v1);
x87_do_pop(dyn, ninst);
// copy the cache value for st0 to stx
i1 = x87_get_cache(dyn, ninst, 0, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
i3 = dyn->x87cache[i1];
dyn->x87cache[i1] = dyn->x87cache[i2];
dyn->x87cache[i2] = i3;
// swap those too
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
i3 = dyn->n.neoncache[i1].v;
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
dyn->n.neoncache[i2].v = i3;
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
@@ -86,9 +103,13 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE6:
case 0xE7:
INST_NAME("FUCOM ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
break;
case 0xE8:
@@ -100,11 +121,15 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEE:
case 0xEF:
INST_NAME("FUCOMP ST0, STx");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xC8:
@@ -138,41 +163,35 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FLD double");
v1 = x87_do_push(dyn, ninst);
#if 0
// can bus error...
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_64(v1, ed, fixedaddress);
#else
parity = getedparity(dyn, ninst, addr, nextop, 3);
if (parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if (parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
VLDR_64(v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
LDR_IMM9(x2, ed, fixedaddress);
LDR_IMM9(x3, ed, fixedaddress + 4);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, ed, fixedaddress);
LDR_IMM9(x3, ed, fixedaddress + 4);
VMOVtoV_D(v1, x2, x3);
}
#endif
}
break;
case 1:
INST_NAME("FISTTP i64, ST0");
x87_forget(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fistp64, -1, 0);
x87_do_pop(dyn, ninst);
CALL(arm_fistt64, -1, 0);
x87_do_pop(dyn, ninst, x3);
break;
case 2:
INST_NAME("FST double");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
VSTR_64(v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
VMOVfrV_D(x2, x3, v1);
STR_IMM9(x2, ed, fixedaddress);
STR_IMM9(x3, ed, fixedaddress+4);
@@ -180,33 +199,50 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
break;
case 3:
INST_NAME("FSTP double");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
VSTR_64(v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
VMOVfrV_D(x2, x3, v1);
STR_IMM9(x2, ed, fixedaddress);
STR_IMM9(x3, ed, fixedaddress+4);
}
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 4:
INST_NAME("FRSTOR m108byte");
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_frstor, -1, 0);
break;
case 6:
INST_NAME("FSAVE m108byte");
fpu_purgecache(dyn, ninst, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fsave, -1, 0);
break;
case 7:
INST_NAME("FNSTSW m2byte");
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0);
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
if(dyn->x87stack) {
// update top
if(dyn->x87stack>0) {
SUB_IMM8(x2, x2, dyn->x87stack);
} else {
ADD_IMM8(x2, x2, -dyn->x87stack);
}
AND_IMM8(x2, x2, 7);
}
BFI(x1, x2, 11, 3); // inject top
STRH_IMM8(x1, ed, 0); // store whole sw flags
break;
default:
DEFAULT;
}
+80 -39
View File
@@ -17,6 +17,7 @@
#include "x86trace.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "dynarec_arm_functions.h"
#include "arm_printer.h"
#include "dynarec_arm_helper.h"
@@ -40,10 +41,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xC6:
case 0xC7:
INST_NAME("FADDP STx, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VADD_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
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)) {
VADD_F32(v2, v2, v1);
} else {
VADD_F64(v2, v2, v1);
}
x87_do_pop(dyn, ninst, x3);
break;
case 0xC8:
case 0xC9:
@@ -54,19 +59,47 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xCE:
case 0xCF:
INST_NAME("FMULP STx, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VMUL_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
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)) {
VMUL_F32(v2, v2, v1);
} else {
VMUL_F64(v2, v2, v1);
}
x87_do_pop(dyn, ninst, x3);
break;
case 0xD9: /* FCOMPP */
INST_NAME("FCOMPP ST0, ST1");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
VCMP_F64(v1, v2);
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
INST_NAME("FCOMP ST0, STx");
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)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xD9:
INST_NAME("FCOMPP ST0, ST1");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, 1));
v2 = x87_get_st(dyn, ninst, x1, x2, 1, X87_COMBINE(0, 1));
if(ST_IS_F(0)) {
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOM(x1, x2);
x87_do_pop(dyn, ninst, x3);
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
case 0xE1:
@@ -77,10 +110,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xE6:
case 0xE7:
INST_NAME("FSUBRP STx, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v2, v1, v2);
x87_do_pop(dyn, ninst);
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)) {
VSUB_F32(v2, v1, v2);
} else {
VSUB_F64(v2, v1, v2);
}
x87_do_pop(dyn, ninst, x3);
break;
case 0xE8:
case 0xE9:
@@ -91,10 +128,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEE:
case 0xEF:
INST_NAME("FSUBP STx, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VSUB_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
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)) {
VSUB_F32(v2, v2, v1);
} else {
VSUB_F64(v2, v2, v1);
}
x87_do_pop(dyn, ninst, x3);
break;
case 0xF0:
case 0xF1:
@@ -105,10 +146,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF6:
case 0xF7:
INST_NAME("FDIVRP STx, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v2, v1, v2);
x87_do_pop(dyn, ninst);
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)) {
VDIV_F32(v2, v1, v2);
} else {
VDIV_F64(v2, v1, v2);
}
x87_do_pop(dyn, ninst, x3);
break;
case 0xF8:
case 0xF9:
@@ -119,20 +164,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xFE:
case 0xFF:
INST_NAME("FDIVP STx, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VDIV_F64(v2, v2, v1);
x87_do_pop(dyn, ninst);
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)) {
VDIV_F32(v2, v2, v1);
} else {
VDIV_F64(v2, v2, v1);
}
x87_do_pop(dyn, ninst, x3);
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
case 0xD8:
case 0xDA:
case 0xDB:
+261 -77
View File
@@ -28,24 +28,47 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
{
uint8_t nextop = F8;
uint8_t u8;
int32_t i32;
int32_t j32;
uint8_t wback;
uint8_t ed;
int v1, v2;
int v0, v1, v2;
int s0;
int fixedaddress;
int parity;
MAYUSE(s0);
MAYUSE(v2);
MAYUSE(v1);
MAYUSE(i32);
MAYUSE(v0);
MAYUSE(j32);
switch(nextop) {
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
INST_NAME("FFREEP STx");
// not handling Tag...
x87_do_pop(dyn, ninst, x3);
break;
case 0xE0:
INST_NAME("FNSTSW AX");
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
AND_IMM8(x2, x2, 7);
if(dyn->x87stack) {
// update top
if(dyn->x87stack>0) {
SUB_IMM8(x2, x2, dyn->x87stack);
} else {
ADD_IMM8(x2, x2, -dyn->x87stack);
}
AND_IMM8(x2, x2, 7);
}
BFI(x1, x2, 11, 3); // inject top
BFI(xEAX, x1, 0, 16);
break;
@@ -59,11 +82,16 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xEF:
INST_NAME("FUCOMIP ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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))
{
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOMI(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xF0:
case 0xF1:
@@ -75,21 +103,18 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
case 0xF7:
INST_NAME("FCOMIP ST0, STx");
SETFLAGS(X_ALL, SF_SET);
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
VCMP_F64(v1, v2);
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))
{
VCMP_F32(v1, v2);
} else {
VCMP_F64(v1, v2);
}
FCOMI(x1, x2);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
case 0xC8:
case 0xC9:
case 0xCA:
@@ -136,101 +161,260 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
switch((nextop>>3)&7) {
case 0:
INST_NAME("FILD ST0, Ew");
v1 = x87_do_push(dyn, ninst);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
LDRSH_IMM8(x1, wback, fixedaddress);
s0 = fpu_get_scratch_single(dyn);
VMOVtoV(s0, x1);
VCVT_F64_S32(v1, s0);
if(ST_IS_F(0)) {
VMOVtoV(v1, x1);
VCVT_F32_S32(v1, v1);
} else {
s0 = fpu_get_scratch_single(dyn);
VMOVtoV(s0, x1);
VCVT_F64_S32(v1, s0);
}
break;
case 1:
INST_NAME("FISTTP Ew, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
ed = x1;
s0 = fpu_get_scratch_single(dyn);
VCVT_S32_F64(s0, v1);
MSR_nzcvq_0();
VMRS(x14); // get fpscr
// x1 already have FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
if(ST_IS_F(0)) {
VCVTR_S32_F32(s0, v1);
} else {
VCVTR_S32_F64(s0, v1);
}
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
VMOVfrV(ed, s0);
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
MRS_aspr(x3); // check Q flag
TSTS_IMM8_ROR(x3, 0b10, 3);
B_MARK(cEQ); // not saturated, continue
MOV32(ed, 0xffff8000);
MARK;
STRH_IMM8(ed, wback, fixedaddress);
x87_do_pop(dyn, ninst);
x87_restoreround(dyn, ninst, u8);
TSTS_IMM8_ROR(x3, 0b00000001, 0);
SSAT_REG_LSL_IMM5_COND(cEQ, x3, 16, ed, 0);
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
MOVW_COND(cNE, x3, 0x8000); // saturated
STRH_IMM8(x3, wback, fixedaddress);
x87_do_pop(dyn, ninst, x3);
VMSR(x14);
break;
case 2:
INST_NAME("FIST Ew, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
u8 = x87_setround(dyn, ninst, x1, x2, x14);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
ed = x1;
s0 = fpu_get_scratch_single(dyn);
VCVTR_S32_F64(s0, v1);
MSR_nzcvq_0();
// x1 already have FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
if(ST_IS_F(0)) {
VCVTR_S32_F32(s0, v1);
} else {
VCVTR_S32_F64(s0, v1);
}
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
VMOVfrV(ed, s0);
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
MRS_aspr(x3); // check Q flag
TSTS_IMM8_ROR(x3, 0b10, 3);
B_MARK(cEQ); // not saturated, continue
MOV32(ed, 0xffff8000);
MARK;
STRH_IMM8(ed, wback, fixedaddress);
TSTS_IMM8_ROR(x3, 0b00000001, 0);
SSAT_REG_LSL_IMM5_COND(cEQ, x3, 16, ed, 0);
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
MOVW_COND(cNE, x3, 0x8000); // saturated
STRH_IMM8(x3, wback, fixedaddress);
x87_restoreround(dyn, ninst, u8);
break;
case 3:
INST_NAME("FISTP Ew, ST0");
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
u8 = x87_setround(dyn, ninst, x1, x2, x12);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
u8 = x87_setround(dyn, ninst, x1, x2, x14);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
ed = x1;
s0 = fpu_get_scratch_single(dyn);
VCVTR_S32_F64(s0, v1);
MSR_nzcvq_0();
// x1 already have FPCSR reg to clear exceptions flags
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
if(ST_IS_F(0)) {
VCVTR_S32_F32(s0, v1);
} else {
VCVTR_S32_F64(s0, v1);
}
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
VMOVfrV(ed, s0);
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
MRS_aspr(x3); // check Q flag
TSTS_IMM8_ROR(x3, 0b10, 3);
B_MARK(cEQ); // not saturated, continue
MOV32(ed, 0xffff8000);
MARK;
STRH_IMM8(ed, wback, fixedaddress);
x87_do_pop(dyn, ninst);
TSTS_IMM8_ROR(x3, 0b00000001, 0);
SSAT_REG_LSL_IMM5_COND(cEQ, x3, 16, ed, 0);
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
MOVW_COND(cNE, x3, 0x8000); // saturated
STRH_IMM8(x3, wback, fixedaddress);
x87_do_pop(dyn, ninst, x3);
x87_restoreround(dyn, ninst, u8);
break;
case 4:
INST_NAME("FBLD ST0, tbytes");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_do_push_empty(dyn, ninst, x1);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(fpu_fbld, -1, 0);
break;
case 5: // could be inlined for most thing, but is it usefull?
case 5:
INST_NAME("FILD ST0, i64");
x87_do_push_empty(dyn, ninst, x1);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fild64, -1, 0);
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
v2 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 3);
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0);
if(parity) {
LDRD_IMM8(x2, wback, 0); // x2/x3 is 64bits
} else {
LDR_IMM9(x2, wback, 0);
LDR_IMM9(x3, wback, 4);
}
if(ninst<dyn->size
&& dyn->insts[ninst+1].x86.addr
&& *(uint8_t*)dyn->insts[ninst+1].x86.addr==0xDF
&& (((*(uint8_t*)(dyn->insts[ninst+1].x86.addr+1))>>3)&7)==7)
{
MESSAGE(LOG_DUMP, "Hack for FILD/FISTP i64");
} else {
// Save xFlags to use it as scratch...
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
// set STll(0).ll=i64 and ref=ST(0).q later (emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top])
// get TOP
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, top));
int a = 0 - dyn->x87stack;
if(a<0) {
SUB_IMM8(xFlags, xFlags, -a);
AND_IMM8(xFlags, xFlags, 7);
} else if(a>0) {
ADD_IMM8(xFlags, xFlags, a);
AND_IMM8(xFlags, xFlags, 7);
}
ADD_REG_LSL_IMM5(xFlags, xEmu, xFlags, 4); // each fpu_ll is 2 int64: ref than ll
ADD_IMM8_ROR(xFlags, xFlags, offsetof(x86emu_t, fpu_ll)>>2, 15);
STRD_IMM8(x2, xFlags, 8); // save ll
// continue with conversion
MOVS_REG_LSR_IMM5(x14, x3, 31); // x14 is sign bit
B_MARK(cEQ); // no NEG is no sign bit
RSBS_IMM8(x2, x2, 0);
RSC_IMM8(x3, x3, 0);
MARK;
VMOVtoV(s0, x3);
VCVT_F64_U32(v1, s0);
VEOR(v2, v2, v2);
MOVW(x1, 0x41F0);
VMOVtoDx_16(v2, 3, x1);
VMUL_F64(v1, v1, v2); // v1 = double high part of i64
VMOVtoV(s0, x2);
VCVT_F64_U32(v2, s0);
VADD_F64(v1, v1, v2);
TSTS_IMM8(x14, 1);
VNEG_F64_cond(cNE, v1, v1);
VST1_64(v1, xFlags); // Store STll(0).ref
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
}
break;
case 6:
INST_NAME("FBSTP tbytes, ST0");
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(fpu_fbst, -1, 0);
x87_do_pop(dyn, ninst);
x87_do_pop(dyn, ninst, x3);
break;
case 7: // could be inlined for most thing, but is it usefull?
INST_NAME("FISTP i64, ST0");
x87_forget(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fistp64, -1, 0);
x87_do_pop(dyn, ninst);
parity = getedparity(dyn, ninst, addr, nextop, 3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
if(ninst
&& dyn->insts[ninst-1].x86.addr
&& *(uint8_t*)dyn->insts[ninst-1].x86.addr==0xDF
&& (((*(uint8_t*)(dyn->insts[ninst-1].x86.addr+1))>>3)&7)==5)
{
if(parity) {
STRD_IMM8(x2, ed, 0); // x2/x3 is 64bits
} else {
STR_IMM9(x2, ed, 0);
STR_IMM9(x3, ed, 4);
}
} else {
#if 0
v1 = x87_get_st(dyn, ninst, x2, x3, 0);
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
v2 = fpu_get_scratch_double(dyn);
v0 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
// check STll(0).ref==ST(0).q so emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top]
// get TOP
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
int a = 0 - dyn->x87stack;
if(a<0) {
SUB_IMM8(x14, x14, -a);
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
} else if(a>0) {
ADD_IMM8(x14, x14, a);
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
}
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
ADD_REG_LSL_IMM5(x14, x14, x2, 0);
VLDR_64(v2, x14, 0);
VCEQ_32(v2, v2, v1); // compare
VMOVfrV_D(x2, x3, v2);
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
B_MARK(cEQ); // do the i64 conversion
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
LDRD_IMM8(x2, x14, 8); // load ll
B_MARK3(c__);
MARK;
VEOR(v0, v0, v0);
MOVW(x2, 0x41F0);
VMOVtoDx_16(v0, 3, x2); // V0 = (1<<32) as double
VMOVfrDx_32(x14, v1, 1); // get high part to extract sign
VABS_F64(v1 ,v1); //ST0 will be poped, so lost...
VDIV_F64(v2, v1, v0); // v2 = abs(ST0)/(1<<32) : so 32 bits high part
MSR_nzcvq_0();
VMRS(x2); // get fpscr
ORR_IMM8(x3, x2, 0b001, 6); // enable exceptions
BIC_IMM8(x3, x3, 0b10011111, 0);
VMSR(x3);
VCVT_U32_F64(s0, v2); // convert high part to U32
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
VMSR(x2); // put back fpscr
TSTS_IMM8_ROR(x3, 0b00000001, 0);
B_MARK2(cEQ); // not overflow...
MARKLOCK;
MOV_IMM(x3, 0b10, 1); // 0x80000000
MOVW(x2, 0);
B_MARK3(c__);
MARK2; // continue conversion, it fits an int64!
VCVT_F64_U32(v2, s0); // int part now
VMLS_F64(v1, v2, v0); // compute low part
VMOVfrV(x3, s0); // transfert high path
TSTS_IMM8_ROR(x14, 0b10, 1); // test high part with 0x800000000
B_MARKLOCK(cNE); // int overflow...
VCVT_U32_F64(s0, v1); // convert low part
VMOVfrV(x2, s0); // transfert low part
TSTS_IMM8_ROR(x14, 0b10, 1); // 0x800000000
B_MARK3(cEQ);
RSBS_IMM8(x2, x2, 0); // NEG(i64)
RSC_IMM8(x3, x3, 0);
MARK3;
STR_IMM9(x2, x1, 0);
STR_IMM9(x3, x1, 4);
#else
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_forget(dyn, ninst, x2, x3, 0);
if(ed!=x1) {MOV_REG(x1, ed);}
CALL(arm_fistp64, -1, 0);
#endif
}
x87_do_pop(dyn, ninst, x3);
break;
default:
DEFAULT;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+402 -88
View File
@@ -23,6 +23,63 @@
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
int32_t j32;
MAYUSE(j32);
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_shl32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
IFX(F_OF) {
CMPS_IMM8(s2, 0);
IFX(F_OF) {
BIC_IMM8_COND(cEQ, xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_PEND) {
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
}
B_NEXT(cEQ);
}
IFX(X_CF | X_OF) {
RSB_IMM8(s4, s2, 32);
MOV_REG_LSR_REG(s4, s1, s4);
BFI(xFlags, s4, F_CF, 1);
}
IFX(X_ZF) {
MOVS_REG_LSL_REG(s1, s1, s2);
} else {
MOV_REG_LSL_REG(s1, s1, s2);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_OF) {
CMPS_IMM8(s2, 1); // if s3==1
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);}
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
// else
BFC_COND(cNE, xFlags, F_OF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
@@ -30,17 +87,13 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_shl32);
SET_DF(s4, d_shl32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(c==0) {
IFX(F_OF) {
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
@@ -48,8 +101,8 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
return;
}
IFX(X_CF) {
UBFX(s3, s1, c, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
MOV_REG_LSR_IMM5(s3, s1, 32-c);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_ZF|X_OF) {
MOVS_REG_LSL_IMM5(s1, s1, c);
@@ -60,33 +113,76 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
MOVW_COND(cNE, s3, 0);
MOVW_COND(cEQ, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_OF) {
if(c==1) {
IFX(X_SF) {} else {UBFX(s3, s1, 31, 1);}
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s3, s1, 31);}
XOR_IMM8_COND(cCS, s3, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s3, F_OF, 1);
} else {
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
int32_t j32;
MAYUSE(j32);
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
IFX(X_ALL) {
CMPS_IMM8(s2, 0); //if(!c)
IFX(X_PEND) {
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
}
B_NEXT(cEQ);
}
IFX(X_ZF|X_CF) {
MOVS_REG_LSR_REG(s1, s1, s2);
} else {
MOV_REG_LSR_REG(s1, s1, s2);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_OF) {
CMPS_IMM8(s2, 1);
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -97,12 +193,9 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_shr32);
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -118,37 +211,28 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
MOVW_COND(cNE, s3, 0);
MOVW_COND(cEQ, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
MOVW_COND(cCC, s3, 0);
MOVW_COND(cCS, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 30);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s4, F_OF, 1);
}
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
@@ -159,12 +243,9 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_sar32);
SET_DF(s4, d_sar32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -180,44 +261,35 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
MOVW_COND(cNE, s3, 0);
MOVW_COND(cEQ, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_CF) {
MOVW_COND(cCC, s3, 0);
MOVW_COND(cCS, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
if(!c)
return;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_rol32);
SET_DF(s4, d_rol32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -230,14 +302,12 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF) {
AND_IMM8(s3, s1, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
BFI(xFlags, s1, F_CF, 1);
}
IFX(X_OF) {
if(c==1) {
ADD_REG_LSR_IMM5(s3, s1, s1, 31);
AND_IMM8(s3, s3, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s3, F_OF, 1);
}
}
}
@@ -245,15 +315,14 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
{
if(!c)
return;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_ror32);
SET_DF(s4, d_ror32);
} else IFX(X_ALL) {
MOVW(s4, d_none);
}
IFX(X_PEND|X_ALL) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
@@ -266,15 +335,260 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF) {
UBFX(s3, s1, 31, 1);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 30);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFI(xFlags, s4, F_OF, 1);
}
}
}
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
{
c&=0x1f;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
// same flags calc as shr32
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_CF) {
MOVS_REG_LSR_IMM5(s1, s1, c);
} else {
MOV_REG_LSR_IMM5(s1, s1, c);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_ZF) {
ORRS_REG_LSL_IMM5(s1, s1, s2, 32-c);
} else {
ORR_REG_LSL_IMM5(s1, s1, s2, 32-c);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 30);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
BFI(xFlags, s4, F_OF, 1);
}
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
{
c&=0x1f;
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
// same flags computation as with shl32
SET_DF(s4, d_shl32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
if(c==0) {
IFX(F_OF) {
BFC(xFlags, F_OF, 1);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
IFX(X_CF) {
MOV_REG_LSR_IMM5(s3, s1, 32-c);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_OF) {
MOVS_REG_LSL_IMM5(s1, s1, c);
} else {
MOV_REG_LSL_IMM5(s1, s1, c);
}
IFX(X_OF) {
if(c==1) {
UBFX(s3, s1, (31-c), 1);
XOR_IMM8_COND(cCS, s3, s3, 1);
BFI(xFlags, s3, F_OF, 1);
} else {
BFC(xFlags, F_OF, 1);
}
}
IFX(X_ZF) {
ORRS_REG_LSR_IMM5(s1, s1, s2, 32-c);
} else {
ORR_REG_LSR_IMM5(s1, s1, s2, 32-c);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s3, s1, 31);
BFI(xFlags, s3, F_SF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit SHRD32 instruction, from s1, fill s2 , shift s3, store result in s1 using s4 and s3 as scratch
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
int j32;
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
// same flags calc as shr32
SET_DF(s4, d_shr32);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
CMPS_IMM8(s3, 0);
IFX(X_PEND) {
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
}
B_NEXT(cEQ);
IFX(X_CF) {
MOVS_REG_LSR_REG(s1, s1, s3);
} else {
MOV_REG_LSR_REG(s1, s1, s3);
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_CF) {
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
}
RSB_IMM8(s3, s3, 32);
IFX(X_ZF) {
ORRS_REG_LSL_REG(s1, s1, s2, s3);
} else {
ORR_REG_LSL_REG(s1, s1, s2, s3);
}
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
MOV_REG_LSR_IMM5(s4, s1, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_OF) {
CMPS_IMM8(s3, 31); // 32-c
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
}
IFX(X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// 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, int32_t c, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_rol8);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
if(c&7) {
BFI(s1, s1, 24, 8); // duplicate the value for rotate left
MOV_REG_ROR_IMM5(s1, s1, 32-(c&7));
}
//AND_IMM8(s1, s1, 0xff);
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF) {
BFI(xFlags, s1, F_CF, 1);
}
IFX(X_OF) {
if(c==1) {
ADD_REG_LSR_IMM5(s3, s1, s1, 7);
BFI(xFlags, s3, F_OF, 1);
}
}
}
// 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, int32_t c, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s3, c);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_ror8);
} else IFX(X_ALL) {
SET_DFNONE(s4);
}
if(!c) {
IFX(X_PEND) {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
return;
}
if(c&7) {
BFI(s1, s1, 8, 8); // duplicate the value for Rotate right
MOV_REG_ROR_IMM5(s1, s1, c&7);
}
IFX(X_PEND) {
AND_IMM8(s1, s1, 0xff);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
}
IFX(X_CF) {
MOV_REG_LSR_IMM5(s3, s1, 7);
BFI(xFlags, s3, F_CF, 1);
}
IFX(X_OF) {
if(c==1) {
MOV_REG_LSR_IMM5(s4, s1, 6);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
BFI(xFlags, s4, F_OF, 1);
}
}
}
+128 -200
View File
@@ -26,43 +26,34 @@
// emit CMP32 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_cmp32);
SET_DF(s4, d_cmp32);
} else {
MOVW(s4, 0);
SET_DFNONE(s4);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SUBS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
IFX(X_ZF) {
IFX(X_PEND) {
MOVW(s4, 0);
}
// first the easy flag, also found on ARM
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_OF) {
IFX(X_ZF|X_PEND) {
MOVW(s4, 0);
}
MOVW_COND(cVS, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
BIC_IMM8_COND(cVC, xFlags, xFlags, 0b10, 0x0b);
}
IFX(X_CF) {
IFX(X_ZF|X_OF|X_PEND) {
MOVW(s4, 0);
}
MOVW_COND(cCC, s4, 1); // Carry flags on ARM is reversed compared to x86 one
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
// reversed carry
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 31);
BFI(xFlags, s4, F_SF, 1);
}
// and now the tricky ones (and mostly unused), PF and AF
IFX(X_AF) {
@@ -73,8 +64,8 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
}
IFX(X_PF) {
@@ -83,90 +74,71 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
}
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
IFX_PENDOR0 {
MOVW(s4, 0);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
MOVW(s4, d_cmp32);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
SET_DF(s4, d_cmp32);
} else {
SET_DFNONE(s4);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SUBS_IMM8(s3, s1, 0); // res = s1 - 0
IFX(X_PEND) {
IFX(X_ZF|X_OF|X_CF|X_AF) {
MOVW(s4, 0);
}
}
// and now the tricky ones (and mostly unused), PF and AF
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80000000
}
IFX(X_AF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
// first the easy flags, also found on ARM
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 31);
BFI(xFlags, s4, F_SF, 1);
}
IFX(X_PF) {
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit CMP16 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
MOVW(s3, d_cmp16);
SET_DF(s3, d_cmp16);
} else {
MOVW(s3, 0);
SET_DFNONE(s3);
}
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
MOVW(s4, 0xffff);
TSTS_REG_LSL_IMM5(s3, s4, 0);
MOVW_COND(cNE, s4, 0);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 15);
BFI(xFlags, s4, F_SF, 1);
}
// bc = (res & (~d | s)) | (~d & s)
IFX(X_CF|X_AF|X_OF) {
@@ -176,108 +148,87 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
IFX(X_CF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
MOV_REG_LSR_IMM5(s4, s3, 15);
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
}
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_OF) {
MOV_REG_LSR_IMM5(s4, s3, 14);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
}
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
IFX(X_CF|X_AF|X_OF) {
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
}
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
MOVW(s3, 0);
IFX(X_PEND) {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
IFX_PENDOR0 {
MOVW(s3, 0);
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
MOVW(s3, d_cmp16);
}
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
IFX(X_OF|X_CF|X_AF) {
MOVW(s4, 0);
SET_DF(s3, d_cmp16);
} else {
SET_DFNONE(s3);
}
// bc = (res & (~d | s)) | (~d & s) = 0
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
}
IFX(X_AF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
MOVW(s4, 0xffff);
TSTS_REG_LSL_IMM5(s1, s4, 0);
MOVW(s4, 0);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s1, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s1, 15);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
IFX(X_PEND) {
MOVW(s4, d_cmp8);
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
SET_DF(s4, d_cmp8);
} else {
MOVW(s4, 0);
SET_DFNONE(s4);
}
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
IFX(X_PEND) {
MOVW(s4, 0);
}
TSTS_IMM8(s3, 0xff);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 7);
BFI(xFlags, s4, F_SF, 1);
}
// bc = (res & (~d | s)) | (~d & s)
IFX(X_CF|X_AF|X_OF) {
@@ -287,198 +238,175 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
IFX(X_CF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
MOV_REG_LSR_IMM5(s4, s3, 7);
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x80
}
IFX(X_AF) {
UBFX(s4, s3, 3, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
MOV_REG_LSR_IMM5(s4, s3, 3);
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
}
IFX(X_OF) {
MOV_REG_LSR_IMM5(s4, s3, 6);
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
}
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
IFX(X_CF|X_AF|X_OF) {
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
}
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_cmp8);
IFX_PENDOR0 {
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
MOVW(s4, 0);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
SET_DF(s3, d_cmp8);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
// bc = (res & (~d | s)) | (~d & s) = 0
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
}
IFX(X_AF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
IFX(X_CF | X_AF | X_ZF) {
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
BFC(xFlags, F_OF, 1);
}
IFX(X_ZF) {
TSTS_IMM8(s1, 0xff);
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s1, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s1, 7);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_IMM8(s3, s1, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
emit_pf(dyn, ninst, s1, s3, s4);
}
}
// emit TEST32 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_tst32);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
IFX_PENDOR0 {
SET_DF(s3, d_tst32);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 31, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 31);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
if(s1==s2) {
AND_IMM8(s3, s1, 31);
} else {
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
}
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// emit TEST16 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_tst16);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
IFX_PENDOR0 {
SET_DF(s3, d_tst16);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 15, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 15);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
MOVW(s4, 0);
IFX(X_PEND) {
MOVW(s3, d_tst8);
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
IFX_PENDOR0 {
SET_DF(s3, d_tst8);
} else {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
SET_DFNONE(s4);
}
IFX(X_OF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
BFC(xFlags, F_OF, 1);
}
IFX(X_CF) {
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
IFX(X_ZF|X_CF) {
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
}
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
IFX(X_PEND) {
IFX_PENDOR0 {
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
}
IFX(X_ZF) {
MOVW_COND(cEQ, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
}
IFX(X_SF) {
UBFX(s4, s3, 7, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
MOV_REG_LSR_IMM5(s4, s3, 7);
BFI(xFlags, s4, F_SF, 1);
}
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
IFX(X_PF) {
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
MOV32(s4, GetParityTab());
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
AND_REG_LSL_IMM5(s3, s1, s2, 0);
AND_IMM8(s3, s3, 31);
MVN_REG_LSR_REG(s4, s4, s3);
AND_IMM8(s4, s4, 1);
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
BFI(xFlags, s4, F_PF, 1);
}
}
File diff suppressed because it is too large. Load diff
+82 -59
View File
@@ -23,17 +23,17 @@
#include "dynarec_arm_helper.h"
// Get Ex as a double, not a quad (warning, x2 and x3 may get used)
#define GETEX(a) \
if((nextop&0xC0)==0xC0) { \
a = sse_get_reg(dyn, ninst, x1, nextop&7); \
#define GETEX(a, w) \
if((nextop&0xC0)==0xC0) { \
a = sse_get_reg(dyn, ninst, x1, nextop&7,w);\
} else { \
parity = getedparity(dyn, ninst, addr, nextop, 3); \
a = fpu_get_scratch_double(dyn); \
if(parity) { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0); \
VLDR_64(a, ed, fixedaddress); \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);\
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);\
LDR_IMM9(x2, ed, fixedaddress+0); \
LDR_IMM9(x3, ed, fixedaddress+4); \
VMOVtoV_D(a, x2, x3); \
@@ -58,17 +58,18 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
MAYUSE(d0);
switch(nextop) {
case 0x10:
INST_NAME("MOVSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
if((nextop&0xC0)==0xC0) {
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
VMOVD(v0, d0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, ed, fixedaddress+0);
LDR_IMM9(x3, ed, fixedaddress+4);
VMOVtoV_D(v0, x2, x3);
@@ -79,13 +80,13 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("MOVSD Ex, Gx");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if((nextop&0xC0)==0xC0) {
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
VMOVD(d0, v0);
} else {
VMOVfrV_D(x2, x3, v0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
STR_IMM9(x2, ed, fixedaddress+0);
STR_IMM9(x3, ed, fixedaddress+4);
}
@@ -94,25 +95,25 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("MOVDDUP Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
if((nextop&0xC0)==0xC0) {
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVD(v0, d0);
VMOVD(v0+1, d0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
LDR_IMM9(x2, ed, fixedaddress+0);
LDR_IMM9(x3, ed, fixedaddress+4);
VMOVtoV_D(v0, x2, x3);
VMOVD(v0+1, v0);
}
VMOVD(v0+1, v0);
break;
case 0x2A:
INST_NAME("CVTSI2SD Gx, Ed");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETED;
s0 = fpu_get_scratch_single(dyn);
VMOVtoV(s0, ed);
@@ -125,9 +126,9 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETGD;
s0 = fpu_get_scratch_single(dyn);
if((nextop&0xC0)==0xC0) {
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
d0 = fpu_get_scratch_double(dyn);
VLDR_64(d0, ed, fixedaddress);
}
@@ -136,14 +137,14 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
break;
case 0x2D:
INST_NAME("CVTSD2SI Gd, Ex");
u8 = x87_setround(dyn, ninst, x1, x2, x12);
u8 = sse_setround(dyn, ninst, x1, x2, x14);
nextop = F8;
GETGD;
s0 = fpu_get_scratch_single(dyn);
if((nextop&0xC0)==0xC0) {
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
d0 = fpu_get_scratch_double(dyn);
VLDR_64(d0, ed, fixedaddress);
}
@@ -156,8 +157,8 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("SQRTSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
VSQRT_F64(v0, d0);
break;
@@ -165,80 +166,82 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("ADDSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
VADD_F64(v0, v0, d0);
break;
case 0x59:
INST_NAME("MULSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
VMUL_F64(v0, v0, d0);
break;
case 0x5A:
INST_NAME("CVTSD2SS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
d1 = fpu_get_scratch_double(dyn);
s0 = fpu_get_scratch_single(dyn);
VCVT_F32_F64(s0, d0);
VMOV_64(d1, v0);
VMOV_32(d1*2, s0);
VMOV_64(v0, d1);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
if(v0<16) {
VCVT_F32_F64(v0*2, d0);
} else {
d1 = fpu_get_scratch_double(dyn);
VMOV_64(d1, v0);
VCVT_F32_F64(d1*2, d0);
VMOV_64(v0, d1);
}
break;
case 0x5C:
INST_NAME("SUBSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
VSUB_F64(v0, v0, d0);
break;
case 0x5D:
INST_NAME("MINSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
VCMP_F64(v0, d0);
VMRS_APSR();
VMOVcond_64(cPL, v0, d0);
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 unordered or v0 >= d0
break;
case 0x5E:
INST_NAME("DIVSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
VDIV_F64(v0, v0, d0);
break;
case 0x5F:
INST_NAME("MAXSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
VCMP_F64(d0, v0);
VMRS_APSR();
VMOVcond_64(cPL, v0, d0);
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 is unordered or d0 >= v0
break;
case 0x70:
INST_NAME("PSHUFLW Gx, Ex, Ib");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
v1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(v1, ed);
}
@@ -269,11 +272,11 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("HADDPS Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
v1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(v1, ed);
}
@@ -289,25 +292,45 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("CMPSD Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
GETEX(d0);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETEX(d0, 0);
u8 = F8;
VCMP_F64(v0, d0);
VMRS_APSR();
MOVW(x2, 0);
u8 = F8;
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal or unordered
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoV_D(v0, x2, x2);
break;
case 0xF0:
INST_NAME("LDDQ Gx,Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
LDR_IMM9(x2, ed, fixedaddress+0);
LDR_IMM9(x3, ed, fixedaddress+4);
VMOVtoV_D(v0, x2, x3);
LDR_IMM9(x2, ed, fixedaddress+8);
LDR_IMM9(x3, ed, fixedaddress+12);
VMOVtoV_D(v0+1, x2, x3);
}
break;
default:
DEFAULT;
}
+141 -63
View File
@@ -23,9 +23,9 @@
#include "dynarec_arm_helper.h"
// Get Ex as a single, not a quad, with b a intermediary double
#define GETEX(a, b) \
if((nextop&0xC0)==0xC0) { \
b = sse_get_reg(dyn, ninst, x1, nextop&7); \
#define GETEX(a, b) \
if((nextop&0xC0)==0xC0) { \
b = sse_get_reg(dyn, ninst, x1, nextop&7,0);\
if(b<16) \
a = b; \
else { \
@@ -38,7 +38,7 @@
a = b*2; \
parity = getedparity(dyn, ninst, addr, nextop, 2); \
if(parity) { \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0); \
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0); \
VLDR_32(a, ed, fixedaddress); \
} else { \
GETED; \
@@ -46,16 +46,16 @@
} \
}
#define GETGX(a) \
gd = (nextop&0x38)>>3; \
a = sse_get_reg(dyn, ninst, x1, gd)
#define GETGX(a, w) \
gd = (nextop&0x38)>>3; \
a = sse_get_reg(dyn, ninst, x1, gd, w)
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
{
uint8_t opcode = F8;
uint8_t nextop, u8;
int32_t i32;
int32_t j32;
uint32_t u32;
uint8_t gd, ed;
uint8_t wback;
@@ -63,12 +63,13 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
int v0, v1;
int s0, s1, s2;
int d0, d1;
int q0;
int q0, q1;
int parity;
MAYUSE(q1);
MAYUSE(s1);
MAYUSE(s2);
MAYUSE(i32);
MAYUSE(j32);
switch(opcode) {
@@ -77,8 +78,8 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
v0 = sse_get_reg(dyn, ninst, x1, gd);
q0 = sse_get_reg(dyn, ninst, x1, nextop&7);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
if(v0<16)
d0 = v0;
else {
@@ -97,7 +98,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
VEORQ(v0, v0, v0);
VMOVtoDx_32(v0, 0, x2);
@@ -107,9 +108,9 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("MOVSS Ex, Gx");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if((nextop&0xC0)==0xC0) {
q0 = sse_get_reg(dyn, ninst, x1, nextop&7);
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
if(v0<16)
d0 = v0;
else {
@@ -128,10 +129,42 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
} else {
VMOVfrDx_32(x2, v0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
STR_IMM9(x2, ed, fixedaddress);
}
break;
case 0x12:
INST_NAME("MOVSLDUP Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
q1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(q1, ed);
}
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VDUP_32(q0+0, q1+0, 0);
VDUP_32(q0+1, q1+1, 0);
break;
case 0x16:
INST_NAME("MOVSHDUP Gx, Ex");
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
q1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(q1, ed);
}
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VDUP_32(q0+0, q1+0, 1);
VDUP_32(q0+1, q1+1, 1);
break;
case 0x1E:
INST_NAME("NOP / ENDBR32 / ENDBR64");
@@ -148,7 +181,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("CVTSI2SS Gx, Ed");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
GETED;
if(v0<16)
d0 = v0;
@@ -170,7 +203,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
GETGD;
s0 = fpu_get_scratch_single(dyn);
if((nextop&0xC0)==0xC0) {
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
if(v0<16)
d0 = v0;
else {
@@ -179,20 +212,27 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
VMOV_32(s0, d0*2);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_32(s0, ed, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
LDR_IMM9(x2, ed, fixedaddress);
VMOVtoV(s0, x2);
}
}
VCVT_S32_F32(s0, s0);
VMOVfrV(gd, s0);
break;
case 0x2D:
INST_NAME("CVTSS2SI Gd, Ex");
u8 = x87_setround(dyn, ninst, x1, x2, x12);
u8 = sse_setround(dyn, ninst, x1, x2, x14);
nextop = F8;
GETGD;
s0 = fpu_get_scratch_single(dyn);
if((nextop&0xC0)==0xC0) {
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
if(v0<16)
d0 = v0;
else {
@@ -201,8 +241,15 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
}
VMOV_32(s0, d0*2);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
VLDR_32(s0, ed, fixedaddress);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
VLDR_32(s0, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
LDR_IMM9(x2, ed, fixedaddress);
VMOVtoV(s0, x2);
}
}
VCVTR_S32_F32(s0, s0);
VMOVfrV(gd, s0);
@@ -212,7 +259,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x51:
INST_NAME("SQRTSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -232,7 +279,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x52:
INST_NAME("RSQRTSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -260,7 +307,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x53:
INST_NAME("RCPSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -283,7 +330,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x58:
INST_NAME("ADDSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -303,7 +350,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x59:
INST_NAME("MULSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -323,7 +370,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x5A:
INST_NAME("CVTSS2SD Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s0, d0);
VCVT_F64_F32(v0, s0);
break;
@@ -331,9 +378,9 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("CVTTPS2DQ Gx, Ex");
nextop = F8;
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
v1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(v1, ed);
}
@@ -344,7 +391,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x5C:
INST_NAME("SUBSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -364,7 +411,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x5D:
INST_NAME("MINSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -379,7 +426,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
VCMP_F32(s0, s1);
VMRS_APSR();
VMOVcond_32(cPL, s0, s1);
VMOVcond_32(cCS, s0, s1); // move s0 <- s1 if s0 or s1 unordered or s0 >= s1
if(v0!=d0) {
VMOV_64(v0, d0);
}
@@ -387,7 +434,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x5E:
INST_NAME("DIVSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -407,7 +454,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0x5F:
INST_NAME("MAXSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -422,7 +469,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
VCMP_F32(s1, s0);
VMRS_APSR();
VMOVcond_32(cPL, s0, s1);
VMOVcond_32(cCS, s0, s1); // move s0 <- s1 if s0 or s1 is unordered or s1 >= s0
if(v0!=d0) {
VMOV_64(v0, d0);
}
@@ -433,12 +480,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVQ(v0, v1);
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
LDR_IMM9(x2, ed, fixedaddress+0);
LDR_IMM9(x3, ed, fixedaddress+4);
VMOVtoV_D(v0, x2, x3);
@@ -451,16 +498,16 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("PSHUFHW Gx, Ex, Ib");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd);
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
v1 = fpu_get_scratch_quad(dyn);
VLD1Q_64(v1, ed);
}
u8 = F8;
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
// only high part need to be shuffled. VTBL only handle 8bits value, so the 16bits shuffles need to be changed in 8bits
u32 = 0;
for (int i=0; i<2; ++i) {
u32 |= (((u8>>(i*2))&3)*2+0)<<(i*16+0);
@@ -487,12 +534,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
nextop = F8;
gd = (nextop&0x38)>>3;
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
VMOVD(v0, v1);
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
VLD1_64(v0, ed);
}
VEOR(v0+1, v0+1, v0+1);
@@ -501,13 +548,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
INST_NAME("MOVDQU Ex,Gx");
nextop = F8;
gd = (nextop&0x38)>>3;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
v0 = sse_get_reg(dyn, ninst, x1, gd);
VMOVQ(v1, v0);
} else {
v0 = sse_get_reg(dyn, ninst, x1, gd);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
VMOVfrV_D(x2, x3, v0);
STR_IMM9(x2, ed, fixedaddress+0);
STR_IMM9(x3, ed, fixedaddress+4);
@@ -519,26 +565,27 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
case 0xBC:
INST_NAME("TZCNT Gd, Ed");
SETFLAGS(X_CF|X_ZF, SF_SET);
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
SET_DFNONE(x3);
nextop = F8;
GETED;
GETGD;
TSTS_REG_LSL_IMM5(ed, ed, 0);
RBIT(x1, ed); // reverse
CLZ(gd, x1); // x2 gets leading 0 == TZCNT
MOVW_COND(cEQ, x1, 1);
MOVW_COND(cNE, x1, 0);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
RSB_IMM8(x1, x1, 1);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
MOVW(x1, d_none);
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
MOVW_COND(cEQ, x3, 1);
MOVW_COND(cNE, x3, 0);
BFI(xFlags, x3, F_CF, 1); // CF = is source 0?
RBIT(x3, ed); // reverse
CLZ(gd, x3); // x2 gets leading 0 == TZCNT
TSTS_REG_LSL_IMM5(gd, gd, 0);
MOVW_COND(cEQ, x3, 1);
MOVW_COND(cNE, x3, 0);
BFI(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
break;
case 0xC2:
INST_NAME("CMPSS Gx, Ex");
nextop = F8;
GETGX(v0);
GETGX(v0, 1);
GETEX(s1, v1);
if(v0==v1)
d0 = s1/2;
@@ -550,22 +597,53 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
VMOV_64(d0, v0);
}
s0 = d0*2;
u8 = F8;
VCMP_F32(s0, s1);
VMRS_APSR();
MOVW(x2, 0);
u8 = F8;
switch(u8&7) {
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal or unordered
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
}
VMOVtoDx_32(v0, 0, x2);
break;
case 0xE6:
INST_NAME("CVTDQ2PD Gx, Ex");
nextop = F8;
if((nextop&0xC0)==0xC0) {
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
if(v1<16)
v0 = v1;
else {
v0 = fpu_get_scratch_double(dyn);
VMOV_64(v0, v1); // vfpu opcode here
}
} else {
v0 = fpu_get_scratch_double(dyn);
parity = getedparity(dyn, ninst, addr, nextop, 3);
if(parity) {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
LDR_IMM9(x2, ed, fixedaddress);
LDR_IMM9(x3, ed, fixedaddress+4);
VMOVtoV_D(v0, x2, x3);
}
}
gd = (nextop&0x38)>>3;
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
//v0 is a low reg now
VCVT_F64_S32(q0+1, v0*2+1);
VCVT_F64_S32(q0+0, v0*2+0);
break;
default:
DEFAULT;
+269 -79
View File
@@ -21,20 +21,15 @@
#include "emu/x86run_private.h"
#include "emu/x87emu_private.h"
#include "x86trace.h"
#include "signals.h"
#include "dynarec_arm.h"
#include "dynarec_arm_private.h"
#include "dynarec_arm_functions.h"
void arm_popf(x86emu_t* emu, uint32_t f)
{
emu->packed_eflags.x32 = (f & 0x3F7FD7) | 0x2; // mask off res2 and res3 and on res1
UnpackFlags(emu);
RESET_FLAGS(emu);
}
#include "bridge.h"
void arm_fstp(x86emu_t* emu, void* p)
{
if(ST0.ll!=STld(0).ref)
if(ST0.q!=STld(0).uref)
D2LD(&ST0.d, p);
else
memcpy(p, &STld(0).ld, 10);
@@ -56,6 +51,7 @@ void arm_fyl2x(x86emu_t* emu)
void arm_ftan(x86emu_t* emu)
{
ST0.d = tan(ST0.d);
emu->sw.f.F87_C2 = 0;
}
void arm_fpatan(x86emu_t* emu)
{
@@ -63,7 +59,7 @@ void arm_fpatan(x86emu_t* emu)
}
void arm_fxtract(x86emu_t* emu)
{
int32_t tmp32s = (ST1.ll&0x7ff0000000000000LL)>>52;
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
tmp32s -= 1023;
ST1.d /= exp2(tmp32s);
ST0.d = tmp32s;
@@ -77,31 +73,15 @@ void arm_fprem(x86emu_t* emu)
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
}
void arm_fyl2xp1(x86emu_t* emu)
{
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
}
void arm_fsincos(x86emu_t* emu)
{
sincos(ST1.d, &ST1.d, &ST0.d);
}
void arm_frndint(x86emu_t* emu)
{
ST0.d = fpu_round(emu, ST0.d);
}
void arm_fscale(x86emu_t* emu)
{
ST0.d *= exp2(trunc(ST1.d));
if(ST0.d!=0.0)
ST0.d *= exp2(trunc(ST1.d));
}
void arm_fsin(x86emu_t* emu)
{
ST0.d = sin(ST0.d);
}
void arm_fcos(x86emu_t* emu)
{
ST0.d = cos(ST0.d);
}
void arm_fbld(x86emu_t* emu, uint8_t* ed)
{
fpu_fbld(emu, ed);
@@ -109,9 +89,11 @@ void arm_fbld(x86emu_t* emu, uint8_t* ed)
void arm_fild64(x86emu_t* emu, int64_t* ed)
{
ST0.d = *ed;
STll(0).ll = *ed;
STll(0).ref = ST0.ll;
int64_t tmp;
memcpy(&tmp, ed, sizeof(tmp));
ST0.d = tmp;
STll(0).sq = tmp;
STll(0).sref = ST0.sq;
}
void arm_fbstp(x86emu_t* emu, uint8_t* ed)
@@ -121,51 +103,36 @@ void arm_fbstp(x86emu_t* emu, uint8_t* ed)
void arm_fistp64(x86emu_t* emu, int64_t* ed)
{
if(STll(0).ref==ST(0).ll) {
*ed = STll(0).ll;
// used of memcpy to avoid aligments issues
if(STll(0).sref==ST(0).sq) {
memcpy(ed, &STll(0).sq, sizeof(int64_t));
} else {
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL))
*ed = 0x8000000000000000LL;
int64_t tmp;
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
tmp = 0x8000000000000000LL;
else
*ed = (int64_t)ST0.d;
tmp = fpu_round(emu, ST0.d);
memcpy(ed, &tmp, sizeof(tmp));
}
}
void arm_fistt64(x86emu_t* emu, int64_t* ed)
{
// used of memcpy to avoid aligments issues
int64_t tmp = ST0.d;
memcpy(ed, &tmp, sizeof(tmp));
}
void arm_fld(x86emu_t* emu, uint8_t* ed)
{
memcpy(&STld(0).ld, ed, 10);
LD2D(&STld(0), &ST(0).d);
STld(0).ref = ST0.ll;
STld(0).uref = ST0.q;
}
void arm_ud(x86emu_t* emu)
{
kill(getpid(), SIGILL);
}
void arm_fxsave(x86emu_t* emu, uint8_t* ed)
{
// should save flags & all
// copy MMX regs...
for(int i=0; i<8; ++i)
memcpy(ed+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(ed+160, &emu->xmm[0], sizeof(emu->xmm));
// put also FPU regs in a reserved area...
for(int i=0; i<8; ++i)
memcpy(ed+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
}
void arm_fxrstor(x86emu_t* emu, uint8_t* ed)
{
// should restore flags & all
// copy back MMX regs...
for(int i=0; i<8; ++i)
memcpy(&emu->mmx[i], ed+32+i*16, sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(&emu->xmm[0], ed+160/4, sizeof(emu->xmm));
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], ed+416+i*8, sizeof(emu->fpu[0]));
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
}
void arm_fsave(x86emu_t* emu, uint8_t* ed)
@@ -175,12 +142,7 @@ void arm_fsave(x86emu_t* emu, uint8_t* ed)
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
#ifdef USE_FLOAT
d = ST(i).f;
LD2D(p, &d);
#else
LD2D(p, &ST(i).d);
#endif
p+=10;
}
}
@@ -191,17 +153,23 @@ void arm_frstor(x86emu_t* emu, uint8_t* ed)
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
#ifdef USE_FLOAT
D2LD(&d, p);
ST(i).f = d;
#else
D2LD(&ST(i).d, p);
#endif
p+=10;
}
}
void arm_fprem1(x86emu_t* emu)
{
// simplified version
int32_t tmp32s = round(ST0.d / ST1.d);
ST0.d -= ST1.d*tmp32s;
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (tmp32s&1);
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
}
// Get a FPU single scratch reg
int fpu_get_scratch_single(dynarec_arm_t* dyn)
@@ -218,6 +186,13 @@ int fpu_get_scratch_double(dynarec_arm_t* dyn)
// Get a FPU quad scratch reg
int fpu_get_scratch_quad(dynarec_arm_t* dyn)
{
if(dyn->fpu_scratch>4) {
if(dyn->fpu_extra_qscratch) {
dynarec_log(LOG_NONE, "Warning, Extra QScratch slot taken and need another one!\n");
} else
dyn->fpu_extra_qscratch = fpu_get_reg_quad(dyn, NEON_CACHE_SCR, 0);
return dyn->fpu_extra_qscratch;
}
int i = (dyn->fpu_scratch+3)&(~3);
dyn->fpu_scratch = i+4;
return i/2; // Return a Dx, not a Qx
@@ -226,15 +201,20 @@ int fpu_get_scratch_quad(dynarec_arm_t* dyn)
void fpu_reset_scratch(dynarec_arm_t* dyn)
{
dyn->fpu_scratch = 0;
if(dyn->fpu_extra_qscratch) {
fpu_free_reg_quad(dyn, dyn->fpu_extra_qscratch);
dyn->fpu_extra_qscratch = 0;
}
}
#define FPUFIRST 8
// Get a FPU double reg
int fpu_get_reg_double(dynarec_arm_t* dyn)
int fpu_get_reg_double(dynarec_arm_t* dyn, unsigned int t, unsigned int n)
{
// TODO: check upper limit?
int i=0;
while (dyn->fpuused[i]) ++i;
dyn->fpuused[i] = 1;
dyn->n.neoncache[i].n = n;
dyn->n.neoncache[i].t = t;
return i+FPUFIRST; // return a Dx
}
// Free a FPU double reg
@@ -243,13 +223,19 @@ void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
// TODO: check upper limit?
int i=reg-FPUFIRST;
dyn->fpuused[i] = 0;
if(dyn->n.neoncache[i].t!=NEON_CACHE_ST_F && dyn->n.neoncache[i].t!=NEON_CACHE_ST_D)
dyn->n.neoncache[i].v = 0;
}
// Get a FPU quad reg
int fpu_get_reg_quad(dynarec_arm_t* dyn)
int fpu_get_reg_quad(dynarec_arm_t* dyn, unsigned int t, unsigned int n)
{
int i=0;
while (dyn->fpuused[i] || dyn->fpuused[i+1]) i+=2;
dyn->fpuused[i] = dyn->fpuused[i+1] = 1;
dyn->n.neoncache[i].t = t;
dyn->n.neoncache[i].n = n;
dyn->n.neoncache[i+1].t = t;
dyn->n.neoncache[i+1].n = n;
return i+FPUFIRST; // Return a Dx, not a Qx
}
// Free a FPU quad reg
@@ -257,20 +243,171 @@ void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
{
int i=reg-FPUFIRST;
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
dyn->n.neoncache[i].v = 0;
dyn->n.neoncache[i+1].v = 0;
}
// Reset fpu regs counter
void fpu_reset_reg(dynarec_arm_t* dyn)
{
dyn->fpu_reg = 0;
for (int i=0; i<24; ++i)
for (int i=0; i<24; ++i) {
dyn->fpuused[i]=0;
dyn->n.neoncache[i].v = 0;
}
}
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
{
if(!dyn->insts)
return NEON_CACHE_ST_D;
for(int i=0; i<24; ++i)
if((dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
&& dyn->insts[ninst].n.neoncache[i].n==a)
return dyn->insts[ninst].n.neoncache[i].t;
// not in the cache yet, so will be fetched...
return NEON_CACHE_ST_D;
}
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
{
(void)ninst;
if(!dyn->insts)
return NEON_CACHE_ST_D;
for(int i=0; i<24; ++i)
if((dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_D)
&& dyn->n.neoncache[i].n==a)
return dyn->n.neoncache[i].t;
// not in the cache yet, so will be fetched...
return NEON_CACHE_ST_D;
}
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st)
{
if(a+dyn->insts[ninst].n.stack_next-st<0)
// The STx has been pushed at the end of instructon, so stop going back
return -1;
for(int i=0; i<24; ++i)
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
&& dyn->insts[ninst].n.neoncache[i].n==a+dyn->insts[ninst].n.stack-st)
return i;
return -1;
}
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a, int st)
{
for(int i=0; i<24; ++i)
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
&& dyn->insts[ninst].n.neoncache[i].n==a+dyn->insts[ninst].n.stack-st)
return i;
return -1;
}
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a, int st)
{
for(int i=0; i<24; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_ST_F
&& dyn->n.neoncache[i].n==a+dyn->n.stack-st)
return i;
return -1;
}
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st);
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st);
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
{
if(a == dyn->insts[ninst].n.combined1) {
int i = neoncache_get_st_f_noback(dyn, ninst, dyn->insts[ninst].n.combined2, st);
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined2 %d i=%d\n", ninst, dyn->insts[ninst].n.combined2 ,i);
if(i>=0) {
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
neoncache_promote_double_internal(dyn, ninst-1, maxinst, dyn->insts[ninst].n.combined2, st);
// go forward is combined is not pop'd
if(dyn->insts[ninst].n.stack_next-dyn->insts[ninst].n.stack<=dyn->insts[ninst].n.combined2)
neoncache_promote_double_forward(dyn, ninst+1, maxinst, dyn->insts[ninst].n.combined2, st);
}
} else if(a == dyn->insts[ninst].n.combined2) {
int i = neoncache_get_st_f_noback(dyn, ninst, dyn->insts[ninst].n.combined1, st);
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined1 %d i=%d\n", ninst, dyn->insts[ninst].n.combined1 ,i);
if(i>=0) {
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
neoncache_promote_double_internal(dyn, ninst-1, maxinst, dyn->insts[ninst].n.combined1, st);
// go forward is combined is not pop'd
if(dyn->insts[ninst].n.stack_next-dyn->insts[ninst].n.stack<=dyn->insts[ninst].n.combined1)
neoncache_promote_double_forward(dyn, ninst+1, maxinst, dyn->insts[ninst].n.combined1, st);
}
}
}
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
{
while(ninst>=0) {
int i = neoncache_get_st_f(dyn, ninst, a, st);
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d/%d, i=%d\n", ninst, a, st, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
if(i<0) return;
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
a+=dyn->insts[ninst].n.stack-st; // adjust STx
st = dyn->insts[ninst].n.stack; // new stack depth
// check combined propagation too
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d/%d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, st, dyn->insts[ninst].n.stack);
neoncache_promote_double_combined(dyn, ninst, maxinst, a, st);
}
--ninst;
}
}
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
{
while(ninst<maxinst) {
int i = neoncache_get_st_f_noback(dyn, ninst, a, st);
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d/%d, i=%d\n", ninst, a, st, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
if(i<0) return;
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
a+=dyn->insts[ninst].n.stack-st; // adjust STx
st = dyn->insts[ninst].n.stack; // new stack depth
// check combined propagation too
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d/%d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, st, dyn->insts[ninst].n.stack);
neoncache_promote_double_combined(dyn, ninst, maxinst, a, st);
}
++ninst;
}
neoncache_promote_double(dyn, ninst, a, st);
}
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st)
{
int i = neoncache_get_current_st_f(dyn, a, st);
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d/%d i=%d\n", ninst, a, st, dyn->n.stack, i);
if(i<0) return;
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
a+=dyn->n.stack-st;
st = dyn->n.stack;
// check combined propagation too
if(dyn->n.combined1 || dyn->n.combined2) {
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
if(dyn->n.combined1 == a)
neoncache_promote_double(dyn, ninst, dyn->n.combined2, st);
else if(dyn->n.combined2 == a)
neoncache_promote_double(dyn, ninst, dyn->n.combined1, st);
}
if(!ninst) return;
neoncache_promote_double_internal(dyn, ninst-1, ninst, a, st);
}
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
{
dyn->n.combined1=a;
dyn->n.combined2=b;
if( neoncache_get_current_st(dyn, ninst, a)==NEON_CACHE_ST_F
&& neoncache_get_current_st(dyn, ninst, b)==NEON_CACHE_ST_F )
return NEON_CACHE_ST_F;
return NEON_CACHE_ST_D;
}
#define F8 *(uint8_t*)(addr++)
#define F32 *(uint32_t*)(addr+=4, addr-4)
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity)
{
#define F8 *(uint8_t*)(addr++)
#define F32 *(uint32_t*)(addr+=4, addr-4)
uint32_t tested = (1<<parity)-1;
if((nextop&0xC0)==0xC0)
@@ -289,7 +426,7 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
return (tmp&tested)?0:1;
}
} else {
if(sib_reg==4)
if(sib_reg==4 && parity<3)
return 0; // simple [reg]
// don't try [reg1 + reg2<<N], unless reg1 is ESP
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
@@ -303,6 +440,59 @@ int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, i
} else {
return 0; //Form [reg1 + reg2<<N + XXXXXX]
}
}
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
{
if((nextop&0xC0)==0xC0)
return addr;
if(!(nextop&0xC0)) {
if((nextop&7)==4) {
uint8_t sib = F8;
if((sib&0x7)==5) {
addr+=4;
}
} else if((nextop&7)==5) {
addr+=4;
}
} else {
if((nextop&7)==4) {
++addr;
}
if(nextop&0x80) {
addr+=4;
} else {
++addr;
}
}
return addr;
}
#undef F8
#undef F32
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
{
#define PK(a) *(uint8_t*)(addr+a)
#define PK32(a) *(uint32_t*)(addr+a)
if(!addr)
return 0;
if(PK(0)==0xff && PK(1)==0x25) { // absolute jump, maybe the GOT
uintptr_t a1 = (PK32(2)); // need to add a check to see if the address is from the GOT !
addr = (uintptr_t)getAlternate(*(void**)a1);
}
if(addr<0x10000) // too low, that is suspicious
return 0;
onebridge_t *b = (onebridge_t*)(addr);
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
// found !
if(retn) *retn = (b->C3==0xC2)?b->N:0;
if(calladdress) *calladdress = addr+1;
return 1;
}
return 0;
#undef PK32
#undef PK
}
+24 -13
View File
@@ -3,35 +3,30 @@
typedef struct x86emu_s x86emu_t;
void arm_popf(x86emu_t* emu, uint32_t f);
void arm_fstp(x86emu_t* emu, void* p);
void arm_print_armreg(x86emu_t* emu, uintptr_t reg, uintptr_t n);
void arm_f2xm1(x86emu_t* emu);
void arm_fyl2x(x86emu_t* emu);
void arm_ftan(x86emu_t* emu);
void arm_fpatan(x86emu_t* emu);
void arm_fxtract(x86emu_t* emu);
void arm_fprem(x86emu_t* emu);
void arm_fyl2xp1(x86emu_t* emu);
void arm_fsincos(x86emu_t* emu);
void arm_frndint(x86emu_t* emu);
void arm_fscale(x86emu_t* emu);
void arm_fsin(x86emu_t* emu);
void arm_fcos(x86emu_t* emu);
void arm_fbld(x86emu_t* emu, uint8_t* ed);
void arm_fild64(x86emu_t* emu, int64_t* ed);
void arm_fbstp(x86emu_t* emu, uint8_t* ed);
void arm_fbst(x86emu_t* emu, uint8_t* ed);
void arm_fistp64(x86emu_t* emu, int64_t* ed);
void arm_fistt64(x86emu_t* emu, int64_t* ed);
void arm_fld(x86emu_t* emu, uint8_t* ed);
void arm_fxsave(x86emu_t* emu, uint8_t* ed);
void arm_fxrstor(x86emu_t* emu, uint8_t* ed);
void arm_fsave(x86emu_t* emu, uint8_t* ed);
void arm_frstor(x86emu_t* emu, uint8_t* ed);
void arm_fprem1(x86emu_t* emu);
void arm_ud(x86emu_t* emu);
#define FPUFIRST 8
// Get an FPU single scratch reg
int fpu_get_scratch_single(dynarec_arm_t* dyn);
// Get an FPU double scratch reg
@@ -40,18 +35,34 @@ int fpu_get_scratch_double(dynarec_arm_t* dyn);
int fpu_get_scratch_quad(dynarec_arm_t* dyn);
// Reset scratch regs counter
void fpu_reset_scratch(dynarec_arm_t* dyn);
// Get an FPU double reg
int fpu_get_reg_double(dynarec_arm_t* dyn);
// Get an FPU double reg, with NEON_CACHE_TYPE
int fpu_get_reg_double(dynarec_arm_t* dyn, unsigned int t, unsigned int n);
// Free a FPU double reg
void fpu_free_reg_double(dynarec_arm_t* dyn, int reg);
// Get an FPU quad reg
int fpu_get_reg_quad(dynarec_arm_t* dyn);
int fpu_get_reg_quad(dynarec_arm_t* dyn, unsigned int t, unsigned int n);
// Free a FPU quad reg
void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg);
// Reset fpu regs counter
void fpu_reset_reg(dynarec_arm_t* dyn);
// ---- Neon cache functions
// Get type for STx
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
// Get if STx is FLOAT or DOUBLE
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st);
// Get actual type for STx
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
// Back-propagate a change float->double
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st);
// Combine and propagate if needed (pass 1 only)
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
// Is what pointed at addr a native call? And if yes, to what function?
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
#endif //__DYNAREC_ARM_FUNCTIONS_H__
File diff suppressed because it is too large. Load diff
+211 -128
View File
@@ -22,9 +22,10 @@
#define F32 *(uint32_t*)(addr+=4, addr-4)
#define F32S *(int32_t*)(addr+=4, addr-4)
#define PK(a) *(uint8_t*)(addr+a)
#define PK32(a) *(uint32_t*)(addr+a)
#define PK16(a) *(uint16_t*)(addr+a)
#define PKip(a) *(uint8_t*)(ip+a)
#define PK32(a) *(uint32_t*)(addr+a)
#define PK16(a) *(uint16_t*)(addr+a)
#define PKip(a) *(uint8_t*)(ip+a)
#define PKa(a) *(uint8_t*)(a)
// GETGD get x86 register in gd
#define GETGD gd = xEAX+((nextop&0x38)>>3)
@@ -33,7 +34,7 @@
ed = xEAX+(nextop&7); \
wback = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0); \
LDR_IMM9(x1, wback, fixedaddress); \
ed = x1; \
}
@@ -42,7 +43,7 @@
ed = xEAX+(nextop&7); \
wback = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0, 0); \
LDR_IMM9(hint, wback, fixedaddress); \
ed = hint; \
}
@@ -52,7 +53,7 @@
MOV_REG(ret, ed); \
wback = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0, 0); \
ed = ret; \
LDR_IMM9(ed, wback, fixedaddress); \
}
@@ -65,10 +66,20 @@
ed = xEAX+(nextop&7); \
wback = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
ed = x1; \
}
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI, else O is added to wback
#define GETEDO2(O) if((nextop&0xC0)==0xC0) { \
ed = xEAX+(nextop&7); \
wback = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
ADD_REG_LSL_IMM5(wback, wback, O, 0);\
LDR_IMM9(x1, wback, 0); \
ed = x1; \
}
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0);}
//FAKEELike GETED, but doesn't get anything
#define FAKEED if((nextop&0xC0)!=0xC0) { \
@@ -83,7 +94,7 @@
ed = i; \
wb1 = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0, 0); \
LDRH_IMM8(i, wback, fixedaddress); \
ed = i; \
wb1 = 1; \
@@ -95,7 +106,7 @@
ed = i; \
wb1 = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
LDRH_IMM8(i, wback, fixedaddress); \
ed = i; \
wb1 = 1; \
@@ -107,7 +118,7 @@
ed = i; \
wb1 = 0; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
LDRSH_IMM8(i, wback, fixedaddress);\
ed = i; \
wb1 = 1; \
@@ -127,11 +138,26 @@
wb1 = 0; \
ed = i; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0); \
LDRB_IMM9(i, wback, fixedaddress); \
wb1 = 1; \
ed = i; \
}
//GETEBO will use i for ed, i is also Offset, and can use r3 for wback.
#define GETEBO(i) if((nextop&0xC0)==0xC0) { \
wback = (nextop&7); \
wb2 = (wback>>2); \
wback = xEAX+(wback&3); \
UXTB(i, wback, wb2); \
wb1 = 0; \
ed = i; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0); \
ADD_REG_LSL_IMM5(wback, wback, i, 0); \
LDRB_IMM9(i, wback, fixedaddress); \
wb1 = 1; \
ed = i; \
}
//GETSEB sign extend EB, will use i for ed, and can use r3 for wback.
#define GETSEB(i) if((nextop&0xC0)==0xC0) { \
wback = (nextop&7); \
@@ -141,7 +167,7 @@
wb1 = 0; \
ed = i; \
} else { \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
LDRSB_IMM8(i, wback, fixedaddress);\
wb1 = 1; \
ed = i; \
@@ -164,18 +190,28 @@
#define GBBACK BFI(gb1, gd, gb2*8, 8);
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
#define GETDIR(r, A) \
LDR_IMM9(r, xEmu, offsetof(x86emu_t, flags[F_DF])); \
CMPS_IMM8(r, 1); \
MOVW(r, A); \
RSB_COND_IMM8(cEQ, r, r, 0)
TSTS_IMM8_ROR(xFlags, 1, 0x0b); \
MOVW(r, A); \
RSB_COND_IMM8(cNE, r, r, 0)
// CALL will use x12 for the call address. Return value can be put in ret (unless ret is -1)
// CALL will use x14 for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2
#define CALL(F, ret, M) call_c(dyn, ninst, F, x12, ret, M)
#define CALL(F, ret, M) call_c(dyn, ninst, F, x14, ret, M, 1)
// CALL_ will use x3 for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M)
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 1)
// CALL_S will use x3 for the call address. Return value can be put in ret (unless ret is -1)
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
#define CALL_S(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 0)
// CALL_1D will use x3 for the call address. Return value in D0, 1 ARG in D0
#define CALL_1D(F, M) call_d(dyn, ninst, F, NULL, 1, x3, -1, M, 0)
// CALL_2D will use x3 for the call address. Return value in D0, 2 ARGs in D0, D1
#define CALL_2D(F, M) call_d(dyn, ninst, F, NULL, 2, x3, -1, M, 0)
// CALL_1DD will use x3 for the call address. Return value in D0, 1 ARG in D0, cals 2 functions in a row
#define CALL_1DD(F, F2, M) call_d(dyn, ninst, F, F2, 1, x3, -1, M, 0)
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
@@ -186,101 +222,97 @@
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = (uintptr_t)dyn->arm_size;}
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
#define MARKLOCK if(dyn->insts) {dyn->insts[ninst].marklock = (uintptr_t)dyn->arm_size;}
#define GETMARKLOCK ((dyn->insts)?dyn->insts[ninst].marklock:(dyn->arm_size+4))
// Branch to MARK if cond (use i32)
// Branch to MARK if cond (use j32)
#define B_MARK(cond) \
i32 = GETMARK-(dyn->arm_size+8); \
Bcond(cond, i32)
// Branch to MARK2 if cond (use i32)
j32 = GETMARK-(dyn->arm_size+8); \
Bcond(cond, j32)
// Branch to MARK2 if cond (use j32)
#define B_MARK2(cond) \
i32 = GETMARK2-(dyn->arm_size+8); \
Bcond(cond, i32)
// Branch to MARK3 if cond (use i32)
j32 = GETMARK2-(dyn->arm_size+8); \
Bcond(cond, j32)
// Branch to MARK3 if cond (use j32)
#define B_MARK3(cond) \
i32 = GETMARK3-(dyn->arm_size+8); \
Bcond(cond, i32)
// Branch to next instruction if cond (use i32)
j32 = GETMARK3-(dyn->arm_size+8); \
Bcond(cond, j32)
// Branch to next instruction if cond (use j32)
#define B_NEXT(cond) \
i32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
Bcond(cond, i32)
// Branch to MARKSEG if cond (use i32)
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
Bcond(cond, j32)
// Branch to MARKSEG if cond (use j32)
#define B_MARKSEG(cond) \
i32 = GETMARKSEG-(dyn->arm_size+8); \
Bcond(cond, i32)
j32 = GETMARKSEG-(dyn->arm_size+8); \
Bcond(cond, j32)
// Branch to MARKLOCK if cond (use j32)
#define B_MARKLOCK(cond) \
j32 = GETMARKLOCK-(dyn->arm_size+8); \
Bcond(cond, j32)
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A)))
#define IFXX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A)))
#define IFX2X(A, B) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
#define IFX(A) if((dyn->insts[ninst].x86.need_flags&(A)))
#define IFX_PENDOR0 if((dyn->insts[ninst].x86.need_flags&(X_PEND) || !dyn->insts[ninst].x86.need_flags))
#define IFXX(A) if((dyn->insts[ninst].x86.need_flags==(A)))
#define IFX2X(A, B) if((dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
#define IFXN(A, B) if((dyn->insts[ninst].x86.need_flags&(A) && !(dyn->insts[ninst].x86.need_flags&(B))))
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
#define FCOM(s1, s2) \
VMRS_APSR(); /* 0b0100011100000000 */ \
LDRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
MOVW(s1, 0b0100011100000000); \
BIC_REG_LSL_IMM5(s2, s2, s1, 0); \
MOVW_COND(cVS, s1, 0b0100010100000000); /* unordered */ \
MOVW_COND(cEQ, s1, 0b0100000000000000); /* zero */ \
MOVW_COND(cGT, s1, 0b0000000000000000); /* greater than */ \
MOVW_COND(cLO, s1, 0b0000000100000000); /* less than */ \
ORR_REG_LSL_IMM5(s2, s2, s1, 0); \
STRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw))
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
BIC_IMM8(s1, s1, 0b01000111, 12); \
ORR_IMM8_COND(cVS, s1, s1, 0b01000101, 12); /* unordered */ \
ORR_IMM8_COND(cEQ, s1, s1, 0b01000000, 12); /* equal */ \
ORR_IMM8_COND(cMI, s1, s1, 0b00000001, 12); /* less than */ \
/* greater than leave 0 */ \
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw))
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
#define FCOMI(s1, s2) \
VMRS_APSR(); /* 0b111 */ \
XOR_REG_LSL_IMM5(s2, s2, s2, 0); \
MOVW_COND(cVS, s1, 0b111); /* unordered */ \
MOVW_COND(cEQ, s1, 0b100); /* zero */ \
MOVW_COND(cGT, s1, 0b000); /* greater than */ \
MOVW_COND(cLO, s1, 0b001); /* less than */ \
IFX(X_CF|X_PEND) { \
UBFX(s2, s1, 0, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_CF]));\
} \
IFX(X_PF|X_PEND) { \
UBFX(s2, s1, 1, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_PF]));\
} \
IFX(X_ZF|X_PEND) { \
UBFX(s2, s1, 2, 1); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_ZF]));\
} \
MOVW(s2, d_none); \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, df)); \
IFX(X_OF|X_PEND) { \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_OF]));\
} \
IFX(X_AF|X_PEND) { \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_AF]));\
} \
IFX(X_SF|X_PEND) { \
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_SF]));\
} \
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
VMRS_APSR(); /* 0b111 */ \
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b01000101, 0); /* unordered */ \
ORR_IMM8_COND(cEQ, xFlags, xFlags, 0b01000000, 0); /* zero */ \
ORR_IMM8_COND(cMI, xFlags, xFlags, 0b00000001, 0); /* less than */ \
/* greater than leave 0 */ \
} \
SET_DFNONE(s1); \
IFX(X_OF|X_AF|X_SF|X_PEND) { \
/* clear 0b100010010000 */ \
BIC_IMM8(xFlags, xFlags, 0b10001001, 14); \
} \
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=1;}
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
#define SET_NODF() dyn->dfnone = 0
#define SET_DFOK() dyn->dfnone = 1
#ifndef READFLAGS
#define READFLAGS(A) \
if(dyn->state_flags!=SF_SET) { \
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET && dyn->state_flags!=SF_SET_PENDING) { \
if(dyn->state_flags!=SF_PENDING) { \
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
TSTS_REG_LSL_IMM5(x3, x3, 0); \
i32 = (GETMARKF)-(dyn->arm_size+8); \
Bcond(cEQ, i32); \
j32 = (GETMARKF)-(dyn->arm_size+8); \
Bcond(cEQ, j32); \
} \
CALL_(UpdateFlags, -1, 0); \
MARKF; \
dyn->state_flags = SF_SET; \
SET_DFOK(); \
}
#endif
#ifndef SETFLAGS
#define SETFLAGS(A, B) \
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)|X_PEND)))) \
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A))); \
dyn->state_flags = (B==SF_SUBSET)?SF_SET:B
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)/*|X_PEND*/)))) \
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A)|X_PEND)); \
dyn->state_flags = (B==SF_SUBSET)?SF_SET: \
((B==SF_SET_PENDING && !(dyn->insts[ninst].x86.need_flags&X_PEND)?SF_SET:B))
#endif
#ifndef JUMP
#define JUMP(A)
#define JUMP(A, C)
#endif
#ifndef BARRIER
#define BARRIER(A)
@@ -288,12 +320,12 @@
#ifndef BARRIER_NEXT
#define BARRIER_NEXT(A)
#endif
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, 0, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {MOVW(r, A); STR_IMM9(r, 0, offsetof(x86emu_t, df));}
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x86.need_flags)
#define UFLAG_OP1(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
#define UFLAG_OP2(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x86.need_flags) {SET_DF(r, A)}
#define UFLAG_IF if(dyn->insts[ninst].x86.need_flags)
#ifndef DEFAULT
#define DEFAULT *ok = -1; BARRIER(2)
#endif
@@ -301,14 +333,16 @@
#define NEW_BARRIER_INST
#endif
// Emit the LOCK mutex (x1, x2 and x3 are lost)
#define LOCK emit_lock(dyn, addr, ninst)
// Emit the UNLOCK mutex (x1, x2 and x3 are lost)
#define UNLOCK emit_unlock(dyn, addr, ninst)
#if STEP < 2
#define PASS2IF(A, B) if(A)
#elif STEP == 2
#define PASS2IF(A, B) if(A) dyn->insts[ninst].pass2choice = B; if(dyn->insts[ninst].pass2choice == B)
#else
#define PASS2IF(A, B) if(dyn->insts[ninst].pass2choice == B)
#endif
void arm_epilog();
void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
void* arm_next(x86emu_t* emu, uintptr_t addr);
#ifndef STEPNAME
#define STEPNAME3(N,M) N##M
@@ -338,18 +372,16 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define dynarecF30F STEPNAME(dynarecF30F)
#define geted STEPNAME(geted_)
#define fakeed STEPNAME(fakeed_)
#define geted16 STEPNAME(geted16_)
#define jump_to_epilog STEPNAME(jump_to_epilog_)
#define jump_to_linker STEPNAME(jump_to_linker_)
#define jump_to_next STEPNAME(jump_to_next_)
#define ret_to_epilog STEPNAME(ret_to_epilog_)
#define retn_to_epilog STEPNAME(retn_to_epilog_)
#define iret_to_epilog STEPNAME(iret_to_epilog_)
#define call_c STEPNAME(call_c_)
#define call_d STEPNAME(call_d_)
#define grab_fsdata STEPNAME(grab_fsdata_)
#define grab_tlsdata STEPNAME(grab_tlsdata_)
#define isNativeCall STEPNAME(isNativeCall_)
#define emit_lock STEPNAME(emit_lock)
#define emit_unlock STEPNAME(emit_unlock)
#define emit_cmp8 STEPNAME(emit_cmp8)
#define emit_cmp16 STEPNAME(emit_cmp16)
#define emit_cmp32 STEPNAME(emit_cmp32)
@@ -410,23 +442,36 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define emit_neg32 STEPNAME(emit_neg32)
#define emit_neg16 STEPNAME(emit_neg16)
#define emit_neg8 STEPNAME(emit_neg8)
#define emit_shl32 STEPNAME(emit_shl32)
#define emit_shl32c STEPNAME(emit_shl32c)
#define emit_shr32 STEPNAME(emit_shr32)
#define emit_shr32c STEPNAME(emit_shr32c)
#define emit_sar32c STEPNAME(emit_sar32c)
#define emit_rol32c STEPNAME(emit_rol32c)
#define emit_rol8c STEPNAME(emit_rol8c)
#define emit_ror32c STEPNAME(emit_ror32c)
#define emit_ror8c STEPNAME(emit_ror8c)
#define emit_shrd32c STEPNAME(emit_shrd32c)
#define emit_shld32c STEPNAME(emit_shld32c)
#define emit_shrd32 STEPNAME(emit_shrd32)
#define emit_pf STEPNAME(emit_pf)
#define x87_do_push STEPNAME(x87_do_push)
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
#define x87_do_pop STEPNAME(x87_do_pop)
#define x87_get_current_cache STEPNAME(x87_get_current_cache)
#define x87_get_cache STEPNAME(x87_get_cache)
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
#define x87_get_st STEPNAME(x87_get_st)
#define x87_get_st_empty STEPNAME(x87_get_st)
#define x87_refresh STEPNAME(x87_refresh)
#define x87_forget STEPNAME(x87_forget)
#define x87_reget_st STEPNAME(x87_reget_st)
#define x87_stackcount STEPNAME(x87_stackcount)
#define x87_setround STEPNAME(x87_setround)
#define x87_restoreround STEPNAME(x87_restoreround)
#define sse_setround STEPNAME(sse_setround)
#define mmx_get_reg STEPNAME(mmx_get_reg)
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
#define sse_get_reg STEPNAME(sse_get_reg)
@@ -436,12 +481,11 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define fpu_popcache STEPNAME(fpu_popcache)
#define fpu_reset STEPNAME(fpu_reset)
#define fpu_purgecache STEPNAME(fpu_purgecache)
#define x87_purgecache STEPNAME(x87_purgecache)
#define mmx_purgecache STEPNAME(mmx_purgecache)
#ifdef HAVE_TRACE
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
#endif
#define cstack_push STEPNAME(cstack_push)
#define cstack_pop STEPNAME(cstack_pop)
// get the single reg that from the double "reg" (so Dx[idx])
#define fpu_get_single_reg STEPNAME(fpu_get_single_reg)
@@ -449,21 +493,22 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
#define fpu_putback_single_reg STEPNAME(fpu_putback_single_reg)
/* setup r2 to address pointed by */
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly);
/* setup r2 to address pointed by */
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
// Do the GETED, but don't emit anything...
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
// generic x86 helper
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask);
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg, int ret, uint32_t mask, int saveflags);
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
void emit_unlock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
@@ -489,21 +534,21 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
@@ -526,25 +571,40 @@ void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
// x87 helper
// cache of the local stack counter, to avoid upadte at every call
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
// fpu push. Return the Dd value to be used
int x87_do_push(dynarec_arm_t* dyn, int ninst);
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t);
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1);
// fpu pop. All previous returned Dd should be considered invalid
void x87_do_pop(dynarec_arm_t* dyn, int ninst);
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1);
// get cache index for a x87 reg, return -1 if cache doesn't exist
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t);
// get cache index for a x87 reg, create the entry if needed
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, int a, int t);
// get neoncache index for a x87 reg
int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
// get vfpu register for a x87 reg, create the entry if needed
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
// refresh a value from the cache ->emu (nothing done if value is not cached)
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
@@ -555,24 +615,52 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// Restore round flag
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
// Set rounding according to mxcsr flags, return reg to restore flags
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
#if STEP == 0
#define ST_IS_F(A) 0
#define X87_COMBINE(A, B) NEON_CACHE_ST_D
#define X87_ST0 NEON_CACHE_ST_D
#define X87_ST(A) NEON_CACHE_ST_D
#elif STEP == 1
#define ST_IS_F(A) (neoncache_get_current_st(dyn, ninst, A)==NEON_CACHE_ST_F)
#define X87_COMBINE(A, B) neoncache_combine_st(dyn, ninst, A, B)
#define X87_ST0 neoncache_get_current_st(dyn, ninst, 0)
#define X87_ST(A) neoncache_get_current_st(dyn, ninst, A)
#else
#define ST_IS_F(A) (neoncache_get_st(dyn, ninst, A)==NEON_CACHE_ST_F)
#if STEP == 3
#define X87_COMBINE(A, B) neoncache_st_coherency(dyn, ninst, A, B)
#else
#define X87_COMBINE(A, B) neoncache_get_st(dyn, ninst, A)
#endif
#define X87_ST0 neoncache_get_st(dyn, ninst, 0)
#define X87_ST(A) neoncache_get_st(dyn, ninst, A)
#endif
//MMX helpers
// get neon register for a MMX reg, create the entry if needed
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
//SSE/SSE2 helpers
// get neon register for a SSE reg, create the entry if needed
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite);
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
// common coproc helpers
// reset the cache
void fpu_reset(dynarec_arm_t* dyn, int ninst);
// purge the FPU cache (needs 3 scratch registers)
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// purge the FPU cache (needs 3 scratch registers) next=1 if for a conditionnal branch jumping out of block (no tracking updated)
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
#ifdef HAVE_TRACE
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
#endif
@@ -603,11 +691,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
// PUSH a x86/native couple of address in cstack, using s1, s2, s2+1
void cstack_push(dynarec_arm_t* dyn, int ninst, uintptr_t x86ip, uintptr_t armip, int s1, int s2);
// POP a x86/native couple of address from cstack, and generate the jump is x86 address is s0, use s1, s2 and s2+1 as scratch
void cstack_pop(dynarec_arm_t* dyn, int ninst, int s0, int s1, int s2);
#if STEP < 2
#define PASS2(A)
#else
+62 -24
View File
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include "debug.h"
#include "box86context.h"
@@ -19,42 +20,56 @@
#include "arm_printer.h"
#include "dynarec_arm_functions.h"
#include "dynarec_arm_helper.h"
#include "custommem.h"
#ifndef STEP
#error No STEP defined
#endif
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
{
int ok = 1;
int ninst = 0;
uintptr_t ip = addr;
uintptr_t init_addr = addr;
MAYUSE(init_addr);
int need_epilog = 1;
dyn->tablei = 0;
dyn->sons_size = 0;
// Clean up (because there are multiple passes)
dyn->state_flags = 0;
dyn->dfnone = 0;
fpu_reset(dyn, ninst);
// ok, go now
INIT;
while(ok) {
if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
ip = addr;
if(dyn->insts && (dyn->insts[ninst].x86.barrier==1)) {
if((dyn->insts[ninst].x86.barrier==1)) {
NEW_BARRIER_INST;
}
// propagate ST stack state, especial stack pop that are defered
if(dyn->n.stack_pop) {
for(int j=0; j<24; ++j)
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
dyn->n.neoncache[j].v = 0;
else
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
}
dyn->n.stack_pop = 0;
}
dyn->n.stack = dyn->n.stack_next;
NEW_INST;
fpu_reset_scratch(dyn);
#ifdef HAVE_TRACE
if(my_context->dec && box86_dynarec_trace) {
if((trace_end == 0)
|| ((ip >= trace_start) && (ip <= trace_end))) {
|| ((ip >= trace_start) && (ip < trace_end))) {
MESSAGE(LOG_DUMP, "TRACE ----\n");
fpu_reflectcache(dyn, ninst, x1, x2, x3);
MOV32(1, ip);
STM(0, (1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11));
STR_IMM9(1, 0, offsetof(x86emu_t, ip));
MOV32(2, 1);
MOV32(x1, ip);
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
MOVW(x2, 1);
CALL(PrintTrace, -1, 0);
MESSAGE(LOG_DUMP, "----------\n");
}
@@ -65,30 +80,53 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
INST_EPILOG;
if(dyn->insts && dyn->insts[ninst+1].x86.barrier) {
fpu_purgecache(dyn, ninst, x1, x2, x3);
if(dyn->insts[ninst+1].x86.barrier!=2)
if(dyn->insts[ninst+1].x86.barrier) {
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
if(dyn->insts[ninst+1].x86.barrier!=2) {
dyn->state_flags = 0;
}
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
ok = 1;
}
if(!ok && !need_epilog && !dyn->insts) { // check if need to continue
uintptr_t next = get_closest_next(dyn, addr);
if(next && ((next-addr)<15) && is_nops(dyn, addr, next-addr)) {
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
ok = 1;
} else if(next && (next-addr)<15) {
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4));
dyn->dfnone = 0;
}
}
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
ok = 1;
}
#if STEP == 0
if(!ok && !need_epilog && box86_dynarec_bigblock && getProtection(addr+3))
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
uintptr_t next = get_closest_next(dyn, addr);
if(next && (
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
{
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
ok = 1;
} else if(next && (next-addr)<30) {
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
}
}
#endif
if(ok<0) {ok = 0; need_epilog=1;}
++ninst;
#if STEP == 0
if(ok && !isJumpTableDefault((void*)addr))
#else
if(ok && (ninst==dyn->size))
#endif
{
#if STEP == 3
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
#endif
BARRIER(2);
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
jump_to_next(dyn, addr, 0, ninst);
ok=0; need_epilog=0;
}
}
if(need_epilog) {
fpu_purgecache(dyn, ninst, x1, x2, x3);
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
}
FINI;
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
return addr;
}
+25 -8
View File
@@ -1,22 +1,39 @@
#define INIT uintptr_t sav_addr=addr
#define FINI dyn->isize = addr-sav_addr
#define FINI \
dyn->isize = addr-sav_addr;\
dyn->insts[ninst].x86.addr = addr;\
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr
#define MESSAGE(A, ...)
#define SETFLAGS(A, B)
#define READFLAGS(A)
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
#define EMIT(A)
#define JUMP(A) add_next(dyn, (uintptr_t)A)
#define NEW_INST ++dyn->size
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x86.barrier = A
#define NEW_INST \
++dyn->size; \
if(dyn->size+3>=dyn->cap) { \
dyn->insts = (instruction_arm_t*)realloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2); \
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \
dyn->cap *= 2; \
} \
dyn->insts[ninst].x86.addr = ip; \
if(ninst) {dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;}
#define INST_EPILOG
#define INST_NAME(name)
#define DEFAULT \
--dyn->size; \
*ok = -1; \
dynarec_log(LOG_INFO, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X (%s)\n", \
if(box86_dynarec_log>=LOG_INFO) {\
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
(void*)ip, PKip(0), \
PKip(1), PKip(2), PKip(3), \
PKip(4), PKip(5), PKip(6), \
PKip(7), PKip(8), PKip(9), \
PKip(10),PKip(11),PKip(12), \
PKip(13),PKip(14), \
GetNativeName((void*)addr))
PKip(13),PKip(14)); \
printFunctionAddr(ip, " => "); \
dynarec_log(LOG_NONE, "\n"); \
}
+7 -12
View File
@@ -1,17 +1,12 @@
#define INIT
#define FINI \
dyn->insts[ninst].x86.addr = addr; \
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;
#define FINI
#define MESSAGE(A, ...)
#define EMIT(A)
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
#define JUMP(A) dyn->insts[ninst].x86.jmp = A
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
#define BARRIER_NEXT(A) if(ninst+1<dyn->size) dyn->insts[ninst+1].x86.barrier = A
#define READFLAGS(A)
#define SETFLAGS(A,B)
#define NEW_INST dyn->n.combined1 = dyn->n.combined2 = 0
#define INST_EPILOG dyn->insts[ninst].n = dyn->n
#define NEW_INST \
dyn->insts[ninst].x86.addr = ip; \
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;
#define INST_EPILOG
#define INST_NAME(name)
+24 -5
View File
@@ -2,8 +2,9 @@
#define FINI
#define EMIT(A) \
if(box86_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(A));} \
*(uint32_t*)(dyn->block) = A; \
dyn->block += 4; dyn->arm_size += 4
*(uint32_t*)(dyn->block) = A; \
dyn->block += 4; dyn->arm_size += 4;\
dyn->insts[ninst].size2 += 4
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
#define NEW_INST
@@ -11,16 +12,34 @@
#define INST_NAME(name) \
if(box86_dynarec_dump) {\
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name); \
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, state=%d/%d, set=%X, use=%X, need=%X%s\n", \
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d, set=%X, use=%X, need=%X", \
(box86_dynarec_dump>1)?"\e[32m":"", \
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
dyn->insts[ninst].size/4, \
ninst, \
dyn->insts[ninst].x86.barrier, \
dyn->insts[ninst].x86.state_flags, \
dyn->state_flags, \
dyn->insts[ninst].x86.set_flags, \
dyn->insts[ninst].x86.use_flags, \
dyn->insts[ninst].x86.need_flags, \
(box86_dynarec_dump>1)?"\e[m":""); \
dyn->insts[ninst].x86.need_flags); \
for(int ii=0; ii<24; ++ii) { \
switch(dyn->insts[ninst].n.neoncache[ii].t) { \
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:ST%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:st%d", (ii+8)*2, dyn->insts[ninst].n.neoncache[ii].n); break; \
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:MM%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:XMM%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:xmm%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:Scratch", ii+8); break; \
case NEON_CACHE_NONE: \
default: break; \
} \
} \
if(dyn->n.stack || dyn->insts[ninst].n.stack_next) \
printf_log(LOG_NONE, " X87:%d/%d", dyn->n.stack, dyn->insts[ninst].n.stack_next);\
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
printf_log(LOG_NONE, " CMB:%d/%d", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
}
#define NEW_BARRIER_INST \
+45 -5
View File
@@ -4,17 +4,55 @@
#include "dynarec_private.h"
typedef struct x86emu_s x86emu_t;
typedef struct dynablock_s dynablock_t;
#define NEON_CACHE_NONE 0
#define NEON_CACHE_ST_D 1
#define NEON_CACHE_ST_F 2
#define NEON_CACHE_MM 3
#define NEON_CACHE_XMMW 4
#define NEON_CACHE_XMMR 5
#define NEON_CACHE_SCR 6
typedef union neon_cache_s {
int8_t v;
struct {
unsigned int t:4; // reg type
unsigned int n:4; // reg number
};
} neon_cache_t;
typedef struct neoncache_s {
neon_cache_t neoncache[24];
int8_t stack;
int8_t stack_next;
int8_t stack_pop;
uint8_t combined1;
uint8_t combined2;
} neoncache_t;
typedef struct instruction_arm_s {
instruction_x86_t x86;
uintptr_t address; // (start) address of the arm emited instruction
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
int size; // size of the arm emited instruction
int size2; // size of the arm emited instrucion after pass2
uintptr_t mark, mark2, mark3;
uintptr_t markf;
uintptr_t markseg;
uintptr_t marklock;
int pass2choice;// value for choices that are fixed on pass2 for pass3
uintptr_t natcall;
int retn;
neoncache_t n;
} instruction_arm_t;
typedef union sse_cache_s {
int v;
struct {
uint8_t reg;
uint8_t write;
};
} sse_cache_t;
typedef struct dynarec_arm_s {
instruction_arm_t *insts;
int32_t size;
@@ -24,29 +62,31 @@ typedef struct dynarec_arm_s {
void* block; // memory pointer where next instruction is emited
uintptr_t arm_start; // start of the arm code
int arm_size; // size of emitted arm code
uintptr_t* table; // jump table
int tablesz; // size of the jump table
int tablei; // index
int state_flags;// actual state for on-demand flags
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
int x87reg[8]; // reg used for x87cache entry
int mmxcache[8];// cache status for the 8 MMX registers
int ssecache[8];// cache status for the 8 SSE(2) registers
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
int x87stack; // cache stack counter
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
int fpu_scratch;// scratch counter
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
int fpu_reg; // x87/sse/mmx reg counter
int nolinker; // disable use of (smart) linker in the block
int dfnone; // if defered flags is already set to df_none
uintptr_t* next; // variable array of "next" jump address
int next_sz;
int next_cap;
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
void** sons_arm; // the arm address of potential dynablock sons
int sons_size; // number of potential dynablock sons
dynablock_t* dynablock;
} dynarec_arm_t;
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
#endif //__DYNAREC_ARM_PRIVATE_H_
+4 -4
View File
@@ -15,14 +15,16 @@
#define SF_UNKNOWN 0
#define SF_SET 1
#define SF_PENDING 2
#define SF_MAYSET 3
#define SF_SUBSET 4
#define SF_SET_PENDING 3
#define SF_MAYSET 4
#define SF_SUBSET 5
typedef struct instruction_x86_s {
uintptr_t addr; //address of the instruction
int32_t size; // size of the instruction
int barrier; // next instruction is a jump point, so no optim allowed
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
int jmp_cond; // 1 of conditionnal jump
int jmp_insts; // instuction to jump to (-1 if out of the block)
uint32_t use_flags; // 0 or combination of X_?F
uint32_t set_flags; // 0 or combination of X_?F
@@ -31,7 +33,5 @@ typedef struct instruction_x86_s {
} instruction_x86_t;
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
void tableupdate(void* jumpto, uintptr_t ref, void** table);
void resettable(void** table);
#endif //__DYNAREC_PRIVATE_H_
+109 -60
View File
@@ -1,3 +1,4 @@
ARM_ 1 1 1 1 0 0 0 1 0 0 0 0 (0) (0) (0) 1 (0) (0) (0) (0) (0) (0) @<1> (0) 0 0 0 0 (0) (0) (0) (0) SETEND \%cparam ? 'B' : 'L'\E
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 op 0 N Q M 0 Vm VH\(op ? "SUB" : "ADD")\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 0 N Q M 1 Vm VQADD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 1 N Q M 0 Vm VRHADD<c>.<dt> <Qd>, <Qn>, <Qm>
@@ -8,10 +9,10 @@ NEON 1 1 1 1 0 0 1 0 0 D 1 1 Vn Vd 0 0 0 1 N Q M 1 Vm VORN<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 1 0 D @<2> Vn Vd 0 0 0 1 N Q M 1 Vm @ param=0b00=0b01=0b10 const char* op op,"EOR","BSL","BIT","BIF"@ @ V\op\<c> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 0 N Q M 1 Vm VQSUB<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 1 N Q M op Vm @ op=0 const char* strict strict,"T","E"@ @ VCG\strict\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qm>, <Qn>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 0 Vm VABD<c>.<dt> <Qd>, <Qn>, <Qm>
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 1 Vm VABA<c>.<dt> <Qd>, <Qn>, <Qm>
@@ -50,12 +51,12 @@ NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=1 1 imm4 BIC<c>.<dt>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=110x 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=1110 0 Q op/=1 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <11> 0 <2> 1 <4>
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Dm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 0 L Q M 1 Vm VSHR<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 1 L Q M 1 Vm VSRA<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 0 L Q M 1 Vm VRSHR<c>.<dt> <Qd>, <Qm>, #<imm>
@@ -64,7 +65,7 @@ NEON 1 1 1 1 0 0 1 1 1 D imm6 Vd 0 1 0 0 L Q M 1 Vm VSRI<c>.<size> <Qd>, <Qm>, #
NEON 1 1 1 1 0 0 1 0 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSHL<c>.I<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 1 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSLI<c>.<size> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 0 1 1 op L Q M 1 Vm VQSHL\((u & op) ? "U" : "")\<c>.<dt> <Qd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm @ set ++size@ @ VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 1 M 1 Vm VRSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 0 M 1 Vm VQSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 1 M 1 Vm VQRSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
@@ -104,7 +105,7 @@ NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 0 Q M 0 Vm VUZP<c>.\%d8 &l&l si
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 1 Q M 0 Vm VZIP<c>.\%d8 &l&l size\ <Qd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 0 M 0 Vm VMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 1 M 0 Vm VQMOVUN<c>.S\%d16 &l&l size\ <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set u = 1 - u@ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 0 Vm VSHLL<c>.I\%d8 &l&l size\ <Qd>, <Dm>, #\%d8 &l&l size\
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 0 0 0 M 0 Vm VCVT<c>.F16.F32 <Dd>, <Qm>
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 1 0 0 M 0 Vm VCVT<c>.F32.F16 <Qd>, <Dm>
@@ -141,99 +142,128 @@ NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQRDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 0 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 0 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 0 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 1 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <2> 1 1 <6>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <2> 0 0 <1> 1 <4>
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 1 0 <3> 1 <4>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 0 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 1 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> Rm VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\], <Rm>
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
INVALIDATE 1 1 1 1 0 1 0 0 <3> 0 <20>
ARM_ 1 1 1 1 0 1 0 0 @<1> 0 0 1 Rn @<8> @<4> @<4> 'NOP'
ARM_ 1 1 1 1 0 1 0 0 U 1 0 1 Rn (1) (1) (1) (1) imm12 PLI [<Rn>, #+/-<imm12>]
ARM_ 1 1 1 1 0 1 0 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm12 PLD\param ? "W" : ""\ [<Rn>, #+/-<imm12>]
ARM_ 1 1 1 1 0 1 0 1 U (1) 0 1 1 1 1 1 (1) (1) (1) (1) imm12 PLD [PC, #+/-<imm>]
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 (1) (1) (1) (1) CLREX
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 0 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DSB \option\
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 1 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DMB \option\
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 1 0 @<4> @ param=0b1111 const char* option option,"SY","!!!"@ @ ISB \option\
ARM_ 1 1 1 1 0 1 1 0 @<1> 0 0 1 Rn @<8> @<3> 0 @<4> 'NOP'
ARMs 1 1 1 1 0 1 1 0 U 1 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLI [<Rn>, +/-<Rm>{, <shift>}]
ARMs 1 1 1 1 0 1 1 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLD\param ? "W" : ""\ [<Rn>, +/-<Rm>{, <shift>}]
INVALIDATE 1 1 1 1 0 1 1 1 1 1 1 1 <4> <8> 1 1 1 1 <4>
INVALIDATE 1 1 1 1 <28>
ARMS cond 0 0 0 0 0 0 0 S Rn Rd imm5 type 0 Rm AND{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 0 0 0 0 S Rd (0) (0) (0) (0) Rm 1 0 0 1 Rn MUL{S}<c> <Rd>, <Rn>, <Rm>
@@ -283,12 +313,15 @@ ARMS cond 0 0 0 1 0 0 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TST<c> <Rn>, <Rm>{,
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
ARM_ cond 0 0 0 1 0 0 0 0 (1) (1) (1) (1) Rd (0) (0) 0 (0) 0 0 0 0 (0) (0) (0) (0) MRS<c> <Rd>, APSR
ARM_ cond 0 0 0 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) (0) (0) 0 (0) 0 0 0 0 Rn @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, <Rn>
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 0 1 Rm BX<c> <Rm>
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 0 Rm BXJ<c> <Rm>
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 1 Rm BLX<c> <Rm>
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
ARM_ cond 0 0 0 1 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
@@ -329,6 +362,17 @@ ARM_ cond 0 0 1 0 1 1 1 S Rn Rd imm12 RSC{S}<c> <Rd>, <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 0 0 imm4 Rd imm12 MOVW<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 0 0 1 Rn (0) (0) (0) (0) imm12 TST<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 0 NOP<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 1 YIELD<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 1 0 WFE<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 1 1 WFI<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 1 0 0 SEV<c>
ARM_ cond/=1110 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 0 1 0 0 CSDB<c>
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 1 1 1 1 imm4 DBG<c> #<imm>
INVALIDATE <4> 0 0 1 1 0 0 1 0 0 0 0 0 <8> <8>
ARM_ cond 0 0 1 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) imm12 @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, #<imm>
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 0 1 <8> <8>
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 1 <1> <8> <8>
INVALIDATE <4> 0 0 1 1 0 1 1 0 <4> <8> <8>
ARM_ cond 0 0 1 1 0 0 1 1 Rn (0) (0) (0) (0) imm12 TEQ<c> <Rn>, #<const>
ARM_ cond 0 0 1 1 0 1 0 0 imm4 Rd imm12 MOVT<c> <Rd>, #<imm16>
ARM_ cond 0 0 1 1 0 1 0 1 Rn (0) (0) (0) (0) imm12 CMP<c> <Rn>, #<const>
@@ -375,6 +419,7 @@ ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
@@ -386,6 +431,8 @@ ARMs cond 0 1 1 0 U 1 0 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>], +/-<Rm>{, <
ARMs cond 0 1 1 0 U 1 0 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 0 Rn Rt imm5 type 0 Rm STRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARMs cond 0 1 1 0 U 1 1 1 Rn Rt imm5 type 0 Rm LDRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
ARM_ cond 0 1 1 1 0 0 0 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn SDIV<c> <Rd>, <Rn>, <Rm>
ARM_ cond 0 1 1 1 0 0 1 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn UDIV<c> <Rd>, <Rn>, <Rm>
ARMs cond 0 1 1 1 U 0 W 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 0 W 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
ARMs cond 0 1 1 1 U 1 W 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
@@ -395,6 +442,7 @@ ARM_ cond 0 1 1 1 1 0 0 0 Rd Ra Rm 0 0 0 1 Rn USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 1 1 1 1 BFC<c> <Rd>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 Rn BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond 0 1 1 1 1 1 1 widthm1 Rd lsb 1 0 1 Rn UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
ARM_ cond/=1110 0 1 1 1 1 1 1 1 imm12 1 1 1 1 imm4 UDF<c> #<imm16>
ARM_ cond 1 0 0 0 0 0 W 0 Rn/=1101 register_list STMED<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 0 Rn register_list STMDA<c> <Rn>{!}, <registers>
ARM_ cond 1 0 0 0 0 0 W 1 Rn/=1101 register_list LDMED<c> <Rn>{!}, <registers>
@@ -425,14 +473,14 @@ INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTMX<c> <LIst>
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 sz imm8 VPUSH<c> <list>
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 @ set imm8*=4@ @ VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 sz imm8 VSTM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDMX<c> <LIst>
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 sz imm8 VPOP<c> <list>
VFPU cond 1 1 0 1 0 D 0 1 1 1 1 1 Vd 1 0 1 sz 0 0 0 0 0 0 0 0 VLDR<c> <Dd>, [PC, #-0]
VFPU cond 1 1 0 1 U D 0 1 1 1 1 1 Vd 1 0 1 sz imm8 VLDR<c> <Dd>, <label>
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 @ set imm8*=4@ @ VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 sz imm8 VLDM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
INVALIDATE <4> 1 1 0 <25>
@@ -444,8 +492,9 @@ VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.32 <Qd>,
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 1 1 (0) (0) (0) (0) VDUP<c>.16 <Qd>, <Rt>
VFPU cond 1 1 1 0 1 1 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.8 <Qd>, <Rt>
VFPU cond 1 1 1 0 0 0 0 1 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Rt>, <Sn>
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt/=1111 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> APSR_nzcv, FPSCR
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> <Rt>, FPSCR
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 3) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 4) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 1 <4>
VFPU cond 1 1 1 0 0 D 0 0 Vn Vd 1 0 1 sz N op M 0 Vm VML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
VFPU cond 1 1 1 0 0 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VNML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
@@ -470,6 +519,6 @@ VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 0 1 1 M 0 Vm VCVT<c>.F64.F32 <Dd>, <S
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 1 1 1 M 0 Vm VCVT<c>.F32.F64 <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCVT<c>.F\(size ? "64" : "32")\.\(op ? "S" : "U")\32 <Dd>, <Sm>
VFPU cond 1 1 1 0 1 D 1 1 1 0 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.F\(size ? "64" : "32")\.\Td\ <Dd>, <Dd>, #<imm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 0 U Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 U 1 Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
INVALIDATE <32>
+69 -59
View File
@@ -40,6 +40,7 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
GO(SHT_HIPROC);
GO(SHT_LOUSER);
GO(SHT_HIUSER);
#if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES)
GO(SHT_GNU_versym);
GO(SHT_GNU_ATTRIBUTES);
GO(SHT_GNU_HASH);
@@ -51,6 +52,7 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
GO(SHT_SUNW_syminfo);
GO(SHT_GNU_verdef);
GO(SHT_GNU_verneed);
#endif
#undef GO
default:
sprintf(buff, "0x%X unknown type", s->sh_type);
@@ -98,6 +100,7 @@ const char* DumpDynamic(Elf32_Dyn *s) {
GO(DT_RUNPATH, 0);
GO(DT_FLAGS, 0);
GO(DT_ENCODING, 0);
#if defined(DT_NUM) && defined(DT_TLSDESC_PLT)
GO(DT_NUM, 0);
GO(DT_VALRNGLO, 0);
GO(DT_GNU_PRELINKED, 0);
@@ -133,6 +136,7 @@ const char* DumpDynamic(Elf32_Dyn *s) {
GO(DT_VERNEEDNUM, 0);
GO(DT_AUXILIARY, 0);
GO(DT_FILTER, 0);
#endif
#undef GO
default:
sprintf(buff, "0x%X unknown type", s->d_tag);
@@ -154,11 +158,13 @@ const char* DumpPHEntry(Elf32_Phdr *e)
GO(PT_SHLIB);
GO(PT_PHDR);
GO(PT_TLS);
#ifdef PT_NUM
GO(PT_NUM);
GO(PT_LOOS);
GO(PT_GNU_EH_FRAME);
GO(PT_GNU_STACK);
GO(PT_GNU_RELRO);
#endif
#undef GO
default: sprintf(buff, "type: %x, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", e->p_type, e->p_offset, (void*)e->p_vaddr, (void*)e->p_paddr, e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break;
}
@@ -187,19 +193,21 @@ const char* DumpRelType(int t)
GO(R_386_TLS_GD_32);
GO(R_386_TLS_DTPMOD32);
GO(R_386_TLS_DTPOFF32);
GO(R_386_TLS_TPOFF32);
#undef GO
default: sprintf(buff, "type: 0x%x (unknown)", t); break;
}
return buff;
}
const char* DumpSym(elfheader_t *h, Elf32_Sym* sym)
const char* DumpSym(elfheader_t *h, Elf32_Sym* sym, int version)
{
static char buff[4096];
const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
memset(buff, 0, sizeof(buff));
sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d",
sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d (ver=%d/%s)",
h->DynStr+sym->st_name, (void*)sym->st_value, sym->st_size,
sym->st_info, sym->st_other, sym->st_shndx);
sym->st_info, sym->st_other, sym->st_shndx, version, vername);
return buff;
}
@@ -214,116 +222,118 @@ const char* IdxSymName(elfheader_t *h, int sym)
void DumpMainHeader(Elf32_Ehdr *header, elfheader_t *h)
{
if(box86_log>=LOG_DUMP) {
printf_log(LOG_DUMP, "ELF Dump main header\n");
printf_log(LOG_DUMP, " Entry point = %p\n", (void*)header->e_entry);
printf_log(LOG_DUMP, " Program Header table offset = %p\n", (void*)header->e_phoff);
printf_log(LOG_DUMP, " Section Header table offset = %p\n", (void*)header->e_shoff);
printf_log(LOG_DUMP, " Flags = 0x%X\n", header->e_flags);
printf_log(LOG_DUMP, " ELF Header size = %d\n", header->e_ehsize);
printf_log(LOG_DUMP, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
printf_log(LOG_DUMP, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
printf_log(LOG_DUMP, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
printf_log(LOG_DUMP, "ELF Dump ==========\n");
if(box86_dump) {
printf_dump(LOG_NEVER, "ELF Dump main header\n");
printf_dump(LOG_NEVER, " Entry point = %p\n", (void*)header->e_entry);
printf_dump(LOG_NEVER, " Program Header table offset = %p\n", (void*)header->e_phoff);
printf_dump(LOG_NEVER, " Section Header table offset = %p\n", (void*)header->e_shoff);
printf_dump(LOG_NEVER, " Flags = 0x%X\n", header->e_flags);
printf_dump(LOG_NEVER, " ELF Header size = %d\n", header->e_ehsize);
printf_dump(LOG_NEVER, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
printf_dump(LOG_NEVER, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
printf_dump(LOG_NEVER, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
printf_dump(LOG_NEVER, "ELF Dump ==========\n");
printf_log(LOG_DUMP, "ELF Dump PEntries (%d)\n", h->numSHEntries);
printf_dump(LOG_NEVER, "ELF Dump PEntries (%d)\n", h->numSHEntries);
for (int i=0; i<h->numPHEntries; ++i)
printf_log(LOG_DUMP, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
printf_log(LOG_DUMP, "ELF Dump PEntries ====\n");
printf_dump(LOG_NEVER, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
printf_log(LOG_DUMP, "ELF Dump Sections (%d)\n", h->numSHEntries);
printf_dump(LOG_NEVER, "ELF Dump Sections (%d)\n", h->numSHEntries);
for (int i=0; i<h->numSHEntries; ++i)
printf_log(LOG_DUMP, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
printf_log(LOG_DUMP, "ELF Dump Sections ====\n");
printf_dump(LOG_NEVER, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
}
}
void DumpSymTab(elfheader_t *h)
{
if(box86_log>=LOG_DUMP && h->SymTab) {
if(box86_dump && h->SymTab) {
const char* name = ElfName(h);
printf_log(LOG_DUMP, "ELF Dump SymTab(%d)=\n", h->numSymTab);
printf_dump(LOG_NEVER, "ELF Dump SymTab(%d)=\n", h->numSymTab);
for (int i=0; i<h->numSymTab; ++i)
printf_log(LOG_DUMP, " %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name,
printf_dump(LOG_NEVER, " %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name,
i, h->StrTab+h->SymTab[i].st_name, (void*)h->SymTab[i].st_value, h->SymTab[i].st_size,
h->SymTab[i].st_info, h->SymTab[i].st_other, h->SymTab[i].st_shndx);
printf_log(LOG_DUMP, "ELF Dump SymTab=====\n");
printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
}
}
void DumpDynamicSections(elfheader_t *h)
{
if(box86_log>=LOG_DUMP && h->Dynamic) {
printf_log(LOG_DUMP, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
if(box86_dump && h->Dynamic) {
printf_dump(LOG_NEVER, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
for (int i=0; i<h->numDynamic; ++i)
printf_log(LOG_DUMP, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
printf_log(LOG_DUMP, "ELF Dump Dynamic=====\n");
printf_dump(LOG_NEVER, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
}
}
void DumpDynSym(elfheader_t *h)
{
if(box86_log>=LOG_DUMP && h->DynSym) {
if(box86_dump && h->DynSym) {
const char* name = ElfName(h);
printf_log(LOG_DUMP, "ELF Dump DynSym(%d)=\n", h->numDynSym);
for (int i=0; i<h->numDynSym; ++i)
printf_log(LOG_DUMP, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i));
printf_log(LOG_DUMP, "ELF Dump DynSym=====\n");
printf_dump(LOG_NEVER, "ELF Dump DynSym(%d)=\n", h->numDynSym);
for (int i=0; i<h->numDynSym; ++i) {
int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
printf_dump(LOG_NEVER, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i, version));
}
printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
}
}
void DumpDynamicNeeded(elfheader_t *h)
{
if(box86_log>=LOG_DUMP && h->DynStrTab) {
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
if(box86_dump && h->DynStrTab) {
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
for (int i=0; i<h->numDynamic; ++i)
if(h->Dynamic[i].d_tag==DT_NEEDED) {
printf_log(LOG_DUMP, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
printf_dump(LOG_NEVER, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
}
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
}
}
void DumpDynamicRPath(elfheader_t *h)
{
if(box86_log>=LOG_DUMP && h->DynStrTab) {
printf_log(LOG_DUMP, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
if(box86_dump && h->DynStrTab) {
printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
for (int i=0; i<h->numDynamic; ++i) {
if(h->Dynamic[i].d_tag==DT_RPATH) {
printf_log(LOG_DUMP, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
printf_dump(LOG_NEVER, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
}
if(h->Dynamic[i].d_tag==DT_RUNPATH) {
printf_log(LOG_DUMP, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
}
}
printf_log(LOG_DUMP, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
}
}
void DumpRelTable(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name)
{
if(box86_log>=LOG_DUMP) {
if(box86_dump) {
const char* elfname = ElfName(h);
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
for (int i = 0; i<cnt; ++i)
printf_log(LOG_DUMP, " %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname,
printf_dump(LOG_NEVER, " %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname,
i, (void*)rel[i].r_offset, rel[i].r_info, DumpRelType(ELF32_R_TYPE(rel[i].r_info)),
ELF32_R_SYM(rel[i].r_info), IdxSymName(h, ELF32_R_SYM(rel[i].r_info)));
printf_log(LOG_DUMP, "ELF Dump Rel Table=====\n");
printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n");
}
}
void DumpRelATable(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name)
{
if(box86_log>=LOG_DUMP && h->rela) {
if(box86_dump && h->rela) {
const char* elfname = ElfName(h);
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
for (int i = 0; i<cnt; ++i)
printf_log(LOG_DUMP, " %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname,
printf_dump(LOG_NEVER, " %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname,
i, (void*)rela[i].r_offset, rela[i].r_info, DumpRelType(ELF32_R_TYPE(rela[i].r_info)),
ELF32_R_SYM(rela[i].r_info), IdxSymName(h, ELF32_R_SYM(rela[i].r_info)),
rela[i].r_addend);
printf_log(LOG_DUMP, "ELF Dump RelA Table=====\n");
printf_dump(LOG_NEVER, "ELF Dump RelA Table=====\n");
}
}
@@ -334,24 +344,24 @@ void DumpBinary(char* p, int sz)
unsigned char* d = (unsigned char*)p;
int delta = ((uintptr_t)p)&0xf;
for (int i = 0; sz; ++i) {
printf_log(LOG_DUMP, "%p ", (void*)(((uintptr_t)d)&~0xf));
printf_dump(LOG_NEVER, "%p ", (void*)(((uintptr_t)d)&~0xf));
int n = 16 - delta;
if (n>sz) n = sz;
int fill = 16-sz;
for (int j = 0; j<delta; ++j)
printf_log(LOG_DUMP, " ");
printf_dump(LOG_NEVER, " ");
for (int j = 0; j<n; ++j)
printf_log(LOG_DUMP, "%02X ", d[j]);
printf_dump(LOG_NEVER, "%02X ", d[j]);
for (int j = 0; j<fill; ++j)
printf_log(LOG_DUMP, " ");
printf_log(LOG_DUMP, " | ");
printf_dump(LOG_NEVER, " ");
printf_dump(LOG_NEVER, " | ");
for (int j = 0; j<delta; ++j)
printf_log(LOG_DUMP, " ");
printf_dump(LOG_NEVER, " ");
for (int j = 0; j<n; ++j)
printf_log(LOG_DUMP, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
printf_dump(LOG_NEVER, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
for (int j = 0; j<fill; ++j)
printf_log(LOG_DUMP, " ");
printf_log(LOG_DUMP, "\n");
printf_dump(LOG_NEVER, " ");
printf_dump(LOG_NEVER, "\n");
d+=n;
sz-=n;
delta=0;
+538 -212
View File
File diff suppressed because it is too large. Load diff
+13 -3
View File
@@ -30,6 +30,12 @@ struct elfheader_s {
int numDynamic;
char* DynStrTab;
int szDynStrTab;
Elf32_Half* VerSym;
Elf32_Verneed* VerNeed;
int szVerNeed;
Elf32_Verdef* VerDef;
int szVerDef;
int e_type;
intptr_t delta; // should be 0
@@ -52,8 +58,12 @@ struct elfheader_s {
int pltent;
uint32_t pltrel;
uintptr_t gotplt;
uintptr_t gotplt_end;
uintptr_t pltgot;
uintptr_t got;
uintptr_t got_end;
uintptr_t plt;
uintptr_t plt_end;
uintptr_t text;
int textsz;
@@ -63,7 +73,9 @@ struct elfheader_s {
uint32_t memsz;
uint32_t stacksz;
int stackalign;
uintptr_t tlsaddr;
uint32_t tlssize;
uint32_t tlsfilesize;
int tlsalign;
int32_t tlsbase; // the base of the tlsdata in the global tlsdata (always negative)
@@ -76,9 +88,7 @@ struct elfheader_s {
uintptr_t* multiblock_offs;
uint32_t* multiblock_size;
int multiblock_n;
#ifdef DYNAREC
dynablocklist_t *blocks;
#endif
library_t *lib;
needed_libs_t *neededlibs;
};
+139 -55
View File
@@ -61,8 +61,9 @@ void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const ch
elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
{
Elf32_Ehdr header;
int level = (exec)?LOG_INFO:LOG_DEBUG;
if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
printf_log(LOG_INFO, "Cannot read ELF Header\n");
printf_log(level, "Cannot read ELF Header\n");
return NULL;
}
if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
@@ -96,7 +97,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
}
if(header.e_machine != EM_386) {
printf_log(LOG_INFO, "Not an i386 ELF (%d)\n", header.e_machine);
printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine);
return NULL;
}
@@ -119,7 +120,8 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
h->numPHEntries = header.e_phnum;
h->numSHEntries = header.e_shnum;
h->SHIdx = header.e_shstrndx;
if(header.e_shentsize!=0) {
h->e_type = header.e_type;
if(header.e_shentsize && header.e_shnum) {
// special cases for nums
if(h->numSHEntries == 0) {
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
@@ -159,7 +161,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
return NULL;
}
if(header.e_shentsize!=0) {
if(header.e_shentsize && header.e_shnum) {
if(h->SHIdx == SHN_XINDEX) {
printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
h->SHIdx = h->SHEntries[0].sh_link;
@@ -175,42 +177,99 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
FreeElfHeader(&h);
return NULL;
}
if(box86_log>=LOG_DUMP) DumpMainHeader(&header, h);
if(box86_dump) DumpMainHeader(&header, h);
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
if(box86_log>=LOG_DUMP && h->SymTab) DumpSymTab(h);
if(box86_dump && h->SymTab) DumpSymTab(h);
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
if(box86_log>=LOG_DUMP && h->Dynamic) DumpDynamicSections(h);
if(box86_dump && h->Dynamic) DumpDynamicSections(h);
// grab DT_REL & DT_RELA stuffs
// also grab the DT_STRTAB string table
{
for (int i=0; i<h->numDynamic; ++i) {
if(h->Dynamic[i].d_tag == DT_REL)
h->rel = h->Dynamic[i].d_un.d_ptr;
else if(h->Dynamic[i].d_tag == DT_RELSZ)
h->relsz = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_RELENT)
h->relent = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_RELA)
h->rela = h->Dynamic[i].d_un.d_ptr;
else if(h->Dynamic[i].d_tag == DT_RELASZ)
h->relasz = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_RELAENT)
h->relaent = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_PLTGOT)
h->pltgot = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_PLTREL)
h->pltrel = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
h->pltsz = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_JMPREL)
h->jmprel = h->Dynamic[i].d_un.d_val;
else if(h->Dynamic[i].d_tag == DT_STRTAB)
h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
else if(h->Dynamic[i].d_tag == DT_STRSZ)
h->szDynStrTab = h->Dynamic[i].d_un.d_val;
Elf32_Dyn d = h->Dynamic[i];
Elf32_Word val = d.d_un.d_val;
Elf32_Addr ptr = d.d_un.d_ptr;
switch (d.d_tag) {
case DT_REL:
h->rel = ptr;
break;
case DT_RELSZ:
h->relsz = val;
break;
case DT_RELENT:
h->relent = val;
break;
case DT_RELA:
h->rela = ptr;
break;
case DT_RELASZ:
h->relasz = val;
break;
case DT_RELAENT:
h->relaent = val;
break;
case DT_PLTGOT:
h->pltgot = ptr;
break;
case DT_PLTREL:
h->pltrel = val;
break;
case DT_PLTRELSZ:
h->pltsz = val;
break;
case DT_JMPREL:
h->jmprel = ptr;
break;
case DT_STRTAB:
h->DynStrTab = (char *)(ptr);
break;
case DT_STRSZ:
h->szDynStrTab = val;
break;
case DT_INIT: // Entry point
h->initentry = ptr;
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
break;
case DT_INIT_ARRAY:
h->initarray = ptr;
printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
break;
case DT_INIT_ARRAYSZ:
h->initarray_sz = val / sizeof(Elf32_Addr);
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
break;
case DT_FINI: // Exit hook
h->finientry = ptr;
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
break;
case DT_FINI_ARRAY:
h->finiarray = ptr;
printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
break;
case DT_FINI_ARRAYSZ:
h->finiarray_sz = val / sizeof(Elf32_Addr);
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
break;
case DT_VERNEEDNUM:
h->szVerNeed = val;
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
break;
case DT_VERNEED:
h->VerNeed = (Elf32_Verneed*)ptr;
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
break;
case DT_VERDEFNUM:
h->szVerDef = val;
printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
break;
case DT_VERDEF:
h->VerDef = (Elf32_Verdef*)ptr;
printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
break;
}
}
if(h->rel) {
if(h->relent != sizeof(Elf32_Rel)) {
@@ -253,38 +312,26 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt");
if(ii) {
h->gotplt = h->SHEntries[ii].sh_addr;
h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
}
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
if(ii) {
h->got = h->SHEntries[ii].sh_addr;
printf_log(LOG_DEBUG, "The GOT Table is at address %p\n", (void*)h->got);
h->got_end = h->got + h->SHEntries[ii].sh_size;
printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
}
// look for .init entry point
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
if(ii) {
h->initentry = h->SHEntries[ii].sh_addr;
printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
h->plt = h->SHEntries[ii].sh_addr;
h->plt_end = h->plt + h->SHEntries[ii].sh_size;
printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
}
// and .init_array
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init_array");
// grab version of symbols
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
if(ii) {
h->initarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
h->initarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
printf_log(LOG_DEBUG, "The .init_array is at address %p, and have %d elements\n", (void*)h->initarray, h->initarray_sz);
}
// look for .fini entry point
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
if(ii) {
h->finientry = h->SHEntries[ii].sh_addr;
printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
}
// and .fini_array
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini_array");
if(ii) {
h->finiarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
h->finiarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
printf_log(LOG_DEBUG, "The .fini_array is at address %p, and have %d elements\n", (void*)h->finiarray, h->finiarray_sz);
h->VerSym = (Elf32_Half*)(h->SHEntries[ii].sh_addr);
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
}
// grab .text for main code
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
@@ -296,8 +343,45 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
if(box86_log>=LOG_DUMP && h->DynSym) DumpDynSym(h);
}
return h;
}
const char* GetSymbolVersion(elfheader_t* h, int version)
{
if(!h->VerNeed || (version<2))
return NULL;
/*if(version==1)
return "*";*/
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
while(ver) {
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
for(int j=0; j<ver->vn_cnt; ++j) {
if(aux->vna_other==version)
return h->DynStr+aux->vna_name;
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
}
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
}
return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead
}
const char* GetParentSymbolVersion(elfheader_t* h, int index)
{
if(!h->VerDef || (index<1))
return NULL;
Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef + h->delta);
while(def) {
if(def->vd_ndx==index) {
if(def->vd_cnt<1)
return NULL;
/*if(def->vd_flags&VER_FLG_BASE)
return NULL;*/
Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
return h->DynStr+aux->vda_name; // return Parent, so 1st aux
}
def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
}
return NULL;
}
+59 -1
View File
@@ -47,6 +47,52 @@
base+=(nextop&0x80)?(F32S):(F8S); \
A = (T*)(base+O); \
}
#define getecommon16(A, T) \
{ \
uint32_t m = nextop&0xC7; \
uint32_t base = 0; \
switch(m&7) { \
case 0: base = R_BX+R_SI; break; \
case 1: base = R_BX+R_DI; break; \
case 2: base = R_BP+R_SI; break; \
case 3: base = R_BP+R_DI; break; \
case 4: base = R_SI; break; \
case 5: base = R_DI; break; \
case 6: base = R_BP; break; \
case 7: base = R_BX; break; \
} \
switch((m>>6)&3) { \
case 0: if(m==6) base = F16; break; \
case 1: base += F8S; break; \
case 2: base += F16S; break; \
} \
A = (T*)base; \
}
#define getecommon16o(A, T, O) \
{ \
uint32_t m = nextop&0xC7; \
uint32_t base = 0; \
switch(m&7) { \
case 0: base = R_BX+R_SI; break; \
case 1: base = R_BX+R_DI; break; \
case 2: base = R_BP+R_SI; break; \
case 3: base = R_BP+R_DI; break; \
case 4: base = R_SI; break; \
case 5: base = R_DI; break; \
case 6: base = R_BP; break; \
case 7: base = R_BX; break; \
} \
switch((m>>6)&3) { \
case 0: if(m==6) base = F16; break; \
case 1: base += F8S; break; \
case 2: base += F16S; break; \
} \
A = (T*)(base+O); \
}
#define geteb(A) \
if((nextop&0xC0)==0xC0) { \
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
@@ -66,11 +112,20 @@
#define getem(A) \
if((nextop&0xC0)==0xC0) { \
A = &emu->mmx[(nextop&7)]; \
} else getecommon(A, mmx_regs_t)
} else getecommon(A, mmx87_regs_t)
#define getex(A) \
if((nextop&0xC0)==0xC0) { \
A = &emu->xmm[(nextop&7)]; \
} else getecommon(A, sse_regs_t)
#define getew16(A) \
if((nextop&0xC0)==0xC0) { \
A = &emu->regs[(nextop&7)]; \
} else getecommon16(A, reg32_t)
#define getew16o(A, O) \
if((nextop&0xC0)==0xC0) { \
A = &emu->regs[(nextop&7)]; \
} else getecommon16o(A, reg32_t, O)
// Macros for ModR/M gets
#define GET_EB geteb(oped)
#define GET_ED geted(oped)
@@ -78,6 +133,8 @@
#define GET_EB_OFFS(o) getebo(oped, o)
#define GET_EM getem(opem)
#define GET_EX getex(opex)
#define GET_EW16 getew16(oped)
#define GET_EW16_OFFS(o) getew16o(oped, o)
#define EB oped
#define ED oped
#define EM opem
@@ -89,5 +146,6 @@
// Alias
#define GET_EW GET_ED
#define GET_EW_OFFS GET_ED_OFFS
#define EW ED
#define GW GD
+230 -86
View File
@@ -3,6 +3,18 @@
_0f_0x00: /* VERx Ed */
nextop = F8;
switch((nextop>>3)&7) {
case 0: /* SLDT Ew */
GET_EW;
EW->word[0] = 0;
if((nextop&0xC0)==0xC0)
EW->word[1] = 0;
break;
case 1: /* STR Ew */
GET_EW;
EW->word[0] = 0x7f; // dummy return
if((nextop&0xC0)==0xC0)
EW->word[1] = 0;
break;
case 4: //VERR
case 5: //VERW
GET_EW;
@@ -15,9 +27,38 @@
goto _default;
}
NEXT;
_0f_0x01:
nextop = F8;
switch((nextop>>3)&7) {
case 0: /* SGDT Ed */
GET_ED;
ED->word[0] = 0x7f; // dummy return...
ED->word[1] = 0x000c;
ED->word[2] = 0xd000;
break;
case 1: /* SIDT Ed */
GET_ED;
ED->word[0] = 0xfff; // dummy return, like "disabled"
ED->word[1] = 0;
ED->word[2] = 0;
break;
case 4: /* SMSW Ew */
GET_ED;
// dummy for now... Do I need to track CR0 state?
ED->word[0] = (1<<0) | (1<<4); // only PE and ET set...
break;
default:
goto _default;
}
NEXT;
_0f_0x0B: /* UD2 */
kill(getpid(), SIGILL); // this is undefined instruction
emu->old_ip = R_EIP;
R_EIP = ip-2;
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
ip = R_EIP;
if(emu->quit) goto fini;
STEP;
NEXT;
_0f_0x10: /* MOVUPS Gx,Ex */
nextop = F8;
@@ -84,6 +125,15 @@
}
NEXT;
_0f_0x1A: /* NOP (multi-byte) / ignored BNDLDX */
nextop = F8;
GET_ED;
NEXT;
_0f_0x1B: /* NOP (multi-byte) / ignored BNDSTX */
nextop = F8;
GET_ED;
NEXT;
_0f_0x1F: /* NOP (multi-byte) */
nextop = F8;
GET_ED;
@@ -123,7 +173,7 @@
// rounding should be done; and indefinite integer should also be assigned if overflow or NaN/Inf
nextop = F8;
GET_EX;
switch(emu->round) {
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GM.sd[1] = floorf(EX->f[1]+0.5f);
GM.sd[0] = floorf(EX->f[0]+0.5f);
@@ -169,18 +219,105 @@
_0f_0x38: // these are some SSE3 opcodes
opcode = F8;
switch(opcode) {
case 0x00: /* PSHUFB */
nextop = F8;
GET_EM;
eam1 = GM;
for (int i=0; i<8; ++i) {
if(EM->ub[i]&128)
GM.ub[i] = 0;
else
GM.ub[i] = eax1.ub[EM->ub[i]&7];
}
break;
case 0x04: /* PMADDUBSW Gm,Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i) {
tmp32s = (int32_t)(GM.ub[i*2+0])*EM->ub[i*2+0] + (int32_t)(GM.ub[i*2+1])*EM->ub[i*2+1];
GM.sw[i] = (tmp32s>32767)?32767:tmp32s; // no negative value to test
tmp32s = (int32_t)(GM.ub[i*2+0])*EM->sb[i*2+0] + (int32_t)(GM.ub[i*2+1])*EM->sb[i*2+1];
GM.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
}
break;
case 0x09: /* PSIGNW Gm, Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i) {
if (EM->sw[i] < 0) {
GM.sw[i] = -GM.sw[i];
} else if (EM->sw[i] == 0) {
GM.sw[i] = 0;
}
}
break;
case 0x0B: /* PMULHRSW Gm, Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i) {
tmp32s = ((((int32_t)(GM.sw[i])*(int32_t)(EM->sw[i]))>>14) + 1)>>1;
GM.uw[i] = tmp32s&0xffff;
}
break;
case 0x1C: /* PABSB Gm, Em */
nextop = F8;
GET_EM;
for (int i=0; i<8; ++i) {
GM.sb[i] = abs(EM->sb[i]);
}
break;
case 0x1D: /* PABSW Gm, Em */
nextop = F8;
GET_EM;
for (int i=0; i<4; ++i) {
GM.sw[i] = abs(EM->sw[i]);
}
break;
case 0x1E: /* PABSD Gm, Em */
nextop = F8;
GET_EM;
for (int i=0; i<2; ++i) {
GM.sd[i] = abs(EM->sd[i]);
}
break;
default:
goto _default;
}
NEXT;
_0f_0x3A:
opcode = F8;
switch(opcode) {
case 0xF: /* palignr */
nextop = F8;
GET_EM;
tmp8u = F8;
if (tmp8u >= 16) {
GM.q = 0;
} else if (tmp8u > 8) {
tmp8u -= 8;
GM.q >>= tmp8u*8;
} else if (tmp8u == 8 || tmp8u == 0) {
} else {
GM.q <<= (8-tmp8u)*8;
GM.q |= (EM->q >> tmp8u*8);
}
break;
default:
goto _default;
}
NEXT;
_0f_0x3F:
emu->old_ip = R_EIP;
R_EIP = ip-2;
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
ip = R_EIP;
if(emu->quit) goto fini;
STEP;
NEXT;
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
_0f_##BASE##_0: \
@@ -415,10 +552,14 @@
GM.sb[1] = (GM.sw[1] > 127) ? 127 : ((GM.sw[1] < -128) ? -128 : GM.sw[1]);
GM.sb[2] = (GM.sw[2] > 127) ? 127 : ((GM.sw[2] < -128) ? -128 : GM.sw[2]);
GM.sb[3] = (GM.sw[3] > 127) ? 127 : ((GM.sw[3] < -128) ? -128 : GM.sw[3]);
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
if(EM==&GM)
GM.ud[1] = GM.ud[0];
else {
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
}
NEXT;
_0f_0x64: /* PCMPGTB Gm,Em */
nextop = F8;
@@ -446,33 +587,42 @@
GET_EM;
for(int i=0; i<4; ++i)
GM.ub[i] = (GM.sw[i]<0)?0:((GM.sw[i]>0xff)?0xff:GM.sw[i]);
for(int i=0; i<4; ++i)
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
if(EM==&GM)
GM.ud[1] = GM.ud[0];
else
for(int i=0; i<4; ++i)
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
NEXT;
_0f_0x68: /* PUNPCKHBW Gm,Em */
nextop = F8;
GET_EM;
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
for(int i=0; i<4; ++i)
GM.ub[2 * i] = GM.ub[i + 4];
for(int i=0; i<4; ++i)
GM.ub[2 * i + 1] = EM->ub[i + 4];
if(EM==&GM)
for(int i=0; i<4; ++i)
GM.ub[2 * i + 1] = GM.ub[2 * i];
else
for(int i=0; i<4; ++i)
GM.ub[2 * i + 1] = EM->ub[i + 4];
NEXT;
_0f_0x69: /* PUNPCKHWD Gm,Em */
nextop = F8;
GET_EM;
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
for(int i=0; i<2; ++i)
GM.uw[2 * i] = GM.uw[i + 2];
for(int i=0; i<2; ++i)
GM.uw[2 * i + 1] = EM->uw[i + 2];
if(EM==&GM)
for(int i=0; i<2; ++i)
GM.uw[2 * i + 1] = GM.uw[2 * i];
else
for(int i=0; i<2; ++i)
GM.uw[2 * i + 1] = EM->uw[i + 2];
NEXT;
_0f_0x6A: /* PUNPCKHDQ Gm,Em */
nextop = F8;
GET_EM;
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
GM.ud[0] = GM.ud[1];
GM.ud[1] = EM->ud[1];
if(EM!=&GM)
GM.ud[1] = EM->ud[1];
NEXT;
_0f_0x6B: /* PACKSSDW Gm,Em */
nextop = F8;
@@ -480,8 +630,11 @@
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
for(int i=0; i<2; ++i)
GM.sw[i] = (GM.sd[i]<-32768)?-32768:((GM.sd[i]>32767)?32767:GM.sd[i]);
for(int i=0; i<2; ++i)
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
if(EM==&GM)
GM.ud[1] = GM.ud[0];
else
for(int i=0; i<2; ++i)
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
NEXT;
_0f_0x6E: /* MOVD Gm, Ed */
@@ -619,7 +772,7 @@
NEXT;
_0f_0xA1: /* POP FS */
emu->segs[_FS] = Pop(emu); // no check, no use....
emu->segs_clean[_FS] = 0;
emu->segs_serial[_FS] = 0;
NEXT;
_0f_0xA2: /* CPUID */
tmp32u = R_EAX;
@@ -629,12 +782,13 @@
CHECK_FLAGS(emu);
nextop = F8;
GET_ED;
tmp8u = GD.byte[0];
tmp32s = GD.sdword[0];
tmp8u=tmp32s&31;
tmp32s >>= 5;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u))
SET_FLAG(F_CF);
else
@@ -653,7 +807,7 @@
NEXT;
_0f_0xA9: /* POP GS */
emu->segs[_GS] = Pop(emu);
emu->segs_clean[_GS] = 0;
emu->segs_serial[_GS] = 0;
NEXT;
@@ -661,12 +815,13 @@
CHECK_FLAGS(emu);
nextop = F8;
GET_ED;
tmp8u = GD.byte[0];
tmp32s = GD.sdword[0];
tmp8u=tmp32s&31;
tmp32s >>= 5;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u))
SET_FLAG(F_CF);
else {
@@ -696,25 +851,10 @@
GET_ED;
switch((nextop>>3)&7) {
case 0: /* FXSAVE m512byte */
// should save flags & all
// copy MMX regs...
for(int i=0; i<8; ++i)
memcpy(ED->dword+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(ED->dword+160, &emu->xmm[0], sizeof(emu->xmm));
// put also FPU regs in a reserved area...
for(int i=0; i<8; ++i)
memcpy(ED->dword+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
fpu_fxsave(emu, ED);
break;
case 1: /* FXRSTOR m512byte */
// should restore flags & all
// copy back MMX regs...
for(int i=0; i<8; ++i)
memcpy(&emu->mmx[i], ED->dword+32+i*16, sizeof(emu->mmx[0]));
// copy SSE regs
memcpy(&emu->xmm[0], ED->dword+160/4, sizeof(emu->xmm));
for(int i=0; i<8; ++i)
memcpy(&emu->fpu[0], ED->dword+416+i*8, sizeof(emu->fpu[0]));
fpu_fxrstor(emu, ED);
break;
case 2: /* LDMXCSR Md */
emu->mxcsr = ED->dword[0];
@@ -732,7 +872,6 @@
GD.dword[0] = imul32(emu, GD.dword[0], ED->dword[0]);
NEXT;
_0f_0xB0: /* CMPXCHG Eb,Gb */
CHECK_FLAGS(emu);
nextop = F8;
GET_EB;
cmp8(emu, R_AL, EB->byte[0]);
@@ -757,12 +896,13 @@
CHECK_FLAGS(emu);
nextop = F8;
GET_ED;
tmp8u = GD.byte[0];
tmp32s = GD.sdword[0];
tmp8u=tmp32s&31;
tmp32s >>= 5;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u)) {
SET_FLAG(F_CF);
ED->dword[0] ^= (1<<tmp8u);
@@ -788,10 +928,6 @@
CHECK_FLAGS(emu);
GET_ED;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u))
SET_FLAG(F_CF);
@@ -802,25 +938,18 @@
CHECK_FLAGS(emu);
GET_ED;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u)) {
SET_FLAG(F_CF);
} else
} else {
ED->dword[0] ^= (1<<tmp8u);
CLEAR_FLAG(F_CF);
}
break;
case 6: /* BTR Ed, Ib */
CHECK_FLAGS(emu);
GET_ED;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u)) {
SET_FLAG(F_CF);
@@ -832,10 +961,6 @@
CHECK_FLAGS(emu);
GET_ED;
tmp8u = F8;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u))
SET_FLAG(F_CF);
@@ -852,12 +977,13 @@
CHECK_FLAGS(emu);
nextop = F8;
GET_ED;
tmp8u = GD.byte[0];
tmp32s = GD.sdword[0];
tmp8u=tmp32s&31;
tmp32s >>= 5;
if((nextop&0xC0)!=0xC0)
{
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
}
tmp8u&=31;
if(ED->dword[0] & (1<<tmp8u))
SET_FLAG(F_CF);
else
@@ -936,7 +1062,11 @@
GX.ud[i]=(tmp8s)?0xffffffff:0;
}
NEXT;
_0f_0xC3: /* MOVNTI Ed,Gd */
nextop = F8;
GET_ED;
ED->dword[0] = GD.dword[0];
NEXT;
_0f_0xC4: /* PINSRW Gm,Ew,Ib */
nextop = F8;
GET_ED;
@@ -1033,12 +1163,15 @@
_0f_0xD7: /* PMOVMSKB Gd,Em */
nextop = F8;
GET_EM;
GD.dword[0] = 0;
for (int i=0; i<8; ++i)
if(EM->ub[i]&0x80)
GD.dword[0] |= (1<<i);
NEXT;
if((nextop&0xC0)==0xC0) {
GET_EM;
GD.dword[0] = 0;
for (int i=0; i<8; ++i)
if(EM->ub[i]&0x80)
GD.dword[0] |= (1<<i);
NEXT;
} else
goto _default;
_0f_0xD8: /* PSUBUSB Gm,Em */
nextop = F8;
GET_EM;
@@ -1055,7 +1188,12 @@
GM.uw[i] = (tmp32s < 0) ? 0 : tmp32s;
}
NEXT;
_0f_0xDA: /* PMINUB Gm,Em */
nextop = F8;
GET_EM;
for (int i=0; i<8; ++i)
GM.ub[i] = (GM.ub[i]<EM->ub[i])?GM.ub[i]:EM->ub[i];
NEXT;
_0f_0xDB: /* PAND Gm,Em */
nextop = F8;
GET_EM;
@@ -1077,7 +1215,12 @@
GM.uw[i] = (tmp32u>65535) ? 65535 : tmp32u;
}
NEXT;
_0f_0xDE: /* PMAXUB Gm,Em */
nextop = F8;
GET_EM;
for (int i=0; i<8; ++i)
GM.ub[i] = (GM.ub[i]>EM->ub[i])?GM.ub[i]:EM->ub[i];
NEXT;
_0f_0xDF: /* PANDN Gm,Em */
nextop = F8;
GET_EM;
@@ -1111,20 +1254,17 @@
GM.sd[i] >>= tmp8u;
}
NEXT;
_0f_0xE3: /* PSRAQ Gm, Em */
_0f_0xE3: /* PAVGW Gm, Em */
nextop = F8;
GET_EM;
if(EM->q>63)
tmp8u = 64;
else
tmp8u = EM->ub[0];
GM.sq >>= tmp8u;
for(int i=0; i<4; ++i)
GM.uw[i] = ((uint32_t)GM.uw[i]+EM->uw[i]+1)>>1;
NEXT;
_0f_0xE4: /* PMULHUW Gm, Em */
nextop = F8;
GET_EM;
for(int i=0; i<4; ++i) {
tmp32u = (int32_t)GM.uw[i] * EM->uw[i];
tmp32u = (uint32_t)GM.uw[i] * EM->uw[i];
GM.uw[i] = (tmp32u>>16)&0xffff;
}
NEXT;
@@ -1277,7 +1417,11 @@
for(int i=0; i<2; ++i)
GM.sd[i] -= EM->sd[i];
NEXT;
_0f_0xFB: /* PSUBQ Gm,Em */
nextop = F8;
GET_EM;
GM.sq -= EM->sq;
NEXT;
_0f_0xFC: /* PADDB Gm, Em */
nextop = F8;
GET_EM;
+64 -10
View File
@@ -2,16 +2,29 @@
goto *opcodes66[opcode];
#define GO(B, OP) \
_66_##B##_0: \
nextop = F8; \
GET_EB; \
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
NEXT; \
_66_##B##_1: \
nextop = F8; \
GET_EW; \
EW->word[0] = OP##16(emu, EW->word[0], GW.word[0]); \
NEXT; \
_66_##B##_2: \
nextop = F8; \
GET_EB; \
GB = OP##8(emu, GB, EB->byte[0]); \
NEXT; \
_66_##B##_3: \
nextop = F8; \
GET_EW; \
GW.word[0] = OP##16(emu, GW.word[0], EW->word[0]); \
NEXT; \
_66_##B##_4: \
R_AL = OP##8(emu, R_AL, F8); \
NEXT; \
_66_##B##_5: \
R_AX = OP##16(emu, R_AX, F16); \
NEXT;
@@ -30,11 +43,22 @@
NEXT;
_66_0x07: /* POP ES */
emu->segs[_ES] = Pop16(emu); // no check, no use....
emu->segs_clean[_ES] = 0;
emu->segs_serial[_ES] = 0;
NEXT;
_66_0x0F: /* 66 0f prefix */
#include "run660f.h"
emu->old_ip = R_EIP;
R_EIP = ip-2; // don't count 66 0F yet
Run660F(emu); // implemented in Run660f.c
ip = R_EIP;
if(emu->quit) goto fini;
STEP
NEXT;
_66_0x1F: /* POP DS */
emu->segs[_DS] = Pop16(emu); // no check, no use....
emu->segs_serial[_DS] = 0;
NEXT;
_66_0x26: /* ES: */
// ignored
@@ -129,6 +153,13 @@
R_AX = Pop16(emu);
NEXT;
_66_0x64:
R_EIP = ip-2;
RunFS66(emu, GetFSBaseEmu(emu));
ip = R_EIP;
STEP;
NEXT;
_66_0x66:
goto _0x66; // 0x66 0x66 => can remove one 0x66
@@ -203,14 +234,14 @@
_66_0x8C: /* MOV Ew,Seg */
nextop = F8;
GET_EW;
EW->word[0] = emu->segs[(nextop&38)>>3];
EW->word[0] = emu->segs[(nextop&0x38)>>3];
NEXT;
_66_0x8E: /* MOV Seg,Ew */
nextop = F8;
GET_EW;
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
emu->segs_clean[((nextop&0x38)>>3)] = 0;
emu->segs_serial[((nextop&0x38)>>3)] = 0;
NEXT;
_66_0x8F: /* POP Ew */
nextop = F8;
@@ -241,15 +272,12 @@
_66_0x9C: /* PUSHFW */
CHECK_FLAGS(emu);
PackFlags(emu);
Push16(emu, (uint16_t)emu->packed_eflags.x32);
Push16(emu, (uint16_t)emu->eflags.x32);
NEXT;
_66_0x9D: /* POPFW */
CHECK_FLAGS(emu);
PackFlags(emu);
emu->packed_eflags.x32 &=0xffff0000;
emu->packed_eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
UnpackFlags(emu);
emu->eflags.x32 &=0xffff0000;
emu->eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
NEXT;
_66_0xA1: /* MOV AX,Ow */
@@ -327,6 +355,22 @@
EW->word[0] = F16;
NEXT;
_66_0xCB: /* FAR RET */
ip = Pop(emu);
emu->segs[_CS] = Pop(emu); // no check, no use....
emu->segs_serial[_CS] = 0;
// need to check status of CS register!
STEP
NEXT;
_66_0xCC: /* INT3 */
emu->old_ip = R_EIP;
R_EIP = ip-1;
if(my_context->signals[SIGTRAP])
raise(SIGTRAP);
ip = R_EIP;
if(emu->quit) goto fini;
STEP
NEXT;
_66_0xD1: /* GRP2 Ew,1 */
_66_0xD3: /* GRP2 Ew,CL */
nextop = F8;
@@ -350,6 +394,7 @@
Run66D9(emu);
ip = R_EIP;
if(emu->quit) goto fini;
STEP
NEXT;
_66_0xDD:
@@ -358,8 +403,17 @@
Run66DD(emu);
ip = R_EIP;
if(emu->quit) goto fini;
STEP
NEXT;
_66_0xF0: /* LOCK prefix */
emu->old_ip = R_EIP;
R_EIP = ip - 2;
RunLock66(emu);
ip = R_EIP;
if(emu->quit) goto fini;
STEP
NEXT;
_66_0xF2: /* REPNZ prefix */
_66_0xF3: /* REPZ prefix */
+8 -88
View File
@@ -10,11 +10,7 @@
case 0xC5:
case 0xC6:
case 0xC7: /* FADD */
#ifdef USE_FLOAT
ST0.f += ST(nextop&7).f;
#else
ST0.d += ST(nextop&7).d;
#endif
break;
case 0xC8:
case 0xC9:
@@ -24,11 +20,7 @@
case 0xCD:
case 0xCE:
case 0xCF: /* FMUL */
#ifdef USE_FLOAT
ST0.f *= ST(nextop&7).f;
#else
ST0.d *= ST(nextop&7).d;
#endif
break;
case 0xD0:
case 0xD1:
@@ -38,11 +30,7 @@
case 0xD5:
case 0xD6:
case 0xD7: /* FCOM */
#ifdef USE_FLOAT
fpu_fcom(emu, ST(nextop&7).f);
#else
fpu_fcom(emu, ST(nextop&7).d);
#endif
break;
case 0xD8:
case 0xD9:
@@ -52,11 +40,7 @@
case 0xDD:
case 0xDE:
case 0xDF: /* FCOMP */
#ifdef USE_FLOAT
fpu_fcom(emu, ST(nextop&7).f);
#else
fpu_fcom(emu, ST(nextop&7).d);
#endif
fpu_do_pop(emu);
break;
case 0xE0:
@@ -67,11 +51,7 @@
case 0xE5:
case 0xE6:
case 0xE7: /* FSUB */
#ifdef USE_FLOAT
ST0.f -= ST(nextop&7).f;
#else
ST0.d -= ST(nextop&7).d;
#endif
break;
case 0xE8:
case 0xE9:
@@ -81,11 +61,7 @@
case 0xED:
case 0xEE:
case 0xEF: /* FSUBR */
#ifdef USE_FLOAT
ST0.f = ST(nextop&7).f - ST0.f;
#else
ST0.d = ST(nextop&7).d - ST0.d;
#endif
break;
case 0xF0:
case 0xF1:
@@ -95,11 +71,7 @@
case 0xF5:
case 0xF6:
case 0xF7: /* FDIV */
#ifdef USE_FLOAT
ST0.f /= ST(nextop&7).f;
#else
ST0.d /= ST(nextop&7).d;
#endif
break;
case 0xF8:
case 0xF9:
@@ -109,46 +81,26 @@
case 0xFD:
case 0xFE:
case 0xFF: /* FDIVR */
#ifdef USE_FLOAT
ST0.f = ST(nextop&7).f / ST0.f;
#else
ST0.d = ST(nextop&7).d / ST0.d;
#endif
break;
default:
switch((nextop>>3)&7) {
case 0: /* FADD ST0, float */
GET_ED;
if(!(((uintptr_t)ED)&3))
#ifdef USE_FLOAT
ST0.f += *(float*)ED;
#else
ST0.d += *(float*)ED;
#endif
else {
*(uint32_t*)&f = ED->dword[0];
#ifdef USE_FLOAT
ST0.f += f;
#else
memcpy(&f, ED, sizeof(float));
ST0.d += f;
#endif
}
break;
case 1: /* FMUL ST0, float */
GET_ED;
if(!(((uintptr_t)ED)&3))
#ifdef USE_FLOAT
ST0.f *= *(float*)ED;
#else
ST0.d *= *(float*)ED;
#endif
else {
*(uint32_t*)&f = ED->dword[0];
#ifdef USE_FLOAT
ST0.f *= f;
#else
memcpy(&f, ED, sizeof(float));
ST0.d *= f;
#endif
}
break;
case 2: /* FCOM ST0, float */
@@ -156,7 +108,7 @@
if(!(((uintptr_t)ED)&3))
fpu_fcom(emu, *(float*)ED);
else {
*(uint32_t*)&f = ED->dword[0];
memcpy(&f, ED, sizeof(float));
fpu_fcom(emu, f);
}
break;
@@ -165,7 +117,7 @@
if(!(((uintptr_t)ED)&3))
fpu_fcom(emu, *(float*)ED);
else {
*(uint32_t*)&f = ED->dword[0];
memcpy(&f, ED, sizeof(float));
fpu_fcom(emu, f);
}
fpu_do_pop(emu);
@@ -173,69 +125,37 @@
case 4: /* FSUB ST0, float */
GET_ED;
if(!(((uintptr_t)ED)&3))
#ifdef USE_FLOAT
ST0.f -= *(float*)ED;
#else
ST0.d -= *(float*)ED;
#endif
else {
*(uint32_t*)&f = ED->dword[0];
#ifdef USE_FLOAT
ST0.f -= f;
#else
memcpy(&f, ED, sizeof(float));
ST0.d -= f;
#endif
}
break;
case 5: /* FSUBR ST0, float */
GET_ED;
if(!(((uintptr_t)ED)&3))
#ifdef USE_FLOAT
ST0.f = *(float*)ED - ST0.f;
#else
ST0.d = *(float*)ED - ST0.d;
#endif
else {
*(uint32_t*)&f = ED->dword[0];
#ifdef USE_FLOAT
ST0.f = f - ST0.f;
#else
memcpy(&f, ED, sizeof(float));
ST0.d = f - ST0.d;
#endif
}
break;
case 6: /* FDIV ST0, float */
GET_ED;
if(!(((uintptr_t)ED)&3))
#ifdef USE_FLOAT
ST0.f /= *(float*)ED;
#else
ST0.d /= *(float*)ED;
#endif
else {
*(uint32_t*)&f = ED->dword[0];
#ifdef USE_FLOAT
ST0.f /= f;
#else
memcpy(&f, ED, sizeof(float));
ST0.d /= f;
#endif
}
break;
case 7: /* FDIVR ST0, float */
GET_ED;
if(!(((uintptr_t)ED)&3))
#ifdef USE_FLOAT
ST0.f = *(float*)ED / ST0.f;
#else
ST0.d = *(float*)ED / ST0.d;
#endif
else {
*(uint32_t*)&f = ED->dword[0];
#ifdef USE_FLOAT
ST0.f = f / ST0.f;
#else
memcpy(&f, ED, sizeof(float));
ST0.d = f / ST0.d;
#endif
}
break;
default:
+47 -157
View File
@@ -1,5 +1,3 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
nextop = F8;
switch (nextop) {
case 0xC0:
@@ -10,9 +8,9 @@
case 0xC5:
case 0xC6:
case 0xC7: /* FLD STx */
ll = ST(nextop&7).ll;
ll = ST(nextop&7).sq;
fpu_do_push(emu);
ST0.ll = ll;
ST0.sq = ll;
break;
case 0xC8:
case 0xC9:
@@ -22,27 +20,19 @@
case 0xCD:
case 0xCE:
case 0xCF: /* FXCH STx */
ll = ST(nextop&7).ll;
ST(nextop&7).ll = ST0.ll;
ST0.ll = ll;
ll = ST(nextop&7).sq;
ST(nextop&7).sq = ST0.sq;
ST0.sq = ll;
break;
case 0xD0: /* FNOP */
break;
case 0xE0: /* FCHS */
#ifdef USE_FLOAT
ST0.f = -ST0.f;
#else
ST0.d = -ST0.d;
#endif
break;
case 0xE1: /* FABS */
#ifdef USE_FLOAT
ST0.f = fabsf(ST0.f);
#else
ST0.d = fabs(ST0.d);
#endif
break;
case 0xE4: /* FTST */
@@ -54,153 +44,96 @@
case 0xE8: /* FLD1 */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = 1.0f;
#else
ST0.d = 1.0;
#endif
break;
case 0xE9: /* FLDL2T */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = L2T;
#else
ST0.d = L2T;
#endif
break;
case 0xEA: /* FLDL2E */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = L2E;
#else
ST0.d = L2E;
#endif
break;
case 0xEB: /* FLDPI */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = PI;
#else
ST0.d = PI;
#endif
break;
case 0xEC: /* FLDLG2 */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = LG2;
#else
ST0.d = LG2;
#endif
break;
case 0xED: /* FLDLN2 */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = LN2;
#else
ST0.d = LN2;
#endif
break;
case 0xEE: /* FLDZ */
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = 0.0f;
#else
ST0.d = 0.0;
#endif
break;
case 0xF0: /* F2XM1 */
#ifdef USE_FLOAT
ST0.f = exp2f(ST0.f) - 1.0f;
#else
ST0.d = exp2(ST0.d) - 1.0;
#endif
break;
case 0xF1: /* FYL2X */
#ifdef USE_FLOAT
ST(1).f = log2f(ST0.f)*ST(1).f;
#else
ST(1).d = log2(ST0.d)*ST(1).d;
#endif
ST(1).d *= log2(ST0.d);
fpu_do_pop(emu);
break;
case 0xF2: /* FPTAN */
#ifdef USE_FLOAT
ST0.f = tanf(ST0.f);
fpu_do_push(emu);
ST0.f = 1.0f;
#else
ST0.d = tan(ST0.d);
fpu_do_push(emu);
ST0.d = 1.0;
#endif
emu->sw.f.F87_C2 = 0;
break;
case 0xF3: /* FPATAN */
#ifdef USE_FLOAT
ST1.f = atan2f(ST1.f, ST0.f);
#else
ST1.d = atan2(ST1.d, ST0.d);
#endif
fpu_do_pop(emu);
break;
case 0xF4: /* FXTRACT */
#ifdef USE_FLOAT
tmp32s = (ST0.ll&0x7f700000)>>23;
tmp32s -= 127;
ST0.f /= exp2f(tmp32s);
fpu_do_push(emu);
ST0.f = tmp32s;
#else
tmp32s = (ST0.ll&0x7ff0000000000000LL)>>52;
tmp32s -= 1023;
ST0.d /= exp2(tmp32s);
ST0.d = frexp(ST0.d, &tmp32s);
fpu_do_push(emu);
ST0.d = tmp32s;
#endif
break;
case 0xF8: /* FPREM */
#ifdef USE_FLOAT
ll = ST0.f / ST1.f;
ST0.f -= ST1.f * ll;
#else
ll = ST0.d / ST1.d;
ST0.d -= ST1.d * ll;
#endif
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C0 = (ll&1);
emu->sw.f.F87_C3 = ((ll>>1)&1);
emu->sw.f.F87_C1 = ((ll>>2)&1);
break;
case 0xF5: /* FPREM1 */
// get exponant(ST(0))-exponant(ST(1)) in temp32s
#ifdef USE_FLOAT
tmp32s = ((ST0.ll&0x7f700000)>>23) - ((ST1.ll&0x7f700000)>>23);
#else
tmp32s = ((ST0.ll&0x7ff0000000000000LL)>>52) - ((ST1.ll&0x7ff0000000000000LL)>>52);
#endif
{
int e0, e1;
frexp(ST0.d, &e0);
frexp(ST1.d, &e1);
tmp32s = e0 - e1;
}
if(tmp32s<64)
{
#ifdef USE_FLOAT
ll = (int64_t)round(ST0.f/ST1.f);
ST0.f = ST0.f - (ST1.f*ll);
#else
ll = (int64_t)round(ST0.d/ST1.d);
ll = (int64_t)floor(ST0.d/ST1.d);
ST0.d = ST0.d - (ST1.d*ll);
#endif
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = (ll&1)?1:0;
emu->sw.f.F87_C3 = (ll&2)?1:0;
emu->sw.f.F87_C0 = (ll&4)?1:0;
} else {
#ifdef USE_FLOAT
ll = (int64_t)(floor((ST0.f/ST1.f))/powf(2, tmp32s - 32));
ST0.f = ST0.f - ST1.f*ll*powf(2, 32);
#else
ll = (int64_t)(floor((ST0.d/ST1.d))/pow(2, tmp32s - 32));
ST0.d = ST0.d - ST1.d*ll*pow(2, tmp32s - 32);
#endif
ll = (int64_t)(floor((ST0.d/ST1.d))/exp2(tmp32s - 32));
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
emu->sw.f.F87_C2 = 1;
}
break;
case 0xF5: /* FPREM1 */
// get exponant(ST(0))-exponant(ST(1)) in temp32s
{
int e0, e1;
frexp(ST0.d, &e0);
frexp(ST1.d, &e1);
tmp32s = e0 - e1;
}
if(tmp32s<64)
{
ll = (int64_t)round(ST0.d/ST1.d);
ST0.d = ST0.d - (ST1.d*ll);
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = (ll&1)?1:0;
emu->sw.f.F87_C3 = (ll&2)?1:0;
emu->sw.f.F87_C0 = (ll&4)?1:0;
} else {
ll = (int64_t)(trunc((ST0.d/ST1.d))/exp2(tmp32s - 32));
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
emu->sw.f.F87_C2 = 1;
}
break;
@@ -211,56 +144,32 @@
emu->top=(emu->top+1)&7; // this will probably break a few things
break;
case 0xF9: /* FYL2XP1 */
#ifdef USE_FLOAT
ST(1).f = log2f(ST0.f + 1.0f)*ST(1).f;
#else
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
#endif
ST(1).d *= log2(ST0.d + 1.0);
fpu_do_pop(emu);
break;
case 0xFA: /* FSQRT */
#ifdef USE_FLOAT
ST0.f = sqrtf(ST0.f);
#else
ST0.d = sqrt(ST0.d);
#endif
break;
case 0xFB: /* FSINCOS */
fpu_do_push(emu);
#ifdef USE_FLOAT
sincosf(ST1.f, &ST1.f, &ST0.f);
#else
sincos(ST1.d, &ST1.d, &ST0.d);
#endif
emu->sw.f.F87_C2 = 0;
break;
case 0xFC: /* FRNDINT */
#ifdef USE_FLOAT
ST0.f = fpu_round(emu, ST0.f);
#else
ST0.d = fpu_round(emu, ST0.d);
#endif
break;
case 0xFD: /* FSCALE */
// this could probably be done by just altering the exponant part of the float...
#ifdef USE_FLOAT
ST0.f *= exp2f(truncf(ST1.f));
#else
ST0.d *= exp2(trunc(ST1.d));
#endif
if(ST0.d!=0.0)
ST0.d *= exp2(trunc(ST1.d));
break;
case 0xFE: /* FSIN */
#ifdef USE_FLOAT
ST0.f = sinf(ST0.f);
#else
ST0.d = sin(ST0.d);
#endif
emu->sw.f.F87_C2 = 0;
break;
case 0xFF: /* FCOS */
#ifdef USE_FLOAT
ST0.f = cosf(ST0.f);
#else
ST0.d = cos(ST0.d);
#endif
emu->sw.f.F87_C2 = 0;
break;
@@ -288,42 +197,30 @@
case 0: /* FLD ST0, Ed float */
GET_ED;
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.ll = ED->dword[0];
#else
if(!(((uintptr_t)ED)&3))
ST0.d = *(float*)ED;
else {
memcpy(&f, ED->dword, sizeof(float));
memcpy(&f, ED, sizeof(float));
ST0.d = f;
}
#endif
break;
case 2: /* FST Ed, ST0 */
GET_ED;
#ifdef USE_FLOAT
*(float*)ED = ST0.f;
#else
if(!(((uintptr_t)ED)&3))
*(float*)ED = ST0.d;
else {
f = ST0.d;
memcpy(ED->dword, &f, sizeof(float));
memcpy(ED, &f, sizeof(float));
}
#endif
break;
case 3: /* FSTP Ed, ST0 */
GET_ED;
#ifdef USE_FLOAT
ED->dword[0] = ST0.ll;
#else
if(!(((uintptr_t)ED)&3))
*(float*)ED = ST0.d;
else {
f = ST0.d;
memcpy(ED->dword, &f, sizeof(float));
memcpy(ED, &f, sizeof(float));
}
#endif
fpu_do_pop(emu);
break;
case 4: /* FLDENV m */
@@ -341,12 +238,6 @@
// warning, incomplete
GET_ED;
fpu_savenv(emu, (char*)ED, 0);
ED->dword[0] = emu->cw;
ED->dword[1] = emu->sw.x16;
// tagword: 2bits*8
ED->word[4] = 0;
for (int i=0; i<8; ++i)
ED->word[4] |= (emu->p_regs[i].tag)<<(i*2);
// intruction pointer: 48bits
// data (operand) pointer: 48bits
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
@@ -359,4 +250,3 @@
goto _default;
}
}
#pragma GCC diagnostic pop
+6 -34
View File
@@ -11,7 +11,7 @@
case 0xC7:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_CF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xC8: /* FCMOVE ST(0), ST(i) */
case 0xC9:
@@ -23,7 +23,7 @@
case 0xCF:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD0: /* FCMOVBE ST(0), ST(i) */
case 0xD1:
@@ -35,7 +35,7 @@
case 0xD7:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD8: /* FCMOVU ST(0), ST(i) */
case 0xD9:
@@ -47,15 +47,11 @@
case 0xDF:
CHECK_FLAGS(emu);
if(ACCESS_FLAG(F_PF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xE9: /* FUCOMPP */
#ifdef USE_FLOAT
fpu_fcom(emu, ST1.f);
#else
fpu_fcom(emu, ST1.d); // bad, should handle QNaN and IA interrupt
#endif
fpu_do_pop(emu);
fpu_do_pop(emu);
break;
@@ -76,19 +72,11 @@
switch((nextop>>3)&7) {
case 0: /* FIADD ST0, Ed int */
GET_ED;
#ifdef USE_FLOAT
ST0.f += ED->sdword[0];
#else
ST0.d += ED->sdword[0];
#endif
break;
case 1: /* FIMUL ST0, Ed int */
GET_ED;
#ifdef USE_FLOAT
ST0.f *= ED->sdword[0];
#else
ST0.d *= ED->sdword[0];
#endif
break;
case 2: /* FICOM ST0, Ed int */
GET_ED;
@@ -101,35 +89,19 @@
break;
case 4: /* FISUB ST0, Ed int */
GET_ED;
#ifdef USE_FLOAT
ST0.f -= ED->sdword[0];
#else
ST0.d -= ED->sdword[0];
#endif
break;
case 5: /* FISUBR ST0, Ed int */
GET_ED;
#ifdef USE_FLOAT
ST0.f = ED->sdword[0] - ST0.f;
#else
ST0.d = ED->sdword[0] - ST0.d;
#endif
ST0.d = (double)ED->sdword[0] - ST0.d;
break;
case 6: /* FIDIV ST0, Ed int */
GET_ED;
#ifdef USE_FLOAT
ST0.f /= ED->sdword[0];
#else
ST0.d /= ED->sdword[0];
#endif
break;
case 7: /* FIDIVR ST0, Ed int */
GET_ED;
#ifdef USE_FLOAT
ST0.f = ED->sdword[0] / ST0.f;
#else
ST0.d = ED->sdword[0] / ST0.d;
#endif
ST0.d = (double)ED->sdword[0] / ST0.d;
break;
}
}
+16 -108
View File
@@ -10,7 +10,7 @@
case 0xC7:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_CF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xC8: /* FCMOVNE ST(0), ST(i) */
case 0xC9:
@@ -22,7 +22,7 @@
case 0xCF:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_ZF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD0: /* FCMOVNBE ST(0), ST(i) */
case 0xD1:
@@ -34,7 +34,7 @@
case 0xD7:
CHECK_FLAGS(emu);
if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xD8: /* FCMOVNU ST(0), ST(i) */
case 0xD9:
@@ -46,9 +46,11 @@
case 0xDF:
CHECK_FLAGS(emu);
if(!ACCESS_FLAG(F_PF))
ST0.ll = ST(nextop&7).ll;
ST0.q = ST(nextop&7).q;
break;
case 0xE1: /* FDISI8087_NOP */
break;
case 0xE2: /* FNCLEX */
//Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE),
// the exception summary status flag (ES), the stack fault flag (SF), and the busy flag (B) in the FPU status word
@@ -73,11 +75,7 @@
case 0xED:
case 0xEE:
case 0xEF:
#ifdef USE_FLOAT
fpu_fcomi(emu, ST(nextop&7).f);
#else
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
#endif
break;
case 0xF0: /* FCOMI ST0, STx */
@@ -88,14 +86,9 @@
case 0xF5:
case 0xF6:
case 0xF7:
#ifdef USE_FLOAT
fpu_fcomi(emu, ST(nextop&7).f);
#else
fpu_fcomi(emu, ST(nextop&7).d);
#endif
break;
case 0xE0:
case 0xE1:
case 0xE4:
case 0xE5:
case 0xE6:
@@ -103,134 +96,49 @@
goto _default;
default:
switch((nextop>>3)&7) {
case 0: /* FILD ST0, Gd */
case 0: /* FILD ST0, Ed */
GET_ED;
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = ED->sdword[0];
#else
ST0.d = ED->sdword[0];
#endif
break;
case 1: /* FISTTP Ed, ST0 */
GET_ED;
#ifdef USE_FLOAT
tmp32s = ST0.f; // TODO: Handling of FPU Exception
if(tmp32s==0x7fffffff && isgreater(ST0.f, (float)(int32_t)0x7fffffff))
tmp32s = 0x80000000;
#else
tmp32s = ST0.d; // TODO: Handling of FPU Exception
if(tmp32s==0x7fffffff && isgreater(ST0.d, (double)(int32_t)0x7fffffff))
tmp32s = 0x80000000;
#endif
fpu_do_pop(emu);
ED->sdword[0] = tmp32s;
break;
case 2: /* FIST Ed, ST0 */
GET_ED;
#ifdef USE_FLOAT
if(isgreater(ST0.f, (float)(int32_t)0x7fffffff) || isless(ST0.f, -(float)(int32_t)0x7fffffff))
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
ED->sdword[0] = 0x80000000;
else {
switch(emu->round) {
case ROUND_Nearest:
ED->sdword[0] = floorf(ST0.f+0.5);
break;
case ROUND_Down:
ED->sdword[0] = floorf(ST0.f);
break;
case ROUND_Up:
ED->sdword[0] = ceilf(ST0.f);
break;
case ROUND_Chop:
ED->sdword[0] = ST0.f;
break;
}
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
ED->sdword[0] = tmp;
}
#else
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff))
ED->sdword[0] = 0x80000000;
else {
switch(emu->round) {
case ROUND_Nearest:
ED->sdword[0] = floor(ST0.d+0.5);
break;
case ROUND_Down:
ED->sdword[0] = floor(ST0.d);
break;
case ROUND_Up:
ED->sdword[0] = ceil(ST0.d);
break;
case ROUND_Chop:
ED->sdword[0] = ST0.d;
break;
}
}
#endif
break;
case 3: /* FISTP Ed, ST0 */
GET_ED;
#ifdef USE_FLOAT
if(isgreater(ST0.f, (float)(int32_t)0x7fffffff) || isless(ST0.f, -(float)(int32_t)0x7fffffff))
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
ED->sdword[0] = 0x80000000;
else {
switch(emu->round) {
case ROUND_Nearest:
ED->sdword[0] = floorf(ST0.f+0.5);
break;
case ROUND_Down:
ED->sdword[0] = floorf(ST0.f);
break;
case ROUND_Up:
ED->sdword[0] = ceilf(ST0.f);
break;
case ROUND_Chop:
ED->sdword[0] = ST0.f;
break;
}
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
ED->sdword[0] = tmp;
}
#else
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff))
ED->sdword[0] = 0x80000000;
else {
switch(emu->round) {
case ROUND_Nearest:
ED->sdword[0] = floor(ST0.d+0.5);
break;
case ROUND_Down:
ED->sdword[0] = floor(ST0.d);
break;
case ROUND_Up:
ED->sdword[0] = ceil(ST0.d);
break;
case ROUND_Chop:
ED->sdword[0] = ST0.d;
break;
}
}
#endif
fpu_do_pop(emu);
break;
case 5: /* FLD ST0, Gt */
case 5: /* FLD ST0, Et */
GET_ED;
fpu_do_push(emu);
memcpy(&STld(0).ld, ED, 10);
#ifdef USE_FLOAT
LD2D(&STld(0), &d);
ST0.f = d;
#else
LD2D(&STld(0), &ST(0).d);
#endif
STld(0).ref = ST0.ll;
STld(0).uref = ST0.q;
break;
case 7: /* FSTP tbyte */
GET_ED;
if(ST0.ll!=STld(0).ref)
#ifdef USE_FLOAT
{d = ST0.f; D2LD(&d, ED);}
#else
if(ST0.q!=STld(0).uref)
D2LD(&ST0.d, ED);
#endif
else
memcpy(ED, &STld(0).ld, 10);
fpu_do_pop(emu);
+9 -97
View File
@@ -1,5 +1,3 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
nextop = F8;
switch(nextop) {
case 0xC0:
@@ -10,11 +8,7 @@
case 0xC5:
case 0xC6:
case 0xC7: /* FADD */
#ifdef USE_FLOAT
ST(nextop&7).f += ST0.f;
#else
ST(nextop&7).d += ST0.d;
#endif
break;
case 0xC8:
case 0xC9:
@@ -24,11 +18,7 @@
case 0xCD:
case 0xCE:
case 0xCF: /* FMUL */
#ifdef USE_FLOAT
ST(nextop&7).f *= ST0.f;
#else
ST(nextop&7).d *= ST0.d;
#endif
break;
case 0xD0:
case 0xD1:
@@ -38,11 +28,7 @@
case 0xD5:
case 0xD6:
case 0xD7: /* FCOM */
#ifdef USE_FLOAT
fpu_fcom(emu, ST(nextop&7).f);
#else
fpu_fcom(emu, ST(nextop&7).d);
#endif
break;
case 0xD8:
case 0xD9:
@@ -52,11 +38,7 @@
case 0xDD:
case 0xDE:
case 0xDF: /* FCOMP */
#ifdef USE_FLOAT
fpu_fcom(emu, ST(nextop&7).f);
#else
fpu_fcom(emu, ST(nextop&7).d); // TODO: is this ok?
#endif
fpu_fcom(emu, ST(nextop&7).d);
fpu_do_pop(emu);
break;
case 0xE0:
@@ -67,11 +49,7 @@
case 0xE5:
case 0xE6:
case 0xE7: /* FSUBR */
#ifdef USE_FLOAT
ST(nextop&7).f = ST0.f -ST(nextop&7).f;
#else
ST(nextop&7).d = ST0.d -ST(nextop&7).d;
#endif
break;
case 0xE8:
case 0xE9:
@@ -81,11 +59,7 @@
case 0xED:
case 0xEE:
case 0xEF: /* FSUB */
#ifdef USE_FLOAT
ST(nextop&7).f -= ST0.f;
#else
ST(nextop&7).d -= ST0.d;
#endif
break;
case 0xF0:
case 0xF1:
@@ -95,11 +69,7 @@
case 0xF5:
case 0xF6:
case 0xF7: /* FDIVR */
#ifdef USE_FLOAT
ST(nextop&7).f = ST0.f / ST(nextop&7).f;
#else
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
#endif
break;
case 0xF8:
case 0xF9:
@@ -109,54 +79,32 @@
case 0xFD:
case 0xFE:
case 0xFF: /* FDIV */
#ifdef USE_FLOAT
ST(nextop&7).f /= ST0.f;
#else
ST(nextop&7).d /= ST0.d;
#endif
break;
default:
GET_ED;
switch((nextop>>3)&7) {
case 0: /* FADD ST0, double */
#ifdef USE_FLOAT
if(!(((uintptr_t)ED)&7))
ST0.f += *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
ST0.f += d;
}
#else
if(!(((uintptr_t)ED)&7))
ST0.d += *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
ST0.d += d;
}
#endif
break;
case 1: /* FMUL ST0, double */
#ifdef USE_FLOAT
if(!(((uintptr_t)ED)&7))
ST0.f *= *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
ST0.f *= d;
}
#else
if(!(((uintptr_t)ED)&7))
ST0.d *= *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
ST0.d *= d;
}
#endif
break;
case 2: /* FCOM ST0, double */
if(!(((uintptr_t)ED)&7))
fpu_fcom(emu, *(double*)ED);
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
fpu_fcom(emu, d);
}
break;
@@ -164,78 +112,42 @@
if(!(((uintptr_t)ED)&7))
fpu_fcom(emu, *(double*)ED);
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
fpu_fcom(emu, d);
}
fpu_do_pop(emu);
break;
case 4: /* FSUB ST0, double */
#ifdef USE_FLOAT
if(!(((uintptr_t)ED)&7))
ST0.f -= *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
ST0.f -= d;
}
#else
if(!(((uintptr_t)ED)&7))
ST0.d -= *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
ST0.d -= d;
}
#endif
break;
case 5: /* FSUBR ST0, double */
#ifdef USE_FLOAT
if(!(((uintptr_t)ED)&7))
ST0.f = *(double*)ED - ST0.f;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
ST0.f = d - ST0.f;
}
#else
if(!(((uintptr_t)ED)&7))
ST0.d = *(double*)ED - ST0.d;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
ST0.d = d - ST0.d;
}
#endif
break;
case 6: /* FDIV ST0, double */
#ifdef USE_FLOAT
if(!(((uintptr_t)ED)&7))
ST0.f /= *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
ST0.f /= d;
}
#else
if(!(((uintptr_t)ED)&7))
ST0.d /= *(double*)ED;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
ST0.d /= d;
}
#endif
break;
case 7: /* FDIVR ST0, double */
#ifdef USE_FLOAT
if(!(((uintptr_t)ED)&7))
ST0.f = *(double*)ED / ST0.f;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
ST0.f = d / ST0.f;
}
#else
if(!(((uintptr_t)ED)&7))
ST0.d = *(double*)ED / ST0.d;
else {
*(uint64_t*)&d = *(uint64_t*)ED;
memcpy(&d, ED, sizeof(double));
ST0.d = d / ST0.d;
}
#endif
break;
default:
goto _default;
+23 -43
View File
@@ -20,7 +20,7 @@
case 0xD5:
case 0xD6:
case 0xD7:
ST(nextop&7).ll = ST0.ll;
ST(nextop&7).q = ST0.q;
break;
case 0xD8: /* FSTP ST0, STx */
case 0xD9:
@@ -30,7 +30,7 @@
case 0xDD:
case 0xDE:
case 0xDF:
ST(nextop&7).ll = ST0.ll;
ST(nextop&7).q = ST0.q;
fpu_do_pop(emu);
break;
case 0xE0: /* FUCOM ST0, STx */
@@ -41,11 +41,7 @@
case 0xE5:
case 0xE6:
case 0xE7:
#ifdef USE_FLOAT
fpu_fcom(emu, ST(nextop&7).f);
#else
fpu_fcom(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
#endif
break;
case 0xE8: /* FUCOMP ST0, STx */
case 0xE9:
@@ -55,11 +51,7 @@
case 0xED:
case 0xEE:
case 0xEF:
#ifdef USE_FLOAT
fpu_fcom(emu, ST(nextop&7).f);
#else
fpu_fcom(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
#endif
fpu_do_pop(emu);
break;
@@ -94,39 +86,37 @@
case 0: /* FLD double */
GET_ED;
fpu_do_push(emu);
#ifdef USE_FLOAT
*(uint64_t*)&d = *(int64_t*)ED;
ST0.f = d;
#else
ST0.ll = *(int64_t*)ED;
#endif
if(!(((uintptr_t)ED)&7))
ST0.d = *(double*)ED;
else {
memcpy(&ST0.d, ED, sizeof(double));
}
break;
case 1: /* FISTTP ED qword */
GET_ED;
#ifdef USE_FLOAT
*(int64_t*)ED = ST0.f;
#else
*(int64_t*)ED = ST0.d;
#endif
if(!(((uintptr_t)ED)&7))
*(int64_t*)ED = ST0.d;
else {
int64_t i64 = ST0.d;
memcpy(ED, &i64, sizeof(int64_t));
}
fpu_do_pop(emu);
break;
case 2: /* FST double */
GET_ED;
#ifdef USE_FLOAT
d = ST0.f;
*(int64_t*)ED = *(uint64_t*)&d;
#else
*(int64_t*)ED = ST0.ll;
#endif
if(!(((uintptr_t)ED)&7))
*(double*)ED = ST0.d;
else {
memcpy(ED, &ST0.d, sizeof(double));
}
break;
case 3: /* FSTP double */
GET_ED;
#ifdef USE_FLOAT
d = ST0.f;
*(int64_t*)ED = *(uint64_t*)&d;
#else
*(int64_t*)ED = ST0.ll;
#endif
if(!(((uintptr_t)ED)&7))
*(double*)ED = ST0.d;
else {
memcpy(ED, &ST0.d, sizeof(double));
}
fpu_do_pop(emu);
break;
case 4: /* FRSTOR m108byte */
@@ -137,12 +127,7 @@
char* p =(char*)ED;
p += 28;
for (int i=0; i<8; ++i) {
#ifdef USE_FLOAT
d = ST(i).f;
LD2D(p, &d);
#else
LD2D(p, &ST(i).d);
#endif
p+=10;
}
}
@@ -157,12 +142,7 @@
char* p =(char*)ED;
p += 28;
for (int i=0; i<8; ++i) {
#ifdef USE_FLOAT
D2LD(&d, p);
ST(i).f = d;
#else
D2LD(&ST(i).d, p);
#endif
p+=10;
}
}
+18 -87
View File
@@ -1,55 +1,41 @@
nextop = F8;
switch (nextop) {
case 0xC1: /* FADDP ST1, ST0 */
#ifdef USE_FLOAT
ST(1).f += ST0.f;
#else
ST(1).d += ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xC0: /* FADDP STx, ST0 */
case 0xC1: /* FADDP ST1, ST0 */
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
#ifdef USE_FLOAT
ST(nextop&7).f += ST0.f;
#else
ST(nextop&7).d += ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xC9: /* FMULP ST1, ST0 */
#ifdef USE_FLOAT
ST1.f *= ST0.f;
#else
ST1.d *= ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xC8: /* FMULP STx, ST0 */
case 0xC9: /* FMULP ST1, ST0 */
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
#ifdef USE_FLOAT
ST(nextop&7).f *= ST0.f;
#else
ST(nextop&7).d *= ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7: /* FCOMP */
fpu_fcom(emu, ST(nextop&7).d);
fpu_do_pop(emu);
break;
case 0xD9: /* FCOMPP */
#ifdef USE_FLOAT
fpu_fcom(emu, ST1.f);
#else
fpu_fcom(emu, ST1.d);
#endif
fpu_do_pop(emu);
fpu_do_pop(emu);
break;
@@ -65,33 +51,18 @@
case 0xE5:
case 0xE6:
case 0xE7:
#ifdef USE_FLOAT
ST(nextop&7).f = ST0.f - ST(nextop&7).f;
#else
ST(nextop&7).d = ST0.d - ST(nextop&7).d;
#endif
fpu_do_pop(emu);
break;
case 0xE9: /* FSUBP ST1, ST0 */
#ifdef USE_FLOAT
ST1.f -= ST0.f;
#else
ST1.d -= ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xE8: /* FSUBP STx, ST0 */
case 0xE9: /* FSUBP ST1, ST0 */
case 0xEA:
case 0xEB:
case 0xEC:
case 0xED:
case 0xEE:
case 0xEF:
#ifdef USE_FLOAT
ST(nextop&7).f -= ST0.f;
#else
ST(nextop&7).d -= ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xF0: /* FDIVRP STx, ST0 */
@@ -102,11 +73,7 @@
case 0xF5:
case 0xF6:
case 0xF7:
#ifdef USE_FLOAT
ST(nextop&7).f = ST0.f / ST(nextop&7).f;
#else
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
#endif
fpu_do_pop(emu);
break;
case 0xF8: /* FDIVP STx, ST0 */
@@ -117,23 +84,11 @@
case 0xFD:
case 0xFE:
case 0xFF:
#ifdef USE_FLOAT
ST(nextop&7).f /= ST0.f;
#else
ST(nextop&7).d /= ST0.d;
#endif
fpu_do_pop(emu);
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
case 0xD8:
case 0xD8:
case 0xDA:
case 0xDB:
case 0xDC:
@@ -146,51 +101,27 @@
switch((nextop>>3)&7) {
case 0: /* FIADD ST0, Ew int */
GET_EW;
#ifdef USE_FLOAT
ST0.f += EW->sword[0];
#else
ST0.d += EW->sword[0];
#endif
break;
case 1: /* FIMUL ST0, Ew int */
GET_EW;
#ifdef USE_FLOAT
ST0.f *= EW->sword[0];
#else
ST0.d *= EW->sword[0];
#endif
break;
case 4: /* FISUB ST0, Ew int */
GET_EW;
#ifdef USE_FLOAT
ST0.f -= EW->sword[0];
#else
ST0.d -= EW->sword[0];
#endif
break;
case 5: /* FISUBR ST0, Ew int */
GET_EW;
#ifdef USE_FLOAT
ST0.f = EW->sword[0] - ST0.f;
#else
ST0.d = EW->sword[0] - ST0.d;
#endif
ST0.d = (double)EW->sword[0] - ST0.d;
break;
case 6: /* FIDIV ST0, Ew int */
GET_EW;
#ifdef USE_FLOAT
ST0.f /= EW->sword[0];
#else
ST0.d /= EW->sword[0];
#endif
break;
case 7: /* FIDIVR ST0, Ew int */
GET_EW;
#ifdef USE_FLOAT
ST0.f = EW->sword[0] / ST0.f;
#else
ST0.d = EW->sword[0] / ST0.d;
#endif
ST0.d = (double)EW->sword[0] / ST0.d;
break;
default:
goto _default;
+52 -127
View File
@@ -1,5 +1,29 @@
nextop = F8;
switch (nextop) {
case 0xC0: /* FFREEP STx */
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
fpu_do_free(emu, nextop-0xC0);
fpu_do_pop(emu);
break;
case 0xD0: /* FSTP STx, ST0 */
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
ST(nextop&7).q = ST0.q;
fpu_do_pop(emu);
break;
case 0xE0: /* FNSTSW AX */
emu->sw.f.F87_TOP = emu->top&7;
R_AX = emu->sw.x16;
@@ -13,11 +37,7 @@
case 0xED:
case 0xEE:
case 0xEF:
#ifdef USE_FLOAT
fpu_fcomi(emu, ST(nextop&7).f);
#else
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
#endif
fpu_do_pop(emu);
break;
@@ -29,22 +49,10 @@
case 0xF5:
case 0xF6:
case 0xF7:
#ifdef USE_FLOAT
fpu_fcomi(emu, ST(nextop&7).f);
#else
fpu_fcomi(emu, ST(nextop&7).d);
#endif
fpu_do_pop(emu);
break;
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
case 0xC8:
case 0xC9:
case 0xCA:
@@ -53,14 +61,6 @@
case 0xCD:
case 0xCE:
case 0xCF:
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
case 0xD8:
case 0xD9:
case 0xDA:
@@ -92,105 +92,27 @@
GET_EW;
tmp16s = EW->sword[0];
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = tmp16s;
#else
ST0.d = tmp16s;
#endif
break;
case 1: /* FISTTP Ew, ST0 */
GET_EW;
#ifdef USE_FLOAT
tmp16s = ST0.f;
#else
tmp16s = ST0.d;
#endif
EW->sword[0] = tmp16s;
fpu_do_pop(emu);
break;
case 2: /* FIST Ew, ST0 */
GET_EW;
#ifdef USE_FLOAT
if(isgreater(ST0.f, (float)(int32_t)0x7fff) || isless(ST0.f, -(float)(int32_t)0x7fff))
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff) || !isfinite(ST0.d))
EW->sword[0] = 0x8000;
else {
switch(emu->round) {
case ROUND_Nearest:
EW->sword[0] = floorf(ST0.f+0.5);
break;
case ROUND_Down:
EW->sword[0] = floorf(ST0.f);
break;
case ROUND_Up:
EW->sword[0] = ceilf(ST0.f);
break;
case ROUND_Chop:
EW->sword[0] = ST0.f;
break;
}
}
#else
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff))
EW->sword[0] = 0x8000;
else {
switch(emu->round) {
case ROUND_Nearest:
EW->sword[0] = floor(ST0.d+0.5);
break;
case ROUND_Down:
EW->sword[0] = floor(ST0.d);
break;
case ROUND_Up:
EW->sword[0] = ceil(ST0.d);
break;
case ROUND_Chop:
EW->sword[0] = ST0.d;
break;
}
}
#endif
else
EW->sword[0] = fpu_round(emu, ST0.d);
break;
case 3: /* FISTP Ew, ST0 */
GET_EW;
#ifdef USE_FLOAT
if(isgreater(ST0.f, (float)(int32_t)0x7fff) || isless(ST0.f, -(float)(int32_t)0x7fff))
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff) || !isfinite(ST0.d))
EW->sword[0] = 0x8000;
else {
switch(emu->round) {
case ROUND_Nearest:
EW->sword[0] = floorf(ST0.f+0.5);
break;
case ROUND_Down:
EW->sword[0] = floorf(ST0.f);
break;
case ROUND_Up:
EW->sword[0] = ceilf(ST0.f);
break;
case ROUND_Chop:
EW->sword[0] = ST0.f;
break;
}
}
#else
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff))
EW->sword[0] = 0x8000;
else {
switch(emu->round) {
case ROUND_Nearest:
EW->sword[0] = floor(ST0.d+0.5);
break;
case ROUND_Down:
EW->sword[0] = floor(ST0.d);
break;
case ROUND_Up:
EW->sword[0] = ceil(ST0.d);
break;
case ROUND_Chop:
EW->sword[0] = ST0.d;
break;
}
}
#endif
else
EW->sword[0] = fpu_round(emu, ST0.d);
fpu_do_pop(emu);
break;
case 4: /* FBLD ST0, tbytes */
@@ -202,13 +124,9 @@
GET_ED;
tmp64s = *(int64_t*)ED;
fpu_do_push(emu);
#ifdef USE_FLOAT
ST0.f = tmp64s;
#else
ST0.d = tmp64s;
#endif
STll(0).ll = tmp64s;
STll(0).ref = ST0.ll;
STll(0).sq = tmp64s;
STll(0).sref = ST0.sq;
break;
case 6: /* FBSTP tbytes, ST0 */
GET_ED;
@@ -217,20 +135,27 @@
break;
case 7: /* FISTP i64 */
GET_ED;
if(STll(0).ref==ST(0).ll) {
*(int64_t*)ED = STll(0).ll;
if((uintptr_t)ED & 0x7) {
// un-aligned!
if(STll(0).sref==ST(0).sq)
memcpy(ED, &STll(0).sq, sizeof(int64_t));
else {
int64_t i64;
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
i64 = 0x8000000000000000LL;
else
i64 = fpu_round(emu, ST0.d);
memcpy(ED, &i64, sizeof(int64_t));
}
} else {
#ifdef USE_FLOAT
if(isgreater(ST0.f, (float)(int64_t)0x7fffffffffffffffLL) || isless(ST0.f, (float)(int64_t)0x8000000000000000LL))
*(int64_t*)ED = 0x8000000000000000LL;
else
*(int64_t*)ED = (int64_t)ST0.f;
#else
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL))
*(int64_t*)ED = 0x8000000000000000LL;
else
*(int64_t*)ED = (int64_t)ST0.d;
#endif
if(STll(0).sref==ST(0).sq)
*(int64_t*)ED = STll(0).sq;
else {
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
*(int64_t*)ED = 0x8000000000000000LL;
else
*(int64_t*)ED = fpu_round(emu, ST0.d);
}
}
fpu_do_pop(emu);
break;
+123 -6
View File
@@ -35,7 +35,7 @@
case 0x2D: /* CVTSD2SI Gd, Ex */
nextop = F8;
GET_EX;
switch(emu->round) {
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GD.sdword[0] = floor(EX->d[0]+0.5);
break;
@@ -66,7 +66,6 @@
GET_EX;
GX.d[0] *= EX->d[0];
break;
case 0x5A: /* CVTSD2SS Gx, Ex */
nextop = F8;
GET_EX;
@@ -125,6 +124,93 @@
}
break;
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
case BASE+0: \
PREFIX \
if(ACCESS_FLAG(F_OF)) \
CONDITIONAL \
break; \
case BASE+1: \
PREFIX \
if(!ACCESS_FLAG(F_OF)) \
CONDITIONAL \
break; \
case BASE+2: \
PREFIX \
if(ACCESS_FLAG(F_CF)) \
CONDITIONAL \
break; \
case BASE+3: \
PREFIX \
if(!ACCESS_FLAG(F_CF)) \
CONDITIONAL \
break; \
case BASE+4: \
PREFIX \
if(ACCESS_FLAG(F_ZF)) \
CONDITIONAL \
break; \
case BASE+5: \
PREFIX \
if(!ACCESS_FLAG(F_ZF)) \
CONDITIONAL \
break; \
case BASE+6: \
PREFIX \
if((ACCESS_FLAG(F_ZF) || ACCESS_FLAG(F_CF))) \
CONDITIONAL \
break; \
case BASE+7: \
PREFIX \
if(!(ACCESS_FLAG(F_ZF) || ACCESS_FLAG(F_CF))) \
CONDITIONAL \
break; \
case BASE+8: \
PREFIX \
if(ACCESS_FLAG(F_SF)) \
CONDITIONAL \
break; \
case BASE+9: \
PREFIX \
if(!ACCESS_FLAG(F_SF)) \
CONDITIONAL \
break; \
case BASE+0xA: \
PREFIX \
if(ACCESS_FLAG(F_PF)) \
CONDITIONAL \
break; \
case BASE+0xB: \
PREFIX \
if(!ACCESS_FLAG(F_PF)) \
CONDITIONAL \
break; \
case BASE+0xC: \
PREFIX \
if(ACCESS_FLAG(F_SF) != ACCESS_FLAG(F_OF)) \
CONDITIONAL \
break; \
case BASE+0xD: \
PREFIX \
if(ACCESS_FLAG(F_SF) == ACCESS_FLAG(F_OF)) \
CONDITIONAL \
break; \
case BASE+0xE: \
PREFIX \
if(ACCESS_FLAG(F_ZF) || (ACCESS_FLAG(F_SF) != ACCESS_FLAG(F_OF))) \
CONDITIONAL \
break; \
case BASE+0xF: \
PREFIX \
if(!ACCESS_FLAG(F_ZF) && (ACCESS_FLAG(F_SF) == ACCESS_FLAG(F_OF))) \
CONDITIONAL \
break;
GOCOND(0x80
, tmp32s = F32S; CHECK_FLAGS(emu);
, ip += tmp32s;
) /* 0x80 -> 0x8F Jxx */
case 0xC2: /* CMPSD Gx, Ex, Ib */
nextop = F8;
GET_EX;
@@ -132,8 +218,8 @@
tmp8s = 0;
switch(tmp8u&7) {
case 0: tmp8s=(GX.d[0] == EX->d[0]); break;
case 1: tmp8s=isless(GX.d[0], EX->d[0]); break;
case 2: tmp8s=islessequal(GX.d[0], EX->d[0]); break;
case 1: tmp8s=isless(GX.d[0], EX->d[0]) && !(isnan(GX.d[0]) || isnan(EX->d[0])); break;
case 2: tmp8s=islessequal(GX.d[0], EX->d[0]) && !(isnan(GX.d[0]) || isnan(EX->d[0])); break;
case 3: tmp8s=isnan(GX.d[0]) || isnan(EX->d[0]); break;
case 4: tmp8s=(GX.d[0] != EX->d[0]); break;
case 5: tmp8s=isnan(GX.d[0]) || isnan(EX->d[0]) || isgreaterequal(GX.d[0], EX->d[0]); break;
@@ -143,6 +229,15 @@
GX.q[0]=(tmp8s)?0xffffffffffffffffLL:0LL;
break;
case 0xD0: /* ADDSUBPS Gx, Ex */
nextop = F8;
GET_EX;
GX.f[0] -= EX->f[0];
GX.f[1] += EX->f[1];
GX.f[2] -= EX->f[2];
GX.f[3] += EX->f[3];
break;
case 0xD6: /* MOVDQ2Q Gm, Ex */
nextop = F8;
GET_EX;
@@ -152,11 +247,33 @@
case 0xE6: /* CVTPD2DQ Gx, Ex */
nextop = F8;
GET_EX;
GX.sd[0] = EX->d[0];
GX.sd[1] = EX->d[1];
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GX.sd[0] = floor(EX->d[0]+0.5);
GX.sd[1] = floor(EX->d[1]+0.5);
break;
case ROUND_Down:
GX.sd[0] = floor(EX->d[0]);
GX.sd[1] = floor(EX->d[1]);
break;
case ROUND_Up:
GX.sd[0] = ceil(EX->d[0]);
GX.sd[1] = ceil(EX->d[1]);
break;
case ROUND_Chop:
GX.sd[0] = EX->d[0];
GX.sd[1] = EX->d[1];
break;
}
GX.q[1] = 0;
break;
case 0xF0: /* LDDQU Gx, Ex */
nextop = F8;
GET_EX;
memcpy(&GX, EX, 16);
break;
default:
goto _default;
}
+34 -3
View File
@@ -15,6 +15,19 @@
GET_EX;
EX->ud[0] = GX.ud[0];
break;
case 0x12: /* MOVSLDUP Gx, Ex */
nextop = F8;
GET_EX;
GX.ud[1] = GX.ud[0] = EX->ud[0];
GX.ud[3] = GX.ud[2] = EX->ud[2];
break;
case 0x16: /* MOVSHDUP Gx, Ex */
nextop = F8;
GET_EX;
GX.ud[1] = GX.ud[0] = EX->ud[1];
GX.ud[3] = GX.ud[2] = EX->ud[3];
break;
case 0x1E: /* NOP / ENDBR32 / ENDBR64 */
nextop = F8;
@@ -39,7 +52,7 @@
case 0x2D: /* CVTSS2SI Gd, Ex */
nextop = F8;
GET_EX;
switch(emu->round) {
switch((emu->mxcsr>>13)&3) {
case ROUND_Nearest:
GD.sdword[0] = floor(EX->f[0]+0.5);
break;
@@ -169,6 +182,24 @@
}
break;
case 0xBD: /* LZCNT Ed,Gd */
CHECK_FLAGS(emu);
nextop = F8;
GET_ED;
tmp32u = ED->dword[0];
if(tmp32u) {
tmp8u = 0;
while(!(tmp32u&(1<<(31-tmp8u)))) ++tmp8u;
GD.dword[0] = tmp8u;
CONDITIONAL_SET_FLAG(tmp8u==0, F_ZF);
CLEAR_FLAG(F_CF);
} else {
SET_FLAG(F_CF);
CLEAR_FLAG(F_ZF);
GD.dword[0] = 32;
}
break;
case 0xC2: /* CMPSS Gx, Ex, Ib */
nextop = F8;
GET_EX;
@@ -176,8 +207,8 @@
tmp8s = 0;
switch(tmp8u&7) {
case 0: tmp8s=(GX.f[0] == EX->f[0]); break;
case 1: tmp8s=isless(GX.f[0], EX->f[0]); break;
case 2: tmp8s=islessequal(GX.f[0], EX->f[0]); break;
case 1: tmp8s=isless(GX.f[0], EX->f[0]) && !(isnan(GX.f[0]) || isnan(EX->f[0])); break;
case 2: tmp8s=islessequal(GX.f[0], EX->f[0]) && !(isnan(GX.f[0]) || isnan(EX->f[0])); break;
case 3: tmp8s=isnan(GX.f[0]) || isnan(EX->f[0]); break;
case 4: tmp8s=(GX.f[0] != EX->f[0]); break;
case 5: tmp8s=isnan(GX.f[0]) || isnan(EX->f[0]) || isgreaterequal(GX.f[0], EX->f[0]); break;
Loaded 100 of 868 files, more files were not shown because too many files have changed in this diff. Show more