Compare commits

...
470 Commits
Author SHA1 Message Date
ptitSeb 81c56d7155 Bumped version to v0.3.8 2025-10-13 14:05:21 +02:00
Yang Liu 524bf21011 [LA64_DYNAREC] Fixed BEXTR opcode (#3067) 2025-10-13 11:26:01 +02:00
Yang Liu 6fbb827955 [LA64_DYNAREC] Fixed non-lbt path INC/DEC opcodes register conflicts (#3066) 2025-10-13 11:25:25 +02:00
Yang Liu 80610037cd [LA64_DYNAREC] Fixed some oversized load (#3065) 2025-10-13 10:19:01 +02:00
Yang Liu bbd22d76be [INTERP] Fixed 16bit PUSH/POP opcodes (#3064) 2025-10-13 09:40:58 +02:00
Yang Liu 256632ea4c [INTERP] Improved cosim handling on 16bit BT/BTS/BTR/BTC opcodes (#3063) 2025-10-12 21:02:42 +02:00
Yang Liu f5eff13acc [RV64_DYNAREC] Fixed some 16bit BT/BTS/BTR/BTC opcodes (#3062) 2025-10-12 20:29:35 +02:00
ptitSeb 7b66c024f0 [DYNACACHE] Allow Dynacache to be serialized when _exit is used 2025-10-12 14:52:49 +02:00
Yang Liu af437fa354 [ARM64_DYNAREC] Fixed a typo in iret_to_epilog (#3059) 2025-10-12 09:09:12 +02:00
Yang Liu 2a559622c9 [INTERP] Fixed GetECommon_16 truncation (#3058) 2025-10-12 09:08:43 +02:00
Yang Liu 494428dbbe [DYNAREC] Fixed negative issues with 0F/F0 A3/AB/B3/BB opcodes (#3057) 2025-10-11 20:15:10 +02:00
Yang Liu a40b6d49cb [RV64_DYNAREC] Fixed some missing sse_forget_reg for implicit xmm0 (#3056) 2025-10-11 19:27:58 +02:00
Yang Liu a5b3c0af5e [INTERP] Fixed a typo in 0F C7 /1 CMPXCHG16B opcode (#3055) 2025-10-11 17:07:29 +02:00
Yang Liu 276e67f329 [INTERP] Fixed a typo in AVX 0F 38 F5 BZHI opcode (#3054) 2025-10-11 14:27:10 +02:00
Yang Liu 56684a2f67 [RV64_DYNAREC] Fixed a typo in 16bit ROR/ROL opcodes (#3053) 2025-10-11 14:25:30 +02:00
Yang Liu 56b4de3b84 [DYNAREC] Fixed some oversized memory load (#3051)
* [DYNAREC] Fixed some oversized memory load

* review
2025-10-10 22:35:59 +02:00
ptitSeb 275c25a048 [INTERP] Fixed 66 E8/E9/EA opcodes in 32bits mode 2025-10-10 16:22:41 +02:00
ptitSeb 0a0228eae2 [ARM64_DYNAREC] Changed BSF/BSR to not changed Ed if Gd==0 (seems current cpu does this) 2025-10-10 16:21:50 +02:00
Yang Liu 65b6f716d5 [DYNAREC] Fixed 66 8D opcode and also a regression introduced in last commit (#3050) 2025-10-10 15:59:31 +02:00
Yang Liu 70ab16a6d6 [DYNAREC][INTERP] Fixed an edge case of CMPXHG (#3049) 2025-10-10 14:45:50 +02:00
ptitSeb 74d4db051b [WRAPPER] Fixed one wrapped function signature (for #3048) 2025-10-10 13:27:19 +02:00
ptitSeb 41f61cf702 [ARM64_DYNAREC] Don't assume x1 is xRIP in link_next (fix regression introduced with 685afa2302) 2025-10-10 13:19:29 +02:00
Yang Liu f0eab197be [DYNAREC] Fixed a special case of SHLD/SHRD opcodes (#3047) 2025-10-10 11:39:02 +02:00
Yang Liu 6250f03b09 [DYNAREC][INTERP] Added a few multibyte nops (#3046) 2025-10-10 10:38:04 +02:00
ptitSeb 535798a730 [BOX32][WRAPPER] Added a missing 32bits function to libc 2025-10-09 14:37:07 +02:00
ptitSeb 89e5c644d0 [BOX32][WRAPPER] Improved glob(64) support 2025-10-09 10:23:29 +02:00
ptitSeb 2ae7402fd7 [BOX32][WRAPPER] Fixed a regression with FT_Done_Face just introduced earlier 2025-10-08 17:16:56 +02:00
ptitSeb 18d95a4627 [BOX32][WRAPPER] Added some more 32bits wrapped functions to libfreetype 2025-10-08 16:57:48 +02:00
ptitSeb b6c9cc93fb [BOX32][WRAPPER] Added 1 more wrapped function to libdbus 2025-10-08 16:41:54 +02:00
ptitSeb 4cc74f45eb [BOX32][WRAPPER] Added 1 more wrapped function to libm 2025-10-08 16:37:25 +02:00
ptitSeb 9892089325 [BOX32][WRAPPER] Added a few more libc 32bits wrapped functions 2025-10-08 16:33:41 +02:00
ptitSeb a029fca7bd [BOX32][WRAPPER] more 32bits wrapped function to libxrandr 2025-10-08 16:20:41 +02:00
ptitSeb 3cfe54f8cf [BOX32][WRAPPER] Added 2 more 32bits functions to libfontconfig 2025-10-08 15:59:23 +02:00
ptitSeb 297dc34799 [BOX32][WRAPPER] Added some more libfreetype wrapped functions 2025-10-08 15:50:48 +02:00
ptitSeb c0ec7eb2bf [BOX32][WRAPPER] Added 1 more 32bits wrapped function to libmount 2025-10-08 14:22:07 +02:00
ptitSeb c33e39bd25 [BOX32][WRAPPER] Added some more libc 32bits wrapped functions 2025-10-08 14:15:05 +02:00
ptitSeb 1dd9b23022 [BOX32][WRAPPER] Added 2 wrapped functions that are misnamed in some programs 2025-10-08 13:57:56 +02:00
ptitSeb 63592011fe [ARM64_DYNAREC] Use UDF for UD2 & unsupported WBINVD 2025-10-07 15:34:20 +02:00
BrunoSX 73238883cb Fixed mmap tracking with MAP_NORESERVE flag on Android (#3044) 2025-10-06 22:14:22 +02:00
Chi-Kuan Chiu 73aed7fd0e [Docs] Add glibc capability warning and fix typo (#3043)
* Fix typo

* Add glibc capability warning
2025-10-06 20:22:49 +02:00
xctan e8ed70905c [DYNAREC] Optimized scalar AES impl in DynaRec (#3041)
* [DYNAREC] Optimized scalar AES impl

* [RV64_DYNAREC] Optimized AES with RVV

* [CI] Bump RISC-V toolchains

* [RV64_DYNAREC] Switch to scalar impl when xtheadvector is present

* [RV64_DYNAREC] Try to disable rvv aes kernels

* [RV64_DYNAREC] Reverted assembly aes functions
2025-10-05 09:56:07 +02:00
ptitSeb f9aa5651cc [BOX32][DYNAREC] Small fix on 32bits SIGILL handling 2025-10-03 18:15:21 +02:00
ptitSeb b1c10d5ccd [DYNAREC] Small fix on SIGILL handling 2025-10-03 17:37:12 +02:00
ptitSeb 7bf2caa5c4 [DYNAREC] Added BOX64_DYNAREC_NOHOTPAGE to disabled hotpage detection 2025-10-03 15:45:11 +02:00
ptitSeb 6ae0524da6 Made SIGILL traced behind BOX64_SHOWSEGV=1, like SIGSEGV 2025-10-03 15:43:19 +02:00
ptitSeb 5768989e54 [DYNAREC] Fixe a speed regression introduced with 3fe020572d (for #3038) 2025-10-03 10:35:08 +02:00
ptitSeb c4c9f1b8cd [INTERP] Fixed regression introduced with latest change on IRET opcode 2025-10-02 10:07:52 +02:00
ptitSeb d547fe4d37 [ARM64_DYNAREC] Small improvment on some invalid opcode handling 2025-10-01 15:57:49 +02:00
ptitSeb 118f4cf3b4 [INTERP] Don't print unsupported opcode on known invalid opcodes 2025-10-01 15:56:56 +02:00
ptitSeb 5ac53d6be2 [TRACE] Added tooling to check if x86/x64 opcode is valid 2025-10-01 15:56:05 +02:00
ptitSeb a02873b9ee [TRACE] Allow both v3 and v4 of libZydis to be on the system 2025-10-01 14:06:04 +02:00
ptitSeb ba9731838e [TRACE] Small improvment in x64 decoder trace when decoder fails 2025-09-30 19:07:42 +02:00
ptitSeb 7c064ef16c [INTERP] Fixed a regression with previous commit 2025-09-29 14:25:52 +02:00
ptitSeb 84756e1ada [INTERP] Better handling of boggus selector for IRET & JMP FAR 2025-09-29 13:31:42 +02:00
ptitSeb a37f7d1800 [ARM64_DYNAREC] Improved IRET handling of boggus parameters 2025-09-29 13:31:15 +02:00
ptitSeb 86dde8c1f7 Improved TF handling 2025-09-29 12:47:36 +02:00
Yang Liu e48881715a [RV64_DYNAREC] Added more scalar avx opcodes (#3037) 2025-09-29 12:12:12 +02:00
definitelyuncertain 79e3d00e35 Explicitly link standard libs through CMake (#3035)
* Explicitly link standard libs through CMake

* Also keep the original link flags
2025-09-27 14:10:12 +02:00
Yang Liu 9b2bef153b [WRAPPER] Wrapped a few more crypto3 symbols (#3034) 2025-09-27 09:46:16 +02:00
Yang Liu 4d7e9ccf51 [RV64_DYNAREC] Fixed a scratch register confliction (#3033) 2025-09-27 08:53:09 +02:00
ptitSeb 8f5613055d [ARM64_DYNAREC] Added more variant of INS/OUT opcodes 2025-09-24 21:23:48 +02:00
ptitSeb 501e8a77ec [INTERP] Added more variant of INS/OUT opcodes 2025-09-24 21:22:36 +02:00
ptitSeb 0e90b94272 [ARM64_DYNAREC] Fixed flags for 8bits imul 2025-09-24 20:38:27 +02:00
ptitSeb 7889934ffa [RCFILE][BOX32] Fine tuned steam profile 2025-09-24 11:03:37 +02:00
Yang Liu 3dfd5bf4b0 RV64_DYNAREC] Added more avx scalar opcodes (#3029) 2025-09-22 16:35:23 +02:00
ptitSeb c605e4630e [RCFILE] Added 2 more game profiles 2025-09-22 16:03:05 +02:00
Yang Liu bad4d13c09 [RV64_DYNAREC] Added more avx scalar opcodes (#3028) 2025-09-22 10:53:52 +02:00
Leslie Zhai 5bfb27d3fa [LA64_DYNAREC] Refactor register mapping (#2940)
* [LA64_DYNAREC] Refactor register mapping

* [LA64_DYNAREC] Fix typo

* [LA64_DYNAREC] Remapping xSavedSP to fp ($r22)

* [LA64_DYNAREC] Fix VPCLMULQDQ x3 and x4 issue

* [LA64_DYNAREC] Fix typo

* [LA64_DYNAREC] Fix typo
2025-09-19 08:10:41 +02:00
ptitSeb 0d355aaf01 [LA64] Do not expose AVX by default for now, there are still some issue to fix before 2025-09-17 21:47:23 +02:00
ptitSeb 220b1e6dad [RCFILE] Fine-tune 2 existing games profile 2025-09-17 18:05:49 +02:00
ptitSeb 78833500c8 [ARM64_DYNAREC] Temporarily disable Atomic path for F0 0F B1, as it avoid some games random freeze (like HorizonZeroDawn or Cyberpunk2077) 2025-09-17 17:41:48 +02:00
Yang Liu 1a58da4315 [LA64_DYNAREC] Fixed AVX 0F 17 VMOVHPS opcode (#3025) 2025-09-17 17:04:32 +02:00
ptitSeb 0f4e298142 [ARM64_DYNAREC] Fixed non-Atomic path for F0 0F C0 opcode 2025-09-17 13:47:44 +02:00
Yang Liu c5981dd11c [LA64_DYNAREC] Fixed AVX 66 0F 67 PACKUSWB opcode (#3024) 2025-09-17 12:39:38 +02:00
Yang Liu 24c15e148d [LA64_DYNAREC] Fixed avx infra (#3023) 2025-09-17 12:02:55 +02:00
ptitSeb ea48f2b823 [DYNAREC] Improved Memory Barrier handling for LOCK prefixed opcodes 2025-09-16 17:44:27 +02:00
ptitSeb 85b07f7441 [ARM64_DYNAREC] Allow use of Native flags when using UFLAG_IF macro helper 2025-09-15 19:02:42 +02:00
Yang Liu c4f5b7c062 [BOX32][TRACE] Fixed chdir tracing (#3021) 2025-09-15 18:48:11 +02:00
ptitSeb 04c1998f1c [RCFILE] Added 1 more game profile 2025-09-14 15:38:43 +02:00
ptitSeb 775c1c19ec [WRAPPER] Added wrapped libblas.so.3 and liblapack.so.3 2025-09-14 15:07:48 +02:00
ptitSeb f077b28459 Small improvment in steam handling 2025-09-14 14:11:22 +02:00
ptitSeb c08fb5d53d [DYNAREC][TRACE] Show if will run Inter or Dynarec when using LongJump to resume emulation after signal 2025-09-14 14:11:04 +02:00
ptitSeb 365b6d57df [INTERP] Better handling of Unimplemented / Invalid opcodes 2025-09-14 14:10:09 +02:00
ptitSeb ef117f726c [RCFILE] Added profile for 2 more games 2025-09-14 09:06:11 +02:00
ptitSeb 52fe2485ae [DYNAREC] Small refactor on StrongMem emulator and lock prefix 2025-09-13 12:53:55 +02:00
ptitSeb 2c6816be8f Update release.yml
Another fix for TERMUX CI
2025-09-12 19:47:38 +02:00
ptitSeb 965e2c93eb Update release.yml
Fixed TERMUX env. setup
2025-09-12 18:46:15 +02:00
ptitSeb fe343190d8 [DYNAREC] Fixed volatile metadata parser that would ignore rage[0] 2025-09-12 17:45:15 +02:00
Chi-Kuan Chiu e514f75c8e [Docs] Add practical cross-compilation details (#3017)
Previous instructions did not mention that users must rename the
`x64lib` folder before placing it in the library search path. Added
examples for x86_64 and i386 to clarify the installation process.
2025-09-12 12:44:45 +02:00
Yang Liu 1dbb057dec [RV64_DYNAREC] Added more scalar avx cmp opcodes (#3016) 2025-09-11 07:44:22 +02:00
ptitSeb 5bd7b24be3 [RCFILE] Added 1 more game profile 2025-09-10 16:44:02 +02:00
ptitSeb f216fda9c1 [ANDROID] Fixing build 2025-09-10 16:17:11 +02:00
ptitSeb 93fc3be3df [BOX32] More work on box32 memory management and threads 2025-09-10 15:44:29 +02:00
ptitSeb d509261f81 [BOX32] Some improvment to box32 memory managment and thread handling 2025-09-10 11:28:59 +02:00
ptitSeb 7862e8a3d5 [BOX32][WRAPPING] Wrapped 2 more functions on libGL (for #2826) 2025-09-10 10:24:24 +02:00
ptitSeb 7acdd87198 [DYNAREC] Fully trust volatile metadata when they are present (fixes Starfield freeze) 2025-09-09 11:59:29 +02:00
Yang Liu 4fb9c658a1 [RV64_DYNAREC] Added more scalar avx opcodes (#3010) 2025-09-09 10:17:21 +02:00
Yang Liu c6bb8b335a [RV64_DYNAREC] Added more scalar avx opcodes and fixed a typo (#3009) 2025-09-08 21:30:04 +02:00
ptitSeb 464fdc3ebe [BOX32] Various small improvments on box32, mostly on memory tracking 2025-09-08 20:45:12 +02:00
ptitSeb 6b9ed18286 [BOX32] Fixed some conversion issues 2025-09-08 19:07:05 +02:00
ptitSeb dca2b99c91 [TRACE] Fixed some typos 2025-09-08 14:21:25 +02:00
ptitSeb 6f144aa429 [ARM64_DYNAREC] A few minor fixes to some opcodes 2025-09-08 11:54:42 +02:00
ptitSeb e5c1e3a2a2 [INTERP] Small fixes in a few rarely used opcodes 2025-09-08 11:53:21 +02:00
ptitSeb e7d2cf5538 [DOCS] Some small fixing / precision in a few doc items 2025-09-08 11:27:37 +02:00
ptitSeb 427f1b8c55 [WRAPPER] Improved wayland wrapping (Unity games seems to run on Wayland now) 2025-09-05 21:08:58 +02:00
ptitSeb f639357591 [WRAPPER] Added VK_ARM_data_graph extension to vulkan wrapper (for #3008) 2025-09-05 10:39:26 +02:00
Yang Liu 49b69ad122 [BOX32] Fixed dirname (#3007) 2025-09-05 09:45:04 +02:00
Yang Liu 1ef35d5d8b [BOX32] Fixed some strange XErrorEvent case (#3006) 2025-09-04 18:18:44 +02:00
ptitSeb 65b7909f6e [BOX32][WRAPPER] Added 1 more symbol to libc 2025-09-04 16:15:13 +02:00
ptitSeb c8c707e7cc [ARM64_DYNAREC] Added some more UD handling in 64bits dynarec 2025-09-04 12:03:19 +02:00
Yang Liu 6440aac9e1 [BOX32] Fixed sign-extend issue when calling RunFunctionFmt with a pointer (#2938) 2025-09-04 11:26:39 +02:00
Yang Liu 4edba2e67a [RV64_DYNAREC] Added more scalar avx opcodes (#3005) 2025-09-04 09:35:12 +02:00
ptitSeb 6b41f28e2b [WOWBOX64] Fixed build 2025-09-03 22:19:24 +02:00
ptitSeb 5e02758713 Make sure to use custom allocator for everything Env related 2025-09-03 18:29:46 +02:00
ptitSeb ff9b2a235b [TRACE] Small improvment for memory allocator trace 2025-09-03 18:29:04 +02:00
ptitSeb be2f566fbf [DYNAREC] Better handling of 32bits 2E & 36 prefix (silent some false negative with Cosim on some multi-bytes NOP) 2025-09-03 18:28:07 +02:00
ptitSeb 08944bc7ca [DYNAREC] Use a static array for preds temporary, like all the other dynarec array 2025-09-03 18:26:20 +02:00
Yang Liu ade6843d3a Removed a useless file (#3001) 2025-09-03 10:04:04 +02:00
theofficialgmanandYang Liu 2de6058c6a [CI] Added ARM64-GCC-8 target (Ubuntu Bionic) (#2987)
* add ARM64-GCC-8 target

uses taiki-e/checkout-action@v1 instead of actions/checkout@v4 due to ubuntu bionic container not having new enough nodejs or glibc to run most github actions

does not build build Trace target due to ubuntu bionic not having the libzydis-dev package

adds cmake ppa for a newer cmake version that box64 requires

uses gcc-8 specifically (instead of bionic's default gcc-7) due to  historically better compatibility with box64 (and it has been used for years now by installation scripts and other ci such as https://github.com/Pi-Apps-Coders/box64-debs)

* comptibility for old glibc

* nodejs

* zstd

* exclude static build

---------

Co-authored-by: Yang Liu <[email protected]>
2025-09-03 08:10:28 +02:00
Yang Liu 986e271280 Minor updates to README.md (#3000) 2025-09-03 08:09:36 +02:00
ptitSeb 578009cccf [WRAPPER] Added experimental cuda wrapping 2025-09-02 21:20:00 +02:00
Yang Liu 94c40d99f6 [BASH] Use custom PS1 prefix to make box64-bash more distinguishable (#2998)
* [BASH] Use custom PS1 prefix to make box64-bash more distinguishable

* quick fix

* tweaks

* review
2025-09-02 21:18:30 +02:00
Yang Liu 28d07f9bf0 [WRAPPERHELPER] Added legacy __attribute support (#2996) 2025-09-02 12:02:42 +02:00
Yang Liu 994ce41adc [WRAPPER] Wrapped a bunch of symbols (#2997) 2025-09-02 11:34:06 +02:00
ptitSeb d890527281 [BOX32] Allow resuming signal directly on dynarec instead of interpretor when possible 2025-09-01 19:41:13 +02:00
Yang Liu 470b8664d2 [RV64_DYNAREC] Added 1 more scalar avx 0F opcode (#2994) 2025-09-01 15:48:21 +02:00
Yang Liu b31e522eb2 [CI] Speedup CI by skipping uncessary jobs when possible (#2993) 2025-09-01 15:17:42 +02:00
ptitSeb cb3cfa991f [INTERP] Fixed and improved 67 prefixed 32bits opcodes 2025-09-01 15:03:29 +02:00
ptitSeb 4b6766c84b [WRAPPER] Improved some libGL function with callback wrapping 2025-09-01 13:30:24 +02:00
Yang Liu 5e5c972cec [RV64_DYNAREC] Added more scalar avx 0F opcodes (#2992)
* [RV64_DYNAREC] Added more scalar avx 0F opcodes

* review
2025-09-01 13:24:47 +02:00
Yang Liu e5556e90df [INTERP][DYNAREC] Aligned !fastnan handling of 0F 51/52 opcodes (#2989)
* [INTERP] Added !fastnan handling to some 0F opcodes

* [RV64_DYNAREC] Fixed/refined !fastnan handling of some 0F opcodes

* la64

* more fixes
2025-09-01 11:39:21 +02:00
ptitSeb 1edd0eb47d Allow resuming signal directly on dynarec instead of interpretor when possible 2025-09-01 11:00:34 +02:00
Yang Liu f46987b6af [LA64_DYNAREC] Fixed a typo in 0F 53 RCPPS opcode (#2991) 2025-09-01 10:54:31 +02:00
phorcys 2af7492cf8 [LA64_DYNAREC] Fix 0f.A3 BT opcode, fix ALSL operand order. (#2988)
ALSL.D:
tmp = (GR[rj][63:0]<<(sa2+1)) + GR[rk][63:0]
GR[rd] = tmp[63:0]
2025-09-01 08:41:08 +02:00
ptitSeb 1b2515cd49 [ARM64_DYNAREC][TRACE] Fixed SWP B/H opcodes printer 2025-08-31 11:43:31 +02:00
Yang Liu 197f962543 [WRAPPER] Wrapped 2 more symbols for libfreetype (#2984) 2025-08-30 19:18:27 +02:00
Yang Liu 373d778f6a [WRAPPER] Wrapped mallinfo2 for libc (#2983) 2025-08-30 18:10:10 +02:00
ptitSeb fcd1aacef0 [ARM64_DYNAREC] Introduced a dynarec version of the UpdateFlags helper function 2025-08-30 16:23:53 +02:00
Yang Liu 56ae4a35e1 Fixed a misguarded box32 endif (#2982) 2025-08-30 15:44:04 +02:00
Yang Liu 1141516226 [WRAPPER] Wrapped more symbols for libresolv (#2981) 2025-08-30 15:42:47 +02:00
Yang Liu b57cafd93d [RV64_DYNAREC] Added more scalar avx opcodes (#2980) 2025-08-30 14:45:34 +02:00
ptitSeb 60ff412d60 [INTERP] Fixed another regression introduced with #cb2c29c5f992cb4e5ec481f8d99b973b90411403 2025-08-29 17:16:55 +02:00
ptitSeb 87064c15ec [RCFILE] Added 2 more game profiles 2025-08-29 15:21:41 +02:00
Yang Liu 67d6501f54 [LA64_DYNAREC] Fixed AVX VCVT[T]PS2DQ fastround path (#2979) 2025-08-29 14:34:00 +02:00
Yang Liu d0ce4ef913 [RV64_DYNAREC] Added more scalar avx opcodes (#2978) 2025-08-29 09:26:17 +02:00
ptitSeb e863acf0a8 [BOX32][TRACE] Improved trace for nanosleep 2025-08-28 11:04:23 +02:00
ptitSeb 3fe020572d Improved handling of TF flag 2025-08-27 16:17:17 +02:00
Yang Liu 234f6f2b14 [RV64_DYNAREC] Added more scalar avx opcodes (#2975)
* [RV64_DYNAREC] Added more scalar avx opcodes

* fix
2025-08-27 13:29:33 +02:00
ptitSeb bdb4aa5dc6 [INTERP] Fixed a regression introduced with cb2c29c5f9 (fixes Wukong) 2025-08-26 23:00:10 +02:00
ptitSeb cf626c580d [TRACE] Adjusted disabled debug code 2025-08-26 16:20:29 +02:00
Yang Liu 485447850c [RV64_DYNAREC] Added more scalar avx opcodes (#2974) 2025-08-26 14:25:44 +02:00
Yang Liu 709a526217 [RV64_DYNAREC] Added more scalar avx opcodes (#2973)
* [RV64_DYNAREC] Added more scalar avx opcodes

* fix
2025-08-26 10:19:51 +02:00
ptitSeb 1cddcad20a [WRAPPER] Improved pulse wrapping 2025-08-25 19:26:09 +02:00
ptitSeb aa30e665ff [TRACE] Small change on commented code (left for debugging purpose) 2025-08-25 17:00:54 +02:00
ptitSeb 9effd3f711 [INTERP] Fixed a regression introduced with a17811f4a6 2025-08-25 16:44:42 +02:00
Yang Liu d71200de69 [RV64_DYNAREC] Added more scalar avx opcodes (#2971) 2025-08-25 13:36:16 +02:00
Yang Liu 8579ef84bd [RV64_DYNAREC] Added more scalar avx opcodes (#2970) 2025-08-25 10:32:59 +02:00
ptitSeb 747882cb4e [BOX32][WRAPPER] Added one more wrapped function to libc 2025-08-24 12:00:58 +02:00
ptitSeb e76570ad7b [BOX32] Sligtly safer handling of 32bits signals 2025-08-24 12:00:24 +02:00
ptitSeb e964b45894 [BOX32][WRAPPER] Fixed some SIGBUS with 32bits smeaphores 2025-08-24 11:32:04 +02:00
ptitSeb b8526c7920 [BOX32][WRAPPER] Added ftw wrapped function to libc 2025-08-24 11:32:04 +02:00
Yang Liu 2a525b4eb2 [RV64_DYNAREC] Added YMM0 placeholder for later optim (#2968) 2025-08-24 10:29:59 +02:00
ptitSeb cb2c29c5f9 [INTERP] Refactored how 64/65/66/67 and F2/F3 prefixes are handled, removing some (mostly) duplicated code 2025-08-22 18:10:13 +02:00
Yang Liu 3b0977eee1 [RV64_DYNAREC] Fixed scalar avx VCMPPD non-ymm case (#2966) 2025-08-22 17:04:05 +02:00
Yang Liu 893ffe8205 [RV64_DYNAREC] Added more scalar avx opcodes (#2965) 2025-08-22 13:13:04 +02:00
Yang Liu 82a91e717a [ARM64_DYNAREC] Fixed an inst name typo (#2964) 2025-08-22 13:12:17 +02:00
Yang Liu 031d3def2d [RV64_DYNAREC] Added scalar SSE 66 0F 3A 60/61/62 opcodes (#2963)
* [RV64_DYNAREC] Added scalar SSE 66 0F 3A 60/61/62 opcodes

* [CI] Bump timeout
2025-08-22 13:11:51 +02:00
Yang Liu 7c32cb24a0 [RV64_DYNAREC] Added more scalar avx 66 0F opcodes (#2960) 2025-08-22 08:45:14 +02:00
Yang Liu cea8f94358 [RV64_DYNAREC] Added more scalar avx opcodes (#2961) 2025-08-21 23:44:40 +02:00
Yang Liu d476217f4c [RV64_DYNAREC] Fixed more scalar avx opcodes (#2959)
* [RV64_DYNAREC] Fixed more scalar avx opcodes

* oops
2025-08-21 19:15:59 +02:00
Yang Liu 34e789484a [CORE] Better trace_file logging (#2958) 2025-08-21 16:55:10 +02:00
Yang Liu 6a6af076dd [COSIM] Better memory diff printing (#2957) 2025-08-21 15:43:46 +02:00
Yang Liu 5327489f39 [RV64_DYNAREC] Fixed some scalar avx opcodes (#2956) 2025-08-21 15:25:42 +02:00
Yang Liu 392255594b [RV64_DYNAREC] Added more scalar avx 66 0F3A opcodes (#2955) 2025-08-21 13:19:56 +02:00
Yang Liu 8d94d21716 [RV64_DYNAREC] Added more scalar avx 66 0F38 opcodes (#2954)
* [RV64_DYNAREC] Added more scalar avx 66 0F38 opcodes

* fix
2025-08-21 13:18:38 +02:00
Yang Liu 44448774a7 [RV64_DYNAREC] Added more scaalr avx opcodes (#2952) 2025-08-19 14:17:10 +02:00
Yang Liu a280884f09 [RV64_DYNAREC] Added more scalar avx opcodes (#2951) 2025-08-19 13:17:02 +02:00
Yang Liu 7435006b7c [RV64_DYNAREC] Added more avx scalar 66 0F38 opcodes (#2950)
* [RV64_DYNAREC] Added more avx scalar 66 0F38 opcodes

* more
2025-08-19 12:26:42 +02:00
Yang Liu 1c2e763ffb [RV64_DYNAREC] Added a few more scalar AVX 66 0F38 opcodes (#2949) 2025-08-18 14:12:24 +02:00
Yang Liu 5f144d8ddd [RV64_DYNAREC] Added scalar AVX VMOVDQA opcodes (#2948) 2025-08-18 12:42:28 +02:00
Yang Liu 0a53d2223a [DYNAREC] Bump ARCH_VERSION (#2947) 2025-08-18 12:41:47 +02:00
Yang Liu fe2930cbe3 [LA64_DYNAREC] Enable AVX/AVX2 by default (#2946) 2025-08-18 12:41:10 +02:00
Yang Liu bf6c1533b3 [RV64_DYNAREC] Added more scalar AVX opcodes (#2945) 2025-08-18 12:40:11 +02:00
Yang Liu 167217c76b [LA64_DYNAREC] Added more scalar AVX opcodes (#2943) 2025-08-15 21:09:44 +02:00
Yang Liu f615a10fe1 [RV64_DYNAREC] Added more scalar AVX VMOV opcodes (#2942)
* [RV64_DYNAREC] Added more scalar AVX VMOV opcodes

* more
2025-08-15 20:13:04 +02:00
Yang Liu 2d60c8c5b9 [RV64_DYNAREC] Added scalar AVX VMOVSS opcodes (#2941) 2025-08-15 14:18:38 +02:00
phorcys 270ce3750e [LA64_DYNAREC] Add la64 BMI/BMI2 ops. (#2933)
VEX.0F.38  BLSR, BLSMSK, BLSI, BZHI, BEXTR
VEX.F2.0F.38 PDEP, MULX
VEX.F3.0F.38 PEXT
2025-08-15 14:16:58 +02:00
Yang Liu 83e2427bfe [RV64_DYNAREC] Fixed OF2 handling (#2937) 2025-08-15 00:17:31 +02:00
Yang Liu 3815c28bfe [DYNAREC] Fixed reading emu->df (#2936) 2025-08-15 00:16:34 +02:00
phorcys 5144a2e286 [LA64_DYNAREC] Fix VMOVNTDQA. (#2934) 2025-08-15 00:13:16 +02:00
phorcys febaf31b93 [LA64_DYNAREC] Add la64 avx insts using helpers. (#2935)
VEX.66.0F.38 VAESIMC, VAESENC, VAESENCLAST, VAESDEC, VAESDECLAST
VEX.66.0F.3a  VPCLMULQDQ, VAESKEYGENASSIST
2025-08-15 00:09:27 +02:00
Yang Liu af057e309a [RV64_DYNAREC] Removed a dispensable line from dump (#2932) 2025-08-13 20:37:39 +02:00
Yang Liu db864b6aa6 [LA64_DYNAREC] Fixed a typo in CMPXCHG8B opcode (#2931) 2025-08-13 13:24:01 +02:00
Yang Liu 3793e595f0 [DYNAREC] Rearranged arch-specific AVX infra code (#2930) 2025-08-13 13:21:51 +02:00
phorcys abe29cc0ba [LA64_DYNAREC] Fix B3 BTR eflags when cpuext.lbt == 1. Fix 16bits AND when cpuext.lbt == 1. (#2929) 2025-08-12 14:38:15 +02:00
Yang Liu c4e50cdbb1 [RV64_DYNAREC] Added F0 08 LOCK OR opcode (#2928) 2025-08-12 00:05:22 +02:00
Yang Liu dce81673af [RV64_DYNAREC] Fixed F0 10 LOCK ADC opcode (#2927) 2025-08-11 15:32:13 +02:00
Yang Liu df2e4f941f [RV64_DYNAREC][LA64_DYNAREC] Fixed missing zeroup in geted_32() (#2921) 2025-08-08 14:40:42 +02:00
Yang Liu efd01c1126 [LA64_DYNAREC] Fixed AVX VPMOVMSKB opcode (#2920) 2025-08-07 23:25:30 +02:00
Yang Liu 197e5e440d [LA64_DYNAREC] Fixed AVX VPERM2F128/VPERM2I128 opcodes (#2919) 2025-08-07 23:24:47 +02:00
Yang Liu eff93582a7 [LA64_DYNAREC] Fixed AVX VMASKMOVDQU opcode (#2918) 2025-08-07 23:23:33 +02:00
Yang Liu 1535907f2d [LA64_DYNAREC] Fixed AVX VPBLENDW opcodes (#2917) 2025-08-07 23:21:52 +02:00
Yang Liu 9eb1642ec8 [LA64_DYNAREC] Fixed AVX VMOVMSKPS/VMOVMSKPD opcodes (#2916) 2025-08-07 23:20:23 +02:00
Yang Liu c85072e4d3 [LA64_DYNAREC] Fixed AVX VMOVSS opcode (#2915) 2025-08-07 23:19:28 +02:00
Yang Liu e1b6976528 [LA64_DYNAREC] Fixed AVX VCMPSS/VCMPSD opcodes (#2914) 2025-08-07 23:18:32 +02:00
Yang Liu a9aff45bf2 [LA64_DYNAREC] Fixed some AVX scalar MIN/MAX opcodes (#2913) 2025-08-07 23:17:30 +02:00
Yang Liu c59b9f2686 [LA64_DYNAREC] Refined F3 0F 5D/5F MINSS/MAXSS opcodes (#2912) 2025-08-07 23:15:47 +02:00
Yang Liu 98431d8cf5 [BOX32] Enlarge xcb connects size for Linux Steam (#2910) 2025-08-07 12:35:42 +02:00
Yang Liu a083025565 [ARM64_DYNAREC] Fixed AVX VMOVMSKPD opcode (#2909) 2025-08-06 17:26:57 +02:00
Yang Liu 309dad99b4 [ARM64_DYNAREC] Fixed AVX VMOVSS opcode (#2908) 2025-08-06 17:23:40 +02:00
Yang Liu c2c5d3b836 [ARM64_DYNAREC][INTERP] Fixed AVX VPERM2F128/VPERM2I128 opcodes (#2907) 2025-08-06 17:22:32 +02:00
Yang Liu 87baa884d2 [LA64_DYNAREC] Fixed 66 0F 3A 16 PEXTRD opcode (#2906) 2025-08-06 10:42:50 +02:00
Yang Liu 442d6a262b [LA64_DYNAREC] Fixed 66 F3 0F B8 POPCNT opcode (#2905) 2025-08-06 10:41:22 +02:00
Yang Liu 47dbadb4d4 [RV64_DYNAREC] Added 1 more opcode (#2903) 2025-08-06 10:35:17 +02:00
Yang Liu 676efe4032 [LA64_DYNAREC] Added more opcodes (#2902) 2025-08-06 10:34:37 +02:00
Chi-Kuan ChiuandJim Huang dd7b99ffd1 Add O(1) early-out to eusing cached bounds (#2901)
Add a fast-path in rb_get() and rb_get_64() that checks the tree’s
cached leftmost->start and rightmost->end bounds before calling
find_addr(). If the query address lies outside the address bounds,
we return 0 immediately, avoiding an unnecessary tree walk.

This mirrors the idea used in jserv/rbtree’s rb_cached_contains(),
using cached min/max to short-circuit lookups.

Behavior is unchanged (both functions still return 0 when not found);
only negative lookups become cheaper.

Co-authored-by: Jim Huang <[email protected]>
2025-08-05 23:43:12 +02:00
Leslie Zhai f82c5440b7 [WRAPPER] Wrapped g_thread_pool some functions (#2900) 2025-08-05 14:33:45 +02:00
ptitSeb c9d5e8bfc3 [RCFILE] Added 1 more game profile 2025-08-05 13:52:52 +02:00
Leslie Zhai 7e5598d0db [WRAPPER] Wrapped g_async_queue_new_full, g_async_queue_push_sorted, (#2899)
g_thread_pool_free, g_thread_pool_new and g_thread_pool_push
2025-08-05 12:01:52 +02:00
Max Parry 9d5b2f3cc5 [DOCS] Fix typo in link (#2898)
1-byte change, I know, I know.
2025-08-05 10:24:39 +02:00
Leslie Zhai 1eba5b1af6 [WRAPPER] Wrapped g_object_add_toggle_ref, g_object_remove_toggle_ref (#2897)
and g_object_weak_unref
2025-08-05 10:23:49 +02:00
Leslie Zhai daeff6fc41 [WRAPPER] Wrapped g_type_module_use, g_type_module_register_type and g_type_module_add_interface (#2895)
* [WRAPPER] Wrapped g_type_module_use, g_type_module_register_type and g_type_module_add_interface

* [WRAPPER] Removed duplicated my_GInterfaceInfo_t
2025-08-05 08:22:01 +02:00
Yang Liu 368f14b4ce [LA64_DYNAREC] Fixed F3 0F 53 RCPSS opcode (#2892) 2025-08-04 14:35:32 +02:00
Yang Liu f480ae4459 [LA64_DYNAREC] Fixed 66 0F 3A 0F PALIGNR for case where dst==src (#2894) 2025-08-04 14:35:04 +02:00
Yang Liu bfb2d14fee [LA64_DYNAREC] Fixed 66 0F 38 06 PHSUBD opcode (#2893) 2025-08-04 14:34:12 +02:00
Yang Liu bef83b6c03 [LA64_DYNAREC] Fixed 66 0F 3A 21 INSERTPS opcode (#2891) 2025-08-04 13:56:27 +02:00
Yang Liu f4cd829c82 [LA64_DYNAREC] Added and optimized more fastround=0 cases (#2890) 2025-08-04 13:52:28 +02:00
ptitSeb 7b0ecf9f6c [STEAM] Added PROTON_USE_WOW64 to the script generated by install_steam.sh 2025-08-04 13:28:52 +02:00
phorcys c769330d92 [LA64_DYNAREC] Fix some la64 ops. (#2889)
Fix 0F.BA./7 BTS CF when cpuext.lbt == 1
Fix 66.0F.CF BSWAP 16bits ops.
Fix VEXTRACTF128, VINSERTF128
2025-08-04 13:24:50 +02:00
Yang Liu afe466b051 [LA64_DYNAREC] Fixed 66 0F 38 14 BLENDVPS opcode (#2888) 2025-08-04 11:28:11 +02:00
Yang Liu 4bb4e45836 [LA64_DYNAREC] Fixed 66 0F 3A 0C/0D BLENDPS/D opcodes (#2887) 2025-08-04 11:27:17 +02:00
Yang Liu cbd1f487c7 [LA64_DYNAREC] Fixed a few GETEX usage (#2886) 2025-08-04 10:52:23 +02:00
Yang Liu 926176c1b5 [LA64_DYNAREC] Fixed 0F E2 PSRAD opcode (#2885) 2025-08-04 10:48:37 +02:00
Yang Liu aac7345603 [LA64_DYNAREC] Fixed 0F E3 PAVGW opcode (#2884) 2025-08-04 10:48:04 +02:00
phorcys 0dc9f8cb62 [LA64_DYNAREC] Add la64 avx bit ops. (#2873)
*  VEX.66.0F.3A VPEXTRB/VPEXTRW/VPEXTRD/VPEXTRQ VPINSRB/VPINSRD/VPINSRQ
  *  VEX.66.0F.C5 VPEXTRW
  *  VEX.66.0f.C4 VPINSRW
  *  VEX.66.0F.38.41 VPHMINPOSUW
2025-08-04 08:57:32 +02:00
phorcys cb0b274c27 [LA64_DYNAREC] Fix some la64 avx/sse ops. (#2882)
Fix 66.0F.F3 PSLLQ
Fix VEX.66.0F.7E VMOVD not zero-extend
Fix Vex.66.0F.3A.06 VPERM2F128/VPERM2I128
Fix Vex.66.0F.3A.0D VBLENDPD
Fix VEX.66.0F.3A.18/38 VINSERTF128/VINSERTI128  when q0 == q1 or q0 == q2
Fix VEX.66.0F.3A.21 VINSERTPS fix u8 get pos
Fix VEX.66.0F.3A.40 VDPPS Fix VREPLVEIxy emit when vex.l
Fix VEX.66.0F.38.0C VPERMILPS
Fix VEX.66.0F.38.2B VPACKUSDW
Fix VEX.66.0F.38.93 VGATHERQPD
2025-08-02 14:42:05 +02:00
Yang Liu ebac583441 [RV64_DYNAREC] Fixed scalar version of 66 0F 3A 21 INSERTPS opcode (#2881) 2025-08-02 12:48:38 +02:00
Yang Liu 6221b01976 [RV64_DYNAREC] Fixed scalar and vector versions of mmx PSRAW/PSRAD (#2880) 2025-08-02 12:47:30 +02:00
Yang Liu caac35cc1e [RV64_DYNAREC] Fixed some mmx opcodes (#2879) 2025-08-02 12:00:04 +02:00
Yang Liu f7302ecb1b [ARM64_DYNAREC] Fixed PCMPESTRI fastpath SF flag computation (#2876) 2025-08-01 19:44:02 +02:00
Yang Liu 4c30838448 [INTERP] Fixed 16bit version POPCNT (#2877) 2025-08-01 19:30:45 +02:00
Yang Liu ded60bbabd [ARM64_DYNAREC] Fixed a typo (#2875) 2025-08-01 15:59:33 +02:00
Yang Liu c2805b0f9b [ARM64_DYNAREC] Fixed some edge cases for mmx PSRLQ (#2874) 2025-08-01 12:55:55 +02:00
phorcys 7e9775de94 [LA64_DYNAREC] Add la64 avx cvt ops, part 3. (#2869)
Double <=> Integer convert.
Half Float <=> Integer convert.
VCVT{DQ2PD, PD2DQ, TPD2DQ}
VCVT{SI2SD, SD2SI, TSD2SI}
VCVT{PH2PS, PS2PH}
2025-08-01 11:49:29 +02:00
Yang Liu ae0ac5a1d0 [INTERP] Added 66 F0 0F BA BTS opcode (#2872) 2025-08-01 11:48:02 +02:00
Yang Liu ea804a5261 [TRACE] Minor improvements to trace logging (#2871) 2025-08-01 11:46:49 +02:00
ptitSeb a17811f4a6 [INTERP] Try to improve aligned LOCK CMPXCHG8B opcode 2025-08-01 11:12:43 +02:00
ptitSeb d2c77ddb01 [RCFIEL] Improved a profile 2025-08-01 11:12:15 +02:00
Yang Liu 6c438a5e65 [WRAPPED] Wrapped more functions for libc (#2870)
* [WRAPPED] Wrapped more functions for libc

* review
2025-08-01 11:11:26 +02:00
phorcys 6da5698c02 [LA64_DYNAREC] Add la64 avx cvt ops, part2. (#2866)
Integer <=> Float convert.
VCVT{DQ2PS, PS2DQ, TPS2DQ}
VCVT{SI2SS, SS2SI, TSS2SI}
2025-08-01 08:17:23 +02:00
ptitSeb ecbe739f52 [WRAPPER] Added 1 more wrapped function to libavcodec58 2025-07-31 21:05:40 +02:00
ptitSeb 27312d7a15 [WRAPPER] Added __powl_finite wrapping to libm (for #2862) 2025-07-31 21:01:16 +02:00
Yang Liu d19a3d987b [RV64_DYNAREC] Fixed a typo (#2865) 2025-07-31 12:10:09 +02:00
phorcys d33706065d [LA64_DYNAREC] Add la64 avx cvt ops, part1. (#2859)
Double <=> Float  ops, VROUND ops.

VCVT{PD2PS,PS2PD, SD2SS, SS2SD}
Round{PD,PS,SD,SS}
2025-07-31 11:21:57 +02:00
Yang Liu 97a78f2d98 Minor improvements to trace logging (#2861) 2025-07-31 08:06:56 +02:00
Fathi Boudra ec0e1077c9 Box64 bundle x86 libs improvements (#2839)
* box64-bundle-x86-libs.csv: fix glibc i686 checksum

glibc i686 checksum is the same as the x86_64 version.
It's a copy paste error. Fix the correct checksum.
Also sort the file content so it's easier to figure out the package
source and read potential mistakes.

Signed-off-by: Fathi Boudra <[email protected]>

* box64-bundle-x86-libs.sh: rewrite the bundle libraries script

Heavily based on Luke's original work, the main improvements:
* portable:
  - it's a POSIX shell script, doesn't rely on bash anymore
  - reduce tool dependencies (use only awk, instead of awk and cut)
* more robust:
  - clean up on exit/errors
  - retry logic with curl
  - check tools availability
  - fails on checksums errors
* more readable
* fixed duplicated removal libraries that can't be emulated
* passed shellcheck analysis tool

Signed-off-by: Fathi Boudra <[email protected]>

---------

Signed-off-by: Fathi Boudra <[email protected]>
2025-07-30 20:20:41 +02:00
phorcys 127d72da17 [LA64_DYNAREC] Add la64 avx cmp ops, part3. TEST ops. (#2857)
VPTEST
VTESTPD, VTESTPS
2025-07-30 08:34:35 +02:00
Yang Liu f2baa6ed35 [RV64_DYNAREC] Added MMX handling to fpu_{push,pop}cache for vector (#2858) 2025-07-30 08:33:23 +02:00
phorcys 5fd843750f [LA64_DYNAREC] Add la64 avx int cmp ops. (#2856)
VCMP{EQ,GT}{B,W,D,Q}
VCOMISS, VUCOMISS, VCOMISD, VUCOMISD
2025-07-29 17:29:59 +02:00
Yang Liu 8180cb3218 [RV64][LA64] Added partial FLUSHTO0 support (#2855)
* [RV64][LA64] Removed obselete TODOs

* more

* more

* more

* more
2025-07-29 17:28:34 +02:00
ptitSeb 68e16f5154 [WOW64] Removed a warning 2025-07-29 11:49:43 +02:00
ptitSeb 0fd5d67fe3 [ARM+4_DYNAREC] Another fix for STMXCSR opcode when using SSE_FLUSHTO0 2025-07-29 11:44:44 +02:00
ptitSeb f628c37a61 [ARM+4_DYNAREC] Fixed (V)[LD/ST]MXCSR opcodes when using SSE_FLUSHTO0 2025-07-29 11:42:44 +02:00
phorcys 0734efea39 [LA64_DYNAREC] Add la64 avx float cmp ops. (#2854)
VCMPPD,VCMPPS,VCMPSD,VCMPSS
2025-07-29 09:55:40 +02:00
phorcys f43a221ffc [LA64_DYNAREC] Add la64 avx float ops part 3. (#2845)
*  add cpuext.frecipe for LoongArch V1.1
  *  Fix VFRSQRTE in sse op  RSQRTPS/RSQRTSS
  *  Fix VFRECIPE in sse op  RCPPS/RCPSS
  *  V{MAX,MIN}{PD,PS,SD,SS}
  *  VRCPPS,VRCPSS
  *  VRSQRTPS,VRSQRTSS
  *  VSQRT{PD,PS,SD,SS}
2025-07-29 09:08:24 +02:00
ptitSeb 397399fd30 [ARM64_DYNAREC] Improved adjust for REP MOVSx opcode on signal 2025-07-28 13:40:21 +02:00
ptitSeb 3e9f394228 [BOX32] Added some comment on arguments for a syscall 2025-07-28 13:39:24 +02:00
ptitSeb 32e2112ab0 [DYNAREC] Fixed an issue introduced with 48ae536d95 and properly address the underlying issue 2025-07-26 10:11:55 +02:00
ptitSeb f0866438fc [WRAPPER][VULKAN] Added 1 new extensions (for #2847, used by PanVK) 2025-07-25 10:20:49 +02:00
Leslie Zhai ec2edd5b3a [WRAPPER] Wrapper wrappedgobject2 g_closure_ref and g_closure_sink (#2848) (#2849)
* [WRAPPER] Wrapper wrappedgobject2 g_closure_ref and g_closure_sink (#2848)

* [WRAPPER] Add testcase for g_closure_ref and g_closure_sink

* [WRAPPER] Just use GO for g_closure_ref|sink|invoke
2025-07-25 10:07:05 +02:00
ptitSeb 4a625db27a [TRACE] More traces for LOG=2 2025-07-24 15:14:23 +02:00
ptitSeb 32cebc6137 [TRACE] Try to preserve errno when tracing 2025-07-24 14:58:35 +02:00
ptitSeb b02b9174e0 [TRACE] Some mor eimprovment to LOG=2 traces 2025-07-24 14:17:52 +02:00
ptitSeb 5b3f675c0d [LA64_DYNAREC] Fixed some issue with ADD/SUB x64 eflags when using LBT extension 2025-07-24 12:05:51 +02:00
ptitSeb a908ce881d [BOX32] Use box64path instead of argv[0] in personality relaunch sequence (could have used execvpe instead) 2025-07-23 13:23:03 +02:00
ptitSeb 49cc5eabcb Some handling of case where signal numbers differs between native and x64 archs (not complete, missing sigset conversions) 2025-07-23 11:13:37 +02:00
Yang Liu bf429a1dcf [RV64_DYNAREC][LA64_DYNAREC] Simplified defered flags handling and limited case where UpdateFlags is actualy called (#2844) 2025-07-23 11:02:23 +02:00
phorcys e1c1303d28 [LA64_DYNAREC] Add la64 avx float ops VDPP{S,D}, VH{ADD,SUB}{PS,PD} (#2842) 2025-07-23 11:01:12 +02:00
ptitSeb 4a8a373662 [BOX32] Better error on box32 personnality re-launch faillure 2025-07-22 19:15:26 +02:00
ptitSeb fff274b45f [WRAPPER] Added more slot to libdbus callback wrappers 2025-07-22 18:57:35 +02:00
ptitSeb 8e1e299395 [WRAPPER] Added 4 more symbols to libwaylandclient 2025-07-22 18:48:27 +02:00
ptitSeb b8d40a8d71 [WRAPPER] Added 1 more function to wrapped libharfbuzz 2025-07-22 18:36:28 +02:00
ptitSeb a3cad12d66 [WRAPPER] Added 2 more wrapped function to libcairo 2025-07-22 18:33:23 +02:00
ptitSeb c4521b3772 [WRAPPER] Added 1 more wrapped function to libfontconfig 2025-07-22 18:11:47 +02:00
ptitSeb 729fbb24d5 [WRAPPER] Added 3 more functions to libcairo 2025-07-22 18:07:01 +02:00
ptitSeb 6740ca196e [WRAPPER] Added some more dbus wrapped functions 2025-07-22 17:53:33 +02:00
Yang Liu 7b755bb6a2 [BOX32] Enable personality setting for RV64 and LA64 (#2841) 2025-07-22 14:37:20 +02:00
phorcys 5f7da532c4 [LA64_DYNAREC] Add la64 avx float arith ops, part 1. (#2840)
*  V{ADD,SUB,MUL,DIV}{PD,PS,SD,SS}
  *  VADDSUB{PD,PS}
2025-07-22 14:36:15 +02:00
phorcys fc1b149fed [LA64_DYNAREC] Add la64 avx FMA insts. (#2838)
* VF{MADD,MSUB,NMADD,NMSUB}{132,213,231}{PD,PS,SD,SS}
  * VFM{ADDSUB,SUBADD}{132,213,231}{PD,PS}
2025-07-22 11:14:45 +02:00
phorcys ea16e05142 [LA64_DYNAREC] add la64 avx pack/unpack ops, part5. (#2837)
INSERT/EXTRACT/BROADCAST/GATHER ops.
VEXTRACTPS,VINSERTPS
VBROADCAST{SD,SS}, VPBROADCAST{B,W,D,Q,I128}
VPGATHER{DD,DQ,QD,QQ,DPD,DPS,QPD,QPS}
2025-07-21 12:06:55 +02:00
ptitSeb 3e74454cf4 [DYNAREC] Another fix for RV64 and LA64 builds 2025-07-21 10:54:38 +02:00
ptitSeb f3a748ae8f [DYNAREC] This should fix build on RV64 and LA64 2025-07-21 10:52:56 +02:00
ptitSeb 5d90fe95e4 [DYNAREC] Consolidate access to native register in signal and register mapping acrross all 3 supported dynarec archs 2025-07-21 10:46:53 +02:00
Yang Liu 8271d37539 [DYNACACHE]LA64] Enabled dynacache for LA64 (#2836)
* [DYNACACHE]LA64] Enabled dynacache for LA64

* review
2025-07-21 08:59:40 +02:00
phorcys 206e3cd561 [LA64_DYNAREC] add la64 avx pack/unpack ops, part4. (#2830)
Shuf/Permute ops.
VSHUFPS, VSHUFPD
VPSHUFD, VPSHUFQ, VPSHUFB, VPSHUFLW, VPSHUFHW
VPERMQ, VPERMD
VPERMPD, VPERMPS
VPERMILPD, VPERMILPS
VPERM2F128, VPERM2I128
2025-07-21 08:16:17 +02:00
Luke Short 5d2a99307e [BUNDLE] Add hidapi (#2833)
Resolves #1809
2025-07-20 21:49:09 +02:00
Luke Short a55cece387 [RCFILE] Update profile for BeamNG (#2832)
Resolves #424
2025-07-20 21:48:26 +02:00
Luke Short ca24435b92 [RCFILE] Add profile for Subnautica (#2831)
Resolves #803
2025-07-20 21:47:57 +02:00
phorcys 0e97b105fe [LA64_DYNAREC] Add la64 avx pack/unpack ops , part 3 blend ops. (#2824)
VBLENDPD, VBLENDPS
VPBLENDW, VPBLENDD, VPBLENDVB
VBLENDVPD, VBLENDVPS
VPALIGNR
2025-07-20 14:25:41 +02:00
Luke Short 2d164c89e2 [BUNDLE] Check for broken symlinks (#2829)
to prevent issues such as #2825
2025-07-19 19:53:54 +02:00
ptitSeb 48ae536d95 [DYNAREC] Change an error to warning, when entering FillBlock64 and current_helper is not cleaned up 2025-07-19 12:25:33 +02:00
ptitSeb b2225e26b1 [WRAPPER] Improved myStackAlignGVariantNew(Va) helper functions, for [RV64] and [LA64] (backported from box86) 2025-07-19 12:07:45 +02:00
ptitSeb 484dc1365e [DYNAREC] Fine tuned DIRTY=1 settings and added 1 game profile to [RCFILE] 2025-07-19 09:25:43 +02:00
Luke Short c9a41ee3ac [BUNDLE] Add ncurses (#2828)
since emulation may be better than the wrapped functions currently.

Related #1942
2025-07-19 08:30:03 +02:00
Luke Short 7f6d18930c [BUNDLE] List install dependencies for Arch Linux (#2827) 2025-07-19 08:25:43 +02:00
phorcys 17ea04766e [LA64_DYNAREC] Add la64 avx pack/unpack ops , part 2. (#2823)
VUNPCK{LPS,LPD,HPS,HPD}
VPUNPCK{LBW,LWD,LDQ,LQDQ,HBW,HWD,HDQ,HQDQ}
2025-07-18 09:36:08 +02:00
Fathi Boudra b1613be0f0 box64-bundle-x86-libs.csv: fix libffi library (#2825)
libffi-devel package is empty and contains only a symlink.
Use the correct package to bundle the library binary.

Signed-off-by: Fathi Boudra <[email protected]>
2025-07-17 18:26:22 +02:00
ptitSeb cdaffe0c1f [RCFILE] Added profile for 1 more game 2025-07-17 14:25:56 +02:00
Luke Short 7fb315c356 [BUNDLE] Add usable libraries from GLIBC package (#2821)
Resolves #2703
2025-07-17 08:14:03 +02:00
phorcys a960e98394 [LA64_DYNAREC] Add la64 avx pack/unpack ops , part 1. (#2818)
VPACKSSWB
VPACKSSDW
VPACKUSWB
VPACKUSDW
2025-07-17 08:10:07 +02:00
ptitSeb ef2f960d4b [ARM64_DYNAREC] Added 64/65 F3 0F 7F opcode 2025-07-16 20:04:20 +02:00
ptitSeb e829cad612 [INTERP] Added 64/65 F3 0F 7F opcode 2025-07-16 20:04:03 +02:00
ptitSeb 609ff66c2c [ARM64_DYNAREC] Small optim on (V/F)COMI(SS/SD) opcodes 2025-07-16 18:52:51 +02:00
Luke Short 1a4bfc2feb [BUNDLE] Add sqlite3 (#2819)
Resolves #2803
2025-07-16 08:14:32 +02:00
ptitSeb e5329d6864 [ARM64_DYNAREC] Fixed a residual issue with xmm unneeded handling when unloading xmm9-xmm15 registers 2025-07-15 13:16:52 +02:00
phorcys 37b1d9ea85 [LA64_DYNAREC] Add la64 avx arith ops, part2. (#2816)
*  VEX.66.0F  VPMADDWD,VPSADBW
  *  VEX.66.0F.38 VPH{ADD,SUB}{W,D,SW}, VPABS{B,W,D} VPMADDUBSW,VPMULHRSW,
  *  VEX.66.0F.3A  VMPSADBW
2025-07-15 12:23:13 +02:00
Yang Liu 98f2460c46 [LA64_DYNAREC] Optimized PMADDUBSW opcodes (#2817) 2025-07-15 11:29:34 +02:00
phorcys 7a4583699b [LA64_DYNAREC] Add la64 avx arith ops , part 1. (#2814)
Add 1:1 avx arith ops.
  *  VP{ADD,SUB}{B,W,D,Q,SB,SW,USB,USW}
  *  VPMUL{DQ,,HW,HUW,Lw,LD,LUDQ}
  *  V{MAX,MIN}{UB,UW,UD,SB,SW,SD}
  *  VAVG{B,W}
  *  VSIGN{B,W,D}
2025-07-14 11:33:26 +02:00
phorcys 26851574ad [LA64_DYNAREC] Fix la64 VMASKMOVPS,VMOVHPD. (#2811)
*  fix la64  VMASKMOVPS,VMOVHPD.
  *  fix arm64 VMASKMOVPS,VMASKMOVPD op memo operand order.
2025-07-14 11:31:57 +02:00
ptitSeb 179cba7a28 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-07-14 10:09:47 +02:00
ptitSeb 0a59321106 Improved Volatile Metadata handling 2025-07-14 10:08:47 +02:00
phorcys ce08e8e27f [LA64_DYNAREC] Add la64 avx shift ops. (#2806)
*  VEX.66.0f    VPSRLW/VPSRLDVPSRLQ/VPSRAW/VPSRAD/VPSLLW/VPSLLD/VPSLLQ
  *  VEX.66.0f.3a VPSRLVD/VPSRLVQ/VPSRAVDVPSLLVD/VPSLLVQ
2025-07-14 08:54:16 +02:00
Yang Liu 6960cfa56f [LA64_DYNAREC] Optimized some SSE shift opcodes (#2813) 2025-07-14 08:53:18 +02:00
phorcys c558bdcb69 [LA64_DYNAREC] Add la64 avx BMI2 shift ops. (#2807)
*  VEX.66.0f.38  SHLX
  *  VEX.f2.0f.38  SHRX
  *  VEX.f3.0f.38  SARX
2025-07-14 08:08:16 +02:00
ptitSeb 0674e546e1 [ANDROID] This should fix the build 2025-07-12 18:36:31 +02:00
ptitSeb 2a10ddc75b [WRAPPER] Added 1 more wrapped function to libpthreads (for #2808) 2025-07-12 17:23:02 +02:00
ptitSeb 8ed08b3bbc [INTERP] Added 64/65 AVX.0F 10/11 opcodes (for #2808) 2025-07-12 11:13:48 +02:00
ptitSeb cf5241ceb3 [ARM64_DYNAREC] Added 0F 00 /0 opcode 2025-07-12 10:52:46 +02:00
phorcys 78460724ea [LA64_DYNAREC] Add la64 avx shift ops with imm operand. (#2805)
VEX.128/256 66.0F  shift imm ops:
   *  71  VPSRLW/VPSRAW/VPSLLW
   *  72  VPSRLD/VPSRAD/VPSLLD
   *  73  VPSRLQ/VPSLLQ/VPSRLDQ/VPSLLDQ
2025-07-11 08:06:37 +02:00
phorcys 6ea020eb54 [LA64_DYNAREC] Fix/Opt la64 avx movsx/movzx ops. (#2804)
Use vext2xv to opt movsx/movzx.
For VEX.128 bw,wd,dq ops, use vsllwil(latency 2) instead of vext2xv (latency 3)
Old imp use xvsllwil is wrong, because xvsllwil operate on per 128bits channel.
But MOVSX/MOVZX VEX.256 ops only read src operand from low 128bits.
2025-07-11 08:06:03 +02:00
ptitSeb 968594ee63 [ARM64_DYNAREC] Simplified defered flags handling and limited case where UpdateFlags is actualy called (could be simplified more) (TODO on RV64 and LA64) 2025-07-10 18:32:35 +02:00
ptitSeb 3ac62c64d8 Default x64emu_t structure for thread now point to a valid IP, just in case 2025-07-10 18:29:58 +02:00
ptitSeb 5596b9ae3f [RCFILE] Fixed profile per lib/dll that was using default instead of curent env for non defined values 2025-07-09 17:21:35 +02:00
ptitSeb 64efac63c0 [ARM64_DYNAREC] Removed fastpath for (V)MINPD/MAXPD as it's too inexact 2025-07-09 11:50:58 +02:00
ptitSeb 6da287f59f [ARM64_DYNAREC] Fined tuned UD value for BSR/BSF 2025-07-09 11:44:00 +02:00
ptitSeb 1c65cdc7cb [INTERP] Fined tuned UD value for BSR/BSF 2025-07-09 11:43:43 +02:00
ptitSeb efa6ee7275 [ARM64_DYNAREC] Fixed rare sideeffect of 32bits cmpxchg opcode 2025-07-09 11:24:23 +02:00
ptitSeb 1ac4cdeae9 [ARM64_DYNAREC] Better handling of shift 0 for rcl/rct 16bits 2025-07-09 10:57:47 +02:00
phorcys 4bb1bc9ea8 [LA64_DYNAREC] Fix la64 avx->sse same reg migration. (#2801)
In current code, if an avx reg  writed reg is used by  following sse inst.
A VLD would emitted by sse_get_reg,  causing prev avx inst writed content lose.
Skip sse_get_reg's VLD  emit, when reg content is already load/changed in prev avx inst.
2025-07-09 08:56:12 +02:00
phorcys 614d142205 [LA64_DYNAREC] Opt/fix la64 avx mov ops. (#2800)
*  opt VEX.66.0F.D6 VMOVD
  *  opt VEX.F2.0F.10 VMOSD
  *  opt VEX.F3.0F.10 VMOVSS
  *  opt/fix VEX.F3.0F.7E VMOVD
2025-07-09 08:10:41 +02:00
phorcys aeec79ec00 [LA64_DYNAREC] Add la64 avx bitwise ops. (#2780)
* avx  VEX.66.0F 54/55/56/57  VANDPD/VANDNPD/VORPD/VXORPD
  * avx  VEX.0F    54/55/56/57  VANDPS/VANDNPS/VORPS/VXORPS
  * avx  VEX.66.0F DB/DF/EB/EF  VPAND/VPANDN/VPOR/VPXOR
  * bmi1 VEX.0F38    F2  ANDN
  * bmi2 VEX.F2.0F3A F0  RORX
2025-07-09 08:10:14 +02:00
ptitSeb b1971c8ef3 [WRAPPER] added one missing wrapped function to libasound (for #2796) 2025-07-08 11:36:35 +02:00
Leslie Zhai 1ed7609fe9 [WRAPPER] Wrapper xmlMemGet and xmlMemSetup (#2799)
* [WRAPPER] Wrapper xmlMemGet and xmlMemSetup

* [WRAPPER] Change GOM to GO for xmlMemGet
2025-07-05 15:31:12 +02:00
phorcys 04396f421e [LA64_DYNAREC] Fix VEX.0f.17 VMOVHPS, one break missing. (#2798) 2025-07-05 08:42:38 +02:00
ptitSeb b4d43748e5 [WRAPPER] Added a couple of libc/libm wrapped functions (for #2796) 2025-07-04 23:02:20 +02:00
Leslie Zhai 549b384c3c [WRAPPER] Add bridge for Display's resource_alloc when directly call (#2795)
XOpenIM but not XOpenDisplay
2025-07-04 08:49:35 +02:00
ptitSeb 60ea78729d [WOW64] This should fix the build 2025-07-03 19:14:14 +02:00
ptitSeb ab9b88091c [BOX32] Simplified and improved 32bits memory management 2025-07-03 18:31:03 +02:00
ptitSeb a0fb28ac55 [WRAPPER] Allow to use libFLAC.so.12 for libFLAC.so.8 2025-07-03 18:26:19 +02:00
ptitSeb 9d92aac4f5 [BOX32] Do not try to switch personality on RV64 or LA64 arch 2025-07-03 13:17:51 +02:00
ptitSeb 5923a9089f [BOX32] Relaunch box32 to set personality to 32bits 2025-07-03 12:10:44 +02:00
ptitSeb e274abf13d [INTERP] Small change in Alternate handling 2025-07-03 11:34:05 +02:00
ptitSeb e327799e62 [ARM64_DYNAREC] Small cosmetic change in indirect_lookup 2025-07-03 11:33:27 +02:00
ptitSeb d56464d01d [ARM64_DYNAREC] Added unused LRCPC emitters 2025-07-03 10:58:53 +02:00
Leslie Zhai accbbe83e2 [WRAPPER] Wrapper XCreateWindow when Display's resource_alloc is x64 entry (#2788) (#2789)
* [WRAPPER] Wrapper XCreateWindow when Display's resource_alloc is x64
entry (#2788)

* [WRAPPER] Use RunFunctionFmt to call x64 resource_alloc entry

* [WRAPPER] Remove useless include header and DBGetBlock

* [WRAPPER] Use FindElfAddress to check the function is from x64 space

* [WRAPPER] Use find_XXX_Fct mechanism
2025-07-03 09:37:13 +02:00
ptitSeb 44ff3375df [DYNAREC] Fixed a potential issue where defered flags are not computed/reset on internal jump 2025-07-02 11:55:39 +02:00
ptitSeb dacc294340 [TRACE] Fixed the jump from instruction idx for Extend blcok in trace 2025-07-02 11:10:43 +02:00
ptitSeb 569b7471f9 Simplified a bit ROLLING_LOG buffer handling 2025-07-01 13:41:35 +02:00
ptitSeb 74710cbf6a [ARM64_DYNAREC] Optimized propate XMM/YMM unused helpers 2025-07-01 10:07:26 +02:00
ptitSeb 54ea4859ec [ARM64_DYNAREC] Fixed a regression introduced with 4903177bab (for ForzaHorizon4, maybe other too) 2025-06-30 20:35:40 +02:00
ptitSeb 2278438462 [DYNAREC] Refactor hotpage detection and dynarec_dirty 1 & 2. Also adjust some launcher/games flags 2025-06-30 16:36:38 +02:00
ptitSeb a942cef1ee [ARM64_DYNAREC] Added 66 8D opcode 2025-06-29 14:07:28 +02:00
ptitSeb f6773b2489 [ARM64_DYNAREC] Added 67 9C opcode 2025-06-29 13:22:08 +02:00
ptitSeb 614c8035ef [ARM64_DYNAREC] Made (V)M(IN/AX)P(D/S) opcodes always exact, it's inexpensive and make FASTNAN=0 less usefull 2025-06-29 12:37:55 +02:00
ptitSeb b01a0ccbb4 [INTERP] Added 67 9C opcode (for LEGO2Kdrive) 2025-06-28 18:22:06 +02:00
ptitSeb c6eaae8760 [INTERP] Small imrpvoment for 0F 03 opcode 2025-06-28 18:12:48 +02:00
ptitSeb 4a447e7f94 [INTERP] Added 0F 03 opcode (for LEGO2Kdrive) 2025-06-28 18:10:39 +02:00
ptitSeb c8c2b84287 [ARM64_DYNAREC] Use Unaligned sepcial handling to handle rare case of 32bits access out of 32bits bounds (for tasty platnet 2 on steam) 2025-06-28 13:53:00 +02:00
Yang Liu 2ce7bdf321 [LA64_DYNAREC] Removed some TABLE64 usage (#2782) 2025-06-27 10:43:07 +02:00
phorcys 2302adcbb9 [LA64_DYNAREC] Add la64 avx load/store ops part 4. (#2775)
*  VEX.66.0f.38  VMOVSX{BW,BD,BQ,WD,WQ,DQ}/VMOVZX{BW,BD,BQ,WD,WQ,DQ}
2025-06-27 09:19:17 +02:00
Yang Liu f6bb7310bb [LA64_DYNAREC] Optimized GETIP macro (#2781) 2025-06-27 09:17:06 +02:00
Yang Liu d57416f4fb [LA64_DYNAREC] Removed some redundant macro definitions (#2778) 2025-06-26 14:35:00 +02:00
Yang Liu e75234c83d [DYNACACHE][LA64] More work on internal reloc (#2779) 2025-06-26 14:32:57 +02:00
phorcys 42b98f77ce [LA64_DYNAREC] Add la64 avx load/store ops part 3. (#2774)
*  VEX.0f       VMOVMSKPS
  *  VEX.66.0f    VMOVMSKPD/VPMOVMSKB/VMASKMOVDQU
  *  VEX.66.0f.38 VMASKMOVPS/VMASKMOVPD/VPMASKMOVD/VPMASKMOVQ
2025-06-26 11:02:28 +02:00
phorcys bb253f3708 [LA64_DYNAREC] Add la64 avx load/store ops part 2. (#2773)
*  VEX.0f    VMOVLPS/VMOVHPS/VMOVLHPS/VMOVHLPS
  *  VEX.66.0f VMOVLPD/VMOVHPD
2025-06-26 10:42:23 +02:00
ptitSeb 0c87fbd42c [ARM64_DYNAREC] Fixed opcode name for VDIVPD 2025-06-25 14:39:10 +02:00
ptitSeb bc210752ab [ARM64_DYNAREC] Fixed some extended instance of VCMPSD opcodes 2025-06-25 14:02:28 +02:00
ptitSeb c274475c47 [INTERP] Improved 32bits to 16bits float conversion 2025-06-25 13:54:36 +02:00
ptitSeb 48a1b11281 [INTERP] More work on UD flags 2025-06-25 10:59:15 +02:00
ptitSeb 3698763bbe [INTERP] More work on UD flags 2025-06-25 10:59:04 +02:00
ptitSeb d67bc08d2d [ARM64_DYNAREC] Adjusted some UD flags in BLSMSK opcode 2025-06-25 10:49:03 +02:00
ptitSeb e2b9776860 [INTERP] Adjusted some UD flags in BLSMSK opcode 2025-06-25 10:48:47 +02:00
ptitSeb 208a84bebb [ARM64_DYNAREC] Fixed CF flag of BLSI opcode 2025-06-25 10:24:55 +02:00
ptitSeb 6a6ad9748a [INTERP] Fixed CF flag of BLSI opcode 2025-06-25 10:24:36 +02:00
ptitSeb 70ee5f0c83 [ARM64_DYNAREC] Fixed BEXTR opcode 2025-06-25 10:16:40 +02:00
ptitSeb 266bb4aa88 [INTERP] Added 66 F0 F7 /2 opcode (aligned only) 2025-06-24 21:05:47 +02:00
ptitSeb 82016ae44f [ARM64_DYNAREC] Improved BTx opcodes (and fixed one BTC opcode) 2025-06-24 20:48:57 +02:00
ptitSeb f470fdcc90 [INTERP] Added F0 BB and improved F0 BA /7 opcodes 2025-06-24 20:48:12 +02:00
ptitSeb 09e39704ae [DYNAREC] Better check of limit for a dynablock 2025-06-24 20:17:58 +02:00
airidosas252 f14fa2f2ce [WRAPPER] additional wrapped symbols (#2765)
* [WRAPPER] Wrap libiconv library

Seems to be required with newer versions of Wine for whatever reason.

* [WRAPPER] Wrap _ctype_ symbol (ANDROID only)

For whatever reason, this symbol is used on bionic at least. Not quite sure if it's the same on Linux.

* [WRAPPER} Fix a signature typo for libiconv function
2025-06-24 20:15:21 +02:00
phorcys 7962aacc7f [LA64_DYNAREC] Add la64 avx load/store ops part 1. (#2766)
*  VEX.0f       VMOVNTPS/VLDMXCSR/VSTMXCSR
  *  VEX.66.0f    VMOVNTPD/VMOVD/VMOVNTDQ
  *  VEX.66.0f.3a VMOVNTDQA
  *  VEX.f2.0f    VMOVDDUP/VLDDQU
  *  VEX.f3.0f    VMOVSLDUP/VMOVSHDUP/VMOVD
2025-06-24 18:38:12 +02:00
ptitSeb 9195bc2d4a [ARM64_DYNAREC] Improved handling of last_ip 2025-06-24 18:25:18 +02:00
Yang Liu 5e9972f2d3 [DYNACACHE][LA64] Added const table for later use in internal relocation (#2770) 2025-06-24 16:34:49 +02:00
ptitSeb acc0d451bb [LA64_DYNAREC] This should help certain builds (for #2769) 2025-06-24 14:18:45 +02:00
Yang Liu 1f5ce7ec18 [CI] Upgraded QEMU and loongarch64 toolchains (#2768) 2025-06-24 13:55:10 +02:00
Yang Liu f8314ffb2b [DYNAREC] Removed some unused code (#2767) 2025-06-24 09:51:46 +02:00
phorcys 9b6ff79c9c [LA64_DYNAREC]Add basic avx support for la64. (#2745)
* basic infra for avx
    * some basic ops for avx
	VMOVDQU/VMOVDQA/VMOVUPS/VMOVAPS/VMOVUPD/VMOVAPD
	VZEROUPPER/VZEROALL
	VMOVD/VMOVSD/VMOVSS
	VINSERTF128/VINSERTI128/VEXTRACTF128/VEXTRACTI128
	VBROADCASTSS/VBROADCASTSD/VBROADCASTF128
2025-06-23 18:16:57 +02:00
ptitSeb 4eabf07385 Fix wowbox64 build 2025-06-23 15:16:06 +02:00
ptitSeb 0d02532dab [DYNACACHE] Added support for unaligned addresses 2025-06-23 14:52:28 +02:00
ptitSeb 8ae0b6e181 [ARM64_DYNAREC] Removed commented code 2025-06-23 14:52:03 +02:00
Chi-Kuan Chiu f6d9caf0d1 Add map64_customMalloc (#2764)
Most allocations target ~56 bytes, causing internal fragmentation
in `map128_customMalloc`. Introduce `map64_customMalloc`, a
64-byte–chunk variant of `map128_customMalloc`. The new allocator
uses a `uint16_t` “map” array: each bit in a 16-bit entry tracks
the in-use status of one 64-byte chunk (16 chunks per map entry).
The bitmap region is fixed at 256 bytes. Note that “map” here is a
fast-lookup structure, distinct from the bitmap itself. All chunk-
size, shift, and map-size calculations have been updated
accordingly.

Relates to #2740
2025-06-23 13:01:17 +02:00
ptitSeb c66630da49 [DYNAREC] Refactored a bit BARRIER_FLOAT ([ARM64] olny for now, todo for RV64 and LA64) 2025-06-23 13:00:45 +02:00
ptitSeb 0cc58732fb [ARM64_DYNAREC] Small fix in arch_build 2025-06-22 18:21:29 +02:00
ptitSeb dcb47b7df8 [DYNACACHE] Introduced B64X_DYNACACHE=2 to use cache but not create new ones, and made it default 2025-06-20 12:10:36 +02:00
ptitSeb d6c08a7511 [DYNACACHE] Fixed a Warning 2025-06-20 11:30:40 +02:00
Yang Liu f1e8841030 [DYNACACHE][RV64] Enabled dynacache for RV64 (#2762) 2025-06-20 11:26:21 +02:00
Yang Liu cfdc733e2f [DYNACACHE] Make sure dynacache folder ends with pathsep (#2761) 2025-06-20 11:23:40 +02:00
Yang Liu 168fe67904 [DOCS] Performance as the top section in USAGE.md (#2760) 2025-06-19 21:06:03 +02:00
Yang Liu 58f4cc352e [DYNACACHE][RV64] More work on internal reloc (#2759) 2025-06-19 16:19:57 +02:00
Yang Liu b840606105 [DYNACACHE][RV64] Added const table for later use in internal relocation (#2758) 2025-06-19 12:13:20 +02:00
ptitSeb f88c864fce [DYNACACHE] Another fix for non-ARM64 Dynarec build 2025-06-19 11:39:45 +02:00
ptitSeb 41a914fa5e [DYNACACHE] Fixed LA64 build 2025-06-19 11:36:05 +02:00
ptitSeb 1f710620fc [DYNACACHE] This should fix non-ARM64 Dynarec build, for good 2025-06-19 11:32:01 +02:00
ptitSeb eb110bf213 [DYNACACHE] This should fix non-ARM64 Dynarec build 2025-06-19 11:28:49 +02:00
ptitSeb 42c0f891e3 [DYNACACHE] Try to fix non Dynarec build 2025-06-19 11:18:07 +02:00
ptitSeb 725316a538 [DYNACACHE] Introduced DynaCache for ARM64 (disabled by default) 2025-06-19 11:07:30 +02:00
Yang Liu cc9ed70837 Fixed compilation errors (#2757) 2025-06-19 11:03:42 +02:00
Yang Liu c96c1ad5dd [BIONIC] Fixed some compilation warnings (#2756) 2025-06-18 17:13:34 +02:00
Yang Liu 71220b7fef [WOW64] Finished host extension detection (#2755) 2025-06-17 09:54:58 +02:00
Yang Liu ae0c91dce0 [WOW64] Refactored host extention detection and added preliminary support for WowBox64 (#2752) 2025-06-16 14:05:38 +02:00
ptitSeb ab6deeb319 [DYNACACHE] Added the ability to mark a maplist has having new blocks (instead of dirty block that are refreshed) 2025-06-16 12:07:22 +02:00
ptitSeb c1785a93ab [DYNACACHE] Made the blocklist_t part of the dynarec allocated mmap, to ease future serialize of the map 2025-06-16 11:51:00 +02:00
ptitSeb 924903e8d2 [RCFILE] Make generic setup profile less strict 2025-06-16 11:15:09 +02:00
Yang Liu d9925eb46a [RCFILE] Updated MiSide profile (#2751) 2025-06-16 11:03:58 +02:00
ptitSeb 01e997a4da [DYNACACHE] More work on dynache relocation 2025-06-15 16:20:26 +02:00
Yang Liu 51db3f1f9a [CMAKE] Limit the optim level to O1 on bionic build (#2749) 2025-06-15 13:44:18 +02:00
Yang Liu 73dfc35c99 [TERMUX] Better handling of non-exists pthread functions (#2748) 2025-06-15 11:35:21 +02:00
Yang Liu 038835c81e [WOW64] Inherit the build type from main project (#2746) 2025-06-14 17:32:44 +02:00
ptitSeb decec260b2 [DYNAREC] Make sure a dynablock does not exit a mmap backed by a file address range 2025-06-14 11:31:18 +02:00
ptitSeb ae6ec48623 [DYNACACHE] Refactored cpu extension, will be used in dynacache signature checks 2025-06-14 10:01:52 +02:00
ptitSeb 9d93770a84 [WOWBOX64] Fixed a few more warnings 2025-06-14 10:01:10 +02:00
ptitSeb 3b53d2dac7 [WOWBOX64] Fixed a few warnings 2025-06-14 09:21:52 +02:00
Yang Liu a3d153caf0 [DOCS] Reworked Wine usage guide (#2743)
* [DOCS] Reworked Wine usage guide

* review
2025-06-13 22:07:46 +02:00
ptitSeb 3f7d726c17 Fix non-box32 build 2025-06-13 18:42:29 +02:00
Yang Liu 0dedfd03a6 [ANDROID] Unimportant updates (#2741) 2025-06-13 17:52:23 +02:00
ptitSeb 099b9c2aaf [DYNACACHE] Some more preparation work for internal relocations 2025-06-13 13:51:01 +02:00
ptitSeb 2d740c91d2 [DYNACACHE] More preparation work for internal relocations 2025-06-13 13:44:05 +02:00
ptitSeb 926a59803d [DYNACACHE][WOWBOX64] This shoyld fix the build 2025-06-13 12:58:53 +02:00
ptitSeb db24d5ddb7 [DYNACACHE] More work on preparing internal reloc, plus fix non-trace build 2025-06-13 12:36:06 +02:00
ptitSeb 217c0fa4e9 [DYNACACHE] Created a const table, for later use in internal relocation ([ARM64] only, todo on RV64 and LA64) 2025-06-13 11:57:08 +02:00
Yang Liu abe3e1c4f8 [WRAPPER] Wrapped a few more functions in gio2 and libresolv (#2737)
* [WRAPPER] Wrapped a few more functions in gio2 and libresolv

* fix static build

* fix fix
2025-06-13 09:01:10 +02:00
Luke Short ffbb0a400e Bundle fix permissions (#2738)
* [DOCS] Update tar command

to extract with root permissions.

Resolves #2713

* [BUNDLE] Use AlamaLinux Vault URLs

AlmaLinux 9.5 has been archived since the release of 9.6.

* [BUNDLE] Make failed downloads fatal

This will help us track down and fix issues with the script faster.

* [BUNDLE] Use Fedora Archive URLs

for Fedora 40. It has been archived since it went end-of-life
recently.

* [BUNLDE] Add libnsl

This is used by the Steam client.
2025-06-13 08:03:01 +02:00
Yang Liu 0d10035ffd [ARM64_DYNAREC] Fixed some typos related ymm unneeded tracing (helps #2724) (#2735) 2025-06-12 15:05:38 +02:00
Yang Liu 9cacc44125 [WRAPPER] Added 2 more functions to libc (for #2731) (#2733) 2025-06-12 10:45:11 +02:00
Yang Liu 3f757df028 [CPUID] Do not warn on the Hypervisor interface query (#2732) 2025-06-12 10:07:28 +02:00
Yang Liu e0ef328402 [ARM64_DYNAREC] Added 64/65 67 89/8B 64bits opcodes (#2730)
* [ARM64_DYNAREC] Added 64/65 67 89/8B 64bits opcodes

* review
2025-06-12 09:36:03 +02:00
Yang Liu e0067667f7 [INTERP] Fixed 64/65 67 64bit rex decoding (#2729) 2025-06-12 09:18:56 +02:00
Yang Liu 44669935da [WOW64] Small improvement to grab_segdata (#2728) 2025-06-11 13:44:41 +02:00
ptitSeb e2f22310f4 [DYNACACHE] Made dynablock part of the dynarec memory 2025-06-11 12:09:27 +02:00
Yang Liu 347f90f975 [WOW64] Small refinement to tls slots usage (#2726) 2025-06-11 12:06:01 +02:00
Yang Liu cc6d5eb0d9 [TRACE] Bring back in-house zydis header for v3.x (#2727) 2025-06-11 11:57:56 +02:00
ptitSeb 4029d52a75 This should fix non-dynarec build 2025-06-11 11:42:56 +02:00
ptitSeb d0dd1c4d4f [WOWBOX64] This should fiw wowbox64 build 2025-06-11 10:23:07 +02:00
ptitSeb 5ebdab90ea [DYNACACHE] Dynarec memory is now part of MMpa file tracking when possible 2025-06-11 10:01:21 +02:00
Yang Liu d1f8458f58 [WOW64] Added a minimal Windows runtime (#2723) 2025-06-11 09:09:06 +02:00
Yang Liu 12d6d14ae2 [ARM64_DYNAREC] Removed redundant flags save/restore around call_c (#2725) 2025-06-11 09:02:23 +02:00
Yang Liu bfd0e1700b [DYNAREC] Sync indirect lookup handling and some cleanup (#2722) 2025-06-10 12:18:35 +02:00
Yang Liu 0ae6083730 [TRACE] Fixed explicit BOX64_TRACE=0 (#2721) 2025-06-10 12:17:03 +02:00
ptitSeb 64080cea81 [DYNAREC] Improved mmap'd file tracking 2025-06-10 10:41:04 +02:00
Yang Liu ab5c42f0dc [TRACE] Added support for libzydis v4.x and removed the in-house zydis header (#2720)
* [TRACE] Exclude non-trace build from relying on in-house Zydis header

* [TRACE] Upgrade zydis to version 4.x

* [TRACE] Update docs

* [TRACE] Update CI

* [TRACE] No reason to drop 3.x support
2025-06-09 17:13:14 +02:00
ptitSeb b19dc0db89 [ARM64_DYNAREC] Added 64/65 0F BF opcode (for #2716) 2025-06-09 11:07:55 +02:00
ptitSeb d886cf1d98 [INTERP] Added 64/65 0F BF opcode (for #2716) 2025-06-09 11:02:33 +02:00
ptitSeb e427c6e9cd [DYNAREC] Reset table64size before pass1 and pass2 2025-06-09 10:59:51 +02:00
Chi-Kuan Chiu caba957426 Refine the naming scheme in rbtree (#2717)
Replaced all occurrences of `rb_get_righter` with `rb_get_rightmost` and
`rb_get_lefter` with `rb_get_leftmost` for improved semantic clarity.

Also updated related function declarations, definitions, and usage
across:
- rbtree.c
- rbtree.h
- custommem.c
- dynablock.c
- env.c
- box64context.c
2025-06-09 08:16:43 +02:00
ptitSeb 873be3cf87 [RCFILE] Fixed MAXCPU so it works for wine apps too 2025-06-08 16:41:51 +02:00
ptitSeb 685afa2302 [DYNAREC] Modified JumpTable slightly so 32bits and 48bits address space jmp can be done with only 2 and 3 memory fetch (todo: RV64 and LA64 handling of 48bits) 2025-06-08 14:16:45 +02:00
ptitSeb d3f0d1c30f [DYNAREC] Small change on jumptable to have the 1st layer maching the over 48bits address space 2025-06-08 11:00:55 +02:00
ptitSeb 7de8687a79 [BOX32][WRAPPER] Added 2 more function to 32bits wrapped libxcb.so 2025-06-08 10:50:08 +02:00
Yang Liu 4fc5885d74 [WOW64] Moved things around for the future (#2712) 2025-06-07 16:17:38 +02:00
ptitSeb 4539eccd40 Start of a new dev. cycle 2025-06-07 16:16:19 +02:00
395 changed files with 38444 additions and 9542 deletions

No files matched your search

+151 -26
View File
@@ -1,6 +1,9 @@
### Auto build Box64 and release its binary with Github Action
name: Build and Release Box64
permissions:
actions: 'write'
on:
workflow_dispatch:
release:
@@ -22,12 +25,17 @@ on:
- "CMakeLists.txt"
- "**/*.yml"
defaults:
run:
# needed on container images which could default to sh
shell: bash
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64]
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64, ARM64-GCC-8]
type: [Release, Trace, StaticBuild, Box32]
os: [ubuntu-latest, ubuntu-22.04-arm]
exclude:
@@ -65,17 +73,103 @@ jobs:
type: StaticBuild
- platform: WOW64
type: Box32
- platform: ARM64-GCC-8
os: ubuntu-latest
- platform: ARM64-GCC-8
type: Trace
- platform: ARM64-GCC-8
type: StaticBuild
- platform: ANDROID
type: Trace
- platform: TERMUX
type: Trace
- platform: LARCH64
type: Trace
include:
- platform: ARM64-GCC-8
image: arm64v8/ubuntu:18.04
runs-on: ${{ matrix.os }}
container:
image: ${{ matrix.image || '' }}
steps:
- name: "Checkout Box64 Repository"
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
uses: actions/checkout@v4
- name: "Environment preparation"
- name: "Checkout Box64 Repository (No NodeJS)"
if: ${{ matrix.platform == 'ARM64-GCC-8' }}
uses: taiki-e/checkout-action@v1
- name: Get all the unique changed directory names
id: changed-files-dir-names
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46
with:
dir_names: "true"
- name: Early exit other jobs if this is a ARM64-only change
id: early-exit-arm64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/arm64'
continue-on-error: true
run: |
sudo apt-get update
if [[ ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' && ${{ matrix.platform }} != 'X64' ]]; then
exit 1
fi
- name: Early exit other jobs if this is a LA64-only change
id: early-exit-la64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/la64'
continue-on-error: true
run: |
if [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
exit 1
fi
- name: Early exit other jobs if this is a RV64-only change
id: early-exit-rv64
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/rv64'
continue-on-error: true
run: |
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
exit 1
fi
- name: Do not early exit otherwise
id: early-exit-never
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DIRS: ${{ steps.changed-files-dir-names.outputs.all_modified_files }}
if: env.DIRS != 'src/dynarec/arm64' && env.DIRS != 'src/dynarec/la64' && env.DIRS != 'src/dynarec/rv64'
continue-on-error: true
run: exit 1
- name: Merge early exit conditions
id: early-exit
if: steps.early-exit-arm64.outcome == 'failure' || steps.early-exit-la64.outcome == 'failure' || steps.early-exit-rv64.outcome == 'failure' || steps.early-exit-never.outcome == 'failure'
continue-on-error: true
run: exit 1
# Use `steps.early-exit.outcome == 'failure'` to check whether the current step should be processed.
- name: "Environment preparation"
if: steps.early-exit.outcome == 'failure'
run: |
if [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
apt-get update
apt install -y sudo
else
sudo apt-get update
zydis_package=libzydis-dev
fi
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
sudo apt-get -y install git cmake make python3 patchelf
sudo apt-get -y install git cmake make python3 patchelf $zydis_package
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
sudo apt-get -y install p7zip
wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
@@ -98,14 +192,26 @@ jobs:
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
elif [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
# some of these dependencies may be unnecessary to explicitly install depending on the image
sudo apt-get -y install git software-properties-common lsb-release \
wget curl build-essential autoconf automake \
pkg-config ca-certificates \
python3 make gettext zstd \
gcc-8 g++-8
sudo add-apt-repository ppa:theofficialgman/cmake-bionic -y
sudo apt update
sudo apt install -y cmake
echo "BOX64_PLATFORM_MARCRO=-DARM64=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc-8" >> $GITHUB_ENV
else
sudo apt-get -y install git gcc-aarch64-linux-gnu
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
fi
if [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
wget https://packages.termux.dev/apt/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1_aarch64.deb
7z x libandroid-sysv-semaphore_0.1_aarch64.deb
wget https://packages.termux.dev/apt/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1-1_aarch64.deb
7z x libandroid-sysv-semaphore_0.1-1_aarch64.deb
tar -xf data.tar.xz
sudo cp -rf data /
sudo chmod 755 -R /data
@@ -120,14 +226,14 @@ jobs:
if [[ ${{ matrix.platform }} == 'X64' ]]; then
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
sudo apt-get -y install git cmake make python3 libzydis-dev
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc-14" >> $GITHUB_ENV
sudo apt-get -y install git gcc-14-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev libzydis-dev
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
sudo mkdir /usr/local/larch
wget -O- -q https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
wget -O- -q https://github.com/loongson/build-tools/releases/download/2025.02.21/x86_64-cross-tools-loongarch64-binutils_2.44-gcc_14.2.0-glibc_2.41.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
sudo ln -sf /usr/local/larch/target /usr/loongarch64-linux-gnu
sudo cp -r /usr/local/larch/loongarch64-unknown-linux-gnu/lib/* /usr/loongarch64-linux-gnu/lib64/
for i in objdump objcopy strip; do
@@ -139,11 +245,11 @@ jobs:
echo BOX64_PLATFORM_MARCRO="-DLARCH64=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git cmake make python3
sudo apt-get -y install git cmake make python3 libzydis-dev
else
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3 libzydis-dev
fi
fi
if [[ ${{ matrix.type }} == 'Release' ]]; then
@@ -167,15 +273,20 @@ jobs:
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
echo BOX64_BOX32=0 >> $GITHUB_ENV
fi
if [[ ${{ matrix.os }} == 'ubuntu-22.04-arm' ]]; then
echo "BOX64_ZYDIS3=1" >> $GITHUB_ENV
else
echo "BOX64_ZYDIS3=0" >> $GITHUB_ENV
fi
- name: "Get XuanTie QEMU Cache Key"
if: matrix.platform == 'RISCV'
if: matrix.platform == 'RISCV' && steps.early-exit.outcome == 'failure'
id: get-xuantie-qemu-cache-key
run: |
echo "key=f2dfdd13014d51f957c7172acc2e791cb42dc400" >> $GITHUB_OUTPUT
- name: "Cache XuanTie QEMU"
if: matrix.platform == 'RISCV'
if: matrix.platform == 'RISCV' && steps.early-exit.outcome == 'failure'
id: cache-xuantie-qemu
uses: actions/cache@v3
with:
@@ -183,7 +294,7 @@ jobs:
key: ${{ runner.os }}-${{ steps.get-xuantie-qemu-cache-key.outputs.key }}-xuantie-qemu
- name: "Checkout XuanTie QEMU"
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true' && steps.early-exit.outcome == 'failure'
uses: actions/checkout@v3
with:
repository: revyos/qemu
@@ -191,7 +302,7 @@ jobs:
ref: f2dfdd13014d51f957c7172acc2e791cb42dc400
- name: "Build XuanTie QEMU for XTheadVector"
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true' && steps.early-exit.outcome == 'failure'
run: |
cd xuantie_qemu
./configure --prefix=$GITHUB_WORKSPACE/xuantie_qemu_install --target-list=riscv64-linux-user --disable-system
@@ -199,6 +310,7 @@ jobs:
make install
- name: "Display Build info"
if: steps.early-exit.outcome == 'failure'
run: |
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
@@ -208,6 +320,7 @@ jobs:
echo "Box32 Enabled: ${{ env.BOX64_BOX32 }}"
- name: "Build Box64"
if: steps.early-exit.outcome == 'failure'
run: |
export PATH=$PATH:${{ env.MINGW_COMPILER_PATH }}
mkdir build
@@ -217,6 +330,7 @@ jobs:
${{ env.BOX64_PLATFORM_MARCRO }}\
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
-DZYDIS3=${{ env.BOX64_ZYDIS3 }}\
-DSTATICBUILD=${{ env.BOX64_STATICBUILD }}\
-DBOX32=${{ env.BOX64_BOX32 }}\
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON\
@@ -224,19 +338,23 @@ jobs:
make -j$(nproc) VERBOSE=1
- name: "Test Box64"
if: steps.early-exit.outcome == 'failure'
run: |
if [[ ${{ matrix.platform }} != 'X64' ]]; then
mkdir qemu9
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-9.0.2-1-x86_64.pkg.tar.zst | tar -I zstd -C qemu9 -xf -
sudo cp qemu9/usr/bin/* /usr/bin/
mkdir qemu10
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-10.0.0-7-x86_64.pkg.tar.zst | tar -I zstd -C qemu10 -xf -
sudo cp qemu10/usr/bin/* /usr/bin/
fi
cd build
export CTEST_OPTIONS="-j$(nproc) --timeout 120 --output-on-failure --repeat until-pass:20"
export CTEST_OPTIONS="-j$(nproc) --timeout 300 --output-on-failure --repeat until-pass:20"
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
export INTERPRETER=qemu-riscv64-static
export QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/
if [[ ${{ env.BOX64_BOX32 }} == '1' ]]; then
export BOX32_PERSONA32BITS=1 # hack to disable personality setting
fi
ctest $CTEST_OPTIONS
QEMU_CPU=rv64,v=false BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest $CTEST_OPTIONS
@@ -257,9 +375,14 @@ jobs:
export INTERPRETER=qemu-loongarch64-static
export QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/
if [[ ${{ env.BOX64_BOX32 }} == '1' ]]; then
export BOX32_PERSONA32BITS=1 # hack to disable personality setting
fi
ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
BOX64_DYNAREC_TEST=1 BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
export INTERPRETER=qemu-aarch64-static
@@ -282,13 +405,15 @@ jobs:
- name: "Get short Git commit"
id: git-info
if: steps.early-exit.outcome == 'failure'
run: echo "SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: "Get Box64 Version"
if: steps.early-exit.outcome == 'failure'
run: echo "BOX64_VERSION=$(cat src/box64version.h | grep BOX64_MAJOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_MINOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_REVISION | cut -d " " -f 3)" >> $GITHUB_ENV
- name: "Packaging WCP file for Winlator"
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild' && steps.early-exit.outcome == 'failure'
run: |
cd build
cat <<EOF > profile.json
@@ -309,7 +434,7 @@ jobs:
tar --zstd -cf box64-latest.wcp box64 profile.json
- name: "Package Rat File for MiceWine"
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild' && steps.early-exit.outcome == 'failure'
run: |
cd build
@@ -326,22 +451,22 @@ jobs:
7z -tzip -mx=5 a box64-latest.rat files pkg-header
- name: "Upload WCP file"
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type == 'Release' && steps.early-exit.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: box64-latest-${{ matrix.type }}-wcp
path: build/box64-latest.wcp
- name: "Upload Rat File"
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
if: matrix.platform == 'ANDROID' && matrix.type == 'Release' && steps.early-exit.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: box64-MiceWine-${{ matrix.type }}
path: build/box64-latest.rat
- name: "Upload WowBox64 file"
if: matrix.platform == 'WOW64' && matrix.type == 'Release'
if: matrix.platform == 'WOW64' && matrix.type == 'Release' && steps.early-exit.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: wowbox64-${{ matrix.type }}
path: build/wowbox64-prefix/src/wowbox64-build/wowbox64.dll
path: build/wowbox64-prefix/src/wowbox64-build/wowbox64.dll
-24
View File
@@ -1,24 +0,0 @@
language: c
arch:
- amd64
- arm64-graviton2
os: linux
dist: focal
compiler:
- gcc
addons:
apt:
packages:
- python3
#Build steps
before_script:
- mkdir build
- cd build
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; else cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; fi
script:
- make
- ctest --output-on-failure
+48 -14
View File
@@ -32,7 +32,8 @@ option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
option(TERMUX "Set to ON if targeting an Android device with Termux" ${TERMUX})
option(WINLATOR_GLIBC "Set to ON if targeting an Android device with Winlator Glibc" ${WINLATOR_GLIBC})
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(HAVE_TRACE "Set to ON to have Trace ability (needs libzydis-dev)" ${HAVE_TRACE})
option(ZYDIS3 "Set to ON if you have trace and an old libzydis v3.x" ${ZYDIS3})
option(SAVE_MEM "Set to ON to build dynarec with some slower memory saving optimizations" ${SAVE_MEM})
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box64" OFF)
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
@@ -50,6 +51,15 @@ if(TERMUX)
set(TERMUX_PATH "/data/data/com.termux/files")
set(ANDROID ON CACHE BOOL "")
endif()
# Hack: limit the optimization level to -O1 for some platforms
if(TERMUX OR ANDROID)
set(CMAKE_C_FLAGS_RELEASE "-O1")
set(CMAKE_CXX_FLAGS_RELEASE "-O1")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O1 -g")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g")
endif()
if(LARCH64)
set(LD80BITS OFF CACHE BOOL "")
set(NOALIGN OFF CACHE BOOL "")
@@ -294,6 +304,10 @@ if(HAVE_TRACE)
add_definitions(-DHAVE_TRACE)
endif()
if(ZYDIS3)
add_definitions(-DZYDIS3)
endif()
if(ARM_DYNAREC)
add_definitions(-DDYNAREC)
add_definitions(-DARM64)
@@ -350,6 +364,8 @@ set_source_files_properties(
set(OS_LINUX_SRC
"${BOX64_ROOT}/src/os/backtrace.c"
"${BOX64_ROOT}/src/os/emit_signals_linux.c"
"${BOX64_ROOT}/src/os/hostext_common.c"
"${BOX64_ROOT}/src/os/hostext_linux.c"
"${BOX64_ROOT}/src/os/freq_linux.c"
"${BOX64_ROOT}/src/os/os_linux.c"
"${BOX64_ROOT}/src/os/perfmap.c"
@@ -455,23 +471,13 @@ endif()
set(INTERPRETER
"${BOX64_ROOT}/src/emu/x64run.c"
"${BOX64_ROOT}/src/emu/x64run0f.c"
"${BOX64_ROOT}/src/emu/x64run64.c"
"${BOX64_ROOT}/src/emu/x64run66.c"
"${BOX64_ROOT}/src/emu/x64run660f.c"
"${BOX64_ROOT}/src/emu/x64run66f20f.c"
"${BOX64_ROOT}/src/emu/x64run66f30f.c"
"${BOX64_ROOT}/src/emu/x64run6664.c"
"${BOX64_ROOT}/src/emu/x64run66d9.c"
"${BOX64_ROOT}/src/emu/x64run66dd.c"
"${BOX64_ROOT}/src/emu/x64run66f0.c"
"${BOX64_ROOT}/src/emu/x64run67.c"
"${BOX64_ROOT}/src/emu/x64run6764.c"
"${BOX64_ROOT}/src/emu/x64run67avx.c"
"${BOX64_ROOT}/src/emu/x64run67_32.c"
"${BOX64_ROOT}/src/emu/x64run6764_32.c"
"${BOX64_ROOT}/src/emu/x64run670f.c"
"${BOX64_ROOT}/src/emu/x64run6766.c"
"${BOX64_ROOT}/src/emu/x64run67660f.c"
"${BOX64_ROOT}/src/emu/x64rund8.c"
"${BOX64_ROOT}/src/emu/x64rund9.c"
"${BOX64_ROOT}/src/emu/x64runda.c"
@@ -521,6 +527,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedayatanaappindicator3.c"
"${BOX64_ROOT}/src/wrapped/wrappedbz2.c"
"${BOX64_ROOT}/src/wrapped/wrappedcap.c"
"${BOX64_ROOT}/src/wrapped/wrappedcuda.c"
"${BOX64_ROOT}/src/wrapped/wrappedcairo.c"
"${BOX64_ROOT}/src/wrapped/wrappedcairogobject.c"
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
@@ -581,6 +588,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibavcodec58.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibavformat58.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibavutil56.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibblas.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibbsd.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
@@ -600,6 +608,7 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibibus.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
"${BOX64_ROOT}/src/wrapped/wrappedliblapack.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses.c"
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
@@ -911,6 +920,7 @@ if(DYNAREC)
"${BOX64_ROOT}/src/dynarec/dynablock.c"
"${BOX64_ROOT}/src/dynarec/dynarec_native.c"
"${BOX64_ROOT}/src/dynarec/dynarec_native_functions.c"
"${BOX64_ROOT}/src/dynarec/dynacache_reloc.c"
"${BOX64_ROOT}/src/emu/x64test.c"
)
endif()
@@ -924,6 +934,8 @@ if(ARM_DYNAREC)
"${BOX64_ROOT}/src/dynarec/arm64/arm64_immenc.c"
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_jmpnext.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_consts.c"
"${BOX64_ROOT}/src/dynarec/arm64/updateflags_arm64.c"
)
set(DYNAREC_ASM
${DYNAREC_ASM}
@@ -947,6 +959,7 @@ if(ARM_DYNAREC)
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67_32.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67_avx.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6764.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6764_32.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d8.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d9.c"
@@ -975,6 +988,8 @@ if(ARM_DYNAREC)
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f38.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f3a.c"
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f3_0f38.c"
"${BOX64_ROOT}/src/dynarec/arm64/updateflags_arm64_pass.c"
)
endif()
@@ -986,7 +1001,7 @@ if(RV64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_arch.c"
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
"${BOX64_ROOT}/src/rv64detect.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_consts.c"
)
set(DYNAREC_ASM
${DYNAREC_ASM}
@@ -1036,6 +1051,11 @@ if(RV64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f_vector.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c"
)
endif()
@@ -1047,6 +1067,7 @@ if(LARCH64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
"${BOX64_ROOT}/src/dynarec/la64/la64_printer.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_jmpnext.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_consts.c"
)
set(DYNAREC_ASM
${DYNAREC_ASM}
@@ -1075,6 +1096,17 @@ if(LARCH64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f0.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f20f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_0f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_0f38.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f38.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f3a.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f38.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f3_0f.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f3_0f38.c"
)
endif()
@@ -1185,6 +1217,7 @@ else()
endif()
else()
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
target_link_libraries(${BOX64} c m dl pthread resolv util c)
endif()
endif()
if(DYNAREC)
@@ -1341,12 +1374,13 @@ if(WOW64 AND ARM_DYNAREC)
include(ExternalProject)
ExternalProject_Add(
wowbox64
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wow64"
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/wow64"
CMAKE_ARGS
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wow64/toolchain_mingw.cmake
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw.cmake
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
-DDYNAREC_ASM_STR=${DYNAREC_ASM_STR}
-DINTERPRETER_STR=${INTERPRETER_STR}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
INSTALL_COMMAND ""
TEST_COMMAND ""
BUILD_ALWAYS ON
+15 -6
View File
@@ -2,7 +2,7 @@
# Box64: Linux Userspace x86-64 Emulator with a Twist
[Changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
[Website](https://box86.org/) | [Changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
![Build Status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main) ![Stars](https://img.shields.io/github/stars/ptitSeb/box64) ![Forks](https://img.shields.io/github/forks/ptitSeb/box64) ![Contributors](https://img.shields.io/github/contributors/ptitSeb/box64) ![Pull Requests](https://img.shields.io/github/issues-pr/ptitSeb/box64) ![Issues](https://img.shields.io/github/issues/ptitSeb/box64)
@@ -27,7 +27,12 @@ _Logo and icon by @grayduck - Thank you!_
## 📖 Usage
Box64 offers environment variables to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
- `$ box64 ./program [args]` to run Linux x86_64 programs.
- `$ box64 -k` to kill all the emulated processes.
- `$ box64-bash` to have a x86_64 bash environment.
- Want to use wine? see [Wine Documentation](docs/WINE.md).
Box64 also offers environment variables and rcfile to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
---
@@ -35,7 +40,7 @@ Box64 offers environment variables to control its behavior. For details, see [Us
- [Compilation Instructions](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
- [Bundle x86 Libraries](https://github.com/ptitSeb/box64/blob/main/docs/BUNDLE-X86-LIBS.md)
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
---
@@ -47,7 +52,7 @@ See the [Changelog](docs/CHANGELOG.md) for version updates.
## 🖥️ Platform Compatibility Notes
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86.
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86 or Box32.
**Notes**
@@ -62,6 +67,8 @@ Box64 has configuration files located in `/etc/box64.box64rc` and `~/.box64rc`,
Settings priority: `~/.box64rc` > `/etc/box64.box64rc` > Command line.
For more information, check [Usage Documentation](docs/USAGE.md).
---
## 📄 Additional Platform-Specific Notes
@@ -76,9 +83,9 @@ Settings priority: `~/.box64rc` > `/etc/box64.box64rc` > Command line.
Box64 wraps GTK libraries, supporting both gtk2 and gtk3.
### Steam
### Linux Steam
Steam requires Box86 due to its 32-bit client app, but uses 64-bit local server binaries. Systems with less than 6GB RAM may need a swap file for optimal performance.
Linux Steam requires Box86 or Box32 due to its 32-bit client app, but uses 64-bit local server binaries. Systems with less than 6GB RAM may need a swap file for optimal performance.
### Wine
@@ -86,6 +93,8 @@ Box64 supports Wine64 and Proton. For 32-bit components, Box86 is required. Syst
**Note**: You can use Wine WOW64 build to run x86 Windows programs in Box64-only environments, this is still experimental, but it works in most cases.
For more information, check [Wine Documentation](docs/WINE.md).
### Vulkan
Box64 wraps Vulkan libraries.
+15 -6
View File
@@ -2,7 +2,7 @@
# Box64:Linux 用户空间 x86-64 模拟器(支持原生库)
[更新日志](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
[官网](https://box86.org/) | [更新日志](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
![Build Status](https://app.travis-ci.com/ptitSeb/box64.svg?branch=main) ![Stars](https://img.shields.io/github/stars/ptitSeb/box64) ![Forks](https://img.shields.io/github/forks/ptitSeb/box64) ![Contributors](https://img.shields.io/github/contributors/ptitSeb/box64) ![Pull Requests](https://img.shields.io/github/issues-pr/ptitSeb/box64) ![Issues](https://img.shields.io/github/issues/ptitSeb/box64)
@@ -27,14 +27,19 @@ _Logo 由 @grayduck 制作,感谢!_
## 📖 使用方法
Box64 提供了环境变量来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
- `$ box64 ./program [args]` 运行 Linux x86_64 程序。
- `$ box64 -k` 杀死所有模拟的进程。
- `$ box64-bash` 进入 x86_64 bash 环境。
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE.md)。
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
---
## 🚀 编译和安装
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
---
@@ -46,7 +51,7 @@ Box64 提供了环境变量来控制其行为。有关详细信息请参阅[使
## 🖥️ 平台兼容性说明
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文​​件,请使用 Box86。
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文​​件,请使用 Box86 或 Box32。
**注意事项**
@@ -61,6 +66,8 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
更多信息,请参阅[使用文档](docs/USAGE.md)。
---
## 📄 特定平台的其他说明
@@ -74,9 +81,9 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
Box64 包装了 GTK 库,支持 gtk2 和 gtk3。
### Steam
### Linux Steam
由于 Steam 客户端应用是 32 位的,需要使用 Box86,但其本地服务器是 64 位的二进制文件。对于内存少于 6GB 的系统,可能需要使用交换文件以获得最佳性能。
由于 Linux Steam 客户端应用是 32 位的,需要使用 Box86 或 Box32,但其本地服务器是 64 位的二进制文件。对于内存少于 6GB 的系统,可能需要使用交换文件以获得最佳性能。
### Wine
@@ -84,6 +91,8 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
有关更多信息,请参阅 [Wine 使用说明](docs/WINE.md)。
### Vulkan
Box64 包装了 Vulkan 库。
+1 -1
View File
@@ -37,7 +37,7 @@ Box64 інтегрується з DynaRec (динамічний рекомпіл
Компіляція/Встановлення
----
> Інструкцію зі складання Box64 можна знайти [тут](docs/COMPILE.md).\
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/X64WINE.md).
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/WINE.md).
----
Історія версій/Журнал змін
+70 -60
View File
@@ -1,66 +1,76 @@
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm,fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.i686.rpm,0c6f2ecc324680c6424bee4b1dbbdad2863f0f7f3130b196fc6e2b2823f07bc4
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.x86_64.rpm,483e4c58cb8af94143a0ff4b3e49b62cb7d6896766c8c0d9fe3659e68945b50e
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm,686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm,9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm,23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm,f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm,77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm,d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.i686.rpm,eb518e9d073c36fd29862c7afd00a8a7cb186074a0e162983f18fb6c9dc71d2c
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.x86_64.rpm,0f44e37e4eb472508e0dba8505ebbb04c2c1390c6a43970a6af80aad886037e3
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm,e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm,2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm,c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm,439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.12-1.fc40.i686.rpm,4a3bce6e6358ddd05ed2941e7b8fcc4c8cc02df20741d3f0f9295facbc687769
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.12-1.fc40.x86_64.rpm,9524803ef42d80dc1b15190d5bb5925200995d5a6152eca04471383ff891af17
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm,13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm,fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm,e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm,9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm,abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm,0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm,f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.i686.rpm,f4776f6f56a8d3e62e95c06fb885832e22116323c0c2e0f57f918cd4b92e16a2
https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.x86_64.rpm,96f52b7cf293ce335e2bf726c8b6aefd82ed76fbe9d9f0db1fe603780477c2d0
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm,fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.i686.rpm,28bc1088e39483d145849e8804c5a0f2524faeb4f76631ae46c41100f40e08b9
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.x86_64.rpm,1848b9ced2dfec6c206791b23a5a8a6356939c5ed0492fc91c86bf1d3a255c1d
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.i686.rpm,386040fc502e2f02b4b072e0cd90c034dc0a30831fbd2ddb116d17c080b6f9a4
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.x86_64.rpm,2a13461c7d5fcf72ffd682b3eb04833aea8306d61c3b8bdeb42a5081d96d5478
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm,77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libffi-3.4.2-8.el9.i686.rpm,70daa216ed2a6540e41c455efc95d2b5671db164137f854bceae07e348f58645
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libffi-3.4.2-8.el9.x86_64.rpm,1cf2d122e5c423681394c1bc599ee2281d2eafff5a3749842bc93c37db4bed5e
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm,686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm,9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm,23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm,f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.i686.rpm,7f4d1552b6036c49028db959f82fc0bc30773cd7ed0a62c3906da0e2388f4dc5
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.x86_64.rpm,7d0e521ab087807ee71d79da66a2829b827bf5080bb5d080dfab108e31cf218b
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm,d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm,e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm,2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm,c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm,439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/ncurses-libs-6.2-10.20210508.el9.i686.rpm,285db6dc6f610f75ef6863dcb0a383eae394c2b33bff283189cb49ac7fae4c58
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/ncurses-libs-6.2-10.20210508.el9.x86_64.rpm,d06b0e491481a345faf21a69666cbdc302d19b54fb29ae1aa78fa6b205f9e604
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm,e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm,9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm,abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm,0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm,f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm,dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm,e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
1 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm 49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm 75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm 64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm 16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm 5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm 1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
1 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4 d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
2 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb 625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463 625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.i686.rpm 0c6f2ecc324680c6424bee4b1dbbdad2863f0f7f3130b196fc6e2b2823f07bc4
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.x86_64.rpm 483e4c58cb8af94143a0ff4b3e49b62cb7d6896766c8c0d9fe3659e68945b50e
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm 686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm 9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm 23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm 4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg 5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm 9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm 83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm 66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm 77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm 7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm 8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm 05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm 7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm 9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm 2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm 2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm 25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm 792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
3 https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.i686.rpm https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.i686.rpm eb518e9d073c36fd29862c7afd00a8a7cb186074a0e162983f18fb6c9dc71d2c eb518e9d073c36fd29862c7afd00a8a7cb186074a0e162983f18fb6c9dc71d2c
4 https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.x86_64.rpm https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.x86_64.rpm 0f44e37e4eb472508e0dba8505ebbb04c2c1390c6a43970a6af80aad886037e3 0f44e37e4eb472508e0dba8505ebbb04c2c1390c6a43970a6af80aad886037e3
5 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.12-1.fc40.i686.rpm e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b 4a3bce6e6358ddd05ed2941e7b8fcc4c8cc02df20741d3f0f9295facbc687769
6 https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.12-1.fc40.x86_64.rpm 3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e 9524803ef42d80dc1b15190d5bb5925200995d5a6152eca04471383ff891af17
7 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49 c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
8 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg 2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce 5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm 439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
9 https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm 13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5 13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
10 https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
11 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970 75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
12 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm 9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5 b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
13 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91 d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
14 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm 0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646 d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
15 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862 ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
16 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm 15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18 d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
17 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm 2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
18 https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm 308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75 b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
19 https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.i686.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm f4776f6f56a8d3e62e95c06fb885832e22116323c0c2e0f57f918cd4b92e16a2 9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
20 https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.x86_64.rpm https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm 96f52b7cf293ce335e2bf726c8b6aefd82ed76fbe9d9f0db1fe603780477c2d0 83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
21 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm 7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
22 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm 8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
23 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm 2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
24 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm 25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
25 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
26 https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm 3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
27 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
28 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm 49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
29 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.i686.rpm 28bc1088e39483d145849e8804c5a0f2524faeb4f76631ae46c41100f40e08b9
30 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.x86_64.rpm 1848b9ced2dfec6c206791b23a5a8a6356939c5ed0492fc91c86bf1d3a255c1d
31 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
32 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
33 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm 64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
34 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm 16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
35 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm 5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
36 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm 1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
37 https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.i686.rpm 386040fc502e2f02b4b072e0cd90c034dc0a30831fbd2ddb116d17c080b6f9a4
38 https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.x86_64.rpm 2a13461c7d5fcf72ffd682b3eb04833aea8306d61c3b8bdeb42a5081d96d5478
39 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
40 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
41 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
42 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm 77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
43 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libffi-3.4.2-8.el9.i686.rpm 70daa216ed2a6540e41c455efc95d2b5671db164137f854bceae07e348f58645
44 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libffi-3.4.2-8.el9.x86_64.rpm 1cf2d122e5c423681394c1bc599ee2281d2eafff5a3749842bc93c37db4bed5e
45 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm 686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
46 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm 9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
47 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm 23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
48 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
49 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm 4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
50 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
51 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.i686.rpm 7f4d1552b6036c49028db959f82fc0bc30773cd7ed0a62c3906da0e2388f4dc5
52 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.x86_64.rpm 7d0e521ab087807ee71d79da66a2829b827bf5080bb5d080dfab108e31cf218b
53 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm 66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
54 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
55 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm 05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
56 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm 7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
57 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm 9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
58 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm 2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
59 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm 792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
60 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
61 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49
62 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm 2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce
63 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
64 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm 439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
65 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/ncurses-libs-6.2-10.20210508.el9.i686.rpm 285db6dc6f610f75ef6863dcb0a383eae394c2b33bff283189cb49ac7fae4c58
66 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/ncurses-libs-6.2-10.20210508.el9.x86_64.rpm d06b0e491481a345faf21a69666cbdc302d19b54fb29ae1aa78fa6b205f9e604
67 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
68 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm 9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
69 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
70 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm 0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
71 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862
72 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm 15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
73 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm 2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
74 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm 308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
75 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
76 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
+113 -81
View File
@@ -1,96 +1,128 @@
#!/bin/bash
#!/bin/sh
set -x
set -ex
extract_pkg_auto() {
# Example x86_64 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb
# Example x86 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb
if echo "${1}" | grep -q -P ".deb$"; then
echo "DEB (Debian) package detected."
ar x "$(basename "${1}")"
tar --extract --file data.tar*
# Example x86_64 package name: curl-gnutls-8.1.2-44-1-x86_64.eopkg
# Example x86 package name: curl-gnutls-32bit-8.1.2-44-1-x86_64.eopkg
elif echo "${1}" | grep -q -P ".eopkg$"; then
echo "EOPKG (Solus Linux) package detected."
unzip -o "$(basename "${1}")"
tar --extract --file install.tar.xz
# Example x86_64 package name: bluez-libs-5.63-1.el8.x86_64.rpm
# Example x86 package name: bluez-libs-5.63-1.el8.i686.rpm
elif echo "${1}" | grep -q -P ".rpm$"; then
echo "RPM (Fedora) detected."
rpm2cpio "$(basename "${1}")" | cpio -idmv
# Example x86_64 package name: libjpeg-turbo-3.0.1_1.x86_64.xbps
# Example x86 package name: libjpeg-turbo-32bit-3.0.1_1.x86_64.xbps
elif echo "${1}" | grep -q -P ".xbps$"; then
echo "XBPS (Void Linux) package detected."
tar --extract --file "$(basename "${1}")"
else
echo "Unsupported package type detected."
exit 1
fi
trap cleanup_exit INT TERM EXIT
cleanup_exit()
{
echo "Running cleanup_exit..."
rm -rf /tmp/box64-bundle.*
}
box64_dir=$(pwd)
dir_tmp_local="$(mktemp --directory)"
cd "${dir_tmp_local}"
# we must have few tools
awk=$(which awk) || { echo "E: You must have awk" && exit 1; }
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
curl=$(which curl) || { echo "E: You must have curl" && exit 1; }
curl_cmd="${curl} --connect-timeout 5 --retry 5 --retry-delay 1 --create-dirs -fsSLo"
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
sha256sum=$(which sha256sum) || { echo "E: You must have sha256sum" && exit 1; }
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
for line in $(cat "${box64_dir}/box64-bundle-x86-libs.csv");
do pkg_url="$(echo "${line}" | cut -d, -f1)"
pkg_checksum_expected="$(echo "${line}" | cut -d, -f2)"
pkg_name="$(basename "${pkg_url}")"
curl --silent --location --remote-name "${pkg_url}"
pkg_checksum_actual="$(sha256sum ${pkg_name} | awk '{print $1}')"
if [[ "${pkg_checksum_expected}" -ne "${pkg_checksum_actual}" ]];
then echo "Invalid checksum for ${pkg_name}"
echo "Expected: ${pkg_checksum_expected}"
echo "Actual: ${pkg_checksum_actual}"
current_dir=$(pwd)
dir_tmp="$(mktemp -d /tmp/box64-bundle.XXXXXX)"
# download the packages
while IFS= read -r line; do
# shellcheck disable=SC2016
pkg_url=$(echo "${line}" | ${awk} -F',' '{print$(NF-1)}')
# shellcheck disable=SC2016
pkg_checksum=$(echo "${line}" | ${awk} -F',' '{print$(NF)}')
# shellcheck disable=SC2016
pkg_name=$(echo "${pkg_url}" | ${awk} -F'/' '{print$(NF)}')
${curl_cmd} "${dir_tmp}/bundle-pkgs/${pkg_name}" "${pkg_url}"
checksum="$(${sha256sum} "${dir_tmp}/bundle-pkgs/${pkg_name}" | awk '{print $1}')"
if [ "${pkg_checksum}" != "${checksum}" ]; then
echo "E: Invalid checksum for ${pkg_name}"
echo "Expected: ${pkg_checksum}"
echo "Computed: ${checksum}"
exit 1
fi
extract_pkg_auto "${pkg_name}"
done < box64-bundle-x86-libs.csv
# generate the bundle packages archive
tar -C "${dir_tmp}"/bundle-pkgs -czvf "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
# extract the packages
cd "${dir_tmp}"/bundle-pkgs
for file in *.deb *.eopkg *.rpm *.xbps; do
# handle the case of no files, e.g. xbps
[ -e "${dir_tmp}"/bundle-pkgs/"${file}" ] || break
# shellcheck disable=SC2016
extension=$(echo "${file}" | ${awk} -F'.' '{print$(NF)}')
mkdir -p "${dir_tmp}"/bundle-libs
cd "${dir_tmp}"/bundle-libs
case "${extension}" in
deb)
echo "I: DEB (Debian) package detected (${file})"
ar x "${dir_tmp}"/bundle-pkgs/"${file}"
tar -xf data.tar*
;;
eopkg)
echo "I: EOPKG (Solus Linux) package detected (${file})"
${unzip} -o "${dir_tmp}"/bundle-pkgs/"${file}"
tar -xf install.tar.xz
;;
rpm)
echo "I: RPM (Fedora) detected (${file})"
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
;;
xbps)
echo "I: XBPS (Void Linux) package detected (${file})"
tar -xf "${dir_tmp}"/bundle-pkgs/"${file}"
;;
esac
done
# Start preperation of bundles.
mkdir -p \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu" \
"${dir_tmp_local}/bundle-pkgs" \
# reorganize the files
cd "${dir_tmp}"/bundle-libs
mkdir -p "${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/*.so* usr/lib32/*.so* \
"${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
mkdir -p "${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
mv lib64/*.so* usr/lib/x86_64-linux-gnu/*.so* usr/lib64/*.so* \
"${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
rm -f ./*.tar.* debian-binary files.xml metadata.xml
rm -rf ./lib* etc run sbin usr var
mkdir -p usr/lib
mv box64-*-linux-gnu usr/lib
# Copy Debian family libraries.
cp --archive "${dir_tmp_local}"/usr/lib/i386-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
cp --archive "${dir_tmp_local}"/usr/lib/x86_64-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
# Copy Fedora family libraries.
cp --archive "${dir_tmp_local}"/usr/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
cp --archive "${dir_tmp_local}"/usr/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
## This location is used by a few special packages such as "glibc".
cp --archive "${dir_tmp_local}"/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
cp --archive "${dir_tmp_local}"/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
# Copy Solus and Void Linux family libraries.
cp --archive "${dir_tmp_local}"/usr/lib32/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
# remove libraries that cannot be emulated
# https://github.com/ptitSeb/box64/blob/v0.3.6/src/librarian/library.c#L433
set -- libc libpthread librt libGL libX11 libasound libdl libm libbsd libutil \
libresolv libXxf86vm libXinerama libXrandr libXext libXfixes libXcursor \
libXrender libXft libXi libXss libXpm libXau libXdmcp libX11-xcb libxcb \
libxcb-xfixes libxcb-shape libxcb-shm libxcb-randr libxcb-image \
libxcb-keysyms libxcb-xtest libxcb-glx libxcb-dri2 libxcb-dri3 libXtst libXt \
libXcomposite libXdamage libXmu libxkbcommon libxkbcommon-x11 \
libpulse-simple libpulse libvulkan ld-linux-x86-64 crashhandler \
libtcmalloc_minimal libanl ld-linux libthread_db
for file in "$@"; do
rm -f "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu/"${file}".so*
done
# Create "<LIBRARY_FILE>.so" symlinks.
for dir_lib in \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
# If two or more libraries of the same name exist, this will symlink the oldest version.
# Pipe this into a reverse sort `| sort -r` to symlink the newest version.
do for lib in $(ls -1 "${dir_lib}")
# Example output: libbluetooth.so
do lib_base="$(echo "${lib}" | cut -d. -f1,2)"
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null
then ln -s "${lib}" "${dir_lib}/${lib_base}"
# check broken symlinks
if find "${dir_tmp}"/bundle-libs -type l ! -exec test -e {} \; -print | grep bundle-libs; then
echo "E: Broken symlinks found"
exit 1
fi
# create shared libraries (.so) symlinks
# if multiple libraries of the same name exist, it will symlink the oldest version
# e.g. libcurl-gnutls soname with versioned symbols (CURL_GNUTLS_3, CURL_GNUTLS_4)
# libcurl-gnutls.so -> libcurl-gnutls.so.3
# libcurl-gnutls.so.3 -> libcurl-gnutls.so.4
# libcurl-gnutls.so.4 -> libcurl-gnutls.so.4.7.0
# libcurl-gnutls.so.4.7.0
for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
cd "${dir_lib}"
for lib in lib*.so*; do
lib_base="$(echo "${lib}" | awk -F'.' '{print $1"."$2}')"
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null; then
ln -s "${lib}" "${lib_base}"
fi
done
done
mv "${dir_tmp_local}"/*.deb "${dir_tmp_local}/bundle-pkgs/"
mv "${dir_tmp_local}"/*.eopkg "${dir_tmp_local}/bundle-pkgs/"
mv "${dir_tmp_local}"/*.rpm "${dir_tmp_local}/bundle-pkgs/"
mv "${dir_tmp_local}"/*.xbps "${dir_tmp_local}/bundle-pkgs/"
tar --directory "${dir_tmp_local}/bundle-libs" --create --file "${box64_dir}/box64-bundle-x86-libs.tar.gz" .
tar --directory "${dir_tmp_local}/bundle-pkgs" --create --file "${box64_dir}/box64-bundle-x86-pkgs.tar.gz" .
# Clean up.
cd -
rm -r -f "${dir_tmp_local}"
# generate the bundle libraries archive
tar -C "${dir_tmp}"/bundle-libs -czvf "${current_dir}"/box64-bundle-x86-libs.tar.gz .
+12
View File
@@ -1,3 +1,15 @@
box64 (0.3.8) unstable; urgency=low
This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
=> DynaCache for faster loading of program, and avoid runtime hicups
=> Batter box32 compatibility (much less "Out of Memory" error)
=> Unity3D games on Wayland are working now
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
box64 (0.3.6) unstable; urgency=low
This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
+11 -6
View File
@@ -8,14 +8,19 @@ The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-b
Install required dependencies for the bundle script.
- Arch Linux
```
sudo pacman -S -y -u
sudo pacman -S binutils coreutils curl rpm-tools tar zstd
```
- Debian
```
sudo apt-get update
sudo apt-get install coreutils curl binutils rpm2cpio tar zstd
sudo apt-get install binutils coreutils curl rpm2cpio tar zstd
```
- Fedora
```
sudo dnf install coreutils curl binutils tar zstd
sudo dnf install binutils coreutils curl tar zstd
```
Run `box64-bundle-x86-libs.sh`. This will create two archives:
@@ -25,7 +30,7 @@ Run `box64-bundle-x86-libs.sh`. This will create two archives:
Extract the library archive. Box will automatically search these paths for library files to emulate.
```
sudo tar --extract --file box64-bundle-x86-libs.tar.gz --directory /
sudo tar --extract --no-same-owner --file box64-bundle-x86-libs.tar.gz --directory /
```
### Developer
@@ -45,9 +50,9 @@ Preference of operating system packages that provide a library:
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
5. Other (whereever a library is packaged)
Some essential library files will never be emulated (only wrapped) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [here](https://github.com/ptitSeb/box64/blob/v0.3.2/src/librarian/library.c#L427). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
Some essential library files will never be emulated (only wrapped) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.3.6/src/librarian/library.c#L433). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
For finding package names that contian a specific library file, use the [pkgs.org](https://pkgs.org/) website. Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
For finding package names that contian a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
- DEB
- `apt-file <LIBRARY_FILE>`
- EOPKG
@@ -70,4 +75,4 @@ Once the package name is found, find the exact URL for downloading it.
Download the package and then find the checksum with the `sha256sum` command.
Major Linux distributions such as AlmaLinux and Debian provide archives of packages. Rolling distributions such as Solus and Void Linux do not. In those cases, use the [Internet Archive](https://web.archive.org/) to archive any rolling release package used by Box by using the "Save Page Now" feature. If the error "Save Page Now browser crashed" appears, it can be safely ignored. The archive will still have been saved.
Major Linux distributions such as AlmaLinux and Debian provide archives of packages. Most rolling distributions such as Solus and Void Linux do not (one exception is Arch Linux which has the [Arch Linux Archive (ALA)](https://wiki.archlinux.org/title/Arch_Linux_Archive)). In those cases, use the [Internet Archive](https://web.archive.org/) to archive any rolling release package used by Box by using the "Save Page Now" feature. If the error "Save Page Now browser crashed" appears, it can be safely ignored. The archive will still have been saved.
+45
View File
@@ -1,3 +1,48 @@
v0.3.8
======
Highlights:
* This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
=> DynaCache for faster loading of program, and avoid runtime hicups
=> Batter box32 compatibility (much less "Out of Memory" error)
=> Unity3D games on Wayland are working now
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
Version summary:
* Improved and fixed memory tracking
* Improved volatile metadata handling, and some light refactor on StrongMem emulation
* Improved handling of TF flag
* DynaCache: Introducing a way to cache on disk native generated code for faster startup time on subsequent release
* DynaCache: Support for all 3 backends ARM64, RV64 & LA64
* Interpreter: refactor opcodes decoding to have prefixes handled in a generic way
* Interpreter: many small fixes
* Dynarec: some optimisations in the jump table, to remove one memory fetch on each jump
* Dynarec: create infrastructure to be able to change easily the reg mapping
* Dynarec: optimised defered flag handling to limit cases where UpdateFlags is needed
* Dynarec: Introduced BOX64_DYNAREC_NOHOTPAGE to disable detection of hotpages
* Dynarec: ARM64: A few more opcode added
* Dynarec: ARM64: Some small fixes and better handling of undefined behavior in opcodes, as well as undefined opcodes
* Dynarec: ARM64: Implemented a Dynarec version of UpdateFlags, for improved performances
* Dynarec; ARM64: Fixes/Improved SSE_FLUSHTO0 support
* Dynarec: LA64: Added support for AVX (& friends) opcodes. Still need some debugging so AVX still disabled by default on LA64
* Dynarec: LA64: Changed register mapping to be closer to the x86_64 ABI
* Dynarec: LA64: RV64: Added limited support to SSE_FLUSHTO0
* Dynarec: RV64: Many fixes and improvments for MMX opcodes
* Dynarec: RV64: many Scalar version of AVX opcodes added
* Dynarec: Many fixes to various OpCodes, on all 3 backends
* WowBox64: Added minimal runtime, improved overall stability
* BOX32: Wrapper: many new functions added, plus many fixes
* BOX32: Improved memory hadnling, using 32bits personality and other tunning to get more reliable 32bits memory allocations
* BOX64: Wrapper: some more wrapped functions added, including wayland (for Unity games on Wayland) and vulkan (more extensions)
* BOX64: Wrapper: improved handling of some VarArg wrapped functions on non-ARM64 backend
* RCFILE: Fixed MAXCPU not working properly with Wine programs
* RCFILE: Generic Setup profile refined, and more games profile added
* Trace: Added support for current libZydis
v0.3.6
======
+20 -7
View File
@@ -1,11 +1,11 @@
Compiling/Installing
----
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-build-packages) for alternatives.
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-built-packages) for alternatives.
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-compiling)
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-Compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-Compiling)
## Per-platform compiling instructions
@@ -260,7 +260,7 @@ Add `-DCMAKE_BUILD_TYPE=RelWithDebInfo` option for an optimized build with debug
#### Build with trace
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime to get x86 trace. Use version v3.2.1, as later versions have changed the API and no longer work with box64.
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) devel package installed (`apt install libzydis-dev` on Debian for example).
#### Build DynaRec
@@ -334,7 +334,7 @@ sudo apt update
sudo apt install box64-generic-arm -y
```
## Cross-compiling
## Cross-Compiling
----
### Set Up the Cross-Compiler
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
@@ -346,6 +346,9 @@ In particular, you must specify the cross-compiler. For example:
-DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc # Or whichever cross-compiler you use
```
Be aware of potential glibc capability errors when choosing a cross-compiler.
To avoid this, run `ldd --version` on your target machine to check its glibc version.
### Running tests with QEMU (optional)
To do a quick check, run:
```
@@ -361,6 +364,16 @@ ctest -j$(nproc)
### Installing on the Target Machine
After successfully cross-compiling, copy the box64 executable to your RISC-V device. Note that simply copying the binary does not automatically install Box64’s shared libraries. Because `make install` does not run on the target during cross-compilation, libraries required for emulation may be missing.
To fix this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target. Place them into the proper library search paths, for example:
- `/usr/lib/box64-x86_64-linux-gnu/` (for x86_64)
- `/usr/lib/box64-i386-linux-gnu/` (for i386)
To resolve this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target device, then rename it and place it in the appropriate library search path (e.g., `/usr/lib`).
For `x86_64`:
```shell
$ mv x64lib box64-x86_64-linux-gnu
$ mv box64-x86_64-linux-gnu /usr/lib
```
For `i386`:
```shell
$ mv x86lib box64-i386-linux-gnu
$ mv box64-i386-linux-gnu /usr/lib
```
+179 -149
View File
@@ -43,6 +43,180 @@ This configuration will apply the specified settings application-wide to any exe
----
## Performance
### BOX64_DYNAREC
Enable/disable the Dynamic Recompiler (a.k.a DynaRec). This option defaults to 1 if it's enabled in the build options for a supported architecture. Availble in WowBox64.
* 0: Disable DynaRec.
* 1: Enable DynaRec.
### BOX64_DYNAREC_ALIGNED_ATOMICS
Generate aligned atomics only (only available on Arm64 for now). Availble in WowBox64.
* 0: Generate unaligned atomics handling code. [Default]
* 1: Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on unaligned data addresses.
### BOX64_DYNAREC_BIGBLOCK
Enable building bigger DynaRec code blocks for better performance. Availble in WowBox64.
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
* 1: Build Dynarec block as big as possible.
* 2: Build Dynarec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
* 3: Build Dynarec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
### BOX64_DYNAREC_CALLRET
Optimize CALL/RET opcodes. Availble in WowBox64.
* 0: Do not optimize CALL/RET, use jump table. [Default]
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
### BOX64_DYNAREC_DF
Enable or disable the use of deferred flags. Availble in WowBox64.
* 0: Disable the use of deferred flags.
* 1: Enable the use of deferred flags. [Default]
### BOX64_DYNAREC_DIRTY
Allow continue running a block that is unprotected and potentially dirty.
* 0: Do not allow continue running a block that is unprotected and potentially dirty. [Default]
* 1: Allow continue to run a dynablock that write data in the same page as code. It can gets faster in loading time of some game but can also get unexpected crashes.
* 2: Will also, when it detect an HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but Block build from that page will always be tested. It can be faster that way (but soem SMC case might not be trapped).
### BOX64_DYNAREC_NOHOTPAGE
Disable detection of hot page (where code is executed and data written at the same time).
* 0: Detect hot page [Default]
* 1: Do not detect hot page
### BOX64_DYNAREC_FASTNAN
Enable or disable fast NaN handling. Availble in WowBox64.
* 0: Precisely emulate the -NaN generation like on x86.
* 1: Do not do anything special with -NAN generation, faster. [Default]
### BOX64_DYNAREC_FASTROUND
Enable or disable fast rounding. Availble in WowBox64.
* 0: Generate float/double -> int rounding and use current rounding mode for float/double computation like on x86.
* 1: Do not do anything special with edge case rounding, faster. [Default]
* 2: Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
### BOX64_DYNAREC_FORWARD
Define max allowed forward value when building block. Availble in WowBox64.
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
### BOX64_DYNAREC_NATIVEFLAGS
Enable or disable the use of native flags. Availble in WowBox64.
* 0: Do not use native flags.
* 1: Use native flags when possible. [Default]
### BOX64_DYNAREC_PAUSE
Enable x86 PAUSE emulation, may help the performance of spinlocks. Availble in WowBox64.
* 0: Ignore x86 PAUSE instruction. [Default]
* 1: Use YIELD to emulate x86 PAUSE instruction.
* 2: Use WFI to emulate x86 PAUSE instruction.
* 3: Use SEVL+WFE to emulate x86 PAUSE instruction.
### BOX64_DYNAREC_SAFEFLAGS
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Availble in WowBox64.
* 0: Treat CALL/RET as if it never needs any flags.
* 1: Most of RETs will need flags, most of CALLs will not. [Default]
* 2: All CALL/RET will need flags. All edge cases are also handled.
### BOX64_DYNAREC_STRONGMEM
Enable the emulation of x86 strong memory model. Availble in WowBox64.
* 0: Do not try anything special. [Default]
* 1: Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
* 2: All in 1, plus memory barriers on SIMD instructions.
* 3: All in 2, plus more memory barriers on a regular basis.
### BOX64_DYNAREC_VOLATILE_METADATA
Use volatile metadata parsed from PE files, only valid for 64bit Windows games.
* 0: Do not use volatile metadata.
* 1: Use volatile metadata, which will guide Box64 for better strong memory emulation. [Default]
### BOX64_DYNAREC_WAIT
Wait or not for the building of a DynaRec code block to be ready. Availble in WowBox64.
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
* 1: Wait for a DynaRec code block to be ready. [Default]
### BOX64_DYNAREC_WEAKBARRIER
Tweak the memory barriers to reduce the performance impact by strong memory emualtion. Availble in WowBox64.
* 0: Use regular safe barrier.
* 1: Use weak barriers to have more performance boost. [Default]
* 2: All in 1, plus disabled the last write barriers.
### BOX64_DYNACACHE
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache write file to home folder by default, and can grow without limit.
* 0: Disable DynaCache.
* 1: Enable DynaCache.
* 2: Use DynaCache files if present, but do not generate new one. [Default]
### BOX64_DYNACACHE_FOLDER
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
* XXXX: Use folder XXXX for DynaCache files.
### BOX64_DYNACACHE_MIN
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
* XXXX: Set a minimum size of XXXX KB of Dynarec code to write the dynacache to disk. Will not be saved to disk else.
* 350: A size of 350 KB is the default value. [Default]
### BOX64_MMAP32
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
* 0: Do not force 32-bit memory mappings.
* 1: Force 32-bit memory mappings. [Default]
### BOX64_NODYNAREC
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter. Availble in WowBox64.
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynablock creation is forbidden (inclusive-exclusive).
### BOX64_RDTSC_1GHZ
Use hardware counter for rdtsc if available.
* 0: Use hardware counter for rdtsc opcode if available. [Default]
* 1: Use hardware counter for rdtsc if and only if precision is at least 1GHz.
## Libraries
### BOX64_ADDLIBS
@@ -213,7 +387,7 @@ Detect MonoBleedingEdge and apply conservative settings.
Enable or disable the generation of division-by-zero exception. Availble in WowBox64.
* 0: Do not generate thr division-by-zero exception. [Default]
* 0: Do not generate the division-by-zero exception. [Default]
* 1: Generate the division-by-zero exception.
### BOX64_DYNAREC_TBB
@@ -323,10 +497,10 @@ Expose SHAEXT (a.k.a. SHA_NI) capabilities.
### BOX64_SSE_FLUSHTO0
Behaviour of SSE Flush to 0 flags. Availble in WowBox64.
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags Availble in WowBox64.
* 0: Just track the flag. [Default]
* 1: Apply SSE Flush to 0 flag directly.
* 1: Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
### BOX64_SSE42
@@ -551,6 +725,8 @@ Same as BOX64_TRACE but starts the trace immediately.
* 0: Disable trace output. [Default]
* 1: Enable trace output. Trace starts before the initialization of dependencies.
* symbolname: Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
### BOX64_TRACE_START
@@ -576,152 +752,6 @@ Only available on box64 build with trace. Adds trace of all instructions execute
* symbolname: Enable trace output for `symbolname` only.
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive).
## Performance
### BOX64_DYNAREC
Enable/disable the Dynamic Recompiler (a.k.a DynaRec). This option defaults to 1 if it's enabled in the build options for a supported architecture. Availble in WowBox64.
* 0: Disable DynaRec.
* 1: Enable DynaRec.
### BOX64_DYNAREC_ALIGNED_ATOMICS
Generate aligned atomics only (only available on Arm64 for now). Availble in WowBox64.
* 0: Generate unaligned atomics handling code. [Default]
* 1: Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.
### BOX64_DYNAREC_BIGBLOCK
Enable building bigger DynaRec code blocks for better performance. Availble in WowBox64.
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
* 1: Build Dynarec block as big as possible.
* 2: Build Dynarec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
* 3: Build Dynarec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
### BOX64_DYNAREC_CALLRET
Optimize CALL/RET opcodes. Availble in WowBox64.
* 0: Do not optimize CALL/RET, use jump table. [Default]
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
### BOX64_DYNAREC_DF
Enable or disable the use of deferred flags. Availble in WowBox64.
* 0: Disable the use of deferred flags.
* 1: Enable the use of deferred flags. [Default]
### BOX64_DYNAREC_DIRTY
Allow continue running a block that is unprotected and potentially dirty.
* 0: Do not allow continue running a block that is unprotected and potentially dirty. [Default]
* 1: Allow continue to run a dynablock that write data in the same page as code. It can gets faster in loading time of some game but can also get unexpected crashes.
* 2: Will also, when it detect an HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but Block build from that page will always be tested. It can be faster that way (but soem SMC case might not be trapped).
### BOX64_DYNAREC_FASTNAN
Enable or disable fast NaN handling. Availble in WowBox64.
* 0: Precisely emulate the -NaN generation like on x86.
* 1: Do not do anything special with -NAN generation, faster. [Default]
### BOX64_DYNAREC_FASTROUND
Enable or disable fast rounding. Availble in WowBox64.
* 0: Generate float/double -> int rounding and use current rounding mode for float/double computation like on x86.
* 1: Do not do anything special with edge case rounding, faster. [Default]
* 2: Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
### BOX64_DYNAREC_FORWARD
Define max allowed forward value when building block. Availble in WowBox64.
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
### BOX64_DYNAREC_NATIVEFLAGS
Enable or disable the use of native flags. Availble in WowBox64.
* 0: Do not use native flags.
* 1: Use native flags when possible. [Default]
### BOX64_DYNAREC_PAUSE
Enable x86 PAUSE emulation, may help the performance of spinlocks. Availble in WowBox64.
* 0: Ignore x86 PAUSE instruction. [Default]
* 1: Use YIELD to emulate x86 PAUSE instruction.
* 2: Use WFI to emulate x86 PAUSE instruction.
* 3: Use SEVL+WFE to emulate x86 PAUSE instruction.
### BOX64_DYNAREC_SAFEFLAGS
Behaviour of flags emulation on CALL/RET opcodes. Availble in WowBox64.
* 0: Treat CALL/RET as if it never needs any flags.
* 1: Most of RETs will need flags, most of CALLs will not. [Default]
* 2: All CALL/RET will need flags.
### BOX64_DYNAREC_STRONGMEM
Enable the emulation of x86 strong memory model. Availble in WowBox64.
* 0: Do not try anything special. [Default]
* 1: Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
* 2: All in 1, plus memory barriers on SIMD instructions.
* 3: All in 2, plus more memory barriers on a regular basis.
### BOX64_DYNAREC_VOLATILE_METADATA
Use volatile metadata parsed from PE files, only valid for 64bit Windows games.
* 0: Do not use volatile metadata.
* 1: Use volatile metadata, which will guide Box64 for better strong memory emulation. [Default]
### BOX64_DYNAREC_WAIT
Wait or not for the building of a DynaRec code block to be ready. Availble in WowBox64.
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
* 1: Wait for a DynaRec code block to be ready. [Default]
### BOX64_DYNAREC_WEAKBARRIER
Tweak the memory barriers to reduce the performance impact by strong memory emualtion. Availble in WowBox64.
* 0: Use regular safe barrier.
* 1: Use weak barriers to have more performance boost. [Default]
* 2: All in 1, plus disabled the last write barriers.
### BOX64_MMAP32
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
* 0: Do not force 32-bit memory mappings.
* 1: Force 32-bit memory mappings. [Default]
### BOX64_NODYNAREC
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter. Availble in WowBox64.
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynablock creation is forbidden (inclusive-exclusive).
### BOX64_RDTSC_1GHZ
Use hardware counter for rdtsc if available.
* 0: Use hardware counter for rdtsc opcode if available. [Default]
* 1: Use hardware counter for rdtsc if and only if precision is at least 1GHz.
## Environment
### BOX64_ENV
+55
View File
@@ -0,0 +1,55 @@
# The guide on using Wine with Box64
<ins>W</ins>ine <ins>I</ins>s <ins>N</ins>ot an <ins>E</ins>mulator, but Box64 is. Box64 supports Wine in multiple ways. Before continuing reading, you should have a basic understanding of Wine.
## Wine variants
Wine ships in multiple forms:
1. **x86 Wine**
The executable architecture of **x86 Wine** is x86, and it runs x32 Windows executables.
**x86 Wine** requires a 32-bit environment (read 32-bit Linux libraries), which is usually available on x86_64 machines because of the nature of the architecture.
However, when you try to run it via an emulator on RISC architectures, the situation is a bit different. For Arm64, there is armhf, which is a 32-bit environment, and there is also Box86, which is made for armhf, so you can use Box86 to run **x86 Wine**.
However, for RISC-V 64, LoongArch64, and many newer Arm64 cores, a 32-bit environment is not available. Box64 introduced a new mode called Box32, which can be enabled at compile time via a CMake option `BOX32`. It essentially emulates a 32-bit environment using the 64-bit environment, so it can be used to run **x86 Wine**. But be aware that Box32 is still highly experimental and unstable.
2. **x86_64 Wine**
The executable architecture of **x86_64 Wine** is x86_64, and it runs x64 Windows executables.
It can be used with Box64. Note that **x86_64 Wine** usually ships with **x86 Wine** included. So you can use a combination of Box86 + Box64 or Box64 alone with Box32 enabled to run both x32 and x64 executables seamlessly.
3. **x86_64 Wine WOW64**
The executable architecture of **x86_64 Wine WOW64** is x86_64, and it runs both x32 and x64 Windows executables.
What's great about **x86_64 Wine WOW64** is that it does not require a 32-bit environment for x32 Windows executable, as the 32-bit environment emulation is taken care of by Wine WOW64 itself.
That means you can just use Box64 (without Box32) to run x32 Windows executables. However, the downside is that the performance of WineD3D is pretty bad for 32-bit (use DXVK!).
4. **Arm64 Wine WOW64**
The executable architecture of **Arm64 Wine WOW64** is Arm64, and it runs
x32, x64, Arm32, Arm64 Windows executables.
However, to run x32 and x64 ones, a cpu.dll is required, known as the
WOW64 (for 32-bit) and Arm64EC (for 64-bit).
Box64 now supports 32-bit WOW64 DLL. You can have it compiled by enabling the `WOW64` CMake option. And we plan to support Arm64EC in the future.
## Wine installation
For x86 Wines, there are plenty of places to download, to name a few:
- https://github.com/Kron4ek/Wine-Builds (Wine \[WOW64\])
- https://github.com/GloriousEggroll/proton-ge-custom (Proton, known as the Valve-optimized Wine)
After the download, just add the `bin` folder to your path in any way you like; Wine should work with Box64 just fine.
To install components like DXVK, d3dcompiler_xx, or cjkfonts, it's recommended to use Winetricks: https://github.com/Winetricks/winetricks
For Arm64 Wines, use of Hangover is recommended: https://github.com/AndreRH/hangover.
-177
View File
@@ -1,177 +0,0 @@
# Installing Wine64
Running Wine64/Wine with Box64/Box86 allows x64/x86 Windows programs to run on 64-bit ARM Linux devices.
- Box64 needs `wine-amd64` to be installed **manually** on ARM64 (aarch64) devices. This will run 64-bit Windows programs (aka x86_64).
- Box86 needs `wine-i386` to be installed **manually** on ARM32 (armhf) devices (or on ARM64 with multiarch or chroot). This will run 32-bit Windows programs (aka x86).
- _Note that `wine:arm64` and `wine:armhf` will not work with Box64/Box86. Your device's package manager might try to install those if you ask it to install wine._
See installation steps below (in the [Examples](#examples) section).
## Overview
The general procedure for installing Wine64 & Wine for Box64 & Box86 is to...
- Download all the install 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 (often `~/wine/` by default)
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries.
- Boot wine to create a new wineprefix.
- Download winetricks (which is just a complicated bash script), make it executable, then copy it to `/usr/local/bin`.
## Examples
### Installing Wine64 & Wine for Box64 & Box86 on Raspberry Pi OS from WineHQ .deb files
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/)_
This install method allows you to install different versions of Wine64/Wine. You may install any version/branch of Wine that you wish.
```
# NOTE: Can only run on aarch64 (since box64 can only run on aarch64)
# box64 runs wine-amd64, box86 runs wine-i386.
### User-defined Wine version variables ################
# - Replace the variables below with your system's info.
# - Note that we need the amd64 version for Box64 even though we're installing it on our ARM processor.
# - Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.
# - Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
local branch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386)
local version="7.1" #example: "7.1"
local id="debian" #example: debian, ubuntu
local dist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, ${VERSION_CODENAME}, etc
local tag="-1" #example: -1 (some wine .deb files have -1 tag on the end and some don't)
########################################################
# Clean up any old wine instances
wineserver -k # stop any old wine installations from running
rm -rf ~/.cache/wine # remove any old wine-mono/wine-gecko install files
rm -rf ~/.local/share/applications/wine # remove any old program shortcuts
# Backup any old wine installs
rm -rf ~/wine-old 2>/dev/null; mv ~/wine ~/wine-old 2>/dev/null
rm -rf ~/.wine-old 2>/dev/null; mv ~/.wine ~/.wine-old 2>/dev/null
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old 2>/dev/null
sudo mv /usr/local/bin/wine64 /usr/local/bin/wine-old 2>/dev/null
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old 2>/dev/null
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old 2>/dev/null
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old 2>/dev/null
# Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
LNKA="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-amd64/" #amd64-wine links
DEB_A1="wine-${branch}-amd64_${version}~${dist}${tag}_amd64.deb" #wine64 main bin
DEB_A2="wine-${branch}_${version}~${dist}${tag}_amd64.deb" #wine64 support files (required for wine64 / can work alongside wine_i386 main bin)
#DEB_A3="winehq-${branch}_${version}~${dist}${tag}_amd64.deb" #shortcuts & docs
LNKB="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-i386/" #i386-wine links
DEB_B1="wine-${branch}-i386_${version}~${dist}${tag}_i386.deb" #wine_i386 main bin
DEB_B2="wine-${branch}_${version}~${dist}${tag}_i386.deb" #wine_i386 support files (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
#DEB_B3="winehq-${branch}_${version}~${dist}${tag}_i386.deb" #shortcuts & docs
# Install amd64-wine (64-bit) alongside i386-wine (32-bit)
echo -e "Downloading wine . . ."
wget -q ${LNKA}${DEB_A1}
wget -q ${LNKA}${DEB_A2}
wget -q ${LNKB}${DEB_B1}
echo -e "Extracting wine . . ."
dpkg-deb -x ${DEB_A1} wine-installer
dpkg-deb -x ${DEB_A2} wine-installer
dpkg-deb -x ${DEB_B1} wine-installer
echo -e "Installing wine . . ."
mv wine-installer/opt/wine* ~/wine
# Download wine dependencies
# - these packages are needed for running box86/wine-i386 on a 64-bit RPiOS via multiarch
sudo dpkg --add-architecture armhf && sudo apt-get update # enable multi-arch
sudo apt-get install -y libasound2:armhf libc6:armhf libglib2.0-0:armhf libgphoto2-6:armhf libgphoto2-port12:armhf \
libgstreamer-plugins-base1.0-0:armhf libgstreamer1.0-0:armhf libldap-2.4-2:armhf libopenal1:armhf libpcap0.8:armhf \
libpulse0:armhf libsane1:armhf libudev1:armhf libusb-1.0-0:armhf libvkd3d1:armhf libx11-6:armhf libxext6:armhf \
libasound2-plugins:armhf ocl-icd-libopencl1:armhf libncurses6:armhf libncurses5:armhf libcap2-bin:armhf libcups2:armhf \
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
libxrender1:armhf libxxf86vm1 libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
# This list found by downloading...
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel_7.1~bullseye-1_i386.deb
# then `dpkg-deb -I package.deb`. Read output, add `:armhf` to packages in dep list, then try installing them on Pi aarch64.
# - these packages are needed for running box64/wine-amd64 on RPiOS (box64 only runs on 64-bit OS's)
sudo apt-get install -y libasound2:arm64 libc6:arm64 libglib2.0-0:arm64 libgphoto2-6:arm64 libgphoto2-port12:arm64 \
libgstreamer-plugins-base1.0-0:arm64 libgstreamer1.0-0:arm64 libldap-2.4-2:arm64 libopenal1:arm64 libpcap0.8:arm64 \
libpulse0:arm64 libsane1:arm64 libudev1:arm64 libunwind8:arm64 libusb-1.0-0:arm64 libvkd3d1:arm64 libx11-6:arm64 libxext6:arm64 \
ocl-icd-libopencl1:arm64 libasound2-plugins:arm64 libncurses6:arm64 libncurses5:arm64 libcups2:arm64 \
libdbus-1-3:arm64 libfontconfig1:arm64 libfreetype6:arm64 libglu1-mesa:arm64 libgnutls30:arm64 \
libgssapi-krb5-2:arm64 libjpeg62-turbo:arm64 libkrb5-3:arm64 libodbc1:arm64 libosmesa6:arm64 libsdl2-2.0-0:arm64 libv4l-0:arm64 \
libxcomposite1:arm64 libxcursor1:arm64 libxfixes3:arm64 libxi6:arm64 libxinerama1:arm64 libxrandr2:arm64 \
libxrender1:arm64 libxxf86vm1:arm64 libc6:arm64 libcap2-bin:arm64
# This list found by downloading...
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel_7.1~bullseye-1_amd64.deb
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel-amd64_7.1~bullseye-1_amd64.deb
# then `dpkg-deb -I package.deb`. Read output, add `:arm64` to packages in dep list, then try installing them on Pi aarch64.
# These packages are needed for running wine-staging on RPiOS (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
# Install symlinks
sudo ln -s ~/wine/bin/wine /usr/local/bin/wine
sudo ln -s ~/wine/bin/wine64 /usr/local/bin/wine64
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/wine64 /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
```
## 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
Creating a 64-bit wineprefix:
`wine64 wineboot` or `wine wineboot` (wineprefix is created in `~/.wine/`)
`WINEPREFIX="$HOME/prefix64" wine wineboot` (wineprefix is created in `~/prefix64/`) _Note: You will need to invoke `WINEPREFIX="$HOME/prefix64"` before every command to use this wineprefix._
Creating a 32-bit wineprefix:
`WINEARCH=win32 wine wineboot` (wineprefix is created in `~/.wine/`)
Fore-quitting wine:
`wineserver -k`
Running Wine Configuration:
`winecfg`
Using winetricks:
`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._
Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will cause winetricks to crash.
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
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.
+41 -7
View File
@@ -150,7 +150,7 @@ Enable/disable the Dynamic Recompiler (a.k.a DynaRec). This option defaults to 1
Generate aligned atomics only (only available on Arm64 for now). Availble in WowBox64.
* 0 : Generate unaligned atomics handling code. [Default]
* 1 : Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.
* 1 : Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on unaligned data addresses.
=item B<BOX64_DYNAREC_BIGBLOCK> =I<0|1|2|3>
@@ -197,11 +197,19 @@ Allow continue running a block that is unprotected and potentially dirty.
* 2 : Will also, when it detect an HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but Block build from that page will always be tested. It can be faster that way (but soem SMC case might not be trapped).
=item B<BOX64_DYNAREC_NOHOTPAGE> =I<0|1>
Disable detection of hot page (where code is executed and data written at the same time).
* 0 : Detect hot page [Default]
* 1 : Do not detect hot page
=item B<BOX64_DYNAREC_DIV0> =I<0|1>
Enable or disable the generation of division-by-zero exception. Availble in WowBox64.
* 0 : Do not generate thr division-by-zero exception. [Default]
* 0 : Do not generate the division-by-zero exception. [Default]
* 1 : Generate the division-by-zero exception.
@@ -305,11 +313,11 @@ Generate map file for Linux perf tool.
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
Behaviour of flags emulation on CALL/RET opcodes. Availble in WowBox64.
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Availble in WowBox64.
* 0 : Treat CALL/RET as if it never needs any flags.
* 1 : Most of RETs will need flags, most of CALLs will not. [Default]
* 2 : All CALL/RET will need flags.
* 2 : All CALL/RET will need flags. All edge cases are also handled.
=item B<BOX64_DYNAREC_STRONGMEM> =I<0|1|2|3>
@@ -381,6 +389,30 @@ Force the use of float/double for x87 emulation. Availble in WowBox64.
* 2 : Check Precision Control low precision on x87 emulation.
=item B<BOX64_DYNACACHE> =I<0|1|2>
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache write file to home folder by default, and can grow without limit.
* 0 : Disable DynaCache.
* 1 : Enable DynaCache.
* 2 : Use DynaCache files if present, but do not generate new one. [Default]
=item B<BOX64_DYNACACHE_FOLDER> =I<XXXX>
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
* XXXX : Use folder XXXX for DynaCache files.
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|350>
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
* XXXX : Set a minimum size of XXXX KB of Dynarec code to write the dynacache to disk. Will not be saved to disk else.
* 350 : A size of 350 KB is the default value. [Default]
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
Force the use of emulated libraries.
@@ -694,10 +726,10 @@ Always show SIGSEGV signal detailes.
=item B<BOX64_SSE_FLUSHTO0> =I<0|1>
Behaviour of SSE Flush to 0 flags. Availble in WowBox64.
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags Availble in WowBox64.
* 0 : Just track the flag. [Default]
* 1 : Apply SSE Flush to 0 flag directly.
* 1 : Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
=item B<BOX64_SSE42> =I<0|1>
@@ -741,12 +773,14 @@ Send all log and trace to a file instead of `stdout`.
* stderr : Send all log and trace to `stderr`.
=item B<BOX64_TRACE_INIT> =I<0|1>
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
Same as BOX64_TRACE but starts the trace immediately.
* 0 : Disable trace output. [Default]
* 1 : Enable trace output. Trace starts before the initialization of dependencies.
* symbolname : Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
=item B<BOX64_TRACE_START> =I<0|1|XXXX>
+3 -1
View File
@@ -63,7 +63,9 @@ This configuration will apply the specified settings application-wide to any exe
for entry in data:
categories[entry["category"]].append(entry)
for category, entries in categories.items():
# Put "Performance" at the top
sorted_categories = sorted(categories.items(), key=lambda x: x[0] != "Performance")
for category, entries in sorted_categories:
md_file.write(f"## {category}\n\n")
for entry in entries:
md_file.write(f"### {entry['name']}\n\n{entry['description']}{' Availble in WowBox64.' if entry['wine'] else ''}\n\n")
+88 -6
View File
@@ -228,7 +228,7 @@
},
{
"key": "1",
"description": "Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.",
"description": "Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on unaligned data addresses.",
"default": false
}
]
@@ -343,6 +343,24 @@
}
]
},
{
"name": "BOX64_DYNAREC_NOHOTPAGE",
"description": "Disable detection of hot page (where code is executed and data written at the same time).",
"category": "Performance",
"wine": false,
"options": [
{
"key": "0",
"description": "Detect hot page",
"default": true
},
{
"key": "1",
"description": "Do not detect hot page",
"default": false
}
]
},
{
"name": "BOX64_DYNAREC_DIV0",
"description": "Enable or disable the generation of division-by-zero exception.",
@@ -351,7 +369,7 @@
"options": [
{
"key": "0",
"description": "Do not generate thr division-by-zero exception.",
"description": "Do not generate the division-by-zero exception.",
"default": true
},
{
@@ -611,7 +629,7 @@
},
{
"name": "BOX64_DYNAREC_SAFEFLAGS",
"description": "Behaviour of flags emulation on CALL/RET opcodes.",
"description": "Behaviour of flags emulation on CALL/RET opcodes and other edge cases.",
"category": "Performance",
"wine": true,
"options": [
@@ -627,7 +645,7 @@
},
{
"key": "2",
"description": "All CALL/RET will need flags.",
"description": "All CALL/RET will need flags. All edge cases are also handled.",
"default": false
}
]
@@ -801,6 +819,60 @@
}
]
},
{
"name": "BOX64_DYNACACHE",
"description": "Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache write file to home folder by default, and can grow without limit.",
"category": "Performance",
"wine": false,
"options": [
{
"key": "0",
"description": "Disable DynaCache.",
"default": false
},
{
"key": "1",
"description": "Enable DynaCache.",
"default": false
},
{
"key": "2",
"description": "Use DynaCache files if present, but do not generate new one.",
"default": true
}
]
},
{
"name": "BOX64_DYNACACHE_FOLDER",
"description": "Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.",
"category": "Performance",
"wine": false,
"options": [
{
"key": "XXXX",
"description": "Use folder XXXX for DynaCache files.",
"default": false
}
]
},
{
"name": "BOX64_DYNACACHE_MIN",
"description": "Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB",
"category": "Performance",
"wine": false,
"options": [
{
"key": "XXXX",
"description": "Set a minimum size of XXXX KB of Dynarec code to write the dynacache to disk. Will not be saved to disk else.",
"default": false
},
{
"key": "350",
"description": "A size of 350 KB is the default value.",
"default": true
}
]
},
{
"name": "BOX64_EMULATED_LIBS",
"description": "Force the use of emulated libraries.",
@@ -1500,7 +1572,7 @@
},
{
"name": "BOX64_SSE_FLUSHTO0",
"description": "Behaviour of SSE Flush to 0 flags.",
"description": "Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags",
"category": "Compatibility",
"wine": true,
"options": [
@@ -1511,7 +1583,7 @@
},
{
"key": "1",
"description": "Apply SSE Flush to 0 flag directly.",
"description": "Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)",
"default": false
}
]
@@ -1626,6 +1698,16 @@
"key": "1",
"description": "Enable trace output. Trace starts before the initialization of dependencies.",
"default": false
},
{
"key": "symbolname",
"description": "Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.",
"default": false
},
{
"key": "0xXXXXXXX-0xYYYYYYY",
"description": "Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.",
"default": false
}
]
},
+1
View File
@@ -21,6 +21,7 @@ cd ../ && rm -rf ./tmp/
echo '#!/bin/bash
export STEAMOS=1
export STEAM_RUNTIME=1
export PROTON_USE_WOW64=1
export DBUS_FATAL_WARNINGS=0
~/steam/bin/steam $@' > steam
+3 -11
View File
@@ -149,10 +149,6 @@ static void atfork_child_box64context(void)
void freeCycleLog(box64context_t* ctx)
{
if(BOX64ENV(rolling_log)) {
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
box_free(ctx->log_call[i]);
box_free(ctx->log_ret[i]);
}
box_free(ctx->log_call);
box_free(ctx->log_ret);
ctx->log_call = NULL;
@@ -162,12 +158,8 @@ void freeCycleLog(box64context_t* ctx)
void initCycleLog(box64context_t* context)
{
if(context && BOX64ENV(rolling_log)) {
context->log_call = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
context->log_ret = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
context->log_call[i] = (char*)box_calloc(256, 1);
context->log_ret[i] = (char*)box_calloc(128, 1);
}
context->log_call = (char*)box_calloc(BOX64ENV(rolling_log), 256*sizeof(char));
context->log_ret = (char*)box_calloc(BOX64ENV(rolling_log), 128*sizeof(char));
}
}
@@ -357,7 +349,7 @@ void FreeBox64Context(box64context_t** context)
FreeMapSymbols(&ctx->uniques);
#ifdef DYNAREC
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, righter=%d\n", ctx->max_db_size, rb_get_righter(ctx->db_sizes));
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, rightmost=%d\n", ctx->max_db_size, rb_get_rightmost(ctx->db_sizes));
rbtree_delete(ctx->db_sizes);
#endif
+1 -1
View File
@@ -3,6 +3,6 @@
#define BOX64_MAJOR 0
#define BOX64_MINOR 3
#define BOX64_REVISION 6
#define BOX64_REVISION 8
#endif //__BOX64_VERSION_H_
+122 -290
View File
@@ -15,11 +15,10 @@
#include <sys/stat.h>
#include <stdarg.h>
#include <ctype.h>
#ifdef DYNAREC
#ifdef ARM64
#include <linux/auxvec.h>
#include <asm/hwcap.h>
#ifdef BOX32
#include <sys/personality.h>
#endif
#ifdef DYNAREC
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -49,6 +48,7 @@
#include "env.h"
#include "cleanup.h"
#include "freq.h"
#include "hostext.h"
box64context_t *my_context = NULL;
extern box64env_t box64env;
@@ -59,6 +59,7 @@ int box64_stdout_no_w = 0;
uintptr_t box64_pagesize;
path_collection_t box64_addlibs = {0};
int box64_is32bits = 0;
int box64_isAddressSpace32 = 0;
int box64_rdtsc = 0;
uint8_t box64_rdtsc_shift = 0;
int box64_mapclean = 0;
@@ -75,43 +76,7 @@ uint32_t default_fs = 0;
int box64_isglibc234 = 0;
#ifdef DYNAREC
#ifdef ARM64
int arm64_asimd = 0;
int arm64_aes = 0;
int arm64_pmull = 0;
int arm64_crc32 = 0;
int arm64_atomics = 0;
int arm64_sha1 = 0;
int arm64_sha2 = 0;
int arm64_uscat = 0;
int arm64_flagm = 0;
int arm64_flagm2 = 0;
int arm64_frintts = 0;
int arm64_afp = 0;
int arm64_rndr = 0;
#elif defined(RV64)
int rv64_zba = 0;
int rv64_zbb = 0;
int rv64_zbc = 0;
int rv64_zbs = 0;
int rv64_vector = 0; // rvv 1.0 or xtheadvector
int rv64_xtheadvector = 0;
int rv64_vlen = 0;
int rv64_xtheadba = 0;
int rv64_xtheadbb = 0;
int rv64_xtheadbs = 0;
int rv64_xtheadcondmov = 0;
int rv64_xtheadmemidx = 0;
int rv64_xtheadmempair = 0;
int rv64_xtheadfmemidx = 0;
int rv64_xtheadmac = 0;
int rv64_xtheadfmv = 0;
#elif defined(LA64)
int la64_lbt = 0;
int la64_lam_bh = 0;
int la64_lamcas = 0;
int la64_scq = 0;
#endif
cpu_ext_t cpuext = {0};
#endif
int box64_wine = 0;
@@ -125,9 +90,10 @@ char* trace_func = NULL;
FILE* ftrace = NULL;
char* ftrace_name = NULL;
int ftrace_has_pid = 0;
int ftrace_opened = 0;
void openFTrace(int reopen)
static void openFTrace(void)
{
const char* p = BOX64ENV(trace_file);
#ifndef MAX_PATH
@@ -135,251 +101,63 @@ void openFTrace(int reopen)
#endif
char tmp[MAX_PATH];
char tmp2[MAX_PATH];
int append=0;
if(p && strlen(p) && p[strlen(p)-1]=='+') {
int append = 0;
if (ftrace_name) box_free(ftrace_name);
ftrace_name = NULL;
if (p && strlen(p) && p[strlen(p) - 1] == '+') {
strncpy(tmp2, p, sizeof(tmp2));
tmp2[strlen(p)-1]='\0';
p = tmp2;
append = 1;
}
if (reopen) {
p = ftrace_name;
append = 1;
} else {
if (p && strstr(p, "\%pid")) {
int next = 0;
do {
strcpy(tmp, p);
char* c = strstr(tmp, "%pid");
*c = 0; // cut
char pid[16];
if (next)
sprintf(pid, "%d-%d", GetTID(), next);
else
sprintf(pid, "%d", GetTID());
strcat(tmp, pid);
c = strstr(p, "\%pid") + strlen("\%pid");
strcat(tmp, c);
++next;
} while (FileExist(tmp, IS_FILE) && !append);
p = tmp;
ftrace_has_pid = 1;
}
if (ftrace_name)
box_free(ftrace_name);
ftrace_name = NULL;
}
if(p) {
if(!strcmp(p, "stderr"))
ftrace = stderr;
else {
if(append)
ftrace = fopen(p, "a");
if (!p || ftrace_opened) return;
ftrace_opened = 1;
if (strstr(p, "\%pid")) {
int next = 0;
do {
strcpy(tmp, p);
char* c = strstr(tmp, "%pid");
*c = 0; // cut
char pid[16];
if (next)
sprintf(pid, "%d-%d", GetTID(), next);
else
ftrace = fopen(p, "w");
if(!ftrace) {
ftrace = stdout;
printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s)\n", p, strerror(errno));
} else {
if (!reopen) ftrace_name = box_strdup(p);
/*fclose(ftrace);
ftrace = NULL;*/
if (!BOX64ENV(nobanner)) {
printf("BOX64 Trace %s to \"%s\"\n", append?"appended":"redirected", p);
box64_stdout_no_w = 1;
}
PrintBox64Version(0);
sprintf(pid, "%d", GetTID());
strcat(tmp, pid);
c = strstr(p, "\%pid") + strlen("\%pid");
strcat(tmp, c);
++next;
} while (FileExist(tmp, IS_FILE) && !append);
p = tmp;
}
if (!strcmp(p, "stderr"))
ftrace = stderr;
else {
if (append)
ftrace = fopen(p, "a");
else
ftrace = fopen(p, "w");
if (!ftrace) {
ftrace = stdout;
printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s), fallback to stdout\n", p, strerror(errno));
} else {
ftrace_name = box_strdup(p);
if (!BOX64ENV(nobanner)) {
printf("[BOX64] Trace %s to \"%s\" (set BOX64_NOBANNER=1 to suppress this log)\n", append ? "appended" : "redirected", p);
box64_stdout_no_w = 1;
}
PrintBox64Version(0);
}
}
}
void my_prepare_fork()
{
if (ftrace_has_pid && ftrace && (ftrace != stdout) && (ftrace != stderr)) {
printf_log(LOG_INFO, "%04d|Closed trace file of %s at prepare\n", GetTID(), GetLastApplyEntryName());
fclose(ftrace);
}
}
void my_parent_fork()
{
if (ftrace_has_pid) {
openFTrace(1);
printf_log(LOG_INFO, "%04d|Reopened trace file of %s at parent\n", GetTID(), GetLastApplyEntryName());
}
}
void my_child_fork()
{
if (ftrace_has_pid) {
openFTrace(0);
printf_log(LOG_INFO, "%04d|Created trace file of %s at child\n", GetTID(), GetLastApplyEntryName());
}
}
const char* getCpuName();
int getNCpu();
#ifdef DYNAREC
void GatherDynarecExtensions()
{
#ifdef ARM64
unsigned long hwcap = real_getauxval(AT_HWCAP);
if(!hwcap)
hwcap = HWCAP_ASIMD;
// first, check all needed extensions, lif half, edsp and fastmult
if((hwcap&HWCAP_ASIMD) == 0) {
printf_log(LOG_INFO, "Missing ASMID cpu support, disabling Dynarec\n");
SET_BOX64ENV(dynarec, 0);
return;
}
if(hwcap&HWCAP_CRC32)
arm64_crc32 = 1;
if(hwcap&HWCAP_PMULL)
arm64_pmull = 1;
if(hwcap&HWCAP_AES)
arm64_aes = 1;
if(hwcap&HWCAP_ATOMICS)
arm64_atomics = 1;
#ifdef HWCAP_SHA1
if(hwcap&HWCAP_SHA1)
arm64_sha1 = 1;
#endif
#ifdef HWCAP_SHA2
if(hwcap&HWCAP_SHA2)
arm64_sha2 = 1;
#endif
#ifdef HWCAP_USCAT
if(hwcap&HWCAP_USCAT)
arm64_uscat = 1;
#endif
#ifdef HWCAP_FLAGM
if(hwcap&HWCAP_FLAGM)
arm64_flagm = 1;
#endif
unsigned long hwcap2 = real_getauxval(AT_HWCAP2);
#ifdef HWCAP2_FLAGM2
if(hwcap2&HWCAP2_FLAGM2)
arm64_flagm2 = 1;
#endif
#ifdef HWCAP2_FRINT
if(hwcap2&HWCAP2_FRINT)
arm64_frintts = 1;
#endif
#ifdef HWCAP2_AFP
if(hwcap2&HWCAP2_AFP)
arm64_afp = 1;
#endif
#ifdef HWCAP2_RNG
if(hwcap2&HWCAP2_RNG)
arm64_rndr = 1;
#endif
printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD");
if(arm64_aes)
printf_log_prefix(0, LOG_INFO, " AES");
if(arm64_crc32)
printf_log_prefix(0, LOG_INFO, " CRC32");
if(arm64_pmull)
printf_log_prefix(0, LOG_INFO, " PMULL");
if(arm64_atomics)
printf_log_prefix(0, LOG_INFO, " ATOMICS");
if(arm64_sha1)
printf_log_prefix(0, LOG_INFO, " SHA1");
if(arm64_sha2)
printf_log_prefix(0, LOG_INFO, " SHA2");
if(arm64_uscat)
printf_log_prefix(0, LOG_INFO, " USCAT");
if(arm64_flagm)
printf_log_prefix(0, LOG_INFO, " FLAGM");
if(arm64_flagm2)
printf_log_prefix(0, LOG_INFO, " FLAGM2");
if(arm64_frintts)
printf_log_prefix(0, LOG_INFO, " FRINT");
if(arm64_afp)
printf_log_prefix(0, LOG_INFO, " AFP");
if(arm64_rndr)
printf_log_prefix(0, LOG_INFO, " RNDR");
printf_log_prefix(0, LOG_INFO, "\n");
#elif defined(LA64)
printf_log(LOG_INFO, "Dynarec for LoongArch ");
char* p = getenv("BOX64_DYNAREC_LA64NOEXT");
if(p == NULL || p[0] == '0') {
uint32_t cpucfg2 = 0, idx = 2;
asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx));
if (((cpucfg2 >> 6) & 0b11) == 3) {
printf_log_prefix(0, LOG_INFO, "with extension LSX LASX");
} else {
printf_log(LOG_INFO, "\nMissing LSX and/or LASX extension support, disabling Dynarec\n");
SET_BOX64ENV(dynarec, 0);
return;
}
if (la64_lbt = ((cpucfg2 >> 18) & 0b1))
printf_log_prefix(0, LOG_INFO, " LBT_X86");
if ((la64_lam_bh = (cpucfg2 >> 27) & 0b1))
printf_log_prefix(0, LOG_INFO, " LAM_BH");
if ((la64_lamcas = (cpucfg2 >> 28) & 0b1))
printf_log_prefix(0, LOG_INFO, " LAMCAS");
if ((la64_scq = (cpucfg2 >> 30) & 0b1))
printf_log_prefix(0, LOG_INFO, " SCQ");
}
printf_log_prefix(0, LOG_INFO, "\n");
#elif defined(RV64)
void RV64_Detect_Function();
// private env. variable for the developer ;)
char *p = getenv("BOX64_DYNAREC_RV64NOEXT");
if(p == NULL || strcasecmp(p, "1")) {
RV64_Detect_Function();
if (p) {
p = strtok(p, ",");
while (p) {
if (!strcasecmp(p, "zba")) rv64_zba = 0;
if (!strcasecmp(p, "zbb")) rv64_zbb = 0;
if (!strcasecmp(p, "zbc")) rv64_zbc = 0;
if (!strcasecmp(p, "zbs")) rv64_zbs = 0;
if (!strcasecmp(p, "vector")) {
rv64_vector = 0;
rv64_xtheadvector = 0;
}
if (!strcasecmp(p, "xtheadba")) rv64_xtheadba = 0;
if (!strcasecmp(p, "xtheadbb")) rv64_xtheadbb = 0;
if (!strcasecmp(p, "xtheadbs")) rv64_xtheadbs = 0;
if (!strcasecmp(p, "xtheadmemidx")) rv64_xtheadmemidx = 0;
// if (!strcasecmp(p, "xtheadfmemidx")) rv64_xtheadfmemidx = 0;
// if (!strcasecmp(p, "xtheadmac")) rv64_xtheadmac = 0;
// if (!strcasecmp(p, "xtheadfmv")) rv64_xtheadfmv = 0;
if (!strcasecmp(p, "xtheadmempair")) rv64_xtheadmempair = 0;
if (!strcasecmp(p, "xtheadcondmov")) rv64_xtheadcondmov = 0;
p = strtok(NULL, ",");
}
}
}
printf_log(LOG_INFO, "Dynarec for rv64g");
if (rv64_vector && !rv64_xtheadvector) printf_log_prefix(0, LOG_INFO, "v");
if (rv64_zba) printf_log_prefix(0, LOG_INFO, "_zba");
if (rv64_zbb) printf_log_prefix(0, LOG_INFO, "_zbb");
if (rv64_zbc) printf_log_prefix(0, LOG_INFO, "_zbc");
if (rv64_zbs) printf_log_prefix(0, LOG_INFO, "_zbs");
if (rv64_vector && !rv64_xtheadvector) printf_log_prefix(0, LOG_INFO, "_zvl%d", rv64_vlen);
if (rv64_xtheadba) printf_log_prefix(0, LOG_INFO, "_xtheadba");
if (rv64_xtheadbb) printf_log_prefix(0, LOG_INFO, "_xtheadbb");
if (rv64_xtheadbs) printf_log_prefix(0, LOG_INFO, "_xtheadbs");
if (rv64_xtheadmempair) printf_log_prefix(0, LOG_INFO, "_xtheadmempair");
if (rv64_xtheadcondmov) printf_log_prefix(0, LOG_INFO, "_xtheadcondmov");
if (rv64_xtheadmemidx) printf_log_prefix(0, LOG_INFO, "_xtheadmemidx");
// Disable the display since these are only detected but never used.
// if(rv64_xtheadfmemidx) printf_log_prefix(0, LOG_INFO, " xtheadfmemidx");
// if(rv64_xtheadmac) printf_log_prefix(0, LOG_INFO, " xtheadmac");
// if(rv64_xtheadfmv) printf_log_prefix(0, LOG_INFO, " xtheadfmv");
if (rv64_xtheadvector) printf_log_prefix(0, LOG_INFO, "_xthvector");
printf_log_prefix(0, LOG_INFO, "\n");
#else
#error Unsupported architecture
#endif
}
#endif
int getNCpuUnmasked();
void computeRDTSC()
{
@@ -423,7 +201,7 @@ void computeRDTSC()
static void displayMiscInfo()
{
openFTrace(0);
openFTrace();
if ((BOX64ENV(nobanner) || BOX64ENV(log)) && ftrace==stdout)
box64_stdout_no_w = 1;
@@ -434,18 +212,17 @@ static void displayMiscInfo()
char* p;
// grab pagesize
box64_pagesize = sysconf(_SC_PAGESIZE);
if(!box64_pagesize)
box64_pagesize = 4096;
#ifdef DYNAREC
// grab cpu extensions for dynarec usage
GatherDynarecExtensions();
if (DetectHostCpuFeatures())
PrintHostCpuFeatures();
else {
printf_log(LOG_INFO, "Minimum CPU requirements not met, disabling DynaRec\n");
SET_BOX64ENV(dynarec, 0);
}
#endif
// grab ncpu and cpu name
int ncpu = getNCpu();
int ncpu = getNCpuUnmasked();
const char* cpuname = getCpuName();
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd\n", cpuname, ncpu, ncpu > 1 ? "s" : "", box64_pagesize);
@@ -551,6 +328,8 @@ void PrintHelp() {
PrintfFtrace(0, " '-v'|'--version' to print box64 version and quit\n");
PrintfFtrace(0, " '-h'|'--help' to print this and quit\n");
PrintfFtrace(0, " '-k'|'--kill-all' to kill all box64 instances\n");
PrintfFtrace(0, " '--dynacache-list' to list of DynaCache file and their validity\n");
PrintfFtrace(0, " '--dynacache-clean' to remove invalide DynaCache files\n");
}
void KillAllInstances()
@@ -586,7 +365,7 @@ void KillAllInstances()
snprintf(self_name_with_deleted, sizeof(self_name_with_deleted), "%s (deleted)", self_name);
const pid_t self = getpid();
while (entry = readdir(proc_dir)) {
while ((entry = readdir(proc_dir))) {
const pid_t pid = atoi(entry->d_name);
if (!pid || pid == self) continue;
@@ -734,6 +513,8 @@ void setupTraceInit()
uintptr_t s_trace_start=0, s_trace_end=0;
if (strcmp(p, "1")==0)
SetTraceEmu(0, 0);
else if (strcmp(p, "0")==0)
;
else if (strchr(p,'-')) {
if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) {
if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2)
@@ -803,6 +584,8 @@ void setupTrace()
uintptr_t s_trace_start=0, s_trace_end=0;
if (strcmp(p, "1")==0)
SetTraceEmu(0, 0);
else if (strcmp(p, "0")==0)
;
else if (strchr(p,'-')) {
if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) {
if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2)
@@ -851,6 +634,7 @@ void endBox64()
if(!my_context || box64_quit)
return;
SerializeAllMapping(); // just to be safe
// then call all the fini
dynarec_log(LOG_DEBUG, "endBox64() called\n");
box64_quit = 1;
@@ -874,6 +658,7 @@ void endBox64()
#ifndef STATICBUILD
endMallocHook();
#endif
SerializeAllMapping(); // to be safe
FreeBox64Context(&my_context);
#ifdef DYNAREC
// disable dynarec now
@@ -951,6 +736,11 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
ftrace = stdout;
// grab pagesize
box64_pagesize = sysconf(_SC_PAGESIZE);
if(!box64_pagesize)
box64_pagesize = 4096;
LoadEnvVariables();
InitializeEnvFiles();
@@ -970,6 +760,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
KillAllInstances();
exit(0);
}
if(!strcmp(prog, "--dynacache-list")) {
DynaCacheList(argv[nextarg+1]);
exit(0);
}
if(!strcmp(prog, "--dynacache-clean")) {
DynaCacheClean();
exit(0);
}
// other options?
if(!strcmp(prog, "--")) {
prog = argv[++nextarg];
@@ -1204,6 +1002,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
box64_zoom = 1;
}
// special case for bash
int setup_bash_rcfile = 0;
if (!strcmp(box64_guest_name, "bash") || !strcmp(box64_guest_name, "box64-bash")) {
printf_log(LOG_INFO, "Bash detected, disabling banner\n");
if (!BOX64ENV(nobanner)) {
@@ -1212,8 +1011,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
}
if (!bashpath) {
bashpath = (char*)prog;
SET_BOX64ENV(bash, (char*)prog);
setenv("BOX64_BASH", prog, 1);
}
setup_bash_rcfile = 1;
}
if(!bashpath)
bashpath = ResolveFile("box64-bash", &my_context->box64_path);
@@ -1225,7 +1026,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
ApplyEnvFileEntry(box64_wine_guest_name);
box64_wine_guest_name = NULL;
}
openFTrace(0);
// Try to open ftrace again after applying rcfile.
openFTrace();
setupZydis(my_context);
PrintEnvVariables(&box64env, LOG_INFO);
@@ -1233,6 +1035,13 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
my_context->argv[i] = box_strdup(argv[i+nextarg]);
printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]);
}
// Setup custom bash rcfile iff no args are present
if (setup_bash_rcfile && my_context->argc == 1) {
add_argv("--rcfile");
add_argv("box64-custom-bashrc-file"); // handled by my_open
}
if(BOX64ENV(nosandbox))
{
add_argv("--no-sandbox");
@@ -1328,6 +1137,32 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
}
#ifdef BOX32
box64_is32bits = FileIsX86ELF(my_context->fullpath);
// try to switch personality, but only if not already tried
if(box64_is32bits) {
int tried = getenv("BOX32_PERSONA32BITS")?1:0;
if(tried) {
unsetenv("BOX32_PERSONA32BITS");
int p = personality(0xffffffff);
if(p==ADDR_LIMIT_32BIT) {
box64_isAddressSpace32 = 1;
printf_log(LOG_INFO, "Personality set to 32bits\n");
}
} else {
if(personality(ADDR_LIMIT_32BIT)!=-1) {
int nenv = 0;
while(env[nenv]) nenv++;
// alloc + "LD_PRELOAD" if needd + last NULL ending
char** newenv = (char**)box_calloc(nenv+1+1, sizeof(char*));
// copy strings
for (int i=0; i<nenv; ++i)
newenv[i] = box_strdup(env[i]);
newenv[nenv] = "BOX32_PERSONA32BITS=1";
// re-launch...
if(execve(my_context->box64path, (void*)argv, newenv)<0)
printf_log(LOG_NONE, "Failed to relaunch. Error is %d/%s (argv[0]=\"%s\")\n", errno, strerror(errno), argv[0]);
}
}
}
if(box64_is32bits) {
printf_log(LOG_INFO, "Using Box32 to load 32bits elf\n");
loadProtectionFromMap();
@@ -1507,9 +1342,6 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
SetRBP(emu, 0); // Frame pointer so to "No more frame pointer"
}
// child fork to handle traces
//pthread_atfork(my_prepare_fork, my_parent_fork, my_child_fork);
thread_set_emu(emu);
// export symbols
+757 -204
View File
File diff suppressed because it is too large. Load diff
+21 -145
View File
@@ -5,148 +5,7 @@
*/
/*
ARM64 Linux Call Convention
SP The Stack Pointer.
r30 LR The Link Register.
r29 FP The Frame Pointer
r19…r28 Callee-saved registers
r18 The Platform Register, if needed; otherwise a temporary register. See notes.
r17 IP1 The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
r16 IP0 The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
r9…r15 Temporary registers
r8 Indirect result location register
r0…r7 Parameter/result registers
For SIMD:
The first eight registers, v0-v7, are used to pass argument values into a subroutine and to return result values from a function.
They may also be used to hold intermediate values within a routine (but, in general, only between subroutine calls).
Registers v8-v15 must be preserved by a callee across subroutine calls;
the remaining registers (v0-v7, v16-v31) do not need to be preserved (or should be preserved by the caller).
Additionally, only the bottom 64 bits of each value stored in v8-v15 need to be preserved [8];
it is the responsibility of the caller to preserve larger values.
For SVE:
z0-z7 are used to pass scalable vector arguments to a subroutine, and to return scalable vector results from a function.
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
or returns results in such regisers, the subroutine must ensure that the entire contents of z8-z23 are preserved across the call.
In other cases it need only preserve the low 64 bits of z8-z15, as described in SIMD and Floating-Point registers.
p0-p3 are used to pass scalable predicate arguments to a subroutine and to return scalable predicate results from a function.
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
or returns results in such registers, the subroutine must ensure that p4-p15 are preserved across the call.
In other cases it need not preserve any scalable predicate register contents.
*/
// x86 Register mapping
#define xRAX 10
#define xRCX 11
#define xRDX 12
#define xRBX 13
#define xRSP 14
#define xRBP 15
#define xRSI 16
#define xRDI 17
#define xR8 18
#define xR9 19
#define xR10 20
#define xR11 21
#define xR12 22
#define xR13 23
#define xR14 24
#define xR15 25
#define xFlags 26
#define xRIP 27
#define xSavedSP 28
// convert a x86 register to native according to the register mapping
#define TO_NAT(A) (xRAX + (A))
// 32bits version
#define wEAX xRAX
#define wECX xRCX
#define wEDX xRDX
#define wEBX xRBX
#define wESP xRSP
#define wEBP xRBP
#define wESI xRSI
#define wEDI xRDI
#define wR8 xR8
#define wR9 xR9
#define wR10 xR10
#define wR11 xR11
#define wR12 xR12
#define wR13 xR13
#define wR14 xR14
#define wR15 xR15
#define wFlags xFlags
// scratch registers
#define x1 1
#define x2 2
#define x3 3
#define x4 4
#define x5 5
#define x6 6
#define x87pc 7
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
// 32bits version of scratch
#define w1 x1
#define w2 x2
#define w3 x3
#define w4 x4
#define w5 x5
#define w6 x6
#define w87pc x87pc
// emu is r0
#define xEmu 0
// ARM64 LR
#define xLR 30
// ARM64 SP is r31 but is a special register
#define xSP 31
// xZR regs is 31
#define xZR 31
#define wZR xZR
// conditions
// Z == 1
#define cEQ 0b0000
// Z != 1
#define cNE 0b0001
// C == 1
#define cCS 0b0010
// C == 1
#define cHS cCS
// C != 1
#define cCC 0b0011
// C != 1
#define cLO cCC
// N == 1
#define cMI 0b0100
// N != 1
#define cPL 0b0101
// V == 1
#define cVS 0b0110
// V != 1
#define cVC 0b0111
// C == 1 && Z == 0
#define cHI 0b1000
// C !=1 || Z == 1
#define cLS 0b1001
// N == V
#define cGE 0b1010
// N != V
#define cLT 0b1011
// N == V && Z == 0
#define cGT 0b1100
// N != V || Z == 1
#define cLE 0b1101
// always
#define c__ 0b1110
//FCMP type of opcode produce:
// if any NAN: CV / v1 == v2: ZC / v1 < v2: N / v1 > v2: C
#include "arm64_mapping.h"
int convert_bitmask(uint64_t bitmask);
#define convert_bitmask_w(A) convert_bitmask(((uint64_t)(A) << 32) + (uint32_t)(A))
@@ -188,10 +47,12 @@ int convert_bitmask(uint64_t bitmask);
#define ADDx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b00, Rm, 0, Rn, Rd))
#define ADDSx_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(1, 0, 1, 0b00, Rm, 0, Rn, Rd))
#define ADDx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b00, Rm, lsl, Rn, Rd))
#define ADDx_REG_LSR(Rd, Rn, Rm, lsr) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b01, Rm, lsr, Rn, Rd))
#define ADDz_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, lsl, Rn, Rd))
#define ADDw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, 0, Rn, Rd))
#define ADDSw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, 0, Rn, Rd))
#define ADDw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, lsl, Rn, Rd))
#define ADDw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b01, Rm, lsr, Rn, Rd))
#define ADDSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, lsl, Rn, Rd))
#define ADDxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 0, 0, 0b00, Rm, 0, Rn, Rd))
#define ADDz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, 0, Rn, Rd))
@@ -261,9 +122,11 @@ int convert_bitmask(uint64_t bitmask);
#define SBCSw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
#define SBCSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
#define SUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
#define ADDSUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
#define ADDw_UXTH(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 0, 0, Rm, 0b001, 0, Rn, Rd))
#define ADDx_UXTW(Rd, Rn, Rm) EMIT(ADDSUB_ext(1, 0, 0, Rm, 0b010, 0, Rn, Rd))
// CCMP compare if cond is true, set nzcv if false
#define CCMP_reg(sf, Rm, cond, Rn, nzcv) ((sf)<<31 | 1<<30 | 1<<29 | 0b11010010<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (nzcv))
@@ -301,6 +164,8 @@ int convert_bitmask(uint64_t bitmask);
#define LDS_gen(size, op1, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b10<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
#define LDRSW_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b10, 0b01, ((uint32_t)((imm12)>>2))&0xfff, Rn, Rt))
#define LDRSH_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b01, 0b01, ((uint32_t)((imm12)>>1))&0xfff, Rn, Rt))
#define LDRSB_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b00, 0b01, ((uint32_t)(imm12))&0xfff, Rn, Rt))
#define LDR_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b01<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
#define LDRx_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b011, 0, Rn, Rt))
@@ -338,6 +203,7 @@ int convert_bitmask(uint64_t bitmask);
#define LDRSW_REG(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
#define LDRSW_REG_SXTW(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
#define LDRSW_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
#define LDRSH_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b01, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
#define LDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | (imm19)<<5 | (Rt))
#define LDRx_literal(Rt, imm21) EMIT(LDR_PC_gen(0b01, (((int64_t)(imm21))>>2)&0x7FFFF, Rt))
@@ -2487,4 +2353,14 @@ int convert_bitmask(uint64_t bitmask);
//SHA256 hash update (part 2)
#define SHA256H2(Vd, Vn, Vm) EMIT(SHA256H2_gen(Vm, Vn, Vd))
// LRCPC extension
#define LDAPR_gen(sz, Rn, Rt) ((sz)<<30 | 0b111<<27 | 1<<23 | 1<<21 | 0b11111<<16 | 1<<15 | 0b100<<12 | (Rn)<<5 | (Rt))
#define LDAPRx(Rt, Rn) EMIT(LDAPR_gen(0b11, Rn, Rt))
#define LDAPRw(Rt, Rn) EMIT(LDAPR_gen(0b10, Rn, Rt))
#define LDAPRxw(Rt, Rn) EMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
#define LDAPRz(Rt, Rn) EMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
#define LDAPRH(Rt, Rn) EMIT(LDAPR_gen(0b01, Rn, Rt))
#define LDAPRB(Rt, Rn) EMIT(LDAPR_gen(0b00, Rn, Rt))
#endif //__ARM64_EMITTER_H__
+56 -31
View File
@@ -5,7 +5,7 @@
.text
.align 4
.extern arm64_atomics
.extern cpuext
.global arm64_lock_read_b
.global arm64_lock_write_b
.global arm64_lock_read_h
@@ -23,6 +23,7 @@
.global arm64_lock_storeifnull
.global arm64_lock_storeifnull_d
.global arm64_lock_storeifref
.global arm64_lock_storeifref2
.global arm64_lock_storeifref_d
.global arm64_lock_storeifref2_d
.global arm64_lock_decifnot0b
@@ -106,10 +107,10 @@ arm64_lock_write_dq:
arm64_lock_xchg_dd:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_xchg_dd
tbnz w3, #0, arm64_atomic_xchg_dd
dmb ish
arm64_lock_xchg_dd_0:
// address is x0, value is x1, return old value in x0
@@ -126,10 +127,10 @@ arm64_atomic_xchg_dd:
ret
arm64_lock_xchg_d:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_xchg_d
tbnz w3, #0, arm64_atomic_xchg_d
dmb ish
arm64_lock_xchg_d_0:
// address is x0, value is x1, return old value in x0
@@ -146,10 +147,10 @@ arm64_atomic_xchg_d:
ret
arm64_lock_xchg_h:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_xchg_h
tbnz w3, #0, arm64_atomic_xchg_h
dmb ish
arm64_lock_xchg_h_0:
// address is x0, value is x1, return old value in x0
@@ -166,10 +167,10 @@ arm64_atomic_xchg_h:
ret
arm64_lock_xchg_b:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_xchg_b
tbnz w3, #0, arm64_atomic_xchg_b
dmb ish
arm64_lock_xchg_b_0:
// address is x0, value is x1, return old value in x0
@@ -186,10 +187,10 @@ arm64_atomic_xchg_b:
ret
arm64_lock_storeifnull:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_storeifnull
tbnz w3, #0, arm64_atomic_storeifnull
dmb ish
1:
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
@@ -211,10 +212,10 @@ arm64_atomic_storeifnull:
arm64_lock_storeifnull_d:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_storeifnull_d
tbnz w3, #0, arm64_atomic_storeifnull_d
dmb ish
1:
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
@@ -236,10 +237,10 @@ arm64_atomic_storeifnull_d:
ret
arm64_lock_storeifref:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_storeifref
tbnz w3, #0, arm64_atomic_storeifref
dmb ish
1:
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
@@ -267,10 +268,10 @@ arm64_atomic_storeifref:
ret
arm64_lock_storeifref_d:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_storeifref_d
tbnz w3, #0, arm64_atomic_storeifref_d
dmb ish
1:
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so x1 or old value)
@@ -298,10 +299,10 @@ arm64_atomic_storeifref_d:
ret
arm64_lock_storeifref2_d:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_storeifref2_d
tbnz w3, #0, arm64_atomic_storeifref2_d
dmb ish
1:
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
@@ -321,6 +322,30 @@ arm64_atomic_storeifref2_d:
mov w0, w2
ret
arm64_lock_storeifref2:
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
tbnz w3, #0, arm64_atomic_storeifref2
dmb ish
1:
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return old [x0] value
ldaxr x3, [x0]
cmp x2, x3
bne 2f
stlxr w4, x1, [x0]
cbnz w4, 1b
2:
mov x0, x3
ret
arm64_atomic_storeifref2:
dmb ish
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return old [x0] value
casal x2, x1, [x0]
mov x0, x2
ret
arm64_lock_decifnot0b:
dmb ish
1:
@@ -352,10 +377,10 @@ arm64_lock_decifnot0:
ret
arm64_lock_incif0:
adrp x3, arm64_atomics
add x3, x3, #:lo12:arm64_atomics
adrp x3, cpuext
add x3, x3, #:lo12:cpuext
ldr w3, [x3]
cbnz w3, arm64_atomic_incif0
tbnz w3, #0, arm64_atomic_incif0
dmb ish
1:
ldaxr w1, [x0]
+5 -1
View File
@@ -55,11 +55,15 @@ extern void* arm64_atomic_storeifnull(void*p, void* val);
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
extern void* arm64_atomic_storeifref(void*p, void* val, void* ref);
// Atomically store value to [p] only if [p] is ref. Return old [p] value (so val or old)
extern void* arm64_lock_storeifref2(void*p, void* val, void* ref);
extern void* arm64_atomic_storeifref2(void*p, void* val, void* ref);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
extern uint32_t arm64_lock_storeifref_d(void*p, uint32_t val, uint32_t ref);
extern uint32_t arm64_atomic_storeifref_d(void*p, uint32_t val, uint32_t ref);
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
// Atomically store value to [p] only if [p] is ref. Return old [p] value (so ref or old)
extern uint32_t arm64_lock_storeifref2_d(void*p, uint32_t val, uint32_t ref);
extern uint32_t arm64_atomic_storeifref2_d(void*p, uint32_t val, uint32_t ref);
+148
View File
@@ -0,0 +1,148 @@
#ifndef __ARM64_MAPPING_H__
#define __ARM64_MAPPING_H__
/*
ARM64 Linux Call Convention
SP The Stack Pointer.
r30 LR The Link Register.
r29 FP The Frame Pointer
r19…r28 Callee-saved registers
r18 The Platform Register, if needed; otherwise a temporary register. See notes.
r17 IP1 The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
r16 IP0 The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
r9…r15 Temporary registers
r8 Indirect result location register
r0…r7 Parameter/result registers
For SIMD:
The first eight registers, v0-v7, are used to pass argument values into a subroutine and to return result values from a function.
They may also be used to hold intermediate values within a routine (but, in general, only between subroutine calls).
Registers v8-v15 must be preserved by a callee across subroutine calls;
the remaining registers (v0-v7, v16-v31) do not need to be preserved (or should be preserved by the caller).
Additionally, only the bottom 64 bits of each value stored in v8-v15 need to be preserved [8];
it is the responsibility of the caller to preserve larger values.
For SVE:
z0-z7 are used to pass scalable vector arguments to a subroutine, and to return scalable vector results from a function.
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
or returns results in such regisers, the subroutine must ensure that the entire contents of z8-z23 are preserved across the call.
In other cases it need only preserve the low 64 bits of z8-z15, as described in SIMD and Floating-Point registers.
p0-p3 are used to pass scalable predicate arguments to a subroutine and to return scalable predicate results from a function.
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
or returns results in such registers, the subroutine must ensure that p4-p15 are preserved across the call.
In other cases it need not preserve any scalable predicate register contents.
*/
// x86 Register mapping
#define xRAX 10
#define xRCX 11
#define xRDX 12
#define xRBX 13
#define xRSP 14
#define xRBP 15
#define xRSI 16
#define xRDI 17
#define xR8 18
#define xR9 19
#define xR10 20
#define xR11 21
#define xR12 22
#define xR13 23
#define xR14 24
#define xR15 25
#define xFlags 26
#define xRIP 27
#define xSavedSP 28
// convert a x86 register to native according to the register mapping
#define TO_NAT(A) (xRAX + (A))
// 32bits version
#define wEAX xRAX
#define wECX xRCX
#define wEDX xRDX
#define wEBX xRBX
#define wESP xRSP
#define wEBP xRBP
#define wESI xRSI
#define wEDI xRDI
#define wR8 xR8
#define wR9 xR9
#define wR10 xR10
#define wR11 xR11
#define wR12 xR12
#define wR13 xR13
#define wR14 xR14
#define wR15 xR15
#define wFlags xFlags
// scratch registers
#define x1 1
#define x2 2
#define x3 3
#define x4 4
#define x5 5
#define x6 6
#define x87pc 7
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
// 32bits version of scratch
#define w1 x1
#define w2 x2
#define w3 x3
#define w4 x4
#define w5 x5
#define w6 x6
#define w87pc x87pc
// emu is r0
#define xEmu 0
// ARM64 LR
#define xLR 30
// ARM64 SP is r31 but is a special register
#define xSP 31
// xZR regs is 31
#define xZR 31
#define wZR xZR
// conditions
// Z == 1
#define cEQ 0b0000
// Z != 1
#define cNE 0b0001
// C == 1
#define cCS 0b0010
// C == 1
#define cHS cCS
// C != 1
#define cCC 0b0011
// C != 1
#define cLO cCC
// N == 1
#define cMI 0b0100
// N != 1
#define cPL 0b0101
// V == 1
#define cVS 0b0110
// V != 1
#define cVC 0b0111
// C == 1 && Z == 0
#define cHI 0b1000
// C !=1 || Z == 1
#define cLS 0b1001
// N == V
#define cGE 0b1010
// N != V
#define cLT 0b1011
// N == V && Z == 0
#define cGT 0b1100
// N != V || Z == 1
#define cLE 0b1101
// always
#define c__ 0b1110
//FCMP type of opcode produce:
// if any NAN: CV / v1 == v2: ZC / v1 < v2: N / v1 > v2: C
#endif //__ARM64_MAPPING_H__
+1
View File
@@ -25,6 +25,7 @@ arm64_next:
#ifdef _WIN32
ldr x18, [x0, 3120]
#endif
mov x1, x27 // xRIP, should not be needed most of the time
mov x2, x30 // "from" is in lr, so put in x2
add x3, sp, 8*11 // x3 is address to change rip
// call the function
+2 -2
View File
@@ -1849,9 +1849,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
snprintf(buff, sizeof(buff), "SWP%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]);
return buff;
}
// SWPxw
// SWP B/H
if(isMask(opcode, "0f111000AR1sssss100000nnnnnttttt", &a)) {
snprintf(buff, sizeof(buff), "CAS%s%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
snprintf(buff, sizeof(buff), "SWP%s%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
return buff;
}
// LDXXXxw
+291 -103
View File
@@ -3,6 +3,7 @@
#include <stddef.h>
#include <errno.h>
#include "x64_signals.h"
#include "os.h"
#include "debug.h"
#include "box64context.h"
@@ -109,7 +110,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
PUSH1_32(x1);
} else {
DEFAULT;
INST_NAME("Illegal 06");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x07:
@@ -119,7 +130,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
} else {
DEFAULT;
INST_NAME("Illegal 07");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x08:
@@ -207,7 +228,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
PUSH1_32(x1);
SMWRITE();
} else {
DEFAULT;
INST_NAME("Illegal 0E");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x0F:
@@ -285,7 +316,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
PUSH1_32(x1);
SMWRITE();
} else {
DEFAULT;
INST_NAME("Illegal 16");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x17:
@@ -296,7 +337,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_SS]));
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
} else {
DEFAULT;
INST_NAME("Illegal 17");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x18:
@@ -362,7 +413,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
PUSH1_32(x1);
SMWRITE();
} else {
DEFAULT;
INST_NAME("Illegal 1E");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x1F:
@@ -373,7 +434,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
} else {
DEFAULT;
INST_NAME("Illegal 1F");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x20:
@@ -443,10 +514,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
READFLAGS(X_AF|X_CF);
SETFLAGS(X_ALL, SF_SET_DF);
UXTBx(x1, xRAX);
CALL_(daa8, x1, 0);
CALL_(const_daa8, x1, 0);
BFIz(xRAX, x1, 0, 8);
} else {
DEFAULT;
INST_NAME("Illegal 27");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x28:
@@ -508,10 +589,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
READFLAGS(X_AF|X_CF);
SETFLAGS(X_ALL, SF_SET_DF);
UXTBx(x1, xRAX);
CALL_(das8, x1, 0);
CALL_(const_das8, x1, 0);
BFIz(xRAX, x1, 0, 8);
} else {
DEFAULT;
INST_NAME("Illegal 2F");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x30:
@@ -602,10 +693,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
READFLAGS(X_AF);
SETFLAGS(X_ALL, SF_SET_DF);
UXTHx(x1, xRAX);
CALL_(aaa16, x1, 0);
CALL_(const_aaa16, x1, 0);
BFIz(xRAX, x1, 0, 16);
} else {
DEFAULT;
INST_NAME("Illegal 37");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x38:
@@ -670,10 +771,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
READFLAGS(X_AF);
SETFLAGS(X_ALL, SF_SET_DF);
UXTHw(x1, xRAX);
CALL_(aas16, x1, 0);
CALL_(const_aas16, x1, 0);
BFIx(xRAX, x1, 0, 16);
} else {
DEFAULT;
INST_NAME("Illegal 3F");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x40:
@@ -805,7 +916,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
PUSH2_32(xRSI, xRDI);
SMWRITE();
} else {
DEFAULT;
INST_NAME("Illegal 60");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x61:
@@ -817,7 +938,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
POP2_32(xRBX, xRDX);
POP2_32(xRCX, xRAX);
} else {
DEFAULT;
INST_NAME("Illegal 61");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x62:
@@ -836,7 +967,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
B_NEXT_nocond;
MARK;
STORE_XEMU_CALL(xRIP);
CALL(native_br, -1);
CALL_S(const_native_br, -1);
LOAD_XEMU_CALL(xRIP);
} else {
if(BOX64DRENV(dynarec_safeflags)>1) {
@@ -846,7 +977,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_ud, -1);
CALL_S(const_native_ud, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -1046,7 +1177,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -1062,7 +1193,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -1072,7 +1203,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
#define GO(GETFLAGS, NO, YES, F) \
READFLAGS(F); \
i8 = F8S; \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
GETFLAGS; \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
@@ -1086,7 +1216,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
} else { \
/* inside the block, cache transform */ \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
CacheTransform(dyn, ninst, cacheupd); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
SKIP_SEVL(i32); \
B(i32); \
@@ -1336,7 +1466,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
BFIx(eb1, x4, eb2, 8);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
SWPALB(x4, x1, ed);
} else {
MARKLOCK;
@@ -1346,7 +1476,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STLXRB(x3, x4, ed);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
BFIx(gb1, x1, gb2, 8);
break;
@@ -1363,7 +1492,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETGD;
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(!ALIGNED_ATOMICxw) {
if(arm64_uscat) {
if(cpuext.uscat) {
ANDx_mask(x1, ed, 1, 0, 3); // mask = F
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
B_MARK(cGT);
@@ -1372,7 +1501,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
B_MARK(cNE);
}
}
if(arm64_atomics) {
if(cpuext.atomics) {
SWPALxw(gd, gd, ed);
if(!ALIGNED_ATOMICxw) {
B_NEXT_nocond;
@@ -1395,8 +1524,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STRxw_U12(gd, ed, 0);
MARK2;
}
SMDMB();
if(!ALIGNED_ATOMICxw || !arm64_atomics) {
if(!ALIGNED_ATOMICxw || !cpuext.atomics) {
MOVxw_REG(gd, x1);
}
}
@@ -1610,7 +1738,23 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("CDQ");
SBFXxw(xRDX, xRAX, rex.w?63:31, 1);
break;
case 0x9A:
if(rex.is32bits) {
DEFAULT;
} else {
INST_NAME("Illegal 9A");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0x9B:
INST_NAME("FWAIT");
break;
@@ -2385,7 +2529,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(BOX64DRENV(dynarec_safeflags)) {
READFLAGS(X_PEND); // lets play safe here too
}
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
BARRIER(BARRIER_FLOAT);
i32 = F16;
retn_to_epilog(dyn, ip, ninst, rex, i32);
*need_epilog = 0;
@@ -2397,7 +2541,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(BOX64DRENV(dynarec_safeflags)) {
READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
}
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
BARRIER(BARRIER_FLOAT);
ret_to_epilog(dyn, ip, ninst, rex);
*need_epilog = 0;
*ok = 0;
@@ -2602,14 +2746,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
if ((BOX64ENV(log)<2 && !BOX64ENV(rolling_log) && !BOX64ENV(dynarec_test)) && tmp) {
//GETIP(ip+3+8+8); // read the 0xCC
call_n(dyn, ninst, *(void**)(addr+8), tmp);
call_n(dyn, ninst, (void*)(addr+8), tmp);
SMWRITE2();
addr+=8+8;
} else {
GETIP(ip+1); // read the 0xCC
STORE_XEMU_CALL(xRIP);
ADDx_U12(x3, xRIP, 8+8+2); // expected return address
ADDx_U12(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
CALL_(EmuInt3, -1, x3);
CALL_(const_int3, -1, x3);
SMWRITE2();
LOAD_XEMU_CALL(xRIP);
addr+=8+8;
@@ -2626,15 +2771,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("INT 3");
if(!BOX64ENV(ignoreint3)) {
// check if TRAP signal is handled
TABLE64(x1, (uintptr_t)my_context);
MOV32w(x2, offsetof(box64context_t, signals[SIGTRAP]));
TABLE64C(x1, const_context);
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
LDRx_REG(x3, x1, x2);
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[SIGTRAP]));
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
CMPSx_U12(x3, 0);
B_MARK(cEQ);
GETIP(addr); // update RIP
STORE_XEMU_CALL(xRIP);
CALL(native_int3, -1);
CALL_S(const_native_int3, -1);
LOAD_XEMU_CALL(xRIP);
MARK;
jump_to_epilog(dyn, addr, 0, ninst);
@@ -2652,7 +2797,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETIP(ip);
STORE_XEMU_CALL(xRIP);
MOV32w(x1, u8);
CALL_S(native_int, -1);
CALL_S(const_native_int, -1);
LOAD_XEMU_CALL(xRIP);
TABLE64(x3, addr); // expected return address
CMPSx_REG(xRIP, x3);
@@ -2670,7 +2815,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETIP(ip); // priviledged instruction, IP not updated
STORE_XEMU_CALL(xRIP);
MOV32w(x1, u8);
CALL(native_int, -1);
CALL_S(const_native_int, -1);
LOAD_XEMU_CALL(xRIP);
LOAD_XEMU_REM();
TABLE64(x3, addr); // expected return address
@@ -2686,7 +2831,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SMEND();
GETIP(addr);
STORE_XEMU_CALL(xRIP);
CALL_S(EmuX86Syscall, -1);
CALL_S(const_x86syscall, -1);
LOAD_XEMU_CALL(xRIP);
TABLE64(x3, addr); // expected return address
CMPSx_REG(xRIP, x3);
@@ -2705,7 +2850,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(addr);
STORE_XEMU_CALL(xRIP);
CALL(native_int3, -1);
CALL_S(const_native_int3, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -2724,7 +2869,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
STORE_XEMU_CALL(xRIP);
MOV32w(x1,u8);
CALL(native_int, -1);
CALL_S(const_native_int, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -2742,7 +2887,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
TBZ_NEXT(wFlags, F_OF);
STORE_XEMU_CALL(xRIP);
MOV32w(x1,4);
CALL(native_int, -1);
CALL_S(const_native_int, -1);
LOAD_XEMU_CALL(xRIP);
}
break;
@@ -3140,7 +3285,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
}
GETEDW(x4, x1, 0);
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
CALL_(rex.w?const_rcl64:const_rcl32, ed, x4);
WBACK;
break;
case 3:
@@ -3158,7 +3303,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
}
GETEDW(x4, x1, 0);
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
CALL_(rex.w?const_rcr64:const_rcr32, ed, x4);
WBACK;
break;
case 4:
@@ -3231,10 +3376,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
UBFXx(x1, xRAX, 0, 8); // load AL
u8 = F8;
MOV32w(x2, u8);
CALL_(aam16, x1, 0);
CALL_(const_aam16, x1, 0);
BFIz(xRAX, x1, 0, 16);
} else {
DEFAULT;
INST_NAME("Illegal D4");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0xD5:
@@ -3244,10 +3399,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
UBFXx(x1, xRAX, 0, 16); // load AX
u8 = F8;
MOV32w(x2, u8);
CALL_(aad16, x1, 0);
CALL_(const_aad16, x1, 0);
BFIz(xRAX, x1, 0, 16);
} else {
DEFAULT;
INST_NAME("Illegal D5");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
@@ -3282,7 +3447,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = dynarec64_DF(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
break;
#define GO(Z) \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
@@ -3294,7 +3458,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
CacheTransform(dyn, ninst, cacheupd); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
SKIP_SEVL(i32); \
Bcond(c__, i32); \
@@ -3308,6 +3472,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE0:
INST_NAME("LOOPNZ");
READFLAGS(X_ZF);
SMEND();
i8 = F8S;
SUBz_U12(xRCX, xRCX, 1);
TBNZ_NEXT(xFlags, F_ZF);
@@ -3316,6 +3481,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xE1:
INST_NAME("LOOPZ");
READFLAGS(X_ZF);
SMEND();
i8 = F8S;
SUBz_U12(xRCX, xRCX, 1);
TBZ_NEXT(xFlags, F_ZF);
@@ -3328,7 +3494,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GO(0);
break;
case 0xE3:
INST_NAME("JECXZ");
INST_NAME("JRCXZ");
i8 = F8S;
GO(1);
break;
@@ -3349,7 +3515,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
u8 = F8;
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -3365,7 +3531,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
#endif
}
#if STEP < 2
if (!rex.is32bits && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
if (!rex.is32bits && !dyn->need_reloc && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
tmp = dyn->insts[ninst].pass2choice = 3;
else
tmp = dyn->insts[ninst].pass2choice = i32?0:1;
@@ -3377,8 +3543,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state
if(dyn->last_ip && (addr-dyn->last_ip<0x1000)) {
ADDx_U12(x2, xRIP, addr-dyn->last_ip);
} else if(dyn->last_ip && (dyn->last_ip-addr<0x1000)) {
SUBx_U12(x2, xRIP, dyn->last_ip-addr);
} else {
MOV64x(x2, addr);
if(dyn->need_reloc) {
TABLE64(x2, addr);
} else {
MOV64x(x2, addr);
}
}
PUSH1(x2);
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetBridgeName((void*)(dyn->insts[ninst].natcall - 1)) ?: GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1)), dyn->insts[ninst].retn);
@@ -3395,7 +3567,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
if ((BOX64ENV(log)<2 && !BOX64ENV(rolling_log)) && dyn->insts[ninst].natcall && tmp) {
//GETIP(ip+3+8+8); // read the 0xCC
call_n(dyn, ninst, *(void**)(dyn->insts[ninst].natcall+2+8), tmp);
call_n(dyn, ninst, (void*)(dyn->insts[ninst].natcall+2+8), tmp);
SMWRITE2();
POP1(xRIP); // pop the return address
dyn->last_ip = addr;
@@ -3403,9 +3575,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETIP_(dyn->insts[ninst].natcall); // read the 0xCC already
STORE_XEMU_CALL(xRIP);
ADDx_U12(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
CALL_S(EmuInt3, -1);
CALL_S(const_int3, -1);
SMWRITE2();
LOAD_XEMU_CALL(xRIP);
// in case of dyn->need_reloc, the previous GETIP_ will end up in a TABLE64 that will generate a RELOC_CANCELBLOCK as natcall will be out of the mmap space anyway
MOV64x(x3, dyn->insts[ninst].natcall);
ADDx_U12(x3, x3, 2+8+8);
CMPSx_REG(xRIP, x3);
@@ -3424,7 +3597,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 1:
// this is call to next step, so just push the return address to the stack
MOV64x(x2, addr);
if(dyn->need_reloc) {
TABLE64(x2, addr);
} else {
MOV64x(x2, addr);
}
PUSH1z(x2);
break;
default:
@@ -3434,8 +3611,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state
}
// regular call
MOV64x(x2, addr);
fpu_purgecache(dyn, ninst, 1, x1, x3, x4);
if(dyn->need_reloc) {
TABLE64(x2, addr);
} else {
MOV64x(x2, addr);
}
BARRIER(BARRIER_FLOAT);
//fpu_purgecache(dyn, ninst, 0, x1, x3, x4);
PUSH1z(x2);
if (BOX64DRENV(dynarec_callret)) {
SET_HASCALLRET();
@@ -3471,16 +3653,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
MOV64x(x4, j64);
if(dyn->need_reloc) {
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
} else {
MOV64x(x4, j64);
}
LDRx_U12(x4, x4, 0);
BR(x4);
}
CLEARIP();
break;
}
break;
case 0xE9:
case 0xEB:
BARRIER(BARRIER_MAYBE);
BARRIER(BARRIER_MAYBE); // there will be a barrier if there is a jump out
if(opcode==0xEB && PK(0)==0xFF) {
INST_NAME("JMP ib");
MESSAGE(LOG_DEBUG, "Hack for EB FF opcode");
@@ -3502,11 +3690,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(dyn->insts[ninst].x64.jmp_insts==-1) {
// out of the block
SET_NODF();
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
} else {
// inside the block
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
CacheTransform(dyn, ninst, CHECK_CACHE());
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);
SKIP_SEVL(tmp);
if(tmp==4) {
@@ -3519,7 +3707,23 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
*ok = 0;
}
break;
case 0xEA:
if(rex.is32bits) {
DEFAULT;
} else {
INST_NAME("Illegal EA");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
BARRIER(BARRIER_FLOAT);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
break;
case 0xEC: /* IN AL, DX */
case 0xED: /* IN EAX, DX */
case 0xEE: /* OUT DX, AL */
@@ -3534,14 +3738,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
}
break;
case 0xF0:
addr = dynarec64_F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
break;
@@ -3554,7 +3757,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1); // is that a privileged opcodes or an int 1??
CALL_S(const_native_priv, -1); // is that a privileged opcodes or an int 1??
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -3570,7 +3773,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -3656,8 +3859,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
BFIx(xRAX, x1, 0, 16);
SET_DFNONE();
IFX(X_CF|X_OF) {
ASRxw(x2, x1, 8);
CMPSw_REG_ASR(x2, x1, 16);
SXTHw(x1, xRAX);
SXTBw(x2, x1);
CMPSw_REG(x2, x1);
CSETw(x3, cNE);
IFX(X_CF) {
BFIw(xFlags, x3, F_CF, 1);
@@ -3683,7 +3887,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZw_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3717,7 +3921,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZw_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3849,14 +4053,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MESSAGE(LOG_INFO, "Divide by 0 hack\n");
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
LOAD_XEMU_CALL(xRIP);
} else {
if(BOX64ENV(dynarec_div0)) {
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3883,7 +4087,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3898,7 +4102,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3906,7 +4110,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
CBZxw_MARK(xRDX);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(div64, -1);
CALL(const_div64, -1);
B_NEXT_nocond;
MARK;
UDIVx(x2, xRAX, ed);
@@ -3939,7 +4143,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(wb);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3961,7 +4165,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3976,7 +4180,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -3992,7 +4196,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
TBNZ_MARK(xRAX, 63);
MARK3;
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL((void*)idiv64, -1);
CALL(const_idiv64, -1);
B_NEXT_nocond;
MARK;
SDIVx(x2, xRAX, ed);
@@ -4034,7 +4238,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -4129,10 +4333,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
TABLE64(x4, j64);
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
LDRx_U12(x4, x4, 0);
BR(x4);
}
CLEARIP();
break;
case 3: // CALL FAR Ed
if(MODREG) {
@@ -4148,24 +4354,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDH(x3, wback, rex.w?8:4);
LDH(x4, xEmu, offsetof(x64emu_t, segs[_CS]));
GETIP_(addr);
/*
if(BOX64DRENV(dynarec_callret)) {
SET_HASCALLRET();
// Push actual return address
if(addr < (dyn->start+dyn->isize)) {
// there is a next...
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
} else {
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
j64 = getJumpTableAddress64(addr);
TABLE64(x4, j64);
LDRx_U12(x4, x4, 0);
}
STPx_S7_preindex(x4, xRIP, xSP, -16);
}
*/
// not doing callret because call far will exit the dynablock anyway, to be sure to recompute CS segment
PUSH1z(x4);
PUSH1z(xRIP);
+111 -92
View File
@@ -16,7 +16,6 @@
#include "my_cpuid.h"
#include "freq.h"
#include "emu/x87emu_private.h"
#include "emu/x64shaext.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
@@ -55,12 +54,29 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
#endif
switch(opcode) {
case 0x00:
if(rex.is32bits) {
nextop = F8;
switch((nextop>>3)&7) {
case 0:
INST_NAME("SLDT EW");
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MOV32w(ed, 0);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
STRH_U12(xZR, wback, 0);
}
break;
default:
DEFAULT;
}
} else {
DEFAULT;
}
break;
case 0x01:
// TODO:, /0 is SGDT. While 0F 01 D0 is XGETBV, etc...
nextop = F8;
@@ -90,7 +106,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("RDTSCP");
NOTEST(x1);
if(box64_rdtsc) {
CALL_(ReadTSC, x1, x3);
CALL_(const_readtsc, x1, x3);
} else {
MRS_cntvct_el0(x1);
}
@@ -99,7 +115,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
LSRx(xRDX, x1, 32);
MOVw_REG(xRAX, x1); // wipe upper part
CALL_(helper_getcpu, x1, x3);
CALL_(const_helper_getcpu, x1, x3);
MOVw_REG(xRCX, x1); // IA32_TSC, 0 for now
break;
default:
@@ -149,7 +165,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SMEND();
GETIP(addr);
STORE_XEMU_CALL(xRIP);
CALL_S(EmuX64Syscall, -1);
CALL_S(const_x64syscall, -1);
LOAD_XEMU_CALL(xRIP);
TABLE64(x3, addr); // expected return address
SUBx_REG(x3, x3, xRIP);
@@ -168,10 +184,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
BARRIER(BARRIER_FLOAT);
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_ud, -1);
LOAD_XEMU_CALL(xRIP);
UDF(0);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
@@ -184,10 +199,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
BARRIER(BARRIER_FLOAT);
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_ud, -1);
LOAD_XEMU_CALL(xRIP);
UDF(0);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
@@ -225,7 +239,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_ud, -1);
CALL_S(const_native_ud, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -379,6 +393,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
INST_NAME("NOP (multibyte)");
nextop = F8;
@@ -443,11 +462,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("CVTTPS2PI Gm,Ex");
nextop = F8;
GETGM(q0);
GETEX(v1, 0, 0);
GETEXSD(v1, 0, 0);
if (BOX64ENV(dynarec_fastround)) {
VFCVTZSS(q0, v1);
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32ZS(q0, v1);
VFCVTZSS(q0, q0);
} else {
@@ -477,7 +496,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("CVTPS2PI Gm, Ex");
nextop = F8;
GETGM(q0);
GETEX(v1, 0, 0);
GETEXSD(v1, 0, 0);
if (BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
VFRINTIS(q0, v1);
@@ -485,7 +504,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VFCVTZSS(q0, q0);
} else {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32XS(q0, v1);
VFCVTZSS(q0, q0);
} else {
@@ -520,7 +539,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETGX(v0, 0);
GETEXSS(s0, 0, 0);
FCMPS(v0, s0);
IFX(X_CF|X_PF|X_ZF) {
FCMPS(v0, s0);
}
FCOMI(x1, x2);
break;
case 0x30:
@@ -532,7 +553,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
// continue the block
@@ -541,7 +562,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("RDTSC");
NOTEST(x1);
if(box64_rdtsc) {
CALL_(ReadTSC, x1, x3);
CALL_(const_readtsc, x1, x3);
} else {
MRS_cntvct_el0(x1);
}
@@ -711,7 +732,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn, ninst);
VEORQ(v0, v0, v0);
if(arm64_sha1) {
if(cpuext.sha1) {
v1 = fpu_get_scratch(dyn, ninst);
VMOVeS(v1, 0, q0, 3);
SHA1H(v1, v1);
@@ -735,7 +756,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCA:
INST_NAME("SHA1MSG2 Gx, Ex");
nextop = F8;
if(arm64_sha1) {
if(cpuext.sha1) {
GETGX(q0, 1);
GETEX(q1, 0, 0);
VEXTQ_8(q0, q0, q0, 8);
@@ -771,13 +792,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETG;
sse_forget_reg(dyn, ninst, gd);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
CALL(sha1msg2, -1);
CALL(const_sha1msg2, -1);
}
break;
case 0xCB:
INST_NAME("SHA256RNDS2 Gx, Ex (, XMM0)");
nextop = F8;
if(arm64_sha2) {
if(cpuext.sha2) {
GETGX(q0, 1);
GETEX(q1, 0, 0);
d0 = sse_get_reg(dyn, ninst, x1, 0, 0);
@@ -817,13 +838,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
sse_forget_reg(dyn, ninst, gd);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
sse_reflect_reg(dyn, ninst, 0);
CALL(sha256rnds2, -1);
CALL(const_sha256rnds2, -1);
}
break;
case 0xCC:
INST_NAME("SHA256MSG1 Gx, Ex");
nextop = F8;
if(arm64_sha2) {
if(cpuext.sha2) {
GETGX(q0, 1);
GETEX(q1, 0, 0);
SHA256SU0(q0, q1);
@@ -842,13 +863,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETG;
sse_forget_reg(dyn, ninst, gd);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
CALL(sha256msg1, -1);
CALL(const_sha256msg1, -1);
}
break;
case 0xCD:
INST_NAME("SHA256MSG2 Gx, Ex");
nextop = F8;
if(arm64_sha2) {
if(cpuext.sha2) {
GETGX(q0, 1);
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn, ninst);
@@ -876,7 +897,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETG;
sse_forget_reg(dyn, ninst, gd);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
CALL(sha256msg2, -1);
CALL(const_sha256msg2, -1);
}
break;
@@ -935,7 +956,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xCC:
INST_NAME("SHA1RNDS4 Gx, Ex, Ib");
nextop = F8;
if(arm64_sha1) {
if(cpuext.sha1) {
GETGX(q0, 1);
GETEX(q1, 0, 1);
u8 = F8&3;
@@ -999,7 +1020,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
sse_forget_reg(dyn, ninst, gd);
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
MOV32w(x3, u8);
CALL(sha1rnds4, -1);
CALL(const_sha1rnds4, -1);
}
break;
@@ -1199,7 +1220,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x5A:
INST_NAME("CVTPS2PD Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETEXSD(q0, 0, 0);
GETGX_empty(q1);
FCVTL(q1, q0);
break;
@@ -1237,13 +1258,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEX(v1, 0, 0);
// FMIN/FMAX wll not copy the value if v0[x] is NaN
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMINQS(v0, v0, v1);
} else {
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQS(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
VBIFQ(v0, v1, q0);
}
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQS(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
VBIFQ(v0, v1, q0);
break;
case 0x5E:
INST_NAME("DIVPS Gx, Ex");
@@ -1272,13 +1289,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEX(v1, 0, 0);
// FMIN/FMAX wll not copy the value if v0[x] is NaN
// but x86 will copy if either v0[x] or v1[x] is NaN, or if values are equals, so lets force a copy if source is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMAXQS(v0, v0, v1);
} else {
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQS(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
VBIFQ(v0, v1, q0);
}
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQS(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
VBIFQ(v0, v1, q0);
break;
case 0x60:
INST_NAME("PUNPCKLBW Gm,Em");
@@ -1677,7 +1690,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
j64 = (uint32_t)(addr+i32_); \
else \
j64 = addr+i32_; \
BARRIER(BARRIER_MAYBE); \
JUMP(j64, 1); \
GETFLAGS; \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
@@ -1690,7 +1702,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
CacheTransform(dyn, ninst, cacheupd); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
SKIP_SEVL(i32); \
B(i32); \
@@ -1743,7 +1755,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("CPUID");
NOTEST(x1);
MOVx_REG(x1, xRAX);
CALL_(my_cpuid, -1, 0);
CALL_(const_cpuid, -1, 0);
break;
case 0xA3:
INST_NAME("BT Ed, Gd");
@@ -1787,6 +1799,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
WBACK;
} else {
FAKEED;
if (!rex.w && !rex.is32bits && MODREG) { MOVw_REG(ed, ed); }
F8;
}
break;
@@ -1874,6 +1887,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
WBACK;
} else {
FAKEED;
if (!rex.w && !rex.is32bits && MODREG) { MOVw_REG(ed, ed); }
F8;
}
break;
@@ -1922,18 +1936,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0:
INST_NAME("FXSAVE Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FXSAVE)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(rex.is32bits?((void*)fpu_fxsave32):((void*)fpu_fxsave64), -1);
CALL(rex.is32bits?const_fpu_fxsave32:const_fpu_fxsave64, -1);
break;
case 1:
INST_NAME("FXRSTOR Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FXRSTOR)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(rex.is32bits?((void*)fpu_fxrstor32):((void*)fpu_fxrstor64), -1);
CALL(rex.is32bits?const_fpu_fxrstor32:const_fpu_fxrstor64, -1);
break;
case 2:
INST_NAME("LDMXCSR Md");
@@ -1950,21 +1964,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(BOX64ENV(sse_flushto0)) {
// try to sync mxcsr with fpsr on the flag side
/* mapping is
ARM -> X86
0 -> 0 // Invalid operation
1 -> 2 // Divide by 0
2 -> 3 // Overflow
3 -> 4 // underflow
4 -> 5 // Inexact
5 -> 1 // denormal
ARM <-> X86
0 <-> 0 // Invalid operation
1 <-> 2 // Divide by 0
2 <-> 3 // Overflow
3 <-> 4 // underflow
4 <-> 5 // Inexact
5 <-> 1 // denormal
*/
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
// doing X86 -> ARM here, 543210 => 432150
if(ed!=x1)
MOVw_REG(x1, ed); // x1 = 543210
RORw(x3, x1, 2); // x3 = 10.....5432
BFIw(x1, x3, 1, 4); // x1 = 54320
RORw(x3, x3, 32-1); // x3 = 0.....54321
BFIw(x1, x3, 5, 1); // x1 = 154320
UBFXw(x2, x1, 1, 5); // x2 = 54321
BFIw(x1, x2, 2, 4); // x1 = 432110
LSRw(x2, x2, 4); // x2 = 5
BFIw(x1, x2, 1, 1); // x1 = 432150
MRS_fpsr(x2);
BFIx(x2, x1, 0, 6);
MSR_fpsr(x2);
@@ -1974,36 +1988,36 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("STMXCSR Md");
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
STW(x4, ed, fixedaddress);
if(BOX64ENV(sse_flushto0)) {
// sync with fpsr, with mask from mxcsr
MRS_fpsr(x1);
// doing ARM -> X86 here, 543210 => 432150
UBFXw(x2, x1, 1, 5); // x2 = 54321
BFIw(x1, x2, 2, 4); // x1 = 432110
LSRw(x2, x2, 4); // x2 = 5
BFIw(x1, x2, 1, 1); // x1 = 432150
// doing ARM -> X86 here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
RORw(x3, x1, 2); // x3 = 10.....5432
BFIw(x1, x3, 1, 4); // x1 = 54320
RORw(x3, x3, 32-1); // x3 = 0.....54321
BFIw(x1, x3, 5, 1); // x1 = 154320
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
BFIw(x4, x1, 0, 6); // inject back the flags
}
STW(x4, ed, fixedaddress);
break;
case 4:
INST_NAME("XSAVE Ed");
MESSAGE(LOG_DUMP, "Need Optimization (XSAVE)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
MOV32w(x2, rex.w?0:1);
CALL((void*)fpu_xsave, -1);
CALL(const_fpu_xsave, -1);
break;
case 5:
INST_NAME("XRSTOR Ed");
MESSAGE(LOG_DUMP, "Need Optimization (XRSTOR)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
MOV32w(x2, rex.w?0:1);
CALL((void*)fpu_xrstor, -1);
CALL(const_fpu_xrstor, -1);
break;
case 7:
INST_NAME("CLFLUSH Ed");
@@ -2012,7 +2026,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(ed!=x1) {
MOVx_REG(x1, ed);
}
CALL_(native_clflush, -1, 0);
CALL_(const_native_clflush, -1, 0);
break;
default:
DEFAULT;
@@ -2092,18 +2106,23 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CMPSxw_REG(xRAX, ed);
}
MOVxw_REG(x1, ed); // save value
CSELxw(ed, gd, ed, cEQ);
Bcond(cNE, 4 + (rex.w ? 4 : 8));
MOVxw_REG(ed, gd);
if (!rex.w) { B_NEXT_nocond; }
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
LDxw(x1, wback, fixedaddress);
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
UFLAG_IF {
emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);
}
SUBxw_REG(x4, xRAX, x1);
CBNZxw_MARK(x4);
// EAX == Ed
STxw(gd, wback, fixedaddress);
if (!rex.w) { B_NEXT_nocond; }
MARK;
}
MOVxw_REG(xRAX, x1); // upper part of RAX will be erase on 32bits, no mater what
MOVxw_REG(xRAX, x1);
break;
case 0xB3:
@@ -2343,8 +2362,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETED(0);
GETGD;
if(ed!=gd)
MOVxw_REG(gd, ed); // to handle ed=0, setting UD gd to 0
IFX(X_ZF) {
TSTxw_REG(ed, ed);
B_MARK(cEQ);
@@ -2379,8 +2396,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
nextop = F8;
GETED(0);
GETGD;
if(ed!=gd)
MOVxw_REG(gd, ed); // to handle ed=0, setting UD gd to 0
IFX(X_ZF) {
TSTxw_REG(ed, ed);
B_MARK(cEQ);
@@ -2591,11 +2606,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
BICw(xFlags, xFlags, x1);
}
if(arm64_rndr) {
if(cpuext.rndr) {
MRS_rndr(x1);
IFX(X_CF) { CSETw(x3, cNE); }
} else {
CALL(rex.w?((void*)get_random64):((void*)get_random32), x1);
CALL(rex.w?const_random64:const_random32, x1);
IFX(X_CF) { MOV32w(x3, 1); }
}
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
@@ -2604,7 +2619,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 7:
INST_NAME("RDPID Ed");
GETED(0);
CALL_(helper_getcpu, ed, x2);
CALL_(const_helper_getcpu, ed, x2);
break;
default:
DEFAULT;
@@ -2640,6 +2655,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("Unsupported XSAVEC Ed");
FAKEED;
BARRIER(BARRIER_FLOAT);
GETIP(ip);
UDF(0);
break;
case 6:
@@ -2650,11 +2667,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
BICw(xFlags, xFlags, x1);
}
if(arm64_rndr) {
if(cpuext.rndr) {
MRS_rndr(x1);
IFX(X_CF) { CSETw(x3, cNE); }
} else {
CALL(rex.w?((void*)get_random64):((void*)get_random32), x1);
CALL(rex.w?const_random64:const_random32, x1);
IFX(X_CF) { MOV32w(x3, 1); }
}
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
@@ -2711,8 +2728,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETGM(d0);
GETEM(d1, 0);
v0 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
UQXTN_32(v1, d1);
MOVI_32(v0, 64);
UMIN_32(v0, v0, d1); // limit to 0 .. +64 values (will force 32bits upper part to 0)
UMIN_32(v0, v0, v1); // limit to 0 .. +64 values
NEG_32(v0, v0);
UXTL_32(v0, v0);
USHL_R_64(d0, d0, v0);
@@ -2740,7 +2759,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
q1 = fpu_get_scratch(dyn, ninst);
GETEM(q0, 0);
GETGD;
TABLE64(x1, (uintptr_t)&mask_shift8);
TABLE64C(x1, const_8b_m7_m6_m5_m4_m3_m2_m1_0);
VLDR64_U12(v0, x1, 0); // load shift
MOVI_8(v1, 0x80); // load mask
VAND(q1, v1, q0);
+58 -14
View File
@@ -272,6 +272,27 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0x7F:
switch(rep) {
case 2:
INST_NAME("MOVDQU Ex,Gx");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
VMOVQ(v1, v0);
} else {
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
ADDz_REG(x4, x4, ed);
VST128(v0, x4, fixedaddress);
SMWRITE2();
}
break;
default:
DEFAULT;
}
break;
case 0xAF:
switch(rep) {
@@ -370,6 +391,27 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0xBF:
switch(rep) {
case 0:
INST_NAME("MOVSX Gd, Ew");
nextop = F8;
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
GETGD;
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
SXTHxw(gd, ed);
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
LDRSH_REGz(gd, x4, ed);
}
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
@@ -541,7 +583,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.is32bits)
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, seg, ok, need_epilog);
else {
DEFAULT;
addr = dynarec64_6764(dyn, addr, ip, ninst, rex, rep, seg, ok, need_epilog);
}
break;
@@ -619,7 +661,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -635,7 +677,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_priv, -1);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -1221,7 +1263,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
CBZw_NEXT(x2);
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x6);
CALL_(rex.w?const_rcl64:const_rcl32, ed, x6);
WBACK;
break;
case 3:
@@ -1242,7 +1284,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
CBZw_NEXT(x2);
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x6);
CALL_(rex.w?const_rcr64:const_rcr32, ed, x6);
WBACK;
break;
case 4:
@@ -1416,7 +1458,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1442,7 +1484,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1455,14 +1497,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETEDO(x6, 0);
CBZxw_MARK(xRDX);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(div64, -1);
CALL(const_div64, -1);
B_NEXT_nocond;
MARK;
if(BOX64ENV(dynarec_div0)) {
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1500,7 +1542,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(wb);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1520,7 +1562,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1535,7 +1577,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZx_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1545,7 +1587,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MVNx_REG(x2, xRDX);
CBZxw_MARK(x2);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL((void*)idiv64, -1);
CALL(const_idiv64, -1);
B_NEXT_nocond;
MARK;
SDIVx(x2, xRAX, ed);
@@ -1626,10 +1668,12 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
TABLE64(x4, j64);
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
LDRx_U12(x4, x4, 0);
BR(x4);
}
CLEARIP();
break;
case 4: // JMP Ed
INST_NAME("JMP Ed");
+104 -16
View File
@@ -472,6 +472,38 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MOV32w(x2, (uint16_t)i16);
PUSH1_16(x2);
break;
case 0x6C:
case 0x6D:
INST_NAME(opcode == 0x6C ? "INSB" : "INSW");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
break;
case 0x6E:
case 0x6F:
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSW");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
break;
case 0x70:
case 0x71:
@@ -596,9 +628,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(!ALIGNED_ATOMICH) {
TBNZ_MARK(ed, 0);
}
if(arm64_atomics) {
if(cpuext.atomics) {
SWPALH(gd, x1, ed);
SMDMB();
if(!ALIGNED_ATOMICH) {
B_MARK2_nocond;
}
@@ -607,7 +638,6 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LDAXRH(x1, ed);
STLXRH(x3, gd, ed);
CBNZx_MARKLOCK(x3);
SMDMB();
if(!ALIGNED_ATOMICH) {
B_MARK2_nocond;
}
@@ -619,7 +649,6 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
STLXRB(x3, gd, ed);
CBNZx_MARK(x3);
STRH_U12(gd, ed, 0);
SMDMB();
MARK2;
}
BFIz(gd, x1, 0, 16);
@@ -670,7 +699,20 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SMWRITE2();
}
break;
case 0x8D:
INST_NAME("LEA Gd, Ed");
nextop=F8;
GETGD;
if(MODREG) { // reg <= reg? that's an invalid operation
DEFAULT;
} else { // mem <= reg
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if (rex.w)
MOVx_REG(gd, ed);
else
BFIx(gd, ed, 0, 16);
}
break;
case 0x8E:
INST_NAME("MOV Seg,Ew");
nextop = F8;
@@ -1284,8 +1326,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
SETFLAGS(X_OF|X_CF, SF_SET_DF);
ANDw_mask(x2, xRCX, 0, 0b00100);
CBZw_NEXT(x2);
GETEW(x1, 0);
CALL_(rcl16, x1, x3);
CALL_(const_rcl16, x1, x3);
EWBACK;
break;
case 3:
@@ -1298,8 +1341,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
SETFLAGS(X_OF|X_CF, SF_SET_DF);
ANDw_mask(x2, xRCX, 0, 0b00100);
CBZw_NEXT(x2);
GETEW(x1, 0);
CALL_(rcr16, x1, x3);
CALL_(const_rcr16, x1, x3);
EWBACK;
break;
case 4:
@@ -1361,11 +1405,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 6:
INST_NAME("FNSTENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV16)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
BARRIER(BARRIER_FLOAT); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
MOV32w(x2, 1);
CALL(fpu_savenv, -1);
CALL(const_fpu_savenv, -1);
break;
default:
DEFAULT;
@@ -1381,25 +1425,69 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("FRSTOR Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR16)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(native_frstor16, -1);
CALL(const_native_frstor16, -1);
break;
case 6:
INST_NAME("FNSAVE Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE16)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(native_fsave16, -1);
CALL(reset_fpu, -1);
CALL(const_native_fsave16, -1);
break;
default:
DEFAULT;
}
break;
case 0xE4: /* IN AL, Ib */
case 0xE5: /* IN AX, Ib */
case 0xE6: /* OUT Ib, AL */
case 0xE7: /* OUT Ib, AX */
INST_NAME(opcode==0xE4?"IN AL, Ib":(opcode==0xE5?"IN AX, Ib":(opcode==0xE6?"OUT Ib, AL":"OUT Ib, AX")));
if (rex.is32bits && BOX64ENV(ignoreint3)) {
F8;
} else {
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
u8 = F8;
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
}
break;
case 0xEC: /* IN AL, DX */
case 0xED: /* IN AX, DX */
case 0xEE: /* OUT DX, AL */
case 0xEF: /* OUT DX, AX */
INST_NAME(opcode==0xEC?"IN AL, DX":(opcode==0xED?"IN AX, DX":(opcode==0xEE?"OUT DX, AL":"OUT DX, AX")));
if(rex.is32bits && BOX64ENV(ignoreint3))
{} else {
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_PEND);
} else {
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
}
GETIP(ip);
STORE_XEMU_CALL(xRIP);
CALL_S(const_native_priv, -1);
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
*ok = 0;
}
break;
case 0xF0:
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
@@ -1506,7 +1594,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZw_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1540,7 +1628,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBNZw_MARK3(ed);
GETIP_(ip);
STORE_XEMU_CALL(xRIP);
CALL(native_div0, -1);
CALL_S(const_native_div0, -1);
CLEARIP();
LOAD_XEMU_CALL(xRIP);
jump_to_epilog(dyn, 0, xRIP, ninst);
+65 -60
View File
@@ -18,7 +18,6 @@
#include "dynarec_arm64_private.h"
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
#include "emu/x64compstrings.h"
uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
{
@@ -47,9 +46,6 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MAYUSE(eb2);
MAYUSE(j64);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
static const int8_t round_round[] = { 0, 2, 1, 3};
#endif
@@ -168,6 +164,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
INST_NAME("NOP (multibyte)");
nextop = F8;
@@ -233,7 +234,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VFCVTZSQD(q0, v1);
SQXTN_32(q0, q0);
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32ZDQ(q0, v1);
VFCVTZSQD(q0, q0);
SQXTN_32(q0, q0);
@@ -273,7 +274,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VFCVTZSS(q0, q0);
} else {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32XDQ(q0, v1);
VFCVTZSQD(q0, q0);
SQXTN_32(q0, q0);
@@ -309,7 +310,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGX(v0, 0);
GETEXSD(q0, 0, 0);
FCMPD(v0, q0);
IFX(X_CF|X_PF|X_ZF) {
FCMPD(v0, q0);
}
FCOMI(x1, x2);
break;
@@ -631,7 +634,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
GETGX_empty(v0);
SMREAD();
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff << 4, 15, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff << 4, 15, rex, NULL, 0, 0);
VLD128(v0, ed, fixedaddress);
}
break;
@@ -769,7 +772,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xDB:
INST_NAME("AESIMC Gx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
GETEX(q1, 0, 0);
GETGX_empty(q0);
AESIMC(q0, q1);
@@ -781,13 +784,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesimc, -1);
CALL(const_native_aesimc, -1);
}
break;
case 0xDC:
INST_NAME("AESENC Gx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
GETEX(q1, 0, 0);
GETGX(q0, 1);
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
@@ -804,7 +807,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aese, -1);
CALL(const_native_aese, -1);
GETGX(q0, 1);
VEORQ(q0, q0, (d0!=-1)?d0:q1);
}
@@ -812,7 +815,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xDD:
INST_NAME("AESENCLAST Gx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
GETEX(q1, 0, 0);
GETGX(q0, 1);
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
@@ -828,7 +831,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aeselast, -1);
CALL(const_native_aeselast, -1);
GETGX(q0, 1);
VEORQ(q0, q0, (d0!=-1)?d0:q1);
}
@@ -836,7 +839,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xDE:
INST_NAME("AESDEC Gx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
GETEX(q1, 0, 0);
GETGX(q0, 1);
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
@@ -853,7 +856,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesd, -1);
CALL(const_native_aesd, -1);
GETGX(q0, 1);
VEORQ(q0, q0, (d0!=-1)?d0:q1);
}
@@ -861,7 +864,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xDF:
INST_NAME("AESDECLAST Gx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
GETEX(q1, 0, 0);
GETGX(q0, 1);
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
@@ -877,7 +880,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesdlast, -1);
CALL(const_native_aesdlast, -1);
GETGX(q0, 1);
VEORQ(q0, q0, (d0!=-1)?d0:q1);
}
@@ -907,10 +910,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
REV16x(x1, gd);
BFIx(ed, x1, 0, 16);
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
REV16x(x1, gd);
STH(x1, ed, fixedaddress);
SMWRITE();
}
break;
@@ -923,7 +926,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGD;
IFNATIVE_BEFORE(NF_CF) {
if(INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(x3);
@@ -1151,7 +1154,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("PINSRB Gx, ED, Ib");
nextop = F8;
GETGX(q0, 1);
GETED(1);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
LDB(x1, wback, fixedaddress);
ed = x1;
}
u8 = F8;
VMOVQBfrom(q0, (u8&15), ed);
break;
@@ -1238,7 +1249,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x44:
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
nextop = F8;
if(arm64_pmull) {
if(cpuext.pmull) {
GETGX(q0, 1);
GETEX(q1, 0, 1);
u8 = F8;
@@ -1276,7 +1287,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
u8 = F8;
MOV32w(x4, u8);
CALL(native_pclmul, -1);
CALL(const_native_pclmul, -1);
}
break;
@@ -1302,7 +1313,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MOVx_REG(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
CALL(sse42_compare_string_explicit_len, x1);
CALL(const_sse42_compare_string_explicit_len, x1);
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
if(u8&0b1000000) {
q1 = fpu_get_scratch(dyn, ninst);
@@ -1312,7 +1323,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
LSRw_IMM(x1, x1, 8);
VDUPQB(q1, x1); // load the high 8bits of the mask
VEXTQ_8(q0, q0, q1, 8); // low and hig bits mask
TABLE64(x2, (uintptr_t)&mask_string8);
TABLE64C(x2, const_8b_7_6_5_4_3_2_1_0);
VLDR64_U12(q1, x2, 0); // load shift
VDUPQ_64(q1, q1, 0);
USHLQ_8(q0, q0, q1); // extract 1 bit
@@ -1322,7 +1333,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
break;
case 0b01:
VDUPQH(q0, x1); // load the 8bits of the mask
TABLE64(x2, (uintptr_t)&mask_string16);
TABLE64C(x2, const_8b_15_14_13_12_11_10_9_8);
VLDR64_U12(q1, x2, 0); // load shift
UXTL_8(q1, q1); // extend mask to 16bits
USHLQ_16(q0, q0, q1); // extract 1 bit
@@ -1354,7 +1365,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
// transform that a mask in x1
q1 = fpu_get_scratch(dyn, ninst);
VSHL_8(q0, q0, 7); // keep only bit 0x80
TABLE64(x1, (uintptr_t)&mask_shift8);
TABLE64C(x1, const_8b_m7_m6_m5_m4_m3_m2_m1_0);
VLDR64_U12(q1, x1, 0); // load shift
USHL_8(q0, q0, q1); // shift
UADDLV_8(q0, q0); // accumulate
@@ -1366,7 +1377,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
q1 = fpu_get_scratch(dyn, ninst);
d0 = fpu_get_scratch(dyn, ninst);
VSHL_8(d0, q0, 7); // keep only bit 0x80
TABLE64(x1, (uintptr_t)&mask_shift8);
TABLE64C(x1, const_8b_m7_m6_m5_m4_m3_m2_m1_0);
VLDR64_U12(q1, x1, 0); // load shift
USHL_8(d0, d0, q1); // shift
UADDLV_8(d0, d0); // accumulate
@@ -1390,10 +1401,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
CMPSw_REG(x3, x4);
CSELw(x3, x3, x4, cLT); // x3 is lmem
CMPSw_REG(x2, x4);
CSELw(x2, x2, x4, cLT); // x2 is lreg
CMPSw_REG(x2, x3);
CSELw(x5, x3, x2, cLT); // x5 is max(lmem, lreg)
CSELw(x2, x2, x3, cLT); // x2 is min(lmem, lreg)
CSELw(x6, x2, x4, cLT); // x6 is lreg
CMPSw_REG(x6, x3);
CSELw(x5, x3, x6, cLT); // x5 is max(lmem, lreg)
CSELw(x2, x6, x3, cLT); // x2 is min(lmem, lreg)
// x2 is min length 0-n_packed
MVNw_REG(x4, xZR);
LSLw_REG(x87pc, x4, x2);
@@ -1429,7 +1440,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIw(xFlags, x5, F_ZF, 1);
}
IFX(X_SF) {
CMPSw_REG(x2, x4);
CMPSw_REG(x6, x4);
CSETw(x5, cLT);
BFIw(xFlags, x5, F_SF, 1);
}
@@ -1471,7 +1482,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
MOVw_REG(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
CALL(sse42_compare_string_explicit_len, x1);
CALL(const_sse42_compare_string_explicit_len, x1);
}
if(u8&0b1000000) {
CBNZw_MARK(x1);
@@ -1507,7 +1518,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
u8 = F8;
MOV32w(x3, u8);
CALL(sse42_compare_string_implicit_len, x1);
CALL(const_sse42_compare_string_implicit_len, x1);
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
if(u8&0b1000000) {
q1 = fpu_get_scratch(dyn, ninst);
@@ -1517,7 +1528,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
LSRw_IMM(x1, x1, 8);
VDUPQB(q1, x1); // load the high 8bits of the mask
VEXTQ_8(q0, q0, q1, 8); // low and hig bits mask
TABLE64(x2, (uintptr_t)&mask_string8);
TABLE64C(x2, const_8b_7_6_5_4_3_2_1_0);
VLDR64_U12(q1, x2, 0); // load shift
VDUPQ_64(q1, q1, 0);
USHLQ_8(q0, q0, q1); // extract 1 bit
@@ -1527,7 +1538,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
break;
case 0b01:
VDUPQH(q0, x1); // load the 8bits of the mask
TABLE64(x2, (uintptr_t)&mask_string16);
TABLE64C(x2, const_8b_15_14_13_12_11_10_9_8);
VLDR64_U12(q1, x2, 0); // load shift
UXTL_8(q1, q1); // extend mask to 16bits
USHLQ_16(q0, q0, q1); // extract 1 bit
@@ -1561,7 +1572,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
u8 = F8;
MOV32w(x3, u8);
CALL(sse42_compare_string_implicit_len, x1);
CALL(const_sse42_compare_string_implicit_len, x1);
CBNZw_MARK(x1);
MOV32w(xRCX, (u8&1)?8:16);
B_NEXT_nocond;
@@ -1596,7 +1607,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
u8 = F8;
MOV32w(x4, u8);
CALL(native_aeskeygenassist, -1);
CALL(const_native_aeskeygenassist, -1);
break;
default:
@@ -1752,7 +1763,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
x87_restoreround(dyn, ninst, u8);
VFCVTZSQS(v0, v0);
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
VFRINT32XSQ(v0, v1); // handle overflow
VFCVTZSQS(v0, v0);
@@ -1807,13 +1818,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETEX(v1, 0, 0);
// FMIN/FMAX wll not copy the value if v0[x] is NaN
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMINQD(v0, v0, v1);
} else {
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQD(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
VBIFQ(v0, v1, q0);
}
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQD(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
VBIFQ(v0, v1, q0);
break;
case 0x5E:
INST_NAME("DIVPD Gx, Ex");
@@ -1842,13 +1849,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETEX(v1, 0, 0);
// FMIN/FMAX wll not copy the value if v0[x] is NaN
// but x86 will copy if either v0[x] or v1[x] is NaN, or if values are equals, so lets force a copy if source is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMAXQD(v0, v0, v1);
} else {
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQD(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
VBIFQ(v0, v1, q0);
}
q0 = fpu_get_scratch(dyn, ninst);
VFCMGTQD(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
VBIFQ(v0, v1, q0);
break;
case 0x60:
INST_NAME("PUNPCKLBW Gx, Ex");
@@ -2514,7 +2517,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(ed!=x1) {
MOVx_REG(x1, ed);
}
CALL_(native_clflush, -1, 0);
CALL_(const_native_clflush, -1, 0);
break;
case 7:
INST_NAME("CLFLUSHOPT Ed");
@@ -2523,7 +2526,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(ed!=x1) {
MOVx_REG(x1, ed);
}
CALL_(native_clflush, -1, 0);
CALL_(const_native_clflush, -1, 0);
break;
default:
DEFAULT;
@@ -2757,8 +2760,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
RBITw(x1, x1); // reverse
CLZw(x1, x1); // x2 gets leading 0 == BSF
MARK;
if(!MODREG) MARK; // value gets written on 0 input only if input is a memory it seems
BFIx(gd, x1, 0, 16);
if(MODREG) MARK;
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(x2, cEQ); //ZF not set
@@ -2794,8 +2798,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
CLZw(x2, x1); // x2 gets leading 0
SUBw_U12(x2, x2, 15);
NEGw_REG(x1, x2); // complement
MARK;
if(!MODREG) MARK;
BFIx(gd, x1, 0, 16);
if(MODREG) MARK;
IFX(X_ZF) {
IFNATIVE(NF_EQ) {} else {
CSETw(x2, cEQ); //ZF not set
@@ -3042,7 +3047,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
q1 = fpu_get_scratch(dyn, ninst);
GETEX(q0, 0, 0);
GETGD;
TABLE64(x2, 0x0706050403020100LL);
TABLE64_(x2, 0x0706050403020100LL);
VDUPQD(v0, x2);
VSHRQ_8(q1, q0, 7);
USHLQ_8(q1, q1, v0); // shift
@@ -3188,7 +3193,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
VFCVTZSQD(v0, v1); // convert double -> int64
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32ZDQ(v0, v1); // handle overflow
VFCVTZSQD(v0, v0); // convert double -> int64
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
+3 -1
View File
@@ -64,7 +64,9 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
v1 = fpu_get_scratch(dyn, ninst);
VLD64(v1, ed, fixedaddress);
}
FCMPD(v0, v1);
IFX(X_CF|X_PF|X_ZF) {
FCMPD(v0, v1);
}
FCOMI(x1, x2);
break;
+15 -32
View File
@@ -60,7 +60,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
UFLAG_IF {
LDADDALH(x5, x1, wback);
emit_add16(dyn, ninst, x1, x5, x3, x4);
@@ -74,7 +74,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
@@ -90,7 +89,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
UFLAG_IF {
LDSETALH(x5, x1, wback);
emit_or16(dyn, ninst, x1, x5, x3, x4);
@@ -104,7 +103,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
@@ -128,7 +126,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(!ALIGNED_ATOMICH) {
if(arm64_uscat) {
if(cpuext.uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
CMPSw_U12(x1, 0xF);
B_MARK3(cGE);
@@ -138,7 +136,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
}
// Aligned version
if(arm64_atomics) {
if(cpuext.atomics) {
MOVw_REG(x1, x6);
CASALH(x1, gd, wback);
} else {
@@ -168,7 +166,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
}
MARK;
SMDMB();
// Common part (and fallback for EAX != Ed)
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
BFIx(xRAX, x1, 0, 16);
@@ -187,7 +184,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIx(ed, x5, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
LDADDALH(x5, x1, wback);
} else {
MARKLOCK;
@@ -196,7 +193,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x4, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
IFX(X_ALL|X_PEND) {
MOVxw_REG(x2, x1);
emit_add16(dyn, ninst, x2, x5, x3, x4);
@@ -228,7 +224,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
break;
@@ -244,7 +239,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
MVNw_REG(x3, gd);
UFLAG_IF {
LDCLRALH(x3, x1, wback);
@@ -259,7 +254,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
@@ -286,7 +280,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
if(!ALIGNED_ATOMICH) {
if(arm64_uscat) {
if(cpuext.uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
CMPSw_U12(x1, 0xF);
B_MARK(cGE);
@@ -295,7 +289,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
B_MARK(cNE);
}
}
if(arm64_atomics) {
if(cpuext.atomics) {
UFLAG_IF {
LDADDALH(x5, x1, wback);
} else {
@@ -308,7 +302,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x4, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
if(!ALIGNED_ATOMICH) {
B_MARK2_nocond;
MARK; // unaligned! also, not enough
@@ -320,7 +313,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRB(x3, x4, wback);
CBNZx_MARK(x3);
STRH_U12(x4, wback, 0); // put the whole value
SMDMB();
}
MARK2;
UFLAG_IF {
@@ -341,7 +333,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
if(!i64) {MOV32w(x5, i16);}
if(arm64_atomics) {
if(cpuext.atomics) {
UFLAG_IF {
LDSETALH(x5, x1, wback);
emit_or16c(dyn, ninst, x1, i16, x3, x4);
@@ -361,7 +353,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 2: //ADC
@@ -384,7 +375,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
emit_adc16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
break;
case 3: //SBB
@@ -407,7 +397,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
break;
case 4: //AND
@@ -423,7 +412,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
i64 = convert_bitmask_w(i16);
if(arm64_atomics) {
if(cpuext.atomics) {
MOV32w(x5, ~i16);
UFLAG_IF {
LDCLRALH(x5, x1, wback);
@@ -447,7 +436,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
}
break;
@@ -466,7 +454,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(opcode==0x81) i16 = F16S; else i16 = F8S;
MOV32w(x5, i16);
if(!ALIGNED_ATOMICH) {
if(arm64_uscat) {
if(cpuext.uscat) {
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
CMPSw_U12(x1, 0xF);
B_MARK(cGE);
@@ -475,7 +463,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
B_MARK(cNE);
}
}
if(arm64_atomics) {
if(cpuext.atomics) {
NEGw_REG(x4, x5);
UFLAG_IF {
LDADDALH(x4, x1, wback);
@@ -489,7 +477,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
if(!ALIGNED_ATOMICH) {
B_MARK2_nocond;
MARK; // unaligned! also, not enough
@@ -501,7 +488,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRB(x3, x4, wback);
CBNZx_MARK(x3);
STRH_U12(x4, wback, 0); // put the whole value
SMDMB();
}
MARK2;
UFLAG_IF {
@@ -522,7 +508,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
if(opcode==0x81) i16 = F16S; else i16 = F8S;
i64 = convert_bitmask_w(i16);
if(arm64_atomics) {
if(cpuext.atomics) {
UFLAG_IF {
LDEORALH(x5, x1, wback);
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
@@ -539,7 +525,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
emit_xor16(dyn, ninst, x1, x5, x3, x4);
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
SMDMB();
}
}
break;
@@ -574,7 +559,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
MOV32w(x3, 1);
UFLAG_IF {
LDADDALH(x3, x1, wback);
@@ -589,7 +574,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
case 1: //DEC Ew
@@ -602,7 +586,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
BFIx(ed, x6, 0, 16);
} else {
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
if(arm64_atomics) {
if(cpuext.atomics) {
MOV32w(x3, -1);
UFLAG_IF {
LDADDALH(x3, x1, wback);
@@ -617,7 +601,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
STLXRH(x3, x1, wback);
CBNZx_MARKLOCK(x3);
}
SMDMB();
}
break;
default:
+1 -7
View File
@@ -45,12 +45,6 @@ uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(j64);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
static const int8_t round_round[] = { 0, 2, 1, 3};
#endif
switch(opcode) {
@@ -63,7 +57,7 @@ uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETEW(x1, 0);
GETGD;
if(arm64_crc32) {
if(cpuext.crc32) {
CRC32CH(gd, gd, ed);
} else {
MOV32w(x2, 0x82f63b78);
-6
View File
@@ -45,12 +45,6 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(j64);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
static const int8_t round_round[] = { 0, 2, 1, 3};
#endif
switch(opcode) {
case 0xB8:
+31 -30
View File
@@ -230,7 +230,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
VLD32(s0, ed, fixedaddress);
}
FCMPS(v0, s0);
IFX(X_CF|X_PF|X_ZF) {
FCMPS(v0, s0);
}
FCOMI(x1, x2);
break;
default:
@@ -1246,6 +1248,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
break;
case 0x9C:
INST_NAME("PUSHF");
READFLAGS(X_ALL);
PUSH1z(xFlags);
break;
case 0xA1:
INST_NAME("MOV EAX,Od");
u64 = F32;
@@ -1424,66 +1432,57 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
#define GO(NO, YES) \
BARRIER(BARRIER_MAYBE); \
#define GO(Z) \
JUMP(addr+i8, 1); \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
Bcond(NO, i32); \
if(Z) {CBNZw(xRCX, i32);} else {CBZw(xRCX, i32);}; \
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
CacheTransform(dyn, ninst, cacheupd); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
SKIP_SEVL(i32); \
B(i32); \
Bcond(c__, i32); \
} \
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
SKIP_SEVL(i32); \
Bcond(YES, i32); \
if(Z) {CBZw(xRCX, i32);} else {CBNZw(xRCX, i32);}; \
}
case 0xE0:
INST_NAME("LOOPNZ (32bits)");
READFLAGS(X_ZF);
SMEND();
i8 = F8S;
MOVw_REG(x1, xRCX);
SUBw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 32);
CBZw_NEXT(x1); // ECX is 0, no LOOP
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
GO(cNE, cEQ);
SUBw_U12(xRCX, xRCX, 1);
TBNZ_NEXT(xFlags, F_ZF);
GO(0);
break;
case 0xE1:
INST_NAME("LOOPZ (32bits)");
READFLAGS(X_ZF);
SMEND();
i8 = F8S;
MOVw_REG(x1, xRCX);
SUBw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 32);
CBZw_NEXT(x1); // ECX is 0, no LOOP
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
GO(cEQ, cNE);
SUBw_U12(xRCX, xRCX, 1);
TBZ_NEXT(xFlags, F_ZF);
GO(0);
break;
case 0xE2:
INST_NAME("LOOP (32bits)");
i8 = F8S;
MOVw_REG(x1, xRCX);
SUBSw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 32);
GO(cEQ, cNE);
SUBw_U12(xRCX, xRCX, 1);
GO(0);
break;
case 0xE3:
INST_NAME("JECXZ");
i8 = F8S;
MOVw_REG(x1, xRCX);
TSTw_REG(x1, x1);
GO(cNE, cEQ);
GO(1);
break;
#undef GO
@@ -1616,7 +1615,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
GETED32H(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
CBZxw_MARK(xRDX);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(div64, -1);
CALL(const_div64, -1);
B_NEXT_nocond;
MARK;
UDIVx(x2, xRAX, ed);
@@ -1666,7 +1665,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MVNx_REG(x2, xRDX);
CBZxw_MARK(x2);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL((void*)idiv64, -1);
CALL(const_idiv64, -1);
B_NEXT_nocond;
MARK;
SDIVx(x2, xRAX, ed);
@@ -1748,10 +1747,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
TABLE64(x4, j64);
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
LDRx_U12(x4, x4, 0);
BR(x4);
}
CLEARIP();
break;
default:
DEFAULT;
+94
View File
@@ -0,0 +1,94 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "arm64_printer.h"
#include "dynarec_arm64_private.h"
#include "../dynarec_helper.h"
#include "dynarec_arm64_functions.h"
#define GETGm gd = ((nextop & 0x38) >> 3)
uintptr_t dynarec64_6764(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop;
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
int64_t fixedaddress;
int unscaled;
int8_t i8;
uint8_t u8;
int32_t i32;
int64_t j64, i64;
int cacheupd = 0;
int lock;
int v0, v1, s0;
MAYUSE(i32);
MAYUSE(j64);
MAYUSE(v0);
MAYUSE(v1);
MAYUSE(s0);
MAYUSE(lock);
MAYUSE(cacheupd);
rep = 0;
while ((opcode == 0xF2) || (opcode == 0xF3)) {
rep = opcode - 0xF1;
opcode = F8;
}
rex.rex = 0;
while (opcode >= 0x40 && opcode <= 0x4f) {
rex.rex = opcode;
opcode = F8;
}
switch (opcode) {
case 0x89:
INST_NAME("MOV Seg:Ed, Gd");
nextop = F8;
GETGD;
if (MODREG) { // reg <= reg
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
} else { // mem <= reg
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
STRxw_REG(gd, x4, ed);
}
break;
case 0x8B:
INST_NAME("MOV Gd, Seg:Ed");
nextop = F8;
GETGD;
if (MODREG) { // reg => reg
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
} else { // mem => reg
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
LDRxw_REG(gd, x4, ed);
}
break;
default:
DEFAULT;
}
return addr;
}
+5 -2
View File
@@ -89,7 +89,6 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
break;
#define GO(NO, YES) \
BARRIER(BARRIER_MAYBE); \
JUMP(addr+i8, 1); \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
CHECK_CACHE()) { \
@@ -101,7 +100,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
CacheTransform(dyn, ninst, cacheupd); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
SKIP_SEVL(i32); \
B(i32); \
@@ -116,6 +115,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("LOOPNZ (16bits)");
READFLAGS(X_ZF);
i8 = F8S;
SMEND();
UXTHw(x1, xRCX);
SUBw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 16);
@@ -126,6 +126,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xE1:
INST_NAME("LOOPZ (16bits)");
READFLAGS(X_ZF);
SMEND();
i8 = F8S;
UXTHw(x1, xRCX);
SUBw_U12(x1, x1, 1);
@@ -137,6 +138,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xE2:
INST_NAME("LOOP (16bits)");
i8 = F8S;
SMEND();
UXTHw(x1, xRCX);
SUBSw_U12(x1, x1, 1);
BFIx(xRCX, x1, 0, 16);
@@ -145,6 +147,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xE3:
INST_NAME("JCXZ");
i8 = F8S;
SMEND();
TSTw_mask(xRCX, 0, 15); //mask=0xffff
GO(cNE, cEQ);
break;
+1 -1
View File
@@ -100,7 +100,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch)
// got through all naoncache to gather regs assignments
int idx;
for(int i=0; i<32; ++i)
if(dyn->insts[ninst].n.neoncache[i].v!=-1)
if(dyn->insts[ninst].n.neoncache[i].v)
switch(dyn->insts[ninst].n.neoncache[i].t) {
case NEON_CACHE_XMMW:
arch->sse = 1;
+35 -43
View File
@@ -54,9 +54,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
#if STEP > 1
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
#endif
rex_t rex = vex.rex;
@@ -297,7 +294,9 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETGX(v0, 0);
GETEXSS(s0, 0, 0);
FCMPS(v0, s0);
IFX(X_CF|X_PF|X_ZF) {
FCMPS(v0, s0);
}
FCOMI(x1, x2);
break;
@@ -509,7 +508,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5A:
INST_NAME("VCVTPS2PD Gx, Ex");
nextop = F8;
GETGX_empty_EX(v0, v1, 0);
if (vex.l) {
GETGX_empty_EX(v0, v1, 0);
} else {
GETEXSD(v1, 0, 0);
GETGX_empty(v0);
}
if(vex.l) {
GETGY_empty(q0, -1, -1, -1);
FCVTL2(q0, v1);
@@ -553,20 +557,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5D:
INST_NAME("VMINPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
}
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
// FMIN/FMAX wll not copy a NaN if either is NaN
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMINQS(v0, v2, v1);
} else {
VFCMGTQS(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
VFCMGTQS(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
if(!vex.l) YMM0(gd);
break;
@@ -597,20 +595,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x5F:
INST_NAME("VMAXPS Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
}
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
// FMIN/FMAX wll not copy a NaN if either is NaN
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMAXQS(v0, v2, v1);
} else {
VFCMGTQS(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
VFCMGTQS(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
if(!vex.l) YMM0(gd);
break;
@@ -660,21 +652,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(BOX64ENV(sse_flushto0)) {
// try to sync mxcsr with fpsr on the flag side
/* mapping is
ARM -> X86
0 -> 0 // Invalid operation
1 -> 2 // Divide by 0
2 -> 3 // Overflow
3 -> 4 // underflow
4 -> 5 // Inexact
5 -> 1 // denormal
ARM <-> X86
0 <-> 0 // Invalid operation
1 <-> 2 // Divide by 0
2 <-> 3 // Overflow
3 <-> 4 // underflow
4 <-> 5 // Inexact
5 <-> 1 // denormal
*/
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
// doing X86 -> ARM here, 543210 => 432150
if(ed!=x1)
MOVw_REG(x1, ed); // x1 = 543210
RORw(x3, x1, 2); // x3 = 10.....5432
BFIw(x1, x3, 1, 4); // x1 = 54320
RORw(x3, x3, 32-1); // x3 = 0.....54321
BFIw(x1, x3, 5, 1); // x1 = 154320
UBFXw(x2, x1, 1, 5); // x2 = 54321
BFIw(x1, x2, 2, 4); // x1 = 432110
LSRw(x2, x2, 4); // x2 = 5
BFIw(x1, x2, 1, 1); // x1 = 432150
MRS_fpsr(x2);
BFIx(x2, x1, 0, 6);
MSR_fpsr(x2);
@@ -684,18 +676,18 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("VSTMXCSR Md");
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
STW(x4, ed, fixedaddress);
if(BOX64ENV(sse_flushto0)) {
// sync with fpsr, with mask from mxcsr
MRS_fpsr(x1);
// doing ARM -> X86 here, 543210 => 432150
UBFXw(x2, x1, 1, 5); // x2 = 54321
BFIw(x1, x2, 2, 4); // x1 = 432110
LSRw(x2, x2, 4); // x2 = 5
BFIw(x1, x2, 1, 1); // x1 = 432150
// doing ARM -> X86 here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
RORw(x3, x1, 2); // x3 = 10.....5432
BFIw(x1, x3, 1, 4); // x1 = 54320
RORw(x3, x3, 32-1); // x3 = 0.....54321
BFIw(x1, x3, 5, 1); // x1 = 154320
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
BFIw(x4, x1, 0, 6); // inject back the flags
}
STW(x4, ed, fixedaddress);
break;
default:
DEFAULT;
+44 -20
View File
@@ -132,9 +132,14 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
IFX(X_OF) {
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
}
if (BOX64ENV(dynarec_test)) {
if (BOX64ENV(dynarec_safeflags)) {
// those are UD flags
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
if(BOX64ENV(cputype)) {
IFX(X_PF) BFCw(xFlags, F_PF, 1);
} else {
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
}
}
break;
@@ -171,9 +176,14 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
IFX(X_OF) {
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
}
if (BOX64ENV(dynarec_test)) {
if (BOX64ENV(dynarec_safeflags)) {
// those are UD flags
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
if(BOX64ENV(cputype)) {
IFX(X_PF) BFCw(xFlags, F_PF, 1);
} else {
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
}
}
break;
@@ -184,7 +194,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
GETVD;
IFX(X_CF) {
TSTxw_REG(ed, ed);
CSETMw(x3, cEQ);
CSETMw(x3, cNE);
BFIw(xFlags, x3, F_CF, 1);
}
NEGxw_REG(x3, ed);
@@ -211,9 +221,14 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
IFX(X_OF) {
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
}
if (BOX64ENV(dynarec_test)) {
if (BOX64ENV(dynarec_safeflags)) {
// those are UD flags
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
if(BOX64ENV(cputype)) {
IFX(X_PF) BFCw(xFlags, F_PF, 1);
} else {
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
}
}
break;
@@ -259,11 +274,18 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
BFIw(xFlags, x3, F_SF, 1);
}
}
IFX(X_AF) BFCw(xFlags, F_AF, 1);
IFX(X_PF) BFCw(xFlags, F_PF, 1);
IFX(X_OF) {
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
}
if (BOX64ENV(dynarec_safeflags)) {
// those are UD flags
IFX(X_AF) BFCw(xFlags, F_AF, 1);
if(BOX64ENV(cputype)) {
IFX(X_PF) BFCw(xFlags, F_PF, 1);
} else {
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
}
}
break;
case 0xF7:
@@ -273,22 +295,24 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
GETGD;
GETED(0);
GETVD;
MOV64xw(x1, 0);
UXTBw(x2, vd); // start
BFXILw(x3, vd, 8, 8); // length
MOV64xw(x5, 0);
UXTBw(x4, vd); // start
UBFXw(x3, vd, 8, 8); // length
TSTw_REG(x3, x3);
B_MARK(cEQ);
LSRxw_REG(x1, ed, x2);
CMPSw_U12(x3, rex.w?64:32);
CMPSw_U12(x4, rex.w?64:32);
B_MARK(cGE);
MOV32w(x2, rex.w?64:32);
SUBw_REG(x2, x2, x3);
LSLxw_REG(x1, x1, x2);
LSRxw_REG(x1, x1, x2);
TSTxw_REG(x1, x1);
LSRxw_REG(x5, ed, x4);
CMPSw_U12(x3, rex.w?64:32);
B_MARK(cGT);
MOV32w(x4, rex.w?64:32);
SUBw_REG(x4, x4, x3);
LSLxw_REG(x5, x5, x4);
LSRxw_REG(x5, x5, x4);
MARK;
MOVxw_REG(gd, x1);
MOVxw_REG(gd, x5);
IFX(X_ZF) {
TSTxw_REG(x5, x5);
IFNATIVE(NF_EQ) {} else {
CSETw(x3, cEQ);
BFIw(xFlags, x3, F_ZF, 1);
+18 -26
View File
@@ -268,7 +268,9 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGX(v0, 0);
GETEXSD(q0, 0, 0);
FCMPD(v0, q0);
IFX(X_CF|X_PF|X_ZF) {
FCMPD(v0, q0);
}
FCOMI(x1, x2);
break;
@@ -285,8 +287,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
GETEY(q0);
VMOVQDto(x1, q0, 0);
VMOVQDto(x2, q0, 1);
BFIx(x1, x2, 63, 1);
RORx(x2, x1, 63);
LSRx(x2, x2, 62);
BFXILx(x2, x1, 63, 1);
BFIx(gd, x2, 2, 2);
}
break;
@@ -429,7 +431,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VCVTPS2DQ Gx, Ex");
nextop = F8;
u8 = sse_setround(dyn, ninst, x1, x2, x6);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
d0 = fpu_get_scratch(dyn, ninst);
d1 = fpu_get_scratch(dyn, ninst);
MOVI_32_lsl(d1, 0x80, 3);
@@ -440,7 +442,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VFRINTISQ(v0, v1);
VFCVTZSQS(v0, v0);
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32XSQ(v0, v1);
VFCVTZSQS(v0, v0);
} else {
@@ -493,24 +495,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x5D:
INST_NAME("VMINPD Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan))
q0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
// FMIN/FMAX wll not copy a NaN if either is NaN
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMINQD(v0, v2, v1);
} else {
VFCMGTQD(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
VFCMGTQD(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
if(!vex.l) YMM0(gd);
break;
case 0x5E:
INST_NAME("DIVPD Gx, Ex");
INST_NAME("VDIVPD Gx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan)) {
q0 = fpu_get_scratch(dyn, ninst);
@@ -536,19 +533,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x5F:
INST_NAME("VMAXPD Gx, Vx, Ex");
nextop = F8;
if(!BOX64ENV(dynarec_fastnan))
q0 = fpu_get_scratch(dyn, ninst);
q0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
// FMIN/FMAX wll not copy a NaN if either is NaN
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
if(BOX64ENV(dynarec_fastnan)) {
VFMAXQD(v0, v2, v1);
} else {
VFCMGTQD(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
VFCMGTQD(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
if(v0!=v1) VBIFQ(v0, v1, q0);
if(v0!=v2) VBITQ(v0, v2, q0);
}
if(!vex.l) YMM0(gd);
break;
@@ -1459,7 +1451,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q1 = fpu_get_scratch(dyn, ninst);
GETEX_Y(q0, 0, 0);
GETGD;
TABLE64(x2, 0x0706050403020100LL);
TABLE64_(x2, 0x0706050403020100LL);
VDUPQD(v0, x2);
VSHRQ_8(q1, q0, 7);
USHLQ_8(q1, q1, v0); // shift
@@ -1694,7 +1686,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
else
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32ZDQ(l?d0:v0, v1); // handle overflow
VFCVTZSQD(l?d0:v0, l?d0:v0); // convert double -> int64
if(!l)
+19 -24
View File
@@ -22,11 +22,6 @@
#include "dynarec_arm64_functions.h"
#include "../dynarec_helper.h"
static const float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
static const double addsubpd[2] = {-1., 1.};
static const float subaddps[4] = {1.f, -1.f, 1.f, -1.f};
static const double subaddpd[2] = {1., -1.};
uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip; (void)need_epilog;
@@ -779,7 +774,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
} else YMM0(gd);
break;
case 0x2E:
INST_NAME("VMASKMOVPS Ex, Gx, Vx");
INST_NAME("VMASKMOVPS Ex, Vx, Gx");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
GETVX(v2, 0);
@@ -835,7 +830,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
SMWRITE2();
break;
case 0x2F:
INST_NAME("VMASKMOVPD Ex, Gx, Vx");
INST_NAME("VMASKMOVPD Ex, Vx, Gx");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
GETVX(v2, 0);
@@ -1587,7 +1582,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
INST_NAME("VFMADDSUB213PS/D Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
TABLE64(x2, (rex.w)?((uintptr_t)&addsubpd):((uintptr_t)&addsubps));
TABLE64C(x2, rex.w?const_2d_m1_1:const_4f_m1_1_m1_1);
VLDR128_U12(q0, x2, 0);
q1 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
@@ -1738,7 +1733,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
INST_NAME("VFMADDSUB231PS/D Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
TABLE64(x2, (rex.w)?((uintptr_t)&addsubpd):((uintptr_t)&addsubps));
TABLE64C(x2, rex.w?const_2d_m1_1:const_4f_m1_1_m1_1);
VLDR128_U12(q0, x2, 0);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_VXEX(v0, v2, v1, 0); if(v0==v2 || v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_VYEY(v0, v2, v1); }
@@ -1761,7 +1756,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
INST_NAME("VFMSUBADD231PS/D Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
TABLE64(x2, (rex.w)?((uintptr_t)&subaddpd):((uintptr_t)&subaddps));
TABLE64C(x2, rex.w?const_2d_1_m1:const_4f_1_m1_1_m1);
VLDR128_U12(q0, x2, 0);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_VXEX(v0, v2, v1, 0); if(v0==v2 || v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_VYEY(v0, v2, v1); }
@@ -1879,7 +1874,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
INST_NAME("VAESIMC Gx, Ex");
nextop = F8;
GETGX_empty_EX(v0, v1, 0);
if(arm64_aes) {
if(cpuext.aes) {
AESIMC(v0, v1);
} else {
if(v0!=v1) {
@@ -1887,7 +1882,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesimc, -1);
CALL(const_native_aesimc, -1);
}
YMM0(gd);
break;
@@ -1895,7 +1890,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 0xDC:
INST_NAME("VAESENC Gx, Vx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
for(int l=0; l<1+vex.l; ++l) {
if(!l) {GETGX_empty_VXEX(v0, v2, v1, 0);} else {GETGY_empty_VYEY(v0, v2, v1);}
@@ -1922,8 +1917,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aese, -1);
if(vex.l) {MOV32w(x1, gd); CALL(native_aese_y, -1);}
CALL(const_native_aese, -1);
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aese_y, -1);}
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
@@ -1936,7 +1931,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 0xDD:
INST_NAME("VAESENCLAST Gx, Vx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
@@ -1962,8 +1957,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aeselast, -1);
if(vex.l) {MOV32w(x1, gd); CALL(native_aeselast_y, -1);}
CALL(const_native_aeselast, -1);
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aeselast_y, -1);}
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
@@ -1976,7 +1971,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 0xDE:
INST_NAME("VAESDEC Gx, Vx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
for(int l=0; l<1+vex.l; ++l) {
if(!l) {GETGX_empty_VXEX(v0, v2, v1, 0);} else {GETGY_empty_VYEY(v0, v2, v1);}
@@ -2003,8 +1998,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesd, -1);
if(vex.l) {MOV32w(x1, gd); CALL(native_aesd_y, -1);}
CALL(const_native_aesd, -1);
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aesd_y, -1);}
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
@@ -2017,7 +2012,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 0xDF:
INST_NAME("VAESDECLAST Gx, Vx, Ex"); // AES-NI
nextop = F8;
if(arm64_aes) {
if(cpuext.aes) {
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
for(int l=0; l<1+vex.l; ++l) {
if(!l) {GETGX_empty_VXEX(v0, v2, v1, 0);} else {GETGY_empty_VYEY(v0, v2, v1);}
@@ -2043,8 +2038,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesdlast, -1);
if(vex.l) {MOV32w(x1, gd); CALL(native_aesdlast_y, -1);}
CALL(const_native_aesdlast, -1);
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aesdlast_y, -1);}
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
+13 -13
View File
@@ -167,12 +167,12 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
u8 = F8;
GETVX(v2, 0);
GETGX_empty(v0);
if((v0==v2) && ((u8&0xf0)==0)) {
if((v0==v2) && ((u8&0b10110000)==0)) {
q0 = fpu_get_scratch(dyn, ninst);
VMOVQ(q0, v2);
v2 = q0;
}
if((v0==v1) && ((u8&0xf0)==0x20)) {
if((v0==v1) && ((u8&0b10110000)==0x20)) {
q1 = fpu_get_scratch(dyn, ninst);
VMOVQ(q1, v1);
v1 = q1;
@@ -184,8 +184,8 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 3: if(MODREG) { d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
default: VEORQ(v0, v0, v0);
}
if((u8&0xf0)==0x10) { if((u8&0x0f)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
if(MODREG && ((u8&0xf0)==0x30)) { if((u8&0x0f)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
if((u8&0b10110000)==0x10) { if((u8&0b1011)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
if(MODREG && ((u8&0b10110000)==0x30)) { if((u8&0b1011)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, s0, -1);
switch((u8>>4)&0b1011) {
case 0: VMOVQ(v0, v2); break;
@@ -378,7 +378,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
ed = x1;
}
@@ -396,7 +395,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 1);
ed = x1;
}
@@ -414,7 +412,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
ed = x1;
}
@@ -436,7 +433,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
ed = x1;
}
@@ -497,7 +493,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
break;
case 0x1D:
INST_NAME("VCVTPS2PH Ex, Gx");
INST_NAME("VCVTPS2PH Ex, Gx, Ib");
nextop = F8;
GETGX(v0, 0);
if(MODREG) {
@@ -586,7 +582,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
YMM0(gd);
break;
case 0x22:
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
if (rex.w) {
INST_NAME("VPINSRQ Gx, Vx, ED, Ib");
} else {
INST_NAME("VPINSRD Gx, Vx, ED, Ib");
}
nextop = F8;
GETGX_empty_VX(v0, v2);
GETED(1);
@@ -662,7 +662,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
case 0x44:
INST_NAME("VPCLMULQDQ Gx, Vx, Ex, Ib");
nextop = F8;
if(arm64_pmull) {
if(cpuext.pmull) {
d0 = fpu_get_scratch(dyn, ninst);
for(int l=0; l<1+vex.l; ++l) {
if(!l) {
@@ -706,7 +706,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
u8 = F8;
MOV32w(x4, u8);
CALL_(vex.l?native_pclmul_y:native_pclmul_x, -1, x3);
CALL_(vex.l?const_native_pclmul_y:const_native_pclmul_x, -1, x3);
}
if(!vex.l) YMM0(gd);
break;
@@ -810,7 +810,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
}
u8 = F8;
MOV32w(x4, u8);
CALL(native_aeskeygenassist, -1);
CALL(const_native_aeskeygenassist, -1);
YMM0(gd);
break;
+20 -17
View File
@@ -144,12 +144,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGD;
GETEXSD(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
v0 = fpu_get_scratch(dyn, ninst);
if(rex.w) {
FRINT64ZD(v0, q0);
@@ -160,7 +160,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
} else {
FCVTZSxwD(gd, q0);
}
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -175,14 +175,14 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGD;
GETEXSD(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
u8 = sse_setround(dyn, ninst, x1, x2, x3);
d1 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
if(rex.w) {
FRINT64XD(d1, q0);
} else {
@@ -193,7 +193,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
}
x87_restoreround(dyn, ninst, u8);
FCVTZSxwD(gd, d1);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -496,9 +496,9 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x09: CSETMx(x2, cHI); break; // Less than or unordered
case 0x0a: CSETMx(x2, cCS); break; // Less or equal or unordered
case 0x0b: MOV32w(x2, 0); break; // false
case 0x0c: CSETMw(x2, cNE); CSETMx(x3, cVS); BICx(x2, x2, x3); break; // Not Equal not unordered
case 0x0d: CSETMw(x2, cLS); break; // Greater or equal not unordered
case 0x0e: CSETMw(x2, cCC); break; // Greater not unordered
case 0x0c: CSETMx(x2, cNE); CSETMx(x3, cVS); BICx(x2, x2, x3); break; // Not Equal not unordered
case 0x0d: CSETMx(x2, cLS); break; // Greater or equal not unordered
case 0x0e: CSETMx(x2, cCC); break; // Greater not unordered
case 0x0f: MOV64x(x2, 0xffffffffffffffffLL); break; // true
}
VMOVQDfrom(v0, 0, x2);
@@ -509,9 +509,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VADDSUBPS Gx, Vx, Ex");
nextop = F8;
q0 = fpu_get_scratch(dyn, ninst);
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
MAYUSE(addsubps);
MOV64x(x2, (uintptr_t)&addsubps);
TABLE64C(x2, const_4f_m1_1_m1_1);
VLDR128_U12(q0, x2, 0);
for(int l=0; l<1+vex.l; ++l) {
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
@@ -550,7 +548,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
else
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32XDQ(l?d0:v0, v1); // round, handling of overflow and Nan to 0x80000000
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
if(!l)
@@ -598,11 +596,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
VMOVQ(v0, v1);
}
} else {
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
VLDP128_I7(v0, v1, ed, fixedaddress);
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
if (vex.l) {
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f << 4, 15, rex, NULL, 1, 0);
VLDP128_I7(v0, v1, ed, fixedaddress);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff << 4, 15, rex, NULL, 0, 0);
VLD128(v0, ed, fixedaddress);
}
}
if(!vex.l) YMM0(gd);
break;
+8 -8
View File
@@ -81,7 +81,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETG;
if(MODREG) {
GETGXVXEX_empty(v0, v2, v1, 0);
GETGXVXEX_empty(v0, v1, v2, 0);
if((v2!=v1) && (v2!=v0)) VMOVQ(v2, v1);
if(v2!=v0) VMOVeS(v2, 0, v0, 0);
if((v2!=v1) && (v2==v0)) { VMOVeS(v2, 1, v0, 1); VMOVeD(v2, 1, v0, 1);}
@@ -144,12 +144,12 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGD;
GETEXSS(d0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
v0 = fpu_get_scratch(dyn, ninst);
if(rex.w) {
FRINT64ZS(v0, d0);
@@ -160,7 +160,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
} else {
FCVTZSxwS(gd, d0);
}
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -175,14 +175,14 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETGD;
GETEXSS(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
u8 = sse_setround(dyn, ninst, x1, x2, x3);
d1 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
if(rex.w) {
FRINT64XS(d1, q0);
} else {
@@ -193,7 +193,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
}
x87_restoreround(dyn, ninst, u8);
FCVTZSxwS(gd, d1);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -342,7 +342,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
if(BOX64ENV(dynarec_fastround)) {
VFCVTZSQS(v0, v1);
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32ZSQ(v0, v1);
VFCVTZSQS(v0, v0);
} else {
+143
View File
@@ -0,0 +1,143 @@
#include <stdint.h>
#include <string.h>
#include "dynarec_arm64_consts.h"
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "emu/x87emu_private.h"
#include "emu/x64primop.h"
#include "my_cpuid.h"
#include "freq.h"
#include "debug.h"
#include "custommem.h"
#include "dynarec_arm64_functions.h"
#include "emu/x64shaext.h"
#include "emu/x87emu_private.h"
#include "emu/x64compstrings.h"
#include "x64test.h"
#include "dynarec/dynarec_next.h"
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
static const float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
static const double addsubpd[2] = {-1., 1.};
static const float subaddps[4] = {1.f, -1.f, 1.f, -1.f};
static const double subaddpd[2] = {1., -1.};
#ifndef HAVE_TRACE
void PrintTrace() {}
#endif
uintptr_t getConst(arm64_consts_t which)
{
switch(which) {
case const_none: dynarec_log(LOG_NONE, "Warning, const none used\n");
return 0;
case const_daa8: return (uintptr_t)daa8;
case const_das8: return (uintptr_t)das8;
case const_aaa16: return (uintptr_t)aaa16;
case const_aas16: return (uintptr_t)aas16;
case const_aam16: return (uintptr_t)aam16;
case const_aad16: return (uintptr_t)aad16;
case const_native_br: return (uintptr_t)native_br;
case const_native_ud: return (uintptr_t)native_ud;
case const_native_priv: return (uintptr_t)native_priv;
case const_native_gpf: return (uintptr_t)native_gpf;
case const_native_int3: return (uintptr_t)native_int3;
case const_native_int: return (uintptr_t)native_int;
case const_native_div0: return (uintptr_t)native_div0;
case const_native_clflush: return (uintptr_t)native_clflush;
case const_native_frstor16: return (uintptr_t)native_frstor16;
case const_native_fsave16: return (uintptr_t)native_fsave16;
case const_native_fsave: return (uintptr_t)native_fsave;
case const_native_aesimc: return (uintptr_t)native_aesimc;
case const_native_aesd: return (uintptr_t)native_aesd;
case const_native_aesd_y: return (uintptr_t)native_aesd_y;
case const_native_aesdlast: return (uintptr_t)native_aesdlast;
case const_native_aesdlast_y: return (uintptr_t)native_aesdlast_y;
case const_native_aese: return (uintptr_t)native_aese;
case const_native_aese_y: return (uintptr_t)native_aese_y;
case const_native_aeselast: return (uintptr_t)native_aeselast;
case const_native_aeselast_y: return (uintptr_t)native_aeselast_y;
case const_native_aeskeygenassist: return (uintptr_t)native_aeskeygenassist;
case const_native_pclmul: return (uintptr_t)native_pclmul;
case const_native_pclmul_x: return (uintptr_t)native_pclmul_x;
case const_native_pclmul_y: return (uintptr_t)native_pclmul_y;
case const_native_f2xm1: return (uintptr_t)native_f2xm1;
case const_native_fyl2x: return (uintptr_t)native_fyl2x;
case const_native_fyl2xp1: return (uintptr_t)native_fyl2xp1;
case const_native_fxtract: return (uintptr_t)native_fxtract;
case const_native_ftan: return (uintptr_t)native_ftan;
case const_native_fpatan: return (uintptr_t)native_fpatan;
case const_native_fcos: return (uintptr_t)native_fcos;
case const_native_fsin: return (uintptr_t)native_fsin;
case const_native_fsincos: return (uintptr_t)native_fsincos;
case const_native_fscale: return (uintptr_t)native_fscale;
case const_native_fld: return (uintptr_t)native_fld;
case const_native_fstp: return (uintptr_t)native_fstp;
case const_native_frstor: return (uintptr_t)native_frstor;
case const_native_next: return (uintptr_t)native_next;
case const_int3: return (uintptr_t)EmuInt3;
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
case const_rcl16: return (uintptr_t)rcl16;
case const_rcl32: return (uintptr_t)rcl32;
case const_rcl64: return (uintptr_t)rcl64;
case const_rcr16: return (uintptr_t)rcr16;
case const_rcr32: return (uintptr_t)rcr32;
case const_rcr64: return (uintptr_t)rcr64;
case const_div64: return (uintptr_t)div64;
case const_idiv64: return (uintptr_t)idiv64;
case const_random32: return (uintptr_t)get_random32;
case const_random64: return (uintptr_t)get_random64;
case const_readtsc: return (uintptr_t)ReadTSC;
case const_helper_getcpu: return (uintptr_t)helper_getcpu;
case const_cpuid: return (uintptr_t)my_cpuid;
case const_getsegmentbase: return (uintptr_t)GetSegmentBaseEmu;
case const_updateflags_arm64: return (uintptr_t)create_updateflags();
case const_reset_fpu: return (uintptr_t)reset_fpu;
case const_sha1msg2: return (uintptr_t)sha1msg2;
case const_sha1rnds4: return (uintptr_t)sha1rnds4;
case const_sha256msg1: return (uintptr_t)sha256msg1;
case const_sha256msg2: return (uintptr_t)sha256msg2;
case const_sha256rnds2: return (uintptr_t)sha256rnds2;
case const_fpu_loadenv: return (uintptr_t)fpu_loadenv;
case const_fpu_savenv: return (uintptr_t)fpu_savenv;
case const_fpu_fxsave32: return (uintptr_t)fpu_fxsave32;
case const_fpu_fxsave64: return (uintptr_t)fpu_fxsave64;
case const_fpu_fxrstor32: return (uintptr_t)fpu_fxrstor32;
case const_fpu_fxrstor64: return (uintptr_t)fpu_fxrstor64;
case const_fpu_xsave: return (uintptr_t)fpu_xsave;
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
case const_x64test_step: return (uintptr_t)x64test_step;
case const_printtrace: return (uintptr_t)PrintTrace;
case const_epilog: return (uintptr_t)native_epilog;
case const_jmptbl32: return getJumpTable32();
case const_jmptbl48: return getJumpTable48();
case const_jmptbl64: return getJumpTable64();
case const_context: return (uintptr_t)my_context;
case const_8b_m7_m6_m5_m4_m3_m2_m1_0: return (uintptr_t)&mask_shift8;
case const_8b_7_6_5_4_3_2_1_0: return (uintptr_t)&mask_string8;
case const_8b_15_14_13_12_11_10_9_8: return (uintptr_t)&mask_string16;
case const_4f_m1_1_m1_1: return (uintptr_t)&addsubps;
case const_4f_1_m1_1_m1: return (uintptr_t)&subaddps;
case const_2d_m1_1: return (uintptr_t)&addsubpd;
case const_2d_1_m1: return (uintptr_t)&subaddpd;
case const_last: dynarec_log(LOG_NONE, "Warning, const last used\n");
return 0;
}
dynarec_log(LOG_NONE, "Warning, Unknown const %d used\n", which);
return 0;
}
+110
View File
@@ -0,0 +1,110 @@
#ifndef __DYNAREC_ARM64_CONSTS__
#define __DYNAREC_ARM64_CONSTS__
#include <stdint.h>
typedef enum arm64_consts_s {
const_none,
const_daa8,
const_das8,
const_aaa16,
const_aas16,
const_aam16,
const_aad16,
const_native_br,
const_native_ud,
const_native_priv,
const_native_gpf,
const_native_int3,
const_native_int,
const_native_div0,
const_native_clflush,
const_native_frstor16,
const_native_fsave16,
const_native_fsave,
const_native_aesimc,
const_native_aesd,
const_native_aesd_y,
const_native_aesdlast,
const_native_aesdlast_y,
const_native_aese,
const_native_aese_y,
const_native_aeselast,
const_native_aeselast_y,
const_native_aeskeygenassist,
const_native_pclmul,
const_native_pclmul_x,
const_native_pclmul_y,
const_native_f2xm1,
const_native_fyl2x,
const_native_fyl2xp1,
const_native_fxtract,
const_native_ftan,
const_native_fpatan,
const_native_fcos,
const_native_fsin,
const_native_fsincos,
const_native_fscale,
const_native_fld,
const_native_fstp,
const_native_frstor,
const_native_next,
const_int3,
const_x86syscall,
const_x64syscall,
const_rcl16,
const_rcl32,
const_rcl64,
const_rcr16,
const_rcr32,
const_rcr64,
const_div64,
const_idiv64,
const_random32,
const_random64,
const_readtsc,
const_helper_getcpu,
const_cpuid,
const_getsegmentbase,
const_updateflags_arm64,
const_reset_fpu,
const_sha1msg2,
const_sha1rnds4,
const_sha256msg1,
const_sha256msg2,
const_sha256rnds2,
const_fpu_loadenv,
const_fpu_savenv,
const_fpu_fxsave32,
const_fpu_fxsave64,
const_fpu_fxrstor32,
const_fpu_fxrstor64,
const_fpu_xsave,
const_fpu_xrstor,
const_fpu_fbld,
const_fpu_fbst,
const_sse42_compare_string_explicit_len,
const_sse42_compare_string_implicit_len,
const_x64test_step,
const_printtrace,
const_epilog,
const_jmptbl32,
const_jmptbl48,
const_jmptbl64,
const_context,
const_8b_m7_m6_m5_m4_m3_m2_m1_0,
const_8b_7_6_5_4_3_2_1_0,
const_8b_15_14_13_12_11_10_9_8,
const_4f_m1_1_m1_1,
const_2d_m1_1,
const_4f_1_m1_1_m1,
const_2d_1_m1,
const_last
} arm64_consts_t;
uintptr_t getConst(arm64_consts_t which);
// temporary define...
#define const_PrintTrace const_printtrace
#endif //__DYNAREC_ARM64_CONSTS__
+16 -41
View File
@@ -271,7 +271,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
MESSAGE(LOG_DUMP, "Need Optimization (F2XM1)\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
CALL(native_f2xm1, -1);
CALL(const_native_f2xm1, -1);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xF1:
@@ -280,7 +280,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fyl2x, -1);
CALL(const_native_fyl2x, -1);
x87_unstackcount(dyn, ninst, x1, i1);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
@@ -291,7 +291,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
CALL_(const_native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
x87_unstackcount(dyn, ninst, x1, i1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
@@ -316,7 +316,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 1);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
CALL_(const_native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
@@ -328,19 +328,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fxtract, -1);
CALL(const_native_fxtract, -1);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xF5:
INST_NAME("FPREM1");
#if 0
MESSAGE(LOG_DUMP, "Need Optimization\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fprem1, -1);
x87_unstackcount(dyn, ninst, x1, i1);
#else
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
@@ -361,11 +353,10 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
#endif
break;
case 0xF6:
INST_NAME("FDECSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
SUBw_U12(x2, x2, 1);
ANDw_mask(x2, x2, 0, 2); //mask=7
@@ -373,7 +364,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xF7:
INST_NAME("FINCSTP");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
ADDw_U12(x2, x2, 1);
ANDw_mask(x2, x2, 0, 2); //mask=7
@@ -381,14 +372,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xF8:
INST_NAME("FPREM");
#if 0
MESSAGE(LOG_DUMP, "Need Optimization\n");
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fprem, -1);
x87_unstackcount(dyn, ninst, x1, i1);
#else
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
@@ -409,7 +392,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
#endif
break;
case 0xF9:
INST_NAME("FYL2XP1");
@@ -417,7 +399,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
i1 = x87_stackcount(dyn, ninst, x1);
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
CALL(native_fyl2xp1, -1);
CALL(const_native_fyl2xp1, -1);
x87_unstackcount(dyn, ninst, x1, i1);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
@@ -443,19 +425,13 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 1);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
CALL_(const_native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
break;
case 0xFC:
INST_NAME("FRNDINT");
#if 0
MESSAGE(LOG_DUMP, "Need Optimization\n");
// use C helper for now, nothing staightforward is available
x87_forget(dyn, ninst, x1, x2, 0);
CALL(native_frndint, -1);
#else
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
u8 = x87_setround(dyn, ninst, x1, x2, x3);
if(ST_IS_F(0)) {
@@ -464,7 +440,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
FRINTID(v1, v1);
}
x87_restoreround(dyn, ninst, u8);
#endif
break;
case 0xFD:
INST_NAME("FSCALE");
@@ -474,7 +449,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 1);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
CALL_(const_native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
@@ -486,7 +461,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
CALL_(const_native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
@@ -498,7 +473,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_(native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
CALL_(const_native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
x87_unstackcount(dyn, ninst, x1, i1);
@@ -550,13 +525,13 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("FLDENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FLDENV)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
BARRIER(BARRIER_FLOAT); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {
MOVx_REG(x1, ed);
}
MOV32w(x2, 0);
CALL(fpu_loadenv, -1);
CALL(const_fpu_loadenv, -1);
NATIVE_RESTORE_X87PC();
break;
case 5:
@@ -569,13 +544,13 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 6:
INST_NAME("FNSTENV Ed");
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
BARRIER(BARRIER_FLOAT); // maybe only x87, not SSE?
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {
MOVx_REG(x1, ed);
}
MOV32w(x2, 0);
CALL(fpu_savenv, -1);
CALL(const_fpu_savenv, -1);
break;
case 7:
INST_NAME("FNSTCW Ew");
+18 -14
View File
@@ -133,7 +133,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("FNINIT");
MESSAGE(LOG_DUMP, "Need Optimization (FNINIT)\n");
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
CALL(reset_fpu, -1);
CALL(const_reset_fpu, -1);
NATIVE_RESTORE_X87PC();
break;
case 0xE8:
@@ -148,10 +148,12 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
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)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
break;
@@ -167,10 +169,12 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
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)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0)) {
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
break;
@@ -193,7 +197,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
s0 = fpu_get_scratch(dyn, ninst);
if(arm64_frintts) {
if(cpuext.frintts) {
FRINT32ZD(s0, v1);
FCVTZSwD(x5, s0);
STW(x5, wback, fixedaddress);
@@ -223,7 +227,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
s0 = fpu_get_scratch(dyn, ninst);
if(arm64_frintts) {
if(cpuext.frintts) {
FRINT32XD(s0, v1);
FCVTZSwD(x5, s0);
STW(x5, wback, fixedaddress);
@@ -253,7 +257,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
s0 = fpu_get_scratch(dyn, ninst);
if(arm64_frintts) {
if(cpuext.frintts) {
FRINT32XD(s0, v1);
FCVTZSwD(x5, s0);
STW(x5, wback, fixedaddress);
@@ -309,7 +313,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
// sync top
x87_reflectcount(dyn, ninst, x3, x4);
CALL(native_fld, -1);
CALL(const_native_fld, -1);
// go back with the top & stack counter
x87_unreflectcount(dyn, ninst, x3, x4);
}
@@ -327,7 +331,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
x87_reflectcount(dyn, ninst, x3, x4);
CALL(native_fstp, -1);
CALL(const_native_fstp, -1);
x87_unreflectcount(dyn, ninst, x3, x4);
} else {
// Painfully long, straight conversion from the C code, shoud be optimized
+5 -14
View File
@@ -49,7 +49,6 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xC6:
case 0xC7:
INST_NAME("FFREE STx");
#if 1
if((nextop&7)==0 && PK(0)==0xD9 && PK(1)==0xF7) {
MESSAGE(LOG_DUMP, "Hack for FFREE ST0 / FINCSTP\n");
x87_do_pop(dyn, ninst, x1);
@@ -57,12 +56,6 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SKIPTEST(x1);
} else
x87_free(dyn, ninst, x1, x2, x3, nextop&7);
#else
MESSAGE(LOG_DUMP, "Need Optimization\n");
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
MOV32w(x1, nextop&7);
CALL(fpu_do_free, -1);
#endif
break;
case 0xD0:
case 0xD1:
@@ -157,7 +150,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
VST64(v1, ed, fixedaddress);
} else {
s0 = fpu_get_scratch(dyn, ninst);
if(arm64_frintts) {
if(cpuext.frintts) {
FRINT64ZD(s0, v1);
VFCVTZSd(s0, s0);
VST64(s0, ed, fixedaddress);
@@ -193,24 +186,22 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("FRSTOR m108byte");
MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(native_frstor, -1);
CALL(const_native_frstor, -1);
break;
case 6:
INST_NAME("FNSAVE m108byte");
MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE)\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(native_fsave, -1);
CALL(reset_fpu, -1);
CALL(const_native_fsave, -1);
NATIVE_RESTORE_X87PC();
break;
case 7:
INST_NAME("FNSTSW m2byte");
//fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
+17 -13
View File
@@ -101,11 +101,13 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
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))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
X87_POP_OR_FAIL(dyn, ninst, x3);
@@ -122,11 +124,13 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
SETFLAGS(X_ALL, SF_SET);
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))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
IFX(X_CF|X_PF|X_ZF) {
if(ST_IS_F(0))
{
FCMPS(v1, v2);
} else {
FCMPD(v1, v2);
}
}
FCOMI(x1, x2);
X87_POP_OR_FAIL(dyn, ninst, x3);
@@ -273,7 +277,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
s0 = x87_stackcount(dyn, ninst, x3);
CALL(fpu_fbld, -1);
CALL(const_fpu_fbld, -1);
x87_unstackcount(dyn, ninst, x3, s0);
break;
case 5:
@@ -310,7 +314,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
x87_forget(dyn, ninst, x1, x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
CALL(fpu_fbst, -1);
CALL(const_fpu_fbst, -1);
x87_unstackcount(dyn, ninst, x1, i1);
X87_POP_OR_FAIL(dyn, ninst, x3);
break;
@@ -354,7 +358,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
B_MARK3(c__);
MARK2;
}
if(arm64_frintts) {
if(cpuext.frintts) {
FRINT64XD(s0, v1);
VFCVTZSd(s0, s0);
VST64(s0, wback, fixedaddress);
+4 -4
View File
@@ -451,7 +451,7 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
BICw_REG(xFlags, xFlags, s3);
}
if(arm64_flagm) {
if(cpuext.flagm) {
COMP_ZFSF(s1, 8)
} else {
IFX(X_ZF) {
@@ -496,7 +496,7 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
BICw(xFlags, xFlags, s3);
}
if(arm64_flagm) {
if(cpuext.flagm) {
COMP_ZFSF(s1, 8)
} else {
IFX(X_ZF) {
@@ -639,7 +639,7 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
BICw_REG(xFlags, xFlags, s3);
}
if(arm64_flagm) {
if(cpuext.flagm) {
COMP_ZFSF(s1, 16)
} else {
IFX(X_ZF) {
@@ -684,7 +684,7 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
BICw(xFlags, xFlags, s3);
}
if(arm64_flagm) {
if(cpuext.flagm) {
COMP_ZFSF(s1, 16)
} else {
IFX(X_ZF) {
+6 -6
View File
@@ -991,7 +991,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
}
IFNATIVE_BEFORE(NF_CF) {
if(INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(s3);
@@ -1134,7 +1134,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
IFNATIVE_BEFORE(NF_CF) {
if(INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(s3);
@@ -1198,7 +1198,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
IFNATIVE_BEFORE(NF_CF) {
if(INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(s3);
@@ -1321,7 +1321,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
}
IFNATIVE_BEFORE(NF_CF) {
if(!INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(s3);
@@ -1470,7 +1470,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
IFNATIVE_BEFORE(NF_CF) {
if(!INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(s3);
@@ -1535,7 +1535,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
}
IFNATIVE_BEFORE(NF_CF) {
if(!INVERTED_CARRY_BEFORE) {
if(arm64_flagm)
if(cpuext.flagm)
CFINV();
else {
MRS_nzcv(s3);
File diff suppressed because it is too large. Load diff
+12 -15
View File
@@ -118,12 +118,12 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGD;
GETEXSD(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
v0 = fpu_get_scratch(dyn, ninst);
if(rex.w) {
FRINT64ZD(v0, q0);
@@ -134,7 +134,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
FCVTZSxwD(gd, q0);
}
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -149,14 +149,14 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGD;
GETEXSD(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
u8 = sse_setround(dyn, ninst, x1, x2, x3);
d1 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
if(rex.w) {
FRINT64XD(d1, q0);
} else {
@@ -167,7 +167,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
x87_restoreround(dyn, ninst, u8);
FCVTZSxwD(gd, d1);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -187,7 +187,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETEB(x1, 0);
GETGD;
if(arm64_crc32) {
if(cpuext.crc32) {
CRC32CB(gd, gd, ed);
} else {
EORw_REG(gd, gd, ed);
@@ -204,7 +204,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETED(0);
GETGD;
if(arm64_crc32) {
if(cpuext.crc32) {
CRC32Cxw(gd, gd, ed);
} else {
MOV32w(x2, 0x82f63b78);
@@ -430,7 +430,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("HSUBPS Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 1);
GETEX(v1, 0, 0);
d0 = fpu_get_scratch(dyn, ninst);
VUZP1Q_32(d0, v0, v1);
VUZP2Q_32(v0, v0, v1);
@@ -456,7 +456,6 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
j64 = (uint32_t)(addr+i32_); \
else \
j64 = addr+i32_; \
BARRIER(BARRIER_MAYBE); \
JUMP(j64, 1); \
GETFLAGS; \
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
@@ -469,7 +468,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
} else { \
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
CacheTransform(dyn, ninst, cacheupd); \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
SKIP_SEVL(i32); \
B(i32); \
@@ -523,9 +522,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETGX(v0, 1);
GETEX(v1, 0, 0);
q0 = fpu_get_scratch(dyn, ninst);
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
MAYUSE(addsubps);
MOV64x(x2, (uintptr_t)&addsubps); // no need to use table64, as box64 is loaded in low memory
TABLE64C(x2, const_4f_m1_1_m1_1);
VLDR128_U12(q0, x2, 0);
VFMLAQS(v0, v1, q0);
break;
@@ -551,7 +548,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
} else {
u8 = sse_setround(dyn, ninst, x1, x2, x3);
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32XDQ(v0, v1); // round, handling of overflow and Nan to 0x80000000
VFCVTNSQD(v0, v0); // convert double -> int64
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
+8 -8
View File
@@ -6,11 +6,11 @@
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64run_private.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
@@ -119,12 +119,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGD;
GETEXSS(d0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
v0 = fpu_get_scratch(dyn, ninst);
if(rex.w) {
FRINT64ZS(v0, d0);
@@ -135,7 +135,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
FCVTZSxwS(gd, d0);
}
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -150,14 +150,14 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGD;
GETEXSS(q0, 0, 0);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5);
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
MSR_fpsr(x5);
}
u8 = sse_setround(dyn, ninst, x1, x2, x3);
d1 = fpu_get_scratch(dyn, ninst);
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
if(rex.w) {
FRINT64XS(d1, q0);
} else {
@@ -168,7 +168,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
}
x87_restoreround(dyn, ninst, u8);
FCVTZSxwS(gd, d1);
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
MRS_fpsr(x5); // get back FPSR to check the IOC bit
TBZ_NEXT(x5, FPSR_IOC);
if(rex.w) {
@@ -322,7 +322,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(BOX64ENV(dynarec_fastround)) {
VFCVTZSQS(v0, v1);
} else {
if(arm64_frintts) {
if(cpuext.frintts) {
VFRINT32ZSQ(v0, v1);
VFCVTZSQS(v0, v0);
} else {
+194 -37
View File
@@ -4,7 +4,6 @@
#include <errno.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
@@ -182,7 +181,6 @@ int is_ymm_to_keep(dynarec_arm_t* dyn, int reg, int k1, int k2, int k3)
// Reset fpu regs counter
static void fpu_reset_reg_neoncache(neoncache_t* n)
{
n->fpu_reg = 0;
for (int i=0; i<32; ++i) {
n->fpuused[i]=0;
n->neoncache[i].v = 0;
@@ -563,7 +561,6 @@ void neoncacheUnwind(neoncache_t* cache)
// And now, rebuild the x87cache info with neoncache
cache->mmxcount = 0;
cache->fpu_scratch = 0;
cache->fpu_reg = 0;
for(int i=0; i<8; ++i) {
cache->x87cache[i] = -1;
cache->mmxcache[i] = -1;
@@ -579,13 +576,11 @@ void neoncacheUnwind(neoncache_t* cache)
case NEON_CACHE_MM:
cache->mmxcache[cache->neoncache[i].n] = i;
++cache->mmxcount;
++cache->fpu_reg;
break;
case NEON_CACHE_XMMR:
case NEON_CACHE_XMMW:
cache->ssecache[cache->neoncache[i].n].reg = i;
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
++cache->fpu_reg;
break;
case NEON_CACHE_YMMR:
case NEON_CACHE_YMMW:
@@ -597,7 +592,6 @@ void neoncacheUnwind(neoncache_t* cache)
cache->x87cache[x87reg] = cache->neoncache[i].n;
cache->x87reg[x87reg] = i;
++x87reg;
++cache->fpu_reg;
break;
case NEON_CACHE_SCR:
cache->fpuused[i] = 0;
@@ -617,7 +611,6 @@ void neoncacheUnwind(neoncache_t* cache)
cache->neoncache[reg].n = i;
cache->ssecache[i].reg = reg;
cache->ssecache[i].write = (cache->xmm_write&(1<<i))?1:0;
++cache->fpu_reg;
}
cache->xmm_write = cache->xmm_removed = 0;
}
@@ -777,10 +770,17 @@ static register_mapping_t register_mappings[] = {
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
{
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) {
/*zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
if(dec && !OpcodeOK(dec, dyn->insts[ninst].x64.addr) && !strstr(name, "Illegal")) {
uint8_t* p = (uint8_t*)dyn->insts[ninst].x64.addr;
printf_log(LOG_INFO, "Warning: %p invalid opcode %02x %02x %02x %02x %02x %02x treated as valid\n", p, p[0], p[1], p[2], p[3], p[4], p[5]);
}*/
return;
}
static char buf[4096];
int length = sprintf(buf, "barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
int length = sprintf(buf, "barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
dyn->insts[ninst].x64.barrier,
dyn->insts[ninst].x64.state_flags,
dyn->f.pending,
@@ -795,7 +795,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
dyn->insts[ninst].x64.use_flags,
dyn->insts[ninst].x64.need_before,
dyn->insts[ninst].x64.need_after,
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock);
if (dyn->insts[ninst].nat_flags_op) {
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
@@ -1155,6 +1155,7 @@ void updateNativeFlags(dynarec_native_t* dyn)
void rasNativeState(dynarec_arm_t* dyn, int ninst)
{
dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].set_nat_flags = dyn->insts[ninst].use_nat_flags = dyn->insts[ninst].need_nat_flags = 0;
dyn->insts[ninst].ymm0_in = dyn->insts[ninst].ymm0_sub = dyn->insts[ninst].ymm0_add = dyn->insts[ninst].ymm0_out = dyn->insts[ninst].purge_ymm = 0;
}
int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
@@ -1196,30 +1197,21 @@ void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache)
memcpy(&dyn->insts[ninst].n, cache, sizeof(neoncache_t));
}
static void propagateXMMUneeded(dynarec_arm_t* dyn, int ninst, int a)
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
{
if(!ninst) return;
ninst = getNominalPred(dyn, ninst);
while(ninst>=0) {
if(dyn->insts[ninst].n.xmm_used&(1<<a)) return; // used, value is needed
mask_x &= ~dyn->insts[ninst].n.xmm_used;
mask_y &= ~dyn->insts[ninst].n.ymm_used;
if(!mask_x && !mask_y) return; // used, value is needed
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return; // barrier, value is needed
if(dyn->insts[ninst].n.xmm_unneeded&(1<<a)) return; // already handled
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
if(!mask_x && !mask_y) return; // already handled
if(dyn->insts[ninst].x64.jmp) return; // stop when a jump is detected, that gets too complicated
dyn->insts[ninst].n.xmm_unneeded |= (1<<a); // flags
ninst = getNominalPred(dyn, ninst); // continue
}
}
static void propagateYMMUneeded(dynarec_arm_t* dyn, int ninst, int a)
{
if(!ninst) return;
ninst = getNominalPred(dyn, ninst);
while(ninst>=0) {
if(dyn->insts[ninst].n.ymm_used&(1<<a)) return; // used, value is needed
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return; // barrier, value is needed
if(dyn->insts[ninst].n.ymm_unneeded&(1<<a)) return; // already handled
if(dyn->insts[ninst].x64.jmp) return; // stop when a jump is detected, that gets too complicated
dyn->insts[ninst].n.ymm_unneeded |= (1<<a); // flags
dyn->insts[ninst].n.xmm_unneeded |= mask_x; // flags
dyn->insts[ninst].n.ymm_unneeded |= mask_y; // flags
ninst = getNominalPred(dyn, ninst); // continue
}
}
@@ -1227,13 +1219,178 @@ static void propagateYMMUneeded(dynarec_arm_t* dyn, int ninst, int a)
void updateUneeded(dynarec_arm_t* dyn)
{
for(int ninst=0; ninst<dyn->size; ++ninst) {
if(dyn->insts[ninst].n.xmm_unneeded)
for(int i=0; i<16; ++i)
if(dyn->insts[ninst].n.xmm_unneeded&(1<<i))
propagateXMMUneeded(dyn, ninst, i);
if(dyn->insts[ninst].n.ymm_unneeded)
for(int i=0; i<16; ++i)
if(dyn->insts[ninst].n.ymm_unneeded&(1<<i))
propagateYMMUneeded(dyn, ninst, i);
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded)
propagateXYMMUneeded(dyn, ninst, dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
}
}
}
void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
{
// there is a barrier at ninst
// check if, up to last fpu_used, if there is some suspicious jump that would prevent the barrier to be put earlier
int usefull = 0;
for(int i=ninst-1; i>last_fpu_used; --i)
{
if(!dyn->insts[i].x64.has_next)
return; // break of chain, don't try to be smart for now
if(dyn->insts[i].x64.barrier&BARRIER_FLOAT)
return; // already done?
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts==-1)
usefull = 1;
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1) {
int i2 = dyn->insts[i].x64.jmp_insts;
if(i2<last_fpu_used || i2>ninst) {
// check if some xmm/ymm/x87 stack are used in landing point
if(i2>ninst) {
if(dyn->insts[i2].n.xmm_used || dyn->insts[i2].n.ymm_used || dyn->insts[i2].n.stack)
return;
}
// we will stop there, not trying to guess too much thing
if((usefull && (i+1)!=ninst)) {
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
}
return;
}
usefull = 1;
}
for(int pred=0; pred<dyn->insts[i].pred_sz; ++pred) {
if(dyn->insts[i].pred[pred]<=last_fpu_used) {
if(usefull && ((i+1)!=ninst)) {
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
}
return;
}
}
if(dyn->insts[i].pred_sz>1)
usefull = 1;
}
if(usefull) {
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
dyn->insts[last_fpu_used+1].x64.barrier|=BARRIER_FLOAT;
}
}
void propagateFpuBarrier(dynarec_arm_t* dyn)
{
int last_fpu_used = -1;
for(int ninst=0; ninst<dyn->size; ++ninst) {
int fpu_used = dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].mmx_used || dyn->insts[ninst].x87_used;
if(fpu_used) last_fpu_used = ninst;
dyn->insts[ninst].fpu_used = fpu_used;
if(dyn->insts[ninst].fpupurge && (last_fpu_used!=-1) && (last_fpu_used!=(ninst-1))) {
tryEarlyFpuBarrier(dyn, last_fpu_used, ninst);
last_fpu_used = -1; // reset the last_fpu_used...
}
}
}
void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
{
int can_incr = ninst == max_ninst_reached; // Are we the top-level call?
int ok = 1;
while ((can_incr || ok) && ninst < dyn->size) {
// if(dyn->need_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
if (dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
// The union of the empty set is empty (0), the intersection is the universe (-1)
// The first instruction is the entry point, which has a virtual pred with ymm0_out = 0
// Similarly, float barriers reset ymm0s
uint16_t ymm0_union = 0;
uint16_t ymm0_inter = (ninst && !(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? ((uint16_t)-1) : (uint16_t)0;
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
int pred = dyn->insts[ninst].pred[i];
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
if (pred >= max_ninst_reached) {
// if(dyn->need_dump) dynarec_log(LOG_NONE, " (skipped)\n");
continue;
}
int pred_out = dyn->insts[pred].x64.has_callret ? 0 : dyn->insts[pred].ymm0_out;
// if(dyn->need_dump) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
ymm0_union |= pred_out;
ymm0_inter &= pred_out;
}
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
// Notice the default values yield something coherent here (if all pred are after ninst)
new_purge_ymm = ymm0_union & ~ymm0_inter;
new_ymm0_in = ymm0_inter;
new_ymm0_out = (ymm0_inter | dyn->insts[ninst].ymm0_add) & ~dyn->insts[ninst].ymm0_sub;
if ((dyn->insts[ninst].purge_ymm != new_purge_ymm) || (dyn->insts[ninst].ymm0_in != new_ymm0_in) || (dyn->insts[ninst].ymm0_out != new_ymm0_out)) {
// Need to update self and next(s)
dyn->insts[ninst].purge_ymm = new_purge_ymm;
dyn->insts[ninst].ymm0_in = new_ymm0_in;
dyn->insts[ninst].ymm0_out = new_ymm0_out;
if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
++max_ninst_reached;
} else {
// We need to stop here if the opcode has no "real" next or if we reached the ninst of the toplevel
ok = (max_ninst_reached - 1 != ninst) && dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].x64.has_callret;
}
int jmp = (dyn->insts[ninst].x64.jmp) ? dyn->insts[ninst].x64.jmp_insts : -1;
if ((jmp != -1) && (jmp < max_ninst_reached)) {
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
// The jump goes before the last instruction reached, update the destination
// If this is the top level call, this means the jump goes backward (jmp != ninst)
// Otherwise, since we don't update all instructions, we may miss the update (don't use jmp < ninst)
updateYmm0s(dyn, jmp, max_ninst_reached);
}
} else {
if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
++max_ninst_reached;
// Also update jumps to before (they are skipped otherwise)
int jmp = (dyn->insts[ninst].x64.jmp) ? dyn->insts[ninst].x64.jmp_insts : -1;
if ((jmp != -1) && (jmp < max_ninst_reached)) {
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
updateYmm0s(dyn, jmp, max_ninst_reached);
}
} else {
// We didn't update anything, we can leave
ok = 0;
}
}
} else if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
++max_ninst_reached;
} else {
// We didn't update anything, we can leave
ok = 0;
}
++ninst;
}
}
// AVX helpers
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
{
dyn->ymm_zero |= (1<<reg);
}
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg)
{
return (dyn->ymm_zero>>reg)&1;
}
int is_avx_zero_unset(dynarec_arm_t* dyn, int ninst, int reg)
{
if((dyn->ymm_zero>>reg)&1) {
dyn->ymm_zero &= ~(1<<reg);
return 1;
}
return 0;
}
void avx_mark_zero_reset(dynarec_arm_t* dyn, int ninst)
{
dyn->ymm_zero = 0;
}
@@ -86,7 +86,17 @@ void fpu_reset_ninst(dynarec_native_t* dyn, int ninst);
// is st freed
int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st);
// propage FPU_BARRIER to trigger it as soon as possible (avoiding fetching an FPU reg if it's unused)
void propagateFpuBarrier(dynarec_arm_t* dyn);
// propage the uneeded flags on XMM/YMM regs (done between step 0 and step 1)
void updateUneeded(dynarec_arm_t* dyn);
void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached);
// AVX helpers
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg);
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg);
int is_avx_zero_unset(dynarec_arm_t* dyn, int ninst, int reg);
void avx_mark_zero_reset(dynarec_arm_t* dyn, int ninst);
#endif //__DYNAREC_ARM_FUNCTIONS_H__
+160 -143
View File
@@ -31,8 +31,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
if (l == LOCK_LOCK) {
dyn->insts[ninst].lock_prefixed = 1;
DMB_ISH();
dyn->insts[ninst].lock = 1;
}
if(rex.is32bits)
@@ -101,7 +100,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
} else if(tmp<0 && tmp>-0x1000) {
GETIP(addr+delta);
SUBx_U12(ret, xRIP, -tmp);
} else if(tmp+addr+delta<0x1000000000000LL) { // 3 opcodes to load immediate is cheap enough
} else if((tmp+addr+delta<0x1000000000000LL) && !dyn->need_reloc) { // 3 opcodes to load immediate is cheap enough
MOV64x(ret, tmp+addr+delta);
} else {
MOV64x(ret, tmp);
@@ -560,62 +559,91 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
GETIP_(ip);
}
NOTEST(x2);
TABLE64(x2, (uintptr_t)arm64_epilog);
TABLE64C(x2, const_epilog);
SMEND();
BR(x2);
}
static int indirect_lookup(dynarec_arm_t* dyn, int ninst, int is32bits, int s1, int s2)
{
MAYUSE(dyn);
if (!is32bits) {
// check higher 48bits
LSRx_IMM(s1, xRIP, 48);
intptr_t j64 = (intptr_t)dyn->jmp_next - (intptr_t)dyn->block;
CBNZw(s1, j64);
// load table
if(dyn->need_reloc) {
TABLE64C(s2, const_jmptbl48);
} else {
MOV64x(s2, getConst(const_jmptbl48)); // this is a static value, so will be a low address
}
#ifdef JMPTABL_SHIFT4
UBFXx(s1, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
LDRx_REG_LSL3(s2, s2, s1);
#endif
UBFXx(s1, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
LDRx_REG_LSL3(s2, s2, s1);
} else {
// check higher 32bits disabled
// LSRx_IMM(s1, xRIP, 32);
// intptr_t j64 = (intptr_t)dyn->jmp_next - (intptr_t)dyn->block;
// CBNZw(s1, j64);
// load table
TABLE64C(s2, const_jmptbl32);
#ifdef JMPTABL_SHIFT4
UBFXx(s1, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
LDRx_REG_LSL3(s2, s2, s1);
#endif
}
UBFXx(s1, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
LDRx_REG_LSL3(s2, s2, s1);
UBFXx(s1, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
LDRx_REG_LSL3(s1, s2, s1);
return s1;
}
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits)
{
MAYUSE(dyn); MAYUSE(ninst);
MAYUSE(dyn);
MAYUSE(ninst);
MESSAGE(LOG_DUMP, "Jump to next\n");
if(is32bits)
if (is32bits)
ip &= 0xffffffffLL;
SMEND();
if(reg) {
if(reg!=xRIP) {
int dest;
if (reg) {
if (reg != xRIP) {
MOVx_REG(xRIP, reg);
}
NOTEST(x2);
uintptr_t tbl = is32bits?getJumpTable32():getJumpTable64();
MAYUSE(tbl);
MOV64x(x3, tbl);
if(!is32bits) {
#ifdef JMPTABL_SHIFT4
UBFXx(x2, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
LDRx_REG_LSL3(x3, x3, x2);
#endif
UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
LDRx_REG_LSL3(x3, x3, x2);
}
UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
LDRx_REG_LSL3(x3, x3, x2);
UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
LDRx_REG_LSL3(x3, x3, x2);
UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
LDRx_REG_LSL3(x2, x3, x2);
dest = indirect_lookup(dyn, ninst, is32bits, x2, x3);
} else {
NOTEST(x2);
uintptr_t p = getJumpTableAddress64(ip);
MAYUSE(p);
MOV64x(x3, p);
if(dyn->need_reloc) AddRelocTable64JmpTbl(dyn, ninst, ip, STEP);
TABLE64_(x3, p);
GETIP_(ip);
LDRx_U12(x2, x3, 0);
dest = x2;
}
if(reg!=x1) {
MOVx_REG(x1, xRIP);
}
CLEARIP();
#ifdef HAVE_TRACE
//MOVx(x3, 15); no access to PC reg
BLR(x2); // save LR...
BLR(dest); // save LR...
#else
if (dyn->insts[ninst].x64.has_callret) {
BLR(x2); // save LR...
BLR(dest); // save LR...
} else {
BR(x2);
BR(dest);
}
#endif
}
@@ -636,27 +664,12 @@ void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
SUBx_U12(xSP, xSavedSP, 16);
}
uintptr_t tbl = rex.is32bits?getJumpTable32():getJumpTable64();
NOTEST(x2);
MOV64x(x2, tbl);
if(!rex.is32bits) {
#ifdef JMPTABL_SHIFT4
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
LDRx_REG_LSL3(x2, x2, x3);
#endif
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
LDRx_REG_LSL3(x2, x2, x3);
}
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
LDRx_REG_LSL3(x2, x2, x3);
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
LDRx_REG_LSL3(x2, x2, x3);
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
LDRx_REG_LSL3(x2, x2, x3);
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
#ifdef HAVE_TRACE
BLR(x2);
BLR(dest);
#else
BR(x2);
BR(dest);
#endif
CLEARIP();
}
@@ -683,27 +696,12 @@ void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int
// not the correct return address, regular jump
SUBx_U12(xSP, xSavedSP, 16);
}
uintptr_t tbl = rex.is32bits?getJumpTable32():getJumpTable64();
NOTEST(x2);
MOV64x(x2, tbl);
if(!rex.is32bits) {
#ifdef JMPTABL_SHIFT4
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
LDRx_REG_LSL3(x2, x2, x3);
#endif
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
LDRx_REG_LSL3(x2, x2, x3);
}
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
LDRx_REG_LSL3(x2, x2, x3);
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
LDRx_REG_LSL3(x2, x2, x3);
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
LDRx_REG_LSL3(x2, x2, x3);
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
#ifdef HAVE_TRACE
BLR(x2);
BLR(dest);
#else
BR(x2);
BR(dest);
#endif
CLEARIP();
}
@@ -720,49 +718,70 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i
// POP IP
NOTEST(x2);
if(is64bits) {
POP1(xRIP);
POP1(x1);
POP1(x2);
POP1(xFlags);
POP1(x3);
} else {
POP1_32(xRIP);
POP1_32(x1);
POP1_32(x2);
POP1_32(xFlags);
POP1_32(x3);
}
// x2 is CS
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
// check CS is NULL, sgfault if it is
CBZw_MARK3(x1);
// clean EFLAGS
MOV32w(x1, 0x3F7FD7);
ANDx_REG(xFlags, xFlags, x1);
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); // xFlags | 0b10
MOV32w(x4, 0x3F7FD7);
ANDx_REG(x3, x3, x4);
ORRx_mask(x3, x3, 1, 0b111111, 0); // xFlags | 0b10
SET_DFNONE();
if(is32bits) {
ANDw_mask(x2, x2, 0, 7); // mask 0xff
ANDw_mask(x4, x2, 0, 7); // mask 0xff
// check if return segment is 64bits, then restore rsp too
CMPSw_U12(x2, 0x23);
CMPSw_U12(x4, 0x23);
B_MARKSEG(cEQ);
}
// POP RSP
if(is64bits) {
POP1(x3); //rsp
POP1(x2); //ss
POP1(x4); //rsp
POP1(x5); //ss
} else {
POP1_32(x3); //rsp
POP1_32(x2); //ss
POP1_32(x4); //rsp
POP1_32(x5); //ss
}
// check if SS is NULL
CBZw_MARK(x5);
// POP SS
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
STRH_U12(x5, xEmu, offsetof(x64emu_t, segs[_SS]));
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
// set new RSP
MOVx_REG(xRSP, x3);
MOVx_REG(xRSP, x4);
MARKSEG;
// x2 is CS, x1 is IP, x3 is eFlags
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
MOVx_REG(xRIP, x1);
MOVw_REG(xFlags, x3);
// Ret....
MOV64x(x2, (uintptr_t)arm64_epilog); // epilog on purpose, CS might have changed!
// epilog on purpose, CS might have changed!
if(dyn->need_reloc)
TABLE64C(x2, const_epilog);
else
MOV64x(x2, getConst(const_epilog));
BR(x2);
CLEARIP();
MARK;
if(is64bits)
ADDx_U12(xRSP, xRSP, 8*2);
else
ADDx_U12(xRSP, xRSP, 4*2);
MARK3;
if(is64bits)
ADDx_U12(xRSP, xRSP, 8*3);
else
ADDx_U12(xRSP, xRSP, 4*3);
CALL_S(const_native_priv, -1);
}
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg)
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
{
MAYUSE(fnc);
#if STEP == 0
@@ -785,7 +804,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
#ifdef _WIN32
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
#endif
TABLE64(reg, (uintptr_t)fnc);
TABLE64C(reg, fnc);
BLR(reg);
if(ret>=0) {
MOVx_REG(ret, xEmu);
@@ -816,7 +835,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
//SET_NODF();
}
void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
void call_i(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc)
{
MAYUSE(fnc);
#if STEP == 0
@@ -837,7 +856,7 @@ void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
#ifdef _WIN32
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
#endif
TABLE64(x87pc, (uintptr_t)fnc);
TABLE64C(x87pc, fnc);
BLR(x87pc);
LDPx_S7_postindex(xEmu, x1, xSP, 16);
LDPx_S7_postindex(x2, x3, xSP, 16);
@@ -886,7 +905,13 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
MOVx_REG(x4, xR8);
MOVx_REG(x5, xR9);
// native call
TABLE64(16, (uintptr_t)fnc); // using x16 as scratch regs for call address
if(dyn->need_reloc) {
// fnc is indirect, to help with relocation (but PltResolver might be an issue here)
TABLE64(16, (uintptr_t)fnc);
LDRx_U12(16, 16, 0);
} else {
TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
}
BLR(16);
// put return value in x64 regs
if(w>0) {
@@ -914,6 +939,9 @@ void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int se
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
int t2 = x4;
if(reg==t2) ++t2;
#ifdef _WIN32
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
#else
LDRw_U12(t2, xEmu, offsetof(x64emu_t, segs_serial[segment]));
/*if(segment==_GS) {
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
@@ -926,8 +954,9 @@ void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int se
CBZw_MARKSEG(t2);
}
MOVZw(x1, segment);
call_c(dyn, ninst, GetSegmentBaseEmu, t2, reg, 1, 0);
call_c(dyn, ninst, const_getsegmentbase, t2, reg, 1, 0);
MARKSEG;
#endif
MESSAGE(LOG_DUMP, "----%s Offset\n", (segment==_FS)?"FS":"GS");
}
@@ -1016,6 +1045,7 @@ int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b)
// the reg returned is *2 for FLOAT
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
{
dyn->insts[ninst].x87_used = 1;
if(dyn->n.mmxcount)
mmx_purgecache(dyn, ninst, 0, s1);
dyn->n.x87stack+=1;
@@ -1050,6 +1080,7 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
}
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
{
dyn->insts[ninst].x87_used = 1;
if(dyn->n.mmxcount)
mmx_purgecache(dyn, ninst, 0, s1);
dyn->n.x87stack+=1;
@@ -1099,6 +1130,7 @@ static int internal_x87_dofree(dynarec_arm_t* dyn)
}
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
{
dyn->insts[ninst].x87_used = 1;
if(dyn->n.mmxcount)
mmx_purgecache(dyn, ninst, 0, s1);
do {
@@ -1181,17 +1213,7 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
for (int i=0; i<8; ++i)
if(dyn->n.x87cache[i]!=-1) {
int st = dyn->n.x87cache[i]+dyn->n.stack_pop;
#if STEP == 1
if(!next) { // don't force promotion here
// pre-apply pop, because purge happens in-between
neoncache_promote_double(dyn, ninst, st);
}
#endif
#if STEP == 3
if(!next && neoncache_get_current_st(dyn, ninst, st)!=NEON_CACHE_ST_D) {
MESSAGE(LOG_DUMP, "Warning, incoherency with purged ST%d cache\n", st);
}
#endif
// don't force promotion here
ADDw_U12(s3, s2, dyn->n.x87cache[i]); // unadjusted count, as it's relative to real top
ANDw_mask(s3, s3, 0, 2); //mask=7 // (emu->top + st)&7
switch(neoncache_get_current_st(dyn, ninst, st)) {
@@ -1366,6 +1388,7 @@ void x87_unreflectcount(dynarec_arm_t* dyn, int ninst, int s1, int s2)
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
{
dyn->insts[ninst].x87_used = 1;
// search in cache first
for (int i=0; i<8; ++i) {
if(dyn->n.x87cache[i]==st) {
@@ -1386,6 +1409,7 @@ int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, int st, int t)
{
dyn->insts[ninst].x87_used = 1;
if(dyn->n.mmxcount)
mmx_purgecache(dyn, ninst, 0, s1);
int ret = x87_get_current_cache(dyn, ninst, st, t);
@@ -1419,6 +1443,7 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
}
int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
{
dyn->insts[ninst].x87_used = 1;
for(int ii=0; ii<24; ++ii)
if((dyn->n.neoncache[ii].t == NEON_CACHE_ST_F
|| dyn->n.neoncache[ii].t == NEON_CACHE_ST_D
@@ -1430,10 +1455,12 @@ int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
}
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t)
{
dyn->insts[ninst].x87_used = 1;
return dyn->n.x87reg[x87_get_cache(dyn, ninst, 1, s1, s2, a, t)];
}
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t)
{
dyn->insts[ninst].x87_used = 1;
return dyn->n.x87reg[x87_get_cache(dyn, ninst, 0, s1, s2, a, t)];
}
@@ -1488,6 +1515,7 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
{
dyn->insts[ninst].x87_used = 1;
if(dyn->n.mmxcount)
mmx_purgecache(dyn, ninst, 0, s1);
// search in cache first
@@ -1538,6 +1566,7 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st)
{
dyn->insts[ninst].x87_used = 1;
int ret = -1;
for (int i=0; (i<8) && (ret==-1); ++i)
if(dyn->n.x87cache[i] == st)
@@ -1671,6 +1700,7 @@ static int isx87Empty(dynarec_arm_t* dyn)
// 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 s2, int s3, int a)
{
dyn->insts[ninst].mmx_used = 1;
if(!dyn->n.x87stack && isx87Empty(dyn))
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
if(dyn->n.mmxcache[a]!=-1)
@@ -1683,6 +1713,7 @@ 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 s2, int s3, int a)
{
dyn->insts[ninst].mmx_used = 1;
if(!dyn->n.x87stack && isx87Empty(dyn))
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
if(dyn->n.mmxcache[a]!=-1)
@@ -2055,8 +2086,10 @@ void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
x87_purgecache(dyn, ninst, next, s1, s2, s3);
mmx_purgecache(dyn, ninst, next, s1);
sse_purgecache(dyn, ninst, next, s1);
if(!next)
if(!next) {
fpu_reset_reg(dyn);
dyn->insts[ninst].fpupurge = 1;
}
}
static int findCacheSlot(dynarec_arm_t* dyn, int ninst, int t, int n, neoncache_t* cache)
@@ -2179,7 +2212,7 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
break;
case NEON_CACHE_YMMR:
case NEON_CACHE_YMMW:
if(dyn->insts[i2].n.xmm_unneeded&(1<<n)) {
if(dyn->insts[i2].n.ymm_unneeded&(1<<n)) {
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
} else {
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
@@ -2238,7 +2271,7 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
MESSAGE(LOG_DUMP, "\t - ignoring %s\n", getCacheName(t, n));
break;
case NEON_CACHE_XMMW:
if(dyn->insts[i2].n.xmm_unneeded&(1<<i)) {
if(dyn->insts[i2].n.xmm_unneeded&(1<<n)) {
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
} else {
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
@@ -2246,7 +2279,7 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
}
break;
case NEON_CACHE_YMMW:
if(dyn->insts[i2].n.ymm_unneeded&(1<<i)) {
if(dyn->insts[i2].n.ymm_unneeded&(1<<n)) {
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
} else {
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
@@ -2475,57 +2508,40 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
}
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
}
static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
{
int j64;
int jmp = dyn->insts[ninst].x64.jmp_insts;
if(jmp<0)
return;
if(dyn->f.dfnone || (dyn->insts[jmp].f_exit.dfnone_here && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
if(dyn->f.dfnone || ((dyn->insts[jmp].f_exit.dfnone && !dyn->insts[jmp].f_entry.dfnone) && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
return;
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone && !dyn->insts[jmp].df_notneeded)?1:0;
switch (dyn->insts[jmp].f_entry.pending) {
case SF_UNKNOWN: break;
case SF_SET:
if(dyn->f.pending!=SF_SET && dyn->f.pending!=SF_SET_PENDING)
go = 1;
case SF_UNKNOWN:
go = 0;
break;
case SF_SET_PENDING:
if(dyn->f.pending!=SF_SET
&& dyn->f.pending!=SF_SET_PENDING
&& dyn->f.pending!=SF_PENDING
) {
// only sync if some previous flags are used or if all flags are not regenerated at the instuction
if(dyn->insts[jmp].x64.use_flags || (dyn->insts[jmp].x64.set_flags!=X_ALL))
go = 1;
else if(go) {
// just clear df flags
go = 0;
STRw_U12(xZR, xEmu, offsetof(x64emu_t, df));
}
default:
if(go && !(dyn->insts[jmp].x64.need_before&X_PEND) && (dyn->f.pending!=SF_UNKNOWN)) {
// just clear df flags
go = 0;
STRw_U12(xZR, xEmu, offsetof(x64emu_t, df));
}
break;
case SF_PENDING:
if(dyn->f.pending!=SF_SET
&& dyn->f.pending!=SF_SET_PENDING
&& dyn->f.pending!=SF_PENDING)
go = 1;
else if (dyn->insts[jmp].f_entry.dfnone !=dyn->f.dfnone)
go = 1;
break;
}
if(go) {
if(dyn->f.pending!=SF_PENDING) {
LDRw_U12(s1, xEmu, offsetof(x64emu_t, df));
LDRw_U12(x1, xEmu, offsetof(x64emu_t, df));
j64 = (GETMARKF2)-(dyn->native_size);
CBZw(s1, j64);
CBZw(x1, j64);
}
if(dyn->insts[ninst].need_nat_flags)
MRS_nzcv(s1);
CALL_(UpdateFlags, -1, s1);
MRS_nzcv(x6);
TABLE64C(x1, const_updateflags_arm64);
BLR(x1);
if(dyn->insts[ninst].need_nat_flags)
MSR_nzcv(s1);
MSR_nzcv(x6);
MARKF2;
}
}
@@ -2595,7 +2611,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
}
// special case for NF_CF changing state
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after)) {
if(arm64_flagm && !mrs) {
if(cpuext.flagm && !mrs) {
CFINV();
} else {
GO_MRS(s2);
@@ -2608,13 +2624,14 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
MESSAGE(LOG_DUMP, "\t---- Native Flags transform\n");
}
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3) {
// Might use all Scratch registers!
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
if(cacheupd&1)
flagsCacheTransform(dyn, ninst, s1);
flagsCacheTransform(dyn, ninst);
if(cacheupd&2)
fpuCacheTransform(dyn, ninst, s1, s2, s3);
fpuCacheTransform(dyn, ninst, x1, x2, x3);
if(cacheupd&4)
nativeFlagsTransform(dyn, ninst, s1, s2);
nativeFlagsTransform(dyn, ninst, x1, x2);
}
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
+79 -38
View File
@@ -4,6 +4,7 @@
// undef to get Close to SSE Float->int conversions
//#define PRECISE_CVT
#ifndef STEP_PASS
#if STEP == 0
#include "dynarec_arm64_pass0.h"
#elif STEP == 1
@@ -13,10 +14,13 @@
#elif STEP == 3
#include "dynarec_arm64_pass3.h"
#endif
#define STEP_PASS
#endif
#include "debug.h"
#include "arm64_emitter.h"
#include "../emu/x64primop.h"
#include "dynarec_arm64_consts.h"
#define F8 *(uint8_t*)(addr++)
#define F8S *(int8_t*)(addr++)
@@ -215,9 +219,12 @@
wb = ed = x1; \
}
//FAKEELike GETED, but doesn't get anything
#define FAKEED \
if (!MODREG) { \
addr = fakeed(dyn, addr, ninst, nextop); \
#define FAKEED \
if (MODREG) { \
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
wback = 0; \
} else { \
addr = fakeed(dyn, addr, ninst, nextop); \
}
// GETGW extract x64 register in gd, that is i
@@ -942,7 +949,7 @@
#define GEN_INVERTED_CARRY()
#endif
#ifndef INVERT_CARRY
#define INVERT_CARRY(A) if(dyn->insts[ninst].normal_carry) {if(arm64_flagm) CFINV(); else {MRS_nzcv(A); EORx_mask(A, A, 1, 35, 0); MSR_nzcv(A);}}
#define INVERT_CARRY(A) if(dyn->insts[ninst].normal_carry) {if(cpuext.flagm) CFINV(); else {MRS_nzcv(A); EORx_mask(A, A, 1, 35, 0); MSR_nzcv(A);}}
#endif
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
@@ -961,19 +968,19 @@
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
#define FCOMI(s1, s2) \
IFX(X_OF|X_AF|X_SF|X_PEND) { \
IFX(X_OF|X_AF|X_SF) { \
MOV32w(s2, 0b100011010101); \
BICw_REG(xFlags, xFlags, s2); \
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
IFX(X_CF|X_PF|X_ZF) { \
MOV32w(s2, 0b01000101); \
} \
} else { \
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
IFX(X_CF|X_PF|X_ZF) { \
MOV32w(s2, 0b01000101); \
BICw_REG(xFlags, xFlags, s2); \
} \
} \
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
IFX(X_CF|X_PF|X_ZF) { \
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
/*s2 already set */ /* unordered */ \
CSELw(s1, s2, s1, cVS); \
@@ -1118,13 +1125,14 @@
x87_do_pop(dyn, ninst, scratch)
#endif
#define FORCE_DFNONE() STRw_U12(wZR, xEmu, offsetof(x64emu_t, df))
#define SET_DFNONE() \
do { \
if (!dyn->f.dfnone) { \
STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); \
FORCE_DFNONE(); \
} \
if(!dyn->insts[ninst].x64.may_set) { \
dyn->f.dfnone_here = 1; \
dyn->f.dfnone = 1; \
} \
} while(0)
@@ -1134,7 +1142,8 @@
MOVZw(S, (N)); \
STRw_U12(S, xEmu, offsetof(x64emu_t, df)); \
if (dyn->f.pending == SF_PENDING && dyn->insts[ninst].x64.need_after && !(dyn->insts[ninst].x64.need_after & X_PEND)) { \
CALL_I(UpdateFlags); \
TABLE64C(x6, const_updateflags_arm64); \
BLR(x6); \
dyn->f.pending = SF_SET; \
SET_NODF(); \
} \
@@ -1145,7 +1154,7 @@
#ifndef SET_NODF
#define SET_NODF() dyn->f.dfnone = 0
#endif
#define SET_DFOK() dyn->f.dfnone = 1; dyn->f.dfnone_here=1
#define SET_DFOK() dyn->f.dfnone = 1
#ifndef READFLAGS
#define READFLAGS(A) \
@@ -1156,7 +1165,8 @@
j64 = (GETMARKF)-(dyn->native_size); \
CBZw(x3, j64); \
} \
CALL_I(UpdateFlags); \
TABLE64C(x6, const_updateflags_arm64); \
BLR(x6); \
MARKF; \
dyn->f.pending = SF_SET; \
SET_DFOK(); \
@@ -1195,9 +1205,12 @@
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, xEmu, offsetof(x64emu_t, op2));}
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.gen_flags) {SET_DF(r, A);}
#ifndef UFLAG_IF
#define UFLAG_IF if(dyn->insts[ninst].x64.gen_flags)
#define UFLAG_IF_DF if(dyn->insts[ninst].x64.gen_flags || (dyn->insts[ninst].f_entry.dfnone && dyn->insts[ninst].f_entry.dfnone_here))
#endif
#ifndef UFLAG_IF2
#define UFLAG_IF2(A) if(dyn->insts[ninst].x64.gen_flags A)
#endif
#ifndef DEFAULT
#define DEFAULT *ok = -1; BARRIER(2)
#endif
@@ -1207,9 +1220,15 @@
#ifndef TABLE64
#define TABLE64(A, V)
#endif
#ifndef TABLE64_
#define TABLE64_(A, V)
#endif
#ifndef FTABLE64
#define FTABLE64(A, V)
#endif
#ifndef TABLE64C
#define TABLE64C(A, V)
#endif
#define ARCH_INIT() \
SMSTART(); \
@@ -1222,23 +1241,40 @@
#define GETIP_(A) MOV64x(xRIP, A)
#else
// put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later...
#define GETIP(A) \
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
uint64_t _delta_ip = (A)-dyn->last_ip; \
dyn->last_ip += _delta_ip; \
if(_delta_ip) { \
ADDx_U12(xRIP, xRIP, _delta_ip); \
} \
} else { \
dyn->last_ip = (A); \
MOV64x(xRIP, dyn->last_ip); \
#define GETIP(A) \
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
uint64_t _delta_ip = (A)-dyn->last_ip; \
dyn->last_ip += _delta_ip; \
if(_delta_ip) { \
ADDx_U12(xRIP, xRIP, _delta_ip); \
} \
} else if(dyn->last_ip && (dyn->last_ip-(A))<0x1000) { \
uint64_t _delta_ip = dyn->last_ip-(A); \
dyn->last_ip -= _delta_ip; \
if(_delta_ip) { \
SUBx_U12(xRIP, xRIP, _delta_ip); \
} \
} else { \
dyn->last_ip = (A); \
if(dyn->need_reloc) { \
TABLE64(xRIP, dyn->last_ip); \
} else { \
MOV64x(xRIP, dyn->last_ip); \
} \
}
#define GETIP_(A) \
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
uint64_t _delta_ip = (A)-dyn->last_ip; \
if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);}\
} else { \
MOV64x(xRIP, (A)); \
#define GETIP_(A) \
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
uint64_t _delta_ip = (A)-dyn->last_ip; \
if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);} \
} else if(dyn->last_ip && (dyn->last_ip-(A))<0x1000) { \
uint64_t _delta_ip = dyn->last_ip-(A); \
if(_delta_ip) {SUBx_U12(xRIP, xRIP, _delta_ip);} \
} else { \
if(dyn->need_reloc) { \
TABLE64(xRIP, (A)); \
} else { \
MOV64x(xRIP, (A)); \
} \
}
#endif
#define CLEARIP() dyn->last_ip=0
@@ -1255,9 +1291,6 @@
#define MODREG ((nextop&0xC0)==0xC0)
void arm64_epilog(void);
void* arm64_next(x64emu_t* emu, uintptr_t addr);
#ifndef STEPNAME
#define STEPNAME3(N,M) N##M
#define STEPNAME2(N,M) STEPNAME3(N,M)
@@ -1266,6 +1299,8 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
#define native_pass STEPNAME(native_pass)
#define updateflags_pass STEPNAME(updateflags_pass)
#define dynarec64_00 STEPNAME(dynarec64_00)
#define dynarec64_0F STEPNAME(dynarec64_0F)
#define dynarec64_64 STEPNAME(dynarec64_64)
@@ -1274,6 +1309,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
#define dynarec64_67 STEPNAME(dynarec64_67)
#define dynarec64_67_32 STEPNAME(dynarec64_67_32)
#define dynarec64_67_AVX STEPNAME(dynarec64_67_AVX)
#define dynarec64_6764 STEPNAME(dynarec64_6764)
#define dynarec64_6764_32 STEPNAME(dynarec64_6764_32)
#define dynarec64_D8 STEPNAME(dynarec64_D8)
#define dynarec64_D9 STEPNAME(dynarec64_D9)
@@ -1482,8 +1518,8 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex);
void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
void call_i(dynarec_arm_t* dyn, int ninst, void* fnc);
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int save_reg);
void call_i(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc);
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
@@ -1628,7 +1664,7 @@ int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
// purge ymm_zero mask according to purge_ymm
void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
@@ -1722,6 +1758,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
uintptr_t dynarec64_6764(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
@@ -1950,7 +1987,7 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
#define COMP_ZFSF(s1, A) \
IFX(X_ZF|X_SF) { \
if(arm64_flagm) { \
if(cpuext.flagm) { \
SETF##A(s1); \
IFX(X_ZF) { \
IFNATIVE(NF_EQ) {} else { \
@@ -1979,6 +2016,10 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
} \
}
#define PURGE_YMM() avx_purge_ymm(dyn, ninst, dyn->insts[ninst+1].purge_ymm, x1)
#define PURGE_YMM() \
do { \
if ((ok > 0) && reset_n == -1 && dyn->insts[ninst + 1].purge_ymm) \
avx_purge_ymm(dyn, ninst, dyn->insts[ninst + 1].purge_ymm, x1); \
} while (0)
#endif //__DYNAREC_ARM64_HELPER_H__
+2
View File
@@ -58,6 +58,8 @@
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
#define UFLAG_IF if(dyn->insts[ninst].x64.set_flags)
#define UFLAG_IF2(A) if(dyn->insts[ninst].x64.set_flags A)
#define IFX(A) if((dyn->insts[ninst].x64.set_flags&(A)))
#define IFX2(A, B) if((dyn->insts[ninst].x64.set_flags&(A)) B)
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.set_flags&(X_PEND) || !dyn->insts[ninst].x64.set_flags))
+14 -2
View File
@@ -15,7 +15,19 @@
}
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
#define INST_NAME(name)
#define TABLE64(A, V) {Table64(dyn, (V), 2); EMIT(0);}
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
#define TABLE64(A, V) do { \
if(dyn->need_reloc) \
AddRelocTable64Addr(dyn, ninst, (V), 2); \
Table64(dyn, (V), 2); EMIT(0); \
} while(0)
#define TABLE64_(A, V) do { \
Table64(dyn, (V), 2); EMIT(0); \
} while(0)
#define TABLE64C(A, V) do { \
if(dyn->need_reloc) \
AddRelocTable64Const(dyn, ninst, (V), 2); \
Table64(dyn, getConst(V), 2); EMIT(0); \
} while(0)
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);} while(0)
#define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
+17 -2
View File
@@ -24,7 +24,22 @@
}
#define INST_EPILOG
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
#define TABLE64(A, V) do { \
if(dyn->need_reloc) \
AddRelocTable64Addr(dyn, ninst, (V), 3); \
int val64offset = Table64(dyn, (V), 3); \
MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
} while(0)
#define TABLE64_(A, V) { \
int val64offset = Table64(dyn, (V), 3); \
MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
}
#define TABLE64C(A, V) do { \
if(dyn->need_reloc) \
AddRelocTable64Const(dyn, ninst, (V), 3); \
int val64offset = Table64(dyn, getConst(V), 3); \
MESSAGE(LOG_DUMP, " Table64C: 0x%lx\n", (V)); LDRx_literal(A, val64offset);\
} while(0)
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} while(0)
#define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
+19 -11
View File
@@ -6,6 +6,7 @@
typedef struct x64emu_s x64emu_t;
typedef struct dynablock_s dynablock_t;
typedef struct instsize_s instsize_t;
typedef struct box64env_s box64env_t;
#define BARRIER_MAYBE 8
@@ -72,7 +73,6 @@ typedef struct neoncache_s {
int8_t x87stack; // cache stack counter
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
int8_t fpu_scratch; // scratch counter
int8_t fpu_reg; // x87/sse/mmx reg counter
uint16_t xmm_write; // 1bit of xmmXX removed write
uint16_t xmm_removed; // 1bit if xmmXX was removed
uint16_t xmm_used; // mask of the xmm regs used in this opcode
@@ -87,7 +87,6 @@ typedef struct neoncache_s {
typedef struct flagcache_s {
int pending; // is there a pending flags here, or to check?
uint8_t dfnone; // if deferred flags is already set to df_none
uint8_t dfnone_here;// defered flags is cleared in this opcode
} flagcache_t;
typedef struct instruction_arm64_s {
@@ -116,7 +115,6 @@ typedef struct instruction_arm64_s {
uint8_t will_read:1; // [strongmem] will read from memory
uint8_t last_write:1; // [strongmem] the last write in a SEQ
uint8_t lock:1; // [strongmem] lock semantic
uint8_t lock_prefixed:1; // [strongmem] the opcode is lock prefixed
uint8_t wfe:1; // opcode uses sevl + wfe
uint8_t set_nat_flags; // 0 or combinaison of native flags define
uint8_t use_nat_flags; // 0 or combinaison of native flags define
@@ -132,6 +130,10 @@ typedef struct instruction_arm64_s {
unsigned df_notneeded:1;
unsigned unaligned:1; // this opcode can be re-generated for unaligned special case
unsigned x87precision:1; // this opcode can handle x87pc
unsigned mmx_used:1; // no fine tracking, just a global "any reg used"
unsigned x87_used:1; // no fine tracking, just a global "any reg used"
unsigned fpu_used:1; // any xmm/ymm/x87/mmx reg used
unsigned fpupurge:1; // this opcode will purge all fpu regs
flagcache_t f_exit; // flags status at end of instruction
neoncache_t n; // neoncache at end of instruction (but before poping)
flagcache_t f_entry; // flags status before the instruction begin
@@ -142,6 +144,7 @@ typedef struct dynarec_arm_s {
int32_t size;
int32_t cap;
uintptr_t start; // start of the block
uintptr_t end; // maximum end of the block (only used in pass0)
uint32_t isize; // size in bytes of x64 instructions included
void* block; // memory pointer where next instruction is emitted
uintptr_t native_start; // start of the arm code
@@ -179,6 +182,10 @@ typedef struct dynarec_arm_s {
void* gdbjit_block;
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
uint32_t need_dump; // need to dump the block
int need_reloc; // does the dynablock need relocations
int reloc_size;
uint32_t* relocs;
box64env_t* env;
} dynarec_arm_t;
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
@@ -189,18 +196,19 @@ int get_first_jump_addr(dynarec_arm_t *dyn, uintptr_t next);
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
int isTable64(dynarec_arm_t *dyn, uint64_t val); // return 1 if val already in Table64
int Table64(dynarec_arm_t *dyn, uint64_t val, int pass); // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
void CreateJmpNext(void* addr, void* next);
#define GO_TRACE(A, B, s0) \
GETIP(addr); \
MOVx_REG(x1, xRIP); \
MRS_nzcv(s0); \
STORE_XEMU_CALL(xRIP); \
MOV32w(x2, B); \
CALL_(A, -1, s0); \
MSR_nzcv(s0); \
#define GO_TRACE(A, B, s0) \
GETIP(addr); \
MOVx_REG(x1, xRIP); \
MRS_nzcv(s0); \
STORE_XEMU_CALL(xRIP); \
MOV32w(x2, B); \
CALL_(const_##A, -1, s0); \
MSR_nzcv(s0); \
LOAD_XEMU_CALL(xRIP)
#endif //__DYNAREC_ARM_PRIVATE_H_
+135
View File
@@ -0,0 +1,135 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include "os.h"
#include "debug.h"
#include "box64context.h"
#include "custommem.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynablock.h"
#include "../dynablock_private.h"
#include "dynarec_native.h"
#include "../dynarec_arch.h"
void updateflags_pass0(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass1(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass2(dynarec_arm_t* dyn, uint64_t jmp_df[]);
void updateflags_pass3(dynarec_arm_t* dyn, uint64_t jmp_df[]);
static dynablock_t* updaflags_arm64 = NULL;
static uint8_t dummy_code[] = {0x90, 0xc3}; // some dummy code so update_flags dynablock point to something
void* create_updateflags()
{
if(updaflags_arm64)
return updaflags_arm64->block;
uint64_t jmp_df[d_unknown+1] = {0};
dynarec_arm_t helper = {0};
instruction_arm64_t insts[1] = {0};
helper.insts = insts;
helper.need_dump = BOX64ENV(dynarec_dump);
helper.cap = 1;
helper.f.dfnone = 1;
helper.f.pending = SF_NODF;
helper.insts[0].x64.gen_flags = X_ALL;
// pass 0
updateflags_pass0(&helper, jmp_df);
// check if all flags are handled
int ok = 1;
for(int i=d_none; i<d_unknown; ++i)
if(!jmp_df[i]) {
printf_log(LOG_NONE, "Error, UpdateFlags case %d is not handled, will crash later\n", i);
ok = 0;
}
// pass 1
updateflags_pass1(&helper, jmp_df);
// pass 2
helper.native_size = 0;
updateflags_pass2(&helper, jmp_df);
// alloc memory for pass3
size_t native_size = (helper.native_size+7)&~7; // round the size...
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + 0 + 0 + 0 + sizeof(dynablock_t) + 0;
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets dynablock relocs
void* actual_p = (void*)AllocDynarecMap((uintptr_t)&dummy_code, sz, 1); // arbitrary address
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
void* tablestart = p + native_size;
void* next = tablestart + helper.table64size*sizeof(uint64_t);
void* instsize = next + 4*sizeof(void*);
void* arch = instsize + 0;
void* callrets = arch + 0;
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%zu) failed, canceling UpdateBlock\n", sz);
return NULL;
}
helper.block = p;
dynablock_t* block = (dynablock_t*)(callrets+0);
memset(block, 0, sizeof(dynablock_t));
void* relocs = helper.need_reloc?(block+1):NULL;
// fill the block
block->x64_addr = &dummy_code;
block->isize = 0;
block->actual_block = actual_p;
helper.relocs = relocs;
block->relocs = relocs;
block->table64size = helper.table64size;
helper.native_start = (uintptr_t)p;
helper.tablestart = (uintptr_t)tablestart;
helper.jmp_next = (uintptr_t)next+sizeof(void*);
helper.instsize = (instsize_t*)instsize;
*(dynablock_t**)actual_p = block;
helper.table64cap = helper.table64size;
helper.table64 = (uint64_t*)helper.tablestart;
helper.callrets = (callret_t*)callrets;
block->table64 = helper.table64;
helper.callret_size = 0;
// pass 3, emit (log emit native opcode)
if(helper.need_dump) {
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for UpdateFlags", (helper.need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size);
PrintFunctionAddr(helper.start, " => ");
dynarec_log_prefix(0, LOG_NONE, "%s\n", (helper.need_dump>1)?"\e[m":"");
}
helper.native_size = 0;
updateflags_pass3(&helper, jmp_df);
helper.jmp_sz = helper.jmp_cap = 0;
helper.jmps = NULL;
// keep size of instructions for signal handling
block->instsize = instsize;
helper.table64 = NULL;
helper.instsize = NULL;
helper.predecessor = NULL;
block->size = sz;
block->isize = helper.size;
block->block = p;
block->jmpnext = next+sizeof(void*);
block->always_test = helper.always_test;
block->dirty = block->always_test;
block->is32bits = 0;
block->relocsize = helper.reloc_size*sizeof(uint32_t);
block->arch = NULL;
block->arch_size = 0;
block->callret_size = helper.callret_size;
block->callrets = helper.callrets;
block->native_size = native_size;
*(dynablock_t**)next = block;
*(void**)(next+3*sizeof(void*)) = NULL;
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
ClearCache(block->jmpnext, 4*sizeof(void*));
block->x64_size = 0;
// all done...
ClearCache(actual_p+sizeof(void*), native_size); // need to clear the cache before execution...
updaflags_arm64 = block;
return block->block;
}
File diff suppressed because it is too large. Load diff
+117 -56
View File
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include "os.h"
#include "debug.h"
@@ -54,14 +55,14 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
if(db->callret_size) {
// mark all callrets to UDF
for(int i=0; i<db->callret_size; ++i)
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_NOP;
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_UDF;
ClearCache(db->block, db->size);
}
#endif
if(db_size && my_context) {
if(db_size && my_context && !BOX64ENV(dynarec_dirty)) {
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
if(!n && (db_size >= my_context->max_db_size)) {
my_context->max_db_size = rb_get_righter(my_context->db_sizes);
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
}
}
@@ -71,29 +72,67 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
return db;
}
dynablock_t* SwitchDynablock(dynablock_t* db, int need_lock)
{
if(db) {
if(!db->done || !db->previous || !db->previous->gone)
return NULL; // not a correct block!
dynarec_log(LOG_DEBUG, "SwitchDynablock(%p/%p), db->block=%p->%p x64=%p:%p->%p hash->%x->%x\n", db, db->previous, db->block, db->previous->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->previous->x64_addr+db->previous->x64_size-1, db->hash, db->previous->hash);
// remove jumptable without waiting
dynablock_t* db_new = db->previous;
db->previous = NULL;
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
InvalidDynablock(db, 0);
db_new->done = 1;
db_new->gone = 0;
db_new->previous = db;
#ifdef ARCH_NOP
if(db_new->callret_size) {
// mark all callrets to UDF
for(int i=0; i<db_new->callret_size; ++i)
*(uint32_t*)(db_new->block+db_new->callrets[i].offs) = ARCH_NOP;
ClearCache(db_new->block, db_new->size);
}
#endif
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
return db_new;
}
return db;
}
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
{
if(db) {
if(!db->gone)
return; // already in the process of deletion!
dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
uintptr_t db_size = db->x64_size;
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
FreeDynarecMap((uintptr_t)db->actual_block);
customFree(db);
if(db_size && my_context && BOX64ENV(dynarec_dirty)) {
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
if(!n && (db_size >= my_context->max_db_size)) {
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
}
}
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
}
}
void FreeDynablock(dynablock_t* db, int need_lock)
void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
{
if(db) {
if(db->gone)
return; // already in the process of deletion!
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
// remove jumptable without waiting
setJumpTableDefault64(db->x64_addr);
if(need_remove)
setJumpTableDefault64(db->x64_addr);
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
@@ -103,14 +142,13 @@ void FreeDynablock(dynablock_t* db, int need_lock)
if(db_size && my_context) {
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
if(!n && (db_size >= my_context->max_db_size)) {
my_context->max_db_size = rb_get_righter(my_context->db_sizes);
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
}
}
if(db->previous)
FreeInvalidDynablock(db->previous, 0);
FreeDynarecMap((uintptr_t)db->actual_block);
customFree(db);
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
}
@@ -170,21 +208,12 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
int need_lock = my_context?1:0;
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) {
FreeDynablock(db, need_lock);
FreeDynablock(db, need_lock, 1);
return 0;
}
return 1;
}
dynablock_t *AddNewDynablock(uintptr_t addr)
{
dynablock_t* block;
// create and add new block
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
return block;
}
NEW_JUMPBUFF(dynarec_jmpbuf);
void cancelFillBlock()
@@ -196,7 +225,7 @@ void cancelFillBlock()
return NULL if block is not found / cannot be created.
Don't create if create==0
*/
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits)
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits, int is_new)
{
if (hasAlternate((void*)filladdr))
return NULL;
@@ -208,18 +237,38 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
return block;
}
#ifndef WIN32
static int critical_filled = 0;
static sigset_t critical_prot = {0};
sigset_t old_sig = {0};
if(!critical_filled) {
critical_filled = 1;
sigfillset(&critical_prot);
sigdelset(&critical_prot, SIGSEGV);
sigdelset(&critical_prot, SIGILL);
sigdelset(&critical_prot, SIGBUS);
sigdelset(&critical_prot, SIGINT);
sigdelset(&critical_prot, SIGABRT);
sigdelset(&critical_prot, SIGFPE);
}
#endif
pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig);
if(need_lock) {
if(BOX64ENV(dynarec_wait)) {
mutex_lock(&my_context->mutex_dyndump);
} else {
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
if(mutex_trylock(&my_context->mutex_dyndump)) { // FillBlock not available for now
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return NULL;
}
}
block = getDB(addr); // just in case
if(block) {
if(block && getNeedTest(addr) && (getProtection_fast(addr)&req_prot)!=req_prot)
block = NULL;
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return block;
}
}
@@ -227,34 +276,31 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return NULL;
}
#endif
block = AddNewDynablock(addr);
// fill the block
block->x64_addr = (void*)addr;
if (SigSetJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1)) {
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, canceling\n", (void*)addr);
FreeDynablock(block, 0);
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
return NULL;
}
void* ret = FillBlock64(block, filladdr, (addr==filladdr)?0:1, is32bits, MAX_INSTS);
if(!ret) {
block = FillBlock64(filladdr, (addr==filladdr)?0:1, is32bits, MAX_INSTS, is_new);
if(!block) {
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
customFree(block);
block = NULL;
}
// check size
if(block) {
// fill-in jumptable
if(!addJumpTableIfDefault64(block->x64_addr, block->dirty?block->jmpnext:block->block)) {
FreeDynablock(block, 0);
if(!addJumpTableIfDefault64(block->x64_addr, (block->dirty || block->always_test)?block->jmpnext:block->block)) {
FreeDynablock(block, 0, 0);
block = getDB(addr);
MarkDynablock(block); // just in case...
} else {
if(block->dirty)
block->dirty = 0;
if(block->x64_size) {
if(block->x64_size>my_context->max_db_size) {
my_context->max_db_size = block->x64_size;
@@ -267,6 +313,7 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
}
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block %p created @%p:%p (%p, 0x%x bytes)\n", GetTID(), block, (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0);
@@ -278,34 +325,50 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
int is_inhotpage = isInHotPage(addr);
if(is_inhotpage && !BOX64ENV(dynarec_dirty))
return NULL;
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits);
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits, 1);
if(db && db->done && db->block && getNeedTest(addr)) {
if (db->always_test) SchedYield(); // just calm down...
//if (db->always_test) SchedYield(); // just calm down...
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
if(is_inhotpage && hash!=db->hash)
return NULL; // will be handle when hotpage is over
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
mutex_lock(&my_context->mutex_dyndump)?1:0;
if(hash!=db->hash) {
if(is_inhotpage && db->previous) {
// check alternate
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash) {
db = SwitchDynablock(db, 0);
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
FreeDynablock(db, 0, 0);
db = getDB(addr);
MarkDynablock(db); // just in case...
}
mutex_unlock(&my_context->mutex_dyndump);
return db;
}
mutex_unlock(&my_context->mutex_dyndump);
return NULL; // will be handle when hotpage is over
}
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,(void*)addr);
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d, previous=%p/hash=%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,db->previous, db->previous?db->previous->hash:0,(void*)addr);
// Free db, it's now invalid!
dynablock_t* old = InvalidDynablock(db, need_lock);
dynablock_t* old = InvalidDynablock(db, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, addr, create, need_lock, is32bits);
db = internalDBGetBlock(emu, addr, addr, create, 0, is32bits, 0);
if(db) {
if(db->previous)
FreeInvalidDynablock(db->previous, need_lock);
FreeInvalidDynablock(db->previous, 0);
db->previous = old;
} else
FreeInvalidDynablock(old, need_lock);
FreeInvalidDynablock(old, 0);
} else {
if(is_inhotpage) {
db->always_test = 2;
// log?
} else {
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->always_test, (void*)addr);
if(db->always_test)
if(db->always_test) {
if(db->always_test==2)
db->always_test = 0;
protectDB((uintptr_t)db->x64_addr, db->x64_size);
else {
} else {
#ifdef ARCH_NOP
if(db->callret_size) {
// mark all callrets to UDF
@@ -318,8 +381,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
}
}
}
if(!need_lock)
mutex_unlock(&my_context->mutex_dyndump);
mutex_unlock(&my_context->mutex_dyndump);
}
if(!db || !db->block || !db->done)
emu->test.test = 0;
@@ -330,24 +392,24 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr,
{
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p%s\n", (void*)addr, (void*)filladdr, is32bits?" 32bits":"");
int create = 1;
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits);
if(db && db->done && db->block && getNeedTest(filladdr)) {
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits, 1);
if(db && db->done && db->block && (db->dirty || getNeedTest(filladdr))) {
if (db->always_test) SchedYield(); // just calm down...
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
mutex_lock(&my_context->mutex_dyndump);
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
if(hash!=db->hash) {
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
// Free db, it's now invalid!
dynablock_t* old = InvalidDynablock(db, need_lock);
dynablock_t* old = InvalidDynablock(db, 0);
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, filladdr, create, need_lock, is32bits);
db = internalDBGetBlock(emu, addr, filladdr, create, 0, is32bits, 0);
if(db) {
if(db->previous)
FreeInvalidDynablock(db->previous, need_lock);
FreeInvalidDynablock(db->previous, 0);
db->previous = old;
} else
FreeInvalidDynablock(old, need_lock);
FreeInvalidDynablock(old, 0);
} else {
if(db->always_test)
protectDB((uintptr_t)db->x64_addr, db->x64_size);
@@ -363,8 +425,7 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr,
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
}
}
if(!need_lock)
mutex_unlock(&my_context->mutex_dyndump);
mutex_unlock(&my_context->mutex_dyndump);
}
if(!db || !db->block || !db->done)
emu->test.test = 0;
+6 -1
View File
@@ -17,12 +17,13 @@ typedef struct dynablock_s {
struct dynablock_s* previous; // a previous block that might need to be freed
void* x64_addr;
uintptr_t x64_size;
size_t native_size;
int size;
uint32_t hash;
uint8_t done;
uint8_t gone;
uint8_t dirty; // if need to be tested as soon as it's created
uint8_t always_test:1;
uint8_t always_test:2;
uint8_t is32bits:1;
int callret_size; // size of the array
int isize;
@@ -31,6 +32,10 @@ typedef struct dynablock_s {
void* arch; // arch dependant per inst info (can be NULL)
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
void* jmpnext; // a branch jmpnext code when block is marked
size_t table64size;// to check table64
void* table64; // to relocate the table64
size_t relocsize; // number of relocations (should be an int only)
void* relocs; // relocations, when block is loaded
#ifdef GDBJIT
void* gdbjit_block;
#endif
+243
View File
@@ -0,0 +1,243 @@
#include <stdint.h>
#include <string.h>
#include "os.h"
#include "dynarec_private.h"
#include "emu/x64run_private.h"
#include "dynablock_private.h"
#include "dynarec_arch.h"
#include "custommem.h"
#include "debug.h"
#define RELOC_TBL64C 1
#define RELOC_TBL64ADDR 2
#define RELOC_TBL64RETENDBL 3
#define RELOC_CANCELBLOCK 4
#define RELOC_TBL64TBLJMPH 5
#define RELOC_TBL64TBLJMPL 6
typedef union reloc_s {
uint8_t type;
struct {
uint8_t type;
uint8_t C;
uint16_t idx;
} table64c;
struct {
uint8_t type;
uint8_t nothing;
uint16_t idx;
} table64addr;
struct {
uint8_t type;
uint8_t delta;
uint16_t idx;
} table64retendbl;
struct {
uint8_t type;
uint8_t deltah;
uint16_t idx;
} table64jmptblh;
struct {
uint32_t type:8;
uint32_t deltal:24;
} table64jmptbll;
uint32_t x;
} reloc_t;
void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, int pass)
{
if(!dyn->need_reloc)
return;
if(isTable64(dyn, getConst(C)))
return;
if(pass<3) {
dyn->reloc_size++;
return;
}
// generating the reloc
reloc_t reloc = {0};
reloc.table64c.type = RELOC_TBL64C;
reloc.table64c.C = C;
reloc.table64c.idx = dyn->table64size;
dyn->relocs[dyn->reloc_size++] = reloc.x;
}
void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
{
if(!dyn->need_reloc)
return;
if(isTable64(dyn, getJumpTableAddress64(addr)))
return; // no need, already handled
// TODO: check iif addr is in current map
if(pass<3) {
dyn->reloc_size++;
return;
}
reloc_t reloc = {0};
intptr_t delta = addr-(dyn->start + dyn->isize);
if(delta>255 || delta<0) {
dynarec_log(LOG_INFO, "Warning Relocation Ret End Block not possible: delta=%lld, aborting block\n", delta);
dyn->abort = 1;
}
reloc.table64retendbl.type = RELOC_TBL64RETENDBL;
reloc.table64retendbl.delta = delta;
reloc.table64retendbl.idx = dyn->table64size;
dyn->relocs[dyn->reloc_size++] = reloc.x;
}
void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass)
{
if(!dyn->need_reloc)
return;
if(pass<3) {
dyn->reloc_size++;
return;
}
reloc_t reloc = {0};
reloc.type = RELOC_CANCELBLOCK;
dyn->relocs[dyn->reloc_size++] = reloc.x;
}
void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
{
if(!dyn->need_reloc)
return;
if(isTable64(dyn, addr))
return; // no need, already handled
// check if addr is in the same mmap area
// else, use a cancel block instead
uintptr_t start;
int ok = 1;
if(!IsAddrFileMapped(dyn->start, NULL, &start))
ok = 0;
else {
uintptr_t end = start + SizeFileMapped(dyn->start);
if(addr<start || addr>=end)
ok = 0;
if(ok && ((addr-start)>=0x100000000LL))
ok = 0;
}
if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
if(pass<3) {
dyn->reloc_size++;
return;
}
reloc_t reloc = {0};
reloc.type = RELOC_TBL64ADDR;
reloc.table64addr.idx = dyn->table64size;
dyn->relocs[dyn->reloc_size++] = reloc.x;
}
void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
{
if(!dyn->need_reloc)
return;
if(isTable64(dyn, getJumpTableAddress64(addr)))
return; // no need, already handled
// check if addr is in the same mmap area
// else, use a cancel block instead
uintptr_t start;
int ok = 1;
if(!IsAddrFileMapped(dyn->start, NULL, &start))
ok = 0;
else {
uintptr_t end = start + SizeFileMapped(dyn->start);
if(addr<start || addr>=end)
ok = 0;
if(ok && ((addr-start)>=0x100000000LL))
ok = 0;
}
if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
if(pass<3) {
dyn->reloc_size+=2;
return;
}
uintptr_t delta = addr - start;
reloc_t reloc = {0};
reloc.type = RELOC_TBL64TBLJMPH;
reloc.table64jmptblh.idx = dyn->table64size;
reloc.table64jmptblh.deltah = delta>>24;
dyn->relocs[dyn->reloc_size++] = reloc.x;
reloc.type = RELOC_TBL64TBLJMPL;
reloc.table64jmptbll.deltal = delta&0xffffff;
dyn->relocs[dyn->reloc_size++] = reloc.x;
}
int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start)
{
if(!block || !block->relocs || !block->relocsize)
return 0;
size_t reloc_size = block->relocsize / sizeof(uint32_t);
reloc_t *relocs = block->relocs;
uint64_t *table64 = block->table64;
int idx;
int i = 0;
uintptr_t addr;
dynarec_log(LOG_DEBUG, "Will apply %zd reloc to dynablock starting at %p - %p\n", reloc_size, block->x64_addr, block->x64_addr + block->x64_size);
while(i<reloc_size) {
idx = -1;
switch(relocs[i].type) {
case RELOC_TBL64C:
idx = relocs[i].table64c.idx;
table64[idx] = getConst(relocs[i].table64c.C);
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Const:%d\n", i, idx, relocs[i].table64c.C);
break;
case RELOC_TBL64ADDR:
idx = relocs[i].table64addr.idx;
table64[idx] += delta_map;
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Addr in Map, delta=%zd\n", i, idx, delta_map);
break;
case RELOC_TBL64RETENDBL:
idx = relocs[i].table64retendbl.idx;
addr = (uintptr_t)block->x64_addr + block->x64_size + relocs[i].table64retendbl.delta;
table64[idx] = getJumpTableAddress64(addr);
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=JmpTable64(%p)\n", i, idx, (void*)addr);
break;
case RELOC_CANCELBLOCK:
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: Cancel Block\n", i);
block->dirty = 1;
block->hash = 0;
return 0;
case RELOC_TBL64TBLJMPH:
if(relocs[i+1].type!=RELOC_TBL64TBLJMPL)
return -2; // bad sequence
idx = relocs[i].table64jmptblh.idx;
addr = relocs[i].table64jmptblh.deltah;
addr = mapping_start + relocs[i+1].table64jmptbll.deltal + (addr<<24);
table64[idx] = getJumpTableAddress64(addr);
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d,%d]: TABLE64[%d]=JmpTable64(%p)=%p\n", i, i+1, idx, (void*)addr, getJumpTableAddress64(addr));
break;
case RELOC_TBL64TBLJMPL:
break;
default:
dynarec_log(LOG_DEBUG, "\tUnknown Relocs[%d]: %d\n", i, relocs[i].type);
return -1;
}
if(idx!=-1) {
if(idx>=block->table64size) {
dynarec_log(LOG_NONE, "Warning: Reloc Table64 idx out of range (%d vs %d)\n", idx, block->table64size);
}
}
++i;
}
return 0;
}
int RelocsHaveCancel(dynablock_t* block)
{
if(!block->relocs || !block->relocsize)
return 0;
size_t reloc_size = block->relocsize/sizeof(uint32_t);
for(size_t i=0; i<reloc_size; ++i)
if(((reloc_t*)block->relocs)[i].type == RELOC_CANCELBLOCK)
return 1;
return 0;
}
uintptr_t RelocGetNext()
{
return getConst(const_native_next);
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef __DYNACACHE_RELOC_H__
#define __DYNACACHE_RELOC_H__
#ifdef ARM64
#include "dynarec/arm64/dynarec_arm64_consts.h"
#define native_consts_t arm64_consts_t
#elif defined(RV64)
#include "dynarec/rv64/dynarec_rv64_consts.h"
#define native_consts_t rv64_consts_t
#elif defined(LA64)
#include "dynarec/la64/dynarec_la64_consts.h"
#define native_consts_t la64_consts_t
#else
#error Unsupported architecture
#endif
void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, int pass);
void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass);
int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start);
int RelocsHaveCancel(dynablock_t* block);
uintptr_t RelocGetNext();
#endif
+2 -2
View File
@@ -43,10 +43,10 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
} else if(emu->segs[_CS]==0x23 && addr>0x100000000LL) {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
printf_log(LOG_INFO, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
#endif
} else if(!memExist(new_addr)) {
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p->%p from %p (db=%p, x64addr=%p/%s)\n", (void*)new_addr, (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
#endif
}
#endif
void * jblock;
@@ -166,7 +166,7 @@ void DynaRun(x64emu_t* emu)
if ((skip = SigSetJmp(emu->jmpbuf, 1)))
#endif
{
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", emu->segs[_FS]);
dynarec_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x will %sskip dynarec next\n", emu->segs[_FS], (skip==3)?"not ":"");
#ifdef DYNAREC
if(BOX64ENV(dynarec_test)) {
if(emu->test.clean)
+6 -2
View File
@@ -24,7 +24,7 @@
#define MAXBLOCK_SIZE ((1<<20)-200)
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
#define UPDATE_SPECIFICS(A) updateNativeFlags(A)
#define UPDATE_SPECIFICS(A) updateYmm0s(dyn, 0, 0); updateNativeFlags(A); propagateFpuBarrier(A)
#define PREUPDATE_SPECIFICS(A)
#define POSTUPDATE_SPECIFICS(A) updateUneeded(A)
#define ARCH_SIZE(A) get_size_arch(A)
@@ -33,7 +33,9 @@
#define STOP_NATIVE_FLAGS(A, B) A->insts[B].nat_flags_op = NAT_FLAG_OP_UNUSABLE
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
extern uint32_t arm64_crc(void* p, uint32_t len);
#define ARCH_CRC(A, B) if(arm64_crc32) return arm64_crc(A, B)
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B)
extern void* create_updateflags();
#define ARCH_UPDATEFLAGS() create_updateflags()
#define ARCH_NOP 0b11010101000000110010000000011111
#define ARCH_UDF 0xcafe
@@ -103,4 +105,6 @@ extern uint32_t arm64_crc(void* p, uint32_t len);
#error Unsupported platform
#endif
#include "dynacache_reloc.h"
#endif //__DYNAREC_ARCH__H_
+5 -5
View File
@@ -36,7 +36,7 @@
#define STRONGMEM_LAST_WRITE 1 // The level of a barrier before the last guest memory store will be put
#define STRONGMEM_SEQ_WRITE 3 // The level of a barrier at every third memory store will be put
#define STRONGMEM_LEVEL() (box64_wine && VolatileRangesContains(ip) ? 0 : BOX64DRENV(dynarec_strongmem))
#define STRONGMEM_LEVEL() ((box64_wine && VolatileRangesContains(ip)) ? 0 : BOX64DRENV(dynarec_strongmem))
#if STEP == 1
@@ -49,10 +49,10 @@
dyn->insts[ninst].will_write = 1; \
} while (0)
#define SMWRITELOCK(lock) \
do { \
dyn->insts[ninst].lock = lock; \
SMWRITE(); \
#define SMWRITELOCK(lock) \
do { \
if(lock) dyn->insts[ninst].lock = 1;\
SMWRITE(); \
} while (0)
#define SMWRITE2() \
+111 -131
View File
@@ -23,6 +23,9 @@
#include "dynarec_arch.h"
#include "dynarec_next.h"
#include "gdbjit.h"
#include "khash.h"
KHASH_MAP_INIT_INT64(table64, uint32_t)
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
uint8_t *ip = (uint8_t*)inst->addr;
@@ -293,27 +296,51 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
}
}
static kh_table64_t* khtable64 = NULL;
int isTable64(dynarec_native_t *dyn, uint64_t val)
{
if(!khtable64)
return 0;
if(kh_get(table64, khtable64, val)==kh_end(khtable64))
return 0;
return 1;
}
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
{
if(!khtable64)
khtable64 = kh_init(table64);
// find the value if already present
int idx = -1;
for(int i=0; i<dyn->table64size && (idx==-1); ++i)
if(dyn->table64[i] == val)
idx = i;
// not found, add it
if(idx==-1) {
khint_t k = kh_get(table64, khtable64, val);
uint32_t idx = 0;
if(k!=kh_end(khtable64)) {
idx = kh_value(khtable64, k);
} else {
idx = dyn->table64size++;
if(idx < dyn->table64cap)
dyn->table64[idx] = val;
else if(pass==3)
printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap);
if(pass==3) {
if(idx < dyn->table64cap)
dyn->table64[idx] = val;
else
printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap);
}
int ret;
k = kh_put(table64, khtable64, val, &ret);
kh_value(khtable64, k) = idx;
}
// calculate offset
int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
return delta;
}
void ResetTable64(dynarec_native_t* dyn)
{
dyn->table64size = 0;
if(khtable64) {
kh_clear(table64, khtable64);
}
}
static void recurse_mark_alive(dynarec_native_t* dyn, int i)
{
if(dyn->insts[i].x64.alive)
@@ -325,9 +352,8 @@ static void recurse_mark_alive(dynarec_native_t* dyn, int i)
recurse_mark_alive(dyn, i+1);
}
static int sizePredecessors(dynarec_native_t* dyn)
static void sizePredecessors(dynarec_native_t* dyn)
{
int pred_sz = 1; // to be safe
// compute total size of predecessor to allocate the array
// mark alive...
recurse_mark_alive(dyn, 0);
@@ -335,7 +361,6 @@ static int sizePredecessors(dynarec_native_t* dyn)
int jmpto;
for(int i=0; i<dyn->size; ++i) {
if(dyn->insts[i].x64.alive && dyn->insts[i].x64.jmp && ((jmpto=dyn->insts[i].x64.jmp_insts)!=-1)) {
pred_sz++;
dyn->insts[jmpto].pred_sz++;
}
}
@@ -347,11 +372,9 @@ static int sizePredecessors(dynarec_native_t* dyn)
// second the "has_next"
for(int i=0; i<dyn->size-1; ++i) {
if(dyn->insts[i].x64.has_next) {
pred_sz++;
dyn->insts[i+1].pred_sz++;
}
}
return pred_sz;
}
static void fillPredecessors(dynarec_native_t* dyn)
{
@@ -417,93 +440,13 @@ static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
return ninst;
}
static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached) {
int can_incr = ninst == max_ninst_reached; // Are we the top-level call?
int ok = 1;
while ((can_incr || ok) && ninst<dyn->size) {
//if(dyn->need_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
if (dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
// The union of the empty set is empty (0), the intersection is the universe (-1)
// The first instruction is the entry point, which has a virtual pred with ymm0_out = 0
// Similarly, float barriers reset ymm0s
uint16_t ymm0_union = 0;
uint16_t ymm0_inter = (ninst && !(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? ((uint16_t)-1) : (uint16_t)0;
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
int pred = dyn->insts[ninst].pred[i];
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
if (pred >= max_ninst_reached) {
//if(dyn->need_dump) dynarec_log(LOG_NONE, " (skipped)\n");
continue;
}
int pred_out = dyn->insts[pred].x64.has_callret ? 0 : dyn->insts[pred].ymm0_out;
//if(dyn->need_dump) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
ymm0_union |= pred_out;
ymm0_inter &= pred_out;
}
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
// Notice the default values yield something coherent here (if all pred are after ninst)
new_purge_ymm = ymm0_union & ~ymm0_inter;
new_ymm0_in = ymm0_inter;
new_ymm0_out = (ymm0_inter | dyn->insts[ninst].ymm0_add) & ~dyn->insts[ninst].ymm0_sub;
if ((dyn->insts[ninst].purge_ymm != new_purge_ymm) || (dyn->insts[ninst].ymm0_in != new_ymm0_in) || (dyn->insts[ninst].ymm0_out != new_ymm0_out)) {
// Need to update self and next(s)
dyn->insts[ninst].purge_ymm = new_purge_ymm;
dyn->insts[ninst].ymm0_in = new_ymm0_in;
dyn->insts[ninst].ymm0_out = new_ymm0_out;
if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
++max_ninst_reached;
} else {
// We need to stop here if the opcode has no "real" next or if we reached the ninst of the toplevel
ok = (max_ninst_reached - 1 != ninst) && dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].x64.has_callret;
}
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
if((jmp!=-1) && (jmp < max_ninst_reached)) {
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
// The jump goes before the last instruction reached, update the destination
// If this is the top level call, this means the jump goes backward (jmp != ninst)
// Otherwise, since we don't update all instructions, we may miss the update (don't use jmp < ninst)
updateYmm0s(dyn, jmp, max_ninst_reached);
}
} else {
if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
++max_ninst_reached;
// Also update jumps to before (they are skipped otherwise)
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
if((jmp!=-1) && (jmp < max_ninst_reached)) {
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
updateYmm0s(dyn, jmp, max_ninst_reached);
}
} else {
// We didn't update anything, we can leave
ok = 0;
}
}
} else if (can_incr) {
// We always have ninst == max_ninst_reached when can_incr == 1
++max_ninst_reached;
} else {
// We didn't update anything, we can leave
ok = 0;
}
++ninst;
}
}
void* current_helper = NULL;
static int static_jmps[MAX_INSTS+2];
static uintptr_t static_next[MAX_INSTS+2];
static uint64_t static_table64[(MAX_INSTS+3)/4];
static instruction_native_t static_insts[MAX_INSTS+2] = {0};
static callret_t static_callrets[MAX_INSTS+2] = {0};
static int static_preds[MAX_INSTS*2+2]; // for the worst case scenario were all instructions are conditional jumps
void* redundant_helper = NULL;
// TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory
void ClearCache(void* start, size_t len)
@@ -549,6 +492,7 @@ void CancelBlock64(int need_lock)
}
}
current_helper = NULL;
redundant_helper = NULL;
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
}
@@ -558,17 +502,21 @@ uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max);
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max);
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr, int is32bits) {
block->isize = 0;
block->done = 0;
size_t sz = 4*sizeof(void*);
void* actual_p = (void*)AllocDynarecMap(sz);
dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
size_t sz = 4*sizeof(void*) + sizeof(dynablock_t);
void* actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
void* p = actual_p + sizeof(void*);
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
CancelBlock64(0);
return NULL;
}
dynablock_t* block = (dynablock_t*)(actual_p+4*sizeof(void*));
memset(block, 0, sizeof(dynablock_t));
// fill the block
block->x64_addr = (void*)addr;
block->isize = 0;
block->done = 0;
block->size = sz;
block->actual_block = actual_p;
block->block = p;
@@ -582,7 +530,7 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr, int is32bits) {
return block;
}
void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bits, int inst_max) {
dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_max, int is_new) {
/*
A Block must have this layout:
@@ -599,16 +547,19 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
*/
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
return CreateEmptyBlock(block, addr, is32bits);
}
if(current_helper) {
dynarec_log(LOG_DEBUG, "Canceling dynarec FillBlock at %p as another one is going on\n", (void*)addr);
return NULL;
return CreateEmptyBlock(addr, is32bits, is_new);
}
if(checkInHotPage(addr)) {
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p as in a HotPage\n", (void*)addr);
return NULL;
}
if(current_helper) {
if(current_helper==redundant_helper) {
dynarec_log(LOG_INFO, "%04d|Warning: previous FillBlock did not cleaned up correctly (helper=%p, x64addr=%p, db=%p)\n", GetTID(), current_helper, (void*)((dynarec_native_t*)current_helper)->start, ((dynarec_native_t*)current_helper)->dynablock);
return NULL;
}
dynarec_log(LOG_INFO, "Warning: some static area curruption appeared (current=%p, redundant=%p)\n", current_helper, redundant_helper);
}
// protect the 1st page
protectDB(addr, 1);
// init the helper
@@ -617,8 +568,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
#ifdef GDBJIT
helper.gdbjit_block = box_calloc(1, sizeof(gdbjit_block_t));
#endif
current_helper = &helper;
helper.dynablock = block;
redundant_helper = current_helper = &helper;
helper.dynablock = NULL;
helper.start = addr;
uintptr_t start = addr;
helper.cap = MAX_INSTS;
@@ -627,8 +578,14 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
helper.jmp_cap = MAX_INSTS;
helper.next = static_next;
helper.next_cap = MAX_INSTS;
helper.table64 = static_table64;
helper.table64cap = sizeof(static_table64)/sizeof(uint64_t);
helper.table64 = NULL;
helper.env = GetCurEnvByAddr(addr);
ResetTable64(&helper);
helper.table64cap = 0;
helper.end = addr + SizeFileMapped(addr);
if(helper.end == helper.start) // that means there is no mmap with a file associated to the memory
helper.end = (uintptr_t)~0LL;
helper.need_reloc = IsAddrNeedReloc(addr);
// pass 0, addresses, x64 jump addresses, overall size of the block
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits, inst_max);
if(helper.abort) {
@@ -643,7 +600,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
if(!helper.size) {
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
CancelBlock64(0);
return CreateEmptyBlock(block, addr, is32bits);
return CreateEmptyBlock(addr, is32bits, is_new);
}
if(!isprotectedDB(addr, 1)) {
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
@@ -667,6 +624,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
#endif
{
helper.insts[i].x64.need_after |= X_PEND;
if(helper.insts[i].barrier_maybe) {
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
helper.insts[i].barrier_maybe = 0;
}
} else {
// find jump address instruction
int k=-1;
@@ -699,8 +660,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
k=i2;
}*/
if(k!=-1) {
if(!helper.insts[i].barrier_maybe)
helper.insts[k].x64.barrier |= BARRIER_FULL;
// special case, loop on itself with some nop in between
if(k<i && !helper.insts[i].x64.has_next && is_nops(&helper, helper.insts[k].x64.addr, helper.insts[i].x64.addr-helper.insts[k].x64.addr)) {
#ifndef ARCH_NOP
@@ -711,12 +670,18 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
#endif
}
helper.insts[i].x64.jmp_insts = k;
helper.insts[i].barrier_maybe = 0;
} else {
if(helper.insts[i].barrier_maybe) {
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
helper.insts[i].barrier_maybe = 0;
}
}
}
}
// fill predecessors with the jump address
int alloc_size = sizePredecessors(&helper);
helper.predecessor = (int*)alloca(alloc_size*sizeof(int));
sizePredecessors(&helper);
helper.predecessor = static_preds;
fillPredecessors(&helper);
PREUPDATE_SPECIFICS(&helper);
@@ -730,7 +695,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
int ii = i;
while(ii<helper.size && !helper.insts[ii].pred_sz) {
fpu_reset_ninst(&helper, ii);
helper.insts[ii].ymm0_in = helper.insts[ii].ymm0_sub = helper.insts[ii].ymm0_add = helper.insts[ii].ymm0_out = helper.insts[ii].purge_ymm = 0;
RAZ_SPECIFIC(&helper, ii);
++ii;
}
@@ -745,9 +709,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
// NULL block after removing dead code, how is that possible?
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
CancelBlock64(0);
return CreateEmptyBlock(block, addr, is32bits);
return CreateEmptyBlock(addr, is32bits, is_new);
}
updateYmm0s(&helper, 0, 0);
UPDATE_SPECIFICS(&helper);
// check for still valid close loop
for(int ii=0; ii<helper.jmp_sz && !helper.always_test; ++ii) {
@@ -763,7 +726,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
// no need for next anymore
helper.next_sz = helper.next_cap = 0;
helper.next = NULL;
ResetTable64(&helper);
helper.reloc_size = 0;
// pass 1, float optimizations, first pass for flags
native_pass1(&helper, addr, alternate, is32bits, inst_max);
if(helper.abort) {
@@ -776,6 +740,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
helper.need_x87check = 0;
}
POSTUPDATE_SPECIFICS(&helper);
ResetTable64(&helper);
helper.reloc_size = 0;
// pass 2, instruction size
helper.callrets = static_callrets;
native_pass2(&helper, addr, alternate, is32bits, inst_max);
@@ -798,16 +764,17 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
--imax;
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock oversized, with %zu (max=%zd), recomputing cutting at %d from %d\n", native_size, MAXBLOCK_SIZE, imax, helper.size);
CancelBlock64(0);
return FillBlock64(block, addr, alternate, is32bits, imax);
return FillBlock64(addr, alternate, is32bits, imax, is_new);
}
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
insts_rsize = (insts_rsize+7)&~7; // round the size...
size_t arch_size = ARCH_SIZE(&helper);
size_t callret_size = helper.callret_size*sizeof(callret_t);
size_t reloc_size = helper.reloc_size*sizeof(uint32_t);
// ok, now allocate mapped memory, with executable flag on
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size;
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets
void* actual_p = (void*)AllocDynarecMap(sz);
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size + sizeof(dynablock_t) + reloc_size;
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets dynablock relocs
void* actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
void* tablestart = p + native_size;
void* next = tablestart + helper.table64size*sizeof(uint64_t);
@@ -815,12 +782,21 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
void* arch = instsize + insts_rsize;
void* callrets = arch + arch_size;
if(actual_p==NULL) {
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
CancelBlock64(0);
return NULL;
}
helper.block = p;
dynablock_t* block = (dynablock_t*)(callrets+callret_size);
memset(block, 0, sizeof(dynablock_t));
void* relocs = helper.need_reloc?(block+1):NULL;
// fill the block
block->x64_addr = (void*)addr;
block->isize = 0;
block->actual_block = actual_p;
helper.relocs = relocs;
block->relocs = relocs;
block->table64size = helper.table64size;
helper.native_start = (uintptr_t)p;
helper.tablestart = (uintptr_t)tablestart;
helper.jmp_next = (uintptr_t)next+sizeof(void*);
@@ -829,6 +805,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
helper.table64cap = helper.table64size;
helper.table64 = (uint64_t*)helper.tablestart;
helper.callrets = (callret_t*)callrets;
block->table64 = helper.table64;
if(callret_size)
memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t));
helper.callret_size = 0;
@@ -846,8 +823,9 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
size_t oldinstsize = helper.insts_size;
int oldsize= helper.size;
helper.native_size = 0;
helper.table64size = 0; // reset table64 (but not the cap)
ResetTable64(&helper); // reset table64 (but not the cap)
helper.insts_size = 0; // reset
helper.reloc_size = 0;
native_pass3(&helper, addr, alternate, is32bits, inst_max);
if(helper.abort) {
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
@@ -869,6 +847,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
block->always_test = helper.always_test;
block->dirty = block->always_test;
block->is32bits = is32bits;
block->relocsize = helper.reloc_size*sizeof(uint32_t);
if(arch_size) {
block->arch_size = arch_size;
block->arch = ARCH_FILL(&helper, arch, arch_size);
@@ -879,6 +858,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
}
block->callret_size = helper.callret_size;
block->callrets = helper.callrets;
block->native_size = native_size;
*(dynablock_t**)next = block;
*(void**)(next+3*sizeof(void*)) = native_next;
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
@@ -920,6 +900,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
return NULL;
}
// ok, free the helper now
ResetTable64(&helper);
//dynaFree(helper.insts);
helper.insts = NULL;
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
@@ -931,7 +912,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
//protectDB(addr, end-addr);
}
if(getProtection(addr)&PROT_NEVERCLEAN) {
block->dirty = 1;
block->always_test = 1;
}
if(block->always_test) {
@@ -943,7 +923,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
*(uint32_t*)(block->block+block->callrets[i].offs) = ARCH_UDF;
#endif
}
current_helper = NULL;
redundant_helper = current_helper = NULL;
//block->done = 1;
return (void*)block;
return block;
}
+193 -53
View File
@@ -7,6 +7,7 @@
#include <sys/types.h>
#include <unistd.h>
#include "x64_signals.h"
#include "os.h"
#include "debug.h"
#include "box64context.h"
@@ -37,7 +38,7 @@ void native_fstp(x64emu_t* emu, void* p)
void native_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
{
(void)emu;
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
dynarec_log(LOG_INFO, "Debug Register R%lu=0x%lx (%lu)\n", n, reg, reg);
}
void native_f2xm1(x64emu_t* emu)
@@ -186,20 +187,26 @@ void native_ud(x64emu_t* emu)
{
if(BOX64ENV(dynarec_test))
emu->test.test = 0;
EmitSignal(emu, SIGILL, (void*)R_RIP, 0);
EmitSignal(emu, X64_SIGILL, (void*)R_RIP, 0);
}
void native_br(x64emu_t* emu)
{
if(BOX64ENV(dynarec_test))
emu->test.test = 0;
EmitSignal(emu, SIGSEGV, (void*)R_RIP, 0xb09d);
EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xb09d);
}
void native_priv(x64emu_t* emu)
{
emu->test.test = 0;
EmitSignal(emu, SIGSEGV, (void*)R_RIP, 0xbad0);
EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xbad0);
}
void native_gpf(x64emu_t* emu)
{
emu->test.test = 0;
EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xbad0); // same effect has private opcode?
}
void native_int(x64emu_t* emu, int num)
@@ -216,7 +223,7 @@ void native_wineint(x64emu_t* emu, int num)
#endif
void native_int3(x64emu_t* emu)
{
EmitSignal(emu, SIGTRAP, NULL, 3);
EmitSignal(emu, X64_SIGTRAP, NULL, 3);
}
void native_div0(x64emu_t* emu)
@@ -235,6 +242,7 @@ void native_fsave(x64emu_t* emu, uint8_t* ed)
LD2D(p, &emu->x87[7-i].d);
p+=10;
}
reset_fpu(emu);
}
void native_fsave16(x64emu_t* emu, uint8_t* ed)
{
@@ -246,6 +254,7 @@ void native_fsave16(x64emu_t* emu, uint8_t* ed)
LD2D(p, &emu->x87[7-i].d);
p+=10;
}
reset_fpu(emu);
}
void native_frstor(x64emu_t* emu, uint8_t* ed)
{
@@ -294,6 +303,147 @@ void native_fprem1(x64emu_t* emu)
}
}
const uint8_t ff_mult2[4][256] = {
// a = 0x0e
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,
0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,
0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,
0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,
0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,
0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,
0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d,
// a = 0x09
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,
0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,
0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,
0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,
0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,
0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,
0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46,
// a = 0x0d
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,
0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,
0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,
0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,
0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,
0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,
0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97,
// a = 0x0b
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,
0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,
0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,
0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,
0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,
0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,
0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3,
};
const uint8_t ff_mult3[4][256] = {
// a = 0x02
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5,
// a = 0x01
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
// a = 0x01
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
// a = 0x03
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a,
};
static uint8_t ff_mult(uint8_t a, uint8_t b)
{
int retval = 0;
@@ -320,10 +470,15 @@ void native_aesimc(x64emu_t* emu, int xmm)
sse_regs_t eax1 = emu->xmm[xmm];
for(int j=0; j<4; ++j) {
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
// 0x0E -> 0, 0x09 -> 1, 0x0D -> 2, 0x0B -> 3
// emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
// emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
// emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
// emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[0+j*4] = ff_mult2[0][eax1.ub[0+j*4]] ^ ff_mult2[3][eax1.ub[1+j*4]] ^ ff_mult2[2][eax1.ub[2+j*4]] ^ ff_mult2[1][eax1.ub[3+j*4]];
emu->xmm[xmm].ub[1+j*4] = ff_mult2[1][eax1.ub[0+j*4]] ^ ff_mult2[0][eax1.ub[1+j*4]] ^ ff_mult2[3][eax1.ub[2+j*4]] ^ ff_mult2[2][eax1.ub[3+j*4]];
emu->xmm[xmm].ub[2+j*4] = ff_mult2[2][eax1.ub[0+j*4]] ^ ff_mult2[1][eax1.ub[1+j*4]] ^ ff_mult2[0][eax1.ub[2+j*4]] ^ ff_mult2[3][eax1.ub[3+j*4]];
emu->xmm[xmm].ub[3+j*4] = ff_mult2[3][eax1.ub[0+j*4]] ^ ff_mult2[2][eax1.ub[1+j*4]] ^ ff_mult2[1][eax1.ub[2+j*4]] ^ ff_mult2[0][eax1.ub[3+j*4]];
}
}
void native_aesimc_y(x64emu_t* emu, int ymm)
@@ -331,10 +486,14 @@ void native_aesimc_y(x64emu_t* emu, int ymm)
sse_regs_t eay1 = emu->ymm[ymm];
for(int j=0; j<4; ++j) {
emu->ymm[ymm].ub[0+j*4] = ff_mult(0x0E, eay1.ub[0+j*4]) ^ ff_mult(0x0B, eay1.ub[1+j*4]) ^ ff_mult(0x0D, eay1.ub[2+j*4]) ^ ff_mult(0x09, eay1.ub[3+j*4]);
emu->ymm[ymm].ub[1+j*4] = ff_mult(0x09, eay1.ub[0+j*4]) ^ ff_mult(0x0E, eay1.ub[1+j*4]) ^ ff_mult(0x0B, eay1.ub[2+j*4]) ^ ff_mult(0x0D, eay1.ub[3+j*4]);
emu->ymm[ymm].ub[2+j*4] = ff_mult(0x0D, eay1.ub[0+j*4]) ^ ff_mult(0x09, eay1.ub[1+j*4]) ^ ff_mult(0x0E, eay1.ub[2+j*4]) ^ ff_mult(0x0B, eay1.ub[3+j*4]);
emu->ymm[ymm].ub[3+j*4] = ff_mult(0x0B, eay1.ub[0+j*4]) ^ ff_mult(0x0D, eay1.ub[1+j*4]) ^ ff_mult(0x09, eay1.ub[2+j*4]) ^ ff_mult(0x0E, eay1.ub[3+j*4]);
// emu->ymm[ymm].ub[0+j*4] = ff_mult(0x0E, eay1.ub[0+j*4]) ^ ff_mult(0x0B, eay1.ub[1+j*4]) ^ ff_mult(0x0D, eay1.ub[2+j*4]) ^ ff_mult(0x09, eay1.ub[3+j*4]);
// emu->ymm[ymm].ub[1+j*4] = ff_mult(0x09, eay1.ub[0+j*4]) ^ ff_mult(0x0E, eay1.ub[1+j*4]) ^ ff_mult(0x0B, eay1.ub[2+j*4]) ^ ff_mult(0x0D, eay1.ub[3+j*4]);
// emu->ymm[ymm].ub[2+j*4] = ff_mult(0x0D, eay1.ub[0+j*4]) ^ ff_mult(0x09, eay1.ub[1+j*4]) ^ ff_mult(0x0E, eay1.ub[2+j*4]) ^ ff_mult(0x0B, eay1.ub[3+j*4]);
// emu->ymm[ymm].ub[3+j*4] = ff_mult(0x0B, eay1.ub[0+j*4]) ^ ff_mult(0x0D, eay1.ub[1+j*4]) ^ ff_mult(0x09, eay1.ub[2+j*4]) ^ ff_mult(0x0E, eay1.ub[3+j*4]);
emu->ymm[ymm].ub[0+j*4] = ff_mult2[0][eay1.ub[0+j*4]] ^ ff_mult2[3][eay1.ub[1+j*4]] ^ ff_mult2[2][eay1.ub[2+j*4]] ^ ff_mult2[1][eay1.ub[3+j*4]];
emu->ymm[ymm].ub[1+j*4] = ff_mult2[1][eay1.ub[0+j*4]] ^ ff_mult2[0][eay1.ub[1+j*4]] ^ ff_mult2[3][eay1.ub[2+j*4]] ^ ff_mult2[2][eay1.ub[3+j*4]];
emu->ymm[ymm].ub[2+j*4] = ff_mult2[2][eay1.ub[0+j*4]] ^ ff_mult2[1][eay1.ub[1+j*4]] ^ ff_mult2[0][eay1.ub[2+j*4]] ^ ff_mult2[3][eay1.ub[3+j*4]];
emu->ymm[ymm].ub[3+j*4] = ff_mult2[3][eay1.ub[0+j*4]] ^ ff_mult2[2][eay1.ub[1+j*4]] ^ ff_mult2[1][eay1.ub[2+j*4]] ^ ff_mult2[0][eay1.ub[3+j*4]];
}
}
void native_aesmc(x64emu_t* emu, int xmm)
@@ -342,10 +501,15 @@ void native_aesmc(x64emu_t* emu, int xmm)
sse_regs_t eax1 = emu->xmm[xmm];
for(int j=0; j<4; ++j) {
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
// 0x02 -> 0, 0x01 -> 1, 0x01 -> 2, 0x03 -> 3
// emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
// emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
// emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
// emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
emu->xmm[xmm].ub[0+j*4] = ff_mult3[0][eax1.ub[0+j*4]] ^ ff_mult3[3][eax1.ub[1+j*4]] ^ ff_mult3[2][eax1.ub[2+j*4]] ^ ff_mult3[1][eax1.ub[3+j*4]];
emu->xmm[xmm].ub[1+j*4] = ff_mult3[1][eax1.ub[0+j*4]] ^ ff_mult3[0][eax1.ub[1+j*4]] ^ ff_mult3[3][eax1.ub[2+j*4]] ^ ff_mult3[2][eax1.ub[3+j*4]];
emu->xmm[xmm].ub[2+j*4] = ff_mult3[2][eax1.ub[0+j*4]] ^ ff_mult3[1][eax1.ub[1+j*4]] ^ ff_mult3[0][eax1.ub[2+j*4]] ^ ff_mult3[3][eax1.ub[3+j*4]];
emu->xmm[xmm].ub[3+j*4] = ff_mult3[3][eax1.ub[0+j*4]] ^ ff_mult3[2][eax1.ub[1+j*4]] ^ ff_mult3[1][eax1.ub[2+j*4]] ^ ff_mult3[0][eax1.ub[3+j*4]];
}
}
void native_aesmc_y(x64emu_t* emu, int ymm)
@@ -353,16 +517,20 @@ void native_aesmc_y(x64emu_t* emu, int ymm)
sse_regs_t eay1 = emu->ymm[ymm];
for(int j=0; j<4; ++j) {
emu->ymm[ymm].ub[0+j*4] = ff_mult(0x02, eay1.ub[0+j*4]) ^ ff_mult(0x03, eay1.ub[1+j*4]) ^ eay1.ub[2+j*4] ^ eay1.ub[3+j*4] ;
emu->ymm[ymm].ub[1+j*4] = eay1.ub[0+j*4] ^ ff_mult(0x02, eay1.ub[1+j*4]) ^ ff_mult(0x03, eay1.ub[2+j*4]) ^ eay1.ub[3+j*4] ;
emu->ymm[ymm].ub[2+j*4] = eay1.ub[0+j*4] ^ eay1.ub[1+j*4] ^ ff_mult(0x02, eay1.ub[2+j*4]) ^ ff_mult(0x03, eay1.ub[3+j*4]);
emu->ymm[ymm].ub[3+j*4] = ff_mult(0x03, eay1.ub[0+j*4]) ^ eay1.ub[1+j*4] ^ eay1.ub[2+j*4] ^ ff_mult(0x02, eay1.ub[3+j*4]);
// emu->ymm[ymm].ub[0+j*4] = ff_mult(0x02, eay1.ub[0+j*4]) ^ ff_mult(0x03, eay1.ub[1+j*4]) ^ eay1.ub[2+j*4] ^ eay1.ub[3+j*4] ;
// emu->ymm[ymm].ub[1+j*4] = eay1.ub[0+j*4] ^ ff_mult(0x02, eay1.ub[1+j*4]) ^ ff_mult(0x03, eay1.ub[2+j*4]) ^ eay1.ub[3+j*4] ;
// emu->ymm[ymm].ub[2+j*4] = eay1.ub[0+j*4] ^ eay1.ub[1+j*4] ^ ff_mult(0x02, eay1.ub[2+j*4]) ^ ff_mult(0x03, eay1.ub[3+j*4]);
// emu->ymm[ymm].ub[3+j*4] = ff_mult(0x03, eay1.ub[0+j*4]) ^ eay1.ub[1+j*4] ^ eay1.ub[2+j*4] ^ ff_mult(0x02, eay1.ub[3+j*4]);
emu->ymm[ymm].ub[0+j*4] = ff_mult3[0][eay1.ub[0+j*4]] ^ ff_mult3[3][eay1.ub[1+j*4]] ^ ff_mult3[2][eay1.ub[2+j*4]] ^ ff_mult3[1][eay1.ub[3+j*4]];
emu->ymm[ymm].ub[1+j*4] = ff_mult3[1][eay1.ub[0+j*4]] ^ ff_mult3[0][eay1.ub[1+j*4]] ^ ff_mult3[3][eay1.ub[2+j*4]] ^ ff_mult3[2][eay1.ub[3+j*4]];
emu->ymm[ymm].ub[2+j*4] = ff_mult3[2][eay1.ub[0+j*4]] ^ ff_mult3[1][eay1.ub[1+j*4]] ^ ff_mult3[0][eay1.ub[2+j*4]] ^ ff_mult3[3][eay1.ub[3+j*4]];
emu->ymm[ymm].ub[3+j*4] = ff_mult3[3][eay1.ub[0+j*4]] ^ ff_mult3[2][eay1.ub[1+j*4]] ^ ff_mult3[1][eay1.ub[2+j*4]] ^ ff_mult3[0][eay1.ub[3+j*4]];
}
}
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
// A N K H E B O L I F C P M J G D
static const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
static const uint8_t invsubbytes[256] = {
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
const uint8_t invsubbytes[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
@@ -402,8 +570,8 @@ void native_aesdlast_y(x64emu_t* emu, int ymm)
emu->ymm[ymm].ub[i] = invsubbytes[eay1.ub[i]];
}
static const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
static const uint8_t subbytes[256] = {
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
const uint8_t subbytes[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
@@ -617,34 +785,6 @@ uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
}
#undef F8
// AVX
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg)
{
dyn->ymm_zero |= (1<<reg);
}
int is_avx_zero(dynarec_native_t* dyn, int ninst, int reg)
{
return (dyn->ymm_zero>>reg)&1;
}
int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg)
{
if((dyn->ymm_zero>>reg)&1) {
dyn->ymm_zero &= ~(1<<reg);
return 1;
}
return 0;
}
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst)
{
dyn->ymm_zero = 0;
}
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg)
{
dyn->ymm_zero &= ~(1<<reg);
}
void propagate_nodf(dynarec_native_t* dyn, int ninst)
{
while(ninst>=0) {
+1 -7
View File
@@ -55,6 +55,7 @@ void native_clflush(x64emu_t* emu, void* p);
void native_ud(x64emu_t* emu);
void native_br(x64emu_t* emu);
void native_priv(x64emu_t* emu);
void native_gpf(x64emu_t* emu);
void native_int3(x64emu_t* emu);
void native_int(x64emu_t* emu, int num);
void native_wineint(x64emu_t* emu, int num);
@@ -74,13 +75,6 @@ uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
// return Ib on a mod/rm opcode without emitting anything
uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
// AVX utilities
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg);
int is_avx_zero(dynarec_native_t* dyn, int ninst, int reg);
int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg);
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst);
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg);
typedef struct register_mapping_s {
const char* name;
const char* native;
+15 -12
View File
@@ -69,7 +69,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
if(cur_page != ((addr)&~(box64_pagesize-1))) {
cur_page = (addr)&~(box64_pagesize-1);
uint32_t prot = getProtection(addr);
if(!(prot&PROT_READ) || checkInHotPage(addr)) {
if(!(prot&PROT_READ) || checkInHotPage(addr) || (addr>dyn->end)) {
dynarec_log(LOG_INFO, "Stopping dynablock because of protection, hotpage or mmap crossing at %p -> %p inst=%d\n", (void*)dyn->start, (void*)addr, ninst);
need_epilog = 1;
break;
}
@@ -116,7 +117,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
dyn->last_ip = 0; // reset IP if some jump are coming here
#endif
dyn->f.dfnone_here = 0;
NEW_INST;
MESSAGE(LOG_DUMP, "New Instruction %s:%p, native:%p\n", is32bits?"x86":"x64",(void*)addr, (void*)dyn->block);
#ifdef ARCH_NOP
@@ -134,8 +134,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
WILLWRITE();
}
int is_opcode_volatile = box64_wine && VolatileRangesContains(ip);
if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed && dyn->insts[ninst].will_write)
int is_opcode_volatile = /*box64_wine &&*/ VolatileRangesContains(ip) && VolatileOpcodesHas(ip);
if (is_opcode_volatile && !dyn->insts[ninst].lock)
DMB_ISHST();
#endif
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !ninst) {
@@ -168,11 +168,16 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
#endif
rep = 0;
rex.is32bits = is32bits;
uint8_t pk = PK(0);
while((pk==0xF2) || (pk==0xF3) || (pk==0x3E) || (pk==0x26)) {
while((pk==0xF2) || (pk==0xF3) || (pk==0x3E) || (pk==0x26)
|| (is32bits && ((pk==0x2E) || (pk==0x36)))
) {
switch(pk) {
case 0xF2: rep = 1; break;
case 0xF3: rep = 2; break;
case 0x2E:
case 0x36:
case 0x3E:
case 0x26: /* ignored */ break;
}
@@ -180,7 +185,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
pk = PK(0);
}
rex.rex = 0;
rex.is32bits = is32bits;
if(!rex.is32bits)
while(pk>=0x40 && pk<=0x4f) {
rex.rex = pk;
@@ -194,8 +198,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
INST_EPILOG;
#if STEP > 1
if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed && dyn->insts[ninst].will_read)
DMB_ISHLD();
if (is_opcode_volatile || dyn->insts[ninst].lock)
DMB_ISH();
#endif
fpu_reset_scratch(dyn);
@@ -255,7 +259,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
}
#else
// check if block need to be stopped, because it's a 00 00 opcode (unreadeable is already checked earlier)
if((ok>0) && !dyn->forward && !(*(uint32_t*)addr)) {
if((ok>0) && !dyn->forward && (!(getProtection(addr)&PROT_READ) || !(*(uint32_t*)addr))) {
if (dyn->need_dump) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00 00 00");
ok = 0;
need_epilog = 1;
@@ -299,7 +303,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
} else {
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
// and pred table is not ready yet
reset_n = get_first_jump(dyn, next);
reset_n = get_first_jump_addr(dyn, next);
}
if (dyn->need_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret ? "(opt. call) " : "", (void*)addr, (void*)next, ninst + 1, dyn->insts[ninst].x64.has_callret ? ninst : reset_n);
} else if (next && (int)(next - addr) < BOX64ENV(dynarec_forward) && (getProtection(next) & PROT_READ) /*BOX64DRENV(dynarec_bigblock)>=stopblock*/) {
@@ -346,8 +350,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
}
if((ok>0) && dyn->insts[ninst].x64.has_callret)
reset_n = -2;
if((ok>0) && reset_n==-1 && dyn->insts[ninst+1].purge_ymm)
PURGE_YMM();
PURGE_YMM();
++ninst;
#if STEP == 0
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
+4
View File
@@ -12,16 +12,20 @@ void arm64_epilog(void) EXPORTDYN;
void la64_next(void) EXPORTDYN;
void la64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
void la64_epilog(void) EXPORTDYN;
void la64_epilog_fast(void) EXPORTDYN;
#define native_next la64_next
#define native_prolog la64_prolog
#define native_epilog la64_epilog
#define native_epilog_fast la64_epilog_fast
#elif defined(RV64)
void rv64_next(void) EXPORTDYN;
void rv64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
void rv64_epilog(void) EXPORTDYN;
void rv64_epilog_fast(void) EXPORTDYN;
#define native_next rv64_next
#define native_prolog rv64_prolog
#define native_epilog rv64_epilog
#define native_epilog_fast rv64_epilog_fast
#else
#error Unsupported architecture
#endif
+113 -67
View File
@@ -2,8 +2,8 @@
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <signal.h>
#include "x64_signals.h"
#include "os.h"
#include "debug.h"
#include "box64context.h"
@@ -377,6 +377,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
i64 = F32S;
emit_sub32c(dyn, ninst, rex, xRAX, i64, x2, x3, x4, x5);
break;
case 0x2E:
INST_NAME("CS:");
break;
case 0x30:
INST_NAME("XOR Eb, Gb");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
@@ -669,9 +672,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
}
GETIP(ip);
GETIP(ip, x7);
STORE_XEMU_CALL();
CALL(native_priv, -1);
CALL(const_native_priv, -1, 0, 0);
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -685,9 +688,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
}
GETIP(ip);
GETIP(ip, x7);
STORE_XEMU_CALL();
CALL(native_priv, -1);
CALL(const_native_priv, -1, 0, 0);
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -700,7 +703,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
BARRIER(BARRIER_MAYBE); \
JUMP(addr + i8, 1); \
if (!dyn->insts[ninst].nat_flags_fusion) { \
if (la64_lbt) { \
if (cpuext.lbt) { \
X64_SETJ(tmp1, I); \
} else { \
GETFLAGS; \
@@ -712,7 +715,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32); \
} else { \
if (la64_lbt) \
if (cpuext.lbt) \
BEQZ_safe(tmp1, i32); \
else \
B##NO##_safe(tmp1, i32); \
@@ -732,7 +735,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32); \
} else { \
if (la64_lbt) \
if (cpuext.lbt) \
BNEZ_safe(tmp1, i32); \
else \
B##YES##_safe(tmp1, i32); \
@@ -980,11 +983,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
GETGB(x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (la64_lam_bh) {
if (cpuext.lam_bh) {
AMSWAP_DB_B(x1, gd, ed);
BSTRINS_D(gb1, x1, gb2 + 7, gb2);
} else {
SMDMB();
// calculate shift amount
ANDI(x1, ed, 0x3);
@@ -1027,7 +1029,6 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
GETGD;
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
SMDMB();
ANDI(x3, ed, (1 << (2 + rex.w)) - 1);
BNEZ_MARK(x3);
MARKLOCK;
@@ -1040,7 +1041,6 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
LDxw(x1, ed, 0);
SDxw(gd, ed, 0);
MARK2;
SMDMB();
MVxw(gd, x1);
}
break;
@@ -1671,7 +1671,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETEB(x1, 1);
u8 = F8;
MOV32w(x2, u8);
CALL_(rol8, ed, x3);
CALL_(const_rol8, ed, x3, x1, x2);
EBBACK();
break;
case 4:
@@ -1868,6 +1868,45 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
*need_epilog = 0;
*ok = 0;
break;
case 0xC4:
nextop = F8;
if (rex.is32bits && !(MODREG)) {
DEFAULT;
} else {
vex_t vex = { 0 };
vex.rex = rex;
u8 = nextop;
vex.m = u8 & 0b00011111;
vex.rex.b = (u8 & 0b00100000) ? 0 : 1;
vex.rex.x = (u8 & 0b01000000) ? 0 : 1;
vex.rex.r = (u8 & 0b10000000) ? 0 : 1;
u8 = F8;
vex.p = u8 & 0b00000011;
vex.l = (u8 >> 2) & 1;
vex.v = ((~u8) >> 3) & 0b1111;
vex.rex.w = (u8 >> 7) & 1;
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
}
break;
case 0xC5:
nextop = F8;
if (rex.is32bits && !(MODREG)) {
DEFAULT;
} else {
vex_t vex = { 0 };
vex.rex = rex;
u8 = nextop;
vex.p = u8 & 0b00000011;
vex.l = (u8 >> 2) & 1;
vex.v = ((~u8) >> 3) & 0b1111;
vex.rex.r = (u8 & 0b10000000) ? 0 : 1;
vex.rex.b = 0;
vex.rex.x = 0;
vex.rex.w = 0;
vex.m = VEX_M_0F;
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
}
break;
case 0xC6:
INST_NAME("MOV Eb, Ib");
nextop = F8;
@@ -1940,13 +1979,13 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
// FIXME: Even the basic support of isSimpleWrapper is disabled for now.
GETIP(ip + 1); // read the 0xCC
GETIP(ip + 1, x7); // read the 0xCC
STORE_XEMU_CALL();
ADDI_D(x3, xRIP, 8 + 8 + 2); // expected return address
ADDI_D(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
CALL_S(EmuInt3, -1);
CALL_(const_int3, -1, x3, x1, 0);
LOAD_XEMU_CALL();
addr += 8 + 8;
TABLE64(x3, addr); // expected return address
BNE_MARK(xRIP, x3);
LD_W(x1, xEmu, offsetof(x64emu_t, quit));
CBZ_NEXT(x1);
@@ -1957,13 +1996,13 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("INT 3");
if (!BOX64ENV(ignoreint3)) {
// check if TRAP signal is handled
TABLE64(x1, (uintptr_t)my_context);
MOV32w(x2, offsetof(box64context_t, signals[SIGTRAP]));
TABLE64C(x1, const_context);
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
LDX_D(x3, x1, x2);
BEQZ_MARK(x3);
GETIP(addr);
GETIP(addr, x7);
STORE_XEMU_CALL();
CALL(native_int3, -1);
CALL(const_native_int3, -1, 0, 0);
LOAD_XEMU_CALL();
MARK;
jump_to_epilog(dyn, addr, 0, ninst);
@@ -1978,18 +2017,18 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("INT 29/2c/2d");
// lets do nothing
MESSAGE(LOG_INFO, "INT 29/2c/2d Windows interruption\n");
GETIP(ip); // priviledged instruction, IP not updated
GETIP(ip, x7); // priviledged instruction, IP not updated
STORE_XEMU_CALL();
MOV32w(x1, u8);
CALL(native_int, -1);
CALL(const_native_int, -1, x1, 0);
LOAD_XEMU_CALL();
} else if (u8 == 0x80) {
INST_NAME("32bits SYSCALL");
NOTEST(x1);
SMEND();
GETIP(addr);
GETIP(addr, x7);
STORE_XEMU_CALL();
CALL_S(EmuX86Syscall, -1);
CALL_S(const_x86syscall, -1, 0);
LOAD_XEMU_CALL();
TABLE64(x3, addr); // expected return address
BNE_MARK(xRIP, x3);
@@ -2005,9 +2044,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
}
GETIP(addr);
GETIP(addr, x7);
STORE_XEMU_CALL();
CALL(native_int3, -1);
CALL(const_native_int3, -1, 0, 0);
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -2019,9 +2058,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
}
GETIP(ip); // priviledged instruction, IP not updated
GETIP(ip, x7); // priviledged instruction, IP not updated
STORE_XEMU_CALL();
CALL(native_priv, -1);
CALL(const_native_priv, -1, 0, 0);
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -2052,7 +2091,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
MESSAGE(LOG_DUMP, "Need Optimization\n");
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
CALL_(rol8, ed, x3);
CALL_(const_rol8, ed, x3, x1, x2);
EBBACK();
break;
case 4:
@@ -2134,7 +2173,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
MOV32w(x2, 1);
GETEDW(x4, x1, 0);
CALL_(rex.w ? ((void*)rcr64) : ((void*)rcr32), ed, x4);
CALL_(rex.w ? const_rcr64 : const_rcr32, ed, x4, x1, x2);
WBACK;
if (!wback && !rex.w) ZEROUP(ed);
break;
@@ -2289,7 +2328,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
READFLAGS(X_ZF);
i8 = F8S;
ADDI_D(xRCX, xRCX, -1);
if (la64_lbt)
if (cpuext.lbt)
X64_GET_EFLAGS(x1, X_ZF);
else
ANDI(x1, xFlags, 1 << F_ZF);
@@ -2301,7 +2340,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
READFLAGS(X_ZF);
i8 = F8S;
ADDI_D(xRCX, xRCX, -1);
if (la64_lbt)
if (cpuext.lbt)
X64_GET_EFLAGS(x1, X_ZF);
else
ANDI(x1, xFlags, 1 << F_ZF);
@@ -2330,10 +2369,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
#endif
}
#if STEP < 2
if (!rex.is32bits && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
if (!rex.is32bits && !dyn->need_reloc && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
tmp = dyn->insts[ninst].pass2choice = 3;
else
tmp = dyn->insts[ninst].pass2choice = 0;
tmp = dyn->insts[ninst].pass2choice = i32 ? 0 : 1;
#else
tmp = dyn->insts[ninst].pass2choice;
#endif
@@ -2342,10 +2381,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags to "dont'care" state
SKIPTEST(x1);
BARRIER(BARRIER_FULL);
if (dyn->last_ip && (addr - dyn->last_ip < 0x800)) {
if (dyn->last_ip && ((addr - dyn->last_ip < 0x800) || (dyn->last_ip - addr < 0x800))) {
ADDI_D(x2, xRIP, addr - dyn->last_ip);
} else {
TABLE64(x2, addr);
if (dyn->need_reloc) {
TABLE64(x2, addr);
} else {
MOV64x(x2, addr);
}
}
PUSH1(x2);
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1)), dyn->insts[ninst].retn);
@@ -2362,17 +2405,17 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
// // return value will be on the stack, so the stack depth needs to be updated
// x87_purgecache(dyn, ninst, 0, x3, x1, x4);
if ((BOX64ENV(log) < 2 && !BOX64ENV(rolling_log)) && dyn->insts[ninst].natcall && tmp) {
// GETIP(ip+3+8+8); // read the 0xCC
// FIXME: call_n(dyn, ninst, *(void**)(dyn->insts[ninst].natcall + 2 + 8), tmp);
// GETIP(ip+3+8+8, x7); // read the 0xCC
// FIXME: call_n(dyn, ninst, (void*)(dyn->insts[ninst].natcall + 2 + 8), tmp);
POP1(xRIP); // pop the return address
dyn->last_ip = addr;
} else {
GETIP_(dyn->insts[ninst].natcall); // read the 0xCC already
GETIP_(dyn->insts[ninst].natcall, x7); // read the 0xCC already
STORE_XEMU_CALL();
ADDI_D(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
CALL_S(EmuInt3, -1);
CALL_S(const_int3, -1, x1);
LOAD_XEMU_CALL();
TABLE64(x3, dyn->insts[ninst].natcall);
MOV64x(x3, dyn->insts[ninst].natcall);
ADDI_D(x3, x3, 2 + 8 + 8);
BNE_MARK(xRIP, x3); // Not the expected address, exit dynarec block
POP1(xRIP); // pop the return address
@@ -2384,8 +2427,6 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ADD_D(xRSP, xRSP, x3);
}
}
TABLE64(x3, addr);
BNE_MARK(xRIP, x3); // Not the expected address again
LD_W(x1, xEmu, offsetof(x64emu_t, quit));
CBZ_NEXT(x1);
MARK;
@@ -2393,6 +2434,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
dyn->last_ip = addr;
}
break;
case 1:
// this is call to next step, so just push the return address to the stack
if (dyn->need_reloc) {
TABLE64(x2, addr);
} else {
MOV64x(x2, addr);
}
PUSH1z(x2);
break;
default:
if ((BOX64DRENV(dynarec_safeflags) > 1) || (ninst && dyn->insts[ninst - 1].x64.set_flags)) {
READFLAGS(X_PEND); // that's suspicious
@@ -2400,18 +2450,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags to "dont'care" state
}
// regular call
/*if (BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock) > 1) {
BARRIER(BARRIER_FULL);
} else {
BARRIER(BARRIER_FLOAT);
*need_epilog = 0;
*ok = 0;
}*/
if (rex.is32bits) {
MOV32w(x2, addr);
} else {
if (dyn->need_reloc) {
TABLE64(x2, addr);
} else {
MOV64x(x2, addr);
}
fpu_purgecache(dyn, ninst, 1, x1, x3, x4);
PUSH1z(x2);
@@ -2446,7 +2488,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
TABLE64(x4, j64);
if (dyn->need_reloc) {
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
} else {
MOV64x(x4, j64);
}
LD_D(x4, x4, 0);
BR(x4);
}
@@ -2496,9 +2543,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
}
GETIP(ip);
GETIP(ip, x7);
STORE_XEMU_CALL();
CALL(native_priv, -1);
CALL(const_native_priv, -1, 0, 0);
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -2508,7 +2555,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("CMC");
READFLAGS(X_CF);
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
if (la64_lbt) {
if (cpuext.lbt) {
X64_GET_EFLAGS(x3, X_CF);
XORI(x3, x3, 1 << F_CF);
X64_SET_EFLAGS(x3, X_CF);
@@ -2564,7 +2611,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MESSAGE(LOG_DUMP, "Need Optimization\n");
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
GETEB(x1, 0);
CALL(div8, -1);
CALL(const_div8, -1, x1, 0);
break;
default:
DEFAULT;
@@ -2674,8 +2721,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
GETEDH(x4, x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
BEQ_MARK(xRDX, xZR);
if (ed != x1) { MV(x1, ed); }
CALL(div64, -1);
CALL(const_div64, -1, ed, 0);
B_NEXT_nocond;
MARK;
DIV_DU(x2, xRAX, ed);
@@ -2720,8 +2766,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
BNE_MARK3(x2, xZR);
BLT_MARK(xRAX, xZR);
MARK3;
if (ed != x1) MV(x1, ed);
CALL((void*)idiv64, -1);
CALL(const_idiv64, -1, ed, 0);
B_NEXT_nocond;
MARK;
DIV_D(x2, xRAX, ed);
@@ -2739,7 +2784,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("CLC");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(xZR, X_CF);
else
BSTRINS_D(xFlags, xZR, F_CF, F_CF);
@@ -2748,7 +2793,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("STC");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
if (la64_lbt) {
if (cpuext.lbt) {
ORI(x3, xZR, 1 << F_CF);
X64_SET_EFLAGS(x3, X_CF);
} else {
@@ -2816,7 +2861,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
*need_epilog = 0;
*ok = 0;
}
GETIP_(addr);
GETIP_(addr, x7);
if (BOX64DRENV(dynarec_callret)) {
SET_HASCALLRET();
// Push actual return address
@@ -2842,7 +2887,8 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
TABLE64(x4, j64);
if (dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
TABLE64_(x4, j64);
LD_D(x4, x4, 0);
BR(x4);
}
+164 -96
View File
@@ -86,9 +86,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SYSCALL");
NOTEST(x1);
SMEND();
GETIP(addr);
GETIP(addr, x7);
STORE_XEMU_CALL();
CALL_S(EmuX64Syscall, -1);
CALL_S(const_x64syscall, -1, 0);
LOAD_XEMU_CALL();
TABLE64(x3, addr); // expected return address
BNE_MARK(xRIP, x3);
@@ -105,9 +105,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
}
GETIP(ip);
GETIP(ip, x7);
STORE_XEMU_CALL();
CALL(native_ud, -1);
CALL(const_native_ud, -1, 0, 0);
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
*need_epilog = 0;
@@ -125,7 +125,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
break;
case 0x10:
INST_NAME("MOVUPS Gx,Ex");
INST_NAME("MOVUPS Gx, Ex");
nextop = F8;
GETG;
if (MODREG) {
@@ -158,16 +158,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0x12:
nextop = F8;
if (MODREG) {
INST_NAME("MOVHLPS Gx,Ex");
INST_NAME("MOVHLPS Gx, Ex");
GETGX(v0, 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
VEXTRINS_D(v0, v1, 1);
} else {
INST_NAME("MOVLPS Gx,Ex");
INST_NAME("MOVLPS Gx, Ex");
GETGX(v0, 1);
SMREAD();
GETEX(q1, 0, 0);
VEXTRINS_D(v0, q1, 0);
v1 = fpu_get_scratch(dyn);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
FLD_D(v1, ed, fixedaddress);
VEXTRINS_D(v0, v1, 0);
}
break;
case 0x13:
@@ -202,11 +204,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0x16:
nextop = F8;
if (MODREG) {
INST_NAME("MOVLHPS Gx,Ex");
INST_NAME("MOVLHPS Gx, Ex");
GETGX(v0, 1);
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
} else {
INST_NAME("MOVHPS Gx,Ex");
INST_NAME("MOVHPS Gx, Ex");
SMREAD();
GETGX(v0, 1);
v1 = fpu_get_scratch(dyn);
@@ -247,13 +249,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
break;
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
INST_NAME("NOP (multibyte)");
nextop = F8;
FAKEED;
break;
case 0x28:
INST_NAME("MOVAPS Gx,Ex");
INST_NAME("MOVAPS Gx, Ex");
nextop = F8;
GETG;
if (MODREG) {
@@ -295,7 +302,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VEXTRINS_D(v0, q0, VEXTRINS_IMM_4_0(0, 0));
break;
case 0x2B:
INST_NAME("MOVNTPS Ex,Gx");
INST_NAME("MOVNTPS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
@@ -309,10 +316,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
break;
case 0x2C:
INST_NAME("CVTTPS2PI Gm,Ex");
INST_NAME("CVTTPS2PI Gm, Ex");
nextop = F8;
GETGM(v0);
GETEX(v1, 0, 0);
GETEXSD(v1, 0, 0);
if (BOX64ENV(dynarec_fastround)) {
VFTINTRZ_W_S(v0, v1);
} else {
@@ -339,7 +346,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("CVTPS2PI Gm, Ex");
nextop = F8;
GETGM(v0);
GETEX(v1, 0, 0);
GETEXSD(v1, 0, 0);
u8 = sse_setround(dyn, ninst, x4, x6);
if (BOX64ENV(dynarec_fastround)) {
VFTINTRZ_W_S(v0, v1);
@@ -420,7 +427,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("RDTSC");
NOTEST(x1);
if (box64_rdtsc) {
CALL(ReadTSC, x3); // will return the u64 in x3
CALL(const_readtsc, x3, 0, 0); // will return the u64 in x3
} else {
RDTIME_D(x3, xZR);
}
@@ -485,21 +492,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSHUF4I_W(q0, q0, 0b11011000);
break;
case 0x04:
INST_NAME("PMADDUBSW Gm,Em");
INST_NAME("PMADDUBSW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VEXT2XV_HU_BU(v0, q0);
VEXT2XV_H_B(v1, q1);
XVMUL_H(v0, v0, v1);
VPICKEV_H(q0, v1, v0);
VPICKOD_H(v0, v1, v0);
VSADD_H(q0, v0, q0);
VMULWEV_H_BU_B(v0, q0, q1);
VMULWOD_H_BU_B(v1, q0, q1);
VSADD_H(q0, v0, v1);
break;
case 0x05:
INST_NAME("PHSUBW Gm,Em");
INST_NAME("PHSUBW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -511,7 +515,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSHUF4I_W(q0, q0, 0b11011000);
break;
case 0x06:
INST_NAME("PHSUBD Gm,Em");
INST_NAME("PHSUBD Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -523,7 +527,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSHUF4I_W(q0, q0, 0b11011000);
break;
case 0x07:
INST_NAME("PHSUBSW Gm,Em");
INST_NAME("PHSUBSW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -535,28 +539,28 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSHUF4I_W(q0, q0, 0b11011000);
break;
case 0x08:
INST_NAME("PSIGNB Gm,Em");
INST_NAME("PSIGNB Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
VSIGNCOV_B(q0, q1, q0);
break;
case 0x09:
INST_NAME("PSIGNW Gm,Em");
INST_NAME("PSIGNW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
VSIGNCOV_H(q0, q1, q0);
break;
case 0x0A:
INST_NAME("PSIGND Gm,Em");
INST_NAME("PSIGND Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
VSIGNCOV_W(q0, q1, q0);
break;
case 0x0B:
INST_NAME("PMULHRSW Gm,Em");
INST_NAME("PMULHRSW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -570,7 +574,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSRLNI_H_W(q0, v0, 1);
break;
case 0x1C:
INST_NAME("PABSB Gm,Em");
INST_NAME("PABSB Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -579,7 +583,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VABSD_B(q0, q1, v0);
break;
case 0x1D:
INST_NAME("PABSW Gm,Em");
INST_NAME("PABSW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -588,7 +592,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VABSD_H(q0, q1, v0);
break;
case 0x1E:
INST_NAME("PABSD Gm,Em");
INST_NAME("PABSD Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
@@ -623,12 +627,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ed = (nextop & 7) + (rex.b << 3);
sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
ed = x2;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
if (ed != x2) {
MV(x2, ed);
}
}
GETG;
sse_forget_reg(dyn, ninst, gd);
@@ -636,22 +638,22 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
sse_reflect_reg(dyn, ninst, 0);
switch (u8) {
case 0xC8:
CALL(sha1nexte, -1);
CALL(const_sha1nexte, -1, x1, ed);
break;
case 0xC9:
CALL(sha1msg1, -1);
CALL(const_sha1msg1, -1, x1, ed);
break;
case 0xCA:
CALL(sha1msg2, -1);
CALL(const_sha1msg2, -1, x1, ed);
break;
case 0xCB:
CALL(sha256rnds2, -1);
CALL(const_sha256rnds2, -1, x1, ed);
break;
case 0xCC:
CALL(sha256msg1, -1);
CALL(const_sha256msg1, -1, x1, ed);
break;
case 0xCD:
CALL(sha256msg2, -1);
CALL(const_sha256msg2, -1, x1, ed);
break;
}
break;
@@ -713,17 +715,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ed = (nextop & 7) + (rex.b << 3);
sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
wback = x2;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
if (wback != x2) MV(x2, wback);
}
u8 = F8;
GETG;
sse_forget_reg(dyn, ninst, gd);
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
MOV32w(x3, u8);
CALL(sha1rnds4, -1);
CALL4(const_sha1rnds4, -1, x1, wback, x3, 0);
break;
default:
DEFAULT;
@@ -733,7 +735,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
if (!dyn->insts[ninst].nat_flags_fusion) { \
if (la64_lbt) { \
if (cpuext.lbt) { \
X64_SETJ(tmp1, I); \
} else { \
GETFLAGS; \
@@ -746,7 +748,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP(NATNO, 8); \
} else { \
if (la64_lbt) \
if (cpuext.lbt) \
BEQZ(tmp1, 8); \
else \
B##NO(tmp1, 8); \
@@ -758,7 +760,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP(NATNO, 8); \
} else { \
if (la64_lbt) \
if (cpuext.lbt) \
BEQZ(tmp1, 8); \
else \
B##NO(tmp1, 8); \
@@ -785,7 +787,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
nextop = F8;
GETEX(q0, 0, 0);
GETGX_empty(v0);
VFSQRT_S(v0, q0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMP_S(d0, q0, q0, cEQ);
VFSQRT_S(v0, q0);
VFCMP_S(d1, v0, v0, cEQ);
VANDN_V(d1, d1, d0);
VSLLI_W(d1, d1, 31);
VOR_V(v0, v0, d1);
} else
VFSQRT_S(v0, q0);
break;
case 0x52:
INST_NAME("RSQRTPS Gx, Ex");
@@ -793,7 +805,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SKIPTEST(x1);
GETEX(q0, 0, 0);
GETGX_empty(q1);
VFRSQRT_S(q1, q0);
if (cpuext.frecipe) {
VFRSQRTE_S(q1, q0);
} else {
VFRSQRT_S(q1, q0);
}
break;
case 0x53:
INST_NAME("RCPPS Gx, Ex");
@@ -801,8 +817,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SKIPTEST(x1);
GETEX(q0, 0, 0);
GETGX_empty(q1);
// TODO: use v1.1 vfrecipe when possible
VFRECIP_S(q1, q0);
if (cpuext.frecipe) {
VFRECIPE_S(q1, q0);
} else {
VFRECIP_S(q1, q0);
}
break;
case 0x54:
INST_NAME("ANDPS Gx, Ex");
@@ -870,7 +889,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0x5A:
INST_NAME("CVTPS2PD Gx, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETEXSD(q0, 0, 0);
GETGX(q1, 1);
VFCVTL_D_S(q1, q0);
break;
@@ -1277,7 +1296,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
BARRIER(BARRIER_MAYBE); \
JUMP(j64, 1); \
if (!dyn->insts[ninst].nat_flags_fusion) { \
if (la64_lbt) { \
if (cpuext.lbt) { \
X64_SETJ(x1, I); \
} else { \
GETFLAGS; \
@@ -1289,7 +1308,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32); \
} else { \
if (la64_lbt) \
if (cpuext.lbt) \
BEQZ_safe(x1, i32); \
else \
B##NO##_safe(x1, i32); \
@@ -1309,7 +1328,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32); \
} else { \
if (la64_lbt) \
if (cpuext.lbt) \
BNEZ_safe(tmp1, i32); \
else \
B##YES##_safe(tmp1, i32); \
@@ -1325,7 +1344,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
READFLAGS(F); \
tmp1 = x1; \
tmp3 = x3; \
if (la64_lbt) { \
if (cpuext.lbt) { \
X64_SETJ(x3, I); \
} else { \
GETFLAGS; \
@@ -1354,8 +1373,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xA2:
INST_NAME("CPUID");
NOTEST(x1);
MV(A1, xRAX);
CALL_(my_cpuid, -1, 0);
CALL_(const_cpuid, -1, 0, xRAX, 0);
// BX and DX are not synchronized durring the call, so need to force the update
LD_D(xRDX, xEmu, offsetof(x64emu_t, regs[_DX]));
LD_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
@@ -1371,15 +1389,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
SRAIxw(x1, gd, 5 + rex.w); // r1 = (gd>>5)
ALSL_D(x3, wback, x1, 2 + rex.w); // (&ed) += r1*4;
if (rex.w)
SRAI_D(x1, gd, 6);
else
SRAI_W(x1, gd, 5);
ALSL_D(x3, x1, wback, 2 + rex.w); // (&ed) += r1*4;
LDxw(x1, x3, fixedaddress);
ed = x1;
}
if (X_CF) {
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
SRLxw(x4, ed, x2);
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(x4, X_CF);
else
BSTRINS_D(xFlags, x4, F_CF, F_CF);
@@ -1397,6 +1418,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
WBACK;
} else {
FAKEED;
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
F8;
}
break;
@@ -1412,7 +1434,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
SRAI_D(x1, gd, 5 + rex.w);
if (rex.w)
SRAI_D(x1, gd, 6);
else
SRAI_W(x1, gd, 5);
ALSL_D(x3, x1, wback, 2 + rex.w);
LDxw(x1, x3, fixedaddress);
ed = x1;
@@ -1421,7 +1446,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
IFX (X_CF) {
SRL_D(x4, ed, x2);
if (la64_lbt) {
if (cpuext.lbt) {
X64_SET_EFLAGS(x4, X_CF);
} else {
BSTRINS_D(xFlags, x4, F_CF, F_CF);
@@ -1450,6 +1475,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
WBACK;
} else {
FAKEED;
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
F8;
}
break;
@@ -1483,8 +1509,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
DEFAULT;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
if (ed != x1) { MV(x1, ed); }
CALL(rex.is32bits ? ((void*)fpu_fxsave32) : ((void*)fpu_fxsave64), -1);
CALL(rex.is32bits ? const_fpu_fxsave32 : const_fpu_fxsave64, -1, ed, 0);
}
break;
case 1:
@@ -1493,21 +1518,54 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SKIPTEST(x1);
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
if (ed != x1) { MV(x1, ed); }
CALL(rex.is32bits ? ((void*)fpu_fxrstor32) : ((void*)fpu_fxrstor64), -1);
CALL(rex.is32bits ? const_fpu_fxrstor32 : const_fpu_fxrstor64, -1, ed, 0);
break;
case 2:
INST_NAME("LDMXCSR Md");
GETED(0);
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
if (BOX64ENV(sse_flushto0)) {
// TODO
/* LA <-> x86
16/24 <-> 5 inexact
17/25 <-> 4 underflow
18/26 <-> 3 overflow
19/27 <-> 2 divide by zero
x <-> 1 denormal
20/28 <-> 0 invalid operation
*/
// Doing x86 -> LA here, ignore denormal
XOR(x4, x4, x4);
BSTRPICK_W(x3, ed, 5, 5);
BSTRINS_W(x4, x3, 16, 16);
BSTRPICK_W(x3, ed, 4, 4);
BSTRINS_W(x4, x3, 17, 17);
BSTRPICK_W(x3, ed, 3, 3);
BSTRINS_W(x4, x3, 18, 18);
BSTRPICK_W(x3, ed, 2, 2);
BSTRINS_W(x4, x3, 19, 19);
BSTRPICK_W(x3, ed, 0, 0);
BSTRINS_W(x4, x3, 20, 20);
MOVGR2FCSR(FCSR2, x4);
}
break;
case 3:
INST_NAME("STMXCSR Md");
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
LD_WU(x4, xEmu, offsetof(x64emu_t, mxcsr));
if (BOX64ENV(sse_flushto0)) {
MOVFCSR2GR(x5, FCSR2);
// Doing LA -> x86 here, ignore denormal
BSTRPICK_W(x3, x5, 16, 16);
BSTRINS_W(x4, x3, 5, 5);
BSTRPICK_W(x3, x5, 17, 17);
BSTRINS_W(x4, x3, 4, 4);
BSTRPICK_W(x3, x5, 18, 18);
BSTRINS_W(x4, x3, 3, 3);
BSTRPICK_W(x3, x5, 19, 19);
BSTRINS_W(x4, x3, 2, 2);
BSTRPICK_W(x3, x5, 20, 20);
BSTRINS_W(x4, x3, 0, 0);
}
ST_W(x4, wback, fixedaddress);
break;
case 4:
@@ -1515,25 +1573,22 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
if (ed != x1) { MV(x1, ed); }
MOV32w(x2, rex.w ? 0 : 1);
CALL((void*)fpu_xsave, -1);
CALL(const_fpu_xsave, -1, ed, x2);
break;
case 5:
INST_NAME("XRSTOR Ed");
MESSAGE(LOG_DUMP, "Need Optimization\n");
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
if (ed != x1) { MV(x1, ed); }
MOV32w(x2, rex.w ? 0 : 1);
CALL((void*)fpu_xrstor, -1);
CALL(const_fpu_xrstor, -1, ed, x2);
break;
case 7:
INST_NAME("CLFLUSH Ed");
MESSAGE(LOG_DUMP, "Need Optimization?\n");
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
if (ed != x1) { MV(x1, ed); }
CALL_(native_clflush, -1, 0);
CALL_(const_native_clflush, -1, 0, ed, 0);
break;
default:
DEFAULT;
@@ -1552,7 +1607,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (rex.w) {
// 64bits imul
UFLAG_IF {
if (la64_lbt) {
if (cpuext.lbt) {
X64_MUL_D(gd, ed);
}
MULH_D(x3, gd, ed);
@@ -1564,7 +1619,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SET_DFNONE();
}
IFXA (X_CF | X_OF, !la64_lbt) {
IFXA (X_CF | X_OF, !cpuext.lbt) {
SRAI_D(x4, gd, 63);
XOR(x3, x3, x4);
SNEZ(x3, x3);
@@ -1581,7 +1636,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
// 32bits imul
UFLAG_IF {
if (la64_lbt) {
if (cpuext.lbt) {
X64_MUL_W(gd, ed);
}
SLLI_W(gd, gd, 0);
@@ -1596,7 +1651,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else IFX (X_CF | X_OF) {
SET_DFNONE();
}
IFXA (X_CF | X_OF, !la64_lbt) {
IFXA (X_CF | X_OF, !cpuext.lbt) {
SRAI_W(x4, gd, 31);
SUB_D(x3, x3, x4);
SNEZ(x3, x3);
@@ -1625,7 +1680,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
SRAIxw(x1, gd, 5 + rex.w);
if (rex.w)
SRAI_D(x1, gd, 6);
else
SRAI_W(x1, gd, 5);
ADDSL(x3, wback, x1, 2 + rex.w, x1);
LDxw(x1, x3, fixedaddress);
ed = x1;
@@ -1633,7 +1691,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
SRL_D(x4, ed, x2);
BSTRINS_D(xFlags, x4, 0, 0);
if(cpuext.lbt) {
X64_SET_EFLAGS(x4, X_CF);
} else {
BSTRINS_D(xFlags, x4, 0, 0);
}
ADDI_D(x4, xZR, 1);
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
SLL_D(x4, x4, x2);
@@ -1689,7 +1751,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
u8 = F8;
u8 &= rex.w ? 0x3f : 0x1f;
BSTRPICK_D(x4, ed, u8, u8);
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(x4, X_CF);
else
BSTRINS_D(xFlags, x4, 0, 0);
@@ -1702,7 +1764,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x1f);
BSTRPICK_D(x4, ed, u8, u8);
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(x4, X_CF);
else
BSTRINS_D(xFlags, x4, 0, 0);
@@ -1723,7 +1785,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x1f);
BSTRPICK_D(x4, ed, u8, u8);
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(x4, X_CF);
else
BSTRINS_D(xFlags, x4, 0, 0);
@@ -1743,7 +1805,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
u8 = F8;
u8 &= rex.w ? 0x3f : 0x1f;
BSTRPICK_D(x3, ed, u8, u8);
BSTRINS_D(xFlags, x3, 0, 0);
if (cpuext.lbt)
X64_SET_EFLAGS(x3, X_CF);
else
BSTRINS_D(xFlags, x3, 0, 0);
if (u8 <= 10) {
XORI(ed, ed, (1LL << u8));
} else {
@@ -1773,7 +1838,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
SRAIxw(x1, gd, 5 + rex.w);
if (rex.w)
SRAI_D(x1, gd, 6);
else
SRAI_W(x1, gd, 5);
ADDSL(x3, wback, x1, 2 + rex.w, x1);
LDxw(x1, x3, fixedaddress);
ed = x1;
@@ -1781,7 +1849,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
SRL_D(x4, ed, x2);
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(x4, X_CF);
else
BSTRINS_D(xFlags, x4, F_CF, F_CF);
@@ -1807,7 +1875,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ed = x4;
}
BNE_MARK(ed, xZR);
if (la64_lbt) {
if (cpuext.lbt) {
ADDI_D(x3, xZR, 1 << F_ZF);
X64_SET_EFLAGS(x3, X_ZF);
} else {
@@ -1820,7 +1888,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
CTZ_D(gd, ed);
else
CTZ_W(gd, ed);
if (la64_lbt) {
if (cpuext.lbt) {
X64_SET_EFLAGS(xZR, X_ZF);
} else {
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
@@ -1838,7 +1906,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ed = x4;
}
BNE_MARK(ed, xZR);
if (la64_lbt) {
if (cpuext.lbt) {
ADDI_D(x3, xZR, 1 << F_ZF);
X64_SET_EFLAGS(x3, X_ZF);
} else {
@@ -1846,7 +1914,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
B_NEXT_nocond;
MARK;
if (la64_lbt) {
if (cpuext.lbt) {
X64_SET_EFLAGS(xZR, X_ZF);
} else {
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
@@ -2123,7 +2191,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VAVGR_BU(v0, v0, v1);
break;
case 0xE1:
INST_NAME("PSRAW Gm,Em");
INST_NAME("PSRAW Gm, Em");
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
@@ -2133,12 +2201,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSRA_H(v0, v0, q0);
break;
case 0xE2:
INST_NAME("PSRAD Gm,Em");
INST_NAME("PSRAD Gm, Em");
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
q0 = fpu_get_scratch(dyn);
VMINI_WU(q0, v1, 31);
VMINI_DU(q0, v1, 31);
VREPLVEI_W(q0, q0, 0);
VSRA_W(v0, v0, q0);
break;
@@ -2147,7 +2215,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
VAVG_HU(v0, v0, v1);
VAVGR_HU(v0, v0, v1);
break;
case 0xE4:
INST_NAME("PMULHUW Gm,Em");
@@ -2191,7 +2259,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VSSUB_H(v0, v0, q0);
break;
case 0xEA:
INST_NAME("PMINSW Gx,Ex");
INST_NAME("PMINSW Gx, Ex");
nextop = F8;
GETGM(v0);
GETEM(v1, 0);
+31 -2
View File
@@ -252,10 +252,10 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
else
i64 = F8S;
MOV64xw(x5, i64);
IFXA (X_ALL, !la64_lbt)
IFXA (X_ALL, !cpuext.lbt)
ST_D(x6, xEmu, offsetof(x64emu_t, scratch));
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, x7);
IFXA (X_ALL, !la64_lbt) {
IFXA (X_ALL, !cpuext.lbt) {
LD_D(x6, xEmu, offsetof(x64emu_t, scratch));
}
WBACKO(x6);
@@ -444,6 +444,22 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else
LDXxw(xRAX, x4, x1);
break;
case 0xA3:
INST_NAME("MOV FS:Od, EAX");
grab_segdata(dyn, addr, ninst, x4, seg, 0);
if (rex.is32bits)
u64 = F32;
else
u64 = F64;
if (u64 < 0x800) {
ADDIz(x1, x4, u64);
} else {
MOV64z(x1, u64);
ADDz(x1, x1, x4);
}
SDxw(xRAX, x1, 0);
SMWRITE2();
break;
case 0xC6:
INST_NAME("MOV Seg:Eb, Ib");
nextop = F8;
@@ -502,6 +518,19 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SMWRITE2();
}
break;
case 0xFF:
nextop = F8;
switch ((nextop >> 3) & 7) {
case 6: // Push Ed
INST_NAME("PUSH Ed");
grab_segdata(dyn, addr, ninst, x6, seg, (MODREG));
GETEDOz(x6, 0, x3);
PUSH1z(ed);
break;
default:
DEFAULT;
}
break;
default:
DEFAULT;
}
+12 -7
View File
@@ -782,7 +782,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETEW(x1, 1);
u8 = F8;
MOV32w(x2, u8);
CALL_(rol16, x1, x3);
CALL_(const_rol16, x1, x3, x1, x2);
EWBACK;
break;
case 1:
@@ -792,7 +792,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETEW(x1, 1);
u8 = F8;
MOV32w(x2, u8);
CALL_(ror16, x1, x3);
CALL_(const_ror16, x1, x3, x1, x2);
EWBACK;
break;
case 4:
@@ -872,7 +872,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
GETEW(x1, 1);
CALL_(rol16, x1, x3);
CALL_(const_rol16, x1, x3, x1, x2);
EWBACK;
break;
case 5:
@@ -968,9 +968,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
OR(x2, x2, x7);
if(BOX64ENV(dynarec_div0)) {
BNE_MARK3(ed, xZR);
GETIP_(ip);
GETIP_(ip, x6);
STORE_XEMU_CALL();
CALL(native_div0, -1);
CALL(const_native_div0, -1, 0, 0);
CLEARIP();
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -989,9 +989,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETSEW(x1, 0);
if (BOX64ENV(dynarec_div0)) {
BNE_MARK3(ed, xZR);
GETIP_(ip);
GETIP_(ip, x7);
STORE_XEMU_CALL();
CALL(native_div0, -1);
CALL(const_native_div0, -1, 0, 0);
CLEARIP();
LOAD_XEMU_CALL();
jump_to_epilog(dyn, 0, xRIP, ninst);
@@ -1026,6 +1026,11 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
EWBACK;
break;
case 6: // Push Ew
INST_NAME("PUSH Ew");
GETEW(x1, 0);
PUSH1_16(ed);
break;
default:
DEFAULT;
}
+139 -135
View File
@@ -61,7 +61,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
switch (opcode) {
case 0x10:
INST_NAME("MOVUPD Gx,Ex");
INST_NAME("MOVUPD Gx, Ex");
nextop = F8;
GETG;
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
@@ -172,6 +172,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
break;
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
INST_NAME("NOP (multibyte)");
nextop = F8;
@@ -231,7 +236,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x2C:
INST_NAME("CVTTPD2PI Gm,Ex");
INST_NAME("CVTTPD2PI Gm, Ex");
nextop = F8;
GETGM(v0);
GETEX(v1, 0, 0);
@@ -270,7 +275,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x2D:
INST_NAME("CVTPD2PI Gm,Ex");
INST_NAME("CVTPD2PI Gm, Ex");
nextop = F8;
GETGM(v0);
GETEX(v1, 0, 0);
@@ -400,19 +405,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VSADD_H(q0, v0, v1);
break;
case 0x04:
INST_NAME("PMADDUBSW Gx,Ex");
INST_NAME("PMADDUBSW Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VEXT2XV_HU_BU(v0, q0);
VEXT2XV_H_B(v1, q1);
XVMUL_H(v0, v0, v1);
XVPERMI_Q(v1, v0, 1); // v1[127:0] = v0[255:128];
VPICKEV_H(q0, v1, v0);
VPICKOD_H(v0, v1, v0);
VSADD_H(q0, v0, q0);
VMULWEV_H_BU_B(v0, q0, q1);
VMULWOD_H_BU_B(v1, q0, q1);
VSADD_H(q0, v0, v1);
break;
case 0x05:
INST_NAME("PHSUBW Gx, Ex");
@@ -434,7 +435,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
v1 = fpu_get_scratch(dyn);
VPICKEV_W(v0, q1, q0);
VPICKOD_W(v1, q1, q0);
VSUB_D(q0, v0, v1);
VSUB_W(q0, v0, v1);
break;
case 0x07:
INST_NAME("PHSUBSW Gx, Ex");
@@ -469,7 +470,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VSIGNCOV_W(q0, q1, q0);
break;
case 0x0B:
INST_NAME("PMULHRSW Gx,Ex");
INST_NAME("PMULHRSW Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -484,7 +485,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
XVPERMI_D(q0, v0, 0b1000);
break;
case 0x10:
INST_NAME("PBLENDVB Gx,Ex");
INST_NAME("PBLENDVB Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -496,19 +497,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x14:
INST_NAME("BLENDVPS Gx,Ex");
INST_NAME("BLENDVPS Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
v0 = sse_get_reg(dyn, ninst, x1, 0, 0); // XMM0
v1 = fpu_get_scratch(dyn);
if (q0 != q1) {
VSRA_W(v1, v0, 31);
VSLTI_W(v1, v0, 0);
VBITSEL_V(q0, q0, q1, v1);
}
break;
case 0x15:
INST_NAME("BLENDVPD Gx,Ex");
INST_NAME("BLENDVPD Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -525,7 +526,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGX(q0, 0);
GETEX(q1, 0, 0);
if (!la64_lbt) {
if (!cpuext.lbt) {
CLEAR_FLAGS(x3);
} else IFX (X_ALL) {
X64_SET_EFLAGS(xZR, X_ALL);
@@ -536,7 +537,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VAND_V(v0, q1, q0);
VSETEQZ_V(fcc0, v0);
BCEQZ_MARK(fcc0);
if (la64_lbt) {
if (cpuext.lbt) {
ADDI_D(x3, xZR, 1 << F_ZF);
X64_SET_EFLAGS(x3, X_ZF);
} else {
@@ -548,9 +549,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VANDN_V(v0, q0, q1);
VSETEQZ_V(fcc0, v0);
BCEQZ_MARK2(fcc0);
if (la64_lbt) {
if (cpuext.lbt) {
ADDI_D(x3, xZR, 1 << F_CF);
X64_SET_EFLAGS(x3, X_ZF);
X64_SET_EFLAGS(x3, X_CF);
} else {
ORI(xFlags, xFlags, 1 << F_CF);
}
@@ -558,7 +559,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
MARK2;
break;
case 0x1C:
INST_NAME("PABSB Gx,Ex");
INST_NAME("PABSB Gx, Ex");
nextop = F8;
GETEX(q1, 0, 0);
GETGX_empty(q0);
@@ -567,7 +568,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VABSD_B(q0, q1, v0);
break;
case 0x1D:
INST_NAME("PABSW Gx,Ex");
INST_NAME("PABSW Gx, Ex");
nextop = F8;
GETEX(q1, 0, 0);
GETGX_empty(q0);
@@ -576,7 +577,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VABSD_H(q0, q1, v0);
break;
case 0x1E:
INST_NAME("PABSD Gx,Ex");
INST_NAME("PABSD Gx, Ex");
nextop = F8;
GETEX(q1, 0, 0);
GETGX_empty(q0);
@@ -801,7 +802,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesimc, -1);
CALL(const_native_aesimc, -1, x1, 0);
break;
case 0xDC:
INST_NAME("AESENC Gx, Ex"); // AES-NI
@@ -815,7 +816,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aese, -1);
CALL(const_native_aese, -1, x1, 0);
GETGX(q0, 1);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
@@ -831,7 +832,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aeselast, -1);
CALL(const_native_aeselast, -1, x1, 0);
GETGX(q0, 1);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
@@ -847,7 +848,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesd, -1);
CALL(const_native_aesd, -1, x1, 0);
GETGX(q0, 1);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
@@ -863,7 +864,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(native_aesdlast, -1);
CALL(const_native_aesdlast, -1, x1, 0);
GETGX(q0, 1);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
@@ -959,7 +960,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("BLENDPS Gx, Ex, Ib");
nextop = F8;
GETGX(q0, 1);
GETEXSS(q1, 0, 1);
GETEX(q1, 0, 1);
u8 = F8 & 0b1111;
if ((u8 & 0b11) == 0b11) {
VEXTRINS_D(q0, q1, 0);
@@ -978,7 +979,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("BLENDPD Gx, Ex, Ib");
nextop = F8;
GETGX(q0, 1);
GETEXSD(q1, 0, 1);
GETEX(q1, 0, 1);
u8 = F8 & 0b11;
if (u8 == 0b01) {
VEXTRINS_D(q0, q1, 0b00000000);
@@ -1002,8 +1003,8 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VOR_V(q0, q1, q1);
} else {
d0 = fpu_get_scratch(dyn);
VBSLL_V(q0, q0, 16 - u8);
VBSRL_V(d0, q1, u8);
VBSLL_V(q0, q0, 16 - u8);
VOR_V(q0, q0, d0);
}
break;
@@ -1111,7 +1112,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (rex.w) {
VPICKVE2GR_D(ed, q0, (u8 & 1));
} else {
VPICKVE2GR_W(ed, q0, (u8 & 3));
VPICKVE2GR_WU(ed, q0, (u8 & 3));
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 1, 1);
@@ -1147,7 +1148,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("PINSRB Gx, ED, Ib");
nextop = F8;
GETGX(q0, 1);
GETED(1);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
LD_B(x1, wback, fixedaddress);
ed = x1;
}
u8 = F8;
VINSGR2VR_B(q0, ed, (u8 & 0xf));
break;
@@ -1155,21 +1164,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("INSERTPS Gx, Ex, Ib");
nextop = F8;
GETGX(q0, 1);
u8 = F8;
uint8_t src_index = (u8 >> 6) & 3;
uint8_t dst_index = (u8 >> 4) & 3;
uint8_t zmask = u8 & 0xf;
q2 = fpu_get_scratch(dyn);
if (MODREG) {
u8 = F8;
q1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
VEXTRINS_W(q0, q1, VEXTRINS_IMM_4_0(dst_index, src_index));
VEXTRINS_W(q0, q1, VEXTRINS_IMM_4_0(((u8 >> 4) & 3), ((u8 >> 6) & 3)));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x5, &fixedaddress, rex, NULL, 0, 1);
u8 = F8;
FLD_S(q2, wback, fixedaddress);
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(dst_index, 0)); // src index is zero when Ex is mem operand
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(((u8 >> 4) & 3), 0)); // src index is zero when Ex is mem operand
}
uint8_t zmask = u8 & 0xf;
VXOR_V(q2, q2, q2);
if (zmask) {
for (uint8_t i = 0; i < 4; i++) {
@@ -1262,7 +1269,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
u8 = F8;
MOV32w(x4, u8);
CALL(native_pclmul, -1);
CALL4(const_native_pclmul, -1, x1, x2, x3, x4);
break;
case 0x61:
INST_NAME("PCMPESTRI Gx, Ex, Ib");
@@ -1278,15 +1285,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (ed > 7)
sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
ed = x1;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x5, &fixedaddress, rex, NULL, 0, 1);
if (ed != x1) MV(x1, ed);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
}
MV(x2, xRDX);
MV(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
CALL(sse42_compare_string_explicit_len, x1);
CALL6(const_sse42_compare_string_explicit_len, x1, ed, x2, x3, x4, x5, 0);
ZEROUP(x1);
BNEZ_MARK(x1);
MOV32w(xRCX, (u8 & 1) ? 8 : 16);
@@ -1311,13 +1318,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
ed = (nextop & 7) + (rex.b << 3);
if (ed > 7) sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
ed = x1;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
if (ed != x1) MV(x1, ed);
}
u8 = F8;
MOV32w(x3, u8);
CALL(sse42_compare_string_implicit_len, x1);
CALL4(const_sse42_compare_string_implicit_len, x1, ed, x2, x3, 0);
BNEZ_MARK(x1);
MOV32w(xRCX, (u8 & 1) ? 8 : 16);
B_NEXT_nocond;
@@ -1350,7 +1357,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
u8 = F8;
MOV32w(x4, u8);
CALL(native_aeskeygenassist, -1);
CALL4(const_native_aeskeygenassist, -1, x1, x2, x3, x4);
break;
default:
DEFAULT;
@@ -1361,7 +1368,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
READFLAGS(F); \
tmp1 = x1; \
tmp3 = x3; \
if (la64_lbt) { \
if (cpuext.lbt) { \
X64_SETJ(x1, I); \
} else { \
GETFLAGS; \
@@ -1375,7 +1382,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
LD_HU(x4, ed, fixedaddress); \
ed = x4; \
} \
if (la64_lbt) \
if (cpuext.lbt) \
BEQZ(x1, 4 + 4); \
else \
B##NO(x1, 4 + 4); \
@@ -1605,28 +1612,28 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
break;
case 0x60:
INST_NAME("PUNPCKLBW Gx,Ex");
INST_NAME("PUNPCKLBW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VILVL_B(v0, q0, v0);
break;
case 0x61:
INST_NAME("PUNPCKLWD Gx,Ex");
INST_NAME("PUNPCKLWD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VILVL_H(v0, q0, v0);
break;
case 0x62:
INST_NAME("PUNPCKLDQ Gx,Ex");
INST_NAME("PUNPCKLDQ Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VILVL_W(v0, q0, v0);
break;
case 0x63:
INST_NAME("PACKSSWB Gx,Ex");
INST_NAME("PACKSSWB Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
@@ -1641,21 +1648,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x64:
INST_NAME("PCMPGTB Gx,Ex");
INST_NAME("PCMPGTB Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
VSLT_B(v0, v1, v0);
break;
case 0x65:
INST_NAME("PCMPGTW Gx,Ex");
INST_NAME("PCMPGTW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
VSLT_H(v0, v1, v0);
break;
case 0x66:
INST_NAME("PCMPGTD Gx,Ex");
INST_NAME("PCMPGTD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
@@ -1682,28 +1689,28 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x68:
INST_NAME("PUNPCKHBW Gx,Ex");
INST_NAME("PUNPCKHBW Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
VILVH_B(q0, q1, q0);
break;
case 0x69:
INST_NAME("PUNPCKHWD Gx,Ex");
INST_NAME("PUNPCKHWD Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
VILVH_H(q0, q1, q0);
break;
case 0x6A:
INST_NAME("PUNPCKHDQ Gx,Ex");
INST_NAME("PUNPCKHDQ Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
VILVH_W(q0, q1, q0);
break;
case 0x6B:
INST_NAME("PACKSSDW Gx,Ex");
INST_NAME("PACKSSDW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
@@ -1713,7 +1720,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VOR_V(v0, d0, d0);
break;
case 0x6C:
INST_NAME("PUNPCKLQDQ Gx,Ex");
INST_NAME("PUNPCKLQDQ Gx, Ex");
nextop = F8;
GETGX(v0, 1);
if (MODREG) {
@@ -1726,7 +1733,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VILVL_D(v0, v1, v0); // v0[127:64] = v1[63:0]
break;
case 0x6D:
INST_NAME("PUNPCKHQDQ Gx,Ex");
INST_NAME("PUNPCKHQDQ Gx, Ex");
nextop = F8;
GETGX(v0, 1);
if (MODREG) {
@@ -1778,7 +1785,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x70:
INST_NAME("PSHUFD Gx,Ex,Ib");
INST_NAME("PSHUFD Gx, Ex, Ib");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 1);
@@ -1932,21 +1939,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0x74:
INST_NAME("PCMPEQB Gx,Ex");
INST_NAME("PCMPEQB Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSEQ_B(v0, v0, q0);
break;
case 0x75:
INST_NAME("PCMPEQW Gx,Ex");
INST_NAME("PCMPEQW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSEQ_H(v0, v0, q0);
break;
case 0x76:
INST_NAME("PCMPEQD Gx,Ex");
INST_NAME("PCMPEQD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
@@ -2047,7 +2054,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGW(x2);
ANDI(gd, gd, 15);
SRL_D(x4, ed, gd);
if (la64_lbt)
if (cpuext.lbt)
X64_SET_EFLAGS(x4, X_CF);
else
BSTRINS_D(xFlags, x4, F_CF, F_CF);
@@ -2097,7 +2104,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 &= rex.w ? 0x3f : 15;
IFX (X_CF) {
BSTRPICK_D(x3, ed, u8, u8);
if (la64_lbt) {
if (cpuext.lbt) {
X64_SET_EFLAGS(x3, X_CF);
} else {
BSTRINS_D(xFlags, x3, F_CF, F_CF);
@@ -2202,10 +2209,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xCF:
INST_NAME("BSWAP Reg");
gd = TO_NAT((opcode & 7) + (rex.b << 3));
REVBxw(gd, gd);
if(rex.w){
REVB_D(gd, gd);
} else {
REVB_2H(x2, gd);
BSTRINS_D(gd, x2, 15, 0);
}
break;
case 0xD0:
INST_NAME("ADDSUBPD Gx,Ex");
INST_NAME("ADDSUBPD Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -2215,7 +2227,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VEXTRINS_D(q0, v0, 0);
break;
case 0xD1:
INST_NAME("PSRLW Gx,Ex");
INST_NAME("PSRLW Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -2234,16 +2246,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VSAT_DU(v0, q1, 31);
VREPLVEI_W(v0, v0, 0);
VLDI(v1, 0b1000000011111); // broadcast 31 as uint32
VSLT_WU(v1, v1, v0);
VMINI_WU(v0, v0, 31);
VSRL_W(q0, q0, v0);
VREPLVEI_D(v0, q1, 0);
VSLEI_DU(v0, v0, 31);
VREPLVEI_W(v1, q1, 0);
VSRL_W(q0, q0, v1);
VAND_V(q0, q0, v0);
break;
case 0xD3:
INST_NAME("PSRLQ Gx,Ex");
INST_NAME("PSRLQ Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -2252,10 +2262,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = fpu_get_scratch(dyn);
VREPLVEI_D(v0, q1, 0);
VLDI(v1, 0b0110000111111); // broadcast 63 as uint64
VMIN_DU(d0, v0, v1);
VSLT_DU(v1, v1, v0);
VSRL_D(q0, q0, d0);
VSRL_D(q0, q0, v1);
VSLE_DU(v1, v0, v1);
VSRL_D(q0, q0, v0);
VAND_V(q0, q0, v1);
break;
case 0xD4:
INST_NAME("PADDQ Gx, Ex");
@@ -2265,7 +2274,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VADD_D(v0, v0, q0);
break;
case 0xD5:
INST_NAME("PMULLW Gx,Ex");
INST_NAME("PMULLW Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -2325,21 +2334,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VMIN_BU(q0, q0, q1);
break;
case 0xDB:
INST_NAME("PAND Gx,Ex");
INST_NAME("PAND Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VAND_V(v0, v0, q0);
break;
case 0xDC:
INST_NAME("PADDUSB Gx,Ex");
INST_NAME("PADDUSB Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
VSADD_BU(q0, q0, q1);
break;
case 0xDD:
INST_NAME("PADDUSW Gx,Ex");
INST_NAME("PADDUSW Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
@@ -2353,7 +2362,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VMAX_BU(q0, q0, q1);
break;
case 0xDF:
INST_NAME("PANDN Gx,Ex");
INST_NAME("PANDN Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
@@ -2377,36 +2386,31 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VSRA_H(q0, q0, v0);
break;
case 0xE2:
INST_NAME("PSRAD Gx,Ex");
INST_NAME("PSRAD Gx, Ex");
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
v2 = fpu_get_scratch(dyn);
VREPLVEI_D(v0, q1, 0);
VSLEI_DU(v1, v0, 31);
VREPLVEI_W(v0, q1, 0);
VSRAI_W(v2, q0, 31);
VMINI_DU(v0, q1, 31);
VREPLVEI_W(v0, v0, 0);
VSRA_W(q0, q0, v0);
VBITSEL_V(q0, v2, q0, v1);
break;
case 0xE3:
INST_NAME("PAVGW Gx,Ex");
INST_NAME("PAVGW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
VAVGR_HU(v0, v0, v1);
break;
case 0xE4:
INST_NAME("PMULHUW Gx,Ex");
INST_NAME("PMULHUW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
VMUH_HU(v0, v0, v1);
break;
case 0xE5:
INST_NAME("PMULHW Gx,Ex");
INST_NAME("PMULHW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(v1, 0, 0);
@@ -2417,8 +2421,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETEX(v1, 0, 0);
GETGX_empty(v0);
// TODO: fastround
VFTINTRZ_W_D(v0, v1, v1);
if (!BOX64ENV(dynarec_fastround)) {
d0 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFTINTRZ_W_D(d0, v1, v1);
VLDI(q0, 0b1001110000000); // broadcast 32bit 0x80000000 to all
LU52I_D(x5, xZR, 0x41e);
VREPLGR2VR_D(q1, x5);
VFCMP_D(q1, q1, v1, cULE);
VSHUF4I_W(q1, q1, 0b00001000);
VBITSEL_V(v0, d0, q0, q1);
} else {
VFTINTRZ_W_D(v0, v1, v1);
}
VINSGR2VR_D(v0, xZR, 1);
break;
case 0xE7:
@@ -2434,56 +2450,56 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
break;
case 0xE8:
INST_NAME("PSUBSB Gx,Ex");
INST_NAME("PSUBSB Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSSUB_B(v0, v0, q0);
break;
case 0xE9:
INST_NAME("PSUBSW Gx,Ex");
INST_NAME("PSUBSW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSSUB_H(v0, v0, q0);
break;
case 0xEA:
INST_NAME("PMINSW Gx,Ex");
INST_NAME("PMINSW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VMIN_H(v0, v0, q0);
break;
case 0xEB:
INST_NAME("POR Gx,Ex");
INST_NAME("POR Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VOR_V(v0, v0, q0);
break;
case 0xEC:
INST_NAME("PADDSB Gx,Ex");
INST_NAME("PADDSB Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSADD_B(v0, v0, q0);
break;
case 0xED:
INST_NAME("PADDSW Gx,Ex");
INST_NAME("PADDSW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSADD_H(v0, v0, q0);
break;
case 0xEE:
INST_NAME("PMAXSW Gx,Ex");
INST_NAME("PMAXSW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VMAX_H(v0, v0, q0);
break;
case 0xEF:
INST_NAME("PXOR Gx,Ex");
INST_NAME("PXOR Gx, Ex");
nextop = F8;
GETG;
if (MODREG && ((nextop & 7) + (rex.b << 3) == gd)) {
@@ -2503,15 +2519,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VREPLVE_H(v1, q1, xZR);
VPICKVE2GR_DU(x4, q1, 0);
SLTUI(x3, x4, 16);
SUB_D(x3, xZR, x3);
NOR(x3, x3, xZR);
VREPLGR2VR_D(v0, x3);
VREPLVEI_D(v0, q1, 0);
VSLEI_DU(v0, v0, 15);
VREPLVEI_H(v1, q1, 0);
VSLL_H(q0, q0, v1);
VAND_V(v0, q0, v0);
VXOR_V(q0, q0, v0);
VAND_V(q0, q0, v0);
break;
case 0xF2:
INST_NAME("PSLLD Gx, Ex");
@@ -2520,15 +2532,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VREPLVE_W(v1, q1, xZR);
VPICKVE2GR_DU(x4, q1, 0);
SLTUI(x3, x4, 32);
SUB_D(x3, xZR, x3);
NOR(x3, x3, xZR);
VREPLGR2VR_D(v0, x3);
VREPLVEI_D(v0, q1, 0);
VSLEI_DU(v0, v0, 31);
VREPLVEI_W(v1, q1, 0);
VSLL_W(q0, q0, v1);
VAND_V(v0, q0, v0);
VXOR_V(q0, q0, v0);
VAND_V(q0, q0, v0);
break;
case 0xF3:
INST_NAME("PSLLQ Gx, Ex");
@@ -2537,15 +2545,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETEX(q1, 0, 0);
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
VREPLVE_D(v1, q1, xZR);
VPICKVE2GR_DU(x4, q1, 0);
SLTUI(x3, x4, 64);
SUB_D(x3, xZR, x3);
NOR(x3, x3, xZR);
VREPLGR2VR_D(v0, x3);
VSLL_D(q0, q0, v1);
VAND_V(v0, q0, v0);
VXOR_V(q0, q0, v0);
VREPLVEI_D(v0, q1, 0);
VLDI(v1, (0b011 << 10) | 0x3f);
VSLE_DU(v1, v0, v1);
VSLL_D(q0, q0, v0);
VAND_V(q0, q0, v1);
break;
case 0xF4:
INST_NAME("PMULUDQ Gx,Ex");
@@ -2597,14 +2601,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VSUB_B(v0, v0, q0);
break;
case 0xF9:
INST_NAME("PSUBW Gx,Ex");
INST_NAME("PSUBW Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
VSUB_H(v0, v0, q0);
break;
case 0xFA:
INST_NAME("PSUBD Gx,Ex");
INST_NAME("PSUBD Gx, Ex");
nextop = F8;
GETGX(v0, 1);
GETEX(q0, 0, 0);
+1 -3
View File
@@ -53,7 +53,6 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x81:
case 0x83:
nextop = F8;
SMDMB();
switch ((nextop >> 3) & 7) {
case 0: // ADD
if (opcode == 0x81) {
@@ -80,7 +79,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u64 = (uint16_t)(int16_t)F8S;
MOV64x(x5, u64);
if (la64_lam_bh) {
if (cpuext.lam_bh) {
AMADD_DB_H(x1, x5, wback);
} else {
ANDI(x3, wback, 0b10);
@@ -119,7 +118,6 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
default:
DEFAULT;
}
SMDMB();
break;
default:
+6 -5
View File
@@ -57,16 +57,17 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
v0 = fpu_get_scratch(dyn);
VINSGR2VR_H(v0, ed, 0);
VPCNT_H(v0, v0);
VPICKVE2GR_HU(gd, v0, 0);
VPICKVE2GR_HU(x2, v0, 0);
BSTRINS_D(gd, x2, 15, 0);
IFX (X_ALL) {
if (la64_lbt) {
if (cpuext.lbt) {
X64_SET_EFLAGS(xZR, X_ALL);
BNEZ_MARK(gd);
BNEZ_MARK(x2);
ADDI_D(x5, xZR, 1 << F_ZF);
X64_SET_EFLAGS(x5, X_ZF);
} else {
CLEAR_FLAGS(x2);
BNEZ_MARK(gd);
CLEAR_FLAGS(x5);
BNEZ_MARK(x2);
ORI(xFlags, xFlags, 1 << F_ZF);
}
MARK;
+187
View File
@@ -60,6 +60,47 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
switch(opcode) {
case 0x0F:
opcode = F8;
switch (opcode) {
case 0xB6:
INST_NAME("MOVZX Gd, Eb");
nextop = F8;
GETGD;
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
if (rex.rex) {
eb1 = TO_NAT(ed);
eb2 = 0;
} else {
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
eb2 = ((ed & 4) << 1); // L or H
}
BSTRPICK_D(gd, eb1, eb2 + 7, eb2);
} else {
SMREAD();
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
LD_BU(gd, ed, fixedaddress);
}
break;
case 0xB7:
INST_NAME("MOVZX Gd, Ew");
nextop = F8;
GETGD;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
BSTRPICK_D(gd, ed, 15, 0);
} else {
SMREAD();
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
LD_HU(gd, ed, fixedaddress);
}
break;
default:
DEFAULT;
}
break;
case 0x19:
INST_NAME("SBB Ed, Gd");
READFLAGS(X_CF);
@@ -97,6 +138,140 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MOV64xw(x2, i64);
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
MOV64xw(x5, i64);
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x5, x6);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
MOV64xw(x5, i64);
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x5);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
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, NAT_FLAGS_FUSION);
GETED32((opcode == 0x81) ? 4 : 1);
if (opcode == 0x81)
i64 = F32S;
else
i64 = F8S;
if (i64) {
MOV64x(x2, i64);
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6);
} else
emit_cmp32_0(dyn, ninst, rex, nextop, ed, x3, x4, x5);
break;
}
break;
case 0x88:
INST_NAME("MOV Eb, Gb");
nextop = F8;
@@ -142,6 +317,18 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SMWRITELOCK(lock);
}
break;
case 0x8B:
INST_NAME("MOV Gd, Ed");
nextop = F8;
GETGD;
if (MODREG) {
MVxw(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
} else {
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
SMREADLOCK(lock);
LDxw(gd, ed, fixedaddress);
}
break;
case 0x8D:
INST_NAME("LEA Gd, Ed");
nextop = F8;
+81
View File
@@ -0,0 +1,81 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "dynarec_la64_helper.h"
static const char* avx_prefix_string(uint16_t p)
{
switch (p) {
case VEX_P_NONE: return "0";
case VEX_P_66: return "66";
case VEX_P_F2: return "F2";
case VEX_P_F3: return "F3";
default: return "??";
}
}
static const char* avx_map_string(uint16_t m)
{
switch (m) {
case VEX_M_NONE: return "0";
case VEX_M_0F: return "0F";
case VEX_M_0F38: return "0F38";
case VEX_M_0F3A: return "0F3A";
default: return "??";
}
}
uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = PK(0);
rex_t rex = vex.rex;
if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_NONE))
addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F38) && (vex.p == VEX_P_NONE))
addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_66))
addr = dynarec64_AVX_66_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_F2))
addr = dynarec64_AVX_F2_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_F3))
addr = dynarec64_AVX_F3_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F38) && (vex.p == VEX_P_66))
addr = dynarec64_AVX_66_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F3A) && (vex.p == VEX_P_66))
addr = dynarec64_AVX_66_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m == VEX_M_0F38) && (vex.p == VEX_P_F2))
addr = dynarec64_AVX_F2_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if ((vex.m == VEX_M_0F3A) && (vex.p == VEX_P_F2))
addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F3))
addr = dynarec64_AVX_F3_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
else {
DEFAULT;
}
if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) {
dynarec_log(LOG_NONE, " Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128 << vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
}
return addr;
}
+624
View File
@@ -0,0 +1,624 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch (opcode) {
case 0x10:
INST_NAME("VMOVUPS Gx, Ex");
nextop = F8;
if (MODREG) {
GETGY_empty_EY_xy(q0, q1, 0);
if (vex.l) {
XVOR_V(q0, q1, q1);
} else {
VOR_V(q0, q1, q1);
}
} else {
GETGYxy_empty(q0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVLD(q0, ed, fixedaddress);
} else {
VLD(q0, ed, fixedaddress);
}
}
break;
case 0x11:
INST_NAME("VMOVUPS Ex, Gx");
nextop = F8;
GETGYxy(q0, 0);
if (MODREG) {
GETEYxy_empty(q1, 0);
if (vex.l) {
XVOR_V(q1, q0, q0);
} else {
VOR_V(q1, q0, q0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVST(q0, ed, fixedaddress);
} else {
VST(q0, ed, fixedaddress);
}
SMWRITE2();
}
break;
case 0x12:
nextop = F8;
GETVYx(v1, 0);
if (MODREG) {
INST_NAME("VMOVHLPS Gx, Vx, Ex");
GETEYx(v2, 0, 0);
GETGYx_empty(v0);
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(0, 1));
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(1, 1));
} else {
INST_NAME("VMOVLPS Gx, Vx, Ex");
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(0, 0));
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(1, 1));
}
break;
case 0x13:
nextop = F8;
INST_NAME("VMOVLPS Ex, Gx");
GETGYx(v0, 0);
if (MODREG) {
DEFAULT;
return addr;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
FST_D(v0, ed, fixedaddress);
SMWRITE2();
}
break;
case 0x14:
INST_NAME("VUNPCKLPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VILVLxy(W, v0, v2, v1);
break;
case 0x15:
INST_NAME("VUNPCKHPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VILVHxy(W, v0, v2, v1);
break;
case 0x16:
nextop = F8;
GETVYx(v1, 0);
if (MODREG) {
INST_NAME("VMOVLHPS Gx, Vx, Ex");
GETEYx(v2, 0, 0);
GETGYx_empty(v0);
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(1, 0));
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(0, 0));
} else {
INST_NAME("VMOVHPS Gx, Vx, Ex");
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(1, 0));
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(0, 0));
}
break;
case 0x17:
nextop = F8;
INST_NAME("VMOVHPS Ex, Gx");
GETGYx(v0, 0);
if (MODREG) {
DEFAULT;
return addr;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 0, 0);
VSTELM_D(v0, ed, fixedaddress, 1);
SMWRITE2();
}
break;
case 0x28:
INST_NAME("VMOVAPS Gx, Ex");
nextop = F8;
if (MODREG) {
GETGY_empty_EY_xy(q0, q1, 0);
if (vex.l) {
XVOR_V(q0, q1, q1);
} else {
VOR_V(q0, q1, q1);
}
} else {
GETGYxy_empty(q0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVLD(q0, ed, fixedaddress);
} else {
VLD(q0, ed, fixedaddress);
}
}
break;
case 0x29:
INST_NAME("VMOVAPS Ex, Gx");
nextop = F8;
GETGYxy(q0, 0);
if (MODREG) {
GETEYxy_empty(q1, 0);
if (vex.l) {
XVOR_V(q1, q0, q0);
} else {
VOR_V(q1, q0, q0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVST(q0, ed, fixedaddress);
} else {
VST(q0, ed, fixedaddress);
}
SMWRITE2();
}
break;
case 0x2B:
INST_NAME("VMOVNTPS Ex, Gx");
nextop = F8;
GETGYxy(q0, 0);
if (MODREG) {
DEFAULT;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVST(q0, ed, fixedaddress);
} else {
VST(q0, ed, fixedaddress);
}
SMWRITE2();
}
break;
case 0x2E:
// no special check...
case 0x2F:
if (opcode == 0x2F) {
INST_NAME("VCOMISS Gx, Ex");
} else {
INST_NAME("VUCOMISS Gx, Ex");
}
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGYx(d0, 0);
GETEYSS(v0, 0, 0);
CLEAR_FLAGS(x2);
// if isnan(d0) || isnan(v0)
IFX (X_ZF | X_PF | X_CF) {
FCMP_S(fcc0, d0, v0, cUN);
BCEQZ_MARK(fcc0);
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
B_MARK3_nocond;
}
MARK;
// else if isless(d0, v0)
IFX (X_CF) {
FCMP_S(fcc1, d0, v0, cLT);
BCEQZ_MARK2(fcc1);
ORI(xFlags, xFlags, 1 << F_CF);
B_MARK3_nocond;
}
MARK2;
// else if d0 == v0
IFX (X_ZF) {
FCMP_S(fcc2, d0, v0, cEQ);
BCEQZ_MARK3(fcc2);
ORI(xFlags, xFlags, 1 << F_ZF);
}
MARK3;
IFX (X_ALL) {
SPILL_EFLAGS();
}
break;
case 0x50:
nextop = F8;
INST_NAME("VMOVMSKPS Gd, Ex");
GETEYxy(v0, 0, 0);
GETGD;
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVMSKLTZ_W(d1, v0);
XVPICKVE2GR_DU(gd, d1, 0);
XVPICKVE2GR_DU(x4, d1, 2);
BSTRINS_D(gd, x4, 7, 4);
} else {
VMSKLTZ_W(d1, v0);
VPICKVE2GR_DU(gd, d1, 0);
}
break;
case 0x51:
INST_NAME("VSQRTPS Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v1, cEQ);
VFSQRTxy(S, v0, v1);
VFCMPxy(S, d1, v0, v0, cEQ);
VANDN_Vxy(d1, d1, d0);
VSLLIxy(W, d1, d1, 31);
VOR_Vxy(v0, v0, d1);
} else {
VFSQRTxy(S, v0, v1);
}
break;
case 0x52:
INST_NAME("VRSQRTPS Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
if (cpuext.frecipe) {
VFRSQRTExy(S, v0, v1);
} else {
VFRSQRTxy(S, v0, v1);
}
break;
case 0x53:
INST_NAME("VRCPPS Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
if (cpuext.frecipe) {
VFRECIPExy(S, v0, v1);
} else {
VFRECIPxy(S, v0, v1);
}
break;
case 0x54:
INST_NAME("VANDPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VAND_Vxy(v0, v1, v2);
break;
case 0x55:
INST_NAME("VANDNPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VANDN_Vxy(v0, v1, v2);
break;
case 0x56:
INST_NAME("VORPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VOR_Vxy(v0, v1, v2);
break;
case 0x57:
INST_NAME("VXORPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VXOR_Vxy(v0, v1, v2);
break;
case 0x58:
INST_NAME("VADDPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
}
VFADDxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0x59:
INST_NAME("VMULPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
}
VFMULxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0x5A:
INST_NAME("VCVTPS2PD Gx, Ex");
nextop = F8;
if(vex.l){
GETEYx(v1, 0 ,0);
} else {
GETEYSD(v1, 0, 0);
}
GETGYxy_empty(v0);
if(!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x6, x4);
}
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if(vex.l) {
XVFCVTH_D_S(d0, v1);
XVFCVTL_D_S(v0, v1);
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2));
} else {
VFCVTL_D_S(v0, v1);
}
if(!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
break;
case 0x5B:
INST_NAME("VCVTDQ2PS Gx, Ex");
nextop = F8;
GETEYxy(v1, 0, 0);
GETGYxy_empty(v0);
if(vex.l){
XVFFINT_S_W(v0, v1);
}else{
VFFINT_S_W(v0, v1);
}
break;
case 0x5C:
INST_NAME("VSUBPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
}
VFSUBxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0x5D:
INST_NAME("VMINPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (BOX64ENV(dynarec_fastnan)) {
VFMINxy(S, v0, v2, v1);
} else {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, q0, v2, v1, cULE);
VBITSEL_Vxy(v0, v1, v2, q0);
}
break;
case 0x5E:
INST_NAME("VDIVPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
}
VFDIVxy(S, v0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0x5F:
INST_NAME("VMAXPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (BOX64ENV(dynarec_fastnan)) {
VFMAXxy(S, v0, v2, v1);
} else {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VFCMPxy(S, q0, v2, v1, cLT);
VBITSEL_Vxy(v0, v2, v1, q0);
}
break;
case 0x77:
if (!vex.l) {
INST_NAME("VZEROUPPER");
if (vex.v != 0) {
UDF();
} else {
q2 = fpu_get_scratch(dyn);
XVXOR_V(q2, q2, q2);
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
if (dyn->lsx.avxcache[i].v != -1) {
// avx used register
if (dyn->lsx.avxcache[i].width == LSX_AVX_WIDTH_256) {
// 256 width, fill upper 128bits with zero.
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256); // mark reg write (dirty)
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
} else {
// 128 width, lazy save.
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_128); // mark reg write (dirty)
dyn->lsx.avxcache[i].zero_upper = 1;
}
} else {
// SSE register or unused register, store 128bit zero to x64emu_t.ymm[]
VST(q2, xEmu, offsetof(x64emu_t, ymm[i]));
}
}
SMWRITE2();
}
} else {
INST_NAME("VZEROALL");
if (vex.v != 0) {
UDF();
} else {
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
q0 = avx_get_reg_empty(dyn, ninst, x1, i, LSX_AVX_WIDTH_256);
XVXOR_V(q0, q0, q0);
}
}
}
break;
case 0xAE:
nextop = F8;
if (MODREG) {
DEFAULT;
} else
switch ((nextop >> 3) & 7) {
case 2:
INST_NAME("VLDMXCSR Md");
GETED(0);
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
if (BOX64ENV(sse_flushto0)) {
/* LA <-> x86
16/24 <-> 5 inexact
17/25 <-> 4 underflow
18/26 <-> 3 overflow
19/27 <-> 2 divide by zero
x <-> 1 denormal
20/28 <-> 0 invalid operation
*/
// Doing x86 -> LA here, ignore denormal
XOR(x4, x4, x4);
BSTRPICK_W(x3, ed, 5, 5);
BSTRINS_W(x4, x3, 16, 16);
BSTRPICK_W(x3, ed, 4, 4);
BSTRINS_W(x4, x3, 17, 17);
BSTRPICK_W(x3, ed, 3, 3);
BSTRINS_W(x4, x3, 18, 18);
BSTRPICK_W(x3, ed, 2, 2);
BSTRINS_W(x4, x3, 19, 19);
BSTRPICK_W(x3, ed, 0, 0);
BSTRINS_W(x4, x3, 20, 20);
MOVGR2FCSR(FCSR2, x4);
}
break;
case 3:
INST_NAME("VSTMXCSR Md");
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
LD_WU(x4, xEmu, offsetof(x64emu_t, mxcsr));
if (BOX64ENV(sse_flushto0)) {
MOVFCSR2GR(x5, FCSR2);
// Doing LA -> x86 here, ignore denormal
BSTRPICK_W(x3, x5, 16, 16);
BSTRINS_W(x4, x3, 5, 5);
BSTRPICK_W(x3, x5, 17, 17);
BSTRINS_W(x4, x3, 4, 4);
BSTRPICK_W(x3, x5, 18, 18);
BSTRINS_W(x4, x3, 3, 3);
BSTRPICK_W(x3, x5, 19, 19);
BSTRINS_W(x4, x3, 2, 2);
BSTRPICK_W(x3, x5, 20, 20);
BSTRINS_W(x4, x3, 0, 0);
}
ST_W(x4, wback, fixedaddress);
break;
default:
DEFAULT;
}
break;
case 0xC2:
INST_NAME("VCMPPS Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
switch (u8 & 0xf) {
case 0x00: VFCMPxy(S, v0, v1, v2, cEQ); break; // Equal, not unordered
case 0x01: VFCMPxy(S, v0, v1, v2, cLT); break; // Less than
case 0x02: VFCMPxy(S, v0, v1, v2, cLE); break; // Less or equal
case 0x03: VFCMPxy(S, v0, v1, v2, cUN); break; // unordered
case 0x04: VFCMPxy(S, v0, v1, v2, cUNE); break; // Not Equal (or unordered on ARM, not on X86...)
case 0x05: VFCMPxy(S, v0, v2, v1, cULE); break; // Greater or equal or unordered
case 0x06: VFCMPxy(S, v0, v2, v1, cULT); break; // Greater or unordered
case 0x07: VFCMPxy(S, v0, v1, v2, cOR); break; // Greater or unordered
case 0x08: VFCMPxy(S, v0, v1, v2, cUEQ); break; // Equal, or unordered
case 0x09: VFCMPxy(S, v0, v1, v2, cULT); break; // Less than or unordered
case 0x0a: VFCMPxy(S, v0, v1, v2, cULE); break; // Less or equal or unordered
case 0x0b: XVXOR_V(v0, v0, v0); break; // false
case 0x0c: VFCMPxy(S, v0, v1, v2, cNE); break; // Not Eual, ordered
case 0x0d: VFCMPxy(S, v0, v2, v1, cLE); break; // Greater or Equal ordered
case 0x0e: VFCMPxy(S, v0, v2, v1, cLT); break; // Greater ordered
case 0x0f: VSEQxy(B, v0, v1, v1); break; // true
}
break;
case 0xC6:
INST_NAME("VSHUFPS Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (v1 == v2) {
VSHUF4Ixy(W, v0, v1, u8);
} else {
VSHUF4Ixy(W, d0, v1, u8);
VSHUF4Ixy(W, d1, v2, u8 >> 4);
VPICKEVxy(D, v0, d1, d0);
}
break;
default:
DEFAULT;
}
return addr;
}
+235
View File
@@ -0,0 +1,235 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch (opcode) {
case 0xF2:
INST_NAME("ANDN Gd, Vd, Ed");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
GETED(0);
GETVD;
ANDN(gd, ed, vd);
if (!rex.w) {
BSTRPICK_D(gd, gd, 31, 0);
}
CLEAR_FLAGS(x6);
IFX (X_SF) {
SRLI_D(x6, gd, rex.w ? 63 : 31);
SLLI_D(x6, x6, F_SF);
OR(xFlags, xFlags, x6);
}
IFX (X_ZF) {
BNEZ(gd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
SPILL_EFLAGS();
break;
case 0xF3:
nextop = F8;
switch ((nextop >> 3) & 7) {
case 1:
INST_NAME("BLSR Vd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETED(0);
GETVD;
CLEAR_FLAGS(x6);
IFX (X_CF) {
BNEZ(ed, 8);
ORI(xFlags, xFlags, 1 << F_CF);
}
ADDIxw(x3, ed, -1);
AND(vd, ed, x3);
if (!rex.w) {
BSTRPICK_D(vd, vd, 31, 0);
}
IFX (X_ZF) {
BNEZ(vd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
SPILL_EFLAGS();
break;
case 2:
INST_NAME("BLSMSK Vd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETED(0);
GETVD;
CLEAR_FLAGS(x6);
IFX (X_CF) {
BNEZ(ed, 8);
ORI(xFlags, xFlags, 1 << F_CF);
}
ADDIxw(x3, ed, -1);
XOR(vd, ed, x3);
if (!rex.w) {
BSTRPICK_D(vd, vd, 31, 0);
}
IFX (X_SF) {
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
SPILL_EFLAGS();
break;
case 3:
INST_NAME("BLSI Vd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETED(0);
GETVD;
CLEAR_FLAGS(x6);
IFX (X_CF) {
BEQZ(ed, 8);
ORI(xFlags, xFlags, 1 << F_CF);
}
SUBxw(x3, xZR, ed);
AND(vd, ed, x3);
if (!rex.w) {
BSTRPICK_D(vd, vd, 31, 0);
}
IFX (X_ZF) {
BNEZ(vd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
SPILL_EFLAGS();
break;
default:
DEFAULT;
}
break;
case 0xF5:
INST_NAME("BZHI Gd, Ed, Vd");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
GETED(0);
GETVD;
CLEAR_FLAGS(x6);
BSTRPICK_D(x4, vd, 7, 0);
MOV64x(x5, rex.w ? 64 : 32);
BGE_MARK(x4, x5);
ADDI_D(x6, xZR, -1);
SLL_D(x6, x6, x4);
ANDN(gd, ed, x6);
B_MARK2_nocond;
MARK;
OR(gd, ed, ed);
IFX (X_CF) {
ORI(xFlags, xFlags, 1 << F_CF);
}
MARK2;
if (!rex.w) {
BSTRPICK_D(gd, gd, 31, 0);
}
IFX (X_ZF) {
BNEZ(gd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
IFX (X_SF) {
BSTRPICK_D(x5, gd, rex.w ? 63 : 31, rex.w ? 63 : 31);
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
SPILL_EFLAGS();
break;
case 0xF7:
INST_NAME("BEXTR Gd, Vd, Ed");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
GETED(0);
GETVD;
BSTRPICK_D(x4, vd, 7, 0); // start
BSTRPICK_D(x3, vd, 15, 8); // length
XOR(x5, x5, x5);
BEQZ_MARK(x3);
MOV64xw(x6, rex.w ? 64 : 32);
BGE_MARK(x4, x6);
SRLxw(x5, ed, x4);
BLT_MARK(x6, x3);
SUBxw(x6, x6, x3);
SLLxw(x5, x5, x6);
SRLxw(x5, x5, x6);
MARK;
OR(gd, x5, x5);
if (!rex.w) {
BSTRPICK_D(gd, gd, 31, 0);
}
CLEAR_FLAGS(x6);
IFX (X_ZF) {
BNEZ(gd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
}
SPILL_EFLAGS();
break;
default:
DEFAULT;
}
return addr;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+810
View File
@@ -0,0 +1,810 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
#if STEP > 1
static const int8_t round_round[] = {
0x3, // round to nearest with ties to even
0x0, // round toward minus infinity
0x1, // round toward plus infinity
0x2 // round toward zero
};
#endif
rex_t rex = vex.rex;
switch (opcode) {
case 0x00:
case 0x01:
if (opcode) {
INST_NAME("VPERMPD Gx, Ex, Imm8");
} else {
INST_NAME("VPERMQ Gx, Ex, Imm8");
}
nextop = F8;
if (!vex.l) EMIT(0);
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
XVPERMI_D(v0, v1, u8);
break;
case 0x02:
case 0x0C:
if (opcode == 0x2) {
INST_NAME("VPBLENDD Gx, Vx, Ex, Ib");
} else {
INST_NAME("VBLENDPS Gx, Vx, Ex, Ib");
}
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (vex.l) {
// 256bits fast path
if (u8 == 0) {
if (v0 != v1) XVOR_V(v0, v1, v1);
break;
} else if (u8 == 0xFF) {
if (v0 != v2) XVOR_V(v0, v2, v2);
break;
}
} else {
// VEX.128 128bits fast path
if ((u8 & 0xf) == 0) {
if (v0 != v1) VOR_V(v0, v1, v1);
break;
} else if ((u8 & 0xf) == 0xF) {
if (v0 != v2) VOR_V(v0, v2, v2);
break;
}
}
tmp64u = 0;
for (int i = 0; i < 8; i++) {
if (u8 & (1 << i)) tmp64u |= (0xffULL << (i * 8));
}
MOV64x(x5, tmp64u);
MOVGR2FR_D(d0, x5);
VEXT2XV_W_B(d0, d0);
XVBITSEL_V(v0, v1, v2, d0);
break;
case 0x04:
INST_NAME("VPERMILPS Gx, Ex, Imm8");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
VSHUF4Ixy(W, v0, v1, u8);
break;
case 0x05:
INST_NAME("VPERMILPD Gx, Ex, Imm8");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
u8 = 0b10100000 + ((u8 & 0b00001000) << 3) + ((u8 & 0b00000100) << 2) + ((u8 & 0b00000010) << 1) + (u8 & 0b00000001);
XVPERMI_D(v0, v1, u8);
break;
case 0x06:
case 0x46:
if (opcode == 0x06) {
INST_NAME("VPERM2F128 Gx, Vx, Ex, Imm8");
} else {
INST_NAME("VPERM2I128 Gx, Vx, Ex, Imm8");
}
nextop = F8;
if (!vex.l) EMIT(0);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
if ((u8 & 0x88) == 0x88) {
XVXOR_V(v0, v0, v0);
break;
}
d0 = fpu_get_scratch(dyn);
uint8_t zero_low = (u8 & 0x8) >> 3;
uint8_t zero_up = (u8 & 0x80) >> 7;
uint8_t vec_lo = (u8 & 0x2) >> 1;
uint8_t index_lo = u8 & 0x1;
uint8_t vec_hi = (u8 & 0x20) >> 5;
uint8_t index_hi = (u8 & 0x10) >> 4;
if (!zero_low && !zero_up) {
if (v0 == v1) {
XVPERMI_Q(v0, v2, XVPERMI_IMM_4_0((vec_hi ? 0 : 2) | index_hi, (vec_lo ? 0 : 2) | index_lo));
} else if (v0 == v2) {
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0((vec_hi << 1) | index_hi, ((vec_lo) << 1) | index_lo));
} else {
XVOR_V(v0, v2, v2);
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0((vec_hi << 1) | index_hi, ((vec_lo) << 1) | index_lo));
}
break;
}
XVXOR_V(d0, d0, d0);
if (zero_low) {
XVORI_B(v0, vec_hi ? v2 : v1, 0);
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(2 + index_hi, 0));
} else {
XVORI_B(v0, vec_lo ? v2 : v1, 0);
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2 + index_lo));
}
break;
case 0x08:
INST_NAME("VROUNDPS Gx, Ex, Ib");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
if (vex.l) {
XVFRINT_S(v0, v1);
} else {
VFRINT_S(v0, v1);
}
x87_restoreround(dyn, ninst, u8);
} else {
if (vex.l) {
XVFRINTRRD_S(v0, v1, round_round[u8 & 3]);
} else {
VFRINTRRD_S(v0, v1, round_round[u8 & 3]);
}
}
break;
case 0x09:
INST_NAME("VROUNDPD Gx, Ex, Ib");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
if (vex.l) {
XVFRINT_D(v0, v1);
} else {
VFRINT_D(v0, v1);
}
x87_restoreround(dyn, ninst, u8);
} else {
if (vex.l) {
XVFRINTRRD_D(v0, v1, round_round[u8 & 3]);
} else {
VFRINTRRD_D(v0, v1, round_round[u8 & 3]);
}
}
break;
case 0x0A:
INST_NAME("VROUNDSS Gx, Vx, Ex, Ib");
nextop = F8;
GETEYSS(v2, 0, 1);
GETVYx(v1, 0);
GETGYx_empty(v0);
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_S(d0, v2);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_S(d0, v2, round_round[u8 & 3]);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x0B:
INST_NAME("VROUNDSD Gx, Vx, Ex, Ib");
nextop = F8;
GETEYSD(v2, 0, 1);
GETVYx(v1, 0);
GETGYx_empty(v0);
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_D(d0, v2);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_D(d0, v2, round_round[u8 & 3]);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
case 0x0D:
INST_NAME("VBLENDPD Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (vex.l) {
u8 = u8 & 0b1111;
if (u8 == 0b0000) {
XVOR_V(v0, v1, v1);
break;
}
if (u8 == 0b1111) {
XVOR_V(v0, v2, v2);
break;
}
if (u8 == 0b0011) {
if (v0 == v1) {
XVPERMI_Q(v0, v2, XVPERMI_IMM_4_0(3, 0));
} else {
XVOR_V(v0, v2, v2);
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(1, 2));
}
break;
}
if (u8 == 0b1100) {
if (v0 == v1) {
XVPERMI_Q(v0, v2, XVPERMI_IMM_4_0(1, 2));
} else {
XVOR_V(v0, v2, v2);
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
}
break;
}
XVOR_V(d0, v1, v1);
XVOR_V(d1, v1, v1);
if (u8 & 1) XVEXTRINS_D(d0, v2, VEXTRINS_IMM_4_0(0, 0));
if (u8 & 2) XVEXTRINS_D(d0, v2, VEXTRINS_IMM_4_0(1, 1));
if (u8 & 4) XVEXTRINS_D(d1, v2, VEXTRINS_IMM_4_0(0, 0));
if (u8 & 8) XVEXTRINS_D(d1, v2, VEXTRINS_IMM_4_0(1, 1));
XVPERMI_Q(d0, d1, XVPERMI_IMM_4_0(1, 2));
XVOR_V(v0, d0, d0);
} else {
u8 = u8 & 0b11;
switch (u8) {
case 0b00:
VOR_V(v0, v1, v1);
break;
case 0b11:
VOR_V(v0, v2, v2);
break;
case 0b01:
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(1, 1));
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(0, 0));
break;
case 0b10:
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(0, 0));
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(1, 1));
}
}
break;
case 0x0E:
INST_NAME("VPBLENDW Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 == 0) {
if (v0 != v1) VOR_Vxy(v0, v1, v1);
break;
} else if (u8 == 0xFF) {
if (v0 != v2) VOR_Vxy(v0, v2, v2);
break;
}
tmp64u = 0;
for (int i = 0; i < 8; i++) {
if (u8 & (1 << i)) tmp64u |= (0xffULL << (i * 8));
}
MOV64x(x5, tmp64u);
MOVGR2FR_D(d0, x5);
VEXT2XV_H_B(d0, d0);
XVPERMI_Q(d0, d0, 0);
XVBITSEL_V(v0, v1, v2, d0);
break;
case 0x0F:
INST_NAME("VPALIGNR Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (vex.l) {
if (u8 > 31) {
XVXOR_V(v0, v0, v0);
break;
} else {
if (u8 > 15) {
XVBSRL_V(v0, v1, u8 - 16);
} else if (!u8) {
XVOR_V(v0, v2, v2);
} else {
XVBSLL_V(d0, v1, 16 - u8);
XVBSRL_V(d1, v2, u8);
XVOR_V(v0, d0, d1);
}
}
} else {
if (u8 > 31) {
XVXOR_V(v0, v0, v0);
YMM_UNMARK_UPPER_ZERO(v0);
} else if (u8 > 15) {
VBSRL_V(v0, v1, u8 - 16);
} else if (!u8) {
VOR_V(v0, v2, v2);
} else {
VBSLL_V(d0, v1, 16 - u8);
VBSRL_V(d1, v2, u8);
VOR_V(v0, d0, d1);
}
}
break;
case 0x14:
INST_NAME("VPEXTRB Ed, Gx, imm8");
nextop = F8;
GETGYx(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
u8 = (F8) & 15;
VPICKVE2GR_BU(ed, q0, u8);
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 0, 1);
u8 = (F8) & 15;
VSTELM_B(q0, wback, 0, u8);
}
break;
case 0x15:
INST_NAME("VPEXTRW Ed, Gx, imm8");
nextop = F8;
GETGYx(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
u8 = (F8) & 7;
VPICKVE2GR_HU(ed, q0, u8);
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 0, 1);
u8 = (F8) & 7;
VSTELM_H(q0, wback, 0, u8);
}
break;
case 0x16:
if (rex.w) {
INST_NAME("VPEXTRQ Ed, Gx, Ib");
} else {
INST_NAME("VPEXTRD Ed, Gx, Ib");
}
nextop = F8;
GETGYx(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
u8 = F8;
if (rex.w) {
VPICKVE2GR_D(ed, q0, (u8 & 1));
} else {
VPICKVE2GR_WU(ed, q0, (u8 & 3));
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
u8 = F8;
if (rex.w) {
VSTELM_D(q0, ed, 0, (u8 & 1));
} else {
VSTELM_W(q0, ed, 0, (u8 & 3));
}
SMWRITE2();
}
break;
case 0x17:
INST_NAME("VEXTRACTPS Ed, Gx, imm8");
nextop = F8;
GETGYx(v0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
u8 = F8 & 0b11;
VPICKVE2GR_WU(ed, v0, u8);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
u8 = F8 & 0b11;
VSTELM_W(v0, ed, 0, u8);
SMWRITE2();
}
break;
case 0x18:
case 0x38:
if (opcode == 0x18) {
INST_NAME("VINSERTF128 Gx, Vx, Ex, imm8");
} else {
INST_NAME("VINSERTI128 Gx, Vx, Ex, imm8");
}
nextop = F8;
GETEYx(q2, 0, 1);
GETVYy(q1, 0);
GETGYy_empty(q0);
u8 = F8;
if (q0 != q2) {
if (q0 != q1) XVOR_V(q0, q1, q1);
XVPERMI_Q(q0, q2, ((u8 & 1) == 0) ? 0x30 : 0x02);
} else {
XVPERMI_Q(q0, q1, ((u8 & 1) == 0) ? 0x12 : 0x20);
}
break;
case 0x19:
case 0x39:
if (opcode == 0x19) {
INST_NAME("VEXTRACTF128 Ex, Gx, imm8");
} else {
INST_NAME("VEXTRACTI128 Ex, Gx, imm8");
}
nextop = F8;
GETGYy(q0, 0);
if (MODREG) {
GETEYx_empty(q1, 1);
u8 = F8;
if ((u8 & 1) == 0) {
VOR_V(q1, q0, q0);
} else {
XVPERMI_Q(q1, q0, XVPERMI_IMM_4_0(3, 1));
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 0, 1);
u8 = F8;
if ((u8 & 1) == 1) {
XVSTELM_D(q0, ed, 0, 2);
XVSTELM_D(q0, ed, 1, 3);
} else {
VST(q0, ed, fixedaddress);
}
SMWRITE2();
}
break;
case 0x1D:
INST_NAME("VCVTPS2PH Ex, Gx, Ib");
nextop = F8;
GETGYxy(v0, 0);
if (vex.l) {
GETEYx(v1, 1, 1);
} else {
GETEYSD(v1, 1, 1);
}
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
} else {
MOVFCSR2GR(x4, FCSR3);
ORI(x5, x5, round_round[u8 & 3]);
SLLI_D(x5, x5, 8);
MOVGR2FCSR(FCSR3, x5);
u8 = x4;
}
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFCVT_H_S(v1, d0, v0);
XVPERMI_D(v1, v1, 0b11011000);
PUTEYx(v1);
} else {
XVXOR_V(d0, d0, d0);
VFCVT_H_S(v1, d0, v0);
PUTEYSD(v1);
}
x87_restoreround(dyn, ninst, u8);
break;
case 0x20:
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
nextop = F8;
GETEB(x5, 1);
GETVYx(v1, 0);
GETGYx_empty(v0);
u8 = F8;
if (v0 != v1) VOR_V(v0, v1, v1);
VINSGR2VR_B(v0, ed, (u8 & 0xf));
break;
case 0x21:
INST_NAME("VINSERTPS Gx, Vx, Ex, Ib");
nextop = F8;
q1 = fpu_get_scratch(dyn);
if (MODREG) {
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
if (v0 == v2) {
VOR_V(q1, v2, v2);
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0((u8 >> 4) & 3, (u8 >> 6) & 3));
} else {
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, v2, VEXTRINS_IMM_4_0((u8 >> 4) & 3, (u8 >> 6) & 3));
}
} else {
GETVYx(v1, 0);
GETGYx_empty(v0);
if (v0 != v1) VOR_V(v0, v1, v1);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x5, &fixedaddress, rex, NULL, 1, 1);
u8 = F8;
FLD_S(q1, wback, fixedaddress);
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0((u8 >> 4) & 3, 0)); // src index is zero when Ex is mem operand
}
uint8_t zmask = u8 & 0xf;
if (zmask) {
VXOR_V(q1, q1, q1);
for (uint8_t i = 0; i < 4; i++) {
if (zmask & (1 << i)) {
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0(i, 0));
}
}
}
break;
case 0x22:
if (rex.w) {
INST_NAME("VPINSRQ Gx, Vx, ED, Ib");
} else {
INST_NAME("VPINSRD Gx, Vx, ED, Ib");
}
nextop = F8;
GETED(1);
GETVYx(v1, 0);
GETGYx_empty(v0);
u8 = F8;
if (v0 != v1) VOR_V(v0, v1, v1);
if (rex.w) {
VINSGR2VR_D(v0, ed, (u8 & 0x1));
} else {
VINSGR2VR_W(v0, ed, (u8 & 0x3));
}
break;
case 0x40:
INST_NAME("VDPPS Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
d2 = fpu_get_scratch(dyn);
VFMULxy(S, d0, v1, v2);
VXOR_Vxy(d2, d2, d2);
for (int i = 0; i < 4; ++i) {
if (!(u8 & (1 << (4 + i)))) {
VEXTRINSxy(W, d0, d2, (i << 4));
}
}
VSHUF4Ixy(W, d1, d0, 0b10110001); // v0[a,b,c,d] v1[b,a,d,c]
VFADDxy(S, d0, d0, d1); // v0[ab,ba,cd,dc]
VSHUF4Ixy(W, d1, d0, 0b01001110); // v1[cd,dc,ab,ba]
VFADDxy(S, d0, d0, d1); // v0[abcd,badc,cdab,dcba]
VREPLVEIxy(W, v0, d0, 0);
for (int i = 0; i < 4; ++i) {
if (!(u8 & (1 << i))) {
VEXTRINSxy(W, v0, d2, (i << 4));
}
}
break;
case 0x41:
INST_NAME("VDPPD Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
d2 = fpu_get_scratch(dyn);
VFMULxy(D, d0, v1, v2);
VXOR_Vxy(d2, d2, d2);
for (int i = 0; i < 2; ++i) {
if (!(u8 & (1 << (4 + i)))) {
VEXTRINSxy(D, d0, d2, (i << 4));
}
}
VSHUF4Ixy(W, d1, d0, 0b01001110); // v0[a,b] v1[b,a]
VFADDxy(D, d0, d0, d1); // v0[ab,ba]
VREPLVEIxy(D, v0, d0, 0);
for (int i = 0; i < 2; ++i) {
if (!(u8 & (1 << i))) {
VEXTRINSxy(D, v0, d2, (i << 4));
}
}
break;
case 0x42:
INST_NAME("VMPSADBW Gx, Vx, Ex, Ib");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
u8 = F8;
if (vex.l) {
uint8_t low_blk2_offset = 4 * (u8 & 3);
uint8_t low_blk1_offset = 4 * ((u8 >> 2) & 1);
uint8_t high_blk2_offset = 4 * ((u8 >> 3) & 3);
uint8_t high_blk1_offset = 4 * ((u8 >> 5) & 1);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (low_blk1_offset == high_blk1_offset) {
// generate hi128/low128 mask in one shot
XVMEPATMSK_V(d0, 1, low_blk1_offset);
XVMEPATMSK_V(d1, 1, low_blk1_offset + 4);
XVSHUF_B(q0, v1, v1, d0);
XVSHUF_B(q2, v1, v1, d1);
} else {
XVMEPATMSK_V(d0, 1, low_blk1_offset);
XVMEPATMSK_V(d1, 1, high_blk1_offset);
XVSHUF_B(q0, v1, v1, d0);
XVSHUF_B(q1, v1, v1, d1);
XVPERMI_Q(q0, q1, XVPERMI_IMM_4_0(1, 2));
XVMEPATMSK_V(d0, 1, low_blk1_offset + 4);
XVMEPATMSK_V(d1, 1, high_blk1_offset + 4);
XVSHUF_B(q2, v1, v1, d0);
XVSHUF_B(q1, v1, v1, d1);
XVPERMI_Q(q2, q1, XVPERMI_IMM_4_0(1, 2));
}
if (low_blk2_offset == high_blk2_offset) {
// generate hi128/low128 mask in one shot
XVBSRL_V(q1, v2, low_blk2_offset);
XVSHUF4I_W(q1, q1, 0b00000000);
} else {
XVBSRL_V(q1, v2, low_blk2_offset);
XVBSRL_V(d1, v2, high_blk2_offset);
XVPERMI_Q(q1, d1, XVPERMI_IMM_4_0(1, 2));
XVSHUF4I_W(q1, q1, 0b00000000);
}
XVABSD_BU(d0, q0, q1);
XVABSD_BU(d1, q2, q1);
XVHADDW_HU_BU(d0, d0, d0);
XVHADDW_HU_BU(d1, d1, d1);
XVHADDW_WU_HU(d0, d0, d0);
XVHADDW_WU_HU(d1, d1, d1);
XVSSRANI_HU_W(d0, d0, 0);
XVSSRANI_HU_W(d1, d1, 0);
XVEXTRINS_D(v0, d0, VEXTRINS_IMM_4_0(0, 0));
XVEXTRINS_D(v0, d1, VEXTRINS_IMM_4_0(1, 0));
} else {
uint8_t blk2_offset = 4 * (u8 & 3);
uint8_t blk1_offset = 4 * ((u8 >> 2) & 1);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VMEPATMSK_V(d0, 1, blk1_offset);
VMEPATMSK_V(d1, 1, blk1_offset + 4);
VSHUF_B(q0, v1, v1, d0);
VSHUF_B(q2, v1, v1, d1);
VBSRL_V(q1, v2, blk2_offset);
VSHUF4I_W(q1, q1, 0b00000000);
VABSD_BU(d0, q0, q1);
VABSD_BU(d1, q2, q1);
VHADDW_HU_BU(d0, d0, d0);
VHADDW_HU_BU(d1, d1, d1);
VHADDW_WU_HU(d0, d0, d0);
VHADDW_WU_HU(d1, d1, d1);
VSSRANI_HU_W(d0, d0, 0);
VSSRANI_HU_W(d1, d1, 0);
VEXTRINS_D(v0, d0, VEXTRINS_IMM_4_0(0, 0));
VEXTRINS_D(v0, d1, VEXTRINS_IMM_4_0(1, 0));
}
break;
case 0x44:
INST_NAME("VPCLMULQDQ Gx, Vx, Ex, Ib");
nextop = F8;
GETG;
avx_forget_reg(dyn, ninst, gd);
avx_reflect_reg(dyn, ninst, vex.v);
MOV32w(x1, gd); // gx
MOV32w(x2, vex.v); // vx
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
avx_forget_reg(dyn, ninst, ed);
MOV32w(x3, ed); // ex
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
if (ed != x3) MV(x3, ed);
}
u8 = F8;
MOV32w(x4, u8);
CALL4_(vex.l ? const_native_pclmul_y : const_native_pclmul_x, -1, x3, x1, x2, x3, x4);
if (!vex.l) {
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]));
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]) + 8);
}
break;
case 0x4A:
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
F8;
q0 = fpu_get_scratch(dyn);
VSLTIxy(W, q0, d0, 0);
VBITSEL_Vxy(v0, v1, v2, q0);
break;
case 0x4B:
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
F8;
q0 = fpu_get_scratch(dyn);
VSLTIxy(D, q0, d0, 0);
VBITSEL_Vxy(v0, v1, v2, q0);
break;
case 0x4C:
INST_NAME("VPBLENDVB Gx, Vx, Ex, XMMImm8");
nextop = F8;
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
F8;
q0 = fpu_get_scratch(dyn);
VSLTIxy(B, q0, d0, 0);
VBITSEL_Vxy(v0, v1, v2, q0);
break;
case 0xDF:
INST_NAME("VAESKEYGENASSIST Gx, Ex, Ib");
nextop = F8;
GETG;
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd); // gx
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
avx_forget_reg(dyn, ninst, ed);
MOV32w(x2, ed);
MOV32w(x3, 0); // p = NULL
} else {
MOV32w(x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 1);
if (ed != x3) {
MV(x3, ed);
}
}
u8 = F8;
MOV32w(x4, u8);
CALL4(const_native_aeskeygenassist, -1, x1, x2, x3, x4);
if (!vex.l) {
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]));
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]) + 8);
}
break;
default:
DEFAULT;
}
return addr;
}
+524
View File
@@ -0,0 +1,524 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u, u64;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch (opcode) {
case 0x10:
INST_NAME("VMOVSD Gx, [Vx,] Ex");
nextop = F8;
if (MODREG) {
GETVYx(q1, 0);
GETEYSD(q2, 0, 0);
GETGYx_empty(q0);
if (gd != vex.v) VOR_V(q0, q1, q1);
VEXTRINS_D(q0, q2, 0);
} else {
GETEYSD(q2, 0, 0);
GETGYx_empty(q0);
XVPICKVE_D(q0, q2, 0);
YMM_UNMARK_UPPER_ZERO(q0);
}
break;
case 0x11:
INST_NAME("VMOVSD Ex, [Vx,] Gx");
nextop = F8;
GETGYx(q2, 0);
if (MODREG) {
if (ed == vex.v) {
GETEYSD(q0, 1, 0);
VEXTRINS_D(q0, q2, 0);
} else {
GETVYx(q1, 0);
GETEYSD(q0, 1, 0);
VOR_V(q0, q1, q1);
VEXTRINS_D(q0, q2, 0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
FST_D(q2, ed, fixedaddress);
SMWRITE2();
}
break;
case 0x12:
INST_NAME("VMOVDDUP Gx, Ex");
nextop = F8;
if (MODREG) {
GETGY_empty_EY_xy(q0, q1, 0);
} else {
GETGYxy_empty(q0);
q1 = fpu_get_scratch(dyn);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 0, 0);
if (vex.l) {
XVLD(q1, ed, 0);
} else {
VLDREPL_D(q0, ed, 0);
}
}
if (vex.l) {
XVSHUF4I_D(q0, q1, 0b1010);
} else if (MODREG) {
VREPLVE_D(q0, q1, 0);
}
break;
case 0x2A:
INST_NAME("VCVTSI2SD Gx, Vx, Ed");
nextop = F8;
GETED(0);
GETVYx(v1, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
if (!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x2, x3);
}
d1 = fpu_get_scratch(dyn);
if (rex.w) {
MOVGR2FR_D(d1, ed);
FFINT_D_L(d1, d1);
} else {
MOVGR2FR_W(d1, ed);
FFINT_D_W(d1, d1);
}
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
if(v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d1, 0);
break;
case 0x2C:
INST_NAME("VCVTTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETEYSD(q0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
d1 = fpu_get_scratch(dyn);
if (rex.w) {
FTINTRZ_L_D(d1, q0);
MOVFR2GR_D(gd, d1);
} else {
FTINTRZ_W_D(d1, q0);
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
AND(x5, x5, x3);
CBZ_NEXT(x5);
if (rex.w) {
MOV64x(gd, 0x8000000000000000LL);
} else {
MOV32w(gd, 0x80000000);
}
}
break;
case 0x2D:
INST_NAME("VCVTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETEYSD(q0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
d1 = fpu_get_scratch(dyn);
u8 = sse_setround(dyn, ninst, x2, x3);
if (rex.w) {
FTINT_L_D(d1, q0);
MOVFR2GR_D(gd, d1);
} else {
FTINT_W_D(d1, q0);
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
x87_restoreround(dyn, ninst, u8);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
AND(x5, x5, x3);
CBZ_NEXT(x5);
if (rex.w) {
MOV64x(gd, 0x8000000000000000LL);
} else {
MOV32w(gd, 0x80000000);
}
}
break;
case 0x51:
INST_NAME("VSQRTSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
FSQRT_D(d1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
VXOR_V(d0, d0, d0);
FCMP_D(fcc0, v2, d0, cLT);
BCEQZ(fcc0, 4 + 4);
FNEG_D(d1, d1);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d1, 0);
break;
case 0x58:
INST_NAME("VADDSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FADD_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
case 0x59:
INST_NAME("VMULSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FMUL_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
case 0x5A:
INST_NAME("VCVTSD2SS Gx, Vx, Ex");
nextop = F8;
GETEYSD(v2, 0, 0);
GETVYx(v1, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FCVT_S_D(d0, v2);
if(v0 != v1) VOR_V(v0, v1, v1);
XVINSVE0_W(v0, d0, 0);
break;
case 0x5C:
INST_NAME("VSUBSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FSUB_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
case 0x5D:
INST_NAME("VMINSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
q0 = fpu_get_scratch(dyn);
if (BOX64ENV(dynarec_fastnan)) {
FMIN_D(q0, v1, v2);
} else {
FCMP_D(fcc0, v2, v1, cULE);
FSEL(q0, v1, v2, fcc0);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, q0, 0);
break;
case 0x5E:
INST_NAME("VDIVSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FDIV_D(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_D(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_D(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_D(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d0, 0);
break;
case 0x5F:
INST_NAME("VMAXSD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 0);
GETGYx_empty(v0);
q0 = fpu_get_scratch(dyn);
if (BOX64ENV(dynarec_fastnan)) {
FMAX_D(q0, v1, v2);
} else {
FCMP_D(fcc0, v2, v1, cLT);
FSEL(q0, v2, v1, fcc0);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, q0, 0);
break;
case 0x70:
INST_NAME("VPSHUFLW Gx, Ex, Ib");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (v0 != v1) {
VSHUF4Ixy(H, v0, v1, u8);
VEXTRINSxy(D, v0, v1, VEXTRINS_IMM_4_0(1, 1));
} else {
VSHUF4Ixy(H, d0, v1, u8);
VEXTRINSxy(D, v0, d0, VEXTRINS_IMM_4_0(0, 0));
}
break;
case 0x7C:
INST_NAME("VHADDPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
q0 = fpu_get_scratch(dyn);
VPICKEVxy(W, q0, v2, v1);
VPICKODxy(W, v0, v2, v1);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, q0, v0, cUN);
}
VFADDxy(S, v0, q0, v0);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0x7D:
INST_NAME("VHSUBPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
q0 = fpu_get_scratch(dyn);
VPICKEVxy(W, q0, v2, v1);
VPICKODxy(W, v0, v2, v1);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, q0, v0, cUN);
}
VFSUBxy(S, v0, q0, v0);
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0xC2:
INST_NAME("VCMPSD Gx, Vx, Ex, Ib");
nextop = F8;
GETVYx(v1, 0);
GETEYSD(v2, 0, 1);
GETGYx(v0, 1);
q0 = fpu_get_scratch(dyn);
u8 = F8;
switch (u8 & 0xf) {
case 0x00: VFCMP_D(q0, v1, v2, cEQ); break; // Equal, not unordered
case 0x01: VFCMP_D(q0, v1, v2, cLT); break; // Less than
case 0x02: VFCMP_D(q0, v1, v2, cLE); break; // Less or equal
case 0x03: VFCMP_D(q0, v1, v2, cUN); break; // unordered
case 0x04: VFCMP_D(q0, v1, v2, cUNE); break; // Not Equal (or unordered on ARM, not on X86...)
case 0x05: VFCMP_D(q0, v2, v1, cULE); break; // Greater or equal or unordered
case 0x06: VFCMP_D(q0, v2, v1, cULT); break; // Greater or unordered
case 0x07: VFCMP_D(q0, v1, v2, cOR); break; // Greater or unordered
case 0x08: VFCMP_D(q0, v1, v2, cUEQ); break; // Equal, or unordered
case 0x09: VFCMP_D(q0, v1, v2, cULT); break; // Less than or unordered
case 0x0a: VFCMP_D(q0, v1, v2, cULE); break; // Less or equal or unordered
case 0x0b: VXOR_V(q0, q0, q0); break; // false
case 0x0c: VFCMP_D(q0, v1, v2, cNE); break; // Not Eual, ordered
case 0x0d: VFCMP_D(q0, v2, v1, cLE); break; // Greater or Equal ordered
case 0x0e: VFCMP_D(q0, v2, v1, cLT); break; // Greater ordered
case 0x0f: VSEQ_B(q0, v1, v1); break; // true
}
XVXOR_V(v0, v0, v0);
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
XVINSVE0_D(v0, q0, 0);
YMM_UNMARK_UPPER_ZERO(v0);
break;
case 0xD0:
INST_NAME("VADDSUBPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFCMPxy(S, d0, v1, v2, cUN);
}
q0 = fpu_get_scratch(dyn);
VFSUBxy(S, q0, v1, v2);
VFADDxy(S, v0, v1, v2);
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(0, 0));
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(2, 2));
if (!BOX64ENV(dynarec_fastnan)) {
VFCMPxy(S, d1, v0, v0, cUN);
VANDN_Vxy(d0, d0, d1);
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
VBITSEL_Vxy(v0, v0, d1, d0);
}
break;
case 0xE6:
INST_NAME("VCVTPD2DQ Gx, Ex");
nextop = F8;
GETEYxy(v1, 0, 0);
GETGYx_empty(v0);
u8 = sse_setround(dyn, ninst, x1, x2);
d0 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
XVFTINT_L_D(q2, v1);
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
MOV32w(x5, 0x7FFFFFFF);
BSTRPICK_D(x5, x5, 31, 0);
XVREPLGR2VR_D(q1, x5);
XVFCMP_D(d0, v1, v1, cUN); // get Nan mask
XVSLT_D(d1, q1, q2); // get +inf mask
XVOR_V(d0, d1, d0);
XVSRLNI_W_D(d0, d0, 0); // [A,B,C,D] => [a,b,--,--,c,d,--,--]
XVBITSEL_V(v0, v0, q0, d0);
}
XVPERMI_D(v0, v0, 0b11011000);
} else {
VFTINT_W_D(d0, v1, v1);
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
VFTINT_L_D(d1, v1);
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
MOV32w(x5, 0x7FFFFFFF);
BSTRPICK_D(x5, x5, 31, 0);
VREPLGR2VR_D(q1, x5);
VSLT_D(q1, q1, d1); // get +inf mask
VFCMP_D(q2, v1, v1, cUN); // get Nan mask
VOR_V(q1, q1, q2);
VSHUF4I_W(q1, q1, 0b11011000);
VBITSEL_V(d0, d0, q0, q1);
}
XVPICKVE_D(v0, d0, 0);
YMM_UNMARK_UPPER_ZERO(v0);
}
x87_restoreround(dyn, ninst, u8);
break;
case 0xF0:
INST_NAME("VLDDQU Gx, Ex");
nextop = F8;
if (MODREG) {
GETGY_empty_EY_xy(q0, q1, 0);
if (vex.l) {
XVOR_V(q0, q1, q1);
} else {
VOR_V(q0, q1, q1);
}
} else {
GETGYxy_empty(q0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVLD(q0, ed, fixedaddress);
} else {
VLD(q0, ed, fixedaddress);
}
}
break;
default:
DEFAULT;
}
return addr;
}
+126
View File
@@ -0,0 +1,126 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch (opcode) {
case 0xF5:
INST_NAME("PDEP Gd, Vd, Ed");
nextop = F8;
GETGD;
GETVD;
GETED(0);
if (gd == ed || gd == vd) {
gb1 = gd;
gd = x6;
} else {
gb1 = 0;
}
MOV64x(gd, 0);
MOV64x(x3, 1);
MOV64x(x4, 1);
MARK;
AND(x5, ed, x4);
BEQZ_MARK2(x5);
AND(x5, vd, x3);
BEQZ_MARK3(x5);
OR(gd, gd, x4);
MARK3;
SLLIxw(x3, x3, 1);
MARK2;
SLLIxw(x4, x4, 1);
BNEZ_MARK(x4);
if (gb1)
OR(gb1, gd, gd);
break;
case 0xF6:
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
nextop = F8;
GETGD;
GETED(0);
GETVD;
if ((gd == xRDX) || (gd == ed) || (gd == vd))
gb1 = x3;
else
gb1 = gd;
if (rex.w) {
MULH_DU(gb1, xRDX, ed);
if (gd != vd) { MUL_D(vd, xRDX, ed); }
if (gb1 == x3) {
OR(gd, gb1, gb1);
}
} else {
MULH_WU(gb1, xRDX, ed);
if (gd != vd) { MUL_W(vd, xRDX, ed); }
}
if (gb1 == x3) {
BSTRINS_D(gd, gb1, 31, 0);
}
break;
case 0xF7:
INST_NAME("SHRX Gd, Ed, Vd");
nextop = F8;
GETGD;
GETED(0);
GETVD;
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
SRLxw(gd, ed, x5);
break;
default:
DEFAULT;
}
return addr;
}
@@ -0,0 +1,72 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F2_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u;
int64_t j64;
int64_t fixedaddress;
int unscaled;
MAYUSE(wb1);
MAYUSE(wb2);
MAYUSE(eb1);
MAYUSE(eb2);
MAYUSE(gb1);
MAYUSE(gb2);
MAYUSE(q0);
MAYUSE(q1);
MAYUSE(d0);
MAYUSE(d1);
MAYUSE(s0);
MAYUSE(j64);
MAYUSE(cacheupd);
rex_t rex = vex.rex;
switch (opcode) {
case 0xF0:
INST_NAME("RORX Gd, Ed, Ib");
nextop = F8;
GETGD;
GETED(1);
u8 = F8;
ROTRIxw(gd, ed, u8 & (rex.w ? 0x3f : 0x1f));
break;
default:
DEFAULT;
}
return addr;
}
+504
View File
@@ -0,0 +1,504 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include "debug.h"
#include "env.h"
#include "box64context.h"
#include "box64cpu.h"
#include "emu/x64emu_private.h"
#include "x64emu.h"
#include "box64stack.h"
#include "callback.h"
#include "emu/x64run_private.h"
#include "x64trace.h"
#include "dynarec_native.h"
#include "la64_printer.h"
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
(void)ip;
(void)need_epilog;
uint8_t opcode = F8;
uint8_t nextop, u8;
uint8_t gd, ed, vd;
uint8_t wback, wb1, wb2, gback, vback;
uint8_t eb1, eb2, gb1, gb2;
int32_t i32, i32_;
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int s0;
uint64_t tmp64u, u64;
int64_t j64;
int64_t fixedaddress, gdoffset, vxoffset;
int unscaled;
rex_t rex = vex.rex;
switch (opcode) {
case 0x10:
INST_NAME("VMOVSS Gx, [Vx,] Ex");
nextop = F8;
if (MODREG) {
GETVYx(q1, 0);
GETEYSS(q2, 0, 0);
GETGYx_empty(q0);
if (gd != vex.v) VOR_V(q0, q1, q1);
VEXTRINS_W(q0, q2, 0);
} else {
GETEYSS(q2, 0, 0);
GETGYx_empty(q0);
XVPICKVE_W(q0, q2, 0);
YMM_UNMARK_UPPER_ZERO(q0);
}
break;
case 0x11:
INST_NAME("VMOVSS Ex, [Vx,] Gx");
nextop = F8;
GETGYx(q2, 0);
if (MODREG) {
if (ed == vex.v) {
GETEYSS(q0, 1, 0);
VEXTRINS_W(q0, q2, 0);
} else {
GETVYx(q1, 0);
GETEYSS(q0, 1, 0);
VOR_V(q0, q1, q1);
VEXTRINS_W(q0, q2, 0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
FST_S(q2, ed, fixedaddress);
SMWRITE2();
}
break;
case 0x12:
INST_NAME("VMOVSLDUP Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(q0, q1, 0);
if (vex.l) {
XVPACKEV_W(q0, q1, q1);
} else {
VPACKEV_W(q0, q1, q1);
}
break;
case 0x16:
INST_NAME("VMOVSHDUP Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(q0, q1, 0);
if (vex.l) {
XVPACKOD_W(q0, q1, q1);
} else {
VPACKOD_W(q0, q1, q1);
}
break;
case 0x2A:
INST_NAME("VCVTSI2SS Gx, Vx, Ed");
nextop = F8;
GETED(0);
GETVYx(v1, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
if (!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x2, x3);
}
if (rex.w) {
MOVGR2FR_D(d1, ed);
FFINT_S_L(d1, d1);
} else {
MOVGR2FR_W(d1, ed);
FFINT_S_W(d1, d1);
}
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
if(v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d1, 0);
break;
case 0x2C:
INST_NAME("VCVTTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETEYSS(d0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
u8 = sse_setround(dyn, ninst, x5, x6);
d1 = fpu_get_scratch(dyn);
if (rex.w) {
FTINTRZ_L_S(d1, d0);
MOVFR2GR_D(gd, d1);
} else {
FTINTRZ_W_S(d1, d0);
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
x87_restoreround(dyn, ninst, u8);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
AND(x5, x5, x3);
CBZ_NEXT(x5);
if (rex.w) {
MOV64x(gd, 0x8000000000000000LL);
} else {
MOV32w(gd, 0x80000000);
}
}
break;
case 0x2D:
INST_NAME("VCVTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETEYSS(d0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
u8 = sse_setround(dyn, ninst, x5, x6);
d1 = fpu_get_scratch(dyn);
if (rex.w) {
FTINT_L_S(d1, d0);
MOVFR2GR_D(gd, d1);
} else {
FTINT_W_S(d1, d0);
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
x87_restoreround(dyn, ninst, u8);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
AND(x5, x5, x3);
CBZ_NEXT(x5);
if (rex.w) {
MOV64x(gd, 0x8000000000000000LL);
} else {
MOV32w(gd, 0x80000000);
}
}
break;
case 0x51:
INST_NAME("VSQRTSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
FSQRT_S(d1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
VXOR_V(d0, d0, d0);
FCMP_S(fcc0, v2, d0, cLT);
BCEQZ(fcc0, 4 + 4);
FNEG_S(d1, d1);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d1, 0);
break;
case 0x52:
INST_NAME("VRSQRTSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
if (cpuext.frecipe) {
FRSQRTE_S(d0, v1);
} else {
FRSQRT_S(d0, v1);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x53:
INST_NAME("VRCPSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
if (cpuext.frecipe) {
FRECIPE_S(d0, v1);
} else {
FRECIP_S(d0, v1);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x58:
INST_NAME("VADDSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FADD_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x59:
INST_NAME("VMULSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FMUL_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x5A:
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
FCVT_D_S(d1, v2);
if(v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d1, 0);
break;
case 0x5B:
INST_NAME("VCVTTPS2DQ Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
if (vex.l) {
if (!BOX64ENV(dynarec_fastround)) {
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn); // mask
d0 = fpu_get_scratch(dyn);
XVFTINTRZ_W_S(d1, v1);
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
XVLDI(d0, (0b10011 << 8) | 0x4f);
XVFCMP_S(q1, d0, v1, cULE); // get Nan,+overflow mark
XVBITSEL_V(v0, d1, q0, q1);
} else {
XVFTINTRZ_W_S(v0, v1);
}
} else {
if (!BOX64ENV(dynarec_fastround)) {
d1 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn); // mask
d0 = fpu_get_scratch(dyn);
VFTINTRZ_W_S(d1, v1);
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
VLDI(d0, (0b10011 << 8) | 0x4f);
VFCMP_S(q1, d0, v1, cULE); // get Nan,+overflow mark
VBITSEL_V(v0, d1, q0, q1);
} else {
VFTINTRZ_W_S(v0, v1);
}
}
break;
case 0x5C:
INST_NAME("VSUBSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FSUB_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x5D:
INST_NAME("VMINSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
q0 = fpu_get_scratch(dyn);
if (BOX64ENV(dynarec_fastnan)) {
FMIN_S(q0, v1, v2);
} else {
FCMP_S(fcc0, v2, v1, cULE);
FSEL(q0, v1, v2, fcc0);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, q0, 0);
break;
case 0x5E:
INST_NAME("VDIVSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
FDIV_S(d0, v1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
FCMP_S(fcc0, v1, v2, cUN);
BCNEZ_MARK(fcc0);
FCMP_S(fcc1, d0, d0, cOR);
BCNEZ_MARK(fcc1);
FNEG_S(d0, d0);
}
MARK;
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d0, 0);
break;
case 0x5F:
INST_NAME("VMAXSS Gx, Vx, Ex");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 0);
GETGYx_empty(v0);
q0 = fpu_get_scratch(dyn);
if (BOX64ENV(dynarec_fastnan)) {
FMAX_S(q0, v1, v2);
} else {
FCMP_S(fcc0, v2, v1, cLT);
FSEL(q0, v2, v1, fcc0);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, q0, 0);
break;
case 0x6F:
INST_NAME("VMOVDQU Gx, Ex");
nextop = F8;
if (MODREG) {
GETGY_empty_EY_xy(q0, q1, 0);
if (vex.l) {
XVOR_V(q0, q1, q1);
} else {
VOR_V(q0, q1, q1);
}
} else {
GETGYxy_empty(q0);
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVLD(q0, ed, fixedaddress);
} else {
VLD(q0, ed, fixedaddress);
}
}
break;
case 0x70:
INST_NAME("VPSHUFHW Gx, Ex, Ib");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (v0 != v1) {
VSHUF4Ixy(H, v0, v1, u8);
VEXTRINSxy(D, v0, v1, VEXTRINS_IMM_4_0(0, 0));
} else {
VSHUF4Ixy(H, d0, v1, u8);
VEXTRINSxy(D, v0, d0, VEXTRINS_IMM_4_0(1, 1));
}
break;
case 0x7E:
INST_NAME("VMOVQ Gx, Ex");
nextop = F8;
GETEYSD(q1, 0, 0);
GETGYx_empty(q0);
XVPICKVE_D(q0, q1, 0);
YMM_UNMARK_UPPER_ZERO(q0);
break;
case 0x7F:
INST_NAME("VMOVDQU Ex, Gx");
nextop = F8;
GETGYxy(q0, 0);
if (MODREG) {
GETEYxy_empty(q1, 0);
if (vex.l) {
XVOR_V(q1, q0, q0);
} else {
VOR_V(q1, q0, q0);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVST(q0, ed, fixedaddress);
} else {
VST(q0, ed, fixedaddress);
}
SMWRITE2();
}
break;
case 0xC2:
INST_NAME("VCMPSS Gx, Vx, Ex, Ib");
nextop = F8;
GETVYx(v1, 0);
GETEYSS(v2, 0, 1);
GETGYx(v0, 1);
q0 = fpu_get_scratch(dyn);
u8 = F8;
switch (u8 & 0xf) {
case 0x00: VFCMP_S(q0, v1, v2, cEQ); break; // Equal, not unordered
case 0x01: VFCMP_S(q0, v1, v2, cLT); break; // Less than
case 0x02: VFCMP_S(q0, v1, v2, cLE); break; // Less or equal
case 0x03: VFCMP_S(q0, v1, v2, cUN); break; // unordered
case 0x04: VFCMP_S(q0, v1, v2, cUNE); break; // Not Equal (or unordered on ARM, not on X86...)
case 0x05: VFCMP_S(q0, v2, v1, cULE); break; // Greater or equal or unordered
case 0x06: VFCMP_S(q0, v2, v1, cULT); break; // Greater or unordered
case 0x07: VFCMP_S(q0, v1, v2, cOR); break; // Greater or unordered
case 0x08: VFCMP_S(q0, v1, v2, cUEQ); break; // Equal, or unordered
case 0x09: VFCMP_S(q0, v1, v2, cULT); break; // Less than or unordered
case 0x0a: VFCMP_S(q0, v1, v2, cULE); break; // Less or equal or unordered
case 0x0b: VXOR_V(q0, q0, q0); break; // false
case 0x0c: VFCMP_S(q0, v1, v2, cNE); break; // Not Eual, ordered
case 0x0d: VFCMP_S(q0, v2, v1, cLE); break; // Greater or Equal ordered
case 0x0e: VFCMP_S(q0, v2, v1, cLT); break; // Greater ordered
case 0x0f: VSEQ_B(q0, v1, v1); break; // true
}
XVXOR_V(v0, v0, v0);
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
XVINSVE0_W(v0, q0, 0);
YMM_UNMARK_UPPER_ZERO(v0);
break;
case 0xE6:
INST_NAME("CVTDQ2PD Gx, Ex");
nextop = F8;
d0 = fpu_get_scratch(dyn);
if(vex.l){
GETEYx(v1, 0, 0);
GETGYy_empty(v0);
XVFFINTL_D_W(v0, v1);
XVFFINTH_D_W(d0, v1);
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2));
}else{
GETEYSD(v1, 0, 0);
GETGYx_empty(v0);
VFFINTL_D_W(v0, v1);
}
break;
default:
DEFAULT;
}
return addr;
}
Loaded 100 of 395 files, more files were not shown because too many files have changed in this diff. Show more