Compare commits

..
394 Commits
Author SHA1 Message Date
ptitSeb 2f130fab1d Bumped version to v0.4.4 2026-08-02 11:31:59 +02:00
Yang Liu 08f8666596 [RV64_DYNAREC] Restored vector SEW after cache transform (#4175) 2026-08-02 11:16:02 +02:00
Mikura Kyouka fb5294a125 [SIGNAL] Preserve TF handling when resuming signals with Dynarec (#4174)
When a signal handler restores a context with TF set, resume through the interpreter for one instruction so no_tf can suppress the initial spurious SIGTRAP.

This fixes the issue exposed after commit 38d64ba when running Syringe.exe from the Ares expansion platform.
2026-08-02 09:00:50 +02:00
Yang Liu b3384b5c81 [RV64_DYNAREC] Fixed more GETEX mistakes (#4173) 2026-08-02 08:56:17 +02:00
Yang Liu 7058d990c4 [RV64_DYNAREC] Fixed PACKSSDW opcode (#4172) 2026-08-02 08:56:05 +02:00
Yang Liu 8557ede0e9 [RV64_DYNAREC] Flush pending double reg on size change (#4171) 2026-08-02 08:55:36 +02:00
Yang Liu 78383901f2 [RV64_DYNAREC] Fixed PEXT opcode (#4170) 2026-08-01 17:43:51 +02:00
Yang Liu ebccae45e3 [RV64_DYNAREC] Fixed a long standing typo in CALL opcode (#4168) 2026-08-01 11:40:18 +02:00
Yang Liu 80b5e387d2 [RV64_DYNAREC] Fixed PDEP opcode (#4167) 2026-08-01 08:49:59 +02:00
Yang Liu 15e065ae5d [WRAPPER] Wrapped isoc23_[v]scanf (#4162)
* [WRAPPER] Wrapped isoc23_[v]scanf

* Fixed scanf wrapping
2026-07-31 13:44:09 +02:00
Yang Liu 00ca85606d [SYSCALL] Added a few more syscalls (#4163) 2026-07-31 13:43:21 +02:00
Yang Liu bc181e7812 [SYSCALL] Fixed a bad bad bug (#4161)
It seems that back in 2019, when `fchmodat4` syscall was introduced, it did get the number 434:
https://lists.openwall.net/linux-kernel/2019/07/17/25, but that patch was rejected and 434 was assigned to `pidfd_open` later.
2026-07-31 12:08:38 +02:00
Luke Short 0f6b8ccc68 [DOCS] Recommend SteamRT3/SteamRT64 (#4157)
when Box86 is unavailable.
2026-07-31 08:56:12 +02:00
Luke Short ffeff6599b [SYSCALL] Add various simple syscalls (#4144) 2026-07-30 16:35:32 +02:00
ptitSeb 3e71996209 Fixed potential overflow on cpu brand for cpuid opcode 2026-07-30 16:33:10 +02:00
ptitSeb bbb2560ff8 [RCFILE] Added 1 more game profile 2026-07-30 14:48:18 +02:00
Zane 30b1bf210d [SYSCALL] Add syscall 32 (#4156) 2026-07-30 11:27:01 +02:00
Luke Short 178e344b98 [RCFILE] Added game profile for VRChat (#4153)
Resolves #1996
2026-07-29 21:04:20 +02:00
Luke Short 1c2fc72c20 [RCFILE] Added game profile for Jetboard Joust (#4152)
Related #1462
2026-07-29 21:03:46 +02:00
Luke Short b7ed2c57f5 [BUNDLE] Generate checksums (#4151)
for both files and symlinks. This will eventually be used to see if
an update of the bundle is required or not.

Related #3564
2026-07-29 17:48:30 +02:00
Zhijin Zeng 23f8db631d [RV64_DYNAREC] Support HSUBPS and MOVDQ2Q (#4141) 2026-07-29 10:13:00 +02:00
Yang Liu f22f5adb55 [RV64_DYNAREC] Fixed MIN/MAX opcodes (#4148) 2026-07-29 09:44:20 +02:00
Yang Liu f02526fdbb [RV64_DYNAREC] Refactored (safe) flags emulation (#4147)
* [RV64_DYNAREC] Refactored (safe) flags emulation

* more
2026-07-29 09:42:37 +02:00
Zhijin Zeng 675814f912 [RV64_DYNAREC] Support VMOVLPS/VMOVHPS Ex,Gx instruction (#4140) 2026-07-29 09:39:17 +02:00
Zhijin Zeng c44264eba0 [RV64_DYNAREC] Support MOVQ2DQ and ADOX instruction (#4146) 2026-07-29 09:36:38 +02:00
Yang Liu 35ea2eedcd [RV64_DYNAREC] Fixed VPADDQ opcode (#4138) 2026-07-28 09:01:47 +02:00
Yang Liu 25f49cbf25 [RV64_DYNAREC] Fixed PCMPSTR opcodes (#4137) 2026-07-28 09:01:06 +02:00
Luke Short 2dd1600cdd [SYSCALL] Add more syscalls for Magisk (#4136)
95, 115, and 269.

Resolves #1497
2026-07-28 00:24:26 +02:00
Luke Short 327b0870f0 [SYSCALL] Add syscall 40 (#4135)
Resolves #3535
2026-07-28 00:23:54 +02:00
Yang Liu 7097ead476 [RV64_DYNAREC] Added 0F C7 /1 CMPXCHG8B opcode (#4134) 2026-07-27 19:47:07 +02:00
Yang Liu 887d5ca523 [RV64_DYNAREC] Fixed VPSUBQ opcode (#4133) 2026-07-27 19:05:37 +02:00
Yang Liu 54c35ef172 [RV64_DYNAREC] Fixed HADDPD opcode (#4132) 2026-07-27 18:52:48 +02:00
ptitSeb a78eec4ebf [RV64_DYNAREC] Fixed F0 C7 /0 opcode 2026-07-27 18:22:32 +02:00
Yang Liu ed140eade7 [RV64_DYNAREC] Fixed RORX opcode (#4131) 2026-07-27 18:19:18 +02:00
Yang Liu 7c6c963168 [RV64_DYNAREC] Fixed conditional move macros again (#4130) 2026-07-27 18:15:05 +02:00
Yang Liu e058be73ca [RV64_DYNAREC] Fixed VSQRTPD opcode (#4129) 2026-07-27 17:28:11 +02:00
Zhijin Zeng d9a136d31c [RV64_DYNAREC] Change some BNEZ+ORI to SET_FLAGS_EQZ (#4126) 2026-07-27 16:24:19 +02:00
Zhijin Zeng 5910a52a60 [RV64_DYNAREC] Support POPCNT/TZCNT/LZCNT 16 bit operand (#4125) 2026-07-27 21:43:51 +08:00
Yang Liu e67bd4b6f6 [RV64_DYNAREC] Fixed conditional move macros (#4124) 2026-07-27 13:10:19 +02:00
Yang Liu 9270fc3727 [RV64_DYNAREC] Fixed CRC opcodes (#4123) 2026-07-27 13:05:40 +02:00
Yang Liu 5101489d21 [RV64_DYNAREC] Refined rotate opcodes (#4122) 2026-07-27 10:42:26 +02:00
Yang Liu 41c3a0caa5 [RV64_DYNAREC] Restored vector width before XMM cache accesses (#4121) 2026-07-27 10:41:16 +02:00
ptitSeb 382065544d [RCFILE] Added a new game profile 2026-07-27 09:49:48 +02:00
Zhijin Zeng e2a2c801f2 [RV64_DYNAREC] Fix RORX if cpu don't support zbb (#4120) 2026-07-27 08:51:40 +02:00
ptitSeb 9e2fa9e360 [RCFILE] Added 1 more game profile 2026-07-26 15:35:21 +02:00
Yang Liu 588f1d9c93 [LA64_DYNAREC] Optimized jump safe macros (#4114) 2026-07-25 10:59:17 +02:00
Zhijin Zeng 347f3b1a13 [RV64_DYNAREC] Support bmi2 PEXT/SARX/RORX instruction (#4116) 2026-07-25 10:58:10 +02:00
Yang Liu c32ebc76fd [LA64_DYNAREC] Extended nativeflags SF fusion (#4115) 2026-07-25 09:06:58 +02:00
Yang Liu a2ae0500d8 [LA64_DYNAREC] Extended nativeflags to 1+N pattern (#4113) 2026-07-24 21:10:46 +02:00
Yang Liu 478972a34b [TLS] Kept x86 TCB self consistent with pthread_self() (#4112) 2026-07-24 20:51:14 +02:00
Zhijin Zeng f4ee1c1b53 [RV64_DYNAREC] Support bmi2 PDEP/MULX/SHRX instruction (#4110)
Implement by referencing the LA64 implementation.
2026-07-25 02:05:17 +08:00
Zhijin Zeng 93fe536549 [RV64_DYNAREC] Add Zicbom and Zicbop disassemble case (#4111) 2026-07-24 14:24:01 +02:00
yzewei 3698562aae [INTERPRETER] Improve x87 long double classification (#4107)
Keep the existing raw 80-bit x87 shadow aligned through FLD ST(i), FXCH,
FST/FSTP, FCMOV, FABS, and FCHS, and use it for FCOMI/FUCOMI/FUCOMIP when
the shadow is still valid.

This avoids falling back to the double representation for long double
classification, where large finite values such as LDBL_MAX may collapse to
inf and break isinf/isnan/isfinite-style checks

Signed-off-by: Zewei Yang <[email protected]>
2026-07-24 11:09:40 +02:00
Yang Liu d8df33a9cb [LA64_DYNAREC] Added simplewrapper float parameter support (#4109) 2026-07-24 09:24:57 +02:00
Zhijin Zeng 0de71be3e5 [RV64_DYNAREC] Use risc-v zicond to eliminate some branchs for setting flag (#4099)
* [RV64_DYNAREC] Support risc-v zicond extension

* [RV64_DYNAREC] Use risc-v zicond to eliminate some branchs
2026-07-24 09:10:25 +02:00
Yang Liu fd895bd142 [LA64_DYNAREC] Cached MXCSR rounding mode in FCSR3 (#4108) 2026-07-24 09:07:16 +02:00
Yang Liu edc68c032a [LA64_DYNAREC] Fixed ARPL opcode (regression of fd6bdfe6) (#4106) 2026-07-24 08:14:53 +02:00
Yang Liu 40a841df8f Small tweaks to the profile (#4105)
* [LA64_DYNAREC] Small tweaks to the profile

* more
2026-07-23 20:03:04 +02:00
Yang Liu df697c683c [LA64_DYNAREC] Added F0 F6 /2 LOCK NOT opcode (#4104) 2026-07-23 19:31:07 +02:00
Yang Liuandphorcys e3cb94f490 [LA64_DYNAREC] Optimized SHA1 opcodes (#4102)
Co-authored-by: phorcys <[email protected]>
2026-07-23 19:05:13 +02:00
Yang Liu 88f6cb97c7 [LA64_DYNAREC] Fixed scratch register shortage in certain VAES opcodes (#4103) 2026-07-23 18:53:16 +02:00
Zhijin Zeng bdd226b9d3 [RV64_DYNAREC] Remove redundant SMREAD (#4100)
GETEX includes SMREAD, and GETGX has no need for SMREAD.
2026-07-24 00:25:16 +08:00
Yang Liu 537d92bf57 [LA64_DYNAREC] Fixed a typo in VPXOR opcode (#4101) 2026-07-23 17:10:39 +02:00
Zhijin Zeng c08644a729 [RV64_DYNAREC] Support some bmi and bmi2 instructions for risc-v (#4098)
Implement by referencing the LA64 implementation.

BMI: ANDN, BLSI, BLSR, BLSMSK, BEXTR
BMI2: BZHI
2026-07-23 09:09:35 +02:00
Yang Liu 7b07789173 [LA64_DYNAREC] Optimized SHA1 opcodes (#4097) 2026-07-23 08:15:19 +02:00
Yang Liu 585e0a6308 [LA64_DYNAREC] Fixed inlined updateflags (#4096) 2026-07-23 08:11:13 +02:00
Yang Liu fd6bdfe69e [LA64_DYNAREC] Added ARPL opcode (#4095) 2026-07-23 08:10:38 +02:00
Yang Liu 654e36622f [DYNAREC] Fixed 16-bit XADD register clobbering (#4094) 2026-07-23 08:08:29 +02:00
Yang Liu 38df9afcf2 Optimized sha1rnds4 helper function utilizing loop-unrolling (#4093)
10% performance gain in Geekbench6 geekbench_x86_64 Single-Core File Compression.
2026-07-23 08:07:07 +02:00
ptitSeb b442786811 [RCFILE] Updated 2 profiles (for UPlay games) 2026-07-22 17:28:08 +02:00
Yang Liu ff943b5d5a Removed useless files (#4092) 2026-07-22 15:16:06 +02:00
Yang Liu ef8b463a25 [DYNAREC] Ported the alternate fix from Arm to others (#4091) 2026-07-22 11:15:58 +02:00
ptitSeb 02a9f25707 [CI] This should fix non-Box32 builds 2026-07-22 11:01:59 +02:00
ptitSeb 9a4b78d35a [BOX32][WRAPPER] Adjusted a function signature for libasound (for #4063) 2026-07-22 10:42:57 +02:00
ptitSeb 7d8ae5f7e2 Added basic support for 32bits syscall 123 2026-07-22 10:42:05 +02:00
ptitSeb f7208a7241 [RCFILE] Adjusted one game profile 2026-07-22 10:41:16 +02:00
Dmitry BrazhenkoandClaude Opus 4.8 da25b06705 box64 fixes for running Electron/Chromium apps (malloc_hack + 48-bit detection) (#4087)
* dynarec/arm64: apply getAlternate on the 0xE8 CALL opcode

The arm64 CALL handler jumped to the target without getAlternate, unlike the
JMP handler and the rv64/la64/ppc64le CALL handlers. So a direct or indirect
call to a redirected symbol (e.g. an app malloc/free under BOX64_MALLOC_HACK,
including one captured as a function pointer and called back) was not
rerouted. Chromium/PartitionAlloc hit this and crashed in free(); with this,
an unmodified amd64 Signal Desktop boots under box64 on aarch64.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* custommem: probe for 48-bit address space when the maps scan finds none

have48bits was only set if /proc/self/maps already had a mapping above
0x7fff00000000; fresh/container processes have none, so box64 assumed 39-bit.
Probe with mmap instead; on a real 39-bit system it stays 0 (unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

* box64rc: add signal-desktop profile

Auto-apply the tuning an Electron/Chromium app needs: malloc_hack, strong
memory ordering for its lock-free threads, no-sandbox, in-process GPU.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-22 10:30:58 +02:00
Zhijin Zeng 66e9f120bb [RV64_DYNAREC] Reduce instruction count for GETSEB/GETSGW by risc-v zbb (#4090) 2026-07-22 15:31:38 +08:00
Yang Liu 79b72348c2 [LA64_DYNAREC] Fixed more up32 tracking bugs (#4088) 2026-07-22 09:09:11 +02:00
Yang Liu 6994c012b8 [DYNAREC] Fixed CALL FAR/RET with callret=2 (#4083) 2026-07-21 20:01:41 +02:00
ptitSeb 26ab7ad6b0 [BOX32] Better trace for missing syscall 2026-07-21 19:08:47 +02:00
ptitSeb 67962cd10d Fixed skip/max cpu guessing for other process 2026-07-21 16:02:24 +02:00
Yang Liu 603730dd3c [LA64_DYNAREC] Fixed more up32 issues (#4082) 2026-07-21 12:54:43 +02:00
Yang Liu 7c3c5dd0d9 [LA64_DYNAREC] Fixed emit_shr32 with up32 tracking (#4081)
Consider:
```
mov edi, 0xFBA6027B
mov ecx, 0xF9
shr edi, cl
```

`edi` is `0xFFFFFFFFFBA6027B` after the mov because of up32 tracking marked it dead, we must not use 64 bit `SRL_D` at `shr`.
2026-07-21 12:53:27 +02:00
Yang Liu 121cf70278 [LA64_DYNAREC] Optimized non-lbt CF flag emulation (#4080)
Ported from #4079.
2026-07-21 12:01:37 +02:00
Zhijin Zeng c8a5246766 [RV64_DYNAREC] Optimize instruction count for 64-bit addition carry flag calculation (#4079)
Because CF flag reside in bit 0 of risc-v xFlags (x23), so we also can remove
BEQZ inst for if block.
2026-07-21 12:01:25 +02:00
yzewei 9c0214dd34 [WRAPPER] Add libmvec wrappers for missing _ZGVb and _ZGVc exp/log/pow variants (#4078)
The AVX wrappers use scalar lane fallback over xmm/ymm halves, matching the existing libmvec wrapper style.

Signed-off-by: Zewei Yang <[email protected]>
2026-07-21 10:12:57 +02:00
ptitSeb d9df72e602 Try to use SKIPCPU for get/set affinity done on another (box64) process too 2026-07-21 10:06:20 +02:00
ptitSeb 8b1fbc150d [ELFLOADER] A bit more work on staticaly linked binary (for #4071) 2026-07-20 18:18:23 +02:00
Mikura Kyouka 0cec433211 [DYNAREC] Added BOX64_DYNAREC_DISASM for Zydis disassembly in dynarec dump (#4049) 2026-07-20 17:32:01 +02:00
Yang Liu 31cb8b5d61 [RV64_DYNAREC] Fixed VCMPSS opcode (#4076) 2026-07-20 17:07:26 +02:00
Yang Liu f681291c1d [RV64_DYNAREC] Refined ROR/ROL opcodes flags emulation (#4075) 2026-07-20 17:01:28 +02:00
Yang Liu 099982d356 [RV64_DYNAREC] Restored SEW after conditional cache transforms (#4074) 2026-07-20 16:59:57 +02:00
Zhijin Zeng 2e7a8867cb [RV64_DYNAREC] Support prefetch family inst by Zicbop (#4073)
* [RV64_DYNAREC] Support risc-v Zicbop

* [RV64_DYNAREC] Support prefetch family inst by Zicbop

1. Map x86-64 prefetch/prefetcht0/prefetcht1/prefetcht2 to risc-v prefetch.r
2. Map x86-64 prefetchw/prefetchwt1 to risc-v prefetch.w
3. Keep x86-64 PREFETCHNTA unchanged
2026-07-20 20:18:23 +08:00
Yang Liu d22f9e6169 [LA64_DYNAREC] Added comis fusion (#4072)
from

```
0x402dd7: 0F 2F F1 comiss xmm6, xmm1
        03a3540f        ori             x2, xZR, 0x8d5(2261)
        0016bfde        andn            xFlags, xFlags, x2
        0c1404c0        fcmp.cun.s      $fcc0, fa6, fa1
        48000c00        bceqz           $fcc0, 0xc(12)
        038117de        ori             xFlags, xFlags, 0x45(69)
        50002000        b               0x20(32)
        0c1104c1        fcmp.clt.s      $fcc1, fa6, fa1
        48000c20        bceqz           $fcc1, 0xc(12)
        038007de        ori             xFlags, xFlags, 0x1(1)
        50001000        b               0x10(16)
        0c1204c2        fcmp.ceq.s      $fcc2, fa6, fa1
        48000840        bceqz           $fcc2, 0x8(8)
        038103de        ori             xFlags, xFlags, 0x40(64)
        005cfc3e        x86mtflag       xFlags, 0x3f(63)
0x402dda: 76 03 jbe 0x0000000000402DDF
        00368c0e        setx86j         x1, 0x3(3)
        44000dc0        bnez            x1, 0xc(12)
        03400000        andi            xZR, xZR, 0x0(0)
```

to

```
0x402dd7: 0F 2F F1 comiss xmm6, xmm1
        0c1704c7        fcmp.cule.s     $fcc7, fa6, fa1
0x402dda: 76 03 jbe 0x0000000000402DDF
        48000de0        bcnez           $fcc7, 0xc(12)
        03400000        andi            xZR, xZR, 0x0(0)
```
2026-07-20 13:44:10 +02:00
Yang Liu f79babc541 [DYNACACHE] Restricted last_mmap to executable images (#4068)
* [DYNACACHE] Restricted last_mmap to executable images

* fix
2026-07-20 10:55:37 +02:00
Zhijin Zeng 5640228909 [RV64_DYNAREC] Support CLWB/CLFLUSH/CLFLUSHOPT by risc-v Zibocm extension (#4070) 2026-07-20 16:33:02 +08:00
yzewei 3e2ab21e70 [INTERP] Set invalid flag for FP-to-int conversions (#4069)
Set the x87 status word or MXCSR invalid flag when floating-point to
integer conversions produce the x86 indefinite integer result.

These paths already returned the expected indefinite integer for NaN,
Inf, and out-of-range inputs, but did not update the observable floating
point exception state. Using fetestexcept(FE_INVALID) could miss invalid
conversion conditions.

Signed-off-by: Zewei Yang <[email protected]>
2026-07-20 10:28:46 +02:00
Yang Liu f19936e53b [LA64_DYNAREC] Disabled rsp merging when cosim is enabled (#4066) 2026-07-20 07:44:53 +02:00
ptitSeb d8cb528a2d [BOX32][WRAPPER] Added 2 new wrapped functions (for #4063) 2026-07-19 09:52:30 +02:00
Ryan 2544543b3a [CORE] Don't consume guest t/test arguments (#4062)
Signed-off-by: Sped0n <[email protected]>
2026-07-18 22:00:19 +02:00
Yang Liu ceb5c13822 [LA64_DYNAREC] Added more fast paths and micro optimizations (#4061) 2026-07-18 18:45:04 +02:00
Yang Liu 8ace9188e8 [LA64_DYNAREC] Added a fast path for 66 C1/D1 /5 SHR opcode (#4060) 2026-07-18 11:31:20 +02:00
Yang Liu 5a20e40e29 [LA64_DYNAREC] Added a fast path for D0 /5 opcode (#4059)
Also removed some dead immediate loading.
2026-07-18 11:16:10 +02:00
Yang Liu 0dc712cec0 [LA64_DYNAREC] Added a fast path for 66 33 XOR opcode (#4058)
Also optimized geted.
2026-07-18 10:31:26 +02:00
Yang Liu 0d8356702b [LA64_DYNAREC] Removed some useless code in rsp merging (#4057) 2026-07-18 10:08:15 +02:00
Yang Liu cf633e161a [LA64_DYNAREC] Removed merge_sync from up32 tracking (#4056) 2026-07-18 09:11:40 +02:00
Yang Liu 3ac45c1ac6 [LA64_DYNAREC] Added push/pop rsp merge optimization (#4054) 2026-07-17 18:13:38 +02:00
Luke Short 86f3d6d316 [BUNDLE] Add 'libpolkit-gobject-1.so.0' (#4043)
Related #449
2026-07-17 14:34:33 +02:00
Shirow 290dc73a3a [CUSTOMMEM] only track the newly added heap when brk changed (#4055)
* [CUSTOMMEM] only track the newly added heap when brk changed

find31/47bitBlockNearHint re-tracked the whole heap from pbrk as RW every
time the program break moved. setProtection only writes the tracking, not
the kernel, so any page the guest had made executable inside the heap (JIT
or hook trampolines) silently lost PROT_EXEC while the kernel still mapped
it rwx, and CheckExec then raised 0xecec forever on it. Track only the
range that was actually added. Fixes #4052

* trim the comment down
2026-07-17 14:12:01 +02:00
Zhijin Zeng c5215cb2f5 [ENV] Disable dynacache when dynarec_trace or dynarec_dump are enabled (#4051) 2026-07-17 08:58:19 +02:00
Leslie Zhai a107c2a52b [LA64] SIGBUS special cases for LA64 ABI 1.0 (#4050) 2026-07-16 13:08:16 +02:00
Yang Liu 373e1306ad [LA64_DYNAREC] Added a fast path for 66 25 AND opcode (#4048) 2026-07-16 09:09:36 +02:00
Yang Liu 0910384e6f [LA64_DYNAREC] Added 66 F5 /5 IMUL opcode (#4047) 2026-07-15 17:53:32 +02:00
Yang Liu 894a183180 [DYNAREC][ENV] Disabled SEP by default (#4045)
* [DYNAREC][ENV] Disabled SEP by default

Now that we have callret enabled by default, I noticed SEP causes the branch misprediction by an order of magnitude in coremark, while the memory-saving effect is almost imperceptible.

```
ksco@steel [ coremark@main ] $ BOX64_LOG=0 BOX64_NOBANNER=1 BOX64_DYNACACHE=0 BOX64_DYNAREC_SEP=0 perf stat -e task-clock,cycles,instructions,branches,branch-misses -- taskset -c 2 box64 ./coremark.exe_x64 0 0 0x66 200000 7 1 >/dev/null

 Performance counter stats for 'taskset -c 2 box64 ./coremark.exe_x64 0 0 0x66 200000 7 1':

         16,339.65 msec task-clock:u
    35,828,022,082      cycles:u
   118,528,644,489      instructions:u
    12,994,274,457      branches:u
        36,068,961      branch-misses:u

      16.348269274 seconds time elapsed

      16.331188000 seconds user
       0.009995000 seconds sys

ksco@steel [ coremark@main ] $ BOX64_LOG=0 BOX64_NOBANNER=1 BOX64_DYNACACHE=0 BOX64_DYNAREC_SEP=1 perf stat -e task-clock,cycles,instructions,branches,branch-misses -- taskset -c 2 box64 ./coremark.exe_x64 0 0 0x66 200000 7 1 >/dev/null

 Performance counter stats for 'taskset -c 2 box64 ./coremark.exe_x64 0 0 0x66 200000 7 1':

         18,571.57 msec task-clock:u
    40,721,222,650      cycles:u
   118,523,943,716      instructions:u
    12,993,208,645      branches:u
       383,363,320      branch-misses:u

      18.581470637 seconds time elapsed

      18.564061000 seconds user
       0.008996000 seconds sys

ksco@steel [ coremark@main ] $ perf stat -e task-clock,cycles,instructions,branches,branch-misses -- taskset -c 2 ./coremark.exe 0 0 0x66 200000 7 1 >/dev/null

 Performance counter stats for 'taskset -c 2 ./coremark.exe 0 0 0x66 200000 7 1':

          9,757.79 msec task-clock:u
    21,407,080,976      cycles:u
    62,785,977,365      instructions:u
    11,852,476,157      branches:u
        18,851,352      branch-misses:u

       9.762550998 seconds time elapsed

       9.757495000 seconds user
       0.000999000 seconds sys

```

* Update docs

* Enable SEP on SAVE_MEM build
2026-07-15 13:09:32 +02:00
Yang Liu e016c5a6cd [LA64_DYNAREC] Added basic arch state gathering support and enabled up32 (#4044) 2026-07-15 08:48:18 +02:00
Mikura Kyouka 900d327aa1 [DOCS] Add Chinese version of WINE.md (#4042) 2026-07-14 09:14:11 +02:00
Yang Liu eb3cd0c1bd [RV64_DYNAREC] Added !fastnan path for more opcodes (#4041) 2026-07-13 18:36:40 +02:00
Yang Liu 4280f4b259 [RV64_DYNAREC] Fixed VCVTPS2PD opcode overwritten (#4040) 2026-07-13 18:34:56 +02:00
Yang Liu 07b76e6f99 [RV64_DYNAREC] Added !fastnan path to ADDSUBPS opcode (#4039) 2026-07-13 17:49:14 +02:00
Yang Liu 5134a414a8 [RV64_DYNAREC] Fixed MOVNTQ opcode (#4038) 2026-07-13 17:45:06 +02:00
Yang Liu 919e426d03 [RV64_DYNAREC] Restored vector SEW after MMX cache reload (#4037) 2026-07-13 17:44:43 +02:00
Yang Liu 4bf60dec65 [RV64_DYNAREC] Ported 0ccd7513 to SS variants (#4036) 2026-07-13 15:28:54 +02:00
ptitSeb 3e9dc054af [WRAPPER][BOX32] Added support for space filling in printf format (for #4020) 2026-07-13 14:50:24 +02:00
Zhijin Zeng a5a320ae3c [RV64_DYNAREC] Change sNaN to qNan for addsd/subsd/mulsd/divsd (#4035)
The x86-64 architecture requires that if the result of addsd/subsd/mulsd/divsd
is an sNaN, it shall be converted to a qNaN.
2026-07-13 14:37:32 +02:00
Yang Liu 1dd0323f8f [LA64_DYNAREC] Fixed gpr upper tracking non-lbt path (#4034) 2026-07-13 10:00:25 +02:00
Yang Liu 4b482fb0e1 [LA64_DYNAREC] Fixed gpr upper tracking with nativeflags (#4033) 2026-07-13 09:59:24 +02:00
Zhijin Zeng 0ccd7513b4 [DYNAREC] Fix the issue where source register values get overwritten. (#4032)
In the implementations of `addsd/subsd/mulsd/divsd` when BOX64_DYNAREC_FASTNAN
is enabled, the source register values are being overwritten. This violates the
x86-64 instruction specification, which prohibits modification of source
registers. The resulting loss of source register data triggers subsequent
runtime errors.

I referenced the LA64 and ARM64 implementations and used temporary floating-point
registers to store intermediate values.

SNAN-to-QNAN conversion handling may also need to be added here. I will address
this in a separate follow-up patch.
2026-07-13 09:55:38 +02:00
ptitSeb a96396985e [ARM64_DYNAREC] Fixed some rare occurence where some native flags would be lost after a shift with 0 count 2026-07-12 12:59:34 +02:00
Yang Liu 8ee3d8f2c8 [ARM64_DYNAREC] Fixed more ROL/ROR opcodes OF emulation (#4030) 2026-07-11 13:26:27 +02:00
Yang Liu bc61374812 [ARM64_DYNAREC] Fixed some AES opcodes fallback path (#4029) 2026-07-11 13:09:16 +02:00
Yang Liu 862fef5e0f [INTERP] Fixed SSE4a opcodes EXTRQ and INSERTQ (#4028)
> A value of zero in the field length is defined as a length of 64
2026-07-11 11:05:48 +02:00
ptitSeb 65898277e9 More small changes to fprem/fprm1 handling 2026-07-11 11:01:27 +02:00
ptitSeb bd0131e973 [ARM64_DYNAREC] Improved fprem/fprem1 handling 2026-07-11 10:47:58 +02:00
Yang Liu f7aa4942de [ARM64_DYNAREC] Fixed ROL/ROR opcodes OF emulation (#4027) 2026-07-11 09:25:44 +02:00
Zhijin Zeng 1953db9145 Support libpipewire bundle (#4019)
* [BUNDLE] Support move the library which located in sub-directories

For example, move the library
```
usr/lib/x86_64-linux-gnu/spa-0.2/v4l2/libspa-v4l2.so
```
to
```
/usr/lib/box64-x86_64-linux-gnu/spa-0.2/v4l2/libspa-v4l2.so
```

* [BUNDLE] Add libpipewire-0.3 for box64-bundle-x86-libs.csv

Add 3 libraries:
1. libpipewire-0.3-0_0.3.65-2~bpo11+1
2. libpipewire-0.3-modules_0.3.65-2~bpo11+1
3. libspa-0.2-modules_0.3.65-2~bpo11+1
2026-07-10 22:30:53 +02:00
Yang Liu 2d5d7d1a41 [LA64_DYNAREC] Fixed some issues in up32 tracking (#4026)
* [LA64_DYNAREC] Fixed some issues in up32 tracking

* Fix more
2026-07-10 13:18:19 +02:00
Yang Liu d53d99ebcf [LA64_DYNAREC] Preserves liveness across internal unconditional jumps (#4025) 2026-07-10 11:28:56 +02:00
Yang Liu 32f966210b [DYNAREC] Added a compat mode to dynarec dump (#4024) 2026-07-10 11:11:04 +02:00
Yang Liu 24d550147f [LA64_DYNAREC] Added upper 32bits zero tracking (#4016)
* [LA64_DYNAREC] Added upper 32bits zero tracking

* Disable up32 by default for now

* Refined a few places

* Review
2026-07-10 08:19:51 +02:00
Yang Liu 384972df38 [CI] Fix CI (#4021) 2026-07-09 12:13:50 +02:00
Zhijin Zeng 7fb6dc4353 [CORE] Change mmap flag judgment in getMmapped (#4003)
Change getMmapped to strictly check MEM_MMAP flag instead of MEM_ALLOCATED bitmask.
2026-07-09 10:57:06 +02:00
ptitSeb 5a1114c76e [INTERP] Fixed a typo in F0 66 0F C1 opcode 2026-07-09 10:03:51 +02:00
Yang Liu 86a850cfcd [DYNAREC] Made callret=2 the default (#4017) 2026-07-09 09:11:03 +02:00
Yang Liu f5c0d135d0 [RCFILE] Loosen Dave The Diver profile (#4018) 2026-07-09 08:38:58 +02:00
Zhijin Zeng 17b0ca1d43 [CMAKE] Remove the trailing '/' from INSTALL_PATH (#4015)
Otherwise an extra slash will be generated when installing directories.
2026-07-08 13:54:29 +02:00
ptitSeb 462b3c0d78 [RCFILE] Add more game profiles 2026-07-07 14:56:19 +02:00
ptitSeb 2a5480652a [RCFILE] Added 1 more game profile 2026-07-06 10:36:37 +02:00
ptitSeb ecc6b95a75 [BOX32] Remove libpulse dependancy from libpulse-simple wrapping as it's not supported in 32bits 2026-07-06 10:33:34 +02:00
ptitSeb c08554e3f3 Try to fix the build from previous commit 2026-07-05 16:49:46 +02:00
ptitSeb d6e43153db Introducing BOX64_SKIPCPU to skip N first cores, (to avoid little cores in big.LITTLE SoC) 2026-07-05 16:32:47 +02:00
ptitSeb d701932fe6 [RCFILE] Fine-tuned some more porfiles 2026-07-05 14:16:20 +02:00
ptitSeb b47131c1e4 [RCFILE] Added 1 more game profile 2026-07-04 18:03:01 +02:00
ptitSeb 70dc4e4897 [DYNAREC] Avoid use on siglongjmp to resume a signal when pc is from a dynablock 2026-07-04 18:02:34 +02:00
ptitSeb 5a6419d322 [DYNAREC] Fully made jumptable 48bits address space only 2026-07-04 18:01:53 +02:00
ptitSeb 0c3d2391f0 [DYNAREC] Fixed a potential regression of f1f572a with large page size 2026-07-03 09:29:14 +02:00
Yang Liu baacff1811 [INTERP] Fixed BTS/BTC unaligned path (#4012) 2026-07-03 08:54:50 +02:00
Yang Liu 39e75158ee [LA64_DYNAREC] Fixed some bad typos in non-lam_bh path (#4010) 2026-07-03 08:47:25 +02:00
Yang Liu b1d094f9bd [INTERP] Added unaligned handling for many opcodes (#4006)
* [INTERP] Added unaligned handling for 0F 81/83 opcodes

* more
2026-07-02 12:07:36 +02:00
Yang Liu 89a2e7d66a [RCFILE] Added a profile for Death Stranding 2 (#4005) 2026-07-02 08:05:36 +02:00
ptitSeb 90dffce78a [INTERP] Improve handling of fprem x87 opcode ([DYNAREC] too) 2026-07-01 15:29:55 +02:00
ptitSeb 55922238d3 [TRACE] Improved trace for x87 register that have valid 80bits value 2026-07-01 13:30:20 +02:00
ptitSeb 38a4a2c751 [DYNAREC] Mark a hopage before changing protection 2026-07-01 10:56:21 +02:00
Yang Liu e6de218979 [RCFILE] Fixed DOOM 2016 profile (#4002) 2026-07-01 10:37:57 +02:00
Yang Liu d9fca2f365 [WRAPPER] Wrapped more symbols for libGL (#4001) 2026-07-01 09:44:01 +02:00
Zhijin Zeng 2f850d4e88 [CORE] Add MallocHookRun to call startMallocHook before RunElfInit (#3999)
The `startMallocHook` function is only invoked inside `RunElfInit`, and
`RunElfInit` is only called for the main ELF binary within `__libc_start_main`.

In the `RunElfInit` function, `startMallocHook` is currently invoked only after
all initialization routines of dynamic libraries have been executed. However,
if the malloc hook is defined within a dependent library and that library’s
initialization routine invokes the malloc hook interface, activation of the
malloc hook will be delayed, leading to unexpected runtime exceptions.

Therefore, I add a call to `MallocHookRun` so that the malloc hook can be
available before the execution of library init functions.

Before:
```
__libc_start_main
    |
    ---> RunElfInit
             |
             ----> libA.so Init
             |          |
             |          ---> _Znam
             |                 |
             |                 ---> Native actual_malloc
             ---> startMallocHook
```

After:
```
__libc_start_main
    |
    ---> MallocHookRun
    |        |
    |        ---> startMallocHook
    |
    ---> RunElfInit
             |
             ----> libA.so Init
                       |
                       ---> _Znam
                              |
                              ---> X86-64 real_malloc
```
2026-07-01 09:04:49 +02:00
Zhijin Zeng dd180478f1 [TRACE] Support configuring trace address list through BOX64_TRACE (#3998)
Format: BOX64_TRACE=0x1000:0x2000:0x3000

Just trace the address 0x1000,0x2000 and 0x3000
2026-06-30 17:47:28 +02:00
ptitSeb fc8a8d0b83 [WRAPPER] Simplified 148a1a2 by add wrpper as part of the hash key for bridge search 2026-06-30 13:32:34 +02:00
Yang Liu 83d9c30aa4 [WRAPPER] Wrapped 1 more symbol for wayland-client (#3996) 2026-06-29 18:54:28 +02:00
Zhijin Zeng ffa7c1a77b [WRAPPER] Fix out-of-bounds memory corruption caused by strncpy in my_readlink (#3995)
Two variables named `sz` exist in the `my_readlink` function, causing the
parameter `sz` to be overwritten and resulting in out-of-bounds memory access.
2026-06-29 18:53:59 +02:00
Yang Liu 148a1a21e8 [WRAPPER][BOX32] Fixed unexpected bridge reuse
ftruncate and ftruncate64 point to the same native libc code on 64-bit systems, but on 32-bit x86 they are different functions. We reused bridges by native address, so a bridge made for ftruncate64 could also be used for ftruncate accidently, which breaks the latest legacy Linux Steam.

Added a new bridge key to include the wrapper too, so aliases with different guest APIs get separate bridges.
2026-06-29 18:02:35 +08:00
ptitSeb d7b78a092f [WRAPPING][BOX32] Some improvments for 32bits wine (might help #3813) 2026-06-28 13:27:53 +02:00
Ming Hengqiang 7da44e5d7e [RV64_DYNAREC] Fixed GETEW delta parameter for ROL/ROR/RCL/RCR (#3992) 2026-06-26 17:48:04 +02:00
ptitSeb 3bf34a77c7 [DYNAREC] Try to limit number of times blocks are invalidated, especialy those on NEVERCLEAN pages 2026-06-25 18:21:22 +02:00
ptitSeb 2cc903bbe0 [DYNAREC] Small refactor on Alt Address Dynablock handling 2026-06-25 18:20:13 +02:00
ptitSeb f1f572a087 [DYNAREC] Only call getProtection once in FillBlock64 2026-06-25 18:18:28 +02:00
ptitSeb 8e96a34da3 [DYNAREC] Validate alt block so it can be used 2026-06-25 18:16:25 +02:00
ptitSeb 38d64baba2 [DYNAREC] Resume regular signal with Dynarec 2026-06-25 18:15:14 +02:00
ptitSeb 896b965325 [LINUX] Small change in GetSegmentBase 2026-06-25 16:58:02 +02:00
ptitSeb 17865c3a9e [WRAPPER] Simplified (and speed up) _dl_find_object function 2026-06-25 13:35:05 +02:00
Yang Liu 8e661d2907 [DYNAREC] Always initialize jump table for DynaRec build (#3990)
If DynaRec is disabled by env var but enabled in rcfile, the initialize process will be:
```
LoadEnvVariables()
NewBox64Context() -> dynarec=0, jump table not initialize
ApplyEnvFileEntry()
AllocLoadElfMemory() -> crash
```

I guess it's okay to always initilize the table.
2026-06-25 10:02:30 +02:00
Yang Liu 46459ebee1 [ENV] Fixed env variables printing (#3989) 2026-06-25 09:51:25 +02:00
Yang Liu 75464e9d94 [LA64_DYNAREC] Added PCMPESTRM/PCMPISTRM opcodes (#3988) 2026-06-25 09:50:55 +02:00
Yang Liu 49e248923e [KDE_PLUGIN] Added KDE 5 support (#3987) 2026-06-25 08:08:57 +02:00
ptitSeb 6656708831 [DYNACACHE] Added Compression % for dynacache-list 2026-06-24 15:44:11 +02:00
ptitSeb 153b6613cc [RCFILE] Fine-tuned 2 game profiles 2026-06-24 13:29:52 +02:00
ptitSeb 2d74207bb7 [KDE_PLUGIN] Make KDE Plugin OFF by default 2026-06-24 13:29:20 +02:00
baibaidashixiong 61131566bb [WRAPPER] Ensure symbols returned from different lookup paths resolve to the same address (#3986) 2026-06-24 13:03:54 +02:00
Yang Liu 915a28f84c [CONFIG] Added KDE propertiesplugin integration (#3985) 2026-06-24 13:03:42 +02:00
Yang Liu 75c0edc100 [CONFIG] Added often-used group and BOX64_PROFILE support (#3984)
* [CONFIG] Added often-used group

* [CONFIG] Added BOX64_PROFILE support
2026-06-24 09:32:12 +02:00
Yang Liu 0053799955 [WRAPPER] Added more listener wrappers for wayland-client (#3983)
Terraria Linux on Wayland works.
2026-06-24 08:08:46 +02:00
ptitSeb 95b02080ec [DYNAREC] Made NOHOTPAGE=1 and DIRTY=2 combonaison to actualy do something 2026-06-23 20:22:30 +02:00
Yang Liu 12ba6c1c3c [WRAPPER] Removed pipewire wrapping (#3982)
This library is non-trivial to wrap. For example:

```
// /usr/include/pipewire-0.3/pipewire/core.h
// ...
#define PW_API_CORE_IMPL static inline
// ...

PW_API_CORE_IMPL struct pw_registry *
pw_core_get_registry(struct pw_core *core, uint32_t version, size_t user_data_size)
{
	return spa_api_method_r(struct pw_registry*, NULL,
			pw_core, (struct spa_interface*)core, get_registry, 0,
			version, user_data_size);
}
// ...
```
2026-06-23 20:05:07 +02:00
Yang Liu a6f44ac2bd [CMAKE] Cleanup ctest (#3981)
* [CMAKE] Cleanup ctest

* fix
2026-06-23 19:06:34 +02:00
Yang Liu 758f352bf5 [WRAPPER] Added 2 more wayland listeners (#3980)
Needed by Wine-Wayland in GE-Proton10-34
2026-06-23 11:48:11 +02:00
Yang Liu 274c5a8f11 [WRAPPER] Wrapped liblz4 (#3979) 2026-06-22 20:53:50 +02:00
Yang Liu fdabd38e7b [WRAPPERHELPER] Fixed a typo in parse.c (#3978) 2026-06-22 20:52:58 +02:00
Yang Liu 59c6aa4932 [WRAPPER] Fixed g_option_group_add_entries (#3977) 2026-06-22 12:30:18 +02:00
ptitSeb 9ddbc50844 [ARM64_DYNAREC] More work on rol/ror 8/16 with constant UB 2026-06-22 12:28:51 +02:00
Yang Liu 093e6353d7 [LA64_DYNAREC] More work on ROL/ROR opcodes OF emulation (#3975)
* [LA64_DYNAREC] More work on ROL/ROR opcodes OF emulation

* review
2026-06-22 11:47:12 +02:00
Yang Liu 6597bef108 [INTERP] More work on ROL/ROR opcodes OF emulation (#3974)
* [INTERP] More work on ROL/ROR opcodes OF emulation

* review
2026-06-22 11:37:40 +02:00
ptitSeb 5fa5298977 Improved cpuid return for cputype=1 for l1/l2/l3 cache informations 2026-06-22 10:17:34 +02:00
Mikura Kyouka 15cced707b [DOCS] Corrected some typos in the usage documentation (#3973) 2026-06-21 10:13:38 +02:00
ptitSeb 50c8b90b09 [RCFILE] Added 1 game profile and adjusted some others 2026-06-20 17:12:00 +02:00
ptitSeb 53968e0d4e [RCFILE] Added 1 game profile 2026-06-20 14:54:30 +02:00
ptitSeb 03157ce442 [WINLATOR] Disabled DYNACACHE by default for this config 2026-06-20 08:01:28 +02:00
Yang Liu c018889389 [LA64_DYNAREC] Fixed deferred flags regression (#3970) 2026-06-19 17:52:51 +02:00
ptitSeb 3ac87fd225 [ARM64_DYNAREC] Adjusted UB for rol/ror 8/16bits with constant 2026-06-19 17:48:58 +02:00
Yang Liu 63c956d8ac [LA64_DYNAREC] Disable flags fusion for all the shift/rotate on CL opcodes (#3969) 2026-06-19 17:40:48 +02:00
Yang Liu 00ee467812 [LA64_DYNAREC] Preseved OF for 8/16-bit ROL/ROR opcodes (#3968) 2026-06-19 17:40:07 +02:00
Yang Liu 75a1456bc3 [INTERP] Preserved OF for 8-bit ROL/ROR opcodes (#3967) 2026-06-19 17:16:05 +02:00
Yang Liu 4b669fbe99 [INTERP] Fixed OF preserving for 16-bit ROL/ROR opcodes (#3966) 2026-06-19 16:39:01 +02:00
ptitSeb d39bf05f39 [ARM64_DYNAREC] Fixed some regressions introduced with c14f0eca84 2026-06-19 16:22:21 +02:00
Yang Liu df36391e74 [LA64_DYNAREC] Implemented AAM/AAD opcodes and fixed AAD16 flags (#3965) 2026-06-19 14:36:59 +02:00
Yang Liu 0873ab1824 [DYNAREC] Fixed zero-extension for 32-bit RCL/RCR Ed, CL (#3964) 2026-06-19 14:36:28 +02:00
ptitSeb 514d5cd770 [TRACE] Avoid issue when tracing poll with NULL argument 2026-06-19 13:18:35 +02:00
ptitSeb 87d06d3afd [SYSCALL] Added a couple of syscalls 2026-06-19 13:18:03 +02:00
ptitSeb 956c89d820 [WRAPPER] Added a few more symbols to libssl.so.3 and libcrypto.so.3 2026-06-19 10:33:42 +02:00
Yang Liu cd15d459b1 [CPUID] Fixed a regression introduced in f05bdb1f9 (#3963) 2026-06-19 09:04:54 +02:00
Yang Liu befc90de1c [LA64_DYNAEC] Fixed some flags emulation edge-cases (#3961) 2026-06-18 09:03:29 +02:00
Yang Liu 05136b7bfb [SIGNAL] Made SHOWSEGV safer (#3960) 2026-06-17 09:37:51 +02:00
Yang Liu f1bbd6f8c6 [DYNAREC] Preserved EFLAGS across pass0-shortened dynablock exit (#3959) 2026-06-17 09:17:48 +02:00
ptitSeb e823292457 Improved flags handling in signal 2026-06-16 16:49:16 +02:00
ptitSeb 8a3ecb8cc5 [DYNAREC] Improved tracking of executable memory 2026-06-16 13:30:26 +02:00
Yang Liu 4ececfb100 [CONFIG] Improved configurator (#3956)
- better UI
- comments presevation
- global entry
- drag and drop to create entry
2026-06-16 12:59:14 +02:00
Yang Liu e424cdb940 [LA64_DYNAREC] Refined iret_to_next (#3955) 2026-06-16 11:40:25 +02:00
Yang Liu fe86cb68f2 [PROFILE] Added a profile for explorer.exe (#3952) 2026-06-16 09:49:19 +02:00
Yang Liu 83a3b787e6 [DYNACACHE] Added 2 more env vars to dynacache (#3954)
* [DYNACACHE] Added 2 more env vars to dynacache

* reformat
2026-06-16 09:48:48 +02:00
Yang Liu 7031e700b3 [DYNACACHE] Refined dynacache-list format 2026-06-16 14:29:52 +08:00
Yang Liu 64ac6bc0a2 [DYNACACHE] Unified dynacache macros with env 2026-06-16 14:29:52 +08:00
Yang Liu efa5a51365 [DYNACACHE] Refined verbose logging 2026-06-16 14:29:52 +08:00
Yang Liu 80bdf9bac7 [SIGNAL] Set no_tf when resuming from a signal for Syringe.exe (#3951)
* [SIGNAL] Set no_tf when resuming from a signal for Syringe.exe

Wine implements NtSetContextThread by send SIGUSR1 to child and resume it after -- where TF might be set, we need to skip the first SIGTRAP.

* oops
2026-06-15 15:42:27 +02:00
Gao d0ab518074 Add null check for dynablock in arch_unaligned (#3945)
* Add null check for dynablock in arch_unaligned

* Fix formatting issues in arch_unaligned function
2026-06-15 20:44:19 +08:00
Yang Liu 17f57e6804 [DYNAREC] Ported IRET TF fix to all backends (#3950) 2026-06-15 13:10:23 +02:00
ptitSeb 771672e6d4 [ARM64_DYNAREC] Fixed TF handling on IRET 2026-06-15 13:03:18 +02:00
ptitSeb d4f675e7bd [INTERP] Fixed TF handling on IRET 2026-06-15 13:02:56 +02:00
Yang Liu 1a66f7ee40 [WRAPPER] Wrapped process_vm_writev for Syringe.exe (#3949) 2026-06-15 13:01:26 +02:00
ptitSeb 3f747727f2 [ARM64_DYNAREC] Fixed rare case where TF would be restored at an IRET 2026-06-14 19:05:51 +02:00
ptitSeb f5e1ebb554 [TRACE] Added missing line return for Signal trace on Interpreted code 2026-06-14 19:02:47 +02:00
ptitSeb 8f445d9a0c [DYNAREC] Fixed a typo in flag transformation 2026-06-12 14:47:36 +02:00
ptitSeb 0292a66f37 [DYNACACHE] Reworked the settings that should generate different dynacache files 2026-06-12 13:41:08 +02:00
Yang Liu 4f5d171032 [ENV] Added box64-configurator GUI tool (#3946) 2026-06-12 12:57:23 +02:00
Yang Liu 8d7f6a54d7 [ENV] Moved dynacache out of fragile and reduced minimum cache file size to 30KiB (#3942) 2026-06-11 16:54:20 +02:00
yzewei d6e26bc9aa [WRAPPER] Fix libresolv compatibility with older glibc (#3943)
Signed-off-by: Zewei Yang <[email protected]>
2026-06-11 15:04:39 +02:00
Yang Liu be4db11199 [DYNAREC] Optimized a hot function seen in Wine 11.10 (#3941) 2026-06-11 12:36:12 +02:00
yzewei 326784b81e [WRAPPER] Add symbols for Anaconda Navigator and Oracle (#3940) 2026-06-11 12:15:55 +02:00
Yang Liu b9ce9049a2 [DYNACACHE] Refined cache validation (#3939) 2026-06-11 12:11:09 +02:00
Yang Liu ad6b10f060 [CMAKE] Disable dynacache for ctest (#3938) 2026-06-11 10:05:17 +02:00
Yang Liu 34fc743599 [LA64_DYNAREC] Reworked flags and df handling (#3937) 2026-06-11 10:04:47 +02:00
Yang Liu c7d6dad1a8 [WRAPPER] Wrapped 1 more symbol for dbus (#3936) 2026-06-11 09:26:50 +02:00
ptitSeb c14f0eca84 [ARM64_DYNAREC] Reworked flags and df handling (fixes new update of SC2) 2026-06-09 18:31:09 +02:00
ptitSeb b15badbc53 [DYNAREC] Added some comment 2026-06-09 18:30:20 +02:00
ptitSeb e731c91204 [DYNAREC][TRACE] Put the NewInst trace at the right place 2026-06-09 18:29:52 +02:00
ptitSeb 15a165f842 [ARM64_DYNAREC] Fixed strings opcodes with 67 prefix 2026-06-09 12:35:47 +02:00
Yang Liu 422007abd9 [LA64_DYNAREC] Fixed string opcodes with 67 prefix (#3935)
* [LA64_DYNAREC] Fixed string opcodes with 67 prefix

* [RV64_DYNAREC] Fixed string opcodes with 67 prefix
2026-06-09 12:32:07 +02:00
Yang Liu 665cacbe7c [DYNAREC] Reverted a undefined behaviour change (#3934) 2026-06-09 10:03:10 +02:00
ptitSeb e2345d735a [ARM64_DYNAREC] Fixed potential corruption on fastround=0 path for more trig x87 functions 2026-06-08 10:30:14 +02:00
Yang Liu 7a52697f9a [INTERP] Reworked on some undefined bahaviours and fixes (#3933) 2026-06-08 08:43:02 +02:00
ptitSeb 7f1cae956c [LA64_DYNAREC] More alignment to ARM64_DYNAREC on UDF and Jump 2026-06-07 18:31:33 +02:00
ptitSeb 5ab21087dd [DYNAREC] Formating... 2026-06-07 18:06:22 +02:00
ptitSeb 58a8629135 [DYNAREC] Changed setJumpTableIfRef64 behaviour to success if it was already the new value 2026-06-07 18:06:02 +02:00
ptitSeb ae53c4c8ae [LA64_DYNAREC][TRACE] Added self_loop mark to dynablocks opcodes 2026-06-07 17:01:33 +02:00
ptitSeb c0aed34f41 [ARM64_DYNAREC][TRACE] Added self_loop mark to dynablocks opcodes 2026-06-07 16:58:50 +02:00
yzewei e694f2ca8b [WRAPPER] Add libmvec and sqlite3 symbols for Open WebUI (#3930) 2026-06-06 09:11:51 +02:00
Yang Liu 93abdcf317 [INTERP] Fixed MOVSXD (#3928) 2026-06-05 21:41:09 +02:00
Yang Liu cad3b16525 [LA64_DYNAREC][RV64_DYNAREC] Tweaked an undefined behaviour (#3927)
* [LA64_DYNAREC][RV64_DYNAREC] Tweaked an undefined behaviour

* and bsr
2026-06-05 19:14:35 +02:00
ptitSeb b7bf42c8b7 [LA64_DYNAREC] Fix issues with s[ah][lr] in UpdateFlags 2026-06-05 17:33:07 +02:00
ptitSeb a49be7e78d [LA64_DYNAREC] Push/Pop LBT.eflags to the stack in la4_next before calling LinkNext in case the C code use lbt 2026-06-05 16:12:19 +02:00
ptitSeb 7468d58af2 [LA64_DYNAREC][TRACE] Sync LBT.eflags with eFlags before trace 2026-06-05 16:11:02 +02:00
ptitSeb c6c5e4f797 [LA64_DYNAREC] Fixed UpdateFlags for shifts with LBT active 2026-06-05 16:10:11 +02:00
ptitSeb 09bce33a45 [RCFILE] Added 1 more program profile for steam 2026-06-05 10:57:37 +02:00
Yang Liu dab3fdc351 [LA64_DYNAREC] Added a dedicated vzero register (#3926) 2026-06-04 18:57:07 +02:00
ptitSeb 1a2ad946cb [DYNACACHE] Remove attempt to relocate Native function call, it's not a safe method 2026-06-04 16:14:14 +02:00
ptitSeb 00cbf50c98 [WRAPPER] Update leftover generted file 2026-06-04 16:13:19 +02:00
Yang Liu 8182d2b7c0 [WRAPPER] Wrapped more symbol for pipewire (#3925) 2026-06-04 13:59:44 +02:00
Ming Hengqiang f7cede9878 [SIGNAL] Fixed my_signal not reporting sigaction failure for SIGKILL/SIGSTOP (#3924) 2026-06-04 08:16:40 +02:00
Zhijin Zeng 419e095ea0 [SYSCALL] Support mmap for io_uring (#3920) 2026-06-03 15:43:41 +02:00
Zane 7fb417db98 [WRAPPER] Added libpipewire-0.3.so wrapping (#3921) 2026-06-03 15:08:23 +02:00
Pepper Gray 3583d9c90e fix clang warnings (#3915)
* fix clang warnings: check linker flags

building for neoverse-n1 (-DADLINK) with clang warns about unsupported
linker flags:
```
clang: warning: optimization flag '-fuse-linker-plugin' is not supported [-Wignored-optimization-argument]
clang: warning: argument unused during compilation: '-fuse-ld=gold' [-Wunused-command-line-argument]
```

add check for ld.gold and only use it if available

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: use portable inttypes

building using clang warns about format specifier mismatch

```
src/os/sysinfo.c:173:26: warning: format specifies type 'unsigned long long' but the argument has type 'uint64_t' (aka 'unsigned long') [-Wformat]
  173 |     sprintf(str, "%llu", info->frequency);
      |                   ~~~~   ^~~~~~~~~~~~~~~
      |                   %lu
src/os/sysinfo.c:193:129: warning: format specifies type 'int' but the argument has type 'uint64_t' (aka 'unsigned long') [-Wformat]
  193 |             snprintf(branding, sizeof(branding), BOX64_BUILD_INFO_STRING_SHORT " on %.*s @%04d MHz", 28, box64_sysinfo.cpuname, box64_sysinfo.frequency / 1000000);
      |                                                                                           ~~~~                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                                                           %04lu
```

use inttypes format macros instead of format specifiers directly

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: print missing argument

building using clangs warns about an unused parameter:
```
src/emu/x64int3.c:208:117: warning: data argument not used by format string [-Wformat-extra-args]
  208 |                     snprintf(buff, 256, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_RSP), s, (tmp)?tmp:"(nil)", (tmp2)?tmp2:"nil");
      |                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                               ^
```

print the missing parameter

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: use array indexing

building using clang warns about the way the signature is formated:

```
src/wrapped/wrappedvulkan_private.h:80:1: warning: adding 'int' to a string does not append to the string [-Wstring-plus-int]
src/libtools/vulkanoverlay.c:133:94: note: expanded from macro 'GO_vFpff'
  133 | #define GO_vFpff(A, B, N)      static void my_##A##_##N(void* a, float b, float c) {F3(A, #B +2, N);}
      |                                                                                     ~~~~~~~~~^~~~~~
src/wrapped/wrappedvulkan_private.h:80:1: note: use array indexing to silence this warning
```

follow compiler suggestion and replace `#B +2` with `&(#B)[2]`

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: remove extraneous parentheses

building using clang warns about extraneous parentheses

```
src/wrapped32/wrappeddbus.c:541:18: warning: equality comparison with extraneous parentheses [-Wparentheses-equality]
  541 |         if((type == (int)'s')) {
      |             ~~~~~^~~~~~~~~~~
src/wrapped32/wrappeddbus.c:541:18: note: remove extraneous parentheses around the comparison to silence this warning
```

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: use proper type in function signature

building on clang warns about type mismatch:

```
src/wrapped/wrappedgmp.c:158:38: warning: passing 'const char *' to parameter of type 'void *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
  158 |     return my->__gmp_vasprintf(strp, fmt, VARARGS);
      |                                      ^~~
  165 |     return my->__gmp_vfprintf(stream, fmt, VARARGS);
      |                                       ^~~
  176 |     return my->__gmp_vasprintf(strp, fmt, VARARGS);
      |                                      ^~~
  187 |     return my->__gmp_vfprintf(stream, fmt, VARARGS);
      |                                       ^~~
```

modifiy definition to use the actual type instead of void.

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: excess elements in initalizer

building using clang warns about excess elements in initalizer:
```
src/wrapped/wrappercallback.h:16:53: warning: excess elements in struct initializer [-Wexcess-initializers]
   16 | static TYPENAME(LIBNAME) TYPENAME2(my_, LIBNAME) = {0};
      |                                                     ^
```

remove redundant initalization of static elements

Signed-off-by: Pepper Gray <[email protected]>

* fix clang warnings: remove excessive argument

building using clans warns about too many arguments:

```
src/wrapped32/wrappedopenal.c:104:41: warning: too many arguments in call to 'fillALProcWrapper32'
  104 |         fillALProcWrapper32(emu->context);
      |         ~~~~~~~~~~~~~~~~~~~             ^
src/wrapped32/wrappedopenal.c:104:28: warning: passing arguments to 'fillALProcWrapper32' without a prototype is deprecated in all versions of C and is not supported in C23 [-Wdeprecated-non-prototype]
  104 |         fillALProcWrapper32(emu->context);
      |                            ^
```

fillALProcWrapper32 takes no arguments

Signed-off-by: Pepper Gray <[email protected]>

---------

Signed-off-by: Pepper Gray <[email protected]>
2026-05-31 12:25:52 +02:00
ptitSeb 194d577d51 [WRAPPER] Added a workaround for system where libanl.so is gone completly 2026-05-29 20:50:28 +02:00
Pepper Gray 87f896e85b fix clang warnings that are bugs (#3917)
* remove suffix only if present

the suffix is always removed, not only when present due to an assignment
that should be a comparission

See-also: #3916
Signed-off-by: Pepper Gray <[email protected]>

* fix isProcAny check

- the pid should only be returned, when the path matches w, but is always
returned.
- pass p as is (is already a pointer)

See-Also: #3916
Signed-off-by: Pepper Gray <[email protected]>

* add missing paramter

pid is missing in path construction

See-Also: #3916
Signed-off-by: Pepper Gray <[email protected]>

---------

Signed-off-by: Pepper Gray <[email protected]>
2026-05-29 20:47:19 +02:00
ptitSeb ea33518f47 Fixed a regression introduced with 5c84eb6f3a 2026-05-29 16:45:14 +02:00
Yang Liu 5b7308fecf [ENV] Enabled AVX by default on LoongArch (#3907)
* [ENV] Enabled AVX by default on LoongArch

* update docs
2026-05-29 11:14:38 +02:00
ptitSeb 5c84eb6f3a Fixed a regression introduced with d39062d3d7 2026-05-29 10:56:03 +02:00
ptitSeb 239fb1ccb3 [DYNACACHE] Fixed an issue when Dynarec is disabled but Dynacache still enabled 2026-05-29 10:50:01 +02:00
ptitSeb e2186c1e8e [DYNACACHE] Enabled dynacache by default 2026-05-29 10:14:15 +02:00
ptitSeb b77a21b1e1 [WRAPPER][VULKAN] Added 3 new extensions (no new functions, easy) 2026-05-29 09:51:36 +02:00
Yang Liu 2d14666f3d [SYSINFO] Fixed readFreq for LoongArch64 (#3906)
We cannot use the "real" value from sysinfo because RDTSC opcode uses a "fake" rdtime.d.
2026-05-29 09:50:11 +02:00
Yang Liu ba3b80e3f1 [LA64_DYNAREC] Fixed RDTSC opcode (#3905) 2026-05-29 09:03:32 +02:00
Yang Liu 2e718b464d [BOX32] Fixed fullpath resolving like the 64-bit version (#3904)
Fixed a null dereferencing issue I had when I try to run Proton manually.
2026-05-29 08:09:41 +02:00
Yang Liu 4feb8b1863 [LA64_DYNAREC] Worked on CF IRET opcode (#3903) 2026-05-29 08:08:27 +02:00
ptitSeb d39062d3d7 [WRAPPER] Fixed gstreamer not always finding the custom gstreamer folder of steam runtime 2026-05-28 16:34:34 +02:00
Yang Liu f05bdb1f93 [ENV] Reworked a strange design for BOX64_AVX=2 (#3902) 2026-05-28 12:53:57 +02:00
Yang Liu df37f6acf0 [LA64_DYNAREC] Fixed some AVX issues (#3900) 2026-05-28 11:18:12 +02:00
Ming Hengqiang 1299966a02 [RV64_DYNAREC] Fixed VHADDPD/VHSUBPD and VPSHUFB register clobbering in 256-bit path (#3899) 2026-05-28 11:10:02 +02:00
ptitSeb 5687b460b9 Remove a workaround on gnutls, it makes things worse with steamrt4 2026-05-27 17:00:51 +02:00
ptitSeb 1867645ef0 [RCFILE] Some more game profiles 2026-05-27 16:28:43 +02:00
ptitSeb 113b8b427e [DYNAREC] Fixed a regression introduced with #3898 when Defered block are part of a lib that is unloaded 2026-05-27 15:57:34 +02:00
ptitSeb 86c7d13769 [STEAM] Added python support in pressure-vessel workaround 2026-05-27 12:49:16 +02:00
Yang Liu 174a9496fa [DYNAREC] Added deferred dynablock support for FreeDynablock (#3898) 2026-05-27 12:21:45 +02:00
Yang Liu b946deaeea [SYSCALL] Added proper syscall user dispatch emulation (#3897) 2026-05-27 08:10:20 +02:00
Yang Liu ce8ae476b8 [SIGNAL] Fixed a regression introduced in deferred signal commit 5873363e (#3896) 2026-05-27 08:05:42 +02:00
Yang Liu 0bce9e5612 [SYSCALL] Ignore PR_SET_SYSCALL_USER_DISPATCH (#3895)
Used by Wine since 11.5: https://www.winehq.org/news/2026032001, but this seems not supported by LoongArch. I think it's supported by Arm, needs more testing.
2026-05-26 19:00:21 +02:00
Yang Liu de3c2a2e60 [MEMORY] Fixed bricks stubs page non exec degrade (#3894)
If I understand correctly, PROT_NOPROT is used to mark brick stubs so that they are not modified. This PR conforms to this assumption.
2026-05-26 18:40:46 +02:00
ptitSeb c1d2de4538 [DYNAREC] Do not decrement db_size twice for invalidated block that are then deleted 2026-05-25 15:55:34 +02:00
Yang Liu 5873363e4c [SIGNAL] Added partial deferred signal support (#3892)
* [SIGNAL] Added partial deferred signal support

The cold startup time of `wine explorer` on my 3B6000 dropped from 21s to 13s.

* Try to fix wow64 build
2026-05-25 12:09:21 +02:00
Yang Liu ef7852773b [RCFILE] Added profile for Call of Duty 4 (#3891) 2026-05-25 09:37:41 +02:00
Yang Liu 8707b8d1ed [DYNAREC] Optimized bigblock add_next performance with hash table (#3890)
* [DYNAREC] Optimized bigblock add_next performance with hash table

I noticed that when I run `wine explorer` with Wine 11.8 without DynaCache on a Snapdragon 8cx Gen3, there is a hotspot on `add_next`:

```diff
-   22.63%    22.62%  explorer.exe     box64  [.] add_next
     0.01%     0.01%  wine64           box64  [.] add_next
     0.00%     0.00%  wineserver       box64  [.] add_next
```

After applying this optimization, the hotspot disappeared:

```diff
+    0.94%     0.57%  explorer.exe     box64  [.] add_next
     0.02%     0.01%  wine64           box64  [.] add_next
     0.00%     0.00%  conhost.exe      box64  [.] add_next
```

The measured startup time of `wine explorer` dropped from 21s to 16s, which is now quite close to the 14s achieved with DynaCache enabled.

* kh_put  alone is enough
2026-05-24 12:14:54 +02:00
Ming Hengqiang e7a0dc92d7 [RV64_DYNAREC] Fixed SBB16/SBB32 scratch register clobbering in flag calculation (#3889) 2026-05-24 09:15:29 +02:00
Yang Liu 86ff049f6b [RV64_DYNAREC] Fixed VBLENDVPS opcode (#3887) 2026-05-23 09:45:01 +02:00
Yang Liu 0e8124e7e8 [RV64_DYNAREC] Fixed MOVBE opcode fallback path scratch register conflict (#3888) 2026-05-23 09:44:06 +02:00
Yang Liu 7ccab5ef92 [RV64_DYNAREC] Fixed PCMPISTRM opcode scratch register conflict (#3884) 2026-05-23 09:39:38 +02:00
Yang Liu 02d26a8038 [RV64_DYNAREC] Fixed BSF/BSR opcodes safeflags handling (#3886) 2026-05-23 09:37:18 +02:00
小明 8b5cc0888a [RV64_DYNAREC] Fixed ANDNPS/ANDNPD/PANDN register reuse conflict in vector path (#3883) 2026-05-22 16:41:52 +02:00
Yang Liu cc3f0997dc [DYNAREC] Reworked invalidate dynablocks management (#3882)
* [DYNAREC] Reworked invalidate dynablocks management

* Smaller size
2026-05-22 11:17:20 +02:00
Zhijin Zeng 419a5b22da [RV64_DYNAREC] Modify nat flag register save logic to now save all scratch registers (#3880)
1. Rename macro to SPILL_NF_REGISTERS, add implementation for LA64 and PPC64LE.
2. Modify nat flag register spill logic to now save all scratch registers.

Fix scratch register corruption caused by non-consecutive flags producer and
consumer when BOX64_DYNAREC_TRACE is enabled, which introduced by #3876.

For example, the `test rax, rax` flags producer stores its flag calculation
operands in scratch register `t3`. The next `mov r14, rax` instruction does
not use scratch registers, but its associated trace code can still overwrite
t3's value. This means we need to reference the flags consumer that is
`jz 0x0000003F0000ABC0` to identify which registers require saving. But this is
too complicated. So we went with the simpler approach of saving all scratch
registers, this won't add noticeable performance overhead in trace mode.

```
[BOX64] 0x3f00009f68: 48 85 C0 test rax, rax
[BOX64] 0x3ff7afaef0: 53 emitted opcodes, inst=14, barrier=0 state=3/1(0), set=3F/80, use=0, need=0/80, fuse=1/0, sm=0(0/0), sew@entry=7, sew@exit=7, pred=13
	03f00e13	ADDI            t3, zero, 0x3f(63)
	45ccaa23	SW              t3, emu_s9, 0x454(1108)
	01087e33	AND             t3, rax_a6, rax_a6
	47ccb423	SD              t3, emu_s9, 0x468(1128)
[BOX64] New Instruction x64:0x3f00009f6b, native:0x3ff7afafc4
[BOX64] TRACE ----
[BOX64]  n1:0 n2:0 ----
	01f80b37	LUI             rip_s6, 0x1f80000(33030144)
	005b0b1b	ADDIW           rip_s6, rip_s6, 0x5(5)
	00db1b13	SLLI            rip_s6, rip_s6, 0xd(13)
	f6bb0b13	ADDI            rip_s6, rip_s6, 0xffffff6b(-149)
...............................................................
...............................................................
...............................................................
	048cb783	LD              r9_a5, emu_s9, 0x48(72)
	000cb803	LD              rax_a6, emu_s9, 0x0(0)
	088cbb03	LD              rip_s6, emu_s9, 0x88(136)
	080cbb83	LD              flags_s7, emu_s9, 0x80(128)
	fdfbfb93	ANDI            flags_s7, flags_s7, 0xffffffdf(-33)
	006bdf93	SRLI            t6, flags_s7, 0x6(6)
	020fff93	ANDI            t6, t6, 0x20(32)
	01fbebb3	OR              flags_s7, flags_s7, t6
[BOX64] ----------
[BOX64] 0x3f00009f6b: 49 89 C6 mov r14, rax
[BOX64] 0x3ff7afafc4: 54 emitted opcodes, inst=15, barrier=0 state=0/3(0), set=0/0, use=0, need=80/80, fuse=0/1, sm=0(0/0), sew@entry=7, sew@exit=7, pred=14
	00080a13	MV              r14_s4, rax_a6
[BOX64] New Instruction x64:0x3f00009f6e, native:0x3ff7afb09c
[BOX64] TRACE ----
[BOX64]  n1:28 n2:0 ----
	ff010113	ADDI            sp, sp, 0xfffffff0(-16)
	01c13023	SD              t3, sp, 0x0(0)
	01f80b37	LUI             rip_s6, 0x1f80000(33030144)
	01fbebb3	OR              flags_s7, flags_s7, t6
...............................................................
...............................................................
...............................................................
	00013e03	LD              t3, sp, 0x0(0)
	01010113	ADDI            sp, sp, 0x10(16)
[BOX64] ----------
[BOX64] 0x3f00009f6e: 0F 84 4C 0C 00 00 jz 0x0000003F0000ABC0
[BOX64] 0x3ff7afb09c: 67 emitted opcodes, inst=16, barrier=2 state=0/3(0), set=0/0, use=0, need=80/80, fuse=1/0, sm=0(0/0), sew@entry=7, sew@exit=7, pred=15, jmp=out
	020e1463	BNE             t3, zero, 0x28(40) # +10i(0x3ff7afb1a8)
	00000013	NOP

```
2026-05-22 10:43:13 +02:00
ptitSeb 8efb1f09bd [ELFLOADER] Try to add support for R_X86_64_TLSDESC with named symbol 2026-05-21 16:31:44 +02:00
Leslie Zhai 6f30f20a47 [CMAKE] Updated minimum cmake version to be 3.19 (#3878) 2026-05-21 09:57:24 +02:00
Zhijin Zeng ee42c716c8 [DYNAREC] Save temporary registers on the stack before calling PrintTrace (#3876)
The PrintTrace function may modify temporary registers, so we need to push
them onto the stack before execution and restore them upon return.

For example, in the RV64 implementation, register `t3` stores the comparison
result. As its value may be overwritten by PrintTrace, the subsequent `jz`
instruction will use invalid data directly.

```
[BOX64] 0x3f0000239b: 48 85 C0 test rax, rax
[BOX64] 0x3ff7af34d4: 53 emitted opcodes, inst=2, barrier=0 state=3/1(0), set=3F/80, use=0, need=0/80, fuse=1/0, sm=0(0/0), sew@entry=7, sew@exit=7, pred=1
        03f00e13        ADDI            t3, zero, 0x3f(63)
        45ccaa23        SW              t3, emu_s9, 0x454(1108)
        01087e33        AND             t3, rax_a6, rax_a6
        47ccb423        SD              t3, emu_s9, 0x468(1128)
[BOX64] New Instruction x64:0x3f0000239e, native:0x3ff7af35a8
[BOX64] TRACE ----
        01f80b37        LUI             rip_s6, 0x1f80000(33030144)
        001b0b1b        ADDIW           rip_s6, rip_s6, 0x1(1)
        00db1b13        SLLI            rip_s6, rip_s6, 0xd(13)
        39eb0b13        ADDI            rip_s6, rip_s6, 0x39e(926)
        000b0313        MV              t1, rip_s6
        018cbc23        SD              rbx_s8, emu_s9, 0x18(24)
        029cb023        SD              rsp_s1, emu_s9, 0x20(32)
        028cb423        SD              rbp_s0, emu_s9, 0x28(40)
        05acb823        SD              r10_s10, emu_s9, 0x50(80)
        05bcbc23        SD              r11_s11, emu_s9, 0x58(88)
        072cb023        SD              r12_s2, emu_s9, 0x60(96)
        073cb423        SD              r13_s3, emu_s9, 0x68(104)
        074cb823        SD              r14_s4, emu_s9, 0x70(112)
        075cbc23        SD              r15_s5, emu_s9, 0x78(120)
        0010039b        ADDIW           t2, zero, 0x1(1)
        ffffffb7        LUI             t6, 0xfffff000(-4096)
        7dff8f9b        ADDIW           t6, t6, 0x7df(2015)
        01fbffb3        AND             t6, flags_s7, t6
        020bfb93        ANDI            flags_s7, flags_s7, 0x20(32)
        006b9b93        SLLI            flags_s7, flags_s7, 0x6(6)
        01fbebb3        OR              flags_s7, flags_s7, t6
        097cb023        SD              flags_s7, emu_s9, 0x80(128)
        ff010113        ADDI            sp, sp, 0xfffffff0(-16)
        00513023        SD              t0, sp, 0x0(0)
        02acbc23        SD              rdi_a0, emu_s9, 0x38(56)
        02bcb823        SD              rsi_a1, emu_s9, 0x30(48)
        00ccb823        SD              rdx_a2, emu_s9, 0x10(16)
        00dcb423        SD              rcx_a3, emu_s9, 0x8(8)
        04ecb023        SD              r8_a4, emu_s9, 0x40(64)
        04fcb423        SD              r9_a5, emu_s9, 0x48(72)
        010cb023        SD              rax_a6, emu_s9, 0x0(0)
        096cb423        SD              rip_s6, emu_s9, 0x88(136)
[BOX64]   Table64: 0x5d
        00000f97        AUIPC           t6, 0x0(0)
        3a8fbf83        LD              t6, t6, 0x3a8(936)
        00030593        MV              rsi_a1, t1
        00038613        MV              rdx_a2, t2
        000c8513        MV              rdi_a0, emu_s9
        000f80e7        JALR            ra, t6, 0x0(0)
        00013283        LD              t0, sp, 0x0(0)
        01010113        ADDI            sp, sp, 0x10(16)
        038cb503        LD              rdi_a0, emu_s9, 0x38(56)
        030cb583        LD              rsi_a1, emu_s9, 0x30(48)
        010cb603        LD              rdx_a2, emu_s9, 0x10(16)
        008cb683        LD              rcx_a3, emu_s9, 0x8(8)
        040cb703        LD              r8_a4, emu_s9, 0x40(64)
        048cb783        LD              r9_a5, emu_s9, 0x48(72)
        000cb803        LD              rax_a6, emu_s9, 0x0(0)
        088cbb03        LD              rip_s6, emu_s9, 0x88(136)
        080cbb83        LD              flags_s7, emu_s9, 0x80(128)
        fdfbfb93        ANDI            flags_s7, flags_s7, 0xffffffdf(-33)
        006bdf93        SRLI            t6, flags_s7, 0x6(6)
        020fff93        ANDI            t6, t6, 0x20(32)
        01fbebb3        OR              flags_s7, flags_s7, t6
[BOX64] ----------
[BOX64] 0x3f0000239e: 74 02 jz 0x0000003F000023A2
[BOX64] 0x3ff7af35a8: 55 emitted opcodes, inst=3, barrier=0 state=0/3(0), set=0/0, use=0, need=80/80, fuse=1/0, sm=0(0/0), sew@entry=7, sew@exit=7, pred=2, jmp=5
        140e0463        BEQ             t3, zero, 0x148(328) # +82i(0x3ff7af37c4)
        00000013        NOP
```
2026-05-20 21:40:34 +02:00
Yang Liu 036978bffc [INTERP] Removed dead code in 66 prefix (#3875) 2026-05-20 11:40:13 +02:00
Yang Liuandphorcys 97a18aa6ff [LA64_DYNAREC] Optimized AES opcodes using vpaes algorithm (#3874)
Co-authored-by: phorcys <[email protected]>
2026-05-20 10:55:03 +02:00
Yang Liu d0695df48d [INTERP] Fixed 66 prefix decoding (#3873) 2026-05-20 10:32:46 +02:00
Yang Liu 024717cb03 [DYNACACHE] Skipped stale blocks when reload cache (#3872) 2026-05-19 12:10:01 +02:00
ptitSeb 129fc83e8d [WRAPPER][VULKAN] Added a couple of extensions (for #3871) 2026-05-18 11:13:58 +02:00
Yang Liu d4f439ea26 [WRAPPER][BOX32] Wrapped more symbols for sdl1 (#3870) 2026-05-18 09:43:23 +02:00
Yang Liu 0a7b7d4f6b [DYNACACHE] Try to update mtime on cache read (#3866) 2026-05-15 12:19:50 +02:00
Yang Liu 7d3b1dfbfb [DYNACACHE] Created dynacache.c (#3865)
* [DYNACACHE] Created dynacache.c

This is pure code moving

* Update

* Fixed a typo
2026-05-15 11:48:51 +02:00
ptitSeb 5e472e3963 [DYNACACHE] Changed default compression of dynacache to fastest 2026-05-15 10:56:26 +02:00
ptitSeb 367c7aed3d [CI] Try to fix some of the build failling 2026-05-15 09:51:05 +02:00
ptitSeb b6b23e63f4 [DYNACACHE] Added file compression for dynacache (enabled by default, but can be changed with BOX64_DYNACACHE_COMPRESS) 2026-05-15 09:40:54 +02:00
ptitSeb ae6fec30a4 [WRAPPER] Added 1 more function to wrapped libpulse 2026-05-14 11:34:20 +02:00
Makhi Burroughs 3698195c49 Optimize ARM64 dynarec cache compilation for non-AVX paths (#3861)
* Update dynarec_arm64_00.c

* Update dynarec_arm64_avx.c

* Update x64run_private.h

* Update x64run.c

* Update x64runavx.c

* Update dynarec_arm64_avx.c

* Update dynarec_arm64_functions.c

* Update dynarec_arm64_helper.c

* Update dynarec_native_functions.c

* Update x64runavx.c

* Update dynarec_arm64_arch.c

* Update dynarec_arm64_functions.c

* Update dynarec_arm64_helper.c

* Update dynarec_arm64_helper.h

* Update dynarec_native_pass.c
2026-05-13 15:01:59 +02:00
Yang Liu f9fc55cf36 [DYNACACHE] Added a new option to limit cache folder size (#3860) 2026-05-13 12:36:09 +02:00
Yang Liu 6ccba477de [DYNACACHE] Added auto-generated DynaCache versions (#3858)
* [DYNACACHE] Added auto-generated DynaCache versions

* Guarded dynacache_hashes.h with DYNAREC
2026-05-13 10:44:58 +02:00
Yang Liu 75721e4f97 [DYNACACHE] Fixed dynacache command line cpuext detection (#3859) 2026-05-13 10:09:05 +02:00
Yang Liu cae00ca8b7 Moved sitecustomize.py out of bin install directory (#3857) 2026-05-13 10:05:37 +02:00
Makhi Burroughs d32df979a4 dynarec/arm64: reduce AVX dispatch and cache transform overhead (#3856)
* Update dynarec_arm64_00.c

* Update dynarec_arm64_avx.c

* Update x64run_private.h

* Update x64run.c

* Update x64runavx.c

* Update dynarec_arm64_avx.c

* Update dynarec_arm64_functions.c

* Update dynarec_arm64_helper.c

* Update dynarec_native_functions.c

* Update x64runavx.c
2026-05-12 20:53:14 +02:00
Yang Liu 37284f9720 Added a fake x86_64 python for compitibility (#3844) 2026-05-12 14:18:46 +02:00
Yang Liu 8319f389bb [TEST] Added simple run for debugging (#3855) 2026-05-12 13:54:40 +02:00
ptitSeb 238ed34fa9 [DYNAREC] Fixed some cases where FXAM would not see the stack is empty (also [LA64_DYNAREC] and [RV64_DYNAREC] fixed x87 stack depth tracking) 2026-05-12 13:54:16 +02:00
Yang Liu ce3af2bd7a [INTERP][DYNAREC] Fixed XSAVE/XRSTOR opcodes (#3849)
* [INTERP][DYNAREC] Fixed XSAVE/XRSTOR opcodes

* Added a unitest
2026-05-12 10:13:02 +02:00
Yang Liu 3b82d5a2c2 [LA64_DYNAREC] Added 66 14 and 66 E8 opcodes (#3854)
Ported from a9ef6fa588
2026-05-12 10:07:10 +02:00
Yang Liu 57ce5c388e [LA64_DYNAREC] Fixed XLAT opcode ([RV64_DYNAREC] too) (#3853) 2026-05-12 10:06:16 +02:00
Makhi Burroughs cf040876be Add strict EVEX dispatch for AVX512VL forms backed by existing AVX handlers (#3843)
* Update dynarec_arm64_00.c

* Update dynarec_arm64_avx.c

* Update x64run_private.h

* Update x64run.c

* Update x64runavx.c
2026-05-11 14:36:23 +02:00
Yang Liu aec26f67c3 Fixed x87 FNSAVE/FRSTOR opcodes (#3851) 2026-05-11 12:26:11 +02:00
Yang Liu 5dffedfa0f Fixed x87 packed-BCD handling (#3850)
- Ignore the sign byte's low nibble on load;
- Round according to the x87 control word on store;
- Preserve the sign of negative zero
2026-05-11 12:19:14 +02:00
Yang Liu 03e81c33b3 [TEST] Refined number parsing (#3848) 2026-05-11 17:09:19 +08:00
Zhijin Zeng 39d1cb4e33 [CORE] Fix unexpected modification of GetNativeName's return value (#3845)
When I enable `BOX64_ROLLING_LOG`, I observe an error that triggers a software
exception in `x64Int3`. The direct cause of the error is that the value of
`R_RSI` or `R_RDI` is passed to the `snprintf` function as a string pointer
(e.g., line 183 in src/emu/x64int3.c), but the value of `R_RSI` or `R_RDI` at
this time is not a valid string pointer.

Initially, I thought the values of `R_RSI` or `R_RDI` were incorrect, but after
analysis, I found that when the error occurs, the actual function pointer, `a`
is `my___tls_get_addr` instead of `fopen`, so the values of `R_RSI` and `R_RDI`
are correct, and the symbol name is wrong.

Furthermore, I discovered that the value of the symbol name changes during the
execution of the `x64Int3` function: it shifts from `__tls_get_addr` to `fopen`
or other values. The root cause of this change is that a static array is used
to store the symbol name in `GetNativeName`, leading to data tampering in a
multi-threaded environment.

I changed the `static char buff` to `static __thread char native_name` to avoid
multi-threaded data tampering.
2026-05-11 09:33:54 +02:00
Yang Liu 874bee26cd [WRAPPER] Added 1 more extension to libGL (#3847) 2026-05-11 09:28:55 +02:00
Yang Liu 1b3382d5ff [CORE] Degraded those endBox64 logs (#3846) 2026-05-11 09:26:23 +02:00
Yang Liu 740d39c6d1 [LA64_DYNAREC] Supported fastround=2 (#3842) 2026-05-10 09:14:20 +02:00
Yang Liu a77b47b5ed [LA64_DYNAREC] Fixed LSX only path (#3840) 2026-05-10 08:42:31 +02:00
Yang Liu 36003fd14a [LA64_DYNAREC] Refined MOVNT opcode modreg handling (#3839) 2026-05-10 07:48:51 +02:00
Yang Liu 027c7e9c05 [RV64_DYNAREC] Refined some !fastnan handling (#3838) 2026-05-09 21:02:16 +02:00
Yang Liu 56cdd9f732 [DOCS] Mark certain options as fragile or legacy (#3836) 2026-05-09 13:06:19 +02:00
ptitSeb ca432c6ff4 [DYNACACHE] Bumped dynacache version for ARM64 and LA64 2026-05-09 11:30:08 +02:00
Yang Liu 08022c5110 [ARM64_DYNAREC] Fixed some typos in the inlined updateflags emitter (#3835) 2026-05-09 11:25:23 +02:00
Yang Liu a15036f442 [LA64_DYNAREC] Introduced a dynarec version of the UpdateFlags helper function (#3834) 2026-05-09 11:20:13 +02:00
Zane d6810e832c [RCFILE] Added a setting to Feishu (#3833) 2026-05-09 10:34:40 +02:00
Yang Liu 70b6068ecb [RV64_DYNAREC] Fixed scratch register conflicts in a few opcodes (#3831) 2026-05-08 20:42:59 +02:00
Yang Liu 84a6eba99f [SYSCALL] Added a new syscall (#3830) 2026-05-08 12:50:51 +02:00
Yang Liu 469c420626 [DOCS] Added a short advertisement text about our new paper (#3829) 2026-05-07 12:43:25 +02:00
ptitSeb 705877e704 [WRAPPER] Fixed some typo in libmvec wrapping (for #2236) 2026-05-07 10:42:56 +02:00
Yang Liu 961dc21f69 [RCFILE] Added global shared entry support (#3828) 2026-05-07 10:41:03 +02:00
Yang Liu ae18999411 [LA64_DYNAREC] Added some F2/F3 faked prefix opcodes (#3827) 2026-05-07 09:16:49 +02:00
Yang Liu 9f1cc32015 [RCFILE] Fixed section priority handling (#3826) 2026-05-07 09:03:35 +02:00
ptitSeb 19c9af4dd0 [ARM64_DYNAREC] Added 1 more faked F2 prefixed opcode 2026-05-06 19:19:16 +02:00
ptitSeb 7ad988fd0f [INTERP] Added 1 more faked F2 prefixed opcode 2026-05-06 19:19:01 +02:00
ptitSeb 73787e54b3 [WRAPPER] Added 2 more wrapped symbols to libmvec 2026-05-06 19:15:31 +02:00
Zhijin Zeng 05b8d97823 [WRAPPER] Add gnutls_free wrapped function for libgnutls (#3824)
In fact, `gnutls_free` is a function pointer. If it were defined as an ordinary
function, it would trigger a signal 11 error in `CheckExec`.
2026-05-06 14:00:43 +02:00
Yang Liu b619090f1d [DYNAREC] Restored sep entries hidden dynablock reference (#3822)
* [DYNAREC] Restored sep entries hidden dynablock reference

This fixes Linux Steam SIGBUS issues with DynaCache.

* Fix review again
2026-05-06 12:23:08 +02:00
Yang Liu e5df85b625 [DYNAREC] Checked cpuext when reloading dynablock from disk (#3823) 2026-05-06 10:38:13 +02:00
Yang Liu ca70fa1b1e [DYNAREC] Fixed x64_readaddr relocation when loading DynaCache (#3821)
When a cached dynablock is reloaded with a non-zero delta_map,
x64_addr was adjusted but x64_readaddr was left unchanged.

Noticed with a Windows game Replaced: with DynaCache, startup
time drops from about 18s to 12s. Without the fix, the startup
time remains at about 18s with or without DynaCache.
2026-05-06 08:06:27 +02:00
Chi-Kuan Chiu dfaabd0187 [ARM64_DYNAREC] Fix NaN detection operand typo (#3820)
The fastnan=0 path of VSQRTSS compared `v1` against itself for NaN
detection, but `v1` is never assigned in this case where the input is
loaded into `d0` by GETEXSS.

Before fix:
    sqrt(4.0)                        0x40000000 2
    sqrt(-1.0)                       0xffc00000 -NaN
    sqrt(+QNaN)                      0xffc00000 -NaN     <-- expected 0x7fc00000 (+NaN)
    sqrt(-QNaN)                      0xffc00000 -NaN

After fix:
    sqrt(4.0)                        0x40000000 2
    sqrt(-1.0)                       0xffc00000 -NaN
    sqrt(+QNaN)                      0x7fc00000 +NaN
    sqrt(-QNaN)                      0xffc00000 -NaN
2026-05-04 13:35:17 +02:00
Yang Liu 234105ff8d [DOCS] Added Chinese translation to the usage document (#3817) 2026-05-01 18:30:09 +02:00
Yang Liu c6418bc3fd [DOCS] Corrected typos in usage document (#3815) 2026-04-30 12:07:23 +01:00
yzewei 2e7d01ec46 add _ZGVbN4vv_powf _ZGVbN4v_acosf (#3814)
Signed-off-by: Zewei Yang <[email protected]>
2026-04-29 22:03:52 +02:00
ptitSeb 2c72942fae [STEAM] Added libnettle as prefer emulated with gnutls when steam runtime is detected 2026-04-25 09:30:29 +02:00
ptitSeb 42ae8b818c [BOX32][WRAPPER] Added 1 more symbol to libxcb 2026-04-24 17:29:22 +02:00
Yang Liu 41054e4599 [LA64_DYNAREC] Fixed a typo (#3811) 2026-04-24 12:10:09 +02:00
ptitSeb 55e39c3c1f [RCFILE] Added 1 game profile 2026-04-24 11:50:10 +02:00
ptitSeb e11c10c1fa [WRAPPER] Added 1 more symbol to libxkbcommon 2026-04-23 17:28:24 +02:00
Yang Liu b579d23114 [WRAPPERHELPER] Added a new --check-only option (#3803)
* [WRAPPERHELPER] Added a new --check-only option

* Review
2026-04-23 16:10:34 +02:00
Yang Liu 790baf4460 [WRAPPER] Fixed more custom wrapping issues (#3810) 2026-04-23 13:31:24 +02:00
Yang Liu ce161a38f5 [WRAPPER] Fixed some gtk custom wrapping issues (#3809) 2026-04-23 10:13:10 +02:00
ptitSeb fb7cdd2c53 [WRAPPER] Fixed regressions introduced with #3806 2026-04-23 09:01:25 +02:00
Zane d118d6ac1a [WRAPPER] Added libpixman-1.so wrapping (#3805) 2026-04-23 08:45:11 +02:00
Yang Liu d021839d1d [WRAPPER] Duplicated libm wrappers to libc (#3806)
* [WRAPPER] Duplicated libm wrappers to libc

* gowm

* Fix static build

* Another try
2026-04-23 08:38:23 +02:00
Yang Liu 2b2f3043bf [ELFLOADER] Refined symbol not found error message (#3807) 2026-04-23 08:36:07 +02:00
Yang Liu f636f7e765 [WRAPPER] Fixed more wrapping issues (#3802)
* [WRAPPER] Fixed more wrapping issues

* Update

* Keep a comment

* Keep another comment
2026-04-23 08:34:31 +02:00
Chi-Kuan Chiu 96fc30b100 [MALLOCHOOK] Fix UAF and leak (#3804)
UAF at src/mallochook.c:763-778 and :811-826 where my_safer_scalable_aligned_realloc
/ my_scalable_aligned_realloc free p then return it (instead of new_p),
leaking the new allocation and handing the caller a freed pointer.
2026-04-22 13:47:44 +02:00
Yang Liu 2deb99ae4a [WRAPPER] Fixed various wrapping issues (#3799)
* [WRAPPER] Fixed various wrapping issues

* Fix build

* More fixes
2026-04-22 09:35:58 +02:00
Yang Liuandphorcys 5c6200059d [DYNAREC] Optimized native_pclmul functions with a 4bit table (#3797)
Co-authored-by: phorcys <[email protected]>
2026-04-22 09:35:09 +02:00
ptitSeb b85b7e5e2f Start of a new dev. cycle 2026-04-22 09:33:12 +02:00
514 changed files with 23600 additions and 7943 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
{ "contextFileName": "AGENTS.md" }
+6 -1
View File
@@ -51,14 +51,16 @@ Module.symvers
Mkfile.old
dkms.conf
# from box86
# Box64
build/
build*/
.vscode
.cache
.gdb_history
src/git_head.h
src/dynacache_hashes.h
backup/
box64-bundle-x86-libs.sha256
# Wrapper helper
/wrapperhelper/bin
@@ -89,3 +91,6 @@ backup/
*.zip
*.zst
*.zstd
# Python
__pycache__/
-1
View File
@@ -1 +0,0 @@
IMPORTANT: Ensure you’ve thoroughly reviewed the [AGENTS.md](AGENTS.md) file before beginning any work.
+151 -508
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.19)
cmake_policy(SET CMP0065 NEW)
@@ -49,6 +49,7 @@ option(BOX32_BINFMT "Also setup binfmt integration for box32" ${BOX32_BINFMT})
option(LARCH64_ABI_1 "Set to ON if building for Loongarch64 ABI 1.0 system" ${LARCH64_ABI_1})
option(GDBJIT "Set to ON to enable GDB JIT support" ${GDBJIT})
option(WOW64 "Set to ON if you want a WOW64 PE build in addition")
option(BOX64_KDE_PROFILE_PLUGIN "Build the Dolphin/KIO Box64 profile properties plugin when KF5 or KF6 is available" OFF)
if(TERMUX)
set(TERMUX_PATH "/data/data/com.termux/files")
@@ -131,18 +132,19 @@ option(STATICBUILD "Set to ON to have a static build (Warning, not working)" ${S
option(NO_LIB_INSTALL "Set ON to not install a few x86_64 libs that are used by many program" ${NO_LIB_INSTALL})
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
set(BOX64_PYTHON_MIN_VERSION 3.7)
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
find_package(PythonInterp 3)
find_package(PythonInterp ${BOX64_PYTHON_MIN_VERSION})
if(NOT PYTHONINTERP_FOUND)
message( FATAL_ERROR "You need a Python interpreter, CMake will exit." )
endif()
if(${PYTHON_VERSION_MAJOR} LESS 3)
message( FATAL_ERROR "You need a Python 3 interpreter, CMake will exit." )
if(${PYTHON_VERSION_STRING} VERSION_LESS ${BOX64_PYTHON_MIN_VERSION})
message( FATAL_ERROR "You need a Python ${BOX64_PYTHON_MIN_VERSION} or newer interpreter, CMake will exit." )
endif()
else()
find_package(Python3)
find_package(Python3 ${BOX64_PYTHON_MIN_VERSION})
if(NOT Python3_Interpreter_FOUND)
message( FATAL_ERROR "You need a Python interpreter, CMake will exit." )
message( FATAL_ERROR "You need a Python ${BOX64_PYTHON_MIN_VERSION} or newer interpreter, CMake will exit." )
endif()
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
endif()
@@ -158,6 +160,10 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
include(CheckLinkerFlag)
enable_language(C)
check_linker_flag(C "-fuse-ld=gold" HAS_FUSE_LD_GOLD)
if(RPI3ARM64)
add_definitions(-DRPI)
add_definitions(-DRPI3ARM64)
@@ -241,7 +247,11 @@ elseif(SDORYON1)
set(CFLAGS -pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57)
elseif(ADLINK)
add_definitions(-DADLINK)
set(CFLAGS -pipe -mcpu=neoverse-n1 -fuse-ld=gold -fuse-linker-plugin)
set(CFLAGS -pipe -mcpu=neoverse-n1)
if(HAS_FUSE_LD_GOLD)
list(APPEND CFLAGS "-fuse-ld=gold")
list(APPEND CFLAGS "-fuse-linker-plugin")
endif()
elseif(M1)
add_definitions(-DM1)
set(CFLAGS -pipe -march=armv8.5-a+simd+crypto)
@@ -393,9 +403,19 @@ if(BOX32)
)
endif()
# git_head.h is a generated file
set(DYNACACHE_HASH_HEADER "${BOX64_ROOT}/src/dynacache_hashes.h")
add_custom_target(generate_dynacache_hashes
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/tools/gen_dynacache_hashes.py"
--root "${BOX64_ROOT}"
--output "${DYNACACHE_HASH_HEADER}"
BYPRODUCTS "${DYNACACHE_HASH_HEADER}"
VERBATIM
)
# generated files
set_source_files_properties(
"${BOX64_ROOT}/src/git_head.h"
"${BOX64_ROOT}/src/dynacache_hashes.h"
PROPERTIES GENERATED TRUE
HEADER_FILE_ONLY TRUE)
@@ -448,6 +468,7 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/libtools/myalign.c"
"${BOX64_ROOT}/src/libtools/signals.c"
"${BOX64_ROOT}/src/libtools/sigtools.c"
"${BOX64_ROOT}/src/libtools/syscall_user_dispatch.c"
"${BOX64_ROOT}/src/libtools/decopcode.c"
"${BOX64_ROOT}/src/libtools/threads.c"
"${BOX64_ROOT}/src/tools/bitutils.c"
@@ -456,11 +477,13 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/tools/alternate.c"
"${BOX64_ROOT}/src/tools/callback.c"
"${BOX64_ROOT}/src/tools/cleanup.c"
"${BOX64_ROOT}/src/tools/cpumask.c"
"${BOX64_ROOT}/src/tools/gdbjit.c"
"${BOX64_ROOT}/src/tools/fileutils.c"
"${BOX64_ROOT}/src/tools/pathcoll.c"
"${BOX64_ROOT}/src/tools/rbtree.c"
"${BOX64_ROOT}/src/tools/env.c"
"${BOX64_ROOT}/src/tools/dynacache.c"
"${BOX64_ROOT}/src/tools/wine_tools.c"
"${BOX64_ROOT}/src/tools/pe_tools.c"
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
@@ -839,9 +862,11 @@ set(WRAPPEDS
"${BOX64_ROOT}/src/wrapped/wrappedlibtiff5.c"
"${BOX64_ROOT}/src/wrapped/wrappedbrotlidec.c"
"${BOX64_ROOT}/src/wrapped/wrappedzstd.c"
"${BOX64_ROOT}/src/wrapped/wrappedlz4.c"
"${BOX64_ROOT}/src/wrapped/wrappedproxy.c"
"${BOX64_ROOT}/src/wrapped/wrappedssh4.c"
"${BOX64_ROOT}/src/wrapped/wrappedsmbclient.c"
"${BOX64_ROOT}/src/wrapped/wrappedpixman1.c"
)
endif()
if(ANDROID)
@@ -1000,6 +1025,7 @@ if(DYNAREC)
"${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/dynarec/dynacache_compress.c"
"${BOX64_ROOT}/src/emu/x64test.c"
)
endif()
@@ -1122,6 +1148,10 @@ if(RV64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f38.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f38.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f38.c"
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f3a.c"
)
endif()
@@ -1130,9 +1160,11 @@ if(LARCH64_DYNAREC)
${DYNAREC_SRC}
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_arch.c"
"${BOX64_ROOT}/src/dynarec/la64/la64_printer.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_jmpnext.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_consts.c"
"${BOX64_ROOT}/src/dynarec/la64/updateflags_la64.c"
)
set(DYNAREC_ASM
${DYNAREC_ASM}
@@ -1177,6 +1209,7 @@ if(LARCH64_DYNAREC)
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_dd.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_de.c"
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_df.c"
"${BOX64_ROOT}/src/dynarec/la64/updateflags_la64_pass.c"
)
endif()
@@ -1296,6 +1329,7 @@ add_library(interpreter OBJECT ${INTERPRETER})
add_library(mainobj OBJECT ${OS_LINUX_SRC} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPEDS32})
add_dependencies(mainobj generate_git_head_target)
add_dependencies(mainobj generate_dynacache_hashes)
add_executable(${BOX64})
target_link_libraries(${BOX64} mainobj)
@@ -1362,16 +1396,118 @@ if(_x86_64 OR _aarch64 OR _ppc64le)
endif()
if(NOT _x86 AND NOT _x86_64)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/share/box64)
configure_file(${CMAKE_SOURCE_DIR}/tests/box64-bash ${CMAKE_BINARY_DIR}/bin/box64-bash COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/system/box64-python ${CMAKE_BINARY_DIR}/bin/box64-python COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/system/sitecustomize.py ${CMAKE_BINARY_DIR}/share/box64/sitecustomize.py COPYONLY)
file(CHMOD ${CMAKE_BINARY_DIR}/bin/box64-python
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)
if(NOT TERMUX)
set(BOX64_CONFIGURATOR_OUTPUT ${CMAKE_BINARY_DIR}/bin/box64-configurator)
set(BOX64_CONFIGURATOR_SOURCES
${CMAKE_SOURCE_DIR}/configurator/build_standalone.py
${CMAKE_SOURCE_DIR}/configurator/box64rc.py
${CMAKE_SOURCE_DIR}/configurator/configurator.py
${CMAKE_SOURCE_DIR}/configurator/configurator.ui
${CMAKE_SOURCE_DIR}/configurator/model.py
${CMAKE_SOURCE_DIR}/configurator/usage.py
${CMAKE_SOURCE_DIR}/configurator/text_en.json
${CMAKE_SOURCE_DIR}/configurator/text_zh.json
${CMAKE_SOURCE_DIR}/docs/gen/usage.json
${CMAKE_SOURCE_DIR}/docs/gen/usage_cn.json)
add_custom_command(
OUTPUT ${BOX64_CONFIGURATOR_OUTPUT}
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/configurator/build_standalone.py"
--output "${BOX64_CONFIGURATOR_OUTPUT}"
--configurator-dir "${CMAKE_SOURCE_DIR}/configurator"
--usage "${CMAKE_SOURCE_DIR}/docs/gen/usage.json"
--usage-cn "${CMAKE_SOURCE_DIR}/docs/gen/usage_cn.json"
DEPENDS ${BOX64_CONFIGURATOR_SOURCES}
VERBATIM)
add_custom_target(box64-configurator ALL DEPENDS ${BOX64_CONFIGURATOR_OUTPUT})
install(TARGETS ${BOX64} RUNTIME DESTINATION bin)
if(NOT NO_LIB_INSTALL)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION bin)
install(PROGRAMS ${BOX64_CONFIGURATOR_OUTPUT} DESTINATION bin)
install(FILES ${CMAKE_SOURCE_DIR}/system/box64-configurator.desktop DESTINATION share/applications)
if(BOX64_KDE_PROFILE_PLUGIN)
include(CheckLanguage)
check_language(CXX)
if(CMAKE_CXX_COMPILER)
enable_language(CXX)
find_package(ECM QUIET NO_MODULE)
if(ECM_FOUND)
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
set(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR "")
set(QT_DEFAULT_MAJOR_VERSION 6)
find_package(Qt6 QUIET COMPONENTS Core Widgets)
find_package(KF6CoreAddons QUIET)
find_package(KF6KIO QUIET)
if(Qt6_FOUND AND Qt6Widgets_FOUND AND KF6CoreAddons_FOUND AND KF6KIO_FOUND)
include(KDEInstallDirs6)
set(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR 6)
set(_BOX64_KDE_PROFILE_PLUGIN_QT_WIDGETS_TARGET Qt6::Widgets)
set(_BOX64_KDE_PROFILE_PLUGIN_KIO_WIDGETS_TARGET KF6::KIOWidgets)
set(_BOX64_KDE_PROFILE_PLUGIN_INSTALL_NAMESPACE "kf6/propertiesdialog")
else()
set(QT_DEFAULT_MAJOR_VERSION 5)
find_package(Qt5 QUIET COMPONENTS Core Widgets)
find_package(KF5CoreAddons QUIET)
find_package(KF5KIO QUIET)
if(Qt5_FOUND AND Qt5Widgets_FOUND AND KF5CoreAddons_FOUND AND KF5KIO_FOUND)
include(KDEInstallDirs5)
set(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR 5)
set(_BOX64_KDE_PROFILE_PLUGIN_QT_WIDGETS_TARGET Qt5::Widgets)
set(_BOX64_KDE_PROFILE_PLUGIN_KIO_WIDGETS_TARGET KF5::KIOWidgets)
set(_BOX64_KDE_PROFILE_PLUGIN_INSTALL_NAMESPACE "kf5/propertiesdialog")
endif()
endif()
if(_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR)
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endif()
set(_BOX64_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS ON)
kcoreaddons_add_plugin(box64_profile_propertiesplugin
SOURCES ${CMAKE_SOURCE_DIR}/system/kde/box64_profile_propertiesplugin.cpp
INSTALL_NAMESPACE "${_BOX64_KDE_PROFILE_PLUGIN_INSTALL_NAMESPACE}")
set(BUILD_SHARED_LIBS ${_BOX64_BUILD_SHARED_LIBS})
target_link_libraries(box64_profile_propertiesplugin PRIVATE
${_BOX64_KDE_PROFILE_PLUGIN_KIO_WIDGETS_TARGET}
${_BOX64_KDE_PROFILE_PLUGIN_QT_WIDGETS_TARGET})
set_target_properties(box64_profile_propertiesplugin PROPERTIES
AUTOMOC ON
PREFIX ""
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF)
message(STATUS "Building Box64 profile properties dialog plugin for KF${_BOX64_KDE_PROFILE_PLUGIN_KF_MAJOR}")
else()
message(STATUS "Dolphin/KIO Box64 profile plugin disabled: missing Qt5/KF5 or Qt6/KF6 KIO development packages")
endif()
else()
message(STATUS "Dolphin/KIO Box64 profile plugin disabled: ECM not found")
endif()
else()
message(STATUS "Dolphin/KIO Box64 profile plugin disabled: C++ compiler not found")
endif()
endif()
if(NOT NO_LIB_INSTALL)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION bin)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/system/box64-python DESTINATION bin)
install(FILES ${CMAKE_SOURCE_DIR}/system/sitecustomize.py DESTINATION share/box64)
endif()
else()
install(TARGETS ${BOX64} RUNTIME DESTINATION ${TERMUX_PATH}/usr/bin)
if(NOT NO_LIB_INSTALL)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION ${TERMUX_PATH}/usr/bin)
endif()
if(NOT NO_LIB_INSTALL)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION ${TERMUX_PATH}/usr/bin)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/system/box64-python DESTINATION ${TERMUX_PATH}/usr/bin)
install(FILES ${CMAKE_SOURCE_DIR}/system/sitecustomize.py DESTINATION ${TERMUX_PATH}/usr/share/box64)
endif()
endif()
if (GDBJIT)
install(TARGETS box64gdbjitreader RUNTIME DESTINATION lib)
@@ -1395,7 +1531,7 @@ if(NOT _x86 AND NOT _x86_64)
endif()
endif()
set(INSTALL_PATH "/usr/lib/box64-x86_64-linux-gnu/")
set(INSTALL_PATH "/usr/lib/box64-x86_64-linux-gnu")
if(NOT NO_LIB_INSTALL)
if(NOT TERMUX AND NOT ANDROID)
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
@@ -1544,497 +1680,4 @@ set(CPACK_DEBIAN_FILE_NAME "${BOX64}-${BOX64_MAJOR}.${BOX64_MINOR}.${BOX64_REVIS
endif()
INCLUDE(CPack)
if(NOT ANDROID)
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(bootSyscallC ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(printf ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(args ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(maths1 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(cppThreads_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(cppThreads_nocosim PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x64lib")
add_test(tlsData ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(fpu ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(contexts ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#add_test(conditionalThreads ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(linkingIndirectNoversion ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(sse_asm PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
add_test(sse_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(sse_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(backtrace ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile20.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(longjumpInSignals_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21 -D TEST_OUTPUT=tmpfile21.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22 -D TEST_OUTPUT=tmpfile22.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(x87 PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
add_test(pshufb ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23 -D TEST_OUTPUT=tmpfile23.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24 -D TEST_OUTPUT=tmpfile24.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(x87cache ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25 -D TEST_OUTPUT=tmpfile25.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26 -D TEST_OUTPUT=tmpfile26.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(feround PROPERTIES ENVIRONMENT "BOX64_SYNC_ROUNDING=1")
add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test27 -D TEST_OUTPUT=tmpfile27.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref27.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(shaext ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test28 -D TEST_OUTPUT=tmpfile28.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref28.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29 -D TEST_OUTPUT=tmpfile29.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test30 -D TEST_OUTPUT=tmpfile30.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref30.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0;BOX64_AVX=2")
add_test(fpu_rounding ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test31 -D TEST_OUTPUT=tmpfile31.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref31.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
add_test(x87pc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test32 -D TEST_OUTPUT=tmpfile32.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref32.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(x87pc PROPERTIES ENVIRONMENT "BOX64_DYNAREC_X87DOUBLE=2")
add_test(Boundary ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test33 -D TEST_OUTPUT=tmpfile33.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref33.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#if(NOT CI)
# add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01-x64.AppImage -D TEST_OUTPUT=tmpfileAppImage.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#endif()
else()
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01_android -D TEST_OUTPUT=tmpfile01.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(bootSyscallC ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02_android -D TEST_OUTPUT=tmpfile02.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(printf ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03_android -D TEST_OUTPUT=tmpfile03.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(args ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04_android -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(maths1 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05_android -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06_android -D TEST_OUTPUT=tmpfile06.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07_android -D TEST_OUTPUT=tmpfile07.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08_android -D TEST_OUTPUT=tmpfile08.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09_android -D TEST_OUTPUT=tmpfile09.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(fpu ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12_android -D TEST_OUTPUT=tmpfile12.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12_android.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(linkingIndirectNoversion ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15_android -D TEST_OUTPUT=tmpfile15.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
# Box64 for Android now have problems with test16, then disable it for now
#add_test(sse_asm ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16_android -D TEST_OUTPUT=tmpfile16.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
# Box64 for Android now have problems with test17, then disable it for now
#set_tests_properties(sse_asm PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
#add_test(sse_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17_android -D TEST_OUTPUT=tmpfile17.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17_android.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#set_tests_properties(sse_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
add_test(aes ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18_android -D TEST_OUTPUT=tmpfile18.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
# Android don't have backtrace symbols
add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20_android -D TEST_OUTPUT=tmpfile20.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
# add_test(longjumpInSignals_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21_android -D TEST_OUTPUT=tmpfile21.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22_android -D TEST_OUTPUT=tmpfile22.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22_android.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(x87 PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
add_test(pshufb ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23_android -D TEST_OUTPUT=tmpfile23.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24_android -D TEST_OUTPUT=tmpfile24.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(x87cache ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25_android -D TEST_OUTPUT=tmpfile25.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26_android -D TEST_OUTPUT=tmpfile26.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(feround PROPERTIES ENVIRONMENT "BOX64_SYNC_ROUNDING=1")
# TODO: need to regen test with latest test27.c sources
#add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test27_android -D TEST_OUTPUT=tmpfile27.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref27.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(shaext ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test28_android -D TEST_OUTPUT=tmpfile28.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref28.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test29_android -D TEST_OUTPUT=tmpfile29.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref29.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test30_android -D TEST_OUTPUT=tmpfile30.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref30.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#
#set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0 BOX64_AVX=2")
#add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/hcl-X64.AppImage -D TEST_ARGS2=--help -D TEST_OUTPUT=tmpfileAppImage.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/refAppImage.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
endif()
if(NOT ANDROID)
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
endforeach()
else()
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}_android -D TEST_OUTPUT=tmpfile-${testname}.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
endforeach()
endif()
if(BOX32)
add_test(NAME bootSyscall_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test01 -D TEST_OUTPUT=tmpfile32_01.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref01.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME bootSyscallC_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test02 -D TEST_OUTPUT=tmpfile32_02.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref02.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME printf_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test03 -D TEST_OUTPUT=tmpfile32_03.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref03.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME args_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile32_04.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref04.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME maths1_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile32_05.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref05.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME threadsStart_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test06 -D TEST_OUTPUT=tmpfile32_06.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref06.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME trig_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test07 -D TEST_OUTPUT=tmpfile32_07.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref07.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME pi_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test08 -D TEST_OUTPUT=tmpfile32_08.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref08.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME fork_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test09 -D TEST_OUTPUT=tmpfile32_09.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref09.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME cppThreads_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test10 -D TEST_OUTPUT=tmpfile32_10.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref10.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(cppThreads_32bits_nocosim PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x86lib")
add_test(NAME tlsData_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test11 -D TEST_OUTPUT=tmpfile32_11.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref11.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME fpu_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test12 -D TEST_OUTPUT=tmpfile32_12.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref12.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME contexts_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test13 -D TEST_OUTPUT=tmpfile32_13.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref13.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
if(NOT LD80BITS)
add_test(NAME conditionalThreads_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test14 -D TEST_OUTPUT=tmpfile32_14.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref14.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
endif()
add_test(NAME linkingIndirectNoversion_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test15 -D TEST_OUTPUT=tmpfile32_15.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref15.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME linkingIndirectVersion_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test16 -D TEST_OUTPUT=tmpfile32_16.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref16.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME sse_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17 -D TEST_OUTPUT=tmpfile32_17.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(sse_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
add_test(NAME longjumpInSignals_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test18 -D TEST_OUTPUT=tmpfile32_18.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref18.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME x87_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test19 -D TEST_OUTPUT=tmpfile32_19.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref19.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
set_tests_properties(x87_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
add_test(NAME idiv_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test20 -D TEST_OUTPUT=tmpfile32_20.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref20.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
add_test(NAME multiple_dlopen_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test21 -D TEST_OUTPUT=tmpfile32_21.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref21.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests32/extensions/*.c")
foreach(file ${extension_tests})
get_filename_component(testname "${file}" NAME_WE)
add_test(NAME "${testname}_32bits" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/extensions/${testname} -D TEST_OUTPUT=tmpfile32_-${testname}.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/extensions/${testname}.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
endforeach()
#add_test(NAME sse_optimized_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17_o2 -D TEST_OUTPUT=tmpfile32_17_o2.txt
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17_o2.txt
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
#set_tests_properties(sse_optimized_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
add_test(bswap_32bits ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test23 -D TEST_OUTPUT=tmpfile32_23.txt
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref23.txt
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
endif()
add_subdirectory(tests)
+10 -1
View File
@@ -16,7 +16,7 @@ Box64 enables running x86_64 Linux programs, including games, on non-x86_64 Linu
Box64 leverages native system libraries (libc, libm, SDL, OpenGL), offering ease of integration and surprising performance in many applications. For performance benchmarks, check [this analysis](https://box86.org/index.php/2021/06/game-performances/).
With DynaRec for Arm, RISC-V and LoongArch platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
With DynaRec for Arm, RISC-V and LoongArch platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/). For a more detailed look at Box64 internals and optimization strategies, see our EuroSys 2026 paper, [Practical and Efficient x86-64 Emulation on RISC-V](https://doi.org/10.1145/3767295.3803574), which focuses on RISC-V but covers many techniques that apply more broadly to Box64.
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
@@ -58,6 +58,15 @@ Box64 requires 64-bit libraries on the host system, as it directly translates x8
1. Box32 is still experimental.
2. Some shell scripts (such as the GOG game installer) may rely on `uname -m` to determine the current architecture. Please run them as `box64 script.sh` to allow Box64 to take over.
Note that DynaCache is now enabled by default (with compression). This will creates files in `~/.cache/box64` to save generated code for executed binaries and libraries, so launch time can be greatly reduced on second run. The files are compressed and will take up to 2Gb by default. You can disable DynaCache writting, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writting there
```ini
[*]
BOX64_DYNACACHE=2
```
(or 0 to completly disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
---
## Configuration
+6 -6
View File
@@ -29,16 +29,16 @@ _Logo 由 @grayduck 制作,感谢!_
- `$ box64 ./program [args]` 运行 Linux x86_64 程序。
- `$ box64 -k` 杀死所有模拟的进程。
- `$ box64-bash` 进入 x86_64 bash 环境。
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE.md)。
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE_CN.md)。
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE_CN.md)。
---
## 编译和安装
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
- [编译说明](docs/COMPILE.md)
- [安装 Wine](docs/WINE_CN.md)
---
@@ -65,7 +65,7 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
更多信息,请参阅[使用文档](docs/USAGE.md)。
更多信息,请参阅[使用文档](docs/USAGE_CN.md)。
---
@@ -88,7 +88,7 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
有关更多信息,请参阅 [Wine 使用说明](docs/WINE.md)。
有关更多信息,请参阅 [Wine 使用说明](docs/WINE_CN.md)。
----
+8
View File
@@ -2,6 +2,12 @@ https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+de
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb,6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb,4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_amd64.deb,b49a24743eb2b6d1198c7cf014ee791bccd5d3223ed8a1e4769d899e1f894a5b
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_i386.deb,1d032b638081704393bc847e2e1f7a00c6894fa262ed0272fb7282962e8915a9
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_amd64.deb,6a4c2d7b127ed18c8c2a558e4d63fcd56de4a154bb9db5fafa7e497f4771dc4a
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_i386.deb,4585064f220490562c132e6fe6a2c46a66d319f6862f60f26e21bccbaadcbd90
https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_amd64.deb,833a024051fcfa79208462486c2761b6e1c464676da96e0d3664f4a189449e34
https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_i386.deb,5cbd85ab559d99dc5907898488c87b8cf0e117412e0d7981ca7e69e35fbc3f84
https://archives.fedoraproject.org/pub/archive/epel/9.5/Everything/x86_64/Packages/m/mbedtls-2.28.8-1.el9.x86_64.rpm,54cb7e43e902a7378e912ecfec470ee30fe69af323d3812cbc39ddebd64790ff
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.i686.rpm,5e4f525f44d538e3467dd13c66010d54f3d12ec4a319829e15a23ff2d0195b5b
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.x86_64.rpm,49f956ad143399c29f5ddf6da6b6fc108ce130d1ed598b4ec5a68b1ff26091de
@@ -79,6 +85,8 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i68
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.i686.rpm,4079b9fe93cef0d2ec5b74502ade41a175e1f95e72bace30af29cdcaab037cae
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.x86_64.rpm,5ff471276dcb8c38fe16bf91f963ec4f051954107c3f0ca28fbb3bd2c6521f2b
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm,dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm,e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/zlib-1.2.11-40.el9.i686.rpm,659ee5222028744806be3f822369a726c721aa346eed2882dcf019d83c111e67
1 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
2 https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb 625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
3 https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb 6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
4 https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb 4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
5 https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_amd64.deb b49a24743eb2b6d1198c7cf014ee791bccd5d3223ed8a1e4769d899e1f894a5b
6 https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_i386.deb 1d032b638081704393bc847e2e1f7a00c6894fa262ed0272fb7282962e8915a9
7 https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_amd64.deb 6a4c2d7b127ed18c8c2a558e4d63fcd56de4a154bb9db5fafa7e497f4771dc4a
8 https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_i386.deb 4585064f220490562c132e6fe6a2c46a66d319f6862f60f26e21bccbaadcbd90
9 https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_amd64.deb 833a024051fcfa79208462486c2761b6e1c464676da96e0d3664f4a189449e34
10 https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_i386.deb 5cbd85ab559d99dc5907898488c87b8cf0e117412e0d7981ca7e69e35fbc3f84
11 https://archives.fedoraproject.org/pub/archive/epel/9.5/Everything/x86_64/Packages/m/mbedtls-2.28.8-1.el9.x86_64.rpm 54cb7e43e902a7378e912ecfec470ee30fe69af323d3812cbc39ddebd64790ff
12 https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.i686.rpm 5e4f525f44d538e3467dd13c66010d54f3d12ec4a319829e15a23ff2d0195b5b
13 https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.x86_64.rpm 49f956ad143399c29f5ddf6da6b6fc108ce130d1ed598b4ec5a68b1ff26091de
85 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm 15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
86 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm 2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
87 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm 308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
88 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.i686.rpm 4079b9fe93cef0d2ec5b74502ade41a175e1f95e72bace30af29cdcaab037cae
89 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.x86_64.rpm 5ff471276dcb8c38fe16bf91f963ec4f051954107c3f0ca28fbb3bd2c6521f2b
90 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
91 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
92 https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/zlib-1.2.11-40.el9.i686.rpm 659ee5222028744806be3f822369a726c721aa346eed2882dcf019d83c111e67
+7 -2
View File
@@ -77,10 +77,10 @@ done
# reorganize the files
cd "${dir_tmp}"/bundle-libs
mkdir -p "${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/*.so* usr/lib32/*.so* \
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/* usr/lib32/*.so* \
"${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
mkdir -p "${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
mv lib64/*.so* usr/lib/x86_64-linux-gnu/*.so* usr/lib64/*.so* \
mv lib64/*.so* usr/lib/x86_64-linux-gnu/* usr/lib64/*.so* \
"${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
rm -f ./*.tar.* debian-binary files.xml metadata.xml
rm -rf ./lib* etc run sbin usr var
@@ -130,5 +130,10 @@ for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
done
done
# generate a SHA256 checksum of every file and symlink in the bundle
cd "${dir_tmp}"/bundle-libs
find usr \( -type f -o -type l \) -exec "${sha256sum}" {} + \
| LC_ALL=C sort --key 2 > "${current_dir}"/box64-bundle-x86-libs.sha256
# generate the bundle libraries archive
tar -C "${dir_tmp}"/bundle-libs -czvf "${current_dir}"/box64-bundle-x86-libs.tar.gz .
+244
View File
@@ -0,0 +1,244 @@
from __future__ import annotations
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, Iterable, List, Optional, Tuple
@dataclass(frozen=True)
class SectionKey:
kind: str
name: str
arch: str = ""
def sort_key(self) -> Tuple[int, str, str]:
order = {"shared": 0, "exact": 1, "wildcard": 2, "file": 3}
return (order.get(self.kind, 9), self.name.lower(), self.arch.lower())
@dataclass(frozen=True)
class Assignment:
key: str
value: str
line_index: int
@dataclass(frozen=True)
class RcSection:
header: str
start: int
end: int
key: SectionKey
assignments: Tuple[Assignment, ...]
def last_value(self, key: str) -> Optional[str]:
return next((item.value for item in reversed(self.assignments) if item.key == key), None)
def normalize_arch(value: Optional[str]) -> str:
value = (value or "").strip().strip("`")
if value == "<empty>":
return ""
return value.lower()
def section_key_from_header(header: str, arch: Optional[str] = None) -> SectionKey:
name = header.strip()
arch_value = normalize_arch(arch)
if name == "*":
return SectionKey("shared", "*", arch_value)
if name.startswith("*") and name.endswith("*") and len(name) > 2:
return SectionKey("wildcard", name[1:-1].strip().lower(), arch_value)
if name.startswith("/"):
return SectionKey("file", name.lower(), arch_value)
return SectionKey("exact", name.lower(), arch_value)
def normalize_section_input(value: str) -> str:
name = value.strip()
if name.startswith("[") or name.endswith("]"):
if not (name.startswith("[") and name.endswith("]")):
raise ValueError("Invalid section name")
name = name[1:-1].strip()
if not name or any(char in name for char in "\r\n[]#"):
raise ValueError("Invalid section name")
return name
def header_from_key(key: SectionKey) -> str:
if key.kind == "shared":
return "*"
if key.kind == "wildcard":
return f"*{key.name}*"
return key.name
def semantic_line(line: str) -> str:
return line.rstrip("\n").split("#", 1)[0].strip()
def parse_section_header(line: str) -> Optional[str]:
semantic = semantic_line(line)
return semantic[1 : semantic.find("]")].strip() if semantic.startswith("[") and "]" in semantic else None
def parse_assignment(line: str) -> Optional[Tuple[str, str]]:
semantic = semantic_line(line)
if "=" not in semantic:
return None
key, value = semantic.split("=", 1)
key = key.strip()
return (key, value.strip()) if key else None
def render_assignment_line(original: str, key: str, value: str) -> str:
text = original.rstrip("\n")
newline = "\n" if original.endswith("\n") else ""
indent = text[: len(text) - len(text.lstrip())]
comment = ""
comment_start = text.find("#")
if comment_start >= 0:
comment = " " + text[comment_start:].strip()
return f"{indent}{key}={value}{comment}{newline or os.linesep}"
class RcDocument:
def __init__(self, path: Path) -> None:
self.path = path
self.lines: List[str] = []
self.sections: List[RcSection] = []
self.sections_by_key: Dict[SectionKey, RcSection] = {}
self.reload()
def reload(self) -> None:
self.lines = self.path.read_text(encoding="utf-8").splitlines(True) if self.path.is_file() else []
self._parse()
def _parse(self) -> None:
builders: List[Dict[str, object]] = []
current: Optional[Dict[str, object]] = None
for index, line in enumerate(self.lines):
header = parse_section_header(line)
if header is not None:
if current is not None:
current["end"] = index
current = {
"header": header,
"start": index,
"end": len(self.lines),
"assignments": [],
}
builders.append(current)
continue
if current is None:
continue
parsed = parse_assignment(line)
if parsed is None:
continue
key, value = parsed
current["assignments"].append(Assignment(key, value, index))
if current is not None:
current["end"] = len(self.lines)
sections: List[RcSection] = []
for builder in builders:
assignments = tuple(builder["assignments"])
arch = next((item.value for item in reversed(assignments) if item.key == "BOX64_ARCH"), None)
key = section_key_from_header(str(builder["header"]), arch)
sections.append(
RcSection(
header=str(builder["header"]),
start=int(builder["start"]),
end=int(builder["end"]),
key=key,
assignments=assignments,
)
)
self.sections = sections
self.sections_by_key = {section.key: section for section in sections}
def section_for_key(self, key: SectionKey) -> Optional[RcSection]:
return self.sections_by_key.get(key)
def add_section(self, header: str, assignments: Optional[Dict[str, str]] = None) -> RcSection:
if self.lines and self.lines[-1].strip():
self.lines.append(os.linesep)
self.lines.append(f"[{header}]{os.linesep}")
for key, value in (assignments or {}).items():
self.lines.append(f"{key}={value}{os.linesep}")
self._parse()
return self.sections[-1]
def delete_section(self, key: SectionKey) -> None:
section = self.section_for_key(key)
if section is None:
return
delete_end = section.end
if section.assignments:
delete_end = section.assignments[-1].line_index + 1
del self.lines[section.start : delete_end]
self._parse()
def set_assignment(self, section_key: SectionKey, key: str, value: str) -> SectionKey:
section = self.section_for_key(section_key)
if section is None:
raise KeyError(section_key)
matching = [assignment for assignment in section.assignments if assignment.key == key]
if matching:
line_index = matching[-1].line_index
self.lines[line_index] = render_assignment_line(self.lines[line_index], key, value)
start = section.start
else:
insert_at = section.end
self.lines.insert(insert_at, f"{key}={value}{os.linesep}")
start = section.start
self._parse()
for updated in self.sections:
if updated.start == start:
return updated.key
raise KeyError(section_key)
def remove_assignment(self, section_key: SectionKey, key: str) -> SectionKey:
section = self.section_for_key(section_key)
if section is None:
raise KeyError(section_key)
indexes = [assignment.line_index for assignment in section.assignments if assignment.key == key]
start = section.start
for line_index in reversed(indexes):
del self.lines[line_index]
self._parse()
for updated in self.sections:
if updated.start == start:
return updated.key
return section_key
def save(self) -> None:
self.path.parent.mkdir(parents=True, exist_ok=True)
data = "".join(self.lines)
tmp_path = self.path.with_name(f"{self.path.name}.tmp")
tmp_path.write_text(data, encoding="utf-8")
if self.path.exists():
mode = self.path.stat().st_mode
os.chmod(tmp_path, mode)
os.replace(tmp_path, self.path)
def copy_assignments(section: RcSection) -> Dict[str, str]:
return {assignment.key: assignment.value for assignment in section.assignments}
def direct_box64_assignments(section: Optional[RcSection]) -> Iterable[Assignment]:
return () if section is None else tuple(
assignment for assignment in section.assignments if assignment.key.startswith("BOX64_")
)
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import os
import pprint
from pathlib import Path
from typing import Dict, Optional, Sequence
MODULES = {
"box64rc": "box64rc.py",
"usage": "usage.py",
"model": "model.py",
"configurator": "configurator.py",
}
UI_FILE = "configurator.ui"
def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Build the standalone box64-configurator script")
parser.add_argument("--output", required=True, type=Path)
parser.add_argument("--configurator-dir", required=True, type=Path)
parser.add_argument("--usage", required=True, type=Path)
parser.add_argument("--usage-cn", required=True, type=Path)
return parser.parse_args(argv)
def read_modules(configurator_dir: Path) -> Dict[str, str]:
return {
name: (configurator_dir / filename).read_text(encoding="utf-8")
for name, filename in MODULES.items()
}
def read_texts(configurator_dir: Path) -> Dict[str, Dict[str, str]]:
return {language: read_json(configurator_dir / f"text_{language}.json") for language in ("en", "zh")}
def read_ui(configurator_dir: Path) -> str:
return (configurator_dir / UI_FILE).read_text(encoding="utf-8")
def read_json(path: Path):
with path.open("r", encoding="utf-8") as file:
return json.load(file)
def render_script(
modules: Dict[str, str],
texts: Dict[str, Dict[str, str]],
ui: str,
usage_data,
usage_cn_data,
) -> str:
return f"""#!/usr/bin/env python3
# Generated by configurator/build_standalone.py. Do not edit this file directly.
from __future__ import annotations
import sys
import types
_MODULES = {pprint.pformat(modules, width=120)}
_EMBEDDED_TEXTS = {pprint.pformat(texts, width=120)}
_EMBEDDED_UI = {pprint.pformat(ui, width=120)}
_EMBEDDED_USAGE_DATA = {pprint.pformat(usage_data, width=120)}
_EMBEDDED_USAGE_CN_DATA = {pprint.pformat(usage_cn_data, width=120)}
def _load_module(name: str) -> types.ModuleType:
module = types.ModuleType(name)
module.__file__ = f"<box64-configurator:{{name}}>"
module.__package__ = ""
if name == "usage":
module._EMBEDDED_USAGE_DATA = _EMBEDDED_USAGE_DATA
module._EMBEDDED_USAGE_CN_DATA = _EMBEDDED_USAGE_CN_DATA
sys.modules[name] = module
exec(compile(_MODULES[name], module.__file__, "exec"), module.__dict__)
return module
for _name in ("box64rc", "usage", "model"):
_load_module(_name)
_app = types.ModuleType("box64_configurator_app")
_app.__file__ = __file__
_app.__package__ = ""
_app._EMBEDDED_TEXTS = _EMBEDDED_TEXTS
_app._EMBEDDED_UI = _EMBEDDED_UI
sys.modules["box64_configurator_app"] = _app
exec(compile(_MODULES["configurator"], __file__, "exec"), _app.__dict__)
if __name__ == "__main__":
raise SystemExit(_app.main())
"""
def main(argv: Optional[Sequence[str]] = None) -> int:
args = parse_args(argv)
configurator_dir = args.configurator_dir.resolve()
output = args.output.resolve()
script = render_script(
read_modules(configurator_dir),
read_texts(configurator_dir),
read_ui(configurator_dir),
read_json(args.usage),
read_json(args.usage_cn),
)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(script, encoding="utf-8")
os.chmod(output, 0o755)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+1354
View File
File diff suppressed because it is too large. Load diff
+179
View File
@@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkHeaderBar" id="header">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkButton" id="reload_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">False</property>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">False</property>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="language_combo">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">4</property>
</packing>
</child>
</object>
<object class="GtkBox" id="root_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkPaned" id="main_paned">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox" id="sidebar">
<property name="width-request">285</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="new_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">False</property>
<property name="margin-start">14</property>
<property name="margin-end">14</property>
<property name="margin-top">10</property>
<property name="margin-bottom">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="margin-start">14</property>
<property name="margin-end">14</property>
<property name="margin-bottom">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="mode_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">14</property>
<property name="margin-end">14</property>
<property name="margin-bottom">8</property>
<child>
<object class="GtkToggleButton" id="user_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="all_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="receives-default">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="list_scroll">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hscrollbar-policy">never</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<style>
<class name="sidebar"/>
</style>
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">False</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="detail_scroll">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hscrollbar-policy">never</property>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">False</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStatusbar" id="statusbar">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>
+386
View File
@@ -0,0 +1,386 @@
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List, Optional, Tuple
try:
from .box64rc import (
Assignment,
RcDocument,
RcSection,
SectionKey,
copy_assignments,
direct_box64_assignments,
header_from_key,
normalize_section_input,
section_key_from_header,
)
from .usage import EnvOption, UsageCatalog
except ImportError:
from box64rc import (
Assignment,
RcDocument,
RcSection,
SectionKey,
copy_assignments,
direct_box64_assignments,
header_from_key,
normalize_section_input,
section_key_from_header,
)
from usage import EnvOption, UsageCatalog
ARCH_ALIASES = {
"aarch64": "arm64",
"arm64": "arm64",
"amd64": "x86_64",
"loong64": "la64",
"loongarch64": "la64",
"powerpc64le": "ppc64le",
"ppc64le": "ppc64le",
"x86_64": "x86_64",
}
def box64_arch_from_machine(machine: Optional[str]) -> str:
value = (machine or "").strip().lower().replace("-", "_")
if value.startswith("riscv64"):
return "rv64"
return ARCH_ALIASES.get(value, value)
@dataclass(frozen=True)
class EntryRecord:
key: SectionKey
display_name: str
system_section: Optional[RcSection]
user_section: Optional[RcSection]
@property
def editable_source(self) -> str:
if self.user_section is not None:
return "user"
if self.system_section is not None:
return "system"
return "new"
@property
def arch(self) -> str:
return self.key.arch
@dataclass(frozen=True)
class ValueState:
option: EnvOption
value: str
source: str
SectionIdentity = Tuple[str, str]
OFTEN_USED_OPTION_NAMES = {
"BOX64_DYNAREC_BIGBLOCK",
"BOX64_DYNAREC_CALLRET",
"BOX64_DYNAREC_SAFEFLAGS",
"BOX64_DYNAREC_STRONGMEM",
"BOX64_DYNAREC_DIRTY",
"BOX64_DYNAREC_FASTROUND",
"BOX64_DYNAREC_FASTNAN",
"BOX64_MAXCPU",
}
PROFILE_OPTION_NAME = "BOX64_PROFILE"
PROFILE_DEFAULT_VALUE = "default"
PROFILE_SETTINGS = {
"safest": (
("BOX64_DYNAREC_FASTNAN", "0"),
("BOX64_DYNAREC_FASTROUND", "0"),
("BOX64_DYNAREC_BIGBLOCK", "0"),
("BOX64_DYNAREC_SAFEFLAGS", "2"),
("BOX64_DYNAREC_STRONGMEM", "2"),
),
"safe": (
("BOX64_DYNAREC_BIGBLOCK", "0"),
("BOX64_DYNAREC_SAFEFLAGS", "2"),
("BOX64_DYNAREC_STRONGMEM", "1"),
),
"fast": (
("BOX64_DYNAREC_CALLRET", "1"),
("BOX64_DYNAREC_BIGBLOCK", "3"),
("BOX64_DYNAREC_SAFEFLAGS", "0"),
("BOX64_DYNAREC_STRONGMEM", "1"),
("BOX64_DYNAREC_DIRTY", "1"),
("BOX64_DYNAREC_FORWARD", "1024"),
),
"fastest": (
("BOX64_DYNAREC_CALLRET", "1"),
("BOX64_DYNAREC_BIGBLOCK", "3"),
("BOX64_DYNAREC_SAFEFLAGS", "0"),
("BOX64_DYNAREC_STRONGMEM", "0"),
("BOX64_DYNAREC_DIRTY", "1"),
("BOX64_DYNAREC_FORWARD", "1024"),
),
}
class ConfigStore:
def __init__(
self, system_path: Path, user_path: Path, catalog: UsageCatalog, machine_arch: str = ""
) -> None:
self.catalog = catalog
self.machine_arch = machine_arch
self.system = RcDocument(system_path)
self.user = RcDocument(user_path)
self.dirty = False
self._entries: Tuple[EntryRecord, ...] = ()
self._entries_by_key: Dict[SectionKey, EntryRecord] = {}
self._system_sections_by_identity: Dict[SectionIdentity, RcSection] = {}
self._user_sections_by_identity: Dict[SectionIdentity, RcSection] = {}
self._rebuild_entry_cache()
def reload(self) -> None:
self.system.reload()
self.user.reload()
self.dirty = False
self._rebuild_entry_cache()
def save(self) -> None:
self.user.save()
self.reload()
def entries(self) -> Tuple[EntryRecord, ...]:
return self._entries
def entry_for_key(self, key: SectionKey) -> Optional[EntryRecord]:
return self._entries_by_key.get(key)
def _rebuild_entry_cache(self) -> None:
self._system_sections_by_identity = self._effective_sections(self.system)
self._user_sections_by_identity = self._effective_sections(self.user)
identities = set(self._system_sections_by_identity)
identities.update(self._user_sections_by_identity)
entries: List[EntryRecord] = []
for identity in identities:
system_section = self._system_sections_by_identity.get(identity)
user_section = self._user_sections_by_identity.get(identity)
display_section = user_section or system_section
if display_section is None:
continue
display_name = display_section.header if display_section else header_from_key(display_section.key)
entries.append(EntryRecord(display_section.key, display_name, system_section, user_section))
self._entries = tuple(
sorted(entries, key=lambda entry: (entry.key.sort_key(), entry.display_name.lower()))
)
self._entries_by_key = {entry.key: entry for entry in self._entries}
def _effective_sections(self, document: RcDocument) -> Dict[SectionIdentity, RcSection]:
sections: Dict[SectionIdentity, RcSection] = {}
for section in document.sections:
if not self._section_matches_arch(section):
continue
identity = self._identity(section.key)
current = sections.get(identity)
if current is None or self._section_replaces(current, section):
sections[identity] = section
return sections
def _section_matches_arch(self, section: RcSection) -> bool:
return not section.key.arch or section.key.arch == self.machine_arch
def _section_replaces(self, current: RcSection, candidate: RcSection) -> bool:
if candidate.key.arch:
return candidate.key.arch == self.machine_arch
return not current.key.arch
def _identity(self, key: SectionKey) -> SectionIdentity:
return key.kind, key.name
def _mark_dirty(self) -> None:
self.dirty = True
self._rebuild_entry_cache()
def create_entry(self, header: str) -> SectionKey:
normalized = normalize_section_input(header)
requested_key = section_key_from_header(normalized)
user_section = self.user.section_for_key(requested_key)
if user_section is not None:
return user_section.key
section = self.user.add_section(normalized)
self._mark_dirty()
return section.key
def delete_user_entry(self, key: SectionKey) -> None:
self.user.delete_section(key)
self._mark_dirty()
def fork_entry(self, entry: EntryRecord) -> Tuple[SectionKey, bool]:
section, forked = self._ensure_user_section(entry)
if forked:
self._mark_dirty()
return section.key, forked
def set_option(self, entry: EntryRecord, option_name: str, value: str) -> Tuple[SectionKey, bool]:
section, forked = self._ensure_user_section(entry)
if self._is_default_profile(option_name, value):
new_key = self.user.remove_assignment(section.key, option_name)
else:
new_key = self.user.set_assignment(section.key, option_name, value)
self._mark_dirty()
return new_key, forked
def reset_option(self, entry: EntryRecord, option_name: str) -> SectionKey:
user_section = entry.user_section
if user_section is None:
return entry.key
system_value = None
if entry.system_section is not None:
system_value = entry.system_section.last_value(option_name)
if system_value is not None and not self._is_default_profile(option_name, system_value):
new_key = self.user.set_assignment(user_section.key, option_name, system_value)
else:
new_key = self.user.remove_assignment(user_section.key, option_name)
self._mark_dirty()
return new_key
def unsupported_assignments(self, entry: EntryRecord) -> Tuple[Assignment, ...]:
section = entry.user_section or entry.system_section
return tuple(
assignment for assignment in direct_box64_assignments(section) if assignment.key not in self.catalog
)
def effective_values(
self, entry: EntryRecord
) -> Tuple[List[ValueState], List[ValueState], List[ValueState]]:
states: Dict[str, ValueState] = {}
if entry.key.kind != "shared":
self._apply_shared(states)
self._apply_matching_wildcards(states, entry)
self._apply_direct(states, entry)
self._apply_profile(states)
active: List[ValueState] = []
often_used: List[ValueState] = []
defaults: List[ValueState] = []
for option in self.catalog.options:
state = states.get(option.name)
if state is None:
default_state = ValueState(
option=option,
value=option.default_value,
source="default",
)
if option.name in OFTEN_USED_OPTION_NAMES:
often_used.append(default_state)
else:
defaults.append(default_state)
else:
active.append(state)
active.sort(key=lambda state: state.option.name != PROFILE_OPTION_NAME)
return active, often_used, defaults
def _apply_profile(self, states: Dict[str, ValueState]) -> None:
profile_option = self.catalog.by_name.get(PROFILE_OPTION_NAME)
if profile_option is None:
return
profile_state = states.get(PROFILE_OPTION_NAME)
if profile_state is None:
profile_state = ValueState(
option=profile_option,
value=PROFILE_DEFAULT_VALUE,
source="default",
)
states[PROFILE_OPTION_NAME] = profile_state
for option_name, value in PROFILE_SETTINGS.get(profile_state.value.lower(), ()):
if option_name in states:
continue
option = self.catalog.by_name.get(option_name)
if option is None:
continue
states[option_name] = ValueState(
option=option,
value=value,
source="profile",
)
def _is_default_profile(self, option_name: str, value: Optional[str]) -> bool:
return (
option_name == PROFILE_OPTION_NAME
and (value or "").strip().lower() == PROFILE_DEFAULT_VALUE
)
def _ensure_user_section(self, entry: EntryRecord) -> Tuple[RcSection, bool]:
user_section = self.user.section_for_key(entry.key)
if user_section is not None:
return user_section, False
if entry.system_section is not None:
assignments = copy_assignments(entry.system_section)
user_section = self.user.add_section(entry.system_section.header, assignments)
return user_section, True
user_section = self.user.add_section(entry.display_name)
return user_section, True
def _apply_shared(self, states: Dict[str, ValueState]) -> None:
for section, source in (
(self._system_sections_by_identity.get(("shared", "*")), "shared-system"),
(self._user_sections_by_identity.get(("shared", "*")), "shared-user"),
):
if section is not None:
self._apply_assignments(states, section, source)
def _apply_matching_wildcards(self, states: Dict[str, ValueState], entry: EntryRecord) -> None:
if entry.key.kind not in ("exact", "file"):
return
target = entry.key.name.lower()
wildcard_identities = {
identity
for identity in (
*self._system_sections_by_identity.keys(),
*self._user_sections_by_identity.keys(),
)
if identity[0] == "wildcard" and identity[1] in target
}
for identity in sorted(wildcard_identities, key=lambda item: item[1]):
user_section = self._user_sections_by_identity.get(identity)
system_section = self._system_sections_by_identity.get(identity)
if user_section is not None:
self._apply_assignments(states, user_section, "wildcard-user")
elif system_section is not None:
self._apply_assignments(states, system_section, "wildcard-system")
def _apply_direct(self, states: Dict[str, ValueState], entry: EntryRecord) -> None:
if entry.user_section is not None:
self._apply_assignments(states, entry.user_section, "user")
elif entry.system_section is not None:
self._apply_assignments(states, entry.system_section, "system")
def _apply_assignments(
self, states: Dict[str, ValueState], section: RcSection, source: str
) -> None:
for assignment in section.assignments:
option = self.catalog.by_name.get(assignment.key)
if option is None:
continue
states[assignment.key] = ValueState(
option=option,
value=assignment.value,
source=source,
)
+48
View File
@@ -0,0 +1,48 @@
{
"title": "Box64 Configurator",
"filter_all": "All",
"filter_user": "User",
"search": "Search entries",
"new": "New entry",
"delete": "Delete user entry",
"reload": "Reload",
"save": "Save",
"select_entry": "Select an entry on the left.",
"effective": "Effective options",
"often_used": "Often used options",
"defaults": "Default values",
"unsupported": "Other rcfile keys",
"unsupported_help": "These keys are preserved when a system entry is forked, but this tool does not edit them.",
"system_note": "This entry comes from the system rcfile. Fork it to edit it in the user rcfile.",
"user_note": "This entry is stored in the user rcfile.",
"forked": "Created a user fork; save writes it to the user rcfile.",
"dirty": "Unsaved changes",
"saved": "Saved user rcfile",
"source_user": "User",
"source_system": "System",
"source_shared-user": "User shared",
"source_shared-system": "System shared",
"source_wildcard-user": "User wildcard",
"source_wildcard-system": "System wildcard",
"source_profile": "Profile",
"source_default": "Default",
"default_dynamic": "build dependent",
"apply": "Apply",
"edit": "Edit",
"reset": "Reset",
"default_marker": "Default",
"new_title": "New entry",
"new_prompt": "Executable name",
"new_drop_hint": "You can also drag and drop an executable onto the window to create an emtry entry.",
"new_global_hint": "Use * to create a global entry.",
"cancel": "Cancel",
"create": "Create",
"delete_title": "Delete user entry?",
"delete_body": "Only the user rcfile section will be removed. The system rcfile is not changed.",
"delete_action": "Delete",
"fork_action": "Fork",
"save_changes_title": "Save changes before closing?",
"save_changes_body": "Your user rcfile edits have not been saved.",
"discard": "Discard",
"error": "Error"
}
+48
View File
@@ -0,0 +1,48 @@
{
"title": "Box64 配置器",
"filter_all": "全部",
"filter_user": "用户",
"search": "搜索条目",
"new": "新建条目",
"delete": "删除用户条目",
"reload": "重新载入",
"save": "保存",
"select_entry": "请在左侧选择一个条目。",
"effective": "生效选项",
"often_used": "常用选项",
"defaults": "默认值",
"unsupported": "其他配置项",
"unsupported_help": "系统条目复制到用户时会保留这些项,但此工具不会编辑它们。",
"system_note": "此条目来自系统配置。请先复制到用户后再编辑。",
"user_note": "此条目保存在用户配置中。",
"forked": "已复制到用户,保存后写入用户配置。",
"dirty": "有未保存的修改",
"saved": "已保存用户配置",
"source_user": "用户",
"source_system": "系统",
"source_shared-user": "用户共享",
"source_shared-system": "系统共享",
"source_wildcard-user": "用户通配",
"source_wildcard-system": "系统通配",
"source_profile": "预设",
"source_default": "默认",
"default_dynamic": "随构建而定",
"apply": "应用",
"edit": "编辑",
"reset": "重置",
"default_marker": "默认",
"new_title": "新建条目",
"new_prompt": "可执行文件名",
"new_drop_hint": "也可以将可执行文件拖放到窗口中来创建新条目。",
"new_global_hint": "输入 * 可创建全局条目。",
"cancel": "取消",
"create": "创建",
"delete_title": "删除用户条目?",
"delete_body": "只会移除用户配置中的段,系统配置不会被修改。",
"delete_action": "删除",
"fork_action": "复制到用户",
"save_changes_title": "关闭前保存修改?",
"save_changes_body": "用户配置的修改尚未保存。",
"discard": "放弃",
"error": "错误"
}
+146
View File
@@ -0,0 +1,146 @@
from __future__ import annotations
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Tuple
PLACEHOLDER_MARKERS = (
"XXXX",
"YYYY",
"ZZZZ",
"xxx",
"yyy",
"zzz",
"symbolname",
)
_EMBEDDED_USAGE_DATA: Optional[List[Dict[str, Any]]] = globals().get("_EMBEDDED_USAGE_DATA")
_EMBEDDED_USAGE_CN_DATA: Optional[Dict[str, Any]] = globals().get("_EMBEDDED_USAGE_CN_DATA")
ALWAYS_CONFIGURATOR_OPTIONS = {"BOX64_PROFILE"}
def clean_choice_value(raw_key: str) -> str:
value = str(raw_key).strip()
if value.startswith("`") and value.endswith("`") and len(value) >= 2:
value = value[1:-1]
return "" if value == "<empty>" else value
def is_placeholder_value(value: str) -> bool:
return bool(value) and (
any(marker in value for marker in PLACEHOLDER_MARKERS) or value.startswith("0x") and "X" in value
)
def localized(language: str, english: str, chinese: str) -> str:
return (chinese or english) if language == "zh" else english
@dataclass(frozen=True)
class Choice:
value: str
label: str
description_en: str
description_cn: str
is_default: bool
is_placeholder: bool
def description(self, language: str) -> str:
return localized(language, self.description_en, self.description_cn)
@dataclass(frozen=True)
class EnvOption:
name: str
description_en: str
description_cn: str
choices: Tuple[Choice, ...]
@property
def allows_custom_value(self) -> bool:
return any(choice.is_placeholder for choice in self.choices)
@property
def default_value(self) -> str:
return next((choice.value for choice in self.choices if choice.is_default), "")
def description(self, language: str) -> str:
return localized(language, self.description_en, self.description_cn)
class UsageCatalog:
def __init__(self, options: Iterable[EnvOption]) -> None:
self.options: Tuple[EnvOption, ...] = tuple(options)
self.by_name: Dict[str, EnvOption] = {option.name: option for option in self.options}
def __contains__(self, name: str) -> bool:
return name in self.by_name
def find_usage_paths(start: Optional[Path] = None) -> Tuple[Path, Path]:
here = (start or Path(__file__)).resolve()
for parent in (here.parent, *here.parents):
for directory in (parent / "docs" / "gen", parent / "share" / "box64"):
usage = directory / "usage.json"
usage_cn = directory / "usage_cn.json"
if usage.is_file() and usage_cn.is_file():
return usage, usage_cn
raise FileNotFoundError("Could not find usage.json and usage_cn.json")
def load_default_usage_catalog() -> UsageCatalog:
if _EMBEDDED_USAGE_DATA is not None and _EMBEDDED_USAGE_CN_DATA is not None:
return load_usage_catalog_from_data(_EMBEDDED_USAGE_DATA, _EMBEDDED_USAGE_CN_DATA)
usage_path, usage_cn_path = find_usage_paths()
return load_usage_catalog(usage_path, usage_cn_path)
def load_usage_catalog(usage_path: Path, usage_cn_path: Path) -> UsageCatalog:
with usage_path.open("r", encoding="utf-8") as file:
english_data = json.load(file)
with usage_cn_path.open("r", encoding="utf-8") as file:
chinese_data = json.load(file)
return load_usage_catalog_from_data(english_data, chinese_data)
def load_usage_catalog_from_data(
english_data: Iterable[Dict[str, Any]], chinese_data: Dict[str, Any]
) -> UsageCatalog:
options: List[EnvOption] = []
for entry in english_data:
name = entry["name"]
if not entry.get("configurator", False) and name not in ALWAYS_CONFIGURATOR_OPTIONS:
continue
chinese_entry = chinese_data.get(name, {})
chinese_choices = chinese_entry.get("options", {})
choices = []
for option in entry.get("options", []):
raw_key = str(option["key"])
value = clean_choice_value(raw_key)
choices.append(
Choice(
value=value,
label="<empty>" if value == "" else value,
description_en=option.get("description", ""),
description_cn=chinese_choices.get(raw_key, ""),
is_default=bool(option.get("default", False)),
is_placeholder=is_placeholder_value(value),
)
)
options.append(
EnvOption(
name=name,
description_en=entry.get("description", ""),
description_cn=chinese_entry.get("description", ""),
choices=tuple(choices),
)
)
return UsageCatalog(options)
+10
View File
@@ -1,3 +1,13 @@
box64 (0.4.4) unstable; urgency=low
This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
=> A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
=> DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
=> You can use box64-configurator on the special `[*]` profile to change default values
=> More improvements on emulation accuracy that help running more DRM'd games
-- Sebastien Chevalier <[email protected]> Mon, 2 Aug 2026 10:30:33 -0100
box64 (0.4.2) unstable; urgency=low
This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
+61
View File
@@ -1,3 +1,64 @@
v0.4.4
======
Highlights:
* This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
=> A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
=> DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
=> You can use box64-configurator on the special `[*]` profile to change default values
=> More improvements on emulation accuracy that help running more DRM'd games
Version summary:
* RCFILE: Created a new GUI tools to edit custom rcfile: box64-configurator
* RCFILE: Created a KDE plugin to quickly set box64 properties for an executable file
* RCFILE: Added more profiles
* RCFILE: Added BOX64_SKIPCPU to avoid using N first cores (for big.LITTLE configuration)
* ELF: Some more Relocation handling
* Wrapping: Improved MALLOC_HACK=2 behaviour
* Wrapping: more fixes to some functions signatures
* Wrapping: added more wrapped functions
* Wrapping: added some more wrapped libraries
* Wrapping: Added more Syscall
* Wrapping: Some rework on the bridges to avoid unexpected reuse of bridges for different function signature
* Wrapping: Box32: Some fixes and improvement on some wrapped functions
* Emulation: Some improvement on handling of x87 80bits values
* Emulation: Added some deferred signal support for improved stability
* Emulation: Improved TF handling
* Emulation: Improved CPUID handling
* Emulation: optimised some sha1 function
* Emulation: LA64: Enabled AVX by default (on par with ARM64)
* Interpreter: A few fixes in some opcodes
* Interpreter: Added unaligned handling of more lock opcodes
* DynaCache: many improvements and fixes
* DynaCache: added libz compression of the dynacache files
* DynaCache: added disk size limit, to purge old/outdated dynacache once a threshold is reached
* Dynarec: Many small opcodes optimisation here and there
* Dynarec: Some improvement on handling of x87 80bits values
* Dynarec: Optimised the internal jump handling while building a dynablock
* Dynarec: Improved TF handling
* Dynarec: Reworked Alt Address handling
* Dynarec: Reworked a bit the jump table to save some memory
* Dynarec: Made BOX64_CALLRET=2 default
* Dynarec: ARM64: Some improvement in some x87 opcodes handling
* Dynarec: ARM64: A few fixes to some opcodes
* Dynarec: LA64: Added optimisation on the zeroing out of the upper 32 bits of registers
* Dynarec: LA64: Added a Dynarec version of UpdateFlags (on par with ARM64)
* Dynarec: LA64: More work FASTNAN / FASTROUND handling
* Dynarec: LA64: Many fixes on many opcodes
* Dynarec: LA64: Added a few opcodes
* Dynarec: LA64: Added fastpath on many logical opcodes (when no flags are needed)
* Dynarec: LA64: AES opcodes optimisations
* Dynarec: LA64: Improved Native flags use for more cases
* Dynarec: LA64: Improved jump_safe macro (removing many useless NOP)
* Dynarec: RV64: Improvement on flags handling (on par with ARM64 & LA64)
* Dynarec: RV64: Many fixes on NaN handling
* Dynarec: RV64: Some fixes to various opcodes
* Dynarec: RV64: Improved Native Flags handling
* Dynarec: RV64: Added some opcodes
* Dynarec: RV64: Detect and use the new Zicbop/Zicond/Zicbom cpu extension when available
* WrapperHelper: some more improvements and fixes
v0.4.2
======
+11 -11
View File
@@ -3,7 +3,7 @@ Compiling/Installing
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-built-packages) for alternatives.
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-Compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-Compiling)
@@ -15,7 +15,7 @@ Additional installation steps may be necessary when copying only the box64 execu
git clone https://github.com/ptitSeb/box64
cd box64
mkdir build; cd build; cmake .. ${OPTIONS}
make -j4
make -j4
sudo make install
```
If it's the first install, you also need:
@@ -288,13 +288,13 @@ To have a trace enabled build (***the interpreter will be slightly slower***), a
#### Build DynaRec
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
#### Save memory at run time
You can use `-DSAVE_MEM` to have a build that will try to save some memory. For now, it only increases the jumptable from 4 levels to 5. The added granularity avoids wasting space, but adds one more read from memory when jumping between blocks.
You can use `-DSAVE_MEM=ON` to build Box64 with memory-saving optimizations. This uses a five-level jump table to reduce unused address-space allocations and enables secondary entry points (BOX64_DYNAREC_SEP=1) by default to reduce duplicate DynaRec blocks. These optimizations may reduce memory usage at the cost of additional memory accesses and lower performance on some workloads.
#### Build outside of a git repo
@@ -326,9 +326,9 @@ Box64 can also be packaged into a .deb file ***using the source code zip from th
## Pre-built packages
### Debian-based Linux
### Debian-based Linux
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
```
# check if .list file already exists
@@ -358,12 +358,12 @@ sudo apt update
sudo apt install box64-generic-arm -y
```
## Cross-Compiling
## Cross-Compiling
----
### Set Up the Cross-Compiler
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
### Run CMake with Cross-Compilation Options
### Run CMake with Cross-Compilation Options
Follow the per-platform compilation instructions to configure the CMake options for your target architecture.
In particular, you must specify the cross-compiler. For example:
```
+5
View File
@@ -14,6 +14,11 @@ Linux Steam requires Box86 or Box32 and it's binfmt enabled, check [Compilation
steam
```
For additional stability with Box64 when Box86 is unavailable, it is recommended to use the new 64-bit-only runtime for the Steam client.
- Steam > Settings > Interface > Client Beta Participation: Steam Beta > Restart Now
- Steam > Settings > Interface > Use experimental SteamRT3 Steam Client: On > Restart Now
## Install and run Windows Steam
It's simple, just download it from Steam website and install it like other Windows applications.
+274 -232
View File
File diff suppressed because it is too large. Load diff
+945
View File
@@ -0,0 +1,945 @@
<!--- 此文件由 gen.py 自动生成,请勿直接编辑。 -->
使用说明
----
Box64 有许多环境变量可用于控制其行为,下面将按类别列出。
Box64 有两种构建类型:Wine WOW64 构建(WowBox64)和常规 Linux 构建。请注意,只有部分环境变量在 WowBox64 中可用。
### 配置文件
除了环境变量之外,如果你使用的是常规 Linux 构建,Box64 默认还会在两个位置查找 rcfile:系统范围的 `/etc/box64.box64rc` 和用户目录下的 `~/.box64rc`。
而在 WowBox64 中,配置文件仅在 `%USERPROFILE%/.box64rc` 处检查。
设置的优先级如下(从高到低):`~/.box64rc` > `/etc/box64.box64rc` > 环境变量。
配置示例:
```
[factorio]
BOX64_DYNAREC_SAFEFLAGS=0
BOX64_DYNAREC_BIGBLOCK=2
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
```
此配置将使所有名为 `factorio` 的可执行文件应用指定的设置。
共享选项也可以定义在特殊的 `[*]` 配置段中。这些设置会全局应用,而更具体的配置段只会覆盖它自己显式定义的选项。
### Linux 构建的高级用法
1. **通配符匹配**
可以使用星号(`*`)对应用程序名称进行基本的模式匹配。例如,`[*setup*]` 将匹配名称中包含 "setup" 的任何程序。请注意,这里实现的是简单的通配符匹配,而非完整的正则表达式支持。
2. **共享设置**
特殊的 `[*]` 配置段可为所有应用程序定义共享的 rcfile 选项。它不同于 `[*setup*]` 这类通配符配置段,是一个专用的全局配置段。
3. **自定义配置文件**
`BOX64_RCFILE` 环境变量可以指定一个替代的配置文件,而不是默认的 `/etc/box64.box64rc`。
4. **按文件设置**
以 `/` 开头的配置项适用于特定文件。例如:
```
[/d3d9.dll]
BOX64_DYNAREC_SAFEFLAGS=0
```
这些设置将仅影响 `d3d9.dll` 文件。此语法同样适用于**模拟的** Linux 库,例如 `[/libstdc++.so.6]`。
----
## 性能
### BOX64_DYNAREC
启用或禁用动态重编译器(DynaRec)。如果在支持的架构上构建时开启了 DynaRec 支持,则默认为 1。 在 WowBox64 中可用。
* 0: 禁用 DynaRec。
* 1: 启用 DynaRec。
### BOX64_DYNAREC_ALIGNED_ATOMICS
仅生成对齐的原子操作(目前仅在 Arm64 上可用)。 在 WowBox64 中可用。
* 0: 生成非对齐原子操作处理代码。 [默认值]
* 1: 仅生成对齐的原子操作,代码更快更小,但在非对齐数据地址上执行 LOCK 前缀指令时会导致 SIGBUS。
### BOX64_DYNAREC_BIGBLOCK
尝试构建更大的代码块以提高性能。 在 WowBox64 中可用。
* 0: 不尝试构建尽可能大的代码块,适用于使用大量线程和 JIT 的程序(如 Unity)。
* 1: 尽可能构建大的代码块。
* 2: 构建更大的代码块,代码块重叠时不停止,但仅针对 elf 内存中的代码块。 [默认值]
* 3: 构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 Wine 程序有用。
### BOX64_DYNAREC_CALLRET
优化 CALL/RET 指令。 在 WowBox64 中可用。
* 0: 不优化 CALL/RET,使用跳转表。
* 1: 尝试优化 CALL/RET,在可能的情况下跳过跳转表。
* 2: 尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。 [默认值]
### BOX64_DYNAREC_SEP
使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。 在 WowBox64 中可用。
* 0: 不在 CALLRET 返回时添加 SEP。 [默认值]
* 1: 在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。
* 2: 在 CALLRET 返回时添加 SEP,适用于所有类型的内存。
### BOX64_DYNAREC_DF
启用或禁用延迟 FLAGS 的使用。 在 WowBox64 中可用。
* 0: 禁用延迟 FLAGS 的使用。
* 1: 启用延迟 FLAGS 的使用。 [默认值]
### BOX64_DYNAREC_DIRTY
是否允许继续运行未受保护且可能已脏的代码块。
* 0: 不允许继续运行未受保护且可能已脏的代码块。 [默认值]
* 1: 允许继续运行在与代码相同页面中写入数据的代码块,可以加快某些游戏的加载时间,但也可能导致意外崩溃。
* 2: 除了 1 之外,当检测到热页时,将该页面标记为永不写保护,但基于该页面构建的代码块将始终被测试。这样可以更快(但某些 SMC 情况可能无法捕获)。
### BOX64_DYNAREC_NOHOTPAGE
是否禁用热页检测(即代码执行和数据写入同时发生的页面)。
* 0: 检测热页。 [默认值]
* 1: 不检测热页。
### BOX64_DYNAREC_FASTNAN
启用或禁用快速 NaN 处理。 在 WowBox64 中可用。
* 0: 精确模拟 x86 上的 -NaN 生成。
* 1: 不对 -NaN 生成做任何特殊处理,速度更快。 [默认值]
### BOX64_DYNAREC_FASTROUND
启用或禁用快速舍入。 在 WowBox64 中可用。
* 0: 生成 float/double -> int 舍入,并使用当前舍入模式进行 float/double 计算,类似 x86。
* 1: 不对边缘情况的舍入做任何特殊处理,速度更快。 [默认值]
* 2: 使用当前舍入模式生成 float/double -> int 舍入(类似 x86),但使用快速的 int -> float/double 转换。
### BOX64_DYNAREC_FORWARD
定义构建代码块时允许的最大前向跳转值。仅接受 0、128、256、512 和 1024;其他值将回退为 128。 在 WowBox64 中可用。
* 0: 无前向跳转值。当前代码块结束时,即使存在之前的前向跳转也不尝试继续前进。
* 128: 允许代码块结束与下一个前向跳转之间最多 128 字节的间隙。 [默认值]
* 256: 允许代码块结束与下一个前向跳转之间最多 256 字节的间隙。
* 512: 允许代码块结束与下一个前向跳转之间最多 512 字节的间隙。
* 1024: 允许代码块结束与下一个前向跳转之间最多 1024 字节的间隙。
### BOX64_DYNAREC_NATIVEFLAGS
启用或禁用原生FLAGS的使用。 在 WowBox64 中可用。
* 0: 不使用原生FLAGS。
* 1: 在可能的情况下使用原生FLAGS。 [默认值]
### BOX64_DYNAREC_PAUSE
启用 x86 PAUSE 模拟,可能有助于自旋锁的性能。 在 WowBox64 中可用。
* 0: 忽略 x86 PAUSE 指令。 [默认值]
* 1: 使用 YIELD 模拟 x86 PAUSE 指令。
* 2: 使用 WFI 模拟 x86 PAUSE 指令。
* 3: 使用 SEVL+WFE 模拟 x86 PAUSE 指令。
### BOX64_DYNAREC_SAFEFLAGS
在 CALL/RET 指令和其他边缘情况下 FLAGS 模拟的行为。 在 WowBox64 中可用。
* 0: 将 CALL/RET 标记为从不需要任何 FLAGS。
* 1: 将大多数 RET 标记为需要 FLAGS,将大多数 CALL 标记为不需要。 [默认值]
* 2: 将所有 CALL/RET 都标记为需要 FLAGS。同时也处理所有边缘情况。
### BOX64_DYNAREC_STRONGMEM
开启或关闭 x86 强内存模型的模拟。 在 WowBox64 中可用。
* 0: 不做任何特殊处理。 [默认值]
* 1: 在写入内存时启用以有限方式模拟 x86 强内存模型的内存屏障。
* 2: 包含 1 的全部内容,外加 SIMD 指令的内存屏障。
* 3: 包含 2 的全部内容,外加定期添加更多内存屏障。
* 4: 模仿 x86 TSO,类似 QEMU 的方法,可用于评估目的。
### BOX64_DYNAREC_VOLATILE_METADATA
使用从 PE 文件解析的 volatile 元数据,仅对 64 位 Windows 游戏有效。
* 0: 不使用 volatile 元数据。
* 1: 使用 volatile 元数据,将指导 Box64 进行更好的强内存模拟。 [默认值]
### BOX64_DYNACACHE
启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 1(启用)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。
* 0: 禁用 DynaCache。
* 1: 启用 DynaCache。 [默认值]
* 2: 使用已有的 DynaCache 文件,但不生成新的。
### BOX64_DYNACACHE_FOLDER
设置 DynaCache 文件的文件夹。默认为 $XDG_CACHE_HOME/box64,如果 $XDG_CACHE_HOME 未设置则为 $HOME/.cache/box64。
* XXXX: 使用文件夹 XXXX 存储 DynaCache 文件。
### BOX64_DYNACACHE_LIMIT
DynaCache 文件夹的最大大小(MiB)。超过限制时,会先删除无效的 DynaCache 文件,如仍超限再删除最旧的有效文件。默认大小为 2048MiB。
* 0: 不限制 DynaCache 文件夹大小。
* XXXX: 先删除无效缓存文件,如仍超限再删除最旧的有效缓存文件,将 DynaCache 文件夹保持在 XXXX MiB 以下。
* 2048: 默认值为 2048 MiB。 [默认值]
### BOX64_DYNACACHE_COMPRESS
设置是否压缩磁盘上的 DynaCache 文件。
* 0: 不压缩 DynaCache 文件。
* 1: 使用 Zlib 最快压缩级别压缩 DynaCache 文件。 [默认值]
* 2: 使用 Zlib 默认压缩级别压缩 DynaCache 文件。
### BOX64_DYNACACHE_MIN
DynaCache 写入磁盘的最小大小(KB)。默认大小为 30KB。
* XXXX: 设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。
* 30: 默认值为 30 KB。 [默认值]
### BOX64_SKIPCPU
Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
* 0: Do not skip any CPU cores. [默认值]
* XXXX: Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
### BOX64_MMAP32
在运行 32 位代码的 64 位程序(如 Wine WOW64)上强制使用 32 位兼容的内存映射,可提高性能。
* 0: 不强制使用 32 位内存映射。
* 1: 强制使用 32 位内存映射。 [默认值]
### BOX64_DYNAREC_NOARCH
从代码块中移除架构元数据(在信号处理时使用)。 在 WowBox64 中可用。
* 0: 为每个代码块生成所有架构元数据,包括 x87/mmx/SSE/AVX 寄存器追踪。会使用更多内存。 [默认值]
* 1: 仅生成每个代码块的必要元数据(FLAGS、对齐),节省一些内存,但某些加密软件可能会失败。
* 2: 不为代码块生成元数据,进一步节省内存,但在信号处理时可能会失败。
### BOX64_RDTSC_1GHZ
如果可用,使用硬件计数器实现 rdtsc。
* 0: 如果可用,使用硬件计数器实现 rdtsc 指令。 [默认值]
* 1: 仅当精度至少为 1GHz 时,使用硬件计数器实现 rdtsc。
## 不稳定或遗留选项
### BOX64_DYNAREC_PURGE
根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。
* 0: DynaRec 不会清除旧的未使用代码块。 [默认值]
* 1: DynaRec 将根据年龄阈值清除旧的未使用代码块。
### BOX64_DYNAREC_PURGE_AGE
代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。
* 4096: 默认年龄阈值。 [默认值]
* XXXX: 自定义年龄阈值(范围:10-65536)。
### BOX64_DYNAREC_WAIT
是否等待代码块构建完成。 在 WowBox64 中可用。
* 0: 不等待,改用解释器,可能在大量多线程或 JIT 程序上略微加速。
* 1: 等待代码块构建完成。 [默认值]
### BOX64_DYNAREC_WEAKBARRIER
调整内存屏障以减少强内存模拟的性能影响。 在 WowBox64 中可用。
* 0: 使用常规安全屏障。
* 1: 使用弱屏障以获得更多性能提升。 [默认值]
* 2: 包含 1 的全部内容,外加禁用最后的写屏障。
## 兼容性
### BOX64_AES
是否暴露 AES 能力。 在 WowBox64 中可用。
* 0: 不暴露 AES 能力。
* 1: 暴露 AES 能力。 [默认值]
### BOX64_ARCH
在 rcfile 中指定当前条目适用的架构。此选项仅在 rcfile 中使用时生效。
* `arm64`: 仅对 AArch64 应用当前条目。
* `la64`: 仅对 LoongArch64 应用当前条目。
* `rv64`: 仅对 RISC-V 应用当前条目。
* `<empty>`: 对所有架构应用当前条目,但如果存在更具体的条目,当前条目将被替换。 [默认值]
### BOX64_AVX
向 CPUID 和 cpuinfo 文件暴露 AVX 扩展。在 Arm64 和龙架构上默认值为 2,因为 DynaRec 已完全实现,其他架构默认为 0。 在 WowBox64 中可用。
* 0: 不暴露 AVX 能力。
* 1: 向 CPUID 和 cpuinfo 文件暴露 AVX、BMI1、F16C 和 VAES 扩展。
* 2: 包含 1 的全部内容,外加 AVX2、BMI2、FMA、ADX、VPCLMULQDQ 和 RDRAND 扩展。
### BOX64_BASH
用于指定 bash 可执行文件的路径。
* XXXX: 使用路径为 XXXX 的 bash 可执行文件。
### BOX64_CPUTYPE
指定要模拟的 CPU 类型。 在 WowBox64 中可用。
* 0: 模拟某个 Intel CPU 型号。 [默认值]
* 1: 模拟某个 AMD CPU 型号。
### BOX64_CRASHHANDLER
是否使用模拟的 crashhandler.so 库。
* 0: 在需要时使用模拟的 crashhandler.so 库。
* 1: 使用内部定义的空 crashhandler.so 库。 [默认值]
### BOX64_DYNAREC_BLEEDING_EDGE
检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。
* 0: 不检测 MonoBleedingEdge。
* 1: 检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_STRONGMEM=1。 [默认值]
### BOX64_DYNAREC_DIV0
启用或禁用除零异常的生成。 在 WowBox64 中可用。
* 0: 不生成除零异常。 [默认值]
* 1: 生成除零异常。
### BOX64_DYNAREC_TBB
启用或禁用 libtbb 检测。
* 0: 不检测 libtbb。
* 1: 检测 libtbb 并应用保守设置。 [默认值]
### BOX64_DYNAREC_X87DOUBLE
强制使用 float/double 进行 x87 模拟。 在 WowBox64 中可用。
* 0: 尝试在可能的情况下对 x87 模拟使用 float。 [默认值]
* 1: 仅对 x87 模拟使用 Double。
* 2: 在 x87 模拟中检查精度控制的低精度。
### BOX64_DYNAREC_INTERP_SIGNAL
允许在信号处理器中使用 DynaRec。
* 0: 允许在信号处理器中使用 DynaRec。 [默认值]
* 1: 仅在信号处理器中使用解释器(与 v0.3.8 及更早版本相同)。
### BOX64_EXIT
直接退出,不运行程序。
* 0: 不执行任何操作。 [默认值]
* 1: 直接退出。
### BOX64_FIX_64BIT_INODES
修复 64 位 inode。
* 0: 不修复 64 位 inode。 [默认值]
* 1: 修复 64 位 inode。
### BOX64_FORCE_LD_PRELOAD
是否强制 BOX64_LD_PRELOAD 库中的符号通过 RTLD_NEXT 解析。
* 0: 不执行任何操作。 [默认值]
* 1: 强制 BOX64_LD_PRELOAD 库中的符号通过 RTLD_NEXT 解析。
### BOX64_IGNOREINT3
忽略 INT3 指令。
* 0: 如果存在处理器则触发 TRAP 信号。 [默认值]
* 1: 静默跳过该指令。
### BOX64_JVM
检测 libjvm 并应用保守设置。
* 0: 不执行任何操作。
* 1: 检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0。 [默认值]
### BOX64_LIBCEF
检测 libcef 并应用 BOX64_MALLOC_HACK 设置。
* 0: 不执行任何操作。 [默认值]
* 1: 检测 libcef,并在检测到时应用 BOX64_MALLOC_HACK=2。
### BOX64_MALLOC_HACK
挂钩 malloc 操作符时的行为。
* 0: 不允许重定向 malloc 操作符,重写代码使用常规函数。 [默认值]
* 1: 允许重定向 malloc 操作符。
* 2: 与 0 类似,但追踪特殊的 mmap/free(某些内联的重定向函数无法被重定向)。
### BOX64_MAXCPU
暴露的最大 CPU 核心数。 在 WowBox64 中可用。
* 0: 使用实际的 CPU 核心数。 [默认值]
* XXXX: 使用 XXXX 个 CPU 核心。
### BOX64_NORCFILES
不加载任何 rc 文件。
* 0: 加载 rc 文件。 [默认值]
* 1: 不加载任何 rc 文件。
### BOX64_PATH
查找 x86_64 二进制文件的路径。
* XXXX: 将路径 XXXX 添加到二进制搜索路径。
### BOX64_PCLMULQDQ
暴露 PCLMULQDQ 能力。 在 WowBox64 中可用。
* 0: 不暴露 PCLMULQDQ 能力。
* 1: 暴露 PCLMULQDQ 能力。 [默认值]
### BOX64_PROFILE
预定义的环境变量集合,以兼容性或性能为导向。 在 WowBox64 中可用。
* safest: 禁用所有不安全的优化。
* safe: 仅启用小部分不安全的优化。
* default: 大多数程序都能正常运行且性能适中的默认设置。 [默认值]
* fast: 启用许多不安全的优化,但同时启用强内存模型模拟。
* fastest: 启用许多不安全的优化以获得更好的性能。
### BOX64_PYTHON3
python3 可执行文件的路径。
* XXXX: 使用路径为 XXXX 的 python3 可执行文件。
### BOX64_RCFILE
要加载的 rc 文件路径。
* XXXX: 加载 rc 文件 XXXX,不会加载默认的 rc 文件。
### BOX64_RDTSC_INV
在 Intel CPU 类型的 CPUID 中报告 Invariant TSC 位。 在 WowBox64 中可用。
* 0: 不为 Intel CPU 类型报告 Invariant TSC(默认)。 [默认值]
* 1: 在 Intel CPU 类型的 CPUID leaf 0x80000007 中报告 Invariant TSC 位。
### BOX64_RESERVE_HIGH
为程序保留高内存区域,在 Box32 上始终启用。
* 0: 不为程序保留高内存区域。 [默认值]
* 1: 为程序保留高内存区域。
### BOX64_SDL2_JGUID
对包装的 SDL2 使用 SDL_GetJoystickGUIDInfo 函数的变通方案。
* 0: 不执行任何操作。 [默认值]
* 1: 对包装的 SDL2 使用 SDL_GetJoystickGUIDInfo 函数的变通方案。
### BOX64_SHAEXT
暴露 SHAEXT(即 SHA_NI)能力。 在 WowBox64 中可用。
* 0: 不暴露 SHAEXT 能力。
* 1: 暴露 SHAEXT 能力。 [默认值]
### BOX64_SSE_FLUSHTO0
SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常 FLAGS。 在 WowBox64 中可用。
* 0: 仅追踪 FLAGS。 [默认值]
* 1: 直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常 FLAGS(如果可用)。
### BOX64_SSE42
暴露 SSE4.2 能力。 在 WowBox64 中可用。
* 0: 不暴露 SSE4.2 能力。
* 1: 暴露 SSE4.2 能力。 [默认值]
### BOX64_STEAM_VULKAN
为 Linux Steam UI 强制使用 Vulkan。
* 0: 不执行任何操作。 [默认值]
* 1: 为 Linux Steam UI 强制使用 Vulkan。
### BOX64_SYNC_ROUNDING
在 x86 和原生之间同步舍入模式。
* 0: 不同步舍入模式。 [默认值]
* 1: 在 x86 和原生之间同步舍入模式。
### BOX64_UNITYPLAYER
检测 UnityPlayer 并应用保守设置。
* 0: 不执行任何操作。
* 1: 检测 UnityPlayer(Windows 或 Linux),并在检测到时应用 BOX64_UNITY=1。 [默认值]
### BOX64_UNITY
告诉 Box64 这是一个 Unity 游戏。
* 0: 不执行任何操作。
* 1: 这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_STRONGMEM=1。 [默认值]
### BOX64_X11GLX
是否强制 Xorg GLX 扩展存在。
* 0: 不强制 Xorg GLX 扩展存在。 [默认值]
* 1: 在使用 XQueryExtension 时要求 Xorg GLX 扩展存在。
### BOX64_X11SYNC
是否强制 X11 显示同步操作。
* 0: 不强制 X11 显示同步操作。 [默认值]
* 1: 强制 X11 显示同步操作。
### BOX64_X11THREADS
加载 X11 时调用 XInitThreads。这主要用于使用 Loki_Compat 库的旧 Loki 游戏。
* 0: 不调用 XInitThreads。 [默认值]
* 1: 一旦加载 libX11 就调用 XInitThreads。
### BOX64_X87_NO80BITS
x87 80 位 long double 的行为。 在 WowBox64 中可用。
* 0: 尝试尽可能精确地处理 80 位 long double。 [默认值]
* 1: 对 x87 使用 64 位 double。
### BOX64_NOPERSONA32BITS
禁用 32 位二进制文件的自动 personality 切换(在 Box32 上始终启用)。
* 0: 为 32 位二进制文件切换 personality(如果尚未尝试)。 [默认值]
* 1: 不为 32 位二进制文件切换 personality。
## 参数
### BOX64_ARGS
传递给目标程序的参数,仅在没有任何已有参数时有效。
* XXXX: 将 XXXX 参数传递给目标程序。
* XXXX YYYY ZZZZ: 将 XXXX、YYYY 和 ZZZZ 参数传递给目标程序。
### BOX64_INSERT_ARGS
在命令行前添加参数。
* XXXX: 在程序前添加参数 XXXX。
* XXXX YYYY ZZZZ: 在目标程序前添加参数 XXXX、YYYY 和 ZZZZ。
### BOX64_INPROCESSGPU
向目标程序添加 --in-process-gpu 参数。
* 0: 不执行任何操作。 [默认值]
* 1: 向目标程序添加 --in-process-gpu 参数。
### BOX64_NOSANDBOX
向目标程序添加 --no-sandbox 参数。
* 0: 不执行任何操作。 [默认值]
* 1: 向目标程序添加 --no-sandbox 参数。
## 库
### BOX64_ADDLIBS
添加额外需要的共享库(这个选项不太常用)。
* XXXX: 将 XXXX 共享库添加到所需库列表。
* XXXX:YYYY:ZZZZ: 将 XXXX、YYYY 和 ZZZZ 共享库添加到所需库列表。
### BOX64_ALLOWMISSINGLIBS
是否允许忽略缺失的共享库。
* 0: 不允许忽略缺失的共享库。 [默认值]
* 1: 允许忽略缺失的共享库。
### BOX64_EMULATED_LIBS
强制使用模拟库。
* XXXX: 强制使用模拟库 XXXX。
* XXXX:YYYY:ZZZZ: 强制使用模拟库 XXXX、YYYY 和 ZZZZ。
### BOX64_LD_LIBRARY_PATH
查找 x86_64 库的路径。
* XXXX: 将路径 XXXX 添加到库搜索路径。
### BOX64_LD_PRELOAD
强制随二进制文件加载库。
* XXXX: 强制加载库 XXXX。
* XXXX:YYYY: 强制加载库 XXXX 和 YYYY。
### BOX64_LIBGL
设置 libGL 的名称。
* libXXXX: 将 libGL 的名称设置为 libXXXX。
* /path/to/libXXXX: 将 libGL 的名称和路径设置为 /path/to/libXXXX,你也可以使用 SDL_VIDEO_GL_DRIVER。
### BOX64_NOGTK
不加载包装的 GTK 库。
* 0: 加载包装的 GTK 库。 [默认值]
* 1: 不加载包装的 GTK 库。
### BOX64_NOPULSE
不加载 PulseAudio 库(原生库和模拟库均不加载)。
* 0: 加载 PulseAudio 库。 [默认值]
* 1: 不加载 PulseAudio 库。
### BOX64_NOVULKAN
不加载 Vulkan 库。
* 0: 加载 Vulkan 库。 [默认值]
* 1: 不加载 Vulkan 库,原生库和模拟库均不加载。
### BOX64_NOVULKANOVERLAY
不加载 x64 Vulkan 覆盖层。
* 0: 尝试加载 x64 Vulkan 覆盖层。 [默认值]
* 1: 不加载 x64 Vulkan 覆盖层。
### BOX64_PREFER_EMULATED
优先使用模拟库而非原生库。
* 0: 优先使用原生库而非模拟库。 [默认值]
* 1: 优先使用模拟库而非原生库。
### BOX64_PREFER_WRAPPED
即使库使用绝对路径指定,也优先使用包装库。
* 0: 优先使用绝对路径指定的库而非包装库。 [默认值]
* 1: 即使库使用绝对路径指定,也优先使用包装库。
### BOX64_WRAP_EGL
优先使用包装库处理 EGL 和 GLESv2。
* 0: 优先使用模拟库处理 EGL 和 GLESv2。 [默认值]
* 1: 优先使用包装库处理 EGL 和 GLESv2。
## 环境变量
### BOX64_ENV
添加环境变量。
* XXXX=yyyy: 添加值为 yyyy 的环境变量 XXXX。
### BOX64_ENV[1-5]
添加环境变量。
* XXXX=yyyy: 添加值为 yyyy 的环境变量 XXXX。
## 调试
### BOX64_DLSYM_ERROR
启用或禁用 dlsym 错误的日志记录。
* 0: 禁用 dlsym 错误的日志记录。 [默认值]
* 1: 启用 dlsym 错误的日志记录。
### BOX64_DUMP
是否输出 elfloader 调试信息。 在 WowBox64 中可用。
* 0: 不输出 elfloader 调试信息。 [默认值]
* 1: 输出 elfloader 调试信息。
### BOX64_DYNAREC_DUMP
启用 DynaRec 转储。 在 WowBox64 中可用。
* 0: 不转储代码块。 [默认值]
* 1: 转储代码块。
* 2: 转储代码块并带有颜色。
* 3: 仅转储 x86 指令和翻译后的本机指令。
### BOX64_DYNAREC_DUMP_RANGE
转储指定范围内的代码块。 在 WowBox64 中可用。
* 0xXXXXXXXX-0xYYYYYYYY: 定义代码块 被转储的范围(左闭右开)。
### BOX64_DYNAREC_DISASM
尝试初始化 libZydis,以在转储、追踪、崩溃报告等场景中获得更具可读性的 x86 反汇编结果。
* 0: 不为 Dynarec 加载 Zydis。 [默认值]
* 1: 尝试为 Dynarec 加载 Zydis。
### BOX64_DYNAREC_GDBJIT
GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb 命令启用:jit-reader-load /usr/local/lib/libbox64gdbjitreader.so。
* 0: DynaRec 不会生成 GDBJIT 调试信息。 [默认值]
* 1: DynaRec 将生成 GDBJIT 调试信息。
* 2: DynaRec 将生成包含内部状态的详细 GDBJIT 调试信息。
* 3: DynaRec 将仅对目标程序陷入的代码块 注册详细的 GDBJIT 调试信息,大幅提升性能。
* 0xXXXXXXX-0xYYYYYYY: 定义 DynaRec 将生成包含内部状态的详细 GDBJIT 调试信息的范围。
### BOX64_DYNAREC_LOG
禁用或启用 DynaRec 日志。 在 WowBox64 中可用。
* 0: 禁用 DynaRec 日志。 [默认值]
* 1: 启用最小级别的 DynaRec 日志。
* 2: 启用调试级别的 DynaRec 日志。
* 3: 启用详细级别的 DynaRec 日志。
### BOX64_DYNAREC_MISSING
打印缺失的指令。 在 WowBox64 中可用。
* 0: 不打印缺失的指令。 [默认值]
* 1: 打印缺失的指令。
* 2: 打印回退到标量指令的信息,仅对 RISC-V 有效。
### BOX64_DYNAREC_NOHOSTEXT
禁用可选的主机扩展。
* 0: 不禁用任何扩展。 [默认值]
* 1: 禁用所有可选扩展。
* xxx,yyy,zzz: 禁用指定的可选扩展,可选项包括 Arm:`crc32,pmull,aes,atomics,sha1,sha2,uscat,flagm,flagm2,frintts,afp,rndr`,LoongArch:`lasx,lbt,frecipe,lam_bh,lamcas,scq`,以及 RISC-V:`zba,zbb,zbc,zbs,vector,xtheadba,xtheadbb,xtheadbs,xtheadmemidx,xtheadmempair,xtheadcondmov`。
### BOX64_DYNAREC_PERFMAP
为 Linux perf 工具生成映射文件。
* 0: DynaRec 不会生成 perf 映射。 [默认值]
* 1: DynaRec 将生成 perf 映射。
### BOX64_DYNAREC_TEST
启用 DynaRec 与解释器的执行对比,非常慢,仅用于测试。 在 WowBox64 中可用。
* 0: 不进行对比。 [默认值]
* 1: 每个指令都在解释器和 DynaRec 上运行,当寄存器或内存不同时进行对比并打印。
* 0xXXXXXXXX-0xYYYYYYYY: 定义 DynaRec 测试的范围(左闭右开)。
### BOX64_DYNAREC_TEST_NODUP
启用 COSIM 发现差异的 IP 地址去重。 在 WowBox64 中可用。
* 0: 显示所有出错的地址。 [默认值]
* 1: 每个出错地址仅显示一次,即使转储可能不同。
### BOX64_DYNAREC_TEST_NODUMP
当 BOX64_DYNAREC_DUMP 启用时不转储测试代码。 在 WowBox64 中可用。
* 0: 转储测试代码。
* 1: 不转储测试代码。 [默认值]
### BOX64_DYNAREC_TRACE
启用或禁用 DynaRec 追踪。
* 0: 不追踪代码块。 [默认值]
* 1: 追踪代码块,会大幅降低程序速度并生成大量日志。
### BOX64_JITGDB
发生 SIGSEGV、SIGILL 和 SIGBUS 时是否启动 gdb。
* 0: 捕获信号时仅打印消息。 [默认值]
* 1: 当捕获到 SIGSEGV、SIGILL 或 SIGBUS 信号时启动 gdb,附加到有问题的进程并进入无限循环等待。在 gdb 中,你需要自己找到正确的线程(在其堆栈中有 `my_box64signalhandler` 的线程),然后可能需要 `finish` 1 或 2 个函数(在 `usleep(..)` 内部),之后你将进入 `my_box64signalhandler`,就在 Segfault 消息的 printf 之前。然后 `set waiting=0` 退出无限循环。
* 2: 当捕获到 SIGSEGV、SIGILL 或 SIGBUS 信号时启动 gdbserver,附加到有问题的进程,并进入无限循环等待。使用 `gdb /PATH/TO/box64` 然后 `target remote 127.0.0.1:1234` 连接到 gdbserver(如果不在本机,则使用实际 IP)。之后的操作步骤与 `BOX64_JITGDB=1` 相同。
* 3: 当捕获到 SIGSEGV、SIGILL 或 SIGBUS 信号时启动 lldb,附加到有问题的进程并进入无限循环等待。
### BOX64_LOAD_ADDR
设置程序加载的地址,仅对 PIE 目标程序有效。
* 0xXXXXXXXX: 设置程序加载的地址。
### BOX64_LOG
启用或禁用 Box64 日志,如果 stdout 不是终端则默认为 0,否则为 1。 在 WowBox64 中可用。
* 0: 禁用 Box64 日志。
* 1: 启用最小级别的 Box64 日志。
* 2: 启用调试级别的 Box64 日志。
* 3: 启用详细级别的 Box64 日志。
### BOX64_NOBANNER
禁用 Box64 横幅。 在 WowBox64 中可用。
* 0: 显示 Box64 横幅。
* 1: 不显示 Box64 横幅。
### BOX64_NODYNAREC
在指定的地址范围内禁止创建代码块,有助于调试 DynaRec 和解释器之间的行为差异。 在 WowBox64 中可用。
* 0xXXXXXXXX-0xYYYYYYYY: 定义禁止创建代码块 的范围(左闭右开)。
### BOX64_NODYNAREC_DELAY
延迟后移除 NoDynaRec 范围。 在 WowBox64 中可用。
* 0: 不移除 NoDynaRec 范围。 [默认值]
* 1: 创建 2 个线程后移除 NoDynaRec 范围。
### BOX64_NOSIGSEGV
禁用 SIGSEGV 的处理。
* 0: 允许 x86 程序为 SIGSEGV 设置信号处理器。 [默认值]
* 1: 禁用 SIGSEGV 的处理。
### BOX64_NOSIGILL
禁用 SIGILL 的处理。
* 0: 允许 x86 程序为 SIGILL 设置信号处理器。 [默认值]
* 1: 禁用 SIGILL 的处理。
### BOX64_ROLLING_LOG
当捕获信号时显示最近几个包装函数调用。
* 0: 不执行任何操作。 [默认值]
* 1: 捕获信号时显示最近 16 个包装函数调用。
* XXXX: 捕获信号时显示最近 XXXX 个包装函数调用。
### BOX64_SHOWBT
捕获信号时显示原生和模拟的回溯。
* 0: 不执行任何操作。 [默认值]
* 1: 捕获信号时显示原生和模拟的回溯。
### BOX64_SHOWSEGV
始终显示 SIGSEGV 信号详情。
* 0: 不执行任何操作。 [默认值]
* 1: 始终显示 SIGSEGV 信号详情。
### BOX64_TRACE_COLOR
启用或禁用彩色追踪输出。
* 0: 禁用彩色追踪输出。 [默认值]
* 1: 启用彩色追踪输出。
### BOX64_TRACE_EMM
启用或禁用 EMM(即 MMX)追踪输出。
* 0: 禁用 EMM 追踪输出。 [默认值]
* 1: 启用 EMM 追踪输出。
### BOX64_TRACE_FILE
将所有日志和追踪发送到文件而非 `stdout`。
* XXXX: 将所有日志和追踪发送到文件 XXXX。
* XXXX%pid: 将所有日志和追踪发送到文件 XXXX,文件名中附加 pid。
* stderr: 将所有日志和追踪发送到 `stderr`。 [默认值]
* stdout: 将所有日志和追踪发送到 `stdout`。
### BOX64_TRACE_INIT
与 BOX64_TRACE 相同,但立即开始追踪。
* 0: 禁用追踪输出。 [默认值]
* 1: 启用追踪输出。追踪在依赖项初始化之前开始。
* symbolname: 仅对 `symbolname` 启用追踪输出。追踪在依赖项初始化之前开始。
* 0xXXXXXXX-0xYYYYYYY: 对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: 对指定的地址列表启用追踪输出。追踪在依赖项初始化之前开始。
### BOX64_TRACE_START
在 N 个指令执行后开始追踪。
* 0: 立即开始追踪。 [默认值]
* 1: 执行 1 个指令后开始追踪。
* XXXX: 执行 XXXX 个指令后开始追踪。
### BOX64_TRACE_XMM
启用或禁用 XMM(即 SSE)追踪输出。
* 0: 禁用 XMM 追踪输出。 [默认值]
* 1: 启用 XMM 追踪输出。
### BOX64_TRACE
仅在带追踪功能的 box64 构建中可用。添加所有执行指令的追踪以及寄存器转储。
* 0: 禁用追踪输出。 [默认值]
* 1: 启用追踪输出。
* symbolname: 仅对 `symbolname` 启用追踪输出。
* 0xXXXXXXX-0xYYYYYYY: 对指定地址范围(左闭右开)启用追踪输出。
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: 对指定地址列表启用追踪输出。
+53
View File
@@ -0,0 +1,53 @@
# 在 Box64 上使用 Wine 的指南
Wine 不是一个模拟器,但 Box64 是。Box64 以多种方式支持 Wine。在继续阅读之前,你应该对 Wine 有基本的了解。
## Wine 的变体
Wine 以多种形式发布:
1. **x86 Wine**
**x86 Wine** 的可执行文件架构是 x86,它运行 x32 Windows 可执行文件。
x86 Wine 需要 32 位环境(读取 32 位 Linux 库),因为该架构天然的特点,这在 x86_64 机器上通常可用。
但是,当你尝试在 RISC 架构上通过模拟器运行它时,情况则有些不同。对于 Arm64,存在 armhf 这样的 32 位环境,也有为 armhf 设计的 Box86,因此你可以使用 Box86 运行 **x86 Wine**。
然而,对于 RISC-V 64、LoongArch64 以及许多较新的 Arm64 核心,32 位环境并不可用。Box64 引入了一种名为 Box32 的新模式,可以在编译时通过 CMake 选项 `BOX32` 启用。它本质上利用 64 位环境模拟 32 位环境,因此可以用来运行 x86 Wine。但请注意,Box32 仍是高度实验性且不稳定的。
2. **x86_64 Wine**
**x86_64 Wine** 的可执行文件架构是 x86_64,它运行 x64 Windows 可执行文件。
它可以与 Box64 配合使用。注意,**x86_64 Wine** 通常自带 **x86 Wine**。因此你可以结合使用 Box86 + Box64,或者仅使用启用了 Box32 的 Box64,来无缝运行 32 位和 64 位可执行文件。
3. **x86_64 Wine WOW64**
**x86_64 Wine WOW64** 的可执行文件架构是 x86_64,它同时能运行 x32 和 x64 Windows 可执行文件。
**x86_64 Wine WOW64** 的优点在于它运行 32 位 Windows 可执行文件时不需要 32 位环境,因为 32 位环境模拟已由 Wine WOW64 自身处理。
这意味着你可以只使用 Box64(无需 Box32)来运行 32 位 Windows 可执行文件。然而缺点是,对于 32 位程序,WineD3D 的性能相当差(请使用 DXVK!)。
4. **Arm64 Wine WOW64**
**Arm64 Wine WOW64** 的可执行文件架构是 Arm64,它能运行 x32、x64、Arm32 和 Arm64 的 Windows 可执行文件。
但是,要运行 x32 和 x64 的程序,需要一个 cpu.dll,也就是所谓的 WOW64(用于 32 位)和 Arm64EC(用于 64 位)。
Box64 现已支持 32 位 WOW64 DLL。你可以通过编译时启用 `WOW64` CMake 选项来启用它。我们计划在未来支持 Arm64EC。
## Wine 的安装
对于 x86 Wine,有很多下载渠道,略举几例:
- https://github.com/Kron4ek/Wine-Builds (Wine \[WOW64\])
- https://github.com/GloriousEggroll/proton-ge-custom (Proton,即 Valve 优化过的 Wine)
下载后,只需以你喜欢的方式将 `bin` 文件夹添加到 `PATH` 环境变量中;Wine 应该能很好地与 Box64 配合工作。
要安装 DXVK、d3dcompiler_xx 或 cjkfonts 等组件,推荐使用 Winetricks:https://github.com/Winetricks/winetricks
对于 Arm64 Wine,推荐使用 Hangover:https://github.com/AndreRH/hangover
+108 -66
View File
@@ -44,6 +44,9 @@ Example:
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
The special C<[*]> section defines shared rcfile options for all applications.
More specific sections override only the options they define themselves.
=head1 ENVIRONMENT VARIABLES
=over 8
@@ -93,7 +96,7 @@ Arguments to pass to the guest program, only valid if there is no existing argum
=item B<BOX64_AVX> =I<0|1|2>
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 because it's fully implemented in DynaRec, 0 otherwise. Available in WowBox64.
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 and LoongArch64 because it's fully implemented in DynaRec, 0 otherwise. Available in WowBox64.
* 0 : Do not expose AVX capabilities.
* 1 : Expose AVX, BMI1, F16C and VAES extensions to CPUID and cpuinfo file.
@@ -160,9 +163,9 @@ Generate aligned atomics only (only available on Arm64 for now). Available in Wo
Enable building bigger DynaRec code blocks for better performance. Available 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.
* 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.
=item B<BOX64_DYNAREC_BLEEDING_EDGE> =I<0|1>
@@ -177,17 +180,17 @@ Detect MonoBleedingEdge and apply conservative settings (Linux only).
Optimize CALL/RET opcodes. Available in WowBox64.
* 0 : Do not optimize CALL/RET, use jump table. [Default]
* 0 : Do not optimize CALL/RET, use jump table.
* 1 : Try to optimize CALL/RET, skipping the jump table when possible.
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
=item B<BOX64_DYNAREC_SEP> =I<0|1|2>
Optimize CALL/RET further with Secondary Entry Points (SEP). Have no effect is CALLRET is not enabled Available in WowBox64.
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
* 0 : Do not add SEP at CALLRET return
* 1 : Add SEP at CALLRET return, on meory that are from known binary files [Default]
* 0 : Do not add SEP at CALLRET return [Default]
* 1 : Add SEP at CALLRET return, on memory that are from known binary files
* 2 : Add SEP at CALLRET return for all type of memory.
@@ -204,8 +207,8 @@ Enable or disable the use of deferred flags. Available in WowBox64.
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).
* 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 detects a HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but blocks built from that page will always be tested. It can be faster that way (but some SMC case might not be trapped).
=item B<BOX64_DYNAREC_NOHOTPAGE> =I<0|1>
@@ -216,14 +219,6 @@ Disable detection of hot page (where code is executed and data written at the sa
* 1 : Do not detect hot page
=item B<BOX64_DYNAREC_HOTPAGE_ALT> =I<0|1>
Use alternative way to detect HotPages (legacy way).
* 0 : Detect hot page, using new method from v0.3.9+ [Default]
* 1 : Use alternate method to detect HotPage (from v0.3.8 and earlier)
=item B<BOX64_DYNAREC_DIV0> =I<0|1>
Enable or disable the generation of division-by-zero exception. Available in WowBox64.
@@ -232,20 +227,29 @@ Enable or disable the generation of division-by-zero exception. Available in Wow
* 1 : Generate the division-by-zero exception.
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2>
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2|3>
Enable DynaRec dump. Available in WowBox64.
* 0 : Do not dump DynaRec blocks. [Default]
* 1 : Dump DynaRec blocks.
* 2 : Dump DynaRec blocks with some colors.
* 3 : Dump only x86 and translated native instructions.
=item B<BOX64_DYNAREC_DUMP_RANGE> =I<0xXXXXXXXX-0xYYYYYYYY>
Dump DynaRec blocks in the specified range. Available in WowBox64.
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where dynablock gets dumped (inclusive-exclusive).
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where DynaBlock gets dumped (inclusive-exclusive).
=item B<BOX64_DYNAREC_DISASM> =I<0|1>
Try to initialize libZydis for more readable x86 disassembly in dump, trace, crash report, etc.
* 0 : Do not load Zydis for Dynarec. [Default]
* 1 : Try to load Zydis for Dynarec.
=item B<BOX64_DYNAREC_FASTNAN> =I<0|1>
@@ -265,24 +269,26 @@ Enable or disable fast rounding. Available in WowBox64.
* 2 : Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|XXXX>
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|256|512|1024>
Define max allowed forward value when building block. Available in WowBox64.
Define max allowed forward value when building block. Only 0, 128, 256, 512 and 1024 are valid; other values fall back to 128. Available in WowBox64.
* 0 : No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
* 128 : Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
* XXXX : Allow up to XXXX bytes of gap between end of the block and the next forward jump.
* 256 : Allow up to 256 bytes of gap between end of the block and the next forward jump.
* 512 : Allow up to 512 bytes of gap between end of the block and the next forward jump.
* 1024 : Allow up to 1024 bytes of gap between end of the block and the next forward jump.
=item B<BOX64_DYNAREC_GDBJIT> =I<0|1|2|3|0xXXXXXXX-0xYYYYYYY>
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
* 0 : Dynarec will not generate GDBJIT debuginfo. [Default]
* 1 : Dynarec will generate GDBJIT debuginfo.
* 2 : Dynarec will generate detailed GDBJIT debuginfo with internal state.
* 3 : Dynarec will register detailed GDBJIT debuginfo only for dynablocks that the guest program trap into, greatly improving performance.
* 0xXXXXXXX-0xYYYYYYY : Define the range where Dynarec will generate detailed GDBJIT debuginfo with internal state.
* 0 : DynaRec will not generate GDBJIT debuginfo. [Default]
* 1 : DynaRec will generate GDBJIT debuginfo.
* 2 : DynaRec will generate detailed GDBJIT debuginfo with internal state.
* 3 : DynaRec will register detailed GDBJIT debuginfo only for DynaBlocks that the guest program trap into, greatly improving performance.
* 0xXXXXXXX-0xYYYYYYY : Define the range where DynaRec will generate detailed GDBJIT debuginfo with internal state.
=item B<BOX64_DYNAREC_LOG> =I<0|1|2|3>
@@ -335,21 +341,21 @@ Enable x86 PAUSE emulation, may help the performance of spinlocks. Available in
Generate map file for Linux perf tool.
* 0 : Dynarec will not generate perf map. [Default]
* 1 : Dynarec will generate perf map.
* 0 : DynaRec will not generate perf map. [Default]
* 1 : DynaRec will generate perf map.
=item B<BOX64_DYNAREC_PURGE> =I<0|1>
Purge dynablocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
* 0 : Dynarec will not purge old unused dynablocks. [Default]
* 1 : Dynarec will purge old unused dynablocks based on tick age.
* 0 : DynaRec will not purge old unused DynaBlocks. [Default]
* 1 : DynaRec will purge old unused DynaBlocks based on tick age.
=item B<BOX64_DYNAREC_PURGE_AGE> =I<4096|XXXX>
Tick age threshold for dynablock purging (requires BOX64_DYNAREC_PURGE=1).
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
* 4096 : Default age threshold. [Default]
* XXXX : Custom age threshold (range: 10-65536).
@@ -388,8 +394,8 @@ Enable or disable libtbb detection.
Enable DynaRec execution comparison with the interpreter, very slow, only for testing. Available in WowBox64.
* 0 : No comparison. [Default]
* 1 : Each opcode runs on interpreter and on Dynarec, regs and memory are compared and printed when they differ.
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where dynarec is tested (inclusive-exclusive).
* 1 : Each opcode runs on interpreter and on DynaRec, regs and memory are compared and printed when they differ.
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where DynaRec is tested (inclusive-exclusive).
=item B<BOX64_DYNAREC_TEST_NODUP> =I<0|1>
@@ -434,11 +440,11 @@ Wait or not for the building of a DynaRec code block to be ready. Available in W
=item B<BOX64_DYNAREC_WEAKBARRIER> =I<0|1|2>
Tweak the memory barriers to reduce the performance impact by strong memory emualtion. Available in WowBox64.
Tweak the memory barriers to reduce the performance impact by strong memory emulation. Available 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.
* 2 : All in 1, plus disable the last write barriers.
=item B<BOX64_DYNAREC_X87DOUBLE> =I<0|1|2>
@@ -452,19 +458,19 @@ Force the use of float/double for x87 emulation. Available in WowBox64.
=item B<BOX64_DYNAREC_INTERP_SIGNAL> =I<0|1>
Allow the use of Dynarec in Signal Handlers.
Allow the use of DynaRec in Signal Handlers.
* 0 : Allow the use of Dynarec in signal handlers. [Default]
* 0 : Allow the use of DynaRec in signal handlers. [Default]
* 1 : Only use the Interpreter for signal handlers (as it was in v0.3.8 and earlier).
=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.
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 1 (enable). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
* 0 : Disable DynaCache.
* 1 : Enable DynaCache.
* 2 : Use DynaCache files if present, but do not generate new one. [Default]
* 1 : Enable DynaCache. [Default]
* 2 : Use DynaCache files if present, but do not generate new one.
=item B<BOX64_DYNACACHE_FOLDER> =I<XXXX>
@@ -474,12 +480,30 @@ Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.c
* XXXX : Use folder XXXX for DynaCache files.
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|350>
=item B<BOX64_DYNACACHE_LIMIT> =I<0|XXXX|2048>
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
Maximum size, in MiB, for the DynaCache folder. When the limit is exceeded, invalid DynaCache files are removed first, then the oldest valid files are removed if needed. Default size is 2048MiB.
* 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]
* 0 : Do not limit the DynaCache folder size.
* XXXX : Keep the DynaCache folder below XXXX MiB by removing invalid cache files first, then the oldest valid cache files.
* 2048 : A size of 2048 MiB is the default value. [Default]
=item B<BOX64_DYNACACHE_COMPRESS> =I<0|1|2>
Compress or not DynaCache files on disk
* 0 : Do not compress dynacache files
* 1 : Compress dynacache files using Zlib with fastest compression. [Default]
* 2 : Compress dynacache files using ZLib with default compression.
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|30>
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 30KB
* XXXX : Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
* 30 : A size of 30 KB is the default value. [Default]
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
@@ -557,7 +581,7 @@ Add --in-process-gpu argument to the guest program.
Launch gdb or not for SIGSEGV, SIGILL, and SIGBUS.
* 0 : Just print the message when the signal is caught. [Default]
* 1 : Launch gdb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting. Inside gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack), then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then `set waiting=0` to exit the infinite loop.
* 1 : Launch gdb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting. Inside gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in its stack), then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then `set waiting=0` to exit the infinite loop.
* 2 : Launch gdbserver when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1: 1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with `BOX64_JITGDB=1`.
* 3 : Launch lldb when a SIGSEGV, SIGILL or SIGBUS signal is trapped, attached to the offending process and go in an endless loop, waiting.
@@ -635,6 +659,14 @@ Maximum CPU cores exposed. Available in WowBox64.
* XXXX : Use XXXX CPU cores.
=item B<BOX64_SKIPCPU> =I<0|XXXX>
Skip N first CPU cores (Is apply before MAXCPU) Available in WowBox64.
* 0 : Do not skip any CPU cores. [Default]
* XXXX : Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
=item B<BOX64_MMAP32> =I<0|1>
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
@@ -653,26 +685,26 @@ Disable the Box64 banner. Available in WowBox64.
=item B<BOX64_NODYNAREC> =I<0xXXXXXXXX-0xYYYYYYYY>
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter. Available in WowBox64.
Forbid DynaBlock creation in the address range specified, helpful for debugging behaviour difference between DynaRec and Interpreter. Available in WowBox64.
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where dynablock creation is forbidden (inclusive-exclusive).
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where DynaBlock creation is forbidden (inclusive-exclusive).
=item B<BOX64_NODYNAREC_DELAY> =I<0|1>
Remove NoDynarec range after a delay. Available in WowBox64.
Remove NoDynaRec range after a delay. Available in WowBox64.
* 0 : Do not remove NoDynarec range. [Default]
* 1 : Remove the NoDynarec range once 2 threads have been created.
* 0 : Do not remove NoDynaRec range. [Default]
* 1 : Remove the NoDynaRec range once 2 threads have been created.
=item B<BOX64_DYNAREC_NOARCH> =I<0|1|2>
Remove Architecture metatdata from Dynarec blocks (used on signal). Available in WowBox64.
Remove Architecture metadata from DynaRec blocks (used on signal). Available in WowBox64.
* 0 : Generate all architecture metadata for each blocks, including x87/mmx/SSE/AVX regs tracking. Wil use some more memory. [Default]
* 1 : Generate only essential metadata for each blocks (flags, alignments), saving some memory, but some encrypted software might fails.
* 2 : Do not generate metadata for blocks. Saving a bit more memory but might fails on signal handling.
* 0 : Generate all architecture metadata for each blocks, including x87/mmx/SSE/AVX regs tracking. Will use some more memory. [Default]
* 1 : Generate only essential metadata for each blocks (flags, alignments), saving some memory, but some encrypted software might fail.
* 2 : Do not generate metadata for blocks. Saving a bit more memory but might fail on signal handling.
=item B<BOX64_NOGTK> =I<0|1>
@@ -735,7 +767,7 @@ Do not load Vulkan libraries.
Do not load x64 Vulkan overlay.
* 0 : Do try to Load x64 Vulkan overlay. [Default]
* 0 : Try to load x64 Vulkan overlay. [Default]
* 1 : Do not load x64 Vulkan overlay.
@@ -805,7 +837,7 @@ Use hardware counter for rdtsc if available.
=item B<BOX64_RDTSC_INV> =I<0|1>
Report Invariant TSC bit in CPUID for Intel CPU type.
Report Invariant TSC bit in CPUID for Intel CPU type. Available in WowBox64.
* 0 : Do not report Invariant TSC for Intel CPU type (default). [Default]
* 1 : Report Invariant TSC bit in CPUID leaf 0x80000007 for Intel CPU type.
@@ -854,10 +886,10 @@ Show native and emulated backtrace when a signal is caught.
=item B<BOX64_SHOWSEGV> =I<0|1>
Always show SIGSEGV signal detailes.
Always show SIGSEGV signal details.
* 0 : Does nothing. [Default]
* 1 : Always show SIGSEGV signal detailes.
* 1 : Always show SIGSEGV signal details.
=item B<BOX64_SSE_FLUSHTO0> =I<0|1>
@@ -865,7 +897,7 @@ Always show SIGSEGV signal detailes.
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags. Available in WowBox64.
* 0 : Just track the flag. [Default]
* 1 : Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
* 1 : Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in DynaRec (if available)
=item B<BOX64_SSE42> =I<0|1>
@@ -918,7 +950,7 @@ Send all log and trace to a file instead of `stdout`.
* stdout : Send all log and trace to `stdout`.
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY|0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ>
Same as BOX64_TRACE but starts the trace immediately.
@@ -926,6 +958,7 @@ Same as BOX64_TRACE but starts the trace immediately.
* 1 : Enable trace output. Trace starts before the initialization of dependencies.
* symbolname : Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ : Enable trace output only for the specified address list. Trace starts before the initialization of dependencies.
=item B<BOX64_TRACE_START> =I<0|1|XXXX>
@@ -945,7 +978,7 @@ Enable or disable XMM (i.e. SSE) trace output.
* 1 : Enable XMM trace output.
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY|0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ>
Only available on box64 build with trace. Adds trace of all instructions executed, along with a register dump.
@@ -953,6 +986,7 @@ Only available on box64 build with trace. Adds trace of all instructions execute
* 1 : Enable trace output.
* symbolname : Enable trace output for `symbolname` only.
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive).
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ : Enable trace output only for the specified address list.
=item B<BOX64_UNITYPLAYER> =I<0|1>
@@ -1005,12 +1039,20 @@ Call XInitThreads when loading X11. This is mostly for old Loki games with the L
=item B<BOX64_X87_NO80BITS> =I<0|1>
Behavoiur of x87 80bits long double. Available in WowBox64.
Behaviour of x87 80bits long double. Available in WowBox64.
* 0 : Try to handle 80bits long double as precise as possible. [Default]
* 1 : Use 64bits double for x87.
=item B<BOX64_NOPERSONA32BITS> =I<0|1>
Disable the automatic switch of personality for 32-bit binaries (always enabled on Box32).
* 0 : Switch personality for 32-bit binaries (if not already tried). [Default]
* 1 : Do not switch personality for 32-bit binaries.
=back
=cut
+149 -34
View File
@@ -8,17 +8,18 @@ from collections import defaultdict
script_dir = os.path.dirname(os.path.abspath(__file__))
usage_file = os.path.join(script_dir, 'usage.json')
with open(usage_file, 'r') as file:
data = json.load(file)
with open(os.path.join(script_dir, '../USAGE.md'), 'w') as md_file:
md_file.write("""<!--- This file is generated by gen.py, do not edit it directly. -->
# Language definitions — add a key here and a corresponding usage_<lang>.json
# (if translations are needed) to add a new language.
LANG = {
"en": {
"suffix": "",
"preamble": """<!--- This file is generated by gen.py, do not edit it directly. -->
Usage
----
There are many environment variables to control Box64's behaviour, which will be listed below by category.
There are 2 types of Box64 builds: the Wine WOW64 build (WowBox64) and the regular Linux build. Beware only some of the environment variables are available in WowBox64.
There are 2 types of Box64 builds: the Wine WOW64 build (WowBox64) and the regular Linux build. Note that only some of the environment variables are available in WowBox64.
### Configuration files
@@ -38,15 +39,20 @@ BOX64_DYNAREC_CALLRET=1
This configuration will apply the specified settings application-wide to any executable named `factorio`.
Shared options can also be defined in a special `[*]` section. Those settings apply globally, and any more specific section only overrides the options it defines itself.
### Advanced usage for Linux build
1. **Wildcard Matching**
Asterisks (`*`) can be used for basic pattern matching in application names. For instance, `[*setup*]` will match any program containing "setup" in its name. Note this implements simple wildcard matching rather than full regex support.
2. **Custom Configuration File**
Asterisks (`*`) can be used for basic pattern matching in application names. For instance, `[*setup*]` will match any program containing "setup" in its name. Note that this implements simple wildcard matching rather than full regex support.
2. **Shared Settings**
The special `[*]` section defines shared rcfile options for all applications. Unlike wildcard sections such as `[*setup*]`, this is a dedicated global section.
3. **Custom Configuration File**
The `BOX64_RCFILE` environment variable can specify an alternative configuration file instead of the default `/etc/box64.box64rc`.
3. **Per-File Settings**
4. **Per-File Settings**
Sections starting with `/` apply to specific files. For example:
```
@@ -57,25 +63,130 @@ This configuration will apply the specified settings application-wide to any exe
----
""")
""",
"wine": "Available in WowBox64.",
"default": "[Default]",
"top_cat": "Performance",
"categories": {},
},
"cn": {
"suffix": "_CN",
"preamble": """<!--- 此文件由 gen.py 自动生成,请勿直接编辑。 -->
使用说明
----
categories = defaultdict(list)
for entry in data:
categories[entry["category"]].append(entry)
Box64 有许多环境变量可用于控制其行为,下面将按类别列出。
# Put "Performance" at the top, then sort the rest alphabetically
sorted_categories = sorted(categories.items(), key=lambda x: (x[0] != "Performance", x[0]))
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']}{' Available in WowBox64.' if entry['wine'] else ''}\n\n")
for option in entry['options']:
md_file.write(f" * {option['key']}: {option['description']} {'[Default]' if option['default'] else ''}\n")
md_file.write("\n")
Box64 有两种构建类型:Wine WOW64 构建(WowBox64)和常规 Linux 构建。请注意,只有部分环境变量在 WowBox64 中可用。
### 配置文件
除了环境变量之外,如果你使用的是常规 Linux 构建,Box64 默认还会在两个位置查找 rcfile:系统范围的 `/etc/box64.box64rc` 和用户目录下的 `~/.box64rc`。
而在 WowBox64 中,配置文件仅在 `%USERPROFILE%/.box64rc` 处检查。
设置的优先级如下(从高到低):`~/.box64rc` > `/etc/box64.box64rc` > 环境变量。
配置示例:
```
[factorio]
BOX64_DYNAREC_SAFEFLAGS=0
BOX64_DYNAREC_BIGBLOCK=2
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
```
此配置将使所有名为 `factorio` 的可执行文件应用指定的设置。
共享选项也可以定义在特殊的 `[*]` 配置段中。这些设置会全局应用,而更具体的配置段只会覆盖它自己显式定义的选项。
### Linux 构建的高级用法
1. **通配符匹配**
可以使用星号(`*`)对应用程序名称进行基本的模式匹配。例如,`[*setup*]` 将匹配名称中包含 "setup" 的任何程序。请注意,这里实现的是简单的通配符匹配,而非完整的正则表达式支持。
2. **共享设置**
特殊的 `[*]` 配置段可为所有应用程序定义共享的 rcfile 选项。它不同于 `[*setup*]` 这类通配符配置段,是一个专用的全局配置段。
3. **自定义配置文件**
`BOX64_RCFILE` 环境变量可以指定一个替代的配置文件,而不是默认的 `/etc/box64.box64rc`。
4. **按文件设置**
以 `/` 开头的配置项适用于特定文件。例如:
```
[/d3d9.dll]
BOX64_DYNAREC_SAFEFLAGS=0
```
这些设置将仅影响 `d3d9.dll` 文件。此语法同样适用于**模拟的** Linux 库,例如 `[/libstdc++.so.6]`。
----
""",
"wine": "在 WowBox64 中可用。",
"default": "[默认值]",
"top_cat": "性能",
"categories": {
"Performance": "性能",
"Arguments": "参数",
"Compatibility": "兼容性",
"Debugging": "调试",
"Environment": "环境变量",
"Libraries": "库",
"Fragile or Legacy": "不稳定或遗留选项",
},
},
}
with open(os.path.join(script_dir, '../box64.pod'), 'w') as pod_file:
pod_file.write("""=head1 NAME
def write_md(data, lang, t_data=None):
L = LANG[lang]
out_path = os.path.join(script_dir, f'../USAGE{L["suffix"]}.md')
with open(out_path, 'w') as md_file:
md_file.write(L['preamble'])
categories = defaultdict(list)
for entry in data:
entry = dict(entry)
entry['category'] = L['categories'].get(entry['category'], entry['category'])
categories[entry["category"]].append(entry)
sorted_categories = sorted(categories.items(), key=lambda x: (x[0] != L['top_cat'], x[0]))
for category, entries in sorted_categories:
md_file.write(f"## {category}\n\n")
for entry in entries:
if t_data:
t_entry = t_data.get(entry['name'], {})
desc = t_entry.get('description', entry['description'])
else:
desc = entry['description']
wine_note = f" {L['wine']}" if entry['wine'] else ""
md_file.write(f"### {entry['name']}\n\n{desc}{wine_note}\n\n")
for option in entry['options']:
if t_data:
t_opts = t_data.get(entry['name'], {}).get('options', {})
opt_desc = t_opts.get(option['key'], option['description'])
else:
opt_desc = option['description']
default_mark = f" {L['default']}" if option['default'] else ""
md_file.write(f" * {option['key']}: {opt_desc}{default_mark}\n")
md_file.write("\n")
with open(usage_file, 'r') as file:
data = json.load(file)
for lang in LANG:
t_file = os.path.join(script_dir, f'usage_{lang}.json')
t_data = None
if os.path.exists(t_file):
with open(t_file, 'r') as file:
t_data = json.load(file)
write_md(data, lang, t_data)
with open(os.path.join(script_dir, '../box64.pod'), 'w') as pod_file:
pod_file.write(
"""=head1 NAME
box64 - Linux Userspace x86_64 Emulator with a twist
@@ -121,17 +232,21 @@ Example:
BOX64_DYNAREC_FORWARD=1024
BOX64_DYNAREC_CALLRET=1
The special C<[*]> section defines shared rcfile options for all applications.
More specific sections override only the options they define themselves.
=head1 ENVIRONMENT VARIABLES
=over 8
""")
"""
)
for entry in data:
pod_file.write(f"\n=item B<{entry['name']}> =I<{ '|'.join(option['key'] for option in entry['options']) }>\n\n{entry['description']}{' Available in WowBox64.' if entry['wine'] else ''}\n\n")
for option in entry['options']:
pod_file.write(f" * {option['key']} : {option['description']} {'[Default]' if option['default'] else ''}\n")
pod_file.write("\n")
pod_file.write(f"\n=item B<{entry['name']}> =I<{ '|'.join(option['key'] for option in entry['options']) }>\n\n{entry['description']}{' Available in WowBox64.' if entry['wine'] else ''}\n\n")
for option in entry['options']:
pod_file.write(f" * {option['key']} : {option['description']} {'[Default]' if option['default'] else ''}\n")
pod_file.write("\n")
pod_file.write("""
=back
@@ -166,16 +281,16 @@ for entry in data:
# regex to match env.h C code
regex = {
"INTEGER": re.compile(
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)\)"
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)(?:, \w+)?\)"
),
"INTEGER64": re.compile(
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)(?:, \w+)?\)"
),
"BOOLEAN": re.compile(
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)(?:, \w+)?\)"
),
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)(?:, \w+)?\)"),
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)(?:, \w+)?\)"),
}
env_file = os.path.join(script_dir, "../../src/include/env.h")
+308 -81
View File
File diff suppressed because it is too large. Load diff
+876
View File
@@ -0,0 +1,876 @@
{
"BOX64_ADDLIBS": {
"description": "添加额外需要的共享库(这个选项不太常用)。",
"options": {
"XXXX": "将 XXXX 共享库添加到所需库列表。",
"XXXX:YYYY:ZZZZ": "将 XXXX、YYYY 和 ZZZZ 共享库添加到所需库列表。"
}
},
"BOX64_AES": {
"description": "是否暴露 AES 能力。",
"options": {
"0": "不暴露 AES 能力。",
"1": "暴露 AES 能力。"
}
},
"BOX64_ALLOWMISSINGLIBS": {
"description": "是否允许忽略缺失的共享库。",
"options": {
"0": "不允许忽略缺失的共享库。",
"1": "允许忽略缺失的共享库。"
}
},
"BOX64_ARCH": {
"description": "在 rcfile 中指定当前条目适用的架构。此选项仅在 rcfile 中使用时生效。",
"options": {
"`arm64`": "仅对 AArch64 应用当前条目。",
"`la64`": "仅对 LoongArch64 应用当前条目。",
"`rv64`": "仅对 RISC-V 应用当前条目。",
"`<empty>`": "对所有架构应用当前条目,但如果存在更具体的条目,当前条目将被替换。"
}
},
"BOX64_ARGS": {
"description": "传递给目标程序的参数,仅在没有任何已有参数时有效。",
"options": {
"XXXX": "将 XXXX 参数传递给目标程序。",
"XXXX YYYY ZZZZ": "将 XXXX、YYYY 和 ZZZZ 参数传递给目标程序。"
}
},
"BOX64_AVX": {
"description": "向 CPUID 和 cpuinfo 文件暴露 AVX 扩展。在 Arm64 和龙架构上默认值为 2,因为 DynaRec 已完全实现,其他架构默认为 0。",
"options": {
"0": "不暴露 AVX 能力。",
"1": "向 CPUID 和 cpuinfo 文件暴露 AVX、BMI1、F16C 和 VAES 扩展。",
"2": "包含 1 的全部内容,外加 AVX2、BMI2、FMA、ADX、VPCLMULQDQ 和 RDRAND 扩展。"
}
},
"BOX64_BASH": {
"description": "用于指定 bash 可执行文件的路径。",
"options": {
"XXXX": "使用路径为 XXXX 的 bash 可执行文件。"
}
},
"BOX64_CPUTYPE": {
"description": "指定要模拟的 CPU 类型。",
"options": {
"0": "模拟某个 Intel CPU 型号。",
"1": "模拟某个 AMD CPU 型号。"
}
},
"BOX64_CRASHHANDLER": {
"description": "是否使用模拟的 crashhandler.so 库。",
"options": {
"0": "在需要时使用模拟的 crashhandler.so 库。",
"1": "使用内部定义的空 crashhandler.so 库。"
}
},
"BOX64_DLSYM_ERROR": {
"description": "启用或禁用 dlsym 错误的日志记录。",
"options": {
"0": "禁用 dlsym 错误的日志记录。",
"1": "启用 dlsym 错误的日志记录。"
}
},
"BOX64_DUMP": {
"description": "是否输出 elfloader 调试信息。",
"options": {
"0": "不输出 elfloader 调试信息。",
"1": "输出 elfloader 调试信息。"
}
},
"BOX64_DYNAREC": {
"description": "启用或禁用动态重编译器(DynaRec)。如果在支持的架构上构建时开启了 DynaRec 支持,则默认为 1。",
"options": {
"0": "禁用 DynaRec。",
"1": "启用 DynaRec。"
}
},
"BOX64_DYNAREC_ALIGNED_ATOMICS": {
"description": "仅生成对齐的原子操作(目前仅在 Arm64 上可用)。",
"options": {
"0": "生成非对齐原子操作处理代码。",
"1": "仅生成对齐的原子操作,代码更快更小,但在非对齐数据地址上执行 LOCK 前缀指令时会导致 SIGBUS。"
}
},
"BOX64_DYNAREC_BIGBLOCK": {
"description": "尝试构建更大的代码块以提高性能。",
"options": {
"0": "不尝试构建尽可能大的代码块,适用于使用大量线程和 JIT 的程序(如 Unity)。",
"1": "尽可能构建大的代码块。",
"2": "构建更大的代码块,代码块重叠时不停止,但仅针对 elf 内存中的代码块。",
"3": "构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 Wine 程序有用。"
}
},
"BOX64_DYNAREC_BLEEDING_EDGE": {
"description": "检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。",
"options": {
"0": "不检测 MonoBleedingEdge。",
"1": "检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_STRONGMEM=1。"
}
},
"BOX64_DYNAREC_CALLRET": {
"description": "优化 CALL/RET 指令。",
"options": {
"0": "不优化 CALL/RET,使用跳转表。",
"1": "尝试优化 CALL/RET,在可能的情况下跳过跳转表。",
"2": "尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。"
}
},
"BOX64_DYNAREC_SEP": {
"description": "使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。",
"options": {
"0": "不在 CALLRET 返回时添加 SEP。",
"1": "在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。",
"2": "在 CALLRET 返回时添加 SEP,适用于所有类型的内存。"
}
},
"BOX64_DYNAREC_DF": {
"description": "启用或禁用延迟 FLAGS 的使用。",
"options": {
"0": "禁用延迟 FLAGS 的使用。",
"1": "启用延迟 FLAGS 的使用。"
}
},
"BOX64_DYNAREC_DIRTY": {
"description": "是否允许继续运行未受保护且可能已脏的代码块。",
"options": {
"0": "不允许继续运行未受保护且可能已脏的代码块。",
"1": "允许继续运行在与代码相同页面中写入数据的代码块,可以加快某些游戏的加载时间,但也可能导致意外崩溃。",
"2": "除了 1 之外,当检测到热页时,将该页面标记为永不写保护,但基于该页面构建的代码块将始终被测试。这样可以更快(但某些 SMC 情况可能无法捕获)。"
}
},
"BOX64_DYNAREC_NOHOTPAGE": {
"description": "是否禁用热页检测(即代码执行和数据写入同时发生的页面)。",
"options": {
"0": "检测热页。",
"1": "不检测热页。"
}
},
"BOX64_DYNAREC_DIV0": {
"description": "启用或禁用除零异常的生成。",
"options": {
"0": "不生成除零异常。",
"1": "生成除零异常。"
}
},
"BOX64_DYNAREC_DUMP": {
"description": "启用 DynaRec 转储。",
"options": {
"0": "不转储代码块。",
"1": "转储代码块。",
"2": "转储代码块并带有颜色。",
"3": "仅转储 x86 指令和翻译后的本机指令。"
}
},
"BOX64_DYNAREC_DUMP_RANGE": {
"description": "转储指定范围内的代码块。",
"options": {
"0xXXXXXXXX-0xYYYYYYYY": "定义代码块 被转储的范围(左闭右开)。"
}
},
"BOX64_DYNAREC_DISASM": {
"description": "尝试初始化 libZydis,以在转储、追踪、崩溃报告等场景中获得更具可读性的 x86 反汇编结果。",
"options": {
"0": "不为 Dynarec 加载 Zydis。",
"1": "尝试为 Dynarec 加载 Zydis。"
}
},
"BOX64_DYNAREC_FASTNAN": {
"description": "启用或禁用快速 NaN 处理。",
"options": {
"0": "精确模拟 x86 上的 -NaN 生成。",
"1": "不对 -NaN 生成做任何特殊处理,速度更快。"
}
},
"BOX64_DYNAREC_FASTROUND": {
"description": "启用或禁用快速舍入。",
"options": {
"0": "生成 float/double -> int 舍入,并使用当前舍入模式进行 float/double 计算,类似 x86。",
"1": "不对边缘情况的舍入做任何特殊处理,速度更快。",
"2": "使用当前舍入模式生成 float/double -> int 舍入(类似 x86),但使用快速的 int -> float/double 转换。"
}
},
"BOX64_DYNAREC_FORWARD": {
"description": "定义构建代码块时允许的最大前向跳转值。仅接受 0、128、256、512 和 1024;其他值将回退为 128。",
"options": {
"0": "无前向跳转值。当前代码块结束时,即使存在之前的前向跳转也不尝试继续前进。",
"128": "允许代码块结束与下一个前向跳转之间最多 128 字节的间隙。",
"256": "允许代码块结束与下一个前向跳转之间最多 256 字节的间隙。",
"512": "允许代码块结束与下一个前向跳转之间最多 512 字节的间隙。",
"1024": "允许代码块结束与下一个前向跳转之间最多 1024 字节的间隙。"
}
},
"BOX64_DYNAREC_GDBJIT": {
"description": "GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb 命令启用:jit-reader-load /usr/local/lib/libbox64gdbjitreader.so。",
"options": {
"0": "DynaRec 不会生成 GDBJIT 调试信息。",
"1": "DynaRec 将生成 GDBJIT 调试信息。",
"2": "DynaRec 将生成包含内部状态的详细 GDBJIT 调试信息。",
"3": "DynaRec 将仅对目标程序陷入的代码块 注册详细的 GDBJIT 调试信息,大幅提升性能。",
"0xXXXXXXX-0xYYYYYYY": "定义 DynaRec 将生成包含内部状态的详细 GDBJIT 调试信息的范围。"
}
},
"BOX64_DYNAREC_LOG": {
"description": "禁用或启用 DynaRec 日志。",
"options": {
"0": "禁用 DynaRec 日志。",
"1": "启用最小级别的 DynaRec 日志。",
"2": "启用调试级别的 DynaRec 日志。",
"3": "启用详细级别的 DynaRec 日志。"
}
},
"BOX64_DYNAREC_MISSING": {
"description": "打印缺失的指令。",
"options": {
"0": "不打印缺失的指令。",
"1": "打印缺失的指令。",
"2": "打印回退到标量指令的信息,仅对 RISC-V 有效。"
}
},
"BOX64_DYNAREC_NATIVEFLAGS": {
"description": "启用或禁用原生FLAGS的使用。",
"options": {
"0": "不使用原生FLAGS。",
"1": "在可能的情况下使用原生FLAGS。"
}
},
"BOX64_DYNAREC_NOHOSTEXT": {
"description": "禁用可选的主机扩展。",
"options": {
"0": "不禁用任何扩展。",
"1": "禁用所有可选扩展。",
"xxx,yyy,zzz": "禁用指定的可选扩展,可选项包括 Arm:`crc32,pmull,aes,atomics,sha1,sha2,uscat,flagm,flagm2,frintts,afp,rndr`,LoongArch:`lasx,lbt,frecipe,lam_bh,lamcas,scq`,以及 RISC-V:`zba,zbb,zbc,zbs,vector,xtheadba,xtheadbb,xtheadbs,xtheadmemidx,xtheadmempair,xtheadcondmov`。"
}
},
"BOX64_DYNAREC_PAUSE": {
"description": "启用 x86 PAUSE 模拟,可能有助于自旋锁的性能。",
"options": {
"0": "忽略 x86 PAUSE 指令。",
"1": "使用 YIELD 模拟 x86 PAUSE 指令。",
"2": "使用 WFI 模拟 x86 PAUSE 指令。",
"3": "使用 SEVL+WFE 模拟 x86 PAUSE 指令。"
}
},
"BOX64_DYNAREC_PERFMAP": {
"description": "为 Linux perf 工具生成映射文件。",
"options": {
"0": "DynaRec 不会生成 perf 映射。",
"1": "DynaRec 将生成 perf 映射。"
}
},
"BOX64_DYNAREC_PURGE": {
"description": "根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。",
"options": {
"0": "DynaRec 不会清除旧的未使用代码块。",
"1": "DynaRec 将根据年龄阈值清除旧的未使用代码块。"
}
},
"BOX64_DYNAREC_PURGE_AGE": {
"description": "代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。",
"options": {
"4096": "默认年龄阈值。",
"XXXX": "自定义年龄阈值(范围:10-65536)。"
}
},
"BOX64_DYNAREC_SAFEFLAGS": {
"description": "在 CALL/RET 指令和其他边缘情况下 FLAGS 模拟的行为。",
"options": {
"0": "将 CALL/RET 标记为从不需要任何 FLAGS。",
"1": "将大多数 RET 标记为需要 FLAGS,将大多数 CALL 标记为不需要。",
"2": "将所有 CALL/RET 都标记为需要 FLAGS。同时也处理所有边缘情况。"
}
},
"BOX64_DYNAREC_STRONGMEM": {
"description": "开启或关闭 x86 强内存模型的模拟。",
"options": {
"0": "不做任何特殊处理。",
"1": "在写入内存时启用以有限方式模拟 x86 强内存模型的内存屏障。",
"2": "包含 1 的全部内容,外加 SIMD 指令的内存屏障。",
"3": "包含 2 的全部内容,外加定期添加更多内存屏障。",
"4": "模仿 x86 TSO,类似 QEMU 的方法,可用于评估目的。"
}
},
"BOX64_DYNAREC_TBB": {
"description": "启用或禁用 libtbb 检测。",
"options": {
"0": "不检测 libtbb。",
"1": "检测 libtbb 并应用保守设置。"
}
},
"BOX64_DYNAREC_TEST": {
"description": "启用 DynaRec 与解释器的执行对比,非常慢,仅用于测试。",
"options": {
"0": "不进行对比。",
"1": "每个指令都在解释器和 DynaRec 上运行,当寄存器或内存不同时进行对比并打印。",
"0xXXXXXXXX-0xYYYYYYYY": "定义 DynaRec 测试的范围(左闭右开)。"
}
},
"BOX64_DYNAREC_TEST_NODUP": {
"description": "启用 COSIM 发现差异的 IP 地址去重。",
"options": {
"0": "显示所有出错的地址。",
"1": "每个出错地址仅显示一次,即使转储可能不同。"
}
},
"BOX64_DYNAREC_TEST_NODUMP": {
"description": "当 BOX64_DYNAREC_DUMP 启用时不转储测试代码。",
"options": {
"0": "转储测试代码。",
"1": "不转储测试代码。"
}
},
"BOX64_DYNAREC_TRACE": {
"description": "启用或禁用 DynaRec 追踪。",
"options": {
"0": "不追踪代码块。",
"1": "追踪代码块,会大幅降低程序速度并生成大量日志。"
}
},
"BOX64_DYNAREC_VOLATILE_METADATA": {
"description": "使用从 PE 文件解析的 volatile 元数据,仅对 64 位 Windows 游戏有效。",
"options": {
"0": "不使用 volatile 元数据。",
"1": "使用 volatile 元数据,将指导 Box64 进行更好的强内存模拟。"
}
},
"BOX64_DYNAREC_WAIT": {
"description": "是否等待代码块构建完成。",
"options": {
"0": "不等待,改用解释器,可能在大量多线程或 JIT 程序上略微加速。",
"1": "等待代码块构建完成。"
}
},
"BOX64_DYNAREC_WEAKBARRIER": {
"description": "调整内存屏障以减少强内存模拟的性能影响。",
"options": {
"0": "使用常规安全屏障。",
"1": "使用弱屏障以获得更多性能提升。",
"2": "包含 1 的全部内容,外加禁用最后的写屏障。"
}
},
"BOX64_DYNAREC_X87DOUBLE": {
"description": "强制使用 float/double 进行 x87 模拟。",
"options": {
"0": "尝试在可能的情况下对 x87 模拟使用 float。",
"1": "仅对 x87 模拟使用 Double。",
"2": "在 x87 模拟中检查精度控制的低精度。"
}
},
"BOX64_DYNAREC_INTERP_SIGNAL": {
"description": "允许在信号处理器中使用 DynaRec。",
"options": {
"0": "允许在信号处理器中使用 DynaRec。",
"1": "仅在信号处理器中使用解释器(与 v0.3.8 及更早版本相同)。"
}
},
"BOX64_DYNACACHE": {
"description": "启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 1(启用)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。",
"options": {
"0": "禁用 DynaCache。",
"1": "启用 DynaCache。",
"2": "使用已有的 DynaCache 文件,但不生成新的。"
}
},
"BOX64_DYNACACHE_FOLDER": {
"description": "设置 DynaCache 文件的文件夹。默认为 $XDG_CACHE_HOME/box64,如果 $XDG_CACHE_HOME 未设置则为 $HOME/.cache/box64。",
"options": {
"XXXX": "使用文件夹 XXXX 存储 DynaCache 文件。"
}
},
"BOX64_DYNACACHE_LIMIT": {
"description": "DynaCache 文件夹的最大大小(MiB)。超过限制时,会先删除无效的 DynaCache 文件,如仍超限再删除最旧的有效文件。默认大小为 2048MiB。",
"options": {
"0": "不限制 DynaCache 文件夹大小。",
"XXXX": "先删除无效缓存文件,如仍超限再删除最旧的有效缓存文件,将 DynaCache 文件夹保持在 XXXX MiB 以下。",
"2048": "默认值为 2048 MiB。"
}
},
"BOX64_DYNACACHE_COMPRESS": {
"description": "设置是否压缩磁盘上的 DynaCache 文件。",
"options": {
"0": "不压缩 DynaCache 文件。",
"1": "使用 Zlib 最快压缩级别压缩 DynaCache 文件。",
"2": "使用 Zlib 默认压缩级别压缩 DynaCache 文件。"
}
},
"BOX64_DYNACACHE_MIN": {
"description": "DynaCache 写入磁盘的最小大小(KB)。默认大小为 30KB。",
"options": {
"XXXX": "设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。",
"30": "默认值为 30 KB。"
}
},
"BOX64_EMULATED_LIBS": {
"description": "强制使用模拟库。",
"options": {
"XXXX": "强制使用模拟库 XXXX。",
"XXXX:YYYY:ZZZZ": "强制使用模拟库 XXXX、YYYY 和 ZZZZ。"
}
},
"BOX64_ENV": {
"description": "添加环境变量。",
"options": {
"XXXX=yyyy": "添加值为 yyyy 的环境变量 XXXX。"
}
},
"BOX64_ENV[1-5]": {
"description": "添加环境变量。",
"options": {
"XXXX=yyyy": "添加值为 yyyy 的环境变量 XXXX。"
}
},
"BOX64_EXIT": {
"description": "直接退出,不运行程序。",
"options": {
"0": "不执行任何操作。",
"1": "直接退出。"
}
},
"BOX64_FIX_64BIT_INODES": {
"description": "修复 64 位 inode。",
"options": {
"0": "不修复 64 位 inode。",
"1": "修复 64 位 inode。"
}
},
"BOX64_FORCE_LD_PRELOAD": {
"description": "是否强制 BOX64_LD_PRELOAD 库中的符号通过 RTLD_NEXT 解析。",
"options": {
"0": "不执行任何操作。",
"1": "强制 BOX64_LD_PRELOAD 库中的符号通过 RTLD_NEXT 解析。"
}
},
"BOX64_IGNOREINT3": {
"description": "忽略 INT3 指令。",
"options": {
"0": "如果存在处理器则触发 TRAP 信号。",
"1": "静默跳过该指令。"
}
},
"BOX64_INSERT_ARGS": {
"description": "在命令行前添加参数。",
"options": {
"XXXX": "在程序前添加参数 XXXX。",
"XXXX YYYY ZZZZ": "在目标程序前添加参数 XXXX、YYYY 和 ZZZZ。"
}
},
"BOX64_INPROCESSGPU": {
"description": "向目标程序添加 --in-process-gpu 参数。",
"options": {
"0": "不执行任何操作。",
"1": "向目标程序添加 --in-process-gpu 参数。"
}
},
"BOX64_JITGDB": {
"description": "发生 SIGSEGV、SIGILL 和 SIGBUS 时是否启动 gdb。",
"options": {
"0": "捕获信号时仅打印消息。",
"1": "当捕获到 SIGSEGV、SIGILL 或 SIGBUS 信号时启动 gdb,附加到有问题的进程并进入无限循环等待。在 gdb 中,你需要自己找到正确的线程(在其堆栈中有 `my_box64signalhandler` 的线程),然后可能需要 `finish` 1 或 2 个函数(在 `usleep(..)` 内部),之后你将进入 `my_box64signalhandler`,就在 Segfault 消息的 printf 之前。然后 `set waiting=0` 退出无限循环。",
"2": "当捕获到 SIGSEGV、SIGILL 或 SIGBUS 信号时启动 gdbserver,附加到有问题的进程,并进入无限循环等待。使用 `gdb /PATH/TO/box64` 然后 `target remote 127.0.0.1:1234` 连接到 gdbserver(如果不在本机,则使用实际 IP)。之后的操作步骤与 `BOX64_JITGDB=1` 相同。",
"3": "当捕获到 SIGSEGV、SIGILL 或 SIGBUS 信号时启动 lldb,附加到有问题的进程并进入无限循环等待。"
}
},
"BOX64_JVM": {
"description": "检测 libjvm 并应用保守设置。",
"options": {
"0": "不执行任何操作。",
"1": "检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0。"
}
},
"BOX64_LD_LIBRARY_PATH": {
"description": "查找 x86_64 库的路径。",
"options": {
"XXXX": "将路径 XXXX 添加到库搜索路径。"
}
},
"BOX64_LD_PRELOAD": {
"description": "强制随二进制文件加载库。",
"options": {
"XXXX": "强制加载库 XXXX。",
"XXXX:YYYY": "强制加载库 XXXX 和 YYYY。"
}
},
"BOX64_LIBCEF": {
"description": "检测 libcef 并应用 BOX64_MALLOC_HACK 设置。",
"options": {
"0": "不执行任何操作。",
"1": "检测 libcef,并在检测到时应用 BOX64_MALLOC_HACK=2。"
}
},
"BOX64_LIBGL": {
"description": "设置 libGL 的名称。",
"options": {
"libXXXX": "将 libGL 的名称设置为 libXXXX。",
"/path/to/libXXXX": "将 libGL 的名称和路径设置为 /path/to/libXXXX,你也可以使用 SDL_VIDEO_GL_DRIVER。"
}
},
"BOX64_LOAD_ADDR": {
"description": "设置程序加载的地址,仅对 PIE 目标程序有效。",
"options": {
"0xXXXXXXXX": "设置程序加载的地址。"
}
},
"BOX64_LOG": {
"description": "启用或禁用 Box64 日志,如果 stdout 不是终端则默认为 0,否则为 1。",
"options": {
"0": "禁用 Box64 日志。",
"1": "启用最小级别的 Box64 日志。",
"2": "启用调试级别的 Box64 日志。",
"3": "启用详细级别的 Box64 日志。"
}
},
"BOX64_MALLOC_HACK": {
"description": "挂钩 malloc 操作符时的行为。",
"options": {
"0": "不允许重定向 malloc 操作符,重写代码使用常规函数。",
"1": "允许重定向 malloc 操作符。",
"2": "与 0 类似,但追踪特殊的 mmap/free(某些内联的重定向函数无法被重定向)。"
}
},
"BOX64_MAXCPU": {
"description": "暴露的最大 CPU 核心数。",
"options": {
"0": "使用实际的 CPU 核心数。",
"XXXX": "使用 XXXX 个 CPU 核心。"
}
},
"BOX64_MMAP32": {
"description": "在运行 32 位代码的 64 位程序(如 Wine WOW64)上强制使用 32 位兼容的内存映射,可提高性能。",
"options": {
"0": "不强制使用 32 位内存映射。",
"1": "强制使用 32 位内存映射。"
}
},
"BOX64_NOBANNER": {
"description": "禁用 Box64 横幅。",
"options": {
"0": "显示 Box64 横幅。",
"1": "不显示 Box64 横幅。"
}
},
"BOX64_NODYNAREC": {
"description": "在指定的地址范围内禁止创建代码块,有助于调试 DynaRec 和解释器之间的行为差异。",
"options": {
"0xXXXXXXXX-0xYYYYYYYY": "定义禁止创建代码块 的范围(左闭右开)。"
}
},
"BOX64_NODYNAREC_DELAY": {
"description": "延迟后移除 NoDynaRec 范围。",
"options": {
"0": "不移除 NoDynaRec 范围。",
"1": "创建 2 个线程后移除 NoDynaRec 范围。"
}
},
"BOX64_DYNAREC_NOARCH": {
"description": "从代码块中移除架构元数据(在信号处理时使用)。",
"options": {
"0": "为每个代码块生成所有架构元数据,包括 x87/mmx/SSE/AVX 寄存器追踪。会使用更多内存。",
"1": "仅生成每个代码块的必要元数据(FLAGS、对齐),节省一些内存,但某些加密软件可能会失败。",
"2": "不为代码块生成元数据,进一步节省内存,但在信号处理时可能会失败。"
}
},
"BOX64_NOGTK": {
"description": "不加载包装的 GTK 库。",
"options": {
"0": "加载包装的 GTK 库。",
"1": "不加载包装的 GTK 库。"
}
},
"BOX64_NOPULSE": {
"description": "不加载 PulseAudio 库(原生库和模拟库均不加载)。",
"options": {
"0": "加载 PulseAudio 库。",
"1": "不加载 PulseAudio 库。"
}
},
"BOX64_NORCFILES": {
"description": "不加载任何 rc 文件。",
"options": {
"0": "加载 rc 文件。",
"1": "不加载任何 rc 文件。"
}
},
"BOX64_NOSANDBOX": {
"description": "向目标程序添加 --no-sandbox 参数。",
"options": {
"0": "不执行任何操作。",
"1": "向目标程序添加 --no-sandbox 参数。"
}
},
"BOX64_NOSIGSEGV": {
"description": "禁用 SIGSEGV 的处理。",
"options": {
"0": "允许 x86 程序为 SIGSEGV 设置信号处理器。",
"1": "禁用 SIGSEGV 的处理。"
}
},
"BOX64_NOSIGILL": {
"description": "禁用 SIGILL 的处理。",
"options": {
"0": "允许 x86 程序为 SIGILL 设置信号处理器。",
"1": "禁用 SIGILL 的处理。"
}
},
"BOX64_NOVULKAN": {
"description": "不加载 Vulkan 库。",
"options": {
"0": "加载 Vulkan 库。",
"1": "不加载 Vulkan 库,原生库和模拟库均不加载。"
}
},
"BOX64_NOVULKANOVERLAY": {
"description": "不加载 x64 Vulkan 覆盖层。",
"options": {
"0": "尝试加载 x64 Vulkan 覆盖层。",
"1": "不加载 x64 Vulkan 覆盖层。"
}
},
"BOX64_PATH": {
"description": "查找 x86_64 二进制文件的路径。",
"options": {
"XXXX": "将路径 XXXX 添加到二进制搜索路径。"
}
},
"BOX64_PCLMULQDQ": {
"description": "暴露 PCLMULQDQ 能力。",
"options": {
"0": "不暴露 PCLMULQDQ 能力。",
"1": "暴露 PCLMULQDQ 能力。"
}
},
"BOX64_PREFER_EMULATED": {
"description": "优先使用模拟库而非原生库。",
"options": {
"0": "优先使用原生库而非模拟库。",
"1": "优先使用模拟库而非原生库。"
}
},
"BOX64_PREFER_WRAPPED": {
"description": "即使库使用绝对路径指定,也优先使用包装库。",
"options": {
"0": "优先使用绝对路径指定的库而非包装库。",
"1": "即使库使用绝对路径指定,也优先使用包装库。"
}
},
"BOX64_PROFILE": {
"description": "预定义的环境变量集合,以兼容性或性能为导向。",
"options": {
"safest": "禁用所有不安全的优化。",
"safe": "仅启用小部分不安全的优化。",
"default": "大多数程序都能正常运行且性能适中的默认设置。",
"fast": "启用许多不安全的优化,但同时启用强内存模型模拟。",
"fastest": "启用许多不安全的优化以获得更好的性能。"
}
},
"BOX64_PYTHON3": {
"description": "python3 可执行文件的路径。",
"options": {
"XXXX": "使用路径为 XXXX 的 python3 可执行文件。"
}
},
"BOX64_RCFILE": {
"description": "要加载的 rc 文件路径。",
"options": {
"XXXX": "加载 rc 文件 XXXX,不会加载默认的 rc 文件。"
}
},
"BOX64_RDTSC_1GHZ": {
"description": "如果可用,使用硬件计数器实现 rdtsc。",
"options": {
"0": "如果可用,使用硬件计数器实现 rdtsc 指令。",
"1": "仅当精度至少为 1GHz 时,使用硬件计数器实现 rdtsc。"
}
},
"BOX64_RDTSC_INV": {
"description": "在 Intel CPU 类型的 CPUID 中报告 Invariant TSC 位。",
"options": {
"0": "不为 Intel CPU 类型报告 Invariant TSC(默认)。",
"1": "在 Intel CPU 类型的 CPUID leaf 0x80000007 中报告 Invariant TSC 位。"
}
},
"BOX64_RESERVE_HIGH": {
"description": "为程序保留高内存区域,在 Box32 上始终启用。",
"options": {
"0": "不为程序保留高内存区域。",
"1": "为程序保留高内存区域。"
}
},
"BOX64_ROLLING_LOG": {
"description": "当捕获信号时显示最近几个包装函数调用。",
"options": {
"0": "不执行任何操作。",
"1": "捕获信号时显示最近 16 个包装函数调用。",
"XXXX": "捕获信号时显示最近 XXXX 个包装函数调用。"
}
},
"BOX64_SDL2_JGUID": {
"description": "对包装的 SDL2 使用 SDL_GetJoystickGUIDInfo 函数的变通方案。",
"options": {
"0": "不执行任何操作。",
"1": "对包装的 SDL2 使用 SDL_GetJoystickGUIDInfo 函数的变通方案。"
}
},
"BOX64_SHAEXT": {
"description": "暴露 SHAEXT(即 SHA_NI)能力。",
"options": {
"0": "不暴露 SHAEXT 能力。",
"1": "暴露 SHAEXT 能力。"
}
},
"BOX64_SHOWBT": {
"description": "捕获信号时显示原生和模拟的回溯。",
"options": {
"0": "不执行任何操作。",
"1": "捕获信号时显示原生和模拟的回溯。"
}
},
"BOX64_SHOWSEGV": {
"description": "始终显示 SIGSEGV 信号详情。",
"options": {
"0": "不执行任何操作。",
"1": "始终显示 SIGSEGV 信号详情。"
}
},
"BOX64_SSE_FLUSHTO0": {
"description": "SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常 FLAGS。",
"options": {
"0": "仅追踪 FLAGS。",
"1": "直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常 FLAGS(如果可用)。"
}
},
"BOX64_SSE42": {
"description": "暴露 SSE4.2 能力。",
"options": {
"0": "不暴露 SSE4.2 能力。",
"1": "暴露 SSE4.2 能力。"
}
},
"BOX64_STEAM_VULKAN": {
"description": "为 Linux Steam UI 强制使用 Vulkan。",
"options": {
"0": "不执行任何操作。",
"1": "为 Linux Steam UI 强制使用 Vulkan。"
}
},
"BOX64_SYNC_ROUNDING": {
"description": "在 x86 和原生之间同步舍入模式。",
"options": {
"0": "不同步舍入模式。",
"1": "在 x86 和原生之间同步舍入模式。"
}
},
"BOX64_TRACE_COLOR": {
"description": "启用或禁用彩色追踪输出。",
"options": {
"0": "禁用彩色追踪输出。",
"1": "启用彩色追踪输出。"
}
},
"BOX64_TRACE_EMM": {
"description": "启用或禁用 EMM(即 MMX)追踪输出。",
"options": {
"0": "禁用 EMM 追踪输出。",
"1": "启用 EMM 追踪输出。"
}
},
"BOX64_TRACE_FILE": {
"description": "将所有日志和追踪发送到文件而非 `stdout`。",
"options": {
"XXXX": "将所有日志和追踪发送到文件 XXXX。",
"XXXX%pid": "将所有日志和追踪发送到文件 XXXX,文件名中附加 pid。",
"stderr": "将所有日志和追踪发送到 `stderr`。",
"stdout": "将所有日志和追踪发送到 `stdout`。"
}
},
"BOX64_TRACE_INIT": {
"description": "与 BOX64_TRACE 相同,但立即开始追踪。",
"options": {
"0": "禁用追踪输出。",
"1": "启用追踪输出。追踪在依赖项初始化之前开始。",
"symbolname": "仅对 `symbolname` 启用追踪输出。追踪在依赖项初始化之前开始。",
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。",
"0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ": "对指定的地址列表启用追踪输出。追踪在依赖项初始化之前开始。"
}
},
"BOX64_TRACE_START": {
"description": "在 N 个指令执行后开始追踪。",
"options": {
"0": "立即开始追踪。",
"1": "执行 1 个指令后开始追踪。",
"XXXX": "执行 XXXX 个指令后开始追踪。"
}
},
"BOX64_TRACE_XMM": {
"description": "启用或禁用 XMM(即 SSE)追踪输出。",
"options": {
"0": "禁用 XMM 追踪输出。",
"1": "启用 XMM 追踪输出。"
}
},
"BOX64_TRACE": {
"description": "仅在带追踪功能的 box64 构建中可用。添加所有执行指令的追踪以及寄存器转储。",
"options": {
"0": "禁用追踪输出。",
"1": "启用追踪输出。",
"symbolname": "仅对 `symbolname` 启用追踪输出。",
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。",
"0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ": "对指定地址列表启用追踪输出。"
}
},
"BOX64_UNITYPLAYER": {
"description": "检测 UnityPlayer 并应用保守设置。",
"options": {
"0": "不执行任何操作。",
"1": "检测 UnityPlayer(Windows 或 Linux),并在检测到时应用 BOX64_UNITY=1。"
}
},
"BOX64_UNITY": {
"description": "告诉 Box64 这是一个 Unity 游戏。",
"options": {
"0": "不执行任何操作。",
"1": "这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_STRONGMEM=1。"
}
},
"BOX64_WRAP_EGL": {
"description": "优先使用包装库处理 EGL 和 GLESv2。",
"options": {
"0": "优先使用模拟库处理 EGL 和 GLESv2。",
"1": "优先使用包装库处理 EGL 和 GLESv2。"
}
},
"BOX64_X11GLX": {
"description": "是否强制 Xorg GLX 扩展存在。",
"options": {
"0": "不强制 Xorg GLX 扩展存在。",
"1": "在使用 XQueryExtension 时要求 Xorg GLX 扩展存在。"
}
},
"BOX64_X11SYNC": {
"description": "是否强制 X11 显示同步操作。",
"options": {
"0": "不强制 X11 显示同步操作。",
"1": "强制 X11 显示同步操作。"
}
},
"BOX64_X11THREADS": {
"description": "加载 X11 时调用 XInitThreads。这主要用于使用 Loki_Compat 库的旧 Loki 游戏。",
"options": {
"0": "不调用 XInitThreads。",
"1": "一旦加载 libX11 就调用 XInitThreads。"
}
},
"BOX64_X87_NO80BITS": {
"description": "x87 80 位 long double 的行为。",
"options": {
"0": "尝试尽可能精确地处理 80 位 long double。",
"1": "对 x87 使用 64 位 double。"
}
},
"BOX64_NOPERSONA32BITS": {
"description": "禁用 32 位二进制文件的自动 personality 切换(在 Box32 上始终启用)。",
"options": {
"0": "为 32 位二进制文件切换 personality(如果尚未尝试)。",
"1": "不为 32 位二进制文件切换 personality。"
}
}
}
+1
View File
@@ -17,6 +17,7 @@ endif()
set(ENV{BOX64_LOG} 0)
set(ENV{BOX64_NOBANNER} 1)
set(ENV{BOX64_DYNACACHE} 0)
# run the test program, capture the stdout/stderr and the result var
execute_process(
+7
View File
@@ -11,6 +11,9 @@
#include "os.h"
#include "box64context.h"
#include "debug.h"
#ifdef DYNAREC
#include "dynablock.h"
#endif
#include "elfloader.h"
#include "custommem.h"
#include "threads.h"
@@ -351,6 +354,10 @@ void FreeBox64Context(box64context_t** context)
signal(i, SIG_DFL);
}
#ifdef DYNAREC
FlushZombieDynablocks(); // free all deferred-free dynablocks before my_context goes away
#endif
*context = NULL; // bye bye my_context
CleanStackSize(ctx);
+1 -1
View File
@@ -3,6 +3,6 @@
#define BOX64_MAJOR 0
#define BOX64_MINOR 4
#define BOX64_REVISION 2
#define BOX64_REVISION 4
#endif //__BOX64_VERSION_H_
+98 -42
View File
@@ -46,6 +46,7 @@
#include "library.h"
#include "core.h"
#include "env.h"
#include "dynacache.h"
#include "cleanup.h"
#include "freq.h"
#include "hostext.h"
@@ -69,6 +70,7 @@ int box64_steam = 0;
int box64_steamcmd = 0;
int box64_musl = 0;
int box64_nolibs = 0;
int box64_hasinterp = 0;
char* box64_custom_gstreamer = NULL;
int box64_tcmalloc_minimal = 0;
uintptr_t fmod_smc_start = 0;
@@ -89,6 +91,8 @@ const char* box64_wine_guest_name = NULL;
#ifdef HAVE_TRACE
uintptr_t trace_start = 0, trace_end = 0;
uintptr_t* trace_addrs = NULL;
int trace_addrs_count = 0;
char* trace_func = NULL;
#endif
@@ -225,14 +229,15 @@ static void displayMiscInfo(void)
#if defined(LA64)
if (box64env.avx && !cpuext.lasx) {
box64env.avx = 0;
box64env.avx2 = 0;
}
#endif
#endif
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd", box64_sysinfo.cpuname, box64_sysinfo.ncpu, box64_sysinfo.ncpu > 1 ? "s" : "", box64_pagesize);
if (BOX64ENV(maxcpu))
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s\n", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
if (BOX64ENV(skipcpu))
printf_log_prefix(0, LOG_INFO, " skipping %d core%s\n", BOX64ENV(skipcpu), BOX64ENV(skipcpu)>1? "s":"");
else
printf_log_prefix(0, LOG_INFO, "\n");
computeRDTSC();
@@ -424,8 +429,6 @@ static void addLibPaths(box64context_t* context)
GO("libpng12.so.0");
GO("libpng16.so.16");
GO("libcurl.so.4");
if(getenv("BOX64_PRESSURE_VESSEL_FILES")) // use emulated gnutls in this case, it's safer
GO("libgnutls.so.30");
GO("libtbbmalloc.so.2");
GO("libtbbmalloc_proxy.so.2");
GO("libicuuc.so.64");
@@ -469,7 +472,7 @@ static void setupZydis(box64context_t* context)
if ((BOX64ENV(trace_init) && strcmp(BOX64ENV(trace_init), "0")) || (BOX64ENV(trace) && strcmp(BOX64ENV(trace), "0"))) {
context->x64trace = 1;
}
if (context->x64trace) {
if (context->x64trace || BOX64ENV(dynarec_disasm)) {
printf_log(LOG_INFO, "Initializing Zydis lib\n");
if (InitX64Trace(context)) {
printf_log(LOG_INFO, "Zydis init failed. No x86 trace activated\n");
@@ -544,6 +547,39 @@ void LoadLDPath(box64context_t *context)
PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world
}
#ifdef HAVE_TRACE
static void setupTraceAddrList(char *p)
{
int cap = 16;
int count = 0;
char *saveptr = NULL;
uintptr_t* addrs = (uintptr_t*)box_malloc(cap * sizeof(uintptr_t));
char* tmp = box_strdup(p);
char* tok = strtok_r(tmp, ":", &saveptr);
while (tok) {
if (count >= cap) {
cap *= 2;
addrs = (uintptr_t*)box_realloc(addrs, cap * sizeof(uintptr_t));
}
char* endptr;
uintptr_t addr = (uintptr_t)strtoul(tok, &endptr, 0);
if (endptr != tok)
addrs[count++] = addr;
tok = strtok_r(NULL, ":", &saveptr);
}
if (count > 0)
SetTraceAddrs(addrs, count);
box_free(tmp);
box_free(addrs);
}
#endif
EXPORTDYN
void setupTraceInit()
{
@@ -563,6 +599,9 @@ void setupTraceInit()
}
if(s_trace_start || s_trace_end)
SetTraceEmu(s_trace_start, s_trace_end);
} else if (strchr(p,':')) {
// Parse BOX64_TRACE=0x1000:0x2000:0x3000 format.
setupTraceAddrList(p);
} else {
int veropt = 1;
int ver = 0;
@@ -640,6 +679,9 @@ void setupTrace()
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
}
}
} else if (strchr(p,':')) {
// Parse BOX64_TRACE=0x1000:0x2000:0x3000 format.
setupTraceAddrList(p);
} else {
int search = 0;
if (my_context->elfs) {
@@ -702,16 +744,14 @@ void endBox64()
const int max_wait_ms = 2000; // 2s
int waited_ms = 0;
printf_log(LOG_INFO, "endBox64: waiting emu workers to exit (n=%d)\n", workers);
printf_log(LOG_DEBUG, "endBox64: waiting emu workers to exit (n=%d)\n", workers);
while ((workers = get_active_emu_workers()) > 0 && waited_ms < max_wait_ms) {
usleep(sleep_us);
waited_ms += sleep_us / 1000;
}
if (workers > 0) {
printf_log(LOG_INFO,
"endBox64: %d emu workers still alive after %dms, skip unload/free to avoid UAF crash\n",
workers, waited_ms);
printf_log(LOG_DEBUG, "endBox64: %d emu workers still alive after %dms, skip unload/free to avoid UAF crash\n", workers, waited_ms);
return;
}
}
@@ -798,14 +838,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
exit(0);
}
int is_test = 0;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--test") || !strcmp(argv[i], "-t")) {
is_test = 1;
break;
}
}
if (is_test) {
if (argc >= 3 && (!strcmp(argv[1], "--test") || !strcmp(argv[1], "-t"))) {
box64_unittest_mode = 1;
exit(unittest(argc, argv));
}
@@ -834,13 +867,23 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
}
if (!strcmp(prog, "-k") || !strcmp(prog, "--kill-all")) {
KillAllInstances();
#ifdef DYNAREC
DetectHostCpuFeatures();
#endif
DynaCacheClean();
exit(0);
}
if(!strcmp(prog, "--dynacache-list")) {
if(!strcmp(prog, "-dl") || !strcmp(prog, "--dynacache-list")) {
#ifdef DYNAREC
DetectHostCpuFeatures();
#endif
DynaCacheList(argv[nextarg+1]);
exit(0);
}
if(!strcmp(prog, "--dynacache-clean")) {
if(!strcmp(prog, "-dc") || !strcmp(prog, "--dynacache-clean")) {
#ifdef DYNAREC
DetectHostCpuFeatures();
#endif
DynaCacheClean();
exit(0);
}
@@ -880,11 +923,11 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
{
char* p = BOX64ENV(python3);
if(p) {
if(FileIsX64ELF(p)) {
if(FileExist(p, IS_FILE)) {
pythonpath = p;
printf_log(LOG_INFO, "Using python3 \"%s\"\n", pythonpath);
printf_log(LOG_INFO, "Using python helper \"%s\"\n", pythonpath);
} else {
printf_log(LOG_INFO, "The x86_64 python3 \"%s\" is not an x86_64 binary.\n", p);
printf_log(LOG_INFO, "The python helper \"%s\" was not found.\n", p);
}
}
}
@@ -930,24 +973,6 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
}
}
box64_wine = 1;
// check if it's proton, with it's custom gstreamer build, to disable gtk3 loading
char tmp[strlen(prog)+100];
strcpy(tmp, prog);
char* pp = strrchr(tmp, '/');
if(pp) {
*pp = '\0'; // remove the wine binary call
strcat(tmp, "/../lib64/gstreamer-1.0");
// check if it exist
if(FileExist(tmp, 0)) {
box64_custom_gstreamer = box_strdup(tmp);
} else {
*pp = '\0';
strcat(tmp, "/../lib/x86_64-linux-gnu/gstreamer-1.0");
if(FileExist(tmp, 0)) {
box64_custom_gstreamer = box_strdup(tmp);
}
}
}
// Try to get the name of the exe being run, to ApplyEnvFileEntry laters
if(argv[nextarg+1] && argv[nextarg+1][0]!='-' && strlen(argv[nextarg+1])>4 /*&& !strcasecmp(argv[nextarg+1]+strlen(argv[nextarg+1])-4, ".exe")*/) {
const char* pp = strrchr(argv[nextarg+1], '/');
@@ -991,6 +1016,30 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
my_context = NewBox64Context(argc - nextarg);
addLibPaths(my_context);
if(box64_wine) {
// check if it's proton, with it's custom gstreamer build, to disable gtk3 loading
char* tmp_ = ResolveFile(prog_, &my_context->box64_path);
if(tmp_) {
char tmp[strlen(tmp_)+100];
strcpy(tmp, tmp_);
box_free(tmp_);
char* pp = strrchr(tmp, '/');
if(pp) {
*pp = '\0'; // remove the wine binary call
strcat(tmp, "/../lib64/gstreamer-1.0");
// check if it exist
if(FileExist(tmp, 0)) {
box64_custom_gstreamer = box_strdup(tmp);
} else {
*pp = '\0';
strcat(tmp, "/../lib/x86_64-linux-gnu/gstreamer-1.0");
if(FileExist(tmp, 0)) {
box64_custom_gstreamer = box_strdup(tmp);
}
}
}
}
}
// Append ld_list if it exist
if(ld_libs_args!=-1)
@@ -1012,6 +1061,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
unsetenv("BOX64_ARG0");
if(!my_context->bashpath)
my_context->bashpath = ResolveFile("box64-bash", &my_context->box64_path);
if(!my_context->pythonpath)
my_context->pythonpath = ResolveFile("box64-python", &my_context->box64_path);
pressure_vessel(argc, argv, nextarg+1, prog);
}
#endif
@@ -1113,6 +1164,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
bashpath = ResolveFile("box64-bash", &my_context->box64_path);
if(bashpath)
my_context->bashpath = box_strdup(bashpath);
if(!pythonpath)
pythonpath = ResolveFile("box64-python", &my_context->box64_path);
if(pythonpath)
my_context->pythonpath = box_strdup(pythonpath);
@@ -1124,8 +1177,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
if (applied) {
printf_log(LOG_INFO, "Applied settings from rcfile\n");
displayMiscInfo();
PrintEnvVariables(&box64env, LOG_INFO);
}
PrintEnvVariables(&box64env, LOG_INFO);
setupZydis(my_context);
for(int i=1; i<my_context->argc; ++i) {
@@ -1421,8 +1474,9 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
my_context->orig_argc = argc;
my_context->orig_argv = (char**)argv;
}
box64_hasinterp = hasElfInterp(elf_header);
box64_nolibs = (NeededLibs(elf_header)==0);
if(box64_nolibs) printf_log(LOG_INFO, "Warning, box64 is not really compatible with staticaly linked binaries. Expect crash!\n");
if(!box64_hasinterp) printf_log(LOG_INFO, "Warning, box64 is not really compatible with staticaly linked binaries. Expect crash!\n");
box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34");
if(box64_isglibc234)
printf_log(LOG_DEBUG, "Program linked with GLIBC 2.34+\n");
@@ -1533,12 +1587,14 @@ int emulate(x64emu_t* emu, elfheader_t* elf_header)
SetEIP(emu, my_context->ep);
Push32(emu, my_context->exit_bridge); // push to pop it just after
SetEDX(emu, Pop32(emu)); // RDX is exit function
if(!box64_hasinterp) SetEDX(emu, 0);
} else
#endif
{
SetRIP(emu, my_context->ep);
Push64(emu, my_context->exit_bridge); // push to pop it just after
SetRDX(emu, Pop64(emu)); // RDX is exit function
if(!box64_hasinterp) SetRDX(emu, 0);
}
DynaRun(emu);
// Get EAX
+329 -290
View File
@@ -16,6 +16,9 @@
#include "callback.h"
#include "x64trace.h"
#include "custommem.h"
#ifndef _WIN32
#include "signals.h"
#endif
#include "khash.h"
#include "threads.h"
#include "rbtree.h"
@@ -26,12 +29,13 @@
#include "dynarec/dynablock_private.h"
#include "dynarec/native_lock.h"
#include "dynarec/dynarec_next.h"
#include "dynacache_compress.h"
#include "freq.h"
// init inside dynablocks.c
static mmaplist_t *mmaplist = NULL;
static rbtree_t *rbt_dynmem = NULL;
static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 = 0, jmptbl_allocated3 = 0;
static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 = 0;
#if JMPTABL_SHIFTMAX != 16
#error Incorect value for jumptable shift max that should be 16
#endif
@@ -39,18 +43,15 @@ static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 =
#if JMPTABL_SHIFT3 != 16
#error Incorect value for jumptable shift3 that should be 16
#endif
static uint64_t jmptbl_allocated4 = 0;
static uintptr_t**** box64_jmptbl4[1<<JMPTABL_SHIFT4];
static uintptr_t*** box64_jmptbldefault3[1<<JMPTABL_SHIFT3];
static uintptr_t*** box64_jmptbl_48[1<<JMPTABL_SHIFT3];
static uint64_t jmptbl_allocated3 = 0;
static uintptr_t*** box64_jmptbl3[1<<JMPTABL_SHIFT3];
static uintptr_t** box64_jmptbldefault2[1<<JMPTABL_SHIFT2];
#else
#if JMPTABL_SHIFT2 != 16
#error Incorect value for jumptable shift2 that should be 16
#endif
static uintptr_t*** box64_jmptbl3[1<<JMPTABL_SHIFT3];
static uintptr_t** box64_jmptbl_48[1<<JMPTABL_SHIFT2];
static uintptr_t** box64_jmptbl2[1<<JMPTABL_SHIFT2];
#endif
static uintptr_t** box64_jmptbldefault2[1<<JMPTABL_SHIFT2];
static uintptr_t* box64_jmptbldefault1[1<<JMPTABL_SHIFT1];
static uintptr_t box64_jmptbldefault0[1<<JMPTABL_SHIFT0];
// lock addresses
@@ -561,24 +562,57 @@ static uintptr_t defered_prot_p = 0;
static size_t defered_prot_sz = 0;
static uint32_t defered_prot_prot = 0;
static mem_flag_t defered_prot_flags = MEM_ALLOCATED;
static sigset_t critical_prot = {0};
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
#define LOCK_PROT() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
#define LOCK_PROT_READ() sigset_t old_sig = {0}; pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig); mutex_lock(&mutex_prot)
#define LOCK_PROT_FAST() mutex_lock(&mutex_prot)
#define UNLOCK_PROT() if(defered_prot_p) { \
uintptr_t p = defered_prot_p; size_t sz = defered_prot_sz; uint32_t prot = defered_prot_prot; mem_flag_t f = defered_prot_flags;\
defered_prot_p = 0; \
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
mutex_unlock(&mutex_prot); \
setProtection_generic(p, sz, prot, f); \
} else { \
pthread_sigmask(SIG_SETMASK, &old_sig, NULL); \
mutex_unlock(&mutex_prot); \
}
#define UNLOCK_PROT_READ() mutex_unlock(&mutex_prot); pthread_sigmask(SIG_SETMASK, &old_sig, NULL)
#define UNLOCK_PROT_FAST() mutex_unlock(&mutex_prot)
#ifdef _WIN32
void enter_critical_section(void) {}
void leave_critical_section(void) {}
#endif
static void setProtection_generic(uintptr_t addr, size_t sz, uint32_t prot, mem_flag_t flags);
#define LOCK_PROT() \
do { \
enter_critical_section(); \
mutex_lock(&mutex_prot); \
} while (0)
#define LOCK_PROT_READ() \
do { \
enter_critical_section(); \
mutex_lock(&mutex_prot); \
} while (0)
#define LOCK_PROT_FAST() \
do { \
mutex_lock(&mutex_prot); \
} while (0)
#define UNLOCK_PROT() \
do { \
if (defered_prot_p) { \
uintptr_t p = defered_prot_p; \
size_t sz = defered_prot_sz; \
uint32_t prot = defered_prot_prot; \
mem_flag_t f = defered_prot_flags; \
defered_prot_p = 0; \
mutex_unlock(&mutex_prot); \
leave_critical_section(); \
setProtection_generic(p, sz, prot, f); \
} else { \
mutex_unlock(&mutex_prot); \
leave_critical_section(); \
} \
} while (0)
#define UNLOCK_PROT_READ() \
do { \
mutex_unlock(&mutex_prot); \
leave_critical_section(); \
} while (0)
#define UNLOCK_PROT_FAST() \
do { \
mutex_unlock(&mutex_prot); \
} while (0)
#ifdef TRACE_MEMSTAT
static uint64_t customMalloc_allocated = 0;
@@ -1433,25 +1467,13 @@ size_t MmaplistTotalAlloc(mmaplist_t* list)
int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delat_map, uintptr_t mapping_start);
uintptr_t RelocGetNext();
int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t size, intptr_t delta_map, uintptr_t mapping_start)
int MmaplistAddBlock_internal(mmaplist_t* list, void* map, void* orig, size_t size, intptr_t delta_map, uintptr_t mapping_start)
{
if(!list) return -1;
if(list->cap==list->size) {
list->cap += 4;
list->chunks = box_realloc(list->chunks, list->cap*sizeof(blocklist_t**));
}
int i = list->size++;
void* map = MAP_FAILED;
#ifdef BOX32
if(box64_is32bits)
map = box32_dynarec_mmap(size, fd, offset);
#endif
if(map==MAP_FAILED)
map = InternalMmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, offset);
if(map==MAP_FAILED) {
printf_log(LOG_INFO, "Failed to load block %d of a maplist\n", i);
return -3;
}
#ifdef MADV_HUGEPAGE
madvise(map, size, MADV_HUGEPAGE);
#endif
@@ -1476,7 +1498,6 @@ int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t
#define GO(A) if(bl->A) bl->A = ((void*)bl->A)+delta
GO(block);
GO(actual_block);
GO(previous);
GO(instsize);
GO(arch);
GO(callrets);
@@ -1495,8 +1516,18 @@ int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t
db_ref = (bl->jmpnext-sizeof(void*)+3*sizeof(void*));
*db_ref = native_next;
}
// adjust x64_addr with delta_map
if(bl->gone || !bl->done) {
dynarec_log(LOG_DEBUG, "Skipping stale DynCache block %p for %p (done=%d, gone=%d)\n", bl, bl->x64_addr, bl->done, bl->gone);
p = NEXT_BLOCK((blockmark_t*)p);
continue;
}
// adjust guest source addresses with delta_map
bl->x64_addr += delta_map;
bl->x64_readaddr += delta_map;
for (int j = 0; j < bl->sep_size; ++j) {
// SEP native entries also carry a hidden dynablock reference.
*(dynablock_t**)(bl->block + bl->sep[j].nat_offs - sizeof(void*)) = bl;
}
*(uintptr_t*)(bl->jmpnext+2*sizeof(void*)) = RelocGetNext();
if(bl->relocs && bl->relocsize)
ApplyRelocs(bl, delta, delta_map, mapping_start);
@@ -1509,8 +1540,7 @@ int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t
} else {
for(int i=0; i<bl->sep_size; ++i) {
uint32_t x64_offs = bl->sep[i].x64_offs;
uint32_t nat_offs = bl->sep[i].nat_offs;
if(addJumpTableIfDefault64(bl->x64_addr+x64_offs, (bl->dirty || bl->always_test)?bl->jmpnext:(bl->block+nat_offs)))
if (addJumpTableIfDefault64(bl->x64_addr + x64_offs, bl->jmpnext))
bl->sep[i].active = 1;
else
bl->sep[i].active = 0;
@@ -1534,13 +1564,53 @@ int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t
return 0;
}
void MmaplistFillBlocks(mmaplist_t* list, DynaCacheBlock_t* blocks)
int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t size, intptr_t delta_map, uintptr_t mapping_start)
{
if(!list) return -1;
void* map = MAP_FAILED;
#ifdef BOX32
if(box64_is32bits)
map = box32_dynarec_mmap(size, fd, offset);
#endif
if(map==MAP_FAILED)
map = InternalMmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, offset);
if(map==MAP_FAILED) {
printf_log(LOG_INFO, "Failed to Mmap a block of a maplist\n");
return -3;
}
return MmaplistAddBlock_internal(list, map, orig, size, delta_map, mapping_start);
}
#ifndef WIN32
int MmaplistAddCompressedBlock(mmaplist_t* list, int type, void* src, size_t src_size, void* orig, size_t size, intptr_t delta_map, uintptr_t mapping_start)
{
if(!list) return -1;
void* map = MAP_FAILED;
#ifdef BOX32
if(box64_is32bits)
map = box32_dynarec_mmap(size, -1, 0);
#endif
if(map==MAP_FAILED)
map = InternalMmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(map==MAP_FAILED) {
printf_log(LOG_INFO, "Failed to Alloc a block of a maplist\n");
return -3;
}
if(dc_uncompress(src, src_size, type, map, size)) {
printf_log(LOG_INFO, "Failed to Uncompress a block of a maplist\n");
return -3;
}
return MmaplistAddBlock_internal(list, map, orig, size, delta_map, mapping_start);
}
#endif
void MmaplistFillBlocks(mmaplist_t* list, CompressedDynaCacheBlock_t* blocks)
{
if(!list) return;
for(int i=0; i<list->size; ++i) {
blocks[i].block = list->chunks[i];
blocks[i].size = list->chunks[i]->size+sizeof(blocklist_t);
blocks[i].free_size = list->chunks[i]->maxfree;
blocks[i].block.block = list->chunks[i];
blocks[i].block.size = list->chunks[i]->size+sizeof(blocklist_t);
blocks[i].block.free_size = list->chunks[i]->maxfree;
blocks[i].compsize = 0;
blocks[i].type = COMP_NONE;
}
}
@@ -1550,6 +1620,7 @@ void DelMmaplist(mmaplist_t* list)
for(int i=0; i<list->size; ++i)
if(list->chunks[i]->size) {
cleanDBFromAddressRange((uintptr_t)list->chunks[i]->block, list->chunks[i]->size, 1);
DeferFreeDynablockClearRange(list->chunks[i]->block, list->chunks[i]->size);
rb_unset(rbt_dynmem, (uintptr_t)list->chunks[i]->block, (uintptr_t)list->chunks[i]->block+list->chunks[i]->size);
// the blocklist_t "chunk" structure is port of the memory map, so grab info before freing the memory
// also need to include back the blocklist_t that is excluded from the blocklist tracking
@@ -1787,34 +1858,30 @@ void FreeDynarecMap(uintptr_t addr)
static uintptr_t getDBSize(uintptr_t addr, size_t maxsize, dynablock_t** db)
{
if(addr&0xffff000000000000ULL) {*db = NULL; return addr+maxsize;} // address beyond 48bits are not handled
#ifdef JMPTABL_START4
const uintptr_t idx4 = (addr>>JMPTABL_START4)&JMPTABLE_MASK4;
#endif
const uintptr_t idx3 = (addr>>JMPTABL_START3)&JMPTABLE_MASK3;
#endif
const uintptr_t idx2 = (addr>>JMPTABL_START2)&JMPTABLE_MASK2;
const uintptr_t idx1 = (addr>>JMPTABL_START1)&JMPTABLE_MASK1;
uintptr_t idx0 = addr&JMPTABLE_MASK0;
#ifdef JMPTABL_START4
*db = *(dynablock_t**)(box64_jmptbl4[idx4][idx3][idx2][idx1][idx0]- sizeof(void*));
#else
*db = *(dynablock_t**)(box64_jmptbl3[idx3][idx2][idx1][idx0]- sizeof(void*));
#else
*db = *(dynablock_t**)(box64_jmptbl2[idx2][idx1][idx0]- sizeof(void*));
#endif
if(*db)
return addr+1;
#ifdef JMPTABL_START4
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
return ((idx4+1)<<JMPTABL_START4);
if(box64_jmptbl4[idx4][idx3] == box64_jmptbldefault2)
return (((addr>>JMPTABL_START3)+1)<<JMPTABL_START3);
if(box64_jmptbl4[idx4][idx3][idx2] == box64_jmptbldefault1)
return (((addr>>JMPTABL_START2)+1)<<JMPTABL_START2);
uintptr_t* block = box64_jmptbl4[idx4][idx3][idx2][idx1];
#else
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
return ((idx3+1)<<JMPTABL_START3);
return (((addr>>JMPTABL_START3)+1)<<JMPTABL_START3);
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
return (((addr>>JMPTABL_START2)+1)<<JMPTABL_START2);
uintptr_t* block = box64_jmptbl3[idx3][idx2][idx1];
#else
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
return (((addr>>JMPTABL_START2)+1)<<JMPTABL_START2);
uintptr_t* block = box64_jmptbl2[idx2][idx1];
#endif
if(block == box64_jmptbldefault0)
return (((addr>>JMPTABL_START1)+1)<<JMPTABL_START1);
@@ -1870,64 +1937,6 @@ int cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
}
#ifdef JMPTABL_SHIFT4
static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, uintptr_t idx2, uintptr_t idx3, uintptr_t idx4)
{
if(box64_jmptbl4[idx4] == box64_jmptbldefault3) {
uintptr_t**** tbl = (uintptr_t****)customMalloc((1<<JMPTABL_SHIFT3)*sizeof(uintptr_t***));
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i)
tbl[i] = box64_jmptbldefault2;
if(native_lock_storeifref(&box64_jmptbl4[idx4], tbl, box64_jmptbldefault3)!=tbl)
customFree(tbl);
#ifdef TRACE_MEMSTAT
else {
jmptbl_allocated += (1<<JMPTABL_SHIFT3)*sizeof(uintptr_t***);
++jmptbl_allocated4;
}
#endif
}
if(box64_jmptbl4[idx4][idx3] == box64_jmptbldefault2) {
uintptr_t*** tbl = (uintptr_t***)customMalloc((1<<JMPTABL_SHIFT2)*sizeof(uintptr_t**));
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i)
tbl[i] = box64_jmptbldefault1;
if(native_lock_storeifref(&box64_jmptbl4[idx4][idx3], tbl, box64_jmptbldefault2)!=tbl)
customFree(tbl);
#ifdef TRACE_MEMSTAT
else {
jmptbl_allocated += (1<<JMPTABL_SHIFT2)*sizeof(uintptr_t**);
++jmptbl_allocated3;
}
#endif
}
if(for32bits) return NULL;
if(box64_jmptbl4[idx4][idx3][idx2] == box64_jmptbldefault1) {
uintptr_t** tbl = (uintptr_t**)customMalloc((1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*));
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
tbl[i] = box64_jmptbldefault0;
if(native_lock_storeifref(&box64_jmptbl4[idx4][idx3][idx2], tbl, box64_jmptbldefault1)!=tbl)
customFree(tbl);
#ifdef TRACE_MEMSTAT
else {
jmptbl_allocated += (1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*);
++jmptbl_allocated2;
}
#endif
}
if(box64_jmptbl4[idx4][idx3][idx2][idx1] == box64_jmptbldefault0) {
uintptr_t* tbl = (uintptr_t*)customMalloc((1<<JMPTABL_SHIFT0)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
tbl[i] = (uintptr_t)native_next;
if(native_lock_storeifref(&box64_jmptbl4[idx4][idx3][idx2][idx1], tbl, box64_jmptbldefault0)!=tbl)
customFree(tbl);
#ifdef TRACE_MEMSTAT
else {
jmptbl_allocated += (1<<JMPTABL_SHIFT0)*sizeof(uintptr_t);
++jmptbl_allocated1;
}
#endif
}
return &box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
}
#else
static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, uintptr_t idx2, uintptr_t idx3)
{
if(box64_jmptbl3[idx3] == box64_jmptbldefault2) {
@@ -1943,6 +1952,7 @@ static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, u
}
#endif
}
if(for32bits) return NULL;
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) {
uintptr_t** tbl = (uintptr_t**)customMalloc((1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*));
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
@@ -1956,7 +1966,6 @@ static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, u
}
#endif
}
if(for32bits) return NULL;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) {
uintptr_t* tbl = (uintptr_t*)customMalloc((1<<JMPTABL_SHIFT0)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
@@ -1972,189 +1981,218 @@ static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, u
}
return &box64_jmptbl3[idx3][idx2][idx1][idx0];
}
#else
static uintptr_t *create_jmptbl(int for32bits, uintptr_t idx0, uintptr_t idx1, uintptr_t idx2)
{
if(box64_jmptbl2[idx2] == box64_jmptbldefault1) {
uintptr_t** tbl = (uintptr_t**)customMalloc((1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*));
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
tbl[i] = box64_jmptbldefault0;
if(native_lock_storeifref(&box64_jmptbl2[idx2], tbl, box64_jmptbldefault1)!=tbl)
customFree(tbl);
#ifdef TRACE_MEMSTAT
else {
jmptbl_allocated += (1<<JMPTABL_SHIFT1)*sizeof(uintptr_t*);
++jmptbl_allocated2;
}
#endif
}
if(for32bits) return NULL;
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0) {
uintptr_t* tbl = (uintptr_t*)customMalloc((1<<JMPTABL_SHIFT0)*sizeof(uintptr_t));
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
tbl[i] = (uintptr_t)native_next;
if(native_lock_storeifref(&box64_jmptbl2[idx2][idx1], tbl, box64_jmptbldefault0)!=tbl)
customFree(tbl);
#ifdef TRACE_MEMSTAT
else {
jmptbl_allocated += (1<<JMPTABL_SHIFT0)*sizeof(uintptr_t);
++jmptbl_allocated1;
}
#endif
}
return &box64_jmptbl2[idx2][idx1][idx0];
}
#endif
int addJumpTableIfDefault64(void* addr, void* jmp)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return 0;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4;
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
#endif
uintptr_t idx3;
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
#endif
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
#ifdef JMPTABL_SHIFT4
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, native_next)==native_next)?1:0;
#else
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, native_next)==native_next)?1:0;
#else
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2), jmp, native_next)==native_next)?1:0;
#endif
}
void setJumpTableDefault64(void* addr)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4;
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
return;
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
#endif
uintptr_t idx3;
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
return;
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
#endif
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
return;
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
return;
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
native_lock_store_dd(&box64_jmptbl3[idx3][idx2][idx1][idx0], (uintptr_t)native_next);
native_lock_store_dd(&box64_jmptbl2[idx2][idx1][idx0], (uintptr_t)native_next);
}
int setJumpTableDefaultIfRef64(void* addr, void* jmp)
{
uintptr_t idx3, idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return 0;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4;
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
return 0;
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
#endif
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
return 0;
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
#endif
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
return 0;
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
return 0;
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
#ifdef JMPTABL_SHIFT4
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), native_next, jmp)==jmp)?1:0;
#else
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), native_next, jmp)==jmp)?1:0;
#else
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2), native_next, jmp)==jmp)?1:0;
#endif
}
void setJumpTableDefaultRef64(void* addr, void* jmp)
{
uintptr_t idx3, idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4;
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
return;
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
#endif
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
return;
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
#endif
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
return;
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
return;
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
native_lock_storeifref2(&box64_jmptbl3[idx3][idx2][idx1][idx0], native_next, jmp);
native_lock_storeifref2(&box64_jmptbl2[idx2][idx1][idx0], native_next, jmp);
}
int setJumpTableIfRef64(void* addr, void* jmp, void* ref)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return 0;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
uintptr_t idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
#endif
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
#ifdef JMPTABL_SHIFT4
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, ref)==ref)?1:0;
void* ret = native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, ref);
#else
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, ref)==ref)?1:0;
void* ret = native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2), jmp, ref);
#endif
return ((ret==ref) || (ret==jmp))?1:0;
}
int isJumpTableDefault64(void* addr)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return 0;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4;
idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
if(box64_jmptbl4[idx4] == box64_jmptbldefault3)
return 1;
uintptr_t ****box64_jmptbl3 = box64_jmptbl4[idx4];
#endif
uintptr_t idx3;
idx3 = (((uintptr_t)addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
return 1;
uintptr_t ***box64_jmptbl2 = box64_jmptbl3[idx3];
#endif
idx2 = (((uintptr_t)addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
if(box64_jmptbl2[idx2] == box64_jmptbldefault1)
return 1;
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
if(box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0)
return 1;
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
return (box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)native_next)?1:0;
return (box64_jmptbl2[idx2][idx1][idx0]==(uintptr_t)native_next)?1:0;
}
uintptr_t getJumpTable64()
{
#ifdef JMPTABL_SHIFT4
return (uintptr_t)box64_jmptbl4;
#else
return (uintptr_t)box64_jmptbl3;
#else
return (uintptr_t)box64_jmptbl2;
#endif
}
uintptr_t getJumpTable48()
{
return (uintptr_t)box64_jmptbl_48;
#ifdef JMPTABL_SHIFT4
return (uintptr_t)box64_jmptbl3;
#else
return (uintptr_t)box64_jmptbl2;
#endif
}
uintptr_t getJumpTable32()
{
#ifdef JMPTABL_SHIFT4
create_jmptbl(1, 0, 0, 0, 0, 0);
return (uintptr_t)box64_jmptbl4[0][0];
#else
create_jmptbl(1, 0, 0, 0, 0);
return (uintptr_t)box64_jmptbl3[0][0];
return (uintptr_t)box64_jmptbl3[0];
#else
create_jmptbl(1, 0, 0, 0);
return (uintptr_t)box64_jmptbl2[0];
#endif
}
uintptr_t getJumpTableAddress64(uintptr_t addr)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return getJumpTableAddress64(0); // this should not happens
#ifdef JMPTABL_SHIFT4
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
uintptr_t idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
#endif
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
idx0 = ((addr) )&JMPTABLE_MASK0;
#ifdef JMPTABL_SHIFT4
return (uintptr_t)create_jmptbl(0, idx0, idx1, idx2, idx3, idx4);
#else
return (uintptr_t)create_jmptbl(0, idx0, idx1, idx2, idx3);
#else
return (uintptr_t)create_jmptbl(0, idx0, idx1, idx2);
#endif
}
dynablock_t* getDBBlock(uintptr_t addr, void** jblock)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
if((uintptr_t)addr&0xffff000000000000UL) return NULL;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
uintptr_t idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
#endif
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
idx0 = ((addr) )&JMPTABLE_MASK0;
#ifdef JMPTABL_SHIFT4
uintptr_t ret = (uintptr_t)box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
#else
uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
#else
uintptr_t ret = (uintptr_t)box64_jmptbl2[idx2][idx1][idx0];
#endif
if(jblock) *jblock = (void*)ret;
@@ -2187,18 +2225,17 @@ dynablock_t* getDBnoTest(uintptr_t addr)
uintptr_t getJumpAddress64(uintptr_t addr)
{
uintptr_t idx3, idx2, idx1, idx0;
uintptr_t idx2, idx1, idx0;
#ifdef JMPTABL_SHIFT4
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
uintptr_t idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
#endif
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
idx0 = ((addr) )&JMPTABLE_MASK0;
#ifdef JMPTABL_SHIFT4
return (uintptr_t)box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
#else
return (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
#else
return (uintptr_t)box64_jmptbl2[idx2][idx1][idx0];
#endif
}
@@ -2408,36 +2445,6 @@ void neverprotectDB(uintptr_t addr, size_t size, int mark)
UNLOCK_PROT();
}
// Remove the NEVERCLEAN flag for an adress range
void unneverprotectDB(uintptr_t addr, size_t size)
{
dynarec_log(LOG_DEBUG, "unneverprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
uintptr_t cur = addr&~(box64_pagesize-1);
uintptr_t end = ALIGN(addr+size);
LOCK_PROT();
while(cur!=end) {
uint32_t prot = 0, oprot;
uintptr_t bend = 0;
if (!rb_get_end(memprot, cur, &prot, &bend)) {
if(bend>=end) break;
else {
cur = bend;
continue;
}
}
oprot = prot;
if(bend>end)
bend = end;
prot &= ~PROT_NEVERCLEAN;
if (prot != oprot)
rb_set(memprot, cur, bend, prot);
cur = bend;
}
UNLOCK_PROT();
}
int isprotectedDB(uintptr_t addr, size_t size)
{
dynarec_log(LOG_DEBUG, "isprotectedDB %p -> %p => ", (void*)addr, (void*)(addr+size-1));
@@ -2516,11 +2523,16 @@ void CheckHotPage(uintptr_t addr, uint32_t prot)
{
if(addr>=0x1000000000000LL) // more than 48bits
return;
if(prot&PROT_NEVERCLEAN && BOX64ENV(dynarec_dirty)==2)
return;
if(BOX64ENV(dynarec_nohotpage))
if((prot&PROT_NEVERCLEAN) && BOX64ENV(dynarec_dirty)==2)
return;
uintptr_t page = addr>>12;
if(BOX64ENV(dynarec_nohotpage)) {
if(BOX64ENV(dynarec_dirty)==2) {
dynarec_log(LOG_INFO, "Switching page at %p to NEVERCLEAN\n", (void*)(page<<12));
neverprotectDB(page<<12, box64_pagesize, 2);
}
return;
}
// look for idx
int idx = IdxHotPage(page);
if(idx!=-1 && (BOX64ENV(dynarec_dirty)>1)) {
@@ -2577,6 +2589,9 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
LOCK_PROT();
uintptr_t cur = addr & ~(box64_pagesize-1);
uintptr_t end = ALIGN(cur+size);
#ifdef DYNAREC
int check = BOX64ENV(dynarec);
#endif
//rb_set(mapallmem, cur, cur+size, MEM_ALLOCATED);
while (cur < end) {
uintptr_t bend;
@@ -2584,7 +2599,21 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
rb_get_end(memprot, cur, &oprot, &bend);
if(bend>end) bend = end;
uint32_t dyn=(oprot&PROT_DYN);
uint32_t never = dyn&PROT_NEVERPROT;
if (dyn & PROT_NOPROT) {
cur = bend;
continue;
}
uint32_t never = dyn & PROT_NEVERCLEAN;
#ifdef DYNAREC
if(check && ((prot ^ oprot) & PROT_EXEC) && !never) { // prot_exec changed
if(prot & PROT_EXEC) {
// no need to do anything
/*if(!IsAddrMappingLoadAndClean(cur))
addDBFromAddressRange(cur, bend-cur);*/
} else
cleanDBFromAddressRange(cur, bend-cur, (!prot)?1:0);
}
#endif
if(!(never)) {
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
dyn = PROT_DYNAREC;
@@ -2737,6 +2766,15 @@ void loadProtectionFromMap()
have48bits = 1;
}
}
if(!have48bits && !box64_is32bits) {
void* probe = InternalMmap((void*)0x7fff00000000LL, box64_pagesize, PROT_NONE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
if(probe!=MAP_FAILED) {
if((uintptr_t)probe>=0x7fff00000000LL)
have48bits = 1;
InternalMunmap(probe, box64_pagesize);
}
}
static int shown48bits = 0;
if(!shown48bits) {
shown48bits = 1;
@@ -2784,7 +2822,12 @@ uint32_t getProtection_fast(uintptr_t addr)
int getMmapped(uintptr_t addr)
{
return (rb_get(mapallmem, addr)&MEM_ALLOCATED); // will be ok for both MEM_ALLOCATED & MEM_MMAP
return (rb_get(mapallmem, addr)&MEM_MMAP) == MEM_MMAP;
}
int getMAllocated(uintptr_t addr)
{
return (rb_get(mapallmem, addr)&MEM_ALLOCATED);
}
int memExist(uintptr_t addr)
@@ -2797,13 +2840,22 @@ int memExist(uintptr_t addr)
#define MEDIUM (void*)0x40000000
#define HIGH (void*)0x60000000
// only track what brk added: re-tracking the whole heap would lose PROT_EXEC on
// pages the guest made executable in it (like hook trampolines)
static void catchup_brk_protection(void)
{
if(pbrk && cur_brk && *cur_brk!=old_brk) {
uintptr_t prev = old_brk ? old_brk : pbrk;
old_brk = *cur_brk;
if(old_brk > prev)
setProtection(prev, old_brk-prev, PROT_READ|PROT_WRITE);
}
}
void* find31bitBlockNearHint(void* hint_, size_t size, uintptr_t mask)
{
// first, check if program break as changed
if(pbrk && cur_brk && *cur_brk!=old_brk) {
old_brk = *cur_brk;
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
}
catchup_brk_protection();
uint32_t prot;
uintptr_t hint = (uintptr_t)hint_;
if(hint_<LOWEST) hint = (uintptr_t)WINE_LOWEST;
@@ -2854,10 +2906,7 @@ void* find47bitBlock(size_t size)
void* find47bitBlockNearHint(void* hint, size_t size, uintptr_t mask)
{
// first, check if program break as changed
if(pbrk && cur_brk && *cur_brk!=old_brk) {
old_brk = *cur_brk;
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
}
catchup_brk_protection();
uint32_t prot;
if(hint<LOWEST) hint = LOWEST;
uintptr_t bend = 0;
@@ -3058,31 +3107,22 @@ void init_custommem_helper(box64context_t* ctx)
for(int i=0; i<n_blocks; ++i)
rb_set(blockstree, (uintptr_t)p_blocks[i].block, (uintptr_t)p_blocks[i].block+p_blocks[i].size, i);
memprot = rbtree_init("memprot");
sigfillset(&critical_prot);
#ifdef DYNAREC
if(BOX64ENV(dynarec)) {
#ifdef JMPTABL_SHIFT4
for(int i=0; i<(1<<JMPTABL_SHIFT4); ++i)
box64_jmptbl4[i] = box64_jmptbldefault3;
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i) {
box64_jmptbldefault3[i] = box64_jmptbldefault2;
box64_jmptbl_48[i] = box64_jmptbldefault2;
#ifdef JMPTABL_SHIFT4
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i) {
box64_jmptbl3[i] = box64_jmptbldefault2;
}
box64_jmptbl4[0] = box64_jmptbl_48;
#else
for(int i=0; i<(1<<JMPTABL_SHIFT3); ++i) {
box64_jmptbl3[i] = box64_jmptbldefault2;
box64_jmptbl_48[i] = box64_jmptbldefault1;
}
box64_jmptbl3[0] = box64_jmptbl_48;
#endif
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i)
box64_jmptbldefault2[i] = box64_jmptbldefault1;
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
box64_jmptbldefault1[i] = box64_jmptbldefault0;
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
box64_jmptbldefault0[i] = (uintptr_t)native_next;
}
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i)
box64_jmptbldefault2[i] = box64_jmptbldefault1;
#else
for(int i=0; i<(1<<JMPTABL_SHIFT2); ++i) {
box64_jmptbl2[i] = box64_jmptbldefault1;
}
#endif
for(int i=0; i<(1<<JMPTABL_SHIFT1); ++i)
box64_jmptbldefault1[i] = box64_jmptbldefault0;
for(int i=0; i<(1<<JMPTABL_SHIFT0); ++i)
box64_jmptbldefault0[i] = (uintptr_t)native_next;
lockaddress = kh_init(lockaddress);
rbt_dynmem = rbtree_init("rbt_dynmem");
#endif
@@ -3100,32 +3140,29 @@ void fini_custommem_helper(box64context_t *ctx)
#ifdef TRACE_MEMSTAT
uintptr_t njmps = 0, njmps_in_lv1_max = 0;
#ifdef JMPTABL_SHIFT4
uintptr_t**** box64_jmptbl3;
for(uintptr_t idx4 = 0; idx4 < (1<< JMPTABL_SHIFT4); ++idx4) {
if (box64_jmptbl4[idx4] == box64_jmptbldefault3) continue;
box64_jmptbl3 = box64_jmptbl4[idx4];
#endif
for (uintptr_t idx3 = 0; idx3 < (1 << JMPTABL_SHIFT3); ++idx3) {
uintptr_t*** box64_jmptbl2;
for(uintptr_t idx3 = 0; idx3 < (1<< JMPTABL_SHIFT3); ++idx3) {
if (box64_jmptbl3[idx3] == box64_jmptbldefault2) continue;
for (uintptr_t idx2 = 0; idx2 < (1 << JMPTABL_SHIFT2); ++idx2) {
if (box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1) continue;
for (uintptr_t idx1 = 0; idx1 < (1 << JMPTABL_SHIFT1); ++idx1) {
if (box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0) continue;
uintptr_t njmps_in_cur_lv1 = 0;
for (uintptr_t idx0 = 0; idx0 < (1 << JMPTABL_SHIFT0); ++idx0) {
if (box64_jmptbl3[idx3][idx2][idx1][idx0] == (uintptr_t)native_next) continue;
++njmps;
++njmps_in_cur_lv1;
}
if (njmps_in_cur_lv1 > njmps_in_lv1_max) njmps_in_lv1_max = njmps_in_cur_lv1;
box64_jmptbl3 = box64_jmptbl3[idx3];
#endif
for (uintptr_t idx2 = 0; idx2 < (1 << JMPTABL_SHIFT2); ++idx2) {
if (box64_jmptbl2[idx2] == box64_jmptbldefault1) continue;
for (uintptr_t idx1 = 0; idx1 < (1 << JMPTABL_SHIFT1); ++idx1) {
if (box64_jmptbl2[idx2][idx1] == box64_jmptbldefault0) continue;
uintptr_t njmps_in_cur_lv1 = 0;
for (uintptr_t idx0 = 0; idx0 < (1 << JMPTABL_SHIFT0); ++idx0) {
if (box64_jmptbl2[idx2][idx1][idx0] == (uintptr_t)native_next) continue;
++njmps;
++njmps_in_cur_lv1;
}
if (njmps_in_cur_lv1 > njmps_in_lv1_max) njmps_in_lv1_max = njmps_in_cur_lv1;
}
}
#ifdef JMPTABL_SHIFT4
}
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 4, %lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated4, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
#else
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
#else
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
#endif
if(BOX64ENV(log)) testAllBlocks();
#endif
@@ -3145,29 +3182,25 @@ void fini_custommem_helper(box64context_t *ctx)
box_free(head);
}
#ifdef JMPTABL_SHIFT4
uintptr_t**** box64_jmptbl3;
for(int i4 = 0; i4 < (1<< JMPTABL_SHIFT4); ++i4)
if (box64_jmptbl4[i4] != box64_jmptbldefault3) {
box64_jmptbl3 = box64_jmptbl4[i4];
uintptr_t*** box64_jmptbl2;
for(int i3 = 0; i3 < (1<< JMPTABL_SHIFT3); ++i3)
if (box64_jmptbl3[i3] != box64_jmptbldefault2) {
box64_jmptbl2 = box64_jmptbl3[i3];
#endif
for (int i3=0; i3<(1<<JMPTABL_SHIFT3); ++i3)
if(box64_jmptbl3[i3]!=box64_jmptbldefault2) {
for (int i2=0; i2<(1<<JMPTABL_SHIFT2); ++i2)
if(box64_jmptbl3[i3][i2]!=box64_jmptbldefault1) {
for (int i1=0; i1<(1<<JMPTABL_SHIFT1); ++i1)
if(box64_jmptbl3[i3][i2][i1]!=box64_jmptbldefault0) {
customFree(box64_jmptbl3[i3][i2][i1]);
}
customFree(box64_jmptbl3[i3][i2]);
for (int i2=0; i2<(1<<JMPTABL_SHIFT2); ++i2)
if(box64_jmptbl2[i2]!=box64_jmptbldefault1) {
for (int i1=0; i1<(1<<JMPTABL_SHIFT1); ++i1)
if(box64_jmptbl2[i2][i1]!=box64_jmptbldefault0) {
customFree(box64_jmptbl2[i2][i1]);
}
#ifndef JMPTABL_SHIFT4
if(i3)
if(i2)
#endif
customFree(box64_jmptbl3[i3]);
customFree(box64_jmptbl2[i2]);
}
#ifdef JMPTABL_SHIFT4
if(i4)
customFree(box64_jmptbl4[i4]);
if(i3)
customFree(box64_jmptbl3[i3]);
}
#endif
}
@@ -3256,6 +3289,12 @@ EXPORT void* box_mmap(void *addr, size_t length, int prot, int flags, int fd, ss
}
#endif
void* ret = InternalMmap(addr, length, prot, new_flags, fd, offset);
// io_uring doesn't support non-NULL address.
// The optimal approach is to detect whether an fd is an io_uring instance,
// but this is overly complex. So we simply retry the mmap call with the
// original address here.
if (ret == MAP_FAILED && old_addr == NULL && fd >= 0)
ret = InternalMmap(old_addr, length, prot, new_flags, fd, offset);
#if !defined(NOALIGN)
if((ret!=MAP_FAILED) && (flags&MAP_32BIT) &&
(((uintptr_t)ret>0xffffffffLL) || ((box64_wine) && ((uintptr_t)ret&0xffff) && (ret!=addr)))) {
+142 -74
View File
@@ -950,7 +950,26 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x62:
nextop = F8;
if(rex.is32bits && !MODREG) {
if(!rex.is32bits) {
vex_t vex = {0};
u8 = F8;
u16 = F8;
if(FillVEXFromEVEX(&vex, rex, nextop, u8, u16)) {
INST_NAME("EVEX");
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
} else {
INST_NAME("Illegal 62");
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);
UDF(0);
*need_epilog = 1;
*ok = 0;
}
} else if(!MODREG) {
INST_NAME("BOUND Gd, Ed");
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
LDRxw_U12(x2, wback, 0);
@@ -1048,9 +1067,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x69:
INST_NAME("IMUL Gd, Ed, Id");
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
nextop = F8;
GETGD;
@@ -1119,9 +1138,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0x6B:
INST_NAME("IMUL Gd, Ed, Ib");
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
nextop = F8;
GETGD;
@@ -1823,7 +1842,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x9D:
INST_NAME("POPF");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
POP1z(xFlags);
MOV32w(x1, 0x3E7FD7);
ANDw_REG(xFlags, xFlags, x1);
@@ -1987,6 +2006,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP MOVSB");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
@@ -2039,11 +2062,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("MOVSB");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 1);
LDRB_U12(x1, xRSI, 0);
STRB_U12(x1, xRDI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
break;
@@ -2052,6 +2079,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP MOVSD");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRxw_S9_postindex(x1, xRSI, rex.w?8:4);
@@ -2067,11 +2098,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("MOVSD");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, rex.w?8:4);
LDRxw_U12(x1, xRSI, 0);
STRxw_U12(x1, xRDI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
break;
@@ -2082,11 +2117,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep==1) {INST_NAME("REPNZ CMPSB");} else {INST_NAME("REPZ CMPSB");}
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
SMREAD();
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRB_S9_postindex(x1, xRSI, 1);
@@ -2109,12 +2148,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
INST_NAME("CMPSB");
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 1);
SMREAD();
LDRB_U12(x1, xRSI, 0);
LDRB_U12(x2, xRDI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
break;
}
@@ -2126,11 +2169,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep==1) {INST_NAME("REPNZ CMPSD");} else {INST_NAME("REPZ CMPSD");}
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
SMREAD();
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRxw_S9_postindex(x1, xRSI, rex.w?8:4);
@@ -2153,12 +2200,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
INST_NAME("CMPSD");
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, rex.w?8:4);
SMREAD();
LDRxw_U12(x1, xRSI, 0);
LDRxw_U12(x2, xRDI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
break;
}
@@ -2181,6 +2232,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP STOSB");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
TBNZ_MARK2(xFlags, F_DF);
IF_UNALIGNED(ip) {
MESSAGE(LOG_DEBUG, "\tUnaligned path");
@@ -2225,9 +2279,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("STOSB");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, 1);
STRB_U12(xRAX, xRDI, 0);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
break;
@@ -2235,6 +2292,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP STOSD");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
STRxw_S9_postindex(xRAX, xRDI, rex.w?8:4);
@@ -2249,9 +2309,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("STOSD");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, rex.w?8:4);
STRxw_U12(xRAX, xRDI, 0);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
break;
@@ -2267,8 +2330,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBZx_NEXT(xRCX);
MARK;
}
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRSI, xRSI);
}
LDRB_U12(x2, xRSI, 0);
ADDx_REG(xRSI, xRSI, x1);
ADDy_REG(xRSI, xRSI, x1);
if(rex.rep) {
SUBx_U12(xRCX, xRCX, 1);
CBNZx_MARK(xRCX);
@@ -2286,8 +2352,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
CBZx_NEXT(xRCX);
MARK;
}
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRSI, xRSI);
}
LDRxw_U12(xRAX, xRSI, 0);
ADDx_REG(xRSI, xRSI, x1);
ADDy_REG(xRSI, xRSI, x1);
if(rex.rep) {
SUBx_U12(xRCX, xRCX, 1);
CBNZx_MARK(xRCX);
@@ -2300,11 +2369,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep==1) {INST_NAME("REPNZ SCASB");} else {INST_NAME("REPZ SCASB");}
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
SMREAD();
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
UBFXw(x1, xRAX, 0, 8);
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
@@ -2326,10 +2398,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
INST_NAME("SCASB");
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, 1);
UBFXw(x1, xRAX, 0, 8);
LDRB_U12(x2, xRDI, 0);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
break;
}
@@ -2341,11 +2416,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep==1) {INST_NAME("REPNZ SCASD");} else {INST_NAME("REPZ SCASD");}
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
SMREAD();
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRxw_S9_postindex(x2, xRDI, rex.w?8:4);
@@ -2366,9 +2444,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
INST_NAME("SCASD");
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, rex.w?8:4);
LDRxw_U12(x2, xRDI, 0);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
break;
}
@@ -2428,10 +2509,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROL Eb, Ib");
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
if(u8) {
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETEB(x1, 1);
u8 = F8&0x1f;
emit_rol8c(dyn, ninst, x1, u8, x4, x5);
emit_rol8c(dyn, ninst, x1, u8, x4, x5, MODREG);
EBBACK;
} else {
FAKEED;
@@ -2442,10 +2523,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROR Eb, Ib");
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
if(u8) {
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETEB(x1, 1);
u8 = F8&0x1f;
emit_ror8c(dyn, ninst, x1, u8, x4, x5);
emit_ror8c(dyn, ninst, x1, u8, x4, x5, MODREG);
EBBACK;
} else {
FAKEED;
@@ -2534,7 +2615,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROL Ed, Ib");
u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
if(u8) {
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETED(1);
u8 = (F8)&(rex.w?0x3f:0x1f);
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
@@ -2553,7 +2634,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROR Ed, Ib");
u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
if(u8) {
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETED(1);
u8 = (F8)&(rex.w?0x3f:0x1f);
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
@@ -3068,14 +3149,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROL Eb, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
GETEB(x1, 0);
emit_rol8c(dyn, ninst, ed, 1, x4, x5);
emit_rol8c(dyn, ninst, ed, 1, x4, x5, 0);
EBBACK;
break;
case 1:
INST_NAME("ROR Eb, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
GETEB(x1, 0);
emit_ror8c(dyn, ninst, ed, 1, x4, x5);
emit_ror8c(dyn, ninst, ed, 1, x4, x5, 0);
EBBACK;
break;
case 2:
@@ -3322,7 +3403,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHL Eb, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
@@ -3337,7 +3418,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHR Eb, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
@@ -3352,7 +3433,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SAR Eb, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
@@ -3446,9 +3527,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
}
GETED(0);
UFLAG_IF {
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
}
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
CBZw_NEXT(x3);
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4, x6);
WBACK;
@@ -3467,9 +3546,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
}
GETED(0);
UFLAG_IF {
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
}
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
CBZw_NEXT(x3);
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4, x6);
WBACK;
@@ -3479,7 +3556,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHL Ed, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.w) {
@@ -3499,7 +3576,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHR Ed, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.w) {
@@ -3519,7 +3596,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SAR Ed, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.w) {
@@ -3820,22 +3897,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
BARRIER(BARRIER_FLOAT);
//fpu_purgecache(dyn, ninst, 0, x1, x3, x4, 0);
PUSH1z(x2);
int can_continue = (addr < (dyn->start + dyn->isize));
if (BOX64DRENV(dynarec_callret)) {
SET_HASCALLRET();
// Push actual return address
if(addr < (dyn->start+dyn->isize)) {
// there is a next...
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
if(can_continue && BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
} else {
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
}
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
STPx_S7_preindex(x4, x2, xSP, -16);
} else {
*ok = 0;
@@ -3845,12 +3916,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
j64 = (uint32_t)(addr+i32);
else
j64 = addr+i32;
j64 = (uintptr_t)getAlternate((void*)j64);
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
int can_continue = (addr < (dyn->start + dyn->isize));
CALLRET_RET(can_continue);
MARK;
if (BOX64DRENV(dynarec_callret) && !can_continue) {
// jumps out of current dynablock...
MARK;
j64 = getJumpTableAddress64(addr);
if(dyn->need_reloc) {
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
@@ -4022,9 +4093,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("MUL AL, Eb");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
GETEB(x1, 0);
UXTBw(x2, xRAX);
@@ -4052,9 +4123,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 5:
INST_NAME("IMUL AL, Eb");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
GETSEB(x1, 0);
SXTBw(x2, xRAX);
@@ -4083,7 +4154,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 6:
INST_NAME("DIV Eb");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
FORCE_DFNONE();
GETEB(x1, 0);
UXTHw(x2, xRAX);
@@ -4121,7 +4192,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("IDIV Eb");
SKIPTEST(x1);
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else if (BOX64ENV(cputype)) {
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
}
@@ -4181,9 +4252,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("MUL EAX, Ed");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
GETED(0);
if(rex.w) {
@@ -4218,9 +4289,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 5:
INST_NAME("IMUL EAX, Ed");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
GETED(0);
if(rex.w) {
@@ -4254,7 +4325,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 6:
INST_NAME("DIV Ed");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
FORCE_DFNONE();
if(!rex.w) {
GETED(0);
@@ -4352,9 +4423,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("IDIV Ed");
SKIPTEST(x1);
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else if (BOX64ENV(cputype)) {
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
}
if(!rex.w) {
GETSEDw(0);
@@ -4595,10 +4666,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
} else {
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
j64 = CALLRET_GETRET();
else
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
ADR_S20(x4, j64);
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
}
+9 -9
View File
@@ -1874,7 +1874,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHLD Ed, Gd, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
@@ -1964,7 +1964,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHRD Ed, Gd, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGD;
@@ -2075,7 +2075,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
MOV32w(x2, rex.w?0:1);
MOV32w(x2, rex.is32bits);
CALL(const_fpu_xsave, -1);
break;
case 5:
@@ -2084,7 +2084,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
MOV32w(x2, rex.w?0:1);
MOV32w(x2, rex.is32bits);
CALL(const_fpu_xrstor, -1);
break;
case 7:
@@ -2100,9 +2100,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xAF:
INST_NAME("IMUL Gd, Ed");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
nextop = F8;
GETGD;
@@ -2421,7 +2421,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
SETFLAGS(X_ZF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
SET_DFNONE();
nextop = F8;
@@ -2459,7 +2459,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
SETFLAGS(X_ZF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
SET_DFNONE();
nextop = F8;
@@ -2671,7 +2671,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(MODREG) switch((nextop>>3)&7) {
case 6:
INST_NAME("RDRAND Ed");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
SET_DFNONE();
GETED(0);
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
+62 -28
View File
@@ -424,9 +424,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("IMUL Gw,Ew,Ib");
}
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
nextop = F8;
GETSEW(x1, (opcode==0x69)?2:1);
@@ -787,7 +787,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0x9D:
INST_NAME("POPF");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
SMREAD();
POP1_16(x1);
MOV32w(x2, 0x7FD7);
@@ -883,6 +883,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP MOVSW");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRH_S9_postindex(x1, xRSI, 2);
@@ -898,11 +902,15 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("MOVSW");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 2);
LDRH_U12(x1, xRSI, 0);
STRH_U12(x1, xRDI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
break;
@@ -915,10 +923,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRH_S9_postindex(x1, xRSI, 2);
@@ -941,11 +953,15 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
INST_NAME("CMPSW");
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 2);
LDRH_U12(x1, xRSI, 0);
LDRH_U12(x2, xRDI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRSI, xRSI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
break;
}
@@ -963,6 +979,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP STOSW");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
STRH_S9_postindex(xRAX, xRDI, 2);
@@ -977,9 +996,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("STOSW");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, 2);
STRH_U12(xRAX, xRDI, 0);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRDI, xRDI, x3);
}
SMWRITE();
break;
@@ -988,6 +1010,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep) {
INST_NAME("REP LODSW");
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRSI, xRSI);
}
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
LDRH_S9_postindex(x2, xRSI, 2);
@@ -1003,9 +1028,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
// done
} else {
INST_NAME("LODSW");
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRSI, xRSI);
}
GETDIR(x3, 2);
LDRH_U12(x2, xRSI, 0);
ADDx_REG(xRSI, xRSI, x3);
ADDy_REG(xRSI, xRSI, x3);
BFIz(xRAX, x2, 0, 16);
}
break;
@@ -1017,10 +1045,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
if(rex.rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
CBZx_NEXT(xRCX);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
UXTHw(x1, xRAX);
TBNZ_MARK2(xFlags, F_DF);
MARK; // Part with DF==0
@@ -1042,10 +1073,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
default:
INST_NAME("SCASW");
SETFLAGS(X_ALL, SF_SET_PENDING);
if(rex.is67 && !rex.is32bits) {
MOVw_REG(xRDI, xRDI);
}
GETDIR(x3, 2);
UXTHw(x1, xRAX);
LDRH_U12(x2, xRDI, 0);
ADDx_REG(xRDI, xRDI, x3);
ADDy_REG(xRDI, xRDI, x3);
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
break;
}
@@ -1076,10 +1110,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROL Ew, Ib");
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
if (u8) {
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETEW(x1, 1);
u8 = (F8)&0x1f;
emit_rol16c(dyn, ninst, x1, u8, x4, x5);
emit_rol16c(dyn, ninst, x1, u8, x4, x5, MODREG);
EWBACK;
} else {
FAKEED;
@@ -1089,10 +1123,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 1:
INST_NAME("ROR Ew, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
GETEW(x1, 1);
u8 = (F8)&0x1f;
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
emit_ror16c(dyn, ninst, x1, u8, x4, x5, MODREG);
EWBACK;
} else {
FAKEED;
@@ -1207,14 +1241,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("ROL Ew, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
GETEW(x1, 0);
emit_rol16c(dyn, ninst, x1, 1, x5, x4);
emit_rol16c(dyn, ninst, x1, 1, x5, x4, 0);
EWBACK;
break;
case 1:
INST_NAME("ROR Ew, 1");
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
GETEW(x1, 0);
emit_ror16c(dyn, ninst, x1, 1, x5, x4);
emit_ror16c(dyn, ninst, x1, 1, x5, x4, 0);
EWBACK;
break;
case 2:
@@ -1405,7 +1439,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHL Ew, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
@@ -1420,7 +1454,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SHR Ew, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
@@ -1435,7 +1469,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("SAR Ew, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
@@ -1545,9 +1579,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 4:
INST_NAME("MUL AX, Ew");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
GETEW(x1, 0);
UXTHw(x2, xRAX);
@@ -1576,9 +1610,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 5:
INST_NAME("IMUL AX, Ew");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
GETSEW(x1, 0);
SXTHw(x2, xRAX);
@@ -1607,7 +1641,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 6:
INST_NAME("DIV Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
GETEW(x1, 0);
UXTHw(x2, xRAX);
BFIw(x2, xRDX, 16, 16);
@@ -1647,9 +1681,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
INST_NAME("IDIV Ew");
SKIPTEST(x1);
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else if (BOX64ENV(cputype)) {
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
}
GETSEW(x1, 0);
if(BOX64ENV(dynarec_div0)) {
+13 -11
View File
@@ -304,7 +304,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
// no special check...
case 0x2F:
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
nextop = F8;
GETGX(v0, 0);
GETEXSD(q0, 0, 0);
@@ -497,7 +497,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0x17:
INST_NAME("PTEST Gx, Ex");
nextop = F8;
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
GETGX(v0, 0);
GETEX(v1, 0, 0);
q0 = fpu_get_scratch(dyn, ninst);
@@ -1367,7 +1367,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
GETG;
u8 = geted_ib(dyn, addr, ninst, nextop);
if((u8&0b1100)==0b1000) {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
// this case is (un)signed word, equal each
GETGX(v0, 0);
GETEX(v1, 0, 1);
@@ -2058,7 +2058,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
v1 = fpu_get_scratch(dyn, ninst);
v1 = fpu_get_scratch(dyn, ninst);
}
u8 = F8;
GETGX_empty(v0);
@@ -2485,7 +2485,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("SHLD Ew, Gw, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGW(x2);
@@ -2554,7 +2554,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
INST_NAME("SHRD Ew, Gw, CL");
if(BOX64DRENV(dynarec_safeflags)>1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
} else
SETFLAGS(X_ALL, SF_SET_PENDING);
GETGW(x2);
@@ -2593,9 +2593,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xAF:
INST_NAME("IMUL Gw,Ew");
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
SETFLAGS(X_OF|X_CF, SF_SET);
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
nextop = F8;
GETSEW(x1, 0);
@@ -2809,7 +2809,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
SETFLAGS(X_ZF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
SET_DFNONE();
nextop = F8;
@@ -2845,7 +2845,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
SETFLAGS(X_ZF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
SET_DFNONE();
nextop = F8;
@@ -2923,9 +2923,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
nextop = F8;
GETGW(x1);
GETEW(x2, 0);
BFIx(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 0, 16);
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
if (!(MODREG && wback == u8)) MOVx_REG(x6, ed);
emit_add16(dyn, ninst, ed, gd, x4, x5);
EWBACK;
if (!(MODREG && wback == u8)) BFIx(u8, x6, 0, 16);
break;
case 0xC2:
INST_NAME("CMPPD Gx, Ex, Ib");
+3 -3
View File
@@ -49,7 +49,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
switch(opcode) {
case 0xB8:
INST_NAME("POPCNT Gw, Ew");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
SET_DFNONE();
nextop = F8;
GETGW(x2);
@@ -85,7 +85,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(BOX64ENV(cputype)) {
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
}
SET_DFNONE();
@@ -123,7 +123,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
if(BOX64ENV(cputype)) {
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
}
SET_DFNONE();
+50 -48
View File
@@ -103,59 +103,61 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
arch->unaligned = dyn->insts[ninst].unaligned;
if(!noarch) {
// 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)
switch(dyn->insts[ninst].n.neoncache[i].t) {
case NEON_CACHE_XMMW:
arch->sse = 1;
arch->sse_.sse |= 1<<dyn->insts[ninst].n.neoncache[i].n;
break;
case NEON_CACHE_MM:
arch->mmx = 1;
arch->mmx_.mmx |= 1<<dyn->insts[ninst].n.neoncache[i].n;
break;
case NEON_CACHE_YMMW:
arch->ymm = 1;
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
idx = i;
if(idx>=EMM0 && idx<=EMM0+8)
idx-=EMM0;
else
idx-=SCRATCH0-8;
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
break;
case NEON_CACHE_ST_D:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_ST_F:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_ST_I64:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_XMMR:
case NEON_CACHE_YMMR:
default:
// doing nothing, it's just a value read in memory
break;
}
if(dyn->use_x87 || dyn->use_mmx || dyn->use_xmm || dyn->use_ymm) {
int idx;
for(int i=0; i<32; ++i)
if(dyn->insts[ninst].n.neoncache[i].v)
switch(dyn->insts[ninst].n.neoncache[i].t) {
case NEON_CACHE_XMMW:
arch->sse = 1;
arch->sse_.sse |= 1<<dyn->insts[ninst].n.neoncache[i].n;
break;
case NEON_CACHE_MM:
arch->mmx = 1;
arch->mmx_.mmx |= 1<<dyn->insts[ninst].n.neoncache[i].n;
break;
case NEON_CACHE_YMMW:
arch->ymm = 1;
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
idx = i;
if(idx>=EMM0 && idx<=EMM0+8)
idx-=EMM0;
else
idx-=SCRATCH0-8;
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
break;
case NEON_CACHE_ST_D:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_ST_F:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_ST_I64:
arch->x87 = 1;
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
break;
case NEON_CACHE_XMMR:
case NEON_CACHE_YMMR:
default:
// doing nothing, it's just a value read in memory
break;
}
}
// ymm0
if(dyn->insts[ninst].ymm0_out) {
if(dyn->use_ymm && dyn->insts[ninst].ymm0_out) {
arch->ymm = 1;
arch->ymm_.ymm0 = dyn->insts[ninst].ymm0_out;
}
// x87 top
if(dyn->insts[ninst].n.x87stack) {
if((dyn->use_x87 || dyn->insts[ninst].x87_used) && dyn->insts[ninst].n.x87stack) {
arch->x87 = 1;
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
}
+29 -24
View File
@@ -40,38 +40,43 @@ static const char* avx_map_string(uint16_t m)
}
}
typedef uintptr_t (*dynarec64_avx_f)(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
uintptr_t dynarec64_AVX(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;
uint8_t opcode = PK(0);
rex_t rex = vex.rex;
static const dynarec64_avx_f avx_dispatch[4][4] = {
[VEX_M_0F] = {
[VEX_P_NONE] = dynarec64_AVX_0F,
[VEX_P_66] = dynarec64_AVX_66_0F,
[VEX_P_F3] = dynarec64_AVX_F3_0F,
[VEX_P_F2] = dynarec64_AVX_F2_0F,
},
[VEX_M_0F38] = {
[VEX_P_NONE] = dynarec64_AVX_0F38,
[VEX_P_66] = dynarec64_AVX_66_0F38,
[VEX_P_F3] = dynarec64_AVX_F3_0F38,
[VEX_P_F2] = dynarec64_AVX_F2_0F38,
},
[VEX_M_0F3A] = {
[VEX_P_66] = dynarec64_AVX_66_0F3A,
[VEX_P_F2] = dynarec64_AVX_F2_0F3A,
},
};
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(vex.m < 4 && vex.p < 4 && avx_dispatch[vex.m][vex.p])
addr = avx_dispatch[vex.m][vex.p](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);
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || (dyn->need_dump && dyn->need_dump != 3) || BOX64ENV(dynarec_missing)))
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || (dyn->need_dump && dyn->need_dump != 3)) {
dynarec_log(LOG_NONE, " Dynarec unimplemented %s opcode size %d prefix %s map %s opcode %02X\n",
vex.evex ? "EVEX" : "VEX", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
}
return addr;
}
+1 -1
View File
@@ -285,7 +285,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
// no special check...
case 0x2F:
if(opcode==0x2F) {INST_NAME("VCOMISS Gx, Ex");} else {INST_NAME("VUCOMISS Gx, Ex");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
nextop = F8;
GETGX(v0, 0);
GETEXSS(s0, 0, 0);
+1 -1
View File
@@ -264,7 +264,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
// no special check...
case 0x2F:
if(opcode==0x2F) {INST_NAME("VCOMISD Gx, Ex");} else {INST_NAME("VUCOMISD Gx, Ex");}
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
nextop = F8;
GETGX(v0, 0);
GETEXSD(q0, 0, 0);
+24 -12
View File
@@ -1904,7 +1904,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l)
d1 = fpu_get_scratch(dyn, ninst);
} else d0 = -1;
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
if(vex.l) {
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
GETGY_empty_VYEY(v0, v2, v1);
}
if(d0!=-1) {
VMOVQ(d0, q1);
if(vex.l) VMOVQ(d1, v1);
@@ -1920,8 +1923,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d0);
GETGY(v0, 1, -1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d1);
}
}
if(!vex.l) YMM0(gd);
@@ -1944,7 +1947,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l)
d1 = fpu_get_scratch(dyn, ninst);
} else d0 = -1;
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
if(vex.l) {
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
GETGY_empty_VYEY(v0, v2, v1);
}
if(d0!=-1) {
VMOVQ(d0, q1);
if(vex.l) VMOVQ(d1, v1);
@@ -1960,8 +1966,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d0);
GETGY(v0, 1, -1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d1);
}
}
if(!vex.l) YMM0(gd);
@@ -1985,7 +1991,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l)
d1 = fpu_get_scratch(dyn, ninst);
} else d0 = -1;
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
if(vex.l) {
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
GETGY_empty_VYEY(v0, v2, v1);
}
if(d0!=-1) {
VMOVQ(d0, q1);
if(vex.l) VMOVQ(d1, v1);
@@ -2001,8 +2010,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d0);
GETGY(v0, 1, -1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d1);
}
}
if(!vex.l) YMM0(gd);
@@ -2025,7 +2034,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
if(vex.l)
d1 = fpu_get_scratch(dyn, ninst);
} else d0 = -1;
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
if(vex.l) {
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
GETGY_empty_VYEY(v0, v2, v1);
}
if(d0!=-1) {
VMOVQ(d0, q1);
if(vex.l) VMOVQ(d1, v1);
@@ -2041,8 +2053,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
GETGX(q0, 1);
VEORQ(q0, q0, (d0==-1)?q1:d0);
if(vex.l) {
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d0);
GETGY(v0, 1, -1, -1, -1);
VEORQ(v0, v0, (d0==-1)?v1:d1);
}
}
if(!vex.l) YMM0(gd);
+1 -1
View File
@@ -214,7 +214,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
q0 = fpu_get_scratch(dyn, ninst);
q1 = fpu_get_scratch(dyn, ninst);
// check if any input value was NAN
FCMEQS(q0, v1, v1); // 0 if NAN, 1 if not NAN
FCMEQS(q0, d0, d0); // 0 if NAN, 1 if not NAN
}
FSQRTS(d1, d0);
if(!BOX64ENV(dynarec_fastnan)) {
+2
View File
@@ -76,6 +76,8 @@ uintptr_t getConst(arm64_consts_t which)
case const_native_fxtract: return (uintptr_t)native_fxtract;
case const_direct_ftan: return (uintptr_t)direct_ftan;
case const_direct_fpatan: return (uintptr_t)direct_fpatan;
case const_native_fprem: return (uintptr_t)native_fprem;
case const_native_fprem1: return (uintptr_t)native_fprem1;
case const_direct_fcos: return (uintptr_t)direct_fcos;
case const_direct_fsin: return (uintptr_t)direct_fsin;
case const_native_fsincos: return (uintptr_t)native_fsincos;
+2
View File
@@ -39,6 +39,8 @@ typedef enum arm64_consts_s {
const_native_fxtract,
const_direct_ftan,
const_direct_fpatan,
const_native_fprem,
const_native_fprem1,
const_direct_fcos,
const_direct_fsin,
const_native_fsincos,
+94 -43
View File
@@ -176,6 +176,19 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
}
}
} else {
// check if stack is empty (freed register will not count, but might work if using tags instead)
i2 = -dyn->n.x87stack;
LDRw_U12(x3, xEmu, offsetof(x64emu_t, fpu_stack));
if(i2) {
if(i2<0) {
ADDw_U12(x3, x3, -i2);
} else {
SUBw_U12(x3, x3, i2);
}
}
CMPSw_U12(x3, 0);
MOV32w(x4, 0b100000100000000); // empty: C3,C2,C0 = 101
B_MARK3(cLE);
// simply move from cache reg to x2
v1 = dyn->n.x87reg[i1];
VMOVQDto(x2, v1, 0);
@@ -330,26 +343,42 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xF5:
INST_NAME("FPREM1");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
FDIVD(s0, v1, v2);
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
FCVTZSxD(x4, s0);
FMULD(s0, s0, v2);
FSUBD(v1, v1, s0);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
// set C2 = 0
BFCw(x1, 10, 1);
// set C1 = Q0
BFIw(x1, x4, 9, 1);
// set C3 = Q1
LSRx_IMM(x4, x4, 1);
BFIw(x1, x4, 14, 1);
// Set C0 = Q2
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
if(!BOX64ENV(dynarec_fastround)) {
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
i1 = x87_stackcount(dyn, ninst, x3);
CALL(const_native_fprem1, -1);
x87_unstackcount(dyn, ninst, x3, i1);
} else {
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
FMOVxD(x4, v2);
LSLx(x4, x4, 1); // remove sign bit
RORx(x4, x4, 53); // put exponant in lower 12bits
SUBx_U12(x4, x4, 0x7ff);// test is inifite
CBNZx_MARK2(x4);
MOV32w(x4, 0); // force q to 0
B_MARK_nocond;
MARK2;
FDIVD(s0, v1, v2);
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
FCVTZSxD(x4, s0);
FMSUB_64(v1, v1, s0, v2);
MARK;
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
// set C2 = 0
BFCw(x1, 10, 1);
// set C1 = Q0
BFIw(x1, x4, 9, 1);
// set C3 = Q1
LSRx_IMM(x4, x4, 1);
BFIw(x1, x4, 14, 1);
// Set C0 = Q2
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
}
break;
case 0xF6:
INST_NAME("FDECSTP");
@@ -369,26 +398,42 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
break;
case 0xF8:
INST_NAME("FPREM");
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
FDIVD(s0, v1, v2);
FRINTZD(s0, s0);
FCVTZSxD(x4, s0);
FMULD(s0, s0, v2);
FSUBD(v1, v1, s0);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
// set C2 = 0
BFCw(x1, 10, 1);
// set C1 = Q0
BFIw(x1, x4, 9, 1);
// set C3 = Q1
LSRx_IMM(x4, x4, 1);
BFIw(x1, x4, 14, 1);
// Set C0 = Q2
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
if(!rex.is32bits || !BOX64ENV(dynarec_fastround)) {
x87_forget(dyn, ninst, x1, x2, 0);
x87_forget(dyn, ninst, x1, x2, 1);
i1 = x87_stackcount(dyn, ninst, x3);
CALL(const_native_fprem, -1);
x87_unstackcount(dyn, ninst, x3, i1);
} else {
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
s0 = fpu_get_scratch(dyn, ninst);
FMOVxD(x4, v2);
LSLx(x4, x4, 1); // remove sign bit
RORx(x4, x4, 53); // put exponant in lower 12bits
SUBx_U12(x4, x4, 0x7ff);// test is inifite
CBNZx_MARK2(x4);
MOV32w(x4, 0); // force q to 0
B_MARK_nocond;
MARK2;
FDIVD(s0, v1, v2);
FRINTZD(s0, s0);
FCVTZSxD(x4, s0);
FMSUB_64(v1, v1, s0, v2);
MARK;
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
// set C2 = 0
BFCw(x1, 10, 1);
// set C1 = Q0
BFIw(x1, x4, 9, 1);
// set C3 = Q1
LSRx_IMM(x4, x4, 1);
BFIw(x1, x4, 14, 1);
// Set C0 = Q2
LSRx(x4, x4, 1);
BFIw(x1, x4, 8, 1);
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
}
break;
case 0xF9:
INST_NAME("FYL2XP1");
@@ -443,7 +488,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_D(const_direct_fscale, v1, v1, v2, -1, -1);
else
u8 = 0;
CALL_D(const_direct_fscale, v1, v1, v2, u8, -1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
@@ -453,7 +500,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_D(const_direct_fsin, v1, v1, -1, -1, -1);
else
u8 = 0;
CALL_D(const_direct_fsin, v1, v1, -1, u8, -1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
@@ -463,7 +512,9 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
if(!BOX64ENV(dynarec_fastround))
u8 = x87_setround(dyn, ninst, x1, x2, x4);
CALL_D(const_direct_fcos, v1, v1, -1, -1, -1);
else
u8 = 0;
CALL_D(const_direct_fcos, v1, v1, -1, u8, -1);
if(!BOX64ENV(dynarec_fastround))
x87_restoreround(dyn, ninst, u8);
break;
+3 -3
View File
@@ -145,7 +145,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEE:
case 0xEF:
INST_NAME("FUCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
@@ -159,7 +159,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xF6:
case 0xF7:
INST_NAME("FCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
@@ -312,7 +312,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
VST64(v1, wback, fixedaddress);
} else {
if(!BOX64ENV(dynarec_fastround)) {
if(!BOX64ENV(dynarec_fastround) || !rex.is32bits) {
x87_forget(dyn, ninst, x1, x3, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
if(ed!=x1) {MOVx_REG(x1, ed);}
+2 -2
View File
@@ -98,7 +98,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xEE:
case 0xEF:
INST_NAME("FUCOMIP ST0, STx");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
@@ -113,7 +113,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
case 0xF6:
case 0xF7:
INST_NAME("FCOMIP ST0, STx");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
+13 -12
View File
@@ -969,17 +969,18 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
}
// emit ROL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
if (!c) return;
IFX2(X_OF, && !BOX64ENV(cputype)) {
LSRw(s3, s1, 6);
EORw_REG_LSR(s3, s3, s3, 1);
BFIw(xFlags, s3, F_OF, 1);
}
if(!BOX64ENV(cputype))
IFX2(X_OF, && ((c==1) || !modreg)) {
LSRw(s3, s1, 6);
EORw_REG_LSR(s3, s3, s3, 1);
BFIw(xFlags, s3, F_OF, 1);
}
if(c&7) {
int rc = 8-(c&7);
ORRw_REG_LSL(s1, s1, s1, 8);
@@ -995,14 +996,14 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
}
// emit ROR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
if (!c) return;
if(!BOX64ENV(cputype))
IFX(X_OF) {
IFX2(X_OF, && ((c==1) || !modreg)) {
EORw_REG_LSR(s3, s1, s1, 7);
BFIw(xFlags, s3, F_OF, 1);
}
@@ -1023,14 +1024,14 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
}
// emit ROL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
if (!c) return;
if(!BOX64ENV(cputype))
IFX2(X_OF, && c == 1) {
IFX2(X_OF, && ((c==1) || !modreg)) {
LSRw(s3, s1, 14);
EORw_REG_LSR(s3, s3, s3, 1);
BFIw(xFlags, s3, F_OF, 1);
@@ -1051,14 +1052,14 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
}
// emit ROR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
{
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
if (!c) return;
if(!BOX64ENV(cputype))
IFX2(X_OF, && c == 1) {
IFX2(X_OF, && ((c==1) || !modreg)) {
EORw_REG_LSR(s3, s1, s1, 15);
BFIw(xFlags, s3, F_OF, 1);
}
+1
View File
@@ -545,6 +545,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xBB:
case 0xBC: // this one is still BSR, not TZCNT
case 0xBD: // and this one is still BSF, not LZCNT
case 0xBF:
case 0xC1:
case 0xCD:
return dynarec64_0F(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
+3 -3
View File
@@ -602,7 +602,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
case 0xB8:
INST_NAME("POPCNT Gd, Ed");
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
SET_DFNONE();
nextop = F8;
v1 = fpu_get_scratch(dyn, ninst);
@@ -667,7 +667,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(BOX64ENV(cputype)) {
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
}
SET_DFNONE();
@@ -701,7 +701,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
if(BOX64ENV(cputype)) {
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
} else {
SETFLAGS(X_ALL, SF_SET);
SETFLAGS(X_ALL, SF_SET_NODF);
}
}
SET_DFNONE();
+50 -37
View File
@@ -98,22 +98,23 @@ int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n)
void fpu_free_reg(dynarec_arm_t* dyn, int reg)
{
// TODO: check upper limit?
int t = dyn->n.neoncache[reg].t;
int n = dyn->n.neoncache[reg].n;
dyn->n.fpuused[reg] = 0;
if(dyn->n.neoncache[reg].t==NEON_CACHE_YMMR || dyn->n.neoncache[reg].t==NEON_CACHE_YMMW) {
dyn->n.ymm_removed |= 1<<dyn->n.neoncache[reg].n;
if(dyn->n.neoncache[reg].t==NEON_CACHE_YMMW)
dyn->n.ymm_write |= 1<<dyn->n.neoncache[reg].n;
if(t==NEON_CACHE_XMMR || t==NEON_CACHE_XMMW) {
dyn->n.xmm_removed |= 1<<n;
if(t==NEON_CACHE_XMMW)
dyn->n.xmm_write |= 1<<n;
} else if(t==NEON_CACHE_YMMR || t==NEON_CACHE_YMMW) {
dyn->n.ymm_removed |= 1<<n;
if(t==NEON_CACHE_YMMW)
dyn->n.ymm_write |= 1<<n;
if(reg>SCRATCH0)
dyn->n.ymm_regs |= (8LL+reg-SCRATCH0)<<(dyn->n.neoncache[reg].n*4);
dyn->n.ymm_regs |= (8LL+reg-SCRATCH0)<<(n*4);
else
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(dyn->n.neoncache[reg].n*4);
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(n*4);
}
if(dyn->n.neoncache[reg].t==NEON_CACHE_XMMR || dyn->n.neoncache[reg].t==NEON_CACHE_XMMW) {
dyn->n.xmm_removed |= 1<<dyn->n.neoncache[reg].n;
if(dyn->n.neoncache[reg].t==NEON_CACHE_XMMW)
dyn->n.xmm_write |= 1<<dyn->n.neoncache[reg].n;
}
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_I64)
if(t!=NEON_CACHE_ST_F && t!=NEON_CACHE_ST_D && t!=NEON_CACHE_ST_I64)
dyn->n.neoncache[reg].v = 0;
if(dyn->n.fpu_scratch && reg==SCRATCH0+dyn->n.fpu_scratch-1)
--dyn->n.fpu_scratch;
@@ -448,13 +449,12 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
if((dyn->insts[i2].x64.barrier&BARRIER_FLOAT))
// if the barrier as already been apply, no transform needed
return ((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT))?0:(isCacheEmpty(dyn, ninst)?0:1);
int ret = 0;
if(!i2) { // just purge
if(dyn->insts[ninst].n.stack_next)
return 1;
if(dyn->insts[ninst].ymm0_out)
return 1;
for(int i=0; i<32 && !ret; ++i)
for(int i=0; i<32; ++i)
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
int t = dyn->insts[ninst].n.neoncache[i].t;
int n = dyn->insts[ninst].n.neoncache[i].n;
@@ -463,15 +463,15 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|| t==NEON_CACHE_ST_D
|| t==NEON_CACHE_ST_I64)
&& n<dyn->insts[ninst].n.stack_pop))
ret = 1;
return 1;
}
return ret;
return 0;
}
// Check if ninst can be compatible to i2
if(dyn->insts[ninst].n.stack_next != dyn->insts[i2].n.stack-dyn->insts[i2].n.stack_push) {
return 1;
}
if(dyn->insts[ninst].ymm0_out && (dyn->insts[ninst].ymm0_out&~dyn->insts[i2].ymm0_in))
if(dyn->insts[ninst].ymm0_out && (dyn->insts[ninst].ymm0_out&~dyn->insts[i2].ymm0_in&~dyn->insts[i2].n.ymm_unneeded))
return 1;
neoncache_t cache_i2 = dyn->insts[i2].n;
neoncacheUnwind(&cache_i2);
@@ -483,23 +483,23 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
if(((t==NEON_CACHE_XMMR) || (t==NEON_CACHE_XMMW)) && (cache_i2.xmm_unneeded&(1<<n))) { /* nothing*/}
else if(((t==NEON_CACHE_YMMR) || (t==NEON_CACHE_YMMW)) && (cache_i2.ymm_unneeded&(1<<n))) { /* nothing*/}
else
ret = 1;
else
return 1;
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
if(n!=cache_i2.neoncache[i].n) { // not the same x64 reg
ret = 1;
return 1;
}
else if((t == NEON_CACHE_XMMR) && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
{/* nothing */ }
else if((t == NEON_CACHE_YMMR) && cache_i2.neoncache[i].t == NEON_CACHE_YMMW)
{/* nothing */ }
else
ret = 1;
return 1;
}
} else if(cache_i2.neoncache[i].v)
ret = 1;
return 1;
}
return ret;
return 0;
}
void neoncacheUnwind(neoncache_t* cache)
@@ -776,6 +776,11 @@ static const char* df_status[] = {"unknown", "set", "none_pending", "none"};
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
{
if (dyn->need_dump == 3) {
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
if (!BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map))
return;
}
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) {
/*zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
if(dec && !OpcodeOK(dec, dyn->insts[ninst].x64.addr) && !strstr(name, "Illegal")) {
@@ -805,8 +810,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
else
length += sprintf(buf + length, " NF:%d", dyn->insts[ninst].nat_flags_op);
}
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags) {
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags || dyn->insts[ninst].nat_flags_in) {
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx->%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].nat_flags_in, dyn->insts[ninst].need_nat_flags);
}
if (dyn->insts[ninst].invert_carry)
length += sprintf(buf + length, " CI");
@@ -880,7 +885,9 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
if (dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
length += sprintf(buf + length, " %s:%d/%d", dyn->insts[ninst].n.swapped ? "SWP" : "CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
}
if (dyn->need_dump) {
if(dyn->insts[ninst].x64.self_loop)
length += sprintf(buf + length, " self-loop");
if (dyn->need_dump && dyn->need_dump != 3) {
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, %s%s\n",
(dyn->need_dump > 1) ? "\e[32m" : "",
@@ -942,20 +949,21 @@ static void mmx_reset(neoncache_t* n)
n->mmxcache[i] = -1;
}
static void sse_reset(neoncache_t* n)
static void sse_reset(neoncache_t* n, int use_ymm)
{
for (int i=0; i<16; ++i)
n->ssecache[i].v = -1;
for (int i=0; i<32; ++i)
if(n->neoncache[i].t==NEON_CACHE_YMMR || n->neoncache[i].t==NEON_CACHE_YMMW)
n->neoncache[i].v = 0;
if(use_ymm)
for (int i=0; i<32; ++i)
if(n->neoncache[i].t==NEON_CACHE_YMMR || n->neoncache[i].t==NEON_CACHE_YMMW)
n->neoncache[i].v = 0;
}
void fpu_reset(dynarec_native_t* dyn)
{
x87_reset(&dyn->n);
mmx_reset(&dyn->n);
sse_reset(&dyn->n);
sse_reset(&dyn->n, dyn->use_ymm);
fpu_reset_reg(dyn);
dyn->ymm_zero = 0;
}
@@ -964,7 +972,7 @@ void fpu_reset_ninst(dynarec_native_t* dyn, int ninst)
{
x87_reset(&dyn->insts[ninst].n);
mmx_reset(&dyn->insts[ninst].n);
sse_reset(&dyn->insts[ninst].n);
sse_reset(&dyn->insts[ninst].n, dyn->use_ymm);
fpu_reset_reg_neoncache(&dyn->insts[ninst].n);
}
@@ -1107,6 +1115,7 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
//printf_log(LOG_INFO, " will use:%x, carry:%d, generate inverted carry:%d\n", used_flags, used_flags&NF_CF, dyn->insts[ninst].gen_inverted_carry);
if(!used_flags) return; // the flags wont be used, so just cancel
int nc = dyn->insts[ninst].gen_inverted_carry?0:1;
int oldnc = nc;
int carry = used_flags&NF_CF;
// propagate
while(ninst<dyn->size) {
@@ -1142,6 +1151,10 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
return;
} else
++ninst;
if(ninst<dyn->size) {
dyn->insts[ninst].nat_flags_in |= used_flags&use_flags;
if(carry) dyn->insts[ninst].normal_carry_in = oldnc;
}
}
}
@@ -1352,7 +1365,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
}
// we will stop there, not trying to guess too much thing
if((usefull && (i+1)!=ninst)) {
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
}
return;
@@ -1362,7 +1375,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
for(int pred=0; pred<dyn->insts[i].pred_sz; ++pred) {
if(dyn->insts[i].pred[pred]<=last_fpu_used) {
if(usefull && ((i+1)!=ninst)) {
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
}
return;
@@ -1372,7 +1385,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
usefull = 1;
}
if(usefull) {
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
dyn->insts[last_fpu_used+1].x64.barrier|=BARRIER_FLOAT;
}
}
@@ -1523,7 +1536,7 @@ static int ymm_preload_reg(dynarec_arm_t* dyn, int ninst, int last, int ymm)
while((ninst<last) && (i!=-1)) {
// check if the reg is always free
if(!(!dyn->insts[ninst].n.neoncache[i].v ||
(dyn->insts[ninst].n.neoncache[i].n==ymm
(dyn->insts[ninst].n.neoncache[i].n==ymm
&& (dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_YMMR || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_YMMW))))
i = -1; // nope
else
@@ -1588,4 +1601,4 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
dyn->insts[i2].preload_from = ninst;
dyn->insts[i2].n.xmm_unneeded |= preload&0xffff;
dyn->insts[i2].n.ymm_unneeded |= ymm_mask;
}
}
+130 -57
View File
@@ -517,6 +517,7 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
rex_t dummy = {0};
dummy.is32bits = is32bits;
dummy.w = is64bits;
TBNZ_MARK2(xFlags, F_TF);
ret_to_next(dyn, ip, ninst, dummy);
CLEARIP();
MARK;
@@ -530,6 +531,11 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
else
ADDx_U12(xRSP, xRSP, 4*3);
CALL_S(const_native_priv, -1);
MARK2;
LDRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
ORRw_mask(x4, x4, 32-FLAGS_NO_TF, 0); //mask=1<<FLAGS_NO_TF
STRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
jump_to_epilog(dyn, 0, xRIP, ninst);
}
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
@@ -665,13 +671,10 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
MOVx_REG(x4, xR8);
MOVx_REG(x5, xR9);
// native call
if(dyn->need_reloc) {
// fnc is indirect, to help with relocation (but PltResolver might be an issue here)
TABLE64(16, (uintptr_t)fnc);
LDRx_U12(16, 16, 0);
} else {
TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
}
TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
// Note that if need_reloc is active, the TABLE64 will trigger cancel block,
// because native function might be very different on a next run: different function address, different brick, different everything basicaly
// and we don't have a relocation mecanism here, it's too complex
BLR(16);
// put return value in x64 regs
if(w>0) {
@@ -1781,9 +1784,10 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
if((dyn->n.ssecache[i].v!=-1) && (dyn->n.ssecache[i].write))
++n;
}
for(int i=0; i<32; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
++n;
if(dyn->use_ymm)
for(int i=0; i<32; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
++n;
if(!n)
return;
MESSAGE(LOG_DUMP, "\tPush XMM Cache (%d)------\n", n);
@@ -1793,10 +1797,11 @@ void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
}
}
// push the YMM values
for(int i=0; i<32; ++i) {
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
}
if(dyn->use_ymm)
for(int i=0; i<32; ++i) {
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
}
MESSAGE(LOG_DUMP, "\t------- Push XMM Cache (%d)\n", n);
}
@@ -1808,9 +1813,10 @@ void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
for (int i=start; i<16; i++)
if(dyn->n.ssecache[i].v!=-1)
++n;
for(int i=0; i<32; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR)
++n;
if(dyn->use_ymm)
for(int i=0; i<32; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR)
++n;
if(!n)
return;
MESSAGE(LOG_DUMP, "\tPop XMM Cache (%d)------\n", n);
@@ -1820,9 +1826,10 @@ void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1, int not07)
/*dyn->n.ssecache[i].write = 0; // OPTIM: it's sync, so not write anymore
dyn->n.neoncache[dyn->n.ssecache[i].reg].t = NEON_CACHE_XMMR;*/
}
for(int i=0; i<32; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR)
VLDR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
if(dyn->use_ymm)
for(int i=0; i<32; ++i)
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR)
VLDR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
MESSAGE(LOG_DUMP, "\t------- Pop XMM Cache (%d)\n", n);
}
@@ -1886,6 +1893,55 @@ static int findCacheSlot(dynarec_arm_t* dyn, int ninst, int t, int n, neoncache_
return -1;
}
static void buildCacheMasks(neoncache_t* cache, uint8_t* st, uint8_t* mm, uint16_t* xmm, uint16_t* ymm)
{
*st = *mm = 0;
*xmm = *ymm = 0;
for(int i=0; i<32; ++i) {
if(!cache->neoncache[i].v)
continue;
int n = cache->neoncache[i].n;
switch(cache->neoncache[i].t) {
case NEON_CACHE_ST_F:
case NEON_CACHE_ST_D:
case NEON_CACHE_ST_I64:
*st |= 1<<n;
break;
case NEON_CACHE_MM:
*mm |= 1<<n;
break;
case NEON_CACHE_XMMR:
case NEON_CACHE_XMMW:
*xmm |= 1<<n;
break;
case NEON_CACHE_YMMR:
case NEON_CACHE_YMMW:
*ymm |= 1<<n;
break;
}
}
}
static int cacheMaskHas(int t, int n, uint8_t st, uint8_t mm, uint16_t xmm, uint16_t ymm)
{
switch(t) {
case NEON_CACHE_ST_F:
case NEON_CACHE_ST_D:
case NEON_CACHE_ST_I64:
return st&(1<<n);
case NEON_CACHE_MM:
return mm&(1<<n);
case NEON_CACHE_XMMR:
case NEON_CACHE_XMMW:
return xmm&(1<<n);
case NEON_CACHE_YMMR:
case NEON_CACHE_YMMW:
return ymm&(1<<n);
default:
return 0;
}
}
static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *cache)
{
if (i==j)
@@ -2095,6 +2151,9 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
}
neoncache_t cache_i2 = dyn->insts[i2].n;
neoncacheUnwind(&cache_i2);
uint8_t cache_i2_st, cache_i2_mm;
uint16_t cache_i2_xmm, cache_i2_ymm;
buildCacheMasks(&cache_i2, &cache_i2_st, &cache_i2_mm, &cache_i2_xmm, &cache_i2_ymm);
if(!cache_i2.stack) {
int purge = 0; // default to purge if there is any regs that are not needed at jump
@@ -2143,22 +2202,22 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
// check SSE first, than MMX, in order, to optimize successive memory write
for(int i=0; i<16; ++i) {
int j=findCacheSlot(dyn, ninst, NEON_CACHE_XMMW, i, &cache);
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_XMMW, i, &cache_i2)==-1)
if(j>=0 && !(cache_i2_xmm&(1<<i)))
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n, i2);
}
for(int i=0; i<16; ++i) {
int j=findCacheSlot(dyn, ninst, NEON_CACHE_YMMW, i, &cache);
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_YMMW, i, &cache_i2)==-1)
if(j>=0 && !(cache_i2_ymm&(1<<i)))
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n, i2);
}
for(int i=0; i<8; ++i) {
int j=findCacheSlot(dyn, ninst, NEON_CACHE_MM, i, &cache);
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_MM, i, &cache_i2)==-1)
if(j>=0 && !(cache_i2_mm&(1<<i)))
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n, i2);
}
for(int i=0; i<32; ++i) {
if(cache.neoncache[i].v)
if(findCacheSlot(dyn, ninst, cache.neoncache[i].t, cache.neoncache[i].n, &cache_i2)==-1)
if(!cacheMaskHas(cache.neoncache[i].t, cache.neoncache[i].n, cache_i2_st, cache_i2_mm, cache_i2_xmm, cache_i2_ymm))
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, i, cache.neoncache[i].t, cache.neoncache[i].n, i2);
}
// and now load/swap the missing one
@@ -2258,7 +2317,7 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
int jmp = dyn->insts[ninst].x64.jmp_insts;
if(jmp<0)
return;
if(dyn->insts[jmp].f_exit==dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
if(dyn->insts[ninst].f_exit==dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
return;
if(dyn->insts[jmp].df_notneeded)
return;
@@ -2402,47 +2461,61 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
nativeFlagsTransform(dyn, ninst, x1, x2);
}
static void flush_native_flags(dynarec_arm_t* dyn, int ninst, int s1, uint8_t flags, uint8_t ic)
{
// some flags disapear, and need to be saved
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", flags);
uint8_t nc_before = dyn->insts[ninst].normal_carry;
if(flags&NF_EQ) {
CSETw(s1, cEQ);
BFIw(xFlags, s1, F_ZF, 1);
}
if(flags&NF_SF) {
CSETw(s1, cMI);
BFIw(xFlags, s1, F_SF, 1);
}
if(flags&NF_VF) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_OF, 1);
}
if(flags&NF_PF_V) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_PF, 1);
}
if(flags&NF_CF) {
if(ic) // might need to invert carry
CSETw(s1, cCS);
else
CSETw(s1, cCC);
BFIw(xFlags, s1, F_CF, 1);
}
}
void additionnal_checks(dynarec_arm_t* dyn, int ninst)
{
int s1 = x1;
// check if a opcode generate partial flags that may clober existing native flags and see need to be "moved" to xFlags
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before) {
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before || (dyn->insts[ninst].nat_flags_in!=dyn->insts[ninst].need_nat_flags)) {
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that will be generated
uint8_t nat_flags_gen = dyn->insts[ninst].set_nat_flags;
//TODO: does it need to fetch previous state with getPred?
uint8_t nat_flags_before = dyn->insts[ninst].before_nat_flags; //flags before the opcode, but it's only there when opcode also consume natflags
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
uint8_t nat_flags_flush = nat_flags_before&~nat_flags_gen; // flags present before bu not after the operation and so that needs to be spared
if(nat_flags_before && nat_flags_flush) {
// some flags disapear, and need to be saved
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", nat_flags_flush);
uint8_t nc_before = dyn->insts[ninst].normal_carry;
if(nat_flags_flush&NF_EQ) {
CSETw(s1, cEQ);
BFIw(xFlags, s1, F_ZF, 1);
}
if(nat_flags_flush&NF_SF) {
CSETw(s1, cMI);
BFIw(xFlags, s1, F_SF, 1);
}
if(nat_flags_flush&NF_VF) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_OF, 1);
}
if(nat_flags_flush&NF_PF_V) {
CSETw(s1, cVS);
BFIw(xFlags, s1, F_PF, 1);
}
if(nat_flags_flush&NF_CF) {
if(nc_before) // might need to invert carry
CSETw(s1, cCS);
else
CSETw(s1, cCC);
BFIw(xFlags, s1, F_CF, 1);
}
}
if(nat_flags_before && nat_flags_flush)
flush_native_flags(dyn, ninst, s1, nat_flags_flush, dyn->insts[ninst].normal_carry_in);
}
}
void flushNative(dynarec_arm_t* dyn, int ninst)
{
int s1 = x1;
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that is needed after
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
uint8_t nat_flags_flush = nat_flags_before&~nat_flags; // flags present before bu not after the operation and so that needs to be spared
if(nat_flags_flush)
flush_native_flags(dyn, ninst, s1, nat_flags_flush, dyn->insts[ninst].normal_carry_in);
}
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
{
x87_reflectcache(dyn, ninst, s1, s2, s3);
@@ -2565,7 +2638,7 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
dyn->ymm_zero = dyn->insts[reset_n].ymm0_out;
#endif
#if STEP == 0
if(dyn->need_dump && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
if(dyn->need_dump && dyn->need_dump != 3 && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
#endif
#if defined(HAVE_TRACE) && (STEP>2)
if(dyn->need_dump && 0) //disable for now, need more work
@@ -2930,4 +3003,4 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
CBZw(x1, 4+2*4);
TABLE64C(x3, const_native_next_invalidate);
BLR(x3);
}
}
+11 -9
View File
@@ -957,7 +957,7 @@
#else
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
dyn->abort = 1; \
return addr; \
} \
@@ -965,7 +965,7 @@
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
dyn->abort = 1; \
return addr; \
} \
@@ -973,7 +973,7 @@
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
dyn->abort = 1; \
return addr; \
} \
@@ -1005,7 +1005,7 @@
TABLE64C(x6, const_updateflags_arm64); \
BLR(x6); \
dyn->f = status_none; \
}
} else if((A)==X_ALL) flushNative(dyn, ninst);
#endif
#define GRABFLAGS(A) \
@@ -1342,6 +1342,7 @@
#define CacheTransform STEPNAME(CacheTransform)
#define additionnal_checks STEPNAME(additionnal_checks)
#define flushNative STEPNAME(flushNative)
#define arm64_move32 STEPNAME(arm64_move32)
#define arm64_move64 STEPNAME(arm64_move64)
@@ -1445,10 +1446,10 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
void emit_rcl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_rcr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
@@ -1509,6 +1510,7 @@ void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
void additionnal_checks(dynarec_arm_t* dyn, int ninst);
void flushNative(dynarec_arm_t* dyn, int ninst);
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
@@ -1872,7 +1874,7 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
#define PURGE_YMM() \
do { \
if ((ok > 0) && reset_n == -1 && dyn->insts[ninst + 1].purge_ymm) \
if (dyn->use_ymm && (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)
+9 -1
View File
@@ -16,7 +16,15 @@
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
if(!BOX64ENV(dynarec_df)) {dyn->f=status_none; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }}
#define EMIT(A) dyn->native_size+=4
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
#define JUMP(A, C) \
do { \
dyn->insts[ninst].x64.jmp = (uintptr_t)(A); \
add_jump(dyn, ninst); \
add_next(dyn, dyn->insts[ninst].x64.jmp); \
SMEND(); \
dyn->insts[ninst].x64.jmp_cond = C; \
dyn->insts[ninst].x64.jmp_insts = 0; \
} while (0)
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
#define NEW_INST \
+2 -1
View File
@@ -3,10 +3,11 @@
#define MESSAGE(A, ...) do {} while (0)
#define EMIT(A) do {} while (0)
// do not update dyn->f for SETFLAGS(..., SF_SET_PENDING) because it will use either DF_NONE or DF_SET anyway (similar to SF_SET_NODF)
#define SETFLAGS(A,B) \
dyn->insts[ninst].x64.set_flags = A; \
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
if(((B)&SF_SET_PENDING)!=SF_SET_PENDING) dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):((dyn->f==status_none)?status_none:status_none_pending); \
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; }
#define NEW_INST \
dyn->insts[ninst].f_entry = dyn->f; \
+1 -1
View File
@@ -14,7 +14,7 @@
#define MESSAGE(A, ...) \
do { \
if (dyn->need_dump) dynarec_log_prefix(0, LOG_NONE, __VA_ARGS__); \
if (dyn->need_dump && dyn->need_dump != 3) dynarec_log_prefix(0, LOG_NONE, __VA_ARGS__); \
} while (0)
#define ENDPREFIX dyn->insts[ninst].size2 = 0
#define NEW_INST \
@@ -135,8 +135,10 @@ typedef struct instruction_arm64_s {
uint8_t nat_flags_op_before:4;// what happens to native flags here
uint8_t before_nat_flags; // 0 or combinaison of native flags define
uint8_t need_nat_flags;
uint8_t nat_flags_in; // native flags at the entry of the opcode
unsigned gen_inverted_carry:1;
unsigned normal_carry:1;
unsigned normal_carry_in:1;
unsigned normal_carry_before:1;
unsigned invert_carry:1; // this opcode force an inverted carry
unsigned df_needed:1;
+3 -4
View File
@@ -38,7 +38,7 @@ void* create_updateflags()
dynarec_arm_t helper = {0};
instruction_arm64_t insts[1] = {0};
helper.insts = insts;
helper.need_dump = BOX64ENV(dynarec_dump);
helper.need_dump = BOX64ENV(dynarec_dump) == 3 ? 0 : BOX64ENV(dynarec_dump);
helper.cap = 1;
helper.f = status_none;
helper.insts[0].x64.gen_flags = X_ALL;
@@ -95,8 +95,7 @@ void* create_updateflags()
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(LOG_NONE, "%s%04d|Emitting %zu bytes for UpdateFlags (%p)", (helper.need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.native_start);
dynarec_log_prefix(0, LOG_NONE, "%s\n", (helper.need_dump>1)?"\e[m":"");
}
helper.native_size = 0;
@@ -131,4 +130,4 @@ void* create_updateflags()
updaflags_arm64 = block;
return block->block;
}
}
+6 -6
View File
@@ -164,7 +164,7 @@ SETMARK(d_inc64);
RET(xLR);
SETMARK(d_imul8);
LDRSH_U12(x1, xEmu, offsetof(x64emu_t, res));
ASRxw(x2, x1, 8);
ASRxw(x2, x1, 7);
CMPSw_REG_ASR(x2, x1, 16);
CSETw(x3, cNE);
BFIw(xFlags, x3, F_CF, 1);
@@ -179,7 +179,7 @@ SETMARK(d_imul8);
RET(xLR);
SETMARK(d_imul16);
LDRw_U12(x1, xEmu, offsetof(x64emu_t, res));
ASRw(x2, x1, 16);
ASRw(x2, x1, 15);
CMPSw_REG_ASR(x2, x1, 31);
CSETw(x3, cNE);
BFIw(xFlags, x3, F_CF, 1);
@@ -783,7 +783,7 @@ SETMARK(d_rol8);
BFIw(xFlags, x2, F_OF, 1);
} else {
LDRB_U12(x2, xEmu, offsetof(x64emu_t, op1));
LSLw_IMM(x3, x2, 6);
LSRw_IMM(x3, x2, 6);
EORw_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
}
@@ -796,7 +796,7 @@ SETMARK(d_rol16);
BFIw(xFlags, x2, F_OF, 1);
} else {
LDRH_U12(x2, xEmu, offsetof(x64emu_t, op1));
LSLw_IMM(x3, x2, 14);
LSRw_IMM(x3, x2, 14);
EORw_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
}
@@ -809,7 +809,7 @@ SETMARK(d_rol32);
BFIw(xFlags, x2, F_OF, 1);
} else {
LDRw_U12(x2, xEmu, offsetof(x64emu_t, op1));
LSLw_IMM(x3, x2, 30);
LSRw_IMM(x3, x2, 30);
EORw_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
}
@@ -822,7 +822,7 @@ SETMARK(d_rol64);
BFIw(xFlags, x2, F_OF, 1);
} else {
LDRx_U12(x2, xEmu, offsetof(x64emu_t, op1));
LSLx_IMM(x3, x2, 62);
LSRw_IMM(x3, x2, 62);
EORw_REG_LSR(x3, x3, x3, 1);
BFIw(xFlags, x3, F_OF, 1);
}
+41 -93
View File
@@ -75,34 +75,24 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
return db;
}
dynablock_t* SwitchDynablock(dynablock_t* db, int need_lock)
static void DeferFreeDynablockMap(dynablock_t* db)
{
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;
// enq for a deferred free so any threads still running in this block has a better chance to finish.
if (my_context->db_zombie_count == DB_ZOMBIE_SIZE) {
if(my_context->db_zombie[my_context->db_zombie_head])
FreeDynarecMap((uintptr_t)my_context->db_zombie[my_context->db_zombie_head]->actual_block);
} else {
my_context->db_zombie_count++;
}
return db;
my_context->db_zombie[my_context->db_zombie_head] = db;
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
}
void DeferFreeDynablockClearRange(void* addr, size_t sz)
{
for(int i=0; i<my_context->db_zombie_count; ++i)
if(my_context->db_zombie[i] && ((void*)my_context->db_zombie[i]>=addr) && ((void*)my_context->db_zombie[i]<(addr+sz)))
my_context->db_zombie[i] = NULL;
}
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
@@ -110,18 +100,19 @@ 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);
dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x64=%p:%p\n", db, db->block, db->x64_addr, db->x64_addr + db->x64_size - 1);
uintptr_t db_size = db->x64_size;
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
if(db_size && my_context && BOX64ENV(dynarec_dirty)) {
// need_lock is also used to check if db_size needs to be decremented...
if(need_lock && db_size && my_context && BOX64ENV(dynarec_dirty)) {
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
if(!n && (db_size >= my_context->max_db_size)) {
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
}
}
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
DeferFreeDynablockMap(db);
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
}
@@ -153,16 +144,12 @@ void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
}
}
if(db->previous)
FreeInvalidDynablock(db->previous, 0);
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
DeferFreeDynablockMap(db);
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
}
}
void MarkDynablock(dynablock_t* db)
{
if(db) {
@@ -175,13 +162,10 @@ void MarkDynablock(dynablock_t* db)
db = getDB((uintptr_t)old->x64_addr);
if(!old->gone && db!=old) {
printf_log(LOG_INFO, "Warning, couldn't mark block as dirty for %p, block=%p, current_block=%p\n", old->x64_addr, old, db);
// the block is lost, need to invalidate it...
// the block is lost, need to invalidate and defer its free
old->gone = 1;
old->done = 0;
if(!db || db->previous)
FreeInvalidDynablock(old, 1);
else
db->previous = old;
FreeInvalidDynablock(old, 1);
}
#ifdef ARCH_NOP
} else {
@@ -276,6 +260,7 @@ dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
dynarec_log(LOG_DEBUG, "Will call Fillblock64 for Alt %p\n", (void*)addr);
dynablock_t* block = FillBlock64(addr, is32bits, MAX_INSTS, 0, 1);
if(block && block->block) block->done = 1; // validate the alt block
mutex_unlock(&my_context->mutex_dyndump);
@@ -288,7 +273,7 @@ dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
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, int create, int need_lock, int is32bits, int is_new)
dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int need_lock, int is32bits, int is_new)
{
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
if(BOX64ENV(nodynarec_delay) && (addr>=BOX64ENV(nodynarec_start)) && (addr<BOX64ENV(nodynarec_end)))
@@ -386,51 +371,16 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create
return block;
}
dynablock_t* DBSwapInvalid(x64emu_t* emu, dynablock_t* db, uintptr_t addr, int is32bits, int need_lock)
void FlushZombieDynablocks(void)
{
if(need_lock)
mutex_lock(&my_context->mutex_dyndump);
db->done = 0; // invalidating the block
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X, gone:%d, autocrc:%d, to_delete:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, db->gone, db->autocrc, db->to_delete, (void*)addr);
// Free db, it's now invalid!
dynablock_t* old = InvalidDynablock(db, 0);
if(old->previous) {
dynarec_log(LOG_DEBUG, "Free alt alt block %p\n", db->previous);
FreeInvalidDynablock(db->previous, 0);
old->previous = NULL;
if (!my_context) return;
if (!my_context->db_zombie_count) return;
int head = my_context->db_zombie_head;
for (int i = 0; i < my_context->db_zombie_count; ++i) {
int idx = (head - my_context->db_zombie_count + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
FreeDynarecMap((uintptr_t)my_context->db_zombie[idx]->actual_block);
}
// start again... (will create a new block)
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0);
if(db) {
if(db->previous)
FreeInvalidDynablock(db->previous, 0);
db->previous = old;
} else
FreeInvalidDynablock(old, 0);
if(need_lock)
mutex_unlock(&my_context->mutex_dyndump);
return db;
}
dynablock_t* DBSwitchPrevious(x64emu_t* emu, dynablock_t* db, uintptr_t addr, int need_lock)
{
dynarec_log(LOG_DEBUG, "Switching to alt block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, (void*)addr);
db = SwitchDynablock(db, need_lock);
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
FreeDynablock(db, need_lock, 0);
db = getDB(addr);
MarkDynablock(db); // just in case...
} else {
for(int i=0; i<db->sep_size; ++i) {
uint32_t x64_offs = db->sep[i].x64_offs;
uint32_t nat_offs = db->sep[i].nat_offs;
if(addJumpTableIfDefault64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs)))
db->sep[i].active = 1;
else
db->sep[i].active = 0;
}
}
return db;
my_context->db_zombie_count = 0;
}
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
@@ -444,18 +394,16 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
uint32_t hash = X31_hash_code((void*)db->x64_readaddr, db->x64_size);
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((void*)db->previous->x64_readaddr, db->previous->x64_size)==db->previous->hash) {
db = DBSwitchPrevious(emu, db, addr, 0);
mutex_unlock(&my_context->mutex_dyndump);
return db;
}
if (is_inhotpage) {
mutex_unlock(&my_context->mutex_dyndump);
dynarec_log(LOG_DEBUG, "Cannot run block (or previous) %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);
return NULL; // will be handle when hotpage is over
dynarec_log(LOG_DEBUG, "Cannot run block %p from %p:%p (hash:%X/%X, always_test:%d) for %p, hotpage\n", db, db->x64_addr, db->x64_addr + db->x64_size - 1, hash, db->hash, db->always_test, (void*)addr);
return NULL; // will be handled when hotpage is over
}
db = DBSwapInvalid(emu, db, addr, is32bits, 0);
db->done = 0;
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X, gone:%d, autocrc:%d, to_delete:%d) for %p\n", db, db->x64_addr, db->x64_addr + db->x64_size, db->hash, db->gone, db->autocrc, db->to_delete, (void*)addr);
dynablock_t* old = InvalidDynablock(db, 0);
FreeInvalidDynablock(old, 0);
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0);
} else {
if(is_inhotpage) {
db->always_test = 2;
-1
View File
@@ -20,7 +20,6 @@ typedef struct sep_s {
typedef struct dynablock_s {
void* block; // block-sizeof(void*) == self
void* actual_block; // the actual start of the block (so block-sizeof(void*))
struct dynablock_s* previous; // a previous block that might need to be freed
uint32_t in_used;// will be 0 if not in_used, >0 if used be some code
uint32_t tick; // last "tick" when dynablock was run
void* x64_addr;
+87
View File
@@ -0,0 +1,87 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "dynacache_compress.h"
#include "debug.h"
#include "custommem.h"
static void* libz = NULL;
static int libz_init = 0;
typedef size_t(*LFL_t)(size_t);
typedef int(*iFpppL_t)(void*, void*, void*, size_t);
typedef int(*iFpppLi_t)(void*, void*, void*, size_t, int);
static iFpppL_t libz_uncompress = NULL;
static iFpppLi_t libz_compress2 = NULL;
static LFL_t libz_compressBound = NULL;
static void init_libz()
{
libz_init = 1;
libz = dlopen("libz.so.1", RTLD_LAZY);
if(!libz) libz = dlopen("libz.so", RTLD_LAZY);
if(!libz) return;
libz_compress2 = dlsym(libz, "compress2");
libz_uncompress = dlsym(libz, "uncompress");
libz_compressBound = dlsym(libz, "compressBound");
}
void* z_compress(void* src, size_t src_size, int type, size_t* dest_size)
{
if(!libz_init)
init_libz();
if(!libz_compress2 || !libz_compressBound)
return NULL;
size_t sz = libz_compressBound(src_size);
void* dest = box_malloc(sz);
int ret = libz_compress2(dest, &sz, src, src_size, (type==COMP_Z_MAX)?-1:1);
if(ret) {
printf_log(LOG_DEBUG, "Failed to compress a DynaCache block (%d)\n", ret);
box_free(dest);
return NULL;
} else
*dest_size = sz;
return dest;
}
void* dc_compress(void* src, size_t src_size, int type, size_t* dest_size)
{
switch(type) {
case COMP_Z:
case COMP_Z_MAX:
return z_compress(src, src_size, type, dest_size);
case COMP_NONE:
default:
return NULL;
}
}
int z_uncompress(void* src, size_t src_size, void* dest, size_t dest_size)
{
if(!libz_init)
init_libz();
if(!libz_uncompress)
return -1;
size_t sz = dest_size;
int ret = libz_uncompress(dest, &sz, src, src_size);
if(ret) {
printf_log(LOG_DEBUG, "Failed to uncompress a DynaCache block (%d)\n", ret);
return -1;
}
return 0;
}
int dc_uncompress(void* src, size_t src_size, int type, void* dest, size_t dest_size)
{
switch(type) {
case COMP_Z:
case COMP_Z_MAX:
return z_uncompress(src, src_size, dest, dest_size);
case COMP_NONE:
default:
return -1;
}
}
+20 -19
View File
@@ -106,14 +106,17 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
}
void* LinkNextInvalid(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
{
// like LinkNext, but invalid the db found first
// like LinkNext, but invalidate the db found first
int is32bits = (R_CS == 0x23);
dynablock_t* db = getDB(addr);
if(db) {
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash)
db = DBSwitchPrevious(emu, db, addr, 1);
else
db = DBSwapInvalid(emu, db, addr, is32bits, 1);
mutex_lock(&my_context->mutex_dyndump);
db->done = 0;
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X, gone:%d, autocrc:%d, to_delete:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, db->gone, db->autocrc, db->to_delete, (void*)addr);
dynablock_t* old = InvalidDynablock(db, 0);
FreeInvalidDynablock(old, 0);
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0);
mutex_unlock(&my_context->mutex_dyndump);
if(db && db->done && db->block) {
void* jblock = db->block;
if(db->sep_size && (uintptr_t)db->x64_addr!=addr) {
@@ -241,22 +244,20 @@ void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
}
if(emu->flags.need_jmpbuf)
emu->flags.need_jmpbuf = 0;
if(no_alt)
{
// the Dynarec will shadow the Entry Point, so using Intperter to enter the function
#if defined(DYNAREC) && defined(HAVE_ALTJUMP)
if(!BOX64ENV(dynarec))
#endif
no_alt = 0;
skip = 1;
}
else
#ifndef DYNAREC
Run(emu, 0);
#else
if(no_alt) {
// the Dynarec will shadow the Entry Point, so using Intperter to enter the function
#if defined(DYNAREC) && defined(HAVE_ALTJUMP)
if(!BOX64ENV(dynarec))
#endif
no_alt = 0;
skip = 1;
} else
R_RIP = (uintptr_t)getAlternate((void*)R_RIP);
#ifdef DYNAREC
if(!BOX64ENV(dynarec) || !use_dynarec)
#endif
Run(emu, 0);
#ifdef DYNAREC
else {
int newis32bits = (emu->segs[_CS]==0x23);
if(newis32bits!=is32bits) {
@@ -278,7 +279,7 @@ void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
#ifdef HAVE_ALTJUMP
if(skip && no_alt) {
block = getDBnoAlt(emu, R_RIP, is32bits);
no_alt = 0;
skip = no_alt = 0;
}
#endif
if(!block || !block->block || !block->done || ACCESS_FLAG(F_TF)) {
+6 -5
View File
@@ -59,6 +59,7 @@ extern void arm64_next_invalid();
#include "la64/la64_printer.h"
#include "la64/dynarec_la64_private.h"
#include "la64/dynarec_la64_functions.h"
#include "la64/dynarec_la64_arch.h"
// Limit here is unconditionnal jump, that is signed 28bits
#define MAXBLOCK_SIZE ((1 << 27) - 200)
@@ -67,17 +68,17 @@ extern void arm64_next_invalid();
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
#define POSTUPDATE_SPECIFICS(A)
#define ARCH_SIZE(A) 0
#define ARCH_FILL(A, B, C) NULL
#define ARCH_ADJUST(A, B, C, D) {}
#define ARCH_SIZE(A) get_size_arch(A)
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
#define STOP_NATIVE_FLAGS(A, B) {}
#define ARCH_UNALIGNED(A, B) 0
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
extern uint32_t la64_crc(void* p, uint32_t len);
extern void la64_crc_autocrc(); // same as la64_crc, but not using regular ABI
#define ARCH_CRC(A, B) return la64_crc(A, B)
#define ARCH_NOP (0b0000001101<<22)
#define ARCH_UDF 0b1010100
#define ARCH_UDF 0x38600400
#define JMPNEXT_SIZE (4*sizeof(void*))
#define ADDITIONNAL_CHECKS()
+62 -28
View File
@@ -27,54 +27,53 @@
#include "khash.h"
KHASH_MAP_INIT_INT64(table64, uint32_t)
KHASH_SET_INIT_INT64(nextset)
KHASH_MAP_INIT_INT64(jumpaddr, int)
static kh_nextset_t* khnextset = NULL;
static kh_jumpaddr_t* khjumpaddr = NULL;
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
uint8_t *ip = (uint8_t*)inst->addr;
if (ip[0] == 0xcc && IsBridgeSignature(ip[1], ip[2])) {
uintptr_t a = *(uintptr_t*)(ip+3);
if(a==0) {
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (dyn->need_dump>1)?"\e[01;33m":"", (void*)ip, (dyn->need_dump>1)?"\e[m":"");
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (dyn->need_dump == 2)?"\e[01;33m":"", (void*)ip, (dyn->need_dump == 2)?"\e[m":"");
} else {
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (dyn->need_dump>1)?"\e[01;33m":"", (void*)ip, (void*)a, (dyn->need_dump>1)?"\e[m":"");
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (dyn->need_dump == 2)?"\e[01;33m":"", (void*)ip, (void*)a, (dyn->need_dump == 2)?"\e[m":"");
}
} else {
if(dec) {
dynarec_log(LOG_NONE, "%s%p: %s", (dyn->need_dump > 1) ? "\e[01;33m" : "", ip, DecodeX64Trace(dec, inst->addr, 1));
dynarec_log(LOG_NONE, "%s%p: %s", (dyn->need_dump == 2) ? "\e[01;33m" : "", ip, DecodeX64Trace(dec, inst->addr, 1));
} else {
dynarec_log(LOG_NONE, "%s%p: ", (dyn->need_dump>1)?"\e[01;33m":"", ip);
dynarec_log(LOG_NONE, "%s%p: ", (dyn->need_dump == 2)?"\e[01;33m":"", ip);
for(int i=0; i<inst->size; ++i) {
dynarec_log_prefix(0, LOG_NONE, "%02X ", ip[i]);
}
dynarec_log_prefix(0, LOG_NONE, " %s", name);
}
// print Call function name if possible
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
if(dyn->need_dump != 3 && (ip[0]==0xE8 || ip[0]==0xE9)) { // Call / Jmp
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
PrintFunctionAddr(nextaddr, "=> ");
} else if(ip[0]==0xFF) {
} else if(dyn->need_dump != 3 && ip[0]==0xFF) {
if(ip[1]==0x25) {
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
PrintFunctionAddr(nextaddr, "=> ");
}
}
// end of line and colors
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_dump>1)?"\e[m":"");
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_dump == 2)?"\e[m":"");
}
}
void add_next(dynarec_native_t *dyn, uintptr_t addr) {
if (!BOX64DRENV(dynarec_bigblock))
return;
// exist?
for(int i=0; i<dyn->next_sz; ++i)
if(dyn->next[i]==addr)
return;
// put in a free slot
for(int i=0; i<dyn->next_sz; ++i)
if(!dyn->next[i]) {
dyn->next[i] = addr;
return;
}
int ret;
kh_put(nextset, khnextset, addr, &ret);
if(!ret)
return;
// add slots
if(dyn->next_sz == dyn->next_cap) {
printf_log(LOG_NONE, "Warning, overallocating next\n");
@@ -85,15 +84,19 @@ uintptr_t get_closest_next(dynarec_native_t *dyn, uintptr_t addr) {
// get closest, but no addresses before
uintptr_t best = 0;
int i = 0;
while((i<dyn->next_sz) && (best!=addr)) {
if(dyn->next[i]) {
if(dyn->next[i]<addr) { // remove the address, it's before current address
dyn->next[i] = 0;
} else {
if((dyn->next[i]<best) || !best)
best = dyn->next[i];
while(i<dyn->next_sz) {
uintptr_t next = dyn->next[i];
if(!next || next<addr) {
if(next) {
khint_t k = kh_get(nextset, khnextset, next);
if(k != kh_end(khnextset))
kh_del(nextset, khnextset, k);
}
dyn->next[i] = dyn->next[--dyn->next_sz];
continue;
}
if((next<best) || !best)
best = next;
++i;
}
return best;
@@ -104,6 +107,14 @@ void add_jump(dynarec_native_t *dyn, int ninst) {
printf_log(LOG_NONE, "Warning, overallocating jmps\n");
}
dyn->jmps[dyn->jmp_sz++] = ninst;
if(dyn->insts[ninst].x64.jmp) {
if(!khjumpaddr)
khjumpaddr = kh_init(jumpaddr);
int ret;
khint_t k = kh_put(jumpaddr, khjumpaddr, dyn->insts[ninst].x64.jmp, &ret);
if(ret > 0)
kh_value(khjumpaddr, k) = ninst;
}
}
int get_first_jump(dynarec_native_t *dyn, int next) {
if(next<0 || next>dyn->size)
@@ -111,6 +122,14 @@ int get_first_jump(dynarec_native_t *dyn, int next) {
return get_first_jump_addr(dyn, dyn->insts[next].x64.addr);
}
int get_first_jump_addr(dynarec_native_t *dyn, uintptr_t next) {
if(khjumpaddr) {
khint_t k = kh_get(jumpaddr, khjumpaddr, next);
if(k != kh_end(khjumpaddr)) {
int ninst = kh_value(khjumpaddr, k);
if(ninst >= 0 && ninst < dyn->size && dyn->insts[ninst].x64.jmp == next)
return ninst;
}
}
for(int i=0; i<dyn->jmp_sz; ++i)
if(dyn->insts[dyn->jmps[i]].x64.jmp == next)
return dyn->jmps[i];
@@ -444,7 +463,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
}
#else
uintptr_t altjump = 0;
#endif
#endif
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
return BOX64ENV(nodynarec_delay)?NULL:CreateEmptyBlock(old_addr, is32bits, is_new);
@@ -454,8 +473,9 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p as in a HotPage\n", (void*)addr);
return NULL;
}
uint32_t prot = getProtection_fast(addr);
#ifndef _WIN32
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
if((prot&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p because EXEC protection is missing\n", (void*)addr);
return NULL;
}
@@ -469,9 +489,17 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
}
// protect the 1st page
protectDB(addr, 1);
if(box64_pagesize>4096)
prot = getProtection_fast(addr); // update protection as it might got a NEVERCLEAN tag because of the protectDB for large pagesize
// init the helper
dynarec_native_t helper = {0};
dynarec_native_t* dyn = &helper;
if(!khnextset)
khnextset = kh_init(nextset);
kh_clear(nextset, khnextset);
if(!khjumpaddr)
khjumpaddr = kh_init(jumpaddr);
kh_clear(jumpaddr, khjumpaddr);
#ifdef GDBJIT
helper.gdbjit_block = box_calloc(1, sizeof(gdbjit_block_t));
#endif
@@ -487,7 +515,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
helper.next_cap = MAX_INSTS;
helper.table64 = NULL;
helper.env = GetCurEnvByAddr(addr);
if(getProtection(addr)&PROT_NEVERCLEAN) {
if(prot&PROT_NEVERCLEAN) {
helper.always_test = 1;
}
ResetTable64(&helper);
@@ -559,6 +587,8 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
}
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock shorten on pass0 at ninst=%d\n", helper.size);
--helper.size;
// preserve flags at the new block exit
helper.insts[helper.size - 1].x64.need_after |= X_PEND;
helper.abort = 0;
}
// basic checks
@@ -662,6 +692,10 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
int pos = helper.size-1;
while (pos>=0)
pos = updateNeed(&helper, pos, 0);
#if defined(LA64)
updateUpperLiveness(&helper);
updateRspMerge(&helper, is32bits);
#endif
// remove fpu stuff on non-executed code
for(int i=1; i<helper.size-1; ++i)
if(!helper.insts[i].pred_sz) {
@@ -798,7 +832,7 @@ dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new,
helper.callret_size = 0;
helper.sep_size = 0;
// pass 3, emit (log emit native opcode)
if(dyn->need_dump) {
if(dyn->need_dump && dyn->need_dump != 3) {
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu, callrets=%zu, entry=%p)", (dyn->need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64", native_size, helper.table64size*sizeof(uint64_t), insts_rsize, arch_size, callret_size, helper.block);
PrintFunctionAddr(helper.start, " => ");
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_dump>1)?"\e[m":"");
+73 -44
View File
@@ -80,6 +80,11 @@ void native_fxtract(x64emu_t* emu)
}
void native_fprem(x64emu_t* emu)
{
if(STld(0).uref==ST0.q && STld(1).uref==ST1.q) {
// try a full precision fpre alternative
if(full_ld_fprem(emu))
return;
}
double x = ST0.d, y = ST1.d;
int64_t q = 0;
if (isnan(x) || isnan(y)) {
@@ -93,14 +98,18 @@ void native_fprem(x64emu_t* emu)
q = 0;
} else {
#if defined(_WIN32) || defined(__MINGW32__)
q = (int64_t)trunc(x / y);
ST0.d = x - (y * q);
if(isinf(y))
q = 0;
else {
q = (int64_t)trunc(x / y);
ST0.d = x - (y * q);
}
#else
ST0.d = fmod(x, y);
q = (int64_t)trunc(x / y);
#endif
}
q &= 7;
//q &= 7; //why forcing all low bits (and so C0, C1 & C3) to 1?
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = q & 1;
emu->sw.f.F87_C3 = (q >> 1) & 1;
@@ -291,7 +300,7 @@ void native_fsave(x64emu_t* emu, uint8_t* ed)
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
LD2D(p, &emu->x87[7-i].d);
LD2D(p, &ST(i).d);
p+=10;
}
reset_fpu(emu);
@@ -303,7 +312,7 @@ void native_fsave16(x64emu_t* emu, uint8_t* ed)
uint8_t* p = ed;
p += 14;
for (int i=0; i<8; ++i) {
LD2D(p, &emu->x87[7-i].d);
LD2D(p, &ST(i).d);
p+=10;
}
reset_fpu(emu);
@@ -315,7 +324,7 @@ void native_frstor(x64emu_t* emu, uint8_t* ed)
uint8_t* p = ed;
p += 28;
for (int i=0; i<8; ++i) {
D2LD(&emu->x87[7-i].d, p);
D2LD(&ST(i).d, p);
p+=10;
}
@@ -327,7 +336,7 @@ void native_frstor16(x64emu_t* emu, uint8_t* ed)
uint8_t* p = ed;
p += 14;
for (int i=0; i<8; ++i) {
D2LD(&emu->x87[7-i].d, p);
D2LD(&ST(i).d, p);
p+=10;
}
@@ -346,13 +355,17 @@ void native_fprem1(x64emu_t* emu)
ST0.d = NAN;
} else {
#if defined(_WIN32) || defined(__MINGW32__)
q = (int)round(x / y);
ST0.d = x - (y * q);
if(isinf(y))
q = 0;
else {
q = (int)round(x / y);
ST0.d = x - (y * q);
}
#else
ST0.d = remquo(x, y, &q);
#endif
}
q &= 7;
//q &= 7; //why forcing all low bits (and so C0, C1 & C3) to 1?
emu->sw.f.F87_C2 = 0;
emu->sw.f.F87_C1 = q & 1;
emu->sw.f.F87_C3 = (q >> 1) & 1;
@@ -704,51 +717,67 @@ void native_aeskeygenassist(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
GX->ud[3] ^= u8;
}
static inline __int128 pclmul_4bit(uint64_t a, uint64_t b)
{
__uint128_t result = 0;
__uint128_t op2 = b;
__uint128_t table[16];
table[0] = 0;
table[1] = op2;
table[2] = op2 << 1;
table[3] = table[2] ^ table[1];
table[4] = op2 << 2;
table[5] = table[4] ^ table[1];
table[6] = table[4] ^ table[2];
table[7] = table[6] ^ table[1];
table[8] = op2 << 3;
table[9] = table[8] ^ table[1];
table[10] = table[8] ^ table[2];
table[11] = table[10] ^ table[1];
table[12] = table[8] ^ table[4];
table[13] = table[12] ^ table[1];
table[14] = table[12] ^ table[2];
table[15] = table[14] ^ table[1];
for (int i = 0; i < 16; ++i) {
result ^= table[(a >> (i * 4)) & 0xf] << (i * 4);
}
return (__int128)result;
}
void native_pclmul(x64emu_t* emu, int gx, int ex, void* p, uint32_t u8)
{
sse_regs_t *EX = p?((sse_regs_t*)p):&emu->xmm[ex];
sse_regs_t *GX = &emu->xmm[gx];
int g = (u8&1)?1:0;
int e = (u8&0b10000)?1:0;
__int128 result = 0;
__int128 op2 = EX->q[e];
for (int i=0; i<64; ++i)
if(GX->q[g]&(1LL<<i))
result ^= (op2<<i);
GX->u128 = result;
sse_regs_t* EX = p ? ((sse_regs_t*)p) : &emu->xmm[ex];
sse_regs_t* GX = &emu->xmm[gx];
int g = (u8 & 1) ? 1 : 0;
int e = (u8 & 0b10000) ? 1 : 0;
GX->u128 = pclmul_4bit(GX->q[g], EX->q[e]);
}
void native_pclmul_x(x64emu_t* emu, int gx, int vx, void* p, uint32_t u8)
{
sse_regs_t* EX = ((uintptr_t)p > 15) ? (sse_regs_t*)p : &emu->xmm[(uintptr_t)p];
sse_regs_t* GX = &emu->xmm[gx];
sse_regs_t* VX = &emu->xmm[vx];
int g = (u8 & 1) ? 1 : 0;
int e = (u8 & 0b10000) ? 1 : 0;
sse_regs_t *EX = ((uintptr_t)p>15)?((sse_regs_t*)p):&emu->xmm[(uintptr_t)p];
sse_regs_t *GX = &emu->xmm[gx];
sse_regs_t *VX = &emu->xmm[vx];
int g = (u8&1)?1:0;
int e = (u8&0b10000)?1:0;
__int128 result = 0;
__int128 op2 = EX->q[e];
for (int i=0; i<64; ++i)
if(VX->q[g]&(1LL<<i))
result ^= (op2<<i);
GX->u128 = result;
GX->u128 = pclmul_4bit(VX->q[g], EX->q[e]);
}
void native_pclmul_y(x64emu_t* emu, int gy, int vy, void* p, uint32_t u8)
{
//compute both low and high values
native_pclmul_x(emu, gy, vy, p, u8);
sse_regs_t *EY = ((uintptr_t)p>15)?((sse_regs_t*)(p+16)):&emu->ymm[(uintptr_t)p];
sse_regs_t *GY = &emu->ymm[gy];
sse_regs_t *VY = &emu->ymm[vy];
int g = (u8&1)?1:0;
int e = (u8&0b10000)?1:0;
__int128 result = 0;
__int128 op2 = EY->q[e];
for (int i=0; i<64; ++i)
if(VY->q[g]&(1LL<<i))
result ^= (op2<<i);
GY->u128 = result;
sse_regs_t* EY = ((uintptr_t)p > 15) ? (sse_regs_t*)((char*)p + 16)
: &emu->ymm[(uintptr_t)p];
sse_regs_t* GY = &emu->ymm[gy];
sse_regs_t* VY = &emu->ymm[vy];
int g = (u8 & 1) ? 1 : 0;
int e = (u8 & 0b10000) ? 1 : 0;
GY->u128 = pclmul_4bit(VY->q[g], EY->q[e]);
}
static int flagsCacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
+68 -22
View File
@@ -54,6 +54,46 @@ static int dynarec_can_read_window(uintptr_t addr, uintptr_t size)
}
#endif
#define X64_PREFIX_LOCK 1
#define X64_PREFIX_REP_F2 2
#define X64_PREFIX_REP_F3 3
#define X64_PREFIX_SEG0 4
#define X64_PREFIX_FS 5
#define X64_PREFIX_GS 6
#define X64_PREFIX_66 7
#define X64_PREFIX_67 8
#define X64_PREFIX_REX 9
static const uint8_t x64_prefix_kind[256] = {
[0x26] = X64_PREFIX_SEG0,
[0x2e] = X64_PREFIX_SEG0,
[0x36] = X64_PREFIX_SEG0,
[0x3e] = X64_PREFIX_SEG0,
[0x40] = X64_PREFIX_REX,
[0x41] = X64_PREFIX_REX,
[0x42] = X64_PREFIX_REX,
[0x43] = X64_PREFIX_REX,
[0x44] = X64_PREFIX_REX,
[0x45] = X64_PREFIX_REX,
[0x46] = X64_PREFIX_REX,
[0x47] = X64_PREFIX_REX,
[0x48] = X64_PREFIX_REX,
[0x49] = X64_PREFIX_REX,
[0x4a] = X64_PREFIX_REX,
[0x4b] = X64_PREFIX_REX,
[0x4c] = X64_PREFIX_REX,
[0x4d] = X64_PREFIX_REX,
[0x4e] = X64_PREFIX_REX,
[0x4f] = X64_PREFIX_REX,
[0x64] = X64_PREFIX_FS,
[0x65] = X64_PREFIX_GS,
[0x66] = X64_PREFIX_66,
[0x67] = X64_PREFIX_67,
[0xf0] = X64_PREFIX_LOCK,
[0xf2] = X64_PREFIX_REP_F2,
[0xf3] = X64_PREFIX_REP_F3,
};
uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max)
{
int ok = 1;
@@ -175,8 +215,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
dyn->last_ip = 0; // reset IP if some jump are coming here
#endif
NEW_INST;
MESSAGE(LOG_DUMP, "New Instruction %s:%p, native:%p\n", is32bits?"x86":"x64",(void*)addr, (void*)dyn->block);
NEW_INST;
#ifdef ARCH_NOP
if(dyn->insts[ninst].x64.alive && dyn->insts[ninst].x64.self_loop)
CALLRET_LOOP();
@@ -197,7 +237,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
DMB_ISHST();
#endif
if (BOX64DRENV(dynarec_dump) && (!BOX64ENV(dynarec_dump_range_end) || (ip >= BOX64ENV(dynarec_dump_range_start) && ip < BOX64ENV(dynarec_dump_range_end)))) {
dyn->need_dump = BOX64DRENV(dynarec_dump);
dyn->need_dump = BOX64DRENV(dynarec_dump) == 3 && STEP != 3 ? 0 : BOX64DRENV(dynarec_dump);
}
if(BOX64ENV(dynarec_test) && (!BOX64ENV(dynarec_test_end) || (ip>=BOX64ENV(dynarec_test_start) && ip<BOX64ENV(dynarec_test_end)))) {
int need_dump = dyn->need_dump;
@@ -205,6 +245,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
MESSAGE(LOG_DUMP, "TEST STEP ----\n");
extcache_native_t save;
fpu_save_and_unwind(dyn, ninst, &save);
#ifdef LA64
UP32_READALL();
#endif
fpu_reflectcache(dyn, ninst, x1, x2, x3);
GO_TRACE(x64test_step, 1, x5);
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
@@ -214,12 +257,20 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
}
#ifdef HAVE_TRACE
else if(my_context->dec && BOX64ENV(dynarec_trace)) {
if((trace_end == 0)
|| ((ip >= trace_start) && (ip < trace_end))) {
if(IsTraceAddr(ip)) {
MESSAGE(LOG_DUMP, "TRACE ----\n");
#if defined (SPILL_NF_REGISTERS)
if (BOX64ENV(dynarec_nativeflags)) SPILL_NF_REGISTERS;
#endif
#ifdef LA64
UP32_READALL();
#endif
fpu_reflectcache(dyn, ninst, x1, x2, x3);
GO_TRACE(PrintTrace, 1, x5);
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
#if defined (RESTORE_NF_REGISTERS)
if (BOX64ENV(dynarec_nativeflags)) RESTORE_NF_REGISTERS;
#endif
MESSAGE(LOG_DUMP, "----------\n");
}
}
@@ -235,27 +286,22 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
rex.is67 = 0;
rex.isf0 = 0;
rex.rep = 0;
while((pk==0xF2) || (pk==0xF3) || (pk==0xf0)
|| (pk==0x3E) || (pk==0x26) || (pk==0x2e) || (pk==0x36)
|| (pk==0x64) || (pk==0x65) || (pk==0x66) || (pk==0x67)
|| (!is32bits && (pk>=0x40 && pk<=0x4f))) {
switch (pk) {
case 0xF0: rex.isf0 = 1; rex.rex = 0; break;
case 0xF2: rex.rep = 1; rex.rex = 0; break;
case 0xF3: rex.rep = 2; rex.rex = 0; break;
case 0x26: /* ES: */
case 0x2E: /* CS: */
case 0x36: /* SS; */
case 0x3E: /* DS; */
rex.seg = 0; rex.rex = 0; break;
case 0x64: rex.seg = _FS; rex.rex = 0; break;
case 0x65: rex.seg = _GS; rex.rex = 0; break;
case 0x66: rex.is66 = 1; rex.rex = 0; break;
case 0x67: rex.is67 = 1; rex.rex = 0; break;
case 0x40 ... 0x4F: rex.rex = pk; break;
uint8_t prefix = x64_prefix_kind[pk];
while(prefix && (prefix!=X64_PREFIX_REX || !is32bits)) {
switch (prefix) {
case X64_PREFIX_LOCK: rex.isf0 = 1; rex.rex = 0; break;
case X64_PREFIX_REP_F2: rex.rep = 1; rex.rex = 0; break;
case X64_PREFIX_REP_F3: rex.rep = 2; rex.rex = 0; break;
case X64_PREFIX_SEG0: rex.seg = 0; rex.rex = 0; break;
case X64_PREFIX_FS: rex.seg = _FS; rex.rex = 0; break;
case X64_PREFIX_GS: rex.seg = _GS; rex.rex = 0; break;
case X64_PREFIX_66: rex.is66 = 1; rex.rex = 0; break;
case X64_PREFIX_67: rex.is67 = 1; rex.rex = 0; break;
case X64_PREFIX_REX: rex.rex = pk; break;
}
++addr;
pk = PK(0);
prefix = x64_prefix_kind[pk];
}
if(rex.isf0) {
if(rex.is66 && !rex.w)
+3
View File
@@ -18,6 +18,7 @@
// all state flags
#define SF_UNKNOWN 0
// Using this in SETFLAGS macro automaticaly include a DF_NONE macro
#define SF_SET 1
#define SF_PENDING 2
#define SF_SET_PENDING (SF_SET|SF_PENDING)
@@ -25,8 +26,10 @@
#define SF_SUBSET (SF_SUB|SF_SET)
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
#define SF_DF 8
// That means the opcode will set df to something (but that might happens outside, in the C part)
#define SF_SET_DF (SF_SET|SF_DF)
#define SF_NODF 16
// That means the opcode will not set DF directly (or it might use DFNONE() later)
#define SF_SET_NODF (SF_SET|SF_NODF)
#define NAT_FLAGS_FUSION 0
File diff suppressed because it is too large. Load diff
+224 -152
View File
@@ -68,7 +68,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
switch (nextop) {
case 0xD0:
INST_NAME("XGETBV");
BEQZ_MARK(xRCX);
ZEROUP2(x1, xRCX);
BEQZ_MARK(x1);
EMIT(0); // Is there any assigned illegal instruction?
MARK;
MOV32w(xRAX, 0b111);
@@ -81,7 +82,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
switch ((nextop >> 3) & 7) {
case 0:
INST_NAME("SGDT Ed");
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 0, 0);
MOV32w(x1, 0x7f);
ST_H(x1, wback, 0);
if (rex.is32bits) {
@@ -94,7 +95,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 1:
INST_NAME("SIDT Ed");
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 0, 0);
MOV32w(x1, 0xfff);
ST_H(x1, wback, 0);
if (rex.is32bits) {
@@ -193,8 +194,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VOR_V(v1, v0, v0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
VST(v0, ed, fixedaddress);
IF_UNALIGNED(ip) {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 15, 0);
for (int i = 0; i < 16; i++) {
VPICKVE2GR_BU(x4, v0, i);
ST_B(x4, ed, fixedaddress + i);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
VST(v0, ed, fixedaddress);
}
SMWRITE2();
}
break;
@@ -348,21 +357,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETGX(v0, 1);
GETEM(v1, 0);
q0 = fpu_get_scratch(dyn);
u8 = sse_setround(dyn, ninst, x1, x2);
VFFINT_S_W(q0, v1);
x87_restoreround(dyn, ninst, u8);
VEXTRINS_D(v0, q0, VEXTRINS_IMM_4_0(0, 0));
break;
case 0x2B:
INST_NAME("MOVNTPS Ex, Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VOR_V(v1, v0, v0);
DEFAULT;
} else {
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
VST(v0, ed, fixedaddress);
}
@@ -399,7 +404,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
nextop = F8;
GETGM(v0);
GETEXSD(v1, 0, 0);
u8 = sse_setround(dyn, ninst, x4, x6);
if (BOX64ENV(dynarec_fastround)) {
VFTINTRZ_W_S(v0, v1);
} else {
@@ -432,7 +436,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MARK3;
}
x87_restoreround(dyn, ninst, u8);
break;
case 0x2E:
// no special check...
@@ -446,36 +449,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
nextop = F8;
GETGX(d0, 0);
GETEXSS(v0, 0, 0);
CLEAR_FLAGS(x2);
// if isnan(d0) || isnan(v0)
IFX (X_ZF | X_PF | X_CF) {
FCMP_S(fcc0, d0, v0, cUN);
BCEQZ_MARK(fcc0);
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
B_MARK3_nocond;
}
MARK;
// else if isless(d0, v0)
IFX (X_CF) {
FCMP_S(fcc1, d0, v0, cLT);
BCEQZ_MARK2(fcc1);
ORI(xFlags, xFlags, 1 << F_CF);
B_MARK3_nocond;
}
MARK2;
// else if d0 == v0
IFX (X_ZF) {
FCMP_S(fcc2, d0, v0, cEQ);
BCEQZ_MARK3(fcc2);
ORI(xFlags, xFlags, 1 << F_ZF);
}
MARK3;
IFX (X_ALL) {
SPILL_EFLAGS();
}
EMIT_COMIS_FLAGS(S, d0, v0, x2);
break;
case 0x31:
INST_NAME("RDTSC");
MARKREGd(xRAX);
MARKREGd(xRDX);
NOTEST(x1);
if (box64_rdtsc) {
CALL(const_readtsc, x3, 0, 0); // will return the u64 in x3
@@ -483,10 +462,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
RDTIME_D(x3, xZR);
}
if (box64_rdtsc_shift) {
SRLI_D(x3, x3, box64_rdtsc_shift);
SLLI_D(x3, x3, box64_rdtsc_shift);
}
SRLI_D(xRDX, x3, 32);
ZEROUP2(xRDX, x3);
ZEROUP2(xRAX, x3);
break;
case 0x38:
// SSE3
@@ -503,8 +482,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VLDI(v0, 0b0000010000111); // broadcast 0b10000111 as byte
VAND_V(v0, v0, q1);
VMINI_BU(v0, v0, 0x1f);
VXOR_V(v1, v1, v1);
VSHUF_B(q0, v1, q0, v0);
VSHUF_B(q0, VZERO, q0, v0);
break;
case 0x01:
INST_NAME("PHADDW Gm, Em");
@@ -641,40 +619,63 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
v0 = fpu_get_scratch(dyn);
VXOR_V(v0, v0, v0);
VABSD_B(q0, q1, v0);
VABSD_B(q0, q1, VZERO);
break;
case 0x1D:
INST_NAME("PABSW Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
v0 = fpu_get_scratch(dyn);
VXOR_V(v0, v0, v0);
VABSD_H(q0, q1, v0);
VABSD_H(q0, q1, VZERO);
break;
case 0x1E:
INST_NAME("PABSD Gm, Em");
nextop = F8;
GETGM(q0);
GETEM(q1, 0);
v0 = fpu_get_scratch(dyn);
VXOR_V(v0, v0, v0);
VABSD_W(q0, q1, v0);
VABSD_W(q0, q1, VZERO);
break;
case 0xC8 ... 0xCD:
case 0xC8:
INST_NAME("SHA1NEXTE Gx, Ex");
u8 = nextop;
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
d0 = fpu_get_scratch(dyn);
VROTRI_W(d0, q0, 2);
VADD_W(d0, d0, q1);
if (q0 != q1) VOR_V(q0, q1, q1);
VEXTRINS_W(q0, d0, VEXTRINS_IMM_4_0(3, 3));
break;
case 0xC9:
INST_NAME("SHA1MSG1 Gx, Ex");
u8 = nextop;
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
d0 = fpu_get_scratch(dyn);
VOR_V(d0, q0, q0);
VPERMI_W(d0, q1, 0x4e);
VXOR_V(q0, q0, d0);
break;
case 0xCA:
INST_NAME("SHA1MSG2 Gx, Ex");
u8 = nextop;
nextop = F8;
GETGX(q0, 1);
GETEX(q1, 0, 0);
d0 = fpu_get_scratch(dyn);
VBSLL_V(d0, q1, 4);
VXOR_V(d0, d0, q0);
VROTRI_W(q0, d0, 31);
VBSRL_V(d0, q0, 12);
VROTRI_W(d0, d0, 31);
VXOR_V(q0, q0, d0);
break;
case 0xCB ... 0xCD:
u8 = nextop;
switch (u8) {
case 0xC8:
INST_NAME("SHA1NEXTE Gx, Ex");
break;
case 0xC9:
INST_NAME("SHA1MSG1 Gx, Ex");
break;
case 0xCA:
INST_NAME("SHA1MSG2 Gx, Ex");
break;
case 0xCB:
INST_NAME("SHA256RNDS2 Gx, Ex");
break;
@@ -700,15 +701,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
sse_reflect_reg(dyn, ninst, 0);
switch (u8) {
case 0xC8:
CALL(const_sha1nexte, -1, x1, ed);
break;
case 0xC9:
CALL(const_sha1msg1, -1, x1, ed);
break;
case 0xCA:
CALL(const_sha1msg2, -1, x1, ed);
break;
case 0xCB:
CALL(const_sha256rnds2, -1, x1, ed);
break;
@@ -723,7 +715,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xF0:
INST_NAME("MOVBE Gd, Ed");
nextop = F8;
GETGD;
GETGDd;
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
LDxw(gd, ed, fixedaddress);
@@ -731,13 +723,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
REVB_D(gd, gd);
} else {
REVB_2W(gd, gd);
ZEROUP(gd);
if (NEED_ZEROUP(gd)) ZEROUP(gd);
}
break;
case 0xF1:
INST_NAME("MOVBE Ed, Gd");
nextop = F8;
GETGD;
GETGDs;
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
if (rex.w)
@@ -772,25 +764,86 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
VEXTRINS_D(q0, d0, 0);
}
break;
#define EMIT_SHA1_F(MODE, VF, VB, VC, VD) \
do { \
switch (MODE) { \
case 0: \
VBITSEL_V(VF, VD, VC, VB); \
break; \
case 1: \
case 3: \
VXOR_V(VF, VB, VC); \
VXOR_V(VF, VF, VD); \
break; \
case 2: \
VXOR_V(VF, VB, VD); \
VBITSEL_V(VF, VB, VC, VF); \
break; \
} \
} while (0)
case 0xCC:
INST_NAME("SHA1RNDS4 Gx, Ex, Ib");
nextop = F8;
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
wback = x2;
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
}
GETGX(q0, 1);
GETEX(q1, 0, 1);
u8 = F8;
GETG;
sse_forget_reg(dyn, ninst, gd);
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
MOV32w(x3, u8);
CALL4(const_sha1rnds4, -1, x1, wback, x3, 0);
static const uint32_t sha1_k[4] = {
0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
};
int vA = fpu_get_scratch(dyn);
int vB = fpu_get_scratch(dyn);
int vC = fpu_get_scratch(dyn);
int vD = fpu_get_scratch(dyn);
int vM = fpu_get_scratch(dyn);
// reuse q1 as vT if Ex is mem operand
int vT = MODREG ? fpu_get_scratch(dyn) : q1;
int vU = SCRATCH;
VSHUF4I_W(vA, q0, 0xff);
VSHUF4I_W(vB, q0, 0xaa);
VSHUF4I_W(vC, q0, 0x55);
VSHUF4I_W(vD, q0, 0x00);
MOV32w(x7, sha1_k[u8 & 3]);
VREPLGR2VR_W(vM, x7);
VADD_W(vM, q1, vM);
EMIT_SHA1_F(u8 & 3, q0, vB, vC, vD);
VROTRI_W(vB, vB, 2);
VROTRI_W(vT, vA, 2);
EMIT_SHA1_F(u8 & 3, vU, vA, vB, vC);
VADD_W(vU, vU, vD);
VREPLVEI_W(vD, vM, 3);
VADD_W(q0, q0, vD);
VREPLVEI_W(vD, vM, 2);
VADD_W(vU, vU, vD);
VROTRI_W(vA, vA, 27);
VREPLVEI_W(vD, vM, 1);
VADD_W(vC, vC, vD);
VREPLVEI_W(vM, vM, 0);
VADD_W(vA, vA, q0);
VROTRI_W(q0, vA, 27);
EMIT_SHA1_F(u8 & 3, vD, vA, vT, vB);
VADD_W(q0, q0, vU);
VADD_W(vD, vD, vC);
VADD_W(vB, vB, vM);
VROTRI_W(vA, vA, 2);
VROTRI_W(vU, q0, 2);
EMIT_SHA1_F(u8 & 3, vC, q0, vA, vT);
VROTRI_W(vM, q0, 27);
VADD_W(vC, vC, vB);
VILVL_W(q0, vU, vA);
VADD_W(vM, vM, vD);
VEXTRINS_W(q0, vM, VEXTRINS_IMM_4_0(2, 0));
VROTRI_W(vD, vM, 27);
VADD_W(vD, vD, vC);
VEXTRINS_W(q0, vD, VEXTRINS_IMM_4_0(3, 0));
break;
#undef EMIT_SHA1_F
default:
DEFAULT;
}
@@ -806,9 +859,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} \
} \
nextop = F8; \
GETGD; \
GETGDsd; \
if (MODREG) { \
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
MARKREGs(ed); \
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP(NATNO, 8); \
} else { \
@@ -818,7 +872,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
B##NO(tmp1, 8); \
} \
MV(gd, ed); \
if (!rex.w) ZEROUP(gd); \
if (NEED_ZEROUP(gd)) ZEROUP(gd); \
} else { \
addr = geted(dyn, addr, ninst, nextop, &ed, tmp2, tmp3, &fixedaddress, rex, NULL, 1, 0); \
if (dyn->insts[ninst].nat_flags_fusion) { \
@@ -830,7 +884,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
B##NO(tmp1, 8); \
} \
LDxw(gd, ed, fixedaddress); \
if (!rex.w) ZEROUP(gd); \
if (NEED_ZEROUP(gd)) ZEROUP(gd); \
}
GOCOND(0x40, "CMOV", "Gd, Ed");
@@ -841,7 +895,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("MOVMSPKPS Gd, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGD;
GETGDd;
q1 = fpu_get_scratch(dyn);
VMSKLTZ_W(q1, q0);
MOVFR2GR_S(gd, q1);
@@ -1155,6 +1209,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
if (MODREG) {
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
MARKREGs(ed);
if (rex.w) {
MOVGR2FR_D(v0, ed);
} else {
@@ -1345,11 +1400,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
GETGM(v0);
if (MODREG) {
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
MARKREGd(ed);
if (rex.w) {
MOVFR2GR_D(ed, v0);
} else {
MOVFR2GR_S(ed, v0);
ZEROUP(ed);
if (NEED_ZEROUP(ed)) ZEROUP(ed);
}
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 1, 0);
@@ -1374,6 +1430,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
break;
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
COMIS_JCC(I); \
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
i32_ = F32S; \
if (rex.is32bits) \
@@ -1381,7 +1438,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
else \
j64 = addr + i32_; \
JUMP(j64, 1); \
if (!dyn->insts[ninst].nat_flags_fusion) { \
if (!COMIS_FUSED() && !dyn->insts[ninst].nat_flags_fusion) { \
if (cpuext.lbt) { \
X64_SETJ(x1, I); \
} else { \
@@ -1391,13 +1448,15 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
/* out of the block */ \
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_NOT_TAKEN(i32, ninst); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATNO, i32, ninst); \
} else { \
if (cpuext.lbt) \
BEQZ_safe(x1, i32); \
BEQZ_safe(x1, i32, ninst); \
else \
B##NO##_safe(x1, i32); \
B##NO##_safe(x1, i32, ninst); \
} \
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
@@ -1411,13 +1470,15 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else { \
/* inside the block */ \
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32); \
if (COMIS_FUSED()) { \
COMIS_BRANCH_TAKEN(i32, dyn->insts[ninst].x64.jmp_insts); \
} else if (dyn->insts[ninst].nat_flags_fusion) { \
NATIVEJUMP_safe(NATYES, i32, dyn->insts[ninst].x64.jmp_insts); \
} else { \
if (cpuext.lbt) \
BNEZ_safe(tmp1, i32); \
BNEZ_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
else \
B##YES##_safe(tmp1, i32); \
B##YES##_safe(tmp1, i32, dyn->insts[ninst].x64.jmp_insts); \
} \
}
@@ -1481,9 +1542,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGs(ed);
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
@@ -1510,14 +1572,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHLD Ed, Gd, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 63 : 31)) {
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETED(1);
GETGD;
GETEDsd(1);
GETGDs;
u8 = F8 & (rex.w ? 63 : 31);
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
WBACK;
} else {
FAKEED;
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
if (!rex.w && !rex.is32bits && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
F8;
}
break;
@@ -1526,12 +1588,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHLD Ed, Gd, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETED(0);
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
GETGDs;
GETEDsd(0);
if (!rex.w && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
CBZ_NEXT(x3);
emit_shld32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
@@ -1555,9 +1617,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGsd(ed);
wback = 0;
} else {
SMREAD();
@@ -1587,7 +1650,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (wback) {
SDxw(ed, wback, fixedaddress);
SMWRITE();
} else if (!rex.w) {
} else if (!rex.w && NEED_ZEROUP(ed)) {
ZEROUP(ed);
}
break;
@@ -1596,14 +1659,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHRD Ed, Gd, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & (rex.w ? 63 : 31)) {
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETED(1);
GETGD;
GETEDsd(1);
GETGDs;
u8 = F8 & (rex.w ? 63 : 31);
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
WBACK;
} else {
FAKEED;
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
if (!rex.w && !rex.is32bits && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
F8;
}
break;
@@ -1612,12 +1675,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHRD Ed, Gd, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETED(0);
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
GETGDs;
GETEDsd(0);
if (!rex.w && MODREG && NEED_ZEROUP(ed)) { ZEROUP(ed); }
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
CBZ_NEXT(x3);
emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4, x6);
@@ -1657,11 +1720,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
CALL(rex.is32bits ? const_fpu_fxrstor32 : const_fpu_fxrstor64, -1, ed, 0);
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
break;
case 2:
INST_NAME("LDMXCSR Md");
GETED(0);
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
if (BOX64ENV(sse_flushto0)) {
/* LA <-> x86
16/24 <-> 5 inexact
@@ -1711,7 +1776,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MESSAGE(LOG_DUMP, "Need Optimization\n");
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
MOV32w(x2, rex.w ? 0 : 1);
MOV32w(x2, rex.is32bits);
CALL(const_fpu_xsave, -1, ed, x2);
break;
case 5:
@@ -1719,8 +1784,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MESSAGE(LOG_DUMP, "Need Optimization\n");
BARRIER(BARRIER_FLOAT);
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
MOV32w(x2, rex.w ? 0 : 1);
MOV32w(x2, rex.is32bits);
CALL(const_fpu_xrstor, -1, ed, x2);
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
break;
case 7:
INST_NAME("CLFLUSH Ed");
@@ -1734,9 +1800,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 0xAF:
INST_NAME("IMUL Gd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
nextop = F8;
GETGD;
GETGDsd;
GETED(0);
CLEAR_FLAGS(x3);
if (rex.w) {
@@ -1771,7 +1837,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
MUL_W(gd, gd, ed);
}
ZEROUP(gd);
if (NEED_ZEROUP(gd)) ZEROUP(gd);
}
IFX (X_SF) {
SRLI_D(x3, gd, rex.w ? 63 : 31);
@@ -1785,9 +1851,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGsd(ed);
wback = 0;
} else {
SMREAD();
@@ -1816,14 +1883,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (wback) {
SDxw(ed, wback, fixedaddress);
SMWRITE();
} else if (!rex.w) {
} else if (!rex.w && NEED_ZEROUP(ed)) {
ZEROUP(ed);
}
break;
case 0xB6:
INST_NAME("MOVZX Gd, Eb");
nextop = F8;
GETGD;
GETGDd;
SCRATCH_USAGE(0);
if (MODREG) {
if (rex.rex) {
@@ -1844,7 +1911,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xB7:
INST_NAME("MOVZX Gd, Ew");
nextop = F8;
GETGD;
GETGDd;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
BSTRPICK_D(gd, ed, 15, 0);
@@ -1874,7 +1941,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("BTS Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
GETED(1);
GETEDsd(1);
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x1f);
BSTRPICK_D(x4, ed, u8, u8);
@@ -1887,7 +1954,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (wback) {
SDxw(ed, wback, fixedaddress);
SMWRITE();
} else if (!rex.w) {
} else if (!rex.w && NEED_ZEROUP(ed)) {
ZEROUP(ed);
}
break;
@@ -1895,7 +1962,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("BTR Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
GETED(1);
GETEDsd(1);
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x1f);
BSTRPICK_D(x4, ed, u8, u8);
@@ -1907,7 +1974,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (wback) {
SDxw(ed, wback, fixedaddress);
SMWRITE();
} else if (!rex.w) {
} else if (!rex.w && NEED_ZEROUP(ed)) {
ZEROUP(ed);
}
break;
@@ -1915,7 +1982,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("BTC Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
GETED(1);
GETEDsd(1);
u8 = F8;
u8 &= rex.w ? 0x3f : 0x1f;
BSTRPICK_D(x3, ed, u8, u8);
@@ -1932,7 +1999,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (wback) {
SDxw(ed, wback, fixedaddress);
SMWRITE();
} else if (!rex.w) {
} else if (!rex.w && NEED_ZEROUP(ed)) {
ZEROUP(ed);
}
break;
@@ -1945,9 +2012,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGsd(ed);
wback = 0;
} else {
SMREAD();
@@ -1974,7 +2042,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (wback) {
SDxw(ed, wback, fixedaddress);
SMWRITE();
} else if (!rex.w) {
} else if (!rex.w && NEED_ZEROUP(ed)) {
ZEROUP(ed);
}
break;
@@ -1983,13 +2051,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
} else {
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
}
SET_DFNONE();
CLEAR_FLAGS(x2);
nextop = F8;
GETED(0);
GETGD;
GETGDw;
if (!rex.w && MODREG) {
ZEROUP2(x4, ed);
ed = x4;
@@ -2013,13 +2081,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
} else {
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
}
SET_DFNONE();
CLEAR_FLAGS(x2);
nextop = F8;
GETED(0);
GETGD;
GETGDw;
if (!rex.w && MODREG) {
ZEROUP2(x4, ed);
ed = x4;
@@ -2043,7 +2111,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xBE:
INST_NAME("MOVSX Gd, Eb");
nextop = F8;
GETGD;
GETGDd;
if (MODREG) {
if (rex.rex) {
wback = TO_NAT((nextop & 7) + (rex.b << 3));
@@ -2060,12 +2128,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
LD_B(gd, ed, fixedaddress);
}
if (!rex.w) ZEROUP(gd);
if (NEED_ZEROUP(gd)) ZEROUP(gd);
break;
case 0xBF:
INST_NAME("MOVSX Gd, Ew");
nextop = F8;
GETGD;
GETGDd;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
EXT_W_H(gd, ed);
@@ -2074,7 +2142,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x1, &fixedaddress, rex, NULL, 1, 0);
LD_H(gd, ed, fixedaddress);
}
if (!rex.w) ZEROUP(gd);
if (NEED_ZEROUP(gd)) ZEROUP(gd);
break;
case 0xC0:
INST_NAME("XADD Eb, Gb");
@@ -2092,7 +2160,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("XADD Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
nextop = F8;
GETGD;
GETGDsd;
GETED(0);
if (ed != gd) MV(x7, ed);
emit_add32(dyn, ninst, rex, ed, gd, x4, x5, x6);
@@ -2119,9 +2187,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xC3:
INST_NAME("MOVNTI Ed, Gd");
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
MVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGd(ed);
MVxw(ed, gd);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
SDxw(gd, ed, fixedaddress);
@@ -2146,7 +2216,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xC5:
INST_NAME("PEXTRW Gd,Em,Ib");
nextop = F8;
GETGD;
GETGDd;
if (MODREG) {
GETEM(v0, 1);
u8 = (F8) & 3;
@@ -2203,6 +2273,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xCF:
INST_NAME("BSWAP Reg");
gd = TO_NAT((opcode & 7) + (rex.b << 3));
MARKREGsd(gd);
REVBxw(gd, gd);
break;
case 0xD1:
@@ -2257,7 +2328,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xD7:
nextop = F8;
INST_NAME("PMOVMSKB Gd, Em");
GETGD;
GETGDd;
v0 = fpu_get_scratch(dyn);
GETEM(v1, 0);
VMSKLTZ_B(v0, v1);
@@ -2503,6 +2574,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xF7:
INST_NAME("MASKMOVQ Gm, Em");
nextop = F8;
UP32_READ(xRDI);
GETGM(v0);
GETEM(v1, 0);
q0 = fpu_get_scratch(dyn);
+181 -30
View File
@@ -132,6 +132,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
emit_adc16(dyn, ninst, gd, ed, x4, x6, x5);
GWBACK;
break;
case 0x14:
return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
case 0x15:
INST_NAME("ADC AX, Iw");
READFLAGS(X_CF);
@@ -200,6 +202,17 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("AND AX, Iw");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
i32 = F16;
if (!dyn->insts[ninst].x64.gen_flags) {
if (!(i32 & 0xF000)) {
ANDI(x1, xRAX, i32);
} else {
MOV32w(x2, i32);
AND(x1, xRAX, x2);
}
BSTRINSz(xRAX, x1, 15, 0);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(x1, xZR, x2, xZR);
break;
}
BSTRPICK_D(x1, xRAX, 15, 0);
MOV32w(x2, i32);
emit_and16(dyn, ninst, x1, x2, x3, x4);
@@ -242,6 +255,20 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("XOR Gw, Ew");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
nextop = F8;
if (!dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].nat_flags_fusion) {
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 1, 0);
LD_HU(x2, wback, fixedaddress);
ed = x2;
}
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
XOR(x1, gd, ed);
BSTRINS_D(gd, x1, 15, 0);
break;
}
GETGWEW(x1, x2, 0);
emit_xor16(dyn, ninst, gd, ed, x3, x4, x5);
GWBACK;
@@ -390,7 +417,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("IMUL Gw, Ew, Ib");
}
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
nextop = F8;
GETSEW(x1, (opcode == 0x69) ? 2 : 1);
if (opcode == 0x69)
@@ -526,6 +553,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("AND Ew, Ib");
}
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
if (MODREG && !dyn->insts[ninst].x64.gen_flags) {
wback = TO_NAT((nextop & 7) + (rex.b << 3));
if (opcode == 0x81)
u64 = F16;
else
u64 = (uint16_t)(int16_t)F8S;
if (!(u64 & 0xF000)) {
ANDI(x1, wback, u64);
} else {
MOV64x(x5, u64);
AND(x1, wback, x5);
}
BSTRINS_D(wback, x1, 15, 0);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(x1, xZR, x2, xZR);
break;
}
GETEW(x1, (opcode == 0x81) ? 2 : 1);
if (opcode == 0x81)
u64 = F16;
@@ -600,13 +643,13 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("(LOCK) XCHG Ew, Gw");
nextop = F8;
if (MODREG) {
GETGD;
GETGDw;
GETED(0);
MV(x1, gd);
BSTRINS_D(gd, ed, 15, 0);
BSTRINS_D(ed, x1, 15, 0);
} else {
GETGD;
GETGDw;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
ANDI(x3, wback, 1);
BEQ_MARK(x3, xZR);
@@ -650,7 +693,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0x89:
INST_NAME("MOV Ew, Gw");
nextop = F8;
GETGD;
GETGDs;
SCRATCH_USAGE(0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
@@ -664,7 +707,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0x8B:
INST_NAME("MOV Gw, Ew");
nextop = F8;
GETGD;
GETGDw;
if (MODREG) {
SCRATCH_USAGE(0);
ed = TO_NAT((nextop & 7) + (rex.b << 3));
@@ -691,7 +734,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0x8D:
INST_NAME("LEA Gd, Ed");
nextop = F8;
GETGD;
GETGDw;
if (MODREG) {
INST_NAME("Invalid 8D");
UDF();
@@ -715,11 +758,12 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("MOV Seg, Ew");
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
BSTRPICK_D(x2, ed, 15, 0);
} else {
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
LD_HU(x1, wback, fixedaddress);
ed = x1;
LD_HU(x2, wback, fixedaddress);
ed = x2;
}
ST_H(ed, xEmu, offsetof(x64emu_t, segs[u8]));
if ((u8 == _FS) || (u8 == _GS)) {
@@ -787,7 +831,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 0x9D:
INST_NAME("POPF");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SMREAD();
POP1_16(x1);
MOV32w(x2, 0x7FD7);
@@ -846,9 +890,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
break;
case 0xA5:
UP32_READ(xRSI);
UP32_READ(xRDI);
if (rex.rep) {
UP32_READ(xRCX);
INST_NAME("REP MOVSW");
CBZ_NEXT(xRCX);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRSI);
ZEROUP(xRDI);
}
ANDI(x1, xFlags, 1 << F_DF);
BNEZ_MARK2(x1);
MARK; // Part with DF==0
@@ -870,17 +921,31 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("MOVSW");
GETDIR(x3, x1, 2);
LD_H(x1, xRSI, 0);
ST_H(x1, xRDI, 0);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRSI);
ZEROUP(xRDI);
}
IF_UNALIGNED(ip) {
LD_BU(x1, xRSI, 0);
ST_B(x1, xRDI, 0);
LD_BU(x1, xRSI, 1);
ST_B(x1, xRDI, 1);
} else {
LD_H(x1, xRSI, 0);
ST_H(x1, xRDI, 0);
}
ADD_D(xRSI, xRSI, x3);
ADD_D(xRDI, xRDI, x3);
}
SMWRITE();
break;
case 0xA7:
UP32_READ(xRSI);
UP32_READ(xRDI);
switch (rex.rep) {
case 1:
case 2:
UP32_READ(xRCX);
if (rex.rep == 1) {
INST_NAME("REPNZ CMPSW");
} else {
@@ -888,10 +953,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
CBZ_NEXT(xRCX);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRSI);
ZEROUP(xRDI);
}
ANDI(x1, xFlags, 1 << F_DF);
BNEZ_MARK2(x1);
MARK; // DF==0
@@ -926,6 +995,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("CMPSW");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
GETDIR(x3, x1, 2);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRSI);
ZEROUP(xRDI);
}
LD_HU(x1, xRSI, 0);
LD_HU(x2, xRDI, 0);
ADD_D(xRSI, xRSI, x3);
@@ -943,9 +1016,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
break;
case 0xAB:
UP32_READ(xRDI);
if (rex.rep) {
UP32_READ(xRCX);
INST_NAME("REP STOSW");
CBZ_NEXT(xRCX);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRDI);
}
ANDI(x1, xFlags, 1 << F_DF);
BNEZ_MARK2(x1);
MARK; // Part with DF==0
@@ -963,26 +1041,36 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("STOSW");
GETDIR(x3, x1, 2);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRDI);
}
ST_H(xRAX, xRDI, 0);
ADD_D(xRDI, xRDI, x3);
}
SMWRITE();
break;
case 0xAD:
UP32_READ(xRSI);
if (rex.rep) {
DEFAULT;
} else {
INST_NAME("LODSW");
GETDIR(x1, x2, 2);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRSI);
}
LD_HU(x2, xRSI, 0);
ADD_D(xRSI, xRSI, x1);
BSTRINSz(xRAX, x2, 15, 0);
}
break;
case 0xAF:
UP32_READ(xRDI);
if (rex.w) MARKREGs(xRAX);
switch (rex.rep) {
case 1:
case 2:
UP32_READ(xRCX);
if (rex.rep == 1) {
INST_NAME("REPNZ SCASW");
} else {
@@ -990,11 +1078,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
CBZ_NEXT(xRCX);
GETDIR(x3, x1, rex.w ? 8 : 2);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRDI);
}
if (rex.w) {
MARK;
LD_D(x2, xRDI, 0);
@@ -1028,6 +1119,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SCASW");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETDIR(x3, x1, rex.w ? 8 : 2);
if (rex.is67 && !rex.is32bits) {
ZEROUP(xRDI);
}
if (rex.w) {
LD_D(x2, xRDI, 0);
ADD_D(xRDI, xRDI, x3);
@@ -1060,8 +1154,13 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
switch ((nextop >> 3) & 7) {
case 0:
INST_NAME("ROL Ew, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
if (u8) {
if (MODREG && u8 > 1) {
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
} else {
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
}
GETEW(x1, 1);
u8 = (F8) & 0x1f;
emit_rol16c(dyn, ninst, x1, u8, x4, x5, x6);
@@ -1073,8 +1172,13 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 1:
INST_NAME("ROR Ew, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
if (u8) {
if (MODREG && u8 > 1) {
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
} else {
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION); // removed PENDING on purpose
}
GETEW(x1, 1);
u8 = (F8) & 0x1f;
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
@@ -1130,6 +1234,17 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHR Ew, Ib");
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
if (MODREG && !dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].nat_flags_fusion) {
u8 = (F8) & 0x1f;
wback = TO_NAT((nextop & 7) + (rex.b << 3));
if (u8 < 16) {
BSTRPICK_D(x1, wback, 15, u8);
BSTRINS_D(wback, x1, 15, 0);
} else {
BSTRINS_D(wback, xZR, 15, 0);
}
break;
}
GETEW(x1, 0);
u8 = (F8) & 0x1f;
emit_shr16c(dyn, ninst, x1, u8, x5, x4, x6);
@@ -1206,6 +1321,12 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 5:
INST_NAME("SHR Ew, 1");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
if (MODREG && !dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].nat_flags_fusion) {
wback = TO_NAT((nextop & 7) + (rex.b << 3));
BSTRPICK_D(x1, wback, 15, 1);
BSTRINS_D(wback, x1, 15, 0);
break;
}
GETEW(x1, 0);
emit_shr16c(dyn, ninst, x1, 1, x5, x4, x6);
EWBACK;
@@ -1236,7 +1357,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_OF | X_CF);
}
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETEW(x1, 0);
@@ -1248,7 +1369,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_OF | X_CF);
}
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETEW(x1, 0);
@@ -1262,7 +1383,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
READFLAGS(X_CF);
}
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETEW(x1, 0);
@@ -1276,7 +1397,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
READFLAGS(X_CF);
}
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETEW(x1, 0);
@@ -1287,9 +1408,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHR Ew, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION); // some flags are left undefined
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETEW(x1, 0);
@@ -1301,9 +1422,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SHL Ew, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION); // some flags are left undefined
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETEW(x1, 0);
@@ -1314,9 +1435,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("SAR Ew, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION); // some flags are left undefined
ANDI(x2, xRCX, 0x1f);
CBZ_NEXT(x2);
GETSEW(x1, 0);
@@ -1349,6 +1470,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 0xE6: /* OUT Ib, AL */
case 0xE7: /* OUT Ib, AX */
return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
case 0xE8: /* CALL Imm */
return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
case 0xEC: /* IN AL, DX */
case 0xED: /* IN AX, DX */
case 0xEE: /* OUT DX, AL */
@@ -1383,7 +1506,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 4:
INST_NAME("MUL AX, Ew");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
GETEW(x1, 0);
BSTRPICK_D(x2, xRAX, 15, 0);
MUL_W(x1, x2, x1);
@@ -1406,9 +1529,35 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
IFX (X_PF) emit_pf(dyn, ninst, xRAX, x3, x5);
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
break;
case 5:
INST_NAME("IMUL AX, Ew");
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
GETSEW(x1, 0);
EXT_W_H(x2, xRAX);
MUL_W(x1, x2, x1);
BSTRINSz(xRAX, x1, 15, 0);
SRLI_D(x3, x1, 16);
BSTRINS_D(xRDX, x3, 15, 0);
SET_DFNONE();
CLEAR_FLAGS(x3);
IFX (X_CF | X_OF) {
SRAI_W(x2, x1, 15);
SRAI_W(x3, x1, 31);
XOR(x3, x3, x2);
SNEZ(x3, x3);
IFX (X_CF) BSTRINS_D(xFlags, x3, F_CF, F_CF);
IFX (X_OF) BSTRINS_D(xFlags, x3, F_OF, F_OF);
}
IFX (X_SF) {
SRLI_D(x3, xRAX, 15);
BSTRINS_D(xFlags, x3, F_SF, F_SF);
}
IFX (X_PF) emit_pf(dyn, ninst, xRAX, x3, x5);
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
break;
case 6:
INST_NAME("DIV Ew");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SET_DFNONE();
GETEW(x1, 0);
BSTRPICK_D(x2, xRAX, 15, 0);
@@ -1436,7 +1585,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
case 7:
INST_NAME("IDIV Ew");
NOTEST(x1);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
}
SET_DFNONE();
GETSEW(x1, 0);
if (BOX64ENV(dynarec_div0)) {
+185 -133
View File
@@ -21,6 +21,7 @@
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
#include "dynarec_la64_aes.h"
#include "emu/x64compstrings.h"
uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
@@ -226,13 +227,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x2B:
INST_NAME("MOVNTPD Ex,Gx");
nextop = F8;
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
VOR_V(v1, v0, v0);
DEFAULT;
} else {
GETG;
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
VST(v0, ed, fixedaddress);
}
@@ -281,7 +280,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETGM(v0);
GETEX(v1, 0, 0);
u8 = sse_setround(dyn, ninst, x4, x6);
if (BOX64ENV(dynarec_fastround)) {
VFTINT_W_D(v0, v1, v1);
} else {
@@ -315,7 +313,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VEXTRINS_W(v0, q0, VEXTRINS_IMM_4_0(1, 0));
MARK3;
}
x87_restoreround(dyn, ninst, u8);
break;
case 0x2E:
// no special check...
@@ -325,37 +322,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
} else {
INST_NAME("UCOMISD Gx, Ex");
}
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGX(d0, 0);
GETEXSD(v0, 0, 0);
CLEAR_FLAGS(x3);
// if isnan(d0) || isnan(v0)
IFX (X_ZF | X_PF | X_CF) {
FCMP_D(fcc0, d0, v0, cUN);
BCEQZ_MARK(fcc0);
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
B_MARK3_nocond;
}
MARK;
// else if isless(d0, v0)
IFX (X_CF) {
FCMP_D(fcc1, d0, v0, cLT);
BCEQZ_MARK2(fcc1);
ORI(xFlags, xFlags, 1 << F_CF);
B_MARK3_nocond;
}
MARK2;
// else if d0 == v0
IFX (X_ZF) {
FCMP_D(fcc2, d0, v0, cEQ);
BCEQZ_MARK3(fcc2);
ORI(xFlags, xFlags, 1 << F_ZF);
}
MARK3;
SPILL_EFLAGS();
EMIT_COMIS_FLAGS(D, d0, v0, x3);
break;
case 0x38: // SSSE3 opcodes
nextop = F8;
@@ -370,8 +342,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VLDI(v0, 0b0000010001111); // broadcast 0b10001111 as byte
VAND_V(v0, v0, q1);
VMINI_BU(v0, v0, 0x1f);
VXOR_V(v1, v1, v1);
VSHUF_B(q0, v1, q0, v0);
VSHUF_B(q0, VZERO, q0, v0);
break;
case 0x01:
INST_NAME("PHADDW Gx, Ex");
@@ -537,7 +508,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0x17:
INST_NAME("PTEST Gx, Ex");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
GETGX(q0, 0);
GETEX(q1, 0, 0);
if (!cpuext.lbt) {
@@ -577,18 +548,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETEX(q1, 0, 0);
GETGX_empty(q0);
v0 = fpu_get_scratch(dyn);
VXOR_V(v0, v0, v0);
VABSD_B(q0, q1, v0);
VABSD_B(q0, q1, VZERO);
break;
case 0x1D:
INST_NAME("PABSW Gx, Ex");
nextop = F8;
GETEX(q1, 0, 0);
GETGX_empty(q0);
v0 = fpu_get_scratch(dyn);
VXOR_V(v0, v0, v0);
VABSD_H(q0, q1, v0);
VABSD_H(q0, q1, VZERO);
break;
case 0x1E:
INST_NAME("PABSD Gx, Ex");
@@ -661,9 +628,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("MOVNTDQA Gx, Ex");
nextop = F8;
if (MODREG) {
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
GETGX_empty(v0);
VOR_V(v0, v1, v1);
DEFAULT;
} else {
GETGX_empty(v0);
SMREAD();
@@ -826,7 +791,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VMIN_HU(q2, q0, q1); // all lane is min(abcdefgh)
VSEQ_H(q0, q2, v1); // get mask(0xffff)
VFRSTPI_H(q2, q0, 1); // find first neg(0xffff),insert index to q2
XVPICKVE_W(v0, q2, 0);
if (cpuext.lasx) {
XVPICKVE_W(v0, q2, 0);
} else {
VXOR_V(v0, v0, v0);
VEXTRINS_W(v0, q2, 0);
}
break;
case 0xDB:
INST_NAME("AESIMC Gx, Ex"); // AES-NI
@@ -836,24 +806,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (q0 != q1) {
VOR_V(q0, q1, q1);
}
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesimc, -1, x1, 0);
la64_aesimc_lsx(dyn, ninst, q0);
break;
case 0xDC:
INST_NAME("AESENC Gx, Ex"); // AES-NI
nextop = F8;
GETG;
GETEX(q1, 0, 0);
GETGX(q0, 1);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_V(d0, q1, q1);
} else
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aese, -1, x1, 0);
GETGX(q0, 1);
la64_aese_lsx(dyn, ninst, q0);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
case 0xDD:
@@ -861,15 +827,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETG;
GETEX(q1, 0, 0);
GETGX(q0, 1);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_V(d0, q1, q1);
} else
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aeselast, -1, x1, 0);
GETGX(q0, 1);
la64_aeselast_lsx(dyn, ninst, q0);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
case 0xDE:
@@ -877,15 +841,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETG;
GETEX(q1, 0, 0);
GETGX(q0, 1);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_V(d0, q1, q1);
} else
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesd, -1, x1, 0);
GETGX(q0, 1);
la64_aesd_lsx(dyn, ninst, q0);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
case 0xDF:
@@ -893,21 +855,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETG;
GETEX(q1, 0, 0);
GETGX(q0, 1);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_V(d0, q1, q1);
} else
d0 = -1;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesdlast, -1, x1, 0);
GETGX(q0, 1);
la64_aesdlast_lsx(dyn, ninst, q0);
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
break;
case 0xF0:
INST_NAME("MOVBE Gw, Ew");
nextop = F8;
GETGD;
GETGDw;
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 1, 0);
LD_HU(x1, ed, fixedaddress);
@@ -917,7 +877,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xF1:
INST_NAME("MOVBE Ew, Gw");
nextop = F8;
GETGD;
GETGDs;
SMREAD();
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, NULL, 1, 0);
REVB_2H(x1, gd);
@@ -929,8 +889,8 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
READFLAGS(X_CF);
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
GETGDsd;
GETED(0);
GETGD;
if (cpuext.lbt) {
X64_GET_EFLAGS(x3, X_CF); // CF pos is 0, no need SLLI
} else {
@@ -960,7 +920,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
} else {
ADDxw(x5, gd, ed);
ADDxw(gd, x5, x3);
if (!rex.w) ZEROUP(gd);
if (NEED_ZEROUP(gd)) ZEROUP(gd);
}
break;
default:
@@ -978,9 +938,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
v1 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_S(q0, q1);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_S(q0, q1, round_round[u8 & 3]);
}
@@ -993,9 +951,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
v1 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_D(q0, q1);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_D(q0, q1, round_round[u8 & 3]);
}
@@ -1008,9 +964,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
v1 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_S(v1, q1);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_S(v1, q1, round_round[u8 & 3]);
}
@@ -1024,9 +978,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
v1 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_D(v1, q1);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_D(v1, q1, round_round[u8 & 3]);
}
@@ -1147,6 +1099,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGX(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UP32_WRITE32(ed);
u8 = (F8) & 15;
VPICKVE2GR_BU(ed, q0, u8);
} else {
@@ -1164,6 +1117,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGX(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UP32_WRITE32(ed);
u8 = (F8) & 7;
VPICKVE2GR_HU(ed, q0, u8);
} else {
@@ -1186,6 +1140,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
d0 = fpu_get_scratch(dyn);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGd(ed);
u8 = F8;
if (rex.w) {
VPICKVE2GR_D(ed, q0, (u8 & 1));
@@ -1211,6 +1166,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETGX(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UP32_WRITE32(ed);
u8 = F8 & 0b11;
VPICKVE2GR_WU(ed, q0, u8);
} else {
@@ -1255,11 +1211,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(((u8 >> 4) & 3), 0)); // src index is zero when Ex is mem operand
}
uint8_t zmask = u8 & 0xf;
VXOR_V(q2, q2, q2);
if (zmask) {
for (uint8_t i = 0; i < 4; i++) {
if (zmask & (1 << i)) {
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(i, 0));
VEXTRINS_W(q0, VZERO, VEXTRINS_IMM_4_0(i, 0));
}
}
}
@@ -1285,12 +1240,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
v2 = fpu_get_scratch(dyn);
VFMUL_S(v0, q0, q1);
VXOR_V(v2, v2, v2);
for (int i = 0; i < 4; ++i) {
if (!(u8 & (1 << (4 + i)))) {
VEXTRINS_W(v0, v2, (i << 4));
VEXTRINS_W(v0, VZERO, (i << 4));
}
}
VSHUF4I_W(v1, v0, 0b10110001); // v0[a,b,c,d] v1[b,a,d,c]
@@ -1300,7 +1253,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VREPLVEI_W(q0, v0, 0);
for (int i = 0; i < 4; ++i) {
if (!(u8 & (1 << i))) {
VEXTRINS_W(q0, v2, (i << 4));
VEXTRINS_W(q0, VZERO, (i << 4));
}
}
break;
@@ -1312,12 +1265,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
u8 = F8;
v0 = fpu_get_scratch(dyn);
v1 = fpu_get_scratch(dyn);
v2 = fpu_get_scratch(dyn);
VFMUL_D(v0, q0, q1);
VXOR_V(v2, v2, v2);
for (int i = 0; i < 2; ++i) {
if (!(u8 & (1 << (4 + i)))) {
VEXTRINS_D(v0, v2, (i << 4));
VEXTRINS_D(v0, VZERO, (i << 4));
}
}
VSHUF4I_W(v1, v0, 0b01001110); // v0[a,b] v1[b,a]
@@ -1325,7 +1276,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VREPLVEI_D(q0, v0, 0);
for (int i = 0; i < 2; ++i) {
if (!(u8 & (1 << i))) {
VEXTRINS_D(q0, v2, (i << 4));
VEXTRINS_D(q0, VZERO, (i << 4));
}
}
break;
@@ -1349,6 +1300,62 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
MOV32w(x4, u8);
CALL4(const_native_pclmul, -1, x1, x2, x3, x4);
break;
case 0x60:
INST_NAME("PCMPESTRM Gx, Ex, Ib");
nextop = F8;
GETG;
u8 = geted_ib(dyn, addr, ninst, nextop);
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
if (gd > 7) sse_reflect_reg(dyn, ninst, gd);
ADDI_D(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
if (ed > 7) sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
ed = x1;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
}
SEXT_W(x2, xRDX);
SEXT_W(x4, xRAX);
u8 = F8;
MOV32w(x5, u8);
CALL6(const_sse42_compare_string_explicit_len, x1, ed, x2, x3, x4, x5, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, 0);
if (u8 & 0b1000000) {
v1 = fpu_get_scratch(dyn);
switch (u8 & 1) {
case 0b00:
VREPLGR2VR_B(v0, x1);
SRLI_D(x2, x1, 8);
VREPLGR2VR_B(v1, x2);
VEXTRINS_D(v0, v1, 0x10);
MOV64x(x2, 0x0001020304050607);
VREPLGR2VR_D(v1, x2);
VSLL_B(v0, v0, v1);
MOV32w(x2, 0x80);
VREPLGR2VR_B(v1, x2);
VAND_V(v0, v0, v1);
VSRAI_B(v0, v0, 7);
break;
case 0b01:
VREPLGR2VR_H(v0, x1);
MOV64x(x2, 0x000C000D000E000F);
VREPLGR2VR_D(v1, x2);
MOV64x(x2, 0x00080009000A000B);
VINSGR2VR_D(v1, x2, 1);
VSLL_H(v0, v0, v1);
MOV32w(x2, 0x80);
VREPLGR2VR_B(v1, x2);
VAND_V(v0, v0, v1);
VSRAI_H(v0, v0, 15);
break;
}
} else {
VXOR_V(v0, v0, v0);
VINSGR2VR_H(v0, x1, 0);
}
break;
case 0x61:
INST_NAME("PCMPESTRI Gx, Ex, Ib");
nextop = F8;
@@ -1385,6 +1392,59 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
CTZ_W(xRCX, x1);
}
break;
case 0x62:
INST_NAME("PCMPISTRM Gx, Ex, Ib");
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
nextop = F8;
GETG;
if (gd > 7) sse_reflect_reg(dyn, ninst, gd);
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
if (ed > 7) sse_reflect_reg(dyn, ninst, ed);
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
ed = x1;
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
}
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
u8 = F8;
MOV32w(x3, u8);
CALL4(const_sse42_compare_string_implicit_len, x1, ed, x2, x3, 0);
v0 = sse_get_reg_empty(dyn, ninst, x1, 0);
if (u8 & 0b1000000) {
v1 = fpu_get_scratch(dyn);
switch (u8 & 1) {
case 0b00:
VREPLGR2VR_B(v0, x1);
SRLI_D(x2, x1, 8);
VREPLGR2VR_B(v1, x2);
VEXTRINS_D(v0, v1, 0x10);
MOV64x(x2, 0x0001020304050607);
VREPLGR2VR_D(v1, x2);
VSLL_B(v0, v0, v1);
MOV32w(x2, 0x80);
VREPLGR2VR_B(v1, x2);
VAND_V(v0, v0, v1);
VSRAI_B(v0, v0, 7);
break;
case 0b01:
VREPLGR2VR_H(v0, x1);
MOV64x(x2, 0x000C000D000E000F);
VREPLGR2VR_D(v1, x2);
MOV64x(x2, 0x00080009000A000B);
VINSGR2VR_D(v1, x2, 1);
VSLL_H(v0, v0, v1);
MOV32w(x2, 0x80);
VREPLGR2VR_B(v1, x2);
VAND_V(v0, v0, v1);
VSRAI_H(v0, v0, 15);
break;
}
} else {
VXOR_V(v0, v0, v0);
VINSGR2VR_H(v0, x1, 0);
}
break;
case 0x63:
INST_NAME("PCMPISTRI Gx, Ex, Ib");
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
@@ -1419,23 +1479,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("AESKEYGENASSIST Gx, Ex, Ib"); // AES-NI
nextop = F8;
GETG;
sse_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd); // gx
if (MODREG) {
ed = (nextop & 7) + (rex.b << 3);
sse_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);
}
}
GETEX(q1, 0, 1);
GETGX_empty(q0);
if (q0 != q1)
VOR_V(q0, q1, q1);
u8 = F8;
MOV32w(x4, u8);
CALL4(const_native_aeskeygenassist, -1, x1, x2, x3, x4);
la64_aeskeygenassist_lsx(dyn, ninst, q0, u8);
break;
default:
DEFAULT;
@@ -1452,7 +1501,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
GETFLAGS; \
} \
nextop = F8; \
GETGD; \
GETGDw; \
if (MODREG) { \
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
} else { \
@@ -1466,14 +1515,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
B##NO(x1, 4 + 4); \
BSTRINS_D(gd, ed, 15, 0);
GOCOND(0x40, "CMOV", "Gd, Ed");
GOCOND(0x40, "CMOV", "Gw, Ew");
#undef GO
case 0x50:
nextop = F8;
INST_NAME("PMOVMSKD Gd, Ex");
GETEX(q0, 0, 0);
GETGD;
GETGDd;
VPICKVE2GR_D(x1, q0, 0);
VPICKVE2GR_D(gd, q0, 1);
SRLI_D(gd, gd, 62);
@@ -1590,7 +1639,6 @@ 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: !BOX64ENV(dynarec_fastround)
q0 = fpu_get_scratch(dyn);
VFCVT_S_D(q0, v1, v1);
VXOR_V(v0, v0, v0);
@@ -1601,7 +1649,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
nextop = F8;
GETEX(v1, 0, 0);
GETGX_empty(v0);
u8 = sse_setround(dyn, ninst, x6, x4);
if (v0 == v1 && !BOX64ENV(dynarec_fastround)) {
v1 = fpu_get_scratch(dyn);
VOR_V(v1, v0, v0);
@@ -1621,7 +1668,6 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
VSRLI_W(q0, q0, 31);
VADD_W(v0, v0, q0);
}
x87_restoreround(dyn, ninst, u8);
break;
case 0x5C:
INST_NAME("SUBPD Gx, Ex");
@@ -1843,6 +1889,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
v1 = fpu_get_scratch(dyn);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGs(ed);
if (rex.w) {
MOVGR2FR_D(v1, ed);
} else {
@@ -2112,6 +2159,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (rex.w) {
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGd(ed);
MOVFR2GR_D(ed, v0);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
@@ -2121,8 +2169,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
} else {
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGd(ed);
MOVFR2GR_S(ed, v0);
ZEROUP(ed);
if (NEED_ZEROUP(ed)) ZEROUP(ed);
} else {
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
FST_S(v0, ed, fixedaddress);
@@ -2152,7 +2201,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
@@ -2193,9 +2242,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("SHLD Ew, Gw, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
GETGWEW(x1, x2, 0);
ANDI(x4, xRCX, 0x1f);
UFLAG_IF { CBZ_NEXT(x4); }
@@ -2211,7 +2260,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
@@ -2261,9 +2310,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("SHRD Ew, Gw, CL");
if (BOX64DRENV(dynarec_safeflags) > 1) {
READFLAGS(X_ALL);
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
} else
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
GETGWEW(x1, x2, 0);
ANDI(x4, xRCX, 0x1f);
UFLAG_IF { CBZ_NEXT(x4); }
@@ -2328,7 +2377,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
@@ -2489,7 +2538,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
}
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
wback = 0;
@@ -2522,7 +2571,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xBC:
INST_NAME("BSF Gw, Ew");
if (BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
IFX (X_ALL) CLEAR_FLAGS(x3);
} else
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
@@ -2549,7 +2598,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xBD:
INST_NAME("BSR Gw, Ew");
if (BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
IFX (X_ALL) CLEAR_FLAGS(x3);
} else
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
@@ -2578,7 +2627,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xBE:
INST_NAME("MOVSX Gw, Eb");
nextop = F8;
GETGD;
GETGDw;
if (MODREG) {
if (rex.rex) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
@@ -2606,7 +2655,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
if (rex.w) return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
INST_NAME("MOVSX Gw, Ew");
nextop = F8;
GETGD;
GETGDw;
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
} else {
@@ -2622,9 +2671,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
nextop = F8;
GETGWEW(x1, x2, 0);
BSTRINS_D(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 15, 0);
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
if (!(MODREG && wback == u8)) MV(x7, ed);
emit_add16(dyn, ninst, ed, gd, x4, x5, x6);
EWBACK;
if (!(MODREG && wback == u8)) BSTRINS_D(u8, x7, 15, 0);
break;
case 0xC2:
INST_NAME("CMPPD Gx, Ex, Ib");
@@ -2662,7 +2713,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xC5:
INST_NAME("PEXTRW Gd, Ex, Ib");
nextop = F8;
GETGD;
GETGDd;
if (MODREG) {
GETEX(v0, 0, 1);
u8 = (F8) & 7;
@@ -2694,6 +2745,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("BSWAP Reg");
gd = TO_NAT((opcode & 7) + (rex.b << 3));
if (rex.w) {
MARKREGsd(gd);
REVB_D(gd, gd);
} else {
// undefined behaviour
@@ -2808,7 +2860,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("PMOVMSKB Gd, Ex");
nextop = F8;
GETEX(q0, 0, 0);
GETGD;
GETGDd;
v0 = fpu_get_scratch(dyn);
VMSKLTZ_B(v0, q0);
MOVFR2GR_D(x1, v0);
@@ -2942,11 +2994,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xE7:
INST_NAME("MOVNTDQ Ex, Gx");
nextop = F8;
GETGX(v0, 0);
if (MODREG) {
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop & 7) + (rex.b << 3));
VOR_V(v1, v0, v0);
DEFAULT;
} else {
GETGX(v0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
VST(v0, ed, fixedaddress);
}
@@ -3086,6 +3137,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
case 0xF7:
INST_NAME("MASKMOVDQU Gx, Ex");
nextop = F8;
UP32_READ(xRDI);
GETGX(v0, 1);
GETEX(v1, 0, 0);
q0 = fpu_get_scratch(dyn);
+10 -11
View File
@@ -77,7 +77,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
BSTRPICK_D(x3, x1, 15, 0);
SRLI_W(x1, x1, 16);
ADD_D(x4, x1, x5);
BSTRINS_D(x3, x4, 31, 15);
BSTRINS_D(x3, x4, 31, 16);
SC_W(x3, wback, 0);
BEQZ_MARK2(x3);
MARK3;
@@ -120,7 +120,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
BSTRPICK_D(x3, x1, 15, 0);
SRLI_W(x1, x1, 16);
OR(x4, x1, x5);
BSTRINS_D(x3, x4, 31, 15);
BSTRINS_D(x3, x4, 31, 16);
SC_W(x3, wback, 0);
BEQZ_MARK2(x3);
MARK3;
@@ -145,7 +145,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
SRAI_D(x1, gd, 3);
@@ -183,7 +183,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("LOCK CMPXCHG Ew, Gw");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
nextop = F8;
GETGD;
GETGDs;
BSTRPICK_D(x6, xRAX, 15, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
// Aligned
@@ -231,7 +231,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
SRAI_D(x1, gd, 3);
@@ -311,7 +311,6 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
INST_NAME("LOCK BTR Ew, Ib");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
GETGD;
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 0, 1);
u8 = F8;
u8 &= (rex.w ? 0x3f : 0xf);
@@ -349,7 +348,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
} else {
INST_NAME("LOCK XADD Gw, Ew");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDw;
BSTRPICK_D(x5, gd, 15, 0);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lam_bh) {
@@ -374,7 +373,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
BSTRPICK_D(x3, x1, 15, 0);
SRLI_W(x1, x1, 16);
ADD_D(x4, x1, x5);
BSTRINS_D(x3, x4, 31, 15);
BSTRINS_D(x3, x4, 31, 16);
SC_W(x3, wback, 0);
BEQZ_MARK2(x3);
MARK3;
@@ -436,7 +435,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
BSTRPICK_D(x3, x1, 15, 0);
SRLI_W(x1, x1, 16);
ADD_D(x4, x1, x5);
BSTRINS_D(x3, x4, 31, 15);
BSTRINS_D(x3, x4, 31, 16);
SC_W(x3, wback, 0);
BEQZ_MARK2(x3);
MARK3;
@@ -488,7 +487,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
BSTRPICK_D(x3, x1, 15, 0);
SRLI_W(x1, x1, 16);
ADDI_D(x4, x1, 1);
BSTRINS_D(x3, x4, 31, 15);
BSTRINS_D(x3, x4, 31, 16);
SC_W(x3, wback, 0);
BEQZ_MARK2(x3);
MARK3;
@@ -534,7 +533,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
BSTRPICK_D(x3, x1, 15, 0);
SRLI_W(x1, x1, 16);
ADDI_D(x4, x1, -1);
BSTRINS_D(x3, x4, 31, 15);
BSTRINS_D(x3, x4, 31, 16);
SC_W(x3, wback, 0);
BEQZ_MARK2(x3);
MARK3;
+2 -2
View File
@@ -56,9 +56,9 @@ uintptr_t dynarec64_66F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
INST_NAME("CRC32 Gd, Ew");
nextop = F8;
GETEW(x1, 0);
GETGD;
GETGDsd;
CRCC_W_H_W(gd, gd, ed);
ZEROUP(gd);
if (NEED_ZEROUP(gd)) ZEROUP(gd);
break;
default:
DEFAULT;
+4 -4
View File
@@ -49,10 +49,10 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
switch (opcode) {
case 0xB8:
INST_NAME("POPCNT Gw, Ew");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDw;
GETEW(x4, 0);
v0 = fpu_get_scratch(dyn);
VINSGR2VR_H(v0, ed, 0);
@@ -72,7 +72,7 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
} else {
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
}
SET_DFNONE();
nextop = F8;
@@ -98,7 +98,7 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (!BOX64DRENV(dynarec_safeflags)) {
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
} else {
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
}
SET_DFNONE();
nextop = F8;
+437
View File
@@ -0,0 +1,437 @@
#ifndef __DYNAREC_LA64_AES_H_
#define __DYNAREC_LA64_AES_H_
#include <stdint.h>
#include "dynarec_la64_consts.h"
static inline void la64_subbytes_lsx(dynarec_la64_t* dyn, int ninst, int dst, int zero, int t0, int t1, int t2, int t3, int tab)
{
(void)dyn;
(void)ninst;
VANDI_B(t0, dst, 0x0f);
VSRLI_B(t1, dst, 4);
VLD(tab, x5, 1 * 16);
VSHUF_B(t2, zero, tab, t1);
VLD(tab, x5, 0 * 16);
VSHUF_B(dst, zero, tab, t0);
VXOR_V(dst, dst, t2);
VANDI_B(t0, dst, 0x0f);
VLD(tab, x5, 3 * 16);
VSHUF_B(t2, zero, tab, t0);
VSRLI_B(t1, dst, 4);
VLD(tab, x5, 2 * 16);
VSHUF_B(dst, zero, tab, t1);
VXOR_V(t3, t1, t0);
VXOR_V(dst, dst, t2);
VSHUF_B(t0, zero, tab, t3);
VSHUF_B(dst, zero, tab, dst);
VXOR_V(t2, t0, t2);
VXOR_V(t0, dst, t3);
VSHUF_B(t2, zero, tab, t2);
VLD(tab, x5, 4 * 16);
VSHUF_B(t0, zero, tab, t0);
VXOR_V(t2, t2, t1);
VLD(tab, x5, 5 * 16);
VSHUF_B(t2, zero, tab, t2);
VXOR_V(dst, t0, t2);
VXORI_B(dst, dst, 99);
}
static inline void la64_subbytes_lasx(dynarec_la64_t* dyn, int ninst, int dst, int zero, int t0, int t1, int t2, int t3, int tab)
{
(void)dyn;
(void)ninst;
XVANDI_B(t0, dst, 0x0f);
XVSRLI_B(t1, dst, 4);
XVLD(tab, x5, 1 * 32);
XVSHUF_B(t2, zero, tab, t1);
XVLD(tab, x5, 0 * 32);
XVSHUF_B(dst, zero, tab, t0);
XVXOR_V(dst, dst, t2);
XVANDI_B(t0, dst, 0x0f);
XVLD(tab, x5, 3 * 32);
XVSHUF_B(t2, zero, tab, t0);
XVSRLI_B(t1, dst, 4);
XVLD(tab, x5, 2 * 32);
XVSHUF_B(dst, zero, tab, t1);
XVXOR_V(t3, t1, t0);
XVXOR_V(dst, dst, t2);
XVSHUF_B(t0, zero, tab, t3);
XVSHUF_B(dst, zero, tab, dst);
XVXOR_V(t2, t0, t2);
XVXOR_V(t0, dst, t3);
XVSHUF_B(t2, zero, tab, t2);
XVLD(tab, x5, 4 * 32);
XVSHUF_B(t0, zero, tab, t0);
XVXOR_V(t2, t2, t1);
XVLD(tab, x5, 5 * 32);
XVSHUF_B(t2, zero, tab, t2);
XVXOR_V(dst, t0, t2);
XVXORI_B(dst, dst, 99);
}
static inline void la64_xtime_table_lsx(dynarec_la64_t* dyn, int ninst, int dst, int src, int tmp, int tab_lo, int tab_hi)
{
(void)dyn;
(void)ninst;
VANDI_B(tmp, src, 0x0f);
VSRLI_B(dst, src, 4);
VSHUF_B(tmp, tab_lo, tab_lo, tmp);
VSHUF_B(dst, tab_hi, tab_hi, dst);
VXOR_V(dst, dst, tmp);
}
static inline void la64_mixcolumns_xtime_lsx(dynarec_la64_t* dyn, int ninst, int dst, int tab_lo, int tab_hi, int t0, int t1, int t2, int t3)
{
la64_xtime_table_lsx(dyn, ninst, t0, dst, t3, tab_lo, tab_hi);
VSHUF4I_B(t1, dst, 0x39);
VSHUF4I_B(t2, dst, 0x4e);
la64_xtime_table_lsx(dyn, ninst, dst, t1, t3, tab_lo, tab_hi);
VSHUF4I_B(t3, t2, 0x39);
VXOR_V(t2, t2, t3);
VXOR_V(dst, dst, t1);
VXOR_V(dst, dst, t0);
VXOR_V(dst, dst, t2);
}
static inline void la64_invmixcolumns_xtime_lsx(dynarec_la64_t* dyn, int ninst, int dst, int tab_lo, int tab_hi, int t0, int t1, int t2, int t3)
{
VSHUF4I_B(t0, dst, 0x4e);
VXOR_V(t0, t0, dst);
la64_xtime_table_lsx(dyn, ninst, t0, t0, t1, tab_lo, tab_hi);
la64_xtime_table_lsx(dyn, ninst, t0, t0, t1, tab_lo, tab_hi);
VXOR_V(dst, dst, t0);
la64_mixcolumns_xtime_lsx(dyn, ninst, dst, tab_lo, tab_hi, t0, t1, t2, t3);
}
static inline void la64_xtime_table_lasx(dynarec_la64_t* dyn, int ninst, int dst, int src, int tmp, int tab_lo, int tab_hi)
{
(void)dyn;
(void)ninst;
XVANDI_B(tmp, src, 0x0f);
XVSRLI_B(dst, src, 4);
XVSHUF_B(tmp, tab_lo, tab_lo, tmp);
XVSHUF_B(dst, tab_hi, tab_hi, dst);
XVXOR_V(dst, dst, tmp);
}
static inline void la64_mixcolumns_xtime_lasx(dynarec_la64_t* dyn, int ninst, int dst, int tab_lo, int tab_hi, int t0, int t1, int t2, int t3)
{
la64_xtime_table_lasx(dyn, ninst, t0, dst, t3, tab_lo, tab_hi);
XVSHUF4I_B(t1, dst, 0x39);
XVSHUF4I_B(t2, dst, 0x4e);
la64_xtime_table_lasx(dyn, ninst, dst, t1, t3, tab_lo, tab_hi);
XVSHUF4I_B(t3, t2, 0x39);
XVXOR_V(t2, t2, t3);
XVXOR_V(dst, dst, t1);
XVXOR_V(dst, dst, t0);
XVXOR_V(dst, dst, t2);
}
static inline void la64_invmixcolumns_xtime_lasx(dynarec_la64_t* dyn, int ninst, int dst, int tab_lo, int tab_hi, int t0, int t1, int t2, int t3)
{
XVSHUF4I_B(t0, dst, 0x4e);
XVXOR_V(t0, t0, dst);
la64_xtime_table_lasx(dyn, ninst, t0, t0, t1, tab_lo, tab_hi);
la64_xtime_table_lasx(dyn, ninst, t0, t0, t1, tab_lo, tab_hi);
XVXOR_V(dst, dst, t0);
la64_mixcolumns_xtime_lasx(dyn, ninst, dst, tab_lo, tab_hi, t0, t1, t2, t3);
}
static inline void la64_aesimc_lsx(dynarec_la64_t* dyn, int ninst, int dst)
{
int tab_lo = fpu_get_scratch(dyn);
int tab_hi = fpu_get_scratch(dyn);
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_dec_tables);
VLD(tab_lo, x5, 7 * 16);
VLD(tab_hi, x5, 8 * 16);
la64_invmixcolumns_xtime_lsx(dyn, ninst, dst, tab_lo, tab_hi, t0, t1, t2, t3);
}
static inline void la64_aesimc_lasx(dynarec_la64_t* dyn, int ninst, int dst)
{
int tab_lo = fpu_get_scratch(dyn);
int tab_hi = fpu_get_scratch(dyn);
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_dec_tables_xv);
XVLD(tab_lo, x5, 7 * 32);
XVLD(tab_hi, x5, 8 * 32);
la64_invmixcolumns_xtime_lasx(dyn, ninst, dst, tab_lo, tab_hi, t0, t1, t2, t3);
}
static inline void la64_aeselast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_enc_tables);
la64_subbytes_lsx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
VLD(tab, x5, 6 * 16);
VSHUF_B(dst, dst, dst, tab);
}
static inline void la64_aeselast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_enc_tables_xv);
la64_subbytes_lasx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
XVLD(tab, x5, 6 * 32);
XVSHUF_B(dst, dst, dst, tab);
}
static inline void la64_aese_lsx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
int tab_hi = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_enc_tables);
la64_subbytes_lsx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
VLD(tab, x5, 6 * 16);
VSHUF_B(dst, dst, dst, tab);
VLD(tab, x5, 7 * 16);
VLD(tab_hi, x5, 8 * 16);
la64_mixcolumns_xtime_lsx(dyn, ninst, dst, tab, tab_hi, t0, t1, t2, t3);
}
static inline void la64_aese_lasx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
int tab_hi = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_enc_tables_xv);
la64_subbytes_lasx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
XVLD(tab, x5, 6 * 32);
XVSHUF_B(dst, dst, dst, tab);
XVLD(tab, x5, 7 * 32);
XVLD(tab_hi, x5, 8 * 32);
la64_mixcolumns_xtime_lasx(dyn, ninst, dst, tab, tab_hi, t0, t1, t2, t3);
}
static inline void la64_aesdlast_lsx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int t4 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_dec_tables);
VLD(tab, x5, 6 * 16);
VSHUF_B(dst, dst, dst, tab);
VXORI_B(dst, dst, 99);
VANDI_B(t0, dst, 0x0f);
VSRLI_B(t1, dst, 4);
VLD(tab, x5, 1 * 16);
VSHUF_B(t1, zero, tab, t1);
VLD(tab, x5, 0 * 16);
VSHUF_B(dst, zero, tab, t0);
VXOR_V(dst, dst, t1);
VANDI_B(t0, dst, 0x0f);
VSRLI_B(t1, dst, 4);
VLD(tab, x5, 2 * 16);
VSHUF_B(t2, zero, tab, t1);
VLD(tab, x5, 3 * 16);
VSHUF_B(t3, zero, tab, t0);
VXOR_V(t0, t1, t0);
VXOR_V(t2, t2, t3);
VLD(tab, x5, 2 * 16);
VSHUF_B(t4, zero, tab, t0);
VSHUF_B(t2, zero, tab, t2);
VXOR_V(t3, t4, t3);
VXOR_V(t0, t2, t0);
VSHUF_B(t3, zero, tab, t3);
VXOR_V(t3, t3, t1);
VLD(tab, x5, 4 * 16);
VSHUF_B(t0, zero, tab, t0);
VLD(tab, x5, 5 * 16);
VSHUF_B(t1, zero, tab, t3);
VXOR_V(dst, t0, t1);
}
static inline void la64_aesdlast_lasx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int t4 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_dec_tables_xv);
XVLD(tab, x5, 6 * 32);
XVSHUF_B(dst, dst, dst, tab);
XVXORI_B(dst, dst, 99);
XVANDI_B(t0, dst, 0x0f);
XVSRLI_B(t1, dst, 4);
XVLD(tab, x5, 1 * 32);
XVSHUF_B(t1, zero, tab, t1);
XVLD(tab, x5, 0 * 32);
XVSHUF_B(dst, zero, tab, t0);
XVXOR_V(dst, dst, t1);
XVANDI_B(t0, dst, 0x0f);
XVSRLI_B(t1, dst, 4);
XVLD(tab, x5, 2 * 32);
XVSHUF_B(t2, zero, tab, t1);
XVLD(tab, x5, 3 * 32);
XVSHUF_B(t3, zero, tab, t0);
XVXOR_V(t0, t1, t0);
XVXOR_V(t2, t2, t3);
XVLD(tab, x5, 2 * 32);
XVSHUF_B(t4, zero, tab, t0);
XVSHUF_B(t2, zero, tab, t2);
XVXOR_V(t3, t4, t3);
XVXOR_V(t0, t2, t0);
XVSHUF_B(t3, zero, tab, t3);
XVXOR_V(t3, t3, t1);
XVLD(tab, x5, 4 * 32);
XVSHUF_B(t0, zero, tab, t0);
XVLD(tab, x5, 5 * 32);
XVSHUF_B(t1, zero, tab, t3);
XVXOR_V(dst, t0, t1);
}
static inline void la64_aesd_lsx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int t4 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_dec_tables);
VLD(tab, x5, 6 * 16);
VSHUF_B(dst, dst, dst, tab);
VXORI_B(dst, dst, 99);
VANDI_B(t0, dst, 0x0f);
VSRLI_B(t1, dst, 4);
VLD(tab, x5, 1 * 16);
VSHUF_B(t1, zero, tab, t1);
VLD(tab, x5, 0 * 16);
VSHUF_B(dst, zero, tab, t0);
VXOR_V(dst, dst, t1);
VANDI_B(t0, dst, 0x0f);
VSRLI_B(t1, dst, 4);
VLD(tab, x5, 2 * 16);
VSHUF_B(t2, zero, tab, t1);
VLD(tab, x5, 3 * 16);
VSHUF_B(t3, zero, tab, t0);
VXOR_V(t0, t1, t0);
VXOR_V(t2, t2, t3);
VLD(tab, x5, 2 * 16);
VSHUF_B(t4, zero, tab, t0);
VSHUF_B(t2, zero, tab, t2);
VXOR_V(t3, t4, t3);
VXOR_V(t0, t2, t0);
VSHUF_B(t3, zero, tab, t3);
VXOR_V(t3, t3, t1);
VLD(tab, x5, 4 * 16);
VSHUF_B(t0, zero, tab, t0);
VLD(tab, x5, 5 * 16);
VSHUF_B(t1, zero, tab, t3);
VXOR_V(dst, t0, t1);
VLD(tab, x5, 7 * 16);
VLD(t4, x5, 8 * 16);
la64_invmixcolumns_xtime_lsx(dyn, ninst, dst, tab, t4, t0, t1, t2, t3);
}
static inline void la64_aesd_lasx(dynarec_la64_t* dyn, int ninst, int dst)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int t4 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_dec_tables_xv);
XVLD(tab, x5, 6 * 32);
XVSHUF_B(dst, dst, dst, tab);
XVXORI_B(dst, dst, 99);
XVANDI_B(t0, dst, 0x0f);
XVSRLI_B(t1, dst, 4);
XVLD(tab, x5, 1 * 32);
XVSHUF_B(t1, zero, tab, t1);
XVLD(tab, x5, 0 * 32);
XVSHUF_B(dst, zero, tab, t0);
XVXOR_V(dst, dst, t1);
XVANDI_B(t0, dst, 0x0f);
XVSRLI_B(t1, dst, 4);
XVLD(tab, x5, 2 * 32);
XVSHUF_B(t2, zero, tab, t1);
XVLD(tab, x5, 3 * 32);
XVSHUF_B(t3, zero, tab, t0);
XVXOR_V(t0, t1, t0);
XVXOR_V(t2, t2, t3);
XVLD(tab, x5, 2 * 32);
XVSHUF_B(t4, zero, tab, t0);
XVSHUF_B(t2, zero, tab, t2);
XVXOR_V(t3, t4, t3);
XVXOR_V(t0, t2, t0);
XVSHUF_B(t3, zero, tab, t3);
XVXOR_V(t3, t3, t1);
XVLD(tab, x5, 4 * 32);
XVSHUF_B(t0, zero, tab, t0);
XVLD(tab, x5, 5 * 32);
XVSHUF_B(t1, zero, tab, t3);
XVXOR_V(dst, t0, t1);
XVLD(tab, x5, 7 * 32);
XVLD(t4, x5, 8 * 32);
la64_invmixcolumns_xtime_lasx(dyn, ninst, dst, tab, t4, t0, t1, t2, t3);
}
static inline void la64_aeskeygenassist_lsx(dynarec_la64_t* dyn, int ninst, int dst, uint8_t imm)
{
int zero = VZERO;
int t0 = fpu_get_scratch(dyn);
int t1 = fpu_get_scratch(dyn);
int t2 = fpu_get_scratch(dyn);
int t3 = fpu_get_scratch(dyn);
int tab = fpu_get_scratch(dyn);
int rcon = fpu_get_scratch(dyn);
TABLE64C(x5, const_la64_vpaes_keygen_tables);
la64_subbytes_lsx(dyn, ninst, dst, zero, t0, t1, t2, t3, tab);
VLD(tab, x5, 6 * 16);
VSHUF_B(dst, zero, dst, tab);
VLDI(rcon, imm);
VLD(tab, x5, 7 * 16);
VAND_V(rcon, rcon, tab);
VXOR_V(dst, dst, rcon);
}
#endif
+147
View File
@@ -0,0 +1,147 @@
#include <stddef.h>
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
#include <string.h>
#include "debug.h"
#include "dynablock.h"
#include "x64emu.h"
#include "emu/x64emu_private.h"
#include "emu/x64run_private.h"
#include "dynarec/dynablock_private.h"
#include "dynarec_la64_arch.h"
#include "dynarec_la64_functions.h"
#include "dynarec_la64_private.h"
typedef struct arch_arch_s
{
uint16_t unaligned:1;
uint16_t seq:10; // how many instruction on the same values
uint16_t up32; // GPRs with pending 32-bit zero-up at this instruction
int16_t rsp; // pending rsp offset at this instruction
} arch_arch_t;
typedef struct arch_build_s
{
uint8_t unaligned;
uint16_t up32;
int16_t rsp;
} arch_build_t;
static int arch_build(dynarec_la64_t* dyn, int ninst, arch_build_t* arch)
{
memset(arch, 0, sizeof(arch_build_t));
// opcode can handle unaligned
arch->unaligned = dyn->insts[ninst].unaligned;
// pending 32-bit zero-ups at this instruction
arch->up32 = dyn->insts[ninst].up32_pending;
arch->rsp = dyn->insts[ninst].rsp_entry;
return arch->unaligned || arch->up32 || arch->rsp;
}
size_t get_size_arch(dynarec_la64_t* dyn)
{
arch_build_t build = {0};
arch_build_t previous = {0};
size_t sz = 0;
int seq = 0;
int nseq = 0;
int last = 0;
if(!dyn->size) return 0;
for(int i=0; i<dyn->size; ++i) {
last = arch_build(dyn, i, &build);
if((!memcmp(&build, &previous, sizeof(arch_build_t))) && (seq<((1<<10)-1)) && i) {
// same sequence, increment
++seq;
} else {
seq = 0;
++nseq;
memcpy(&previous, &build, sizeof(arch_build_t));
sz+=sizeof(arch_arch_t);
}
}
if(nseq==1 && !last)
return 0; //empty, no flags, no nothing
return sz;
}
static void build_next(arch_arch_t* arch, arch_build_t* build)
{
arch->unaligned = build->unaligned;
arch->seq = 0;
arch->up32 = build->up32;
arch->rsp = build->rsp;
}
void* populate_arch(dynarec_la64_t* dyn, void* p, size_t sz)
{
(void)sz;
arch_build_t build = {0};
arch_build_t previous = {0};
arch_arch_t* arch = p;
arch_arch_t* next = p;
int seq = 0;
for(int i=0; i<dyn->size; ++i) {
arch_build(dyn, i, &build);
if((!memcmp(&build, &previous, sizeof(arch_build_t))) && (seq<((1<<10)-1)) && i) {
// same sequence, increment
seq++;
arch->seq = seq;
} else {
arch = next;
build_next(arch, &build);
seq = 0;
memcpy(&previous, &build, sizeof(arch_build_t));
next = (arch_arch_t*)((uintptr_t)arch+sizeof(arch_arch_t));
}
}
return p;
}
int getX64AddressInst(dynablock_t* db, uintptr_t x64pc); // define is signal.c
static arch_arch_t* arch_for_ninst(dynablock_t* db, int ninst)
{
arch_arch_t* arch = db->arch;
arch_arch_t* next = arch;
int i = -1;
while(i<ninst) {
arch = next;
i += 1+arch->seq;
next = (arch_arch_t*)((uintptr_t)next+sizeof(arch_arch_t));
}
return arch;
}
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
{
if(!db)
return 0;
if(!db->arch_size || !db->arch)
return 0;
int ninst = getX64AddressInst(db, x64pc);
if(ninst<0) {
return 0;
}
// look for state at ninst
arch_arch_t* arch = arch_for_ninst(db, ninst);
return arch->unaligned;
}
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
{
(void)p;
if(!db) return;
if(!db->arch_size || !db->arch) return;
int ninst = getX64AddressInst(db, x64pc);
if(ninst < 0 || ninst >= db->isize) return;
arch_arch_t* arch = arch_for_ninst(db, ninst);
uint16_t up32 = arch->up32;
while(up32) {
int r = __builtin_ctz(up32);
up32 &= up32 - 1;
emu->regs[r].q[0] &= 0xffffffffULL;
}
if (arch->rsp) emu->regs[_SP].q[0] += arch->rsp;
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef __DYNAREC_LA_ARCH_H__
#define __DYNAREC_LA_ARCH_H__
#include <stddef.h>
#include <ucontext.h>
#include "x64emu.h"
#include "box64context.h"
#include "dynarec_la64_private.h"
// get size of arch specific info (can be 0)
size_t get_size_arch(dynarec_la64_t* dyn);
//populate the array
void* populate_arch(dynarec_la64_t* dyn, void* p, size_t sz);
//adjust flags and more (needed for signal handling)
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
// get if instruction can be regenerated for unaligned access
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
#endif // __DYNAREC_LA_ARCH_H__
+3 -3
View File
@@ -74,9 +74,9 @@ uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int n
DEFAULT;
}
if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) {
if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || (dyn->need_dump && dyn->need_dump != 3) || BOX64ENV(dynarec_missing)))
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || (dyn->need_dump && dyn->need_dump != 3)) {
dynarec_log(LOG_NONE, " Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128 << vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
}
return addr;
}
}
+6 -39
View File
@@ -237,44 +237,18 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
} else {
INST_NAME("VUCOMISS Gx, Ex");
}
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGYx(d0, 0);
GETEYSS(v0, 0, 0);
CLEAR_FLAGS(x2);
// if isnan(d0) || isnan(v0)
IFX (X_ZF | X_PF | X_CF) {
FCMP_S(fcc0, d0, v0, cUN);
BCEQZ_MARK(fcc0);
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
B_MARK3_nocond;
}
MARK;
// else if isless(d0, v0)
IFX (X_CF) {
FCMP_S(fcc1, d0, v0, cLT);
BCEQZ_MARK2(fcc1);
ORI(xFlags, xFlags, 1 << F_CF);
B_MARK3_nocond;
}
MARK2;
// else if d0 == v0
IFX (X_ZF) {
FCMP_S(fcc2, d0, v0, cEQ);
BCEQZ_MARK3(fcc2);
ORI(xFlags, xFlags, 1 << F_ZF);
}
MARK3;
IFX (X_ALL) {
SPILL_EFLAGS();
}
EMIT_COMIS_FLAGS(S, d0, v0, x2);
break;
case 0x50:
nextop = F8;
INST_NAME("VMOVMSKPS Gd, Ex");
GETEYxy(v0, 0, 0);
GETGD;
GETGDd;
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVMSKLTZ_W(d1, v0);
@@ -406,9 +380,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
GETEYSD(v1, 0, 0);
}
GETGYxy_empty(v0);
if(!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x6, x4);
}
d0 = fpu_get_scratch(dyn);
if(vex.l) {
XVFCVTH_D_S(d0, v1);
@@ -417,9 +388,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
} else {
VFCVTL_D_S(v0, v1);
}
if(!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
break;
case 0x5B:
INST_NAME("VCVTDQ2PS Gx, Ex");
@@ -506,14 +474,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
if (vex.v != 0) {
UDF();
} else {
q2 = fpu_get_scratch(dyn);
XVXOR_V(q2, q2, q2);
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
if (dyn->lsx.avxcache[i].v != -1) {
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256);
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
XVPERMI_Q(q1, VZERO, XVPERMI_IMM_4_0(0, 2));
} else {
VST(q2, xEmu, offsetof(x64emu_t, ymm[i]));
VST(VZERO, xEmu, offsetof(x64emu_t, ymm[i]));
}
}
SMWRITE2();
@@ -540,6 +506,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
INST_NAME("VLDMXCSR Md");
GETED(0);
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
sse_fcsr3_from_mxcsr(dyn, ninst, x3);
if (BOX64ENV(sse_flushto0)) {
/* LA <-> x86
16/24 <-> 5 inexact
+33 -18
View File
@@ -61,9 +61,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("ANDN Gd, Vd, Ed");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDsd;
ANDN(gd, ed, vd);
if (!rex.w) {
BSTRPICK_D(gd, gd, 31, 0);
@@ -90,7 +90,11 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("BLSR Vd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETED(0);
GETVD;
GETVDsd;
if (!rex.w) {
ZEROUP2(x4, ed);
ed = x4;
}
CLEAR_FLAGS(x6);
IFX (X_CF) {
BNEZ(ed, 8);
@@ -98,9 +102,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
ADDIxw(x3, ed, -1);
AND(vd, ed, x3);
if (!rex.w) {
BSTRPICK_D(vd, vd, 31, 0);
}
if (!rex.w) ZEROUP(vd);
IFX (X_ZF) {
BNEZ(vd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
@@ -110,13 +112,20 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, vd, x3, x5);
}
SPILL_EFLAGS();
break;
case 2:
INST_NAME("BLSMSK Vd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETED(0);
GETVD;
GETVDsd;
if (!rex.w) {
ZEROUP2(x4, ed);
ed = x4;
}
CLEAR_FLAGS(x6);
IFX (X_CF) {
BNEZ(ed, 8);
@@ -124,21 +133,26 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
ADDIxw(x3, ed, -1);
XOR(vd, ed, x3);
if (!rex.w) {
BSTRPICK_D(vd, vd, 31, 0);
}
if (!rex.w) ZEROUP(vd);
IFX (X_SF) {
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, vd, x3, x5);
}
SPILL_EFLAGS();
break;
case 3:
INST_NAME("BLSI Vd, Ed");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETED(0);
GETVD;
GETVDsd;
if (!rex.w) {
ZEROUP2(x4, ed);
ed = x4;
}
CLEAR_FLAGS(x6);
IFX (X_CF) {
BEQZ(ed, 8);
@@ -146,9 +160,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
SUBxw(x3, xZR, ed);
AND(vd, ed, x3);
if (!rex.w) {
BSTRPICK_D(vd, vd, 31, 0);
}
if (!rex.w) ZEROUP(vd);
IFX (X_ZF) {
BNEZ(vd, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
@@ -158,6 +170,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
SLLI_D(x5, x5, F_SF);
OR(xFlags, xFlags, x5);
}
if (BOX64DRENV(dynarec_safeflags)) {
IFX (X_PF) emit_pf(dyn, ninst, vd, x3, x5);
}
SPILL_EFLAGS();
break;
default:
@@ -169,9 +184,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("BZHI Gd, Ed, Vd");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDs;
CLEAR_FLAGS(x6);
BSTRPICK_D(x4, vd, 7, 0);
MOV64x(x5, rex.w ? 64 : 32);
@@ -205,9 +220,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("BEXTR Gd, Ed, Vd");
nextop = F8;
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDs;
BSTRPICK_D(x4, vd, 7, 0); // start
BSTRPICK_D(x3, vd, 15, 8); // length
XOR(x5, x5, x5);
+17 -49
View File
@@ -210,10 +210,10 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x2B:
INST_NAME("VMOVNTPD Ex, Gx");
nextop = F8;
GETGYxy(q0, 0);
if (MODREG) {
DEFAULT;
} else {
GETGYxy(q0, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
if (vex.l) {
XVST(q0, ed, fixedaddress);
@@ -231,43 +231,18 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
} else {
INST_NAME("VUCOMISD Gx, Ex");
}
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGYx(d0, 0);
GETEYSD(v0, 0, 0);
CLEAR_FLAGS(x3);
// if isnan(d0) || isnan(v0)
IFX (X_ZF | X_PF | X_CF) {
FCMP_D(fcc0, d0, v0, cUN);
BCEQZ_MARK(fcc0);
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
B_MARK3_nocond;
}
MARK;
// else if isless(d0, v0)
IFX (X_CF) {
FCMP_D(fcc1, d0, v0, cLT);
BCEQZ_MARK2(fcc1);
ORI(xFlags, xFlags, 1 << F_CF);
B_MARK3_nocond;
}
MARK2;
// else if d0 == v0
IFX (X_ZF) {
FCMP_D(fcc2, d0, v0, cEQ);
BCEQZ_MARK3(fcc2);
ORI(xFlags, xFlags, 1 << F_ZF);
}
MARK3;
SPILL_EFLAGS();
EMIT_COMIS_FLAGS(D, d0, v0, x3);
break;
case 0x50:
nextop = F8;
INST_NAME("VMOVMSKPD Gd, Ex");
GETEYxy(v0, 0, 0);
GETGD;
GETGDd;
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVMSKLTZ_D(d1, v0);
@@ -375,27 +350,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETEYxy(v1, 0, 0);
GETGYx_empty(v0);
if (!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x6, x4);
}
d0 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFCVT_S_D(v0, d0, v1);
XVFCVT_S_D(v0, VZERO, v1);
XVPERMI_D(v0, v0, 0b11011000);
} else {
d0 = fpu_get_scratch(dyn);
VFCVT_S_D(d0, v1, v1);
XVPICKVE_D(v0, d0, 0);
}
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
break;
case 0x5B:
INST_NAME("VCVTPS2DQ Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
u8 = sse_setround(dyn, ninst, x6, x4);
if (vex.l) {
if (!BOX64ENV(dynarec_fastround)) {
d1 = fpu_get_scratch(dyn);
@@ -425,7 +392,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
VFTINT_W_S(v0, v1);
}
}
x87_restoreround(dyn, ninst, u8);
break;
case 0x5C:
INST_NAME("VSUBPD Gx, Vx, Ex");
@@ -867,6 +833,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETGYx(v0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
MARKREGd(ed);
if (rex.w) {
VPICKVE2GR_D(ed, v0, 0);
} else {
@@ -940,7 +907,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0xC5:
INST_NAME("VPEXTRW Gd, Ex, Ib");
nextop = F8;
GETGD;
GETGDd;
if (MODREG) {
GETEYx(v0, 0, 1);
u8 = (F8) & 7;
@@ -1048,13 +1015,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
VADDxy(D, v0, v1, v2);
break;
case 0xD5:
INST_NAME("VPMULLW Gx, Ex");
INST_NAME("VPMULLW Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VMULxy(H, v0, v1, v2);
break;
case 0xD6:
INST_NAME("VMOVD Ex, Gx");
INST_NAME("VMOVQ Ex, Gx");
nextop = F8;
GETGYx(q0, 0);
if (MODREG) {
@@ -1070,7 +1037,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
INST_NAME("VPMOVMSKB Gd, Ex");
GETEYxy(v0, 0, 0);
GETGD;
GETGDd;
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVMSKLTZ_B(d1, v0);
@@ -1177,12 +1144,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETEYxy(v1, 0, 0);
GETGYx_empty(v0);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFTINTRZ_W_D(d1, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
d1 = fpu_get_scratch(dyn);
XVFTINTRZ_W_D(d1, VZERO, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
if (!BOX64ENV(dynarec_fastround)) {
d0 = fpu_get_scratch(dyn);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
@@ -1198,6 +1164,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
XVPERMI_D(v0, v0, 0b11011000);
} else {
d0 = fpu_get_scratch(dyn);
VFTINTRZ_W_D(d0, v1, v1);
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
@@ -1274,7 +1241,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
INST_NAME("VPXOR Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VXOR_Vxy(v0, v1, v2);
XVXOR_V(v0, v1, v2);
if (v0 == v1 && v0 == v2) YMM_UNMARK_UPPER_ZERO(v0);
break;
case 0xF1:
@@ -1341,6 +1308,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0xF7:
INST_NAME("VMASKMOVDQU Gx, Ex");
nextop = F8;
UP32_READ(xRDI);
GETEYx(v1, 0, 0);
GETGYx(v0, 0);
q0 = fpu_get_scratch(dyn);
+37 -64
View File
@@ -19,6 +19,7 @@
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
#include "dynarec_la64_aes.h"
uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
{
@@ -62,12 +63,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
VLDIxy(q0, 0b0000010001111); // broadcast 0b10001111 as byte
VAND_Vxy(q0, q0, v2);
VMINIxy(BU, q0, q0, 0x1f);
VXOR_Vxy(q1, q1, q1);
VSHUF_Bxy(v0, q1, v1, q0);
VSHUF_Bxy(v0, VZERO, v1, q0);
break;
case 0x01:
INST_NAME("VPHADDW Gx, Vx, Ex");
@@ -345,25 +344,19 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
INST_NAME("VPABSB Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
q0 = fpu_get_scratch(dyn);
XVXOR_V(q0, q0, q0);
VABSDxy(B, v0, v1, q0);
VABSDxy(B, v0, v1, VZERO);
break;
case 0x1D:
INST_NAME("VPABSW Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
q0 = fpu_get_scratch(dyn);
XVXOR_V(q0, q0, q0);
VABSDxy(H, v0, v1, q0);
VABSDxy(H, v0, v1, VZERO);
break;
case 0x1E:
INST_NAME("VPABSD Gx, Ex");
nextop = F8;
GETGY_empty_EY_xy(v0, v1, 0);
q0 = fpu_get_scratch(dyn);
XVXOR_V(q0, q0, q0);
VABSDxy(W, v0, v1, q0);
VABSDxy(W, v0, v1, VZERO);
break;
case 0x20:
INST_NAME("VPMOVSXBW Gx, Ex");
@@ -497,32 +490,26 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
INST_NAME("VMASKMOVPS Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVSLTI_W(d1, v1, 0); // create all-one mask for negetive element.
XVBITSEL_V(v0, d0, v2, d1);
XVBITSEL_V(v0, VZERO, v2, d1);
} else {
VXOR_V(d0, d0, d0);
VSLTI_W(d1, v1, 0); // create all-one mask for negetive element.
VBITSEL_V(v0, d0, v2, d1);
VBITSEL_V(v0, VZERO, v2, d1);
}
break;
case 0x2D:
INST_NAME("VMASKMOVPD Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVSLTI_D(d1, v1, 0); // create all-one mask for negetive element.
XVBITSEL_V(v0, d0, v2, d1);
XVBITSEL_V(v0, VZERO, v2, d1);
} else {
VXOR_V(d0, d0, d0);
VSLTI_D(d1, v1, 0); // create all-one mask for negetive element.
VBITSEL_V(v0, d0, v2, d1);
VBITSEL_V(v0, VZERO, v2, d1);
}
break;
case 0x2E:
@@ -697,7 +684,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
VMAXxy(WU, v0, v1, v2);
break;
case 0x40:
INST_NAME("VPMULLD Gx, Ex");
INST_NAME("VPMULLD Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
VMULxy(W, v0, v1, v2);
@@ -835,24 +822,21 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
INST_NAME("VPMASKMOVD/Q Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
if (vex.l) {
XVXOR_V(d0, d0, d0);
if (rex.w) {
XVSLTI_D(d1, v1, 0);
} else {
XVSLTI_W(d1, v1, 0);
}
XVBITSEL_V(v0, d0, v2, d1);
XVBITSEL_V(v0, VZERO, v2, d1);
} else {
VXOR_V(d0, d0, d0);
if (rex.w) {
VSLTI_D(d1, v1, 0);
} else {
VSLTI_W(d1, v1, 0);
}
VBITSEL_V(v0, d0, v2, d1);
VBITSEL_V(v0, VZERO, v2, d1);
}
break;
case 0x8E:
@@ -893,8 +877,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
int64_t i64 = F32S64;
MOV64x(x5, i64);
eb1 = x5;
} else
} else {
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
UP32_READ(eb1);
}
eb2 = ((u8 >> 3) & 7) + (rex.x << 3); // index
if (nextop & 0x40)
i32 = F8S;
@@ -973,8 +959,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
int64_t i64 = F32S64;
MOV64x(x5, i64);
eb1 = x5;
} else
} else {
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
UP32_READ(eb1);
}
eb2 = ((u8 >> 3) & 7) + (rex.x << 3); // index
if (nextop & 0x40)
i32 = F8S;
@@ -1304,31 +1292,25 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
if (q0 != q1) {
VOR_V(q0, q1, q1);
}
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesimc, -1, x1, 0);
GETGYx(q0, 1); // reget writable for mark zeroup hi-128bits.
la64_aesimc_lsx(dyn, ninst, q0);
break;
case 0xDC:
INST_NAME("VAESENC Gx, Vx, Ex");
nextop = F8;
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_Vxy(d0, q2, q2);
} else
d0 = -1;
if (gd != vex.v) {
VOR_Vxy(q0, q1, q1);
}
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aese, -1, x1, 0);
if (vex.l) {
MOV32w(x1, gd);
CALL(const_native_aese_y, -1, x1, 0);
la64_aese_lasx(dyn, ninst, q0);
} else {
la64_aese_lsx(dyn, ninst, q0);
}
GETGYxy(q0, 1);
VXOR_Vxy(q0, q0, (d0 != -1) ? d0 : q2);
break;
case 0xDD:
@@ -1336,21 +1318,18 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
nextop = F8;
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_Vxy(d0, q2, q2);
} else
d0 = -1;
if (gd != vex.v) {
VOR_Vxy(q0, q1, q1);
}
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aeselast, -1, x1, 0);
if (vex.l) {
MOV32w(x1, gd);
CALL(const_native_aeselast_y, -1, x1, 0);
la64_aeselast_lasx(dyn, ninst, q0);
} else {
la64_aeselast_lsx(dyn, ninst, q0);
}
GETGYxy(q0, 1);
VXOR_Vxy(q0, q0, (d0 != -1) ? d0 : q2);
break;
case 0xDE:
@@ -1358,21 +1337,18 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
nextop = F8;
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_Vxy(d0, q2, q2);
} else
d0 = -1;
if (gd != vex.v) {
VOR_Vxy(q0, q1, q1);
}
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesd, -1, x1, 0);
if (vex.l) {
MOV32w(x1, gd);
CALL(const_native_aesd_y, -1, x1, 0);
la64_aesd_lasx(dyn, ninst, q0);
} else {
la64_aesd_lsx(dyn, ninst, q0);
}
GETGYxy(q0, 1);
VXOR_Vxy(q0, q0, (d0 != -1) ? d0 : q2);
break;
case 0xDF:
@@ -1380,29 +1356,26 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
nextop = F8;
GETGY_empty_VYEY_xy(q0, q1, q2, 0);
if (MODREG && (gd == (nextop & 7) + (rex.b << 3))) {
d0 = fpu_get_scratch(dyn);
d0 = SCRATCH;
VOR_Vxy(d0, q2, q2);
} else
d0 = -1;
if (gd != vex.v) {
VOR_Vxy(q0, q1, q1);
}
avx_forget_reg(dyn, ninst, gd);
MOV32w(x1, gd);
CALL(const_native_aesdlast, -1, x1, 0);
if (vex.l) {
MOV32w(x1, gd);
CALL(const_native_aesdlast_y, -1, x1, 0);
la64_aesdlast_lasx(dyn, ninst, q0);
} else {
la64_aesdlast_lsx(dyn, ninst, q0);
}
GETGYxy(q0, 1);
VXOR_Vxy(q0, q0, (d0 != -1) ? d0 : q2);
break;
case 0xF7:
INST_NAME("SHLX Gd, Ed, Vd");
nextop = F8;
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDs;
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
SLLxw(gd, ed, x5);
break;
+24 -51
View File
@@ -19,6 +19,7 @@
#include "dynarec_la64_private.h"
#include "dynarec_la64_functions.h"
#include "../dynarec_helper.h"
#include "dynarec_la64_aes.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)
{
@@ -34,7 +35,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
int cacheupd = 0;
int v0, v1, v2;
int q0, q1, q2;
int d0, d1, d2;
int d0, d1;
int s0;
uint64_t tmp64u;
int64_t j64;
@@ -146,7 +147,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
XVXOR_V(v0, v0, v0);
break;
}
d0 = fpu_get_scratch(dyn);
uint8_t zero_low = (u8 & 0x8) >> 3;
uint8_t zero_up = (u8 & 0x80) >> 7;
uint8_t vec_lo = (u8 & 0x2) >> 1;
@@ -164,13 +164,12 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
}
break;
}
XVXOR_V(d0, d0, d0);
if (zero_low) {
XVORI_B(v0, vec_hi ? v2 : v1, 0);
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(2 + index_hi, 0));
XVPERMI_Q(v0, VZERO, XVPERMI_IMM_4_0(2 + index_hi, 0));
} else {
XVORI_B(v0, vec_lo ? v2 : v1, 0);
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2 + index_lo));
XVPERMI_Q(v0, VZERO, XVPERMI_IMM_4_0(0, 2 + index_lo));
}
break;
case 0x08:
@@ -179,13 +178,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
if (vex.l) {
XVFRINT_S(v0, v1);
} else {
VFRINT_S(v0, v1);
}
x87_restoreround(dyn, ninst, u8);
} else {
if (vex.l) {
XVFRINTRRD_S(v0, v1, round_round[u8 & 3]);
@@ -200,13 +197,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGY_empty_EY_xy(v0, v1, 1);
u8 = F8;
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
if (vex.l) {
XVFRINT_D(v0, v1);
} else {
VFRINT_D(v0, v1);
}
x87_restoreround(dyn, ninst, u8);
} else {
if (vex.l) {
XVFRINTRRD_D(v0, v1, round_round[u8 & 3]);
@@ -224,9 +219,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_S(d0, v2);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_S(d0, v2, round_round[u8 & 3]);
}
@@ -242,9 +235,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x1, x2);
VFRINT_D(d0, v2);
x87_restoreround(dyn, ninst, u8);
} else {
VFRINTRRD_D(d0, v2, round_round[u8 & 3]);
}
@@ -380,6 +371,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGYx(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UP32_WRITE32(ed);
u8 = (F8) & 15;
VPICKVE2GR_BU(ed, q0, u8);
} else {
@@ -396,6 +388,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGYx(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UP32_WRITE32(ed);
u8 = (F8) & 7;
VPICKVE2GR_HU(ed, q0, u8);
} else {
@@ -416,6 +409,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGYx(q0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
MARKREGd(ed);
u8 = F8;
if (rex.w) {
VPICKVE2GR_D(ed, q0, (u8 & 1));
@@ -439,6 +433,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETGYx(v0, 0);
if (MODREG) {
ed = TO_NAT((nextop & 7) + (rex.b << 3));
UP32_WRITE32(ed);
u8 = F8 & 0b11;
VPICKVE2GR_WU(ed, v0, u8);
} else {
@@ -506,26 +501,20 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
GETEYSD(v1, 1, 1);
}
u8 = F8;
d0 = fpu_get_scratch(dyn);
if (u8 & 4) {
u8 = sse_setround(dyn, ninst, x4, x5);
} else {
if (!(u8 & 4)) {
MOVFCSR2GR(x4, FCSR3);
ORI(x5, xZR, ((-(u8 & 3)) & 3) << 8);
MOVGR2FCSR(FCSR3, x5);
u8 = x4;
}
if (vex.l) {
XVXOR_V(d0, d0, d0);
XVFCVT_H_S(v1, d0, v0);
XVFCVT_H_S(v1, VZERO, v0);
XVPERMI_D(v1, v1, 0b11011000);
PUTEYx(v1);
} else {
XVXOR_V(d0, d0, d0);
VFCVT_H_S(v1, d0, v0);
VFCVT_H_S(v1, VZERO, v0);
PUTEYSD(v1);
}
x87_restoreround(dyn, ninst, u8);
if (!(u8 & 4)) x87_restoreround(dyn, ninst, x4);
break;
case 0x20:
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
@@ -572,10 +561,9 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
}
uint8_t zmask = u8 & 0xf;
if (zmask) {
VXOR_V(q1, q1, q1);
for (uint8_t i = 0; i < 4; i++) {
if (zmask & (1 << i)) {
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0(i, 0));
VEXTRINS_W(v0, VZERO, VEXTRINS_IMM_4_0(i, 0));
}
}
}
@@ -605,12 +593,10 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
d2 = fpu_get_scratch(dyn);
VFMULxy(S, d0, v1, v2);
VXOR_Vxy(d2, d2, d2);
for (int i = 0; i < 4; ++i) {
if (!(u8 & (1 << (4 + i)))) {
VEXTRINSxy(W, d0, d2, (i << 4));
VEXTRINSxy(W, d0, VZERO, (i << 4));
}
}
VSHUF4Ixy(W, d1, d0, 0b10110001); // v0[a,b,c,d] v1[b,a,d,c]
@@ -620,7 +606,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
VREPLVEIxy(W, v0, d0, 0);
for (int i = 0; i < 4; ++i) {
if (!(u8 & (1 << i))) {
VEXTRINSxy(W, v0, d2, (i << 4));
VEXTRINSxy(W, v0, VZERO, (i << 4));
}
}
break;
@@ -631,12 +617,10 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
u8 = F8;
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
d2 = fpu_get_scratch(dyn);
VFMULxy(D, d0, v1, v2);
VXOR_Vxy(d2, d2, d2);
for (int i = 0; i < 2; ++i) {
if (!(u8 & (1 << (4 + i)))) {
VEXTRINSxy(D, d0, d2, (i << 4));
VEXTRINSxy(D, d0, VZERO, (i << 4));
}
}
VSHUF4Ixy(W, d1, d0, 0b01001110); // v0[a,b] v1[b,a]
@@ -644,7 +628,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
VREPLVEIxy(D, v0, d0, 0);
for (int i = 0; i < 2; ++i) {
if (!(u8 & (1 << i))) {
VEXTRINSxy(D, v0, d2, (i << 4));
VEXTRINSxy(D, v0, VZERO, (i << 4));
}
}
break;
@@ -789,27 +773,16 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
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
GETEYx(q1, 0, 1);
if (vex.l) {
GETGYy(q0, 1);
} else {
MOV32w(x2, 0);
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 1);
if (ed != x3) {
MV(x3, ed);
}
GETGYx_empty(q0);
}
if (q0 != q1)
VOR_V(q0, q1, q1);
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);
}
la64_aeskeygenassist_lsx(dyn, ninst, q0, u8);
break;
default:
+8 -20
View File
@@ -117,9 +117,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETVYx(v1, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
if (!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x2, x3);
}
if (rex.w) {
MOVGR2FR_D(d1, ed);
FFINT_D_L(d1, d1);
@@ -127,16 +124,13 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
MOVGR2FR_W(d1, ed);
FFINT_D_W(d1, d1);
}
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_D(v0, d1, 0);
break;
case 0x2C:
INST_NAME("VCVTTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETGDd;
GETEYSD(q0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
@@ -165,13 +159,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x2D:
INST_NAME("VCVTSD2SI Gd, Ex");
nextop = F8;
GETGD;
GETGDd;
GETEYSD(q0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
d1 = fpu_get_scratch(dyn);
u8 = sse_setround(dyn, ninst, x2, x3);
if (rex.w) {
FTINT_L_D(d1, q0);
MOVFR2GR_D(gd, d1);
@@ -180,7 +173,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
x87_restoreround(dyn, ninst, u8);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
@@ -202,9 +194,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d1 = fpu_get_scratch(dyn);
FSQRT_D(d1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
VXOR_V(d0, d0, d0);
FCMP_D(fcc0, v2, d0, cLT);
FCMP_D(fcc0, v2, VZERO, cLT);
BCEQZ(fcc0, 4 + 4);
FNEG_D(d1, d1);
}
@@ -432,8 +422,8 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETVYx(v1, 0);
GETEYSD(v2, 0, 1);
GETGYx(v0, 1);
q0 = fpu_get_scratch(dyn);
u8 = F8;
q0 = ((u8 & 0xf) == 0x0b) ? VZERO : fpu_get_scratch(dyn);
switch (u8 & 0xf) {
case 0x00: VFCMP_D(q0, v1, v2, cEQ); break; // Equal, not unordered
case 0x01: VFCMP_D(q0, v1, v2, cLT); break; // Less than
@@ -446,7 +436,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x08: VFCMP_D(q0, v1, v2, cUEQ); break; // Equal, or unordered
case 0x09: VFCMP_D(q0, v1, v2, cULT); break; // Less than or unordered
case 0x0a: VFCMP_D(q0, v1, v2, cULE); break; // Less or equal or unordered
case 0x0b: VXOR_V(q0, q0, q0); break; // false
case 0x0b: break; // false
case 0x0c: VFCMP_D(q0, v1, v2, cNE); break; // Not Eual, ordered
case 0x0d: VFCMP_D(q0, v2, v1, cLE); break; // Greater or Equal ordered
case 0x0e: VFCMP_D(q0, v2, v1, cLT); break; // Greater ordered
@@ -488,19 +478,17 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
nextop = F8;
GETEYxy(v1, 0, 0);
GETGYx_empty(v0);
u8 = sse_setround(dyn, ninst, x1, x2);
d0 = fpu_get_scratch(dyn);
if (vex.l) {
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
q1 = fpu_get_scratch(dyn);
q2 = fpu_get_scratch(dyn);
d0 = fpu_get_scratch(dyn);
d1 = fpu_get_scratch(dyn);
XVFTINT_L_D(q2, v1);
XVFCMP_D(d1, v1, v1, cUN); // get NaN mask
}
XVXOR_V(d0, d0, d0);
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
XVFTINT_W_D(v0, VZERO, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
if (!BOX64ENV(dynarec_fastround)) {
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
MOV32w(x5, 0x7FFFFFFF);
@@ -513,6 +501,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
XVPERMI_D(v0, v0, 0b11011000);
} else {
d0 = fpu_get_scratch(dyn);
VFTINT_W_D(d0, v1, v1);
if (!BOX64ENV(dynarec_fastround)) {
q0 = fpu_get_scratch(dyn);
@@ -532,7 +521,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
}
XVPICKVE_D(v0, d0, 0);
}
x87_restoreround(dyn, ninst, u8);
break;
case 0xF0:
INST_NAME("VLDDQU Gx, Ex");
+7 -6
View File
@@ -60,8 +60,8 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0xF5:
INST_NAME("PDEP Gd, Vd, Ed");
nextop = F8;
GETGD;
GETVD;
GETGDd;
GETVDs;
GETED(0);
if (gd == ed || gd == vd) {
gb1 = gd;
@@ -89,9 +89,10 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0xF6:
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
nextop = F8;
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDsd;
MARKREGs(xRDX);
if (rex.w) {
if ((gd == xRDX) || (gd == ed) || (gd == vd))
gb1 = x3;
@@ -111,9 +112,9 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0xF7:
INST_NAME("SHRX Gd, Ed, Vd");
nextop = F8;
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDs;
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
SRLxw(gd, ed, x5);
break;
+1 -1
View File
@@ -60,7 +60,7 @@ uintptr_t dynarec64_AVX_F2_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0xF0:
INST_NAME("RORX Gd, Ed, Ib");
nextop = F8;
GETGD;
GETGDsd;
GETED(1);
u8 = F8;
ROTRIxw(gd, ed, u8 & (rex.w ? 0x3f : 0x1f));
+5 -17
View File
@@ -107,9 +107,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETVYx(v1, 0);
GETGYx_empty(v0);
d1 = fpu_get_scratch(dyn);
if (!BOX64ENV(dynarec_fastround)) {
u8 = sse_setround(dyn, ninst, x2, x3);
}
if (rex.w) {
MOVGR2FR_D(d1, ed);
FFINT_S_L(d1, d1);
@@ -117,21 +114,17 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
MOVGR2FR_W(d1, ed);
FFINT_S_W(d1, d1);
}
if (!BOX64ENV(dynarec_fastround)) {
x87_restoreround(dyn, ninst, u8);
}
if (v0 != v1) VOR_V(v0, v1, v1);
VEXTRINS_W(v0, d1, 0);
break;
case 0x2C:
INST_NAME("VCVTTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETGDd;
GETEYSS(d0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
u8 = sse_setround(dyn, ninst, x5, x6);
d1 = fpu_get_scratch(dyn);
if (rex.w) {
FTINTRZ_L_S(d1, d0);
@@ -141,7 +134,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
x87_restoreround(dyn, ninst, u8);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
@@ -157,12 +149,11 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x2D:
INST_NAME("VCVTSS2SI Gd, Ex");
nextop = F8;
GETGD;
GETGDd;
GETEYSS(d0, 0, 0);
if (!BOX64ENV(dynarec_fastround)) {
MOVGR2FCSR(FCSR2, xZR); // reset all bits
}
u8 = sse_setround(dyn, ninst, x5, x6);
d1 = fpu_get_scratch(dyn);
if (rex.w) {
FTINT_L_S(d1, d0);
@@ -172,7 +163,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
MOVFR2GR_S(gd, d1);
ZEROUP(gd);
}
x87_restoreround(dyn, ninst, u8);
if (!BOX64ENV(dynarec_fastround)) {
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
@@ -194,9 +184,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
d1 = fpu_get_scratch(dyn);
FSQRT_S(d1, v2);
if (!BOX64ENV(dynarec_fastnan)) {
d0 = fpu_get_scratch(dyn);
VXOR_V(d0, d0, d0);
FCMP_S(fcc0, v2, d0, cLT);
FCMP_S(fcc0, v2, VZERO, cLT);
BCEQZ(fcc0, 4 + 4);
FNEG_S(d1, d1);
}
@@ -475,8 +463,8 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
GETVYx(v1, 0);
GETEYSS(v2, 0, 1);
GETGYx(v0, 1);
q0 = fpu_get_scratch(dyn);
u8 = F8;
q0 = ((u8 & 0xf) == 0x0b) ? VZERO : fpu_get_scratch(dyn);
switch (u8 & 0xf) {
case 0x00: VFCMP_S(q0, v1, v2, cEQ); break; // Equal, not unordered
case 0x01: VFCMP_S(q0, v1, v2, cLT); break; // Less than
@@ -489,7 +477,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
case 0x08: VFCMP_S(q0, v1, v2, cUEQ); break; // Equal, or unordered
case 0x09: VFCMP_S(q0, v1, v2, cULT); break; // Less than or unordered
case 0x0a: VFCMP_S(q0, v1, v2, cULE); break; // Less or equal or unordered
case 0x0b: VXOR_V(q0, q0, q0); break; // false
case 0x0b: break; // false
case 0x0c: VFCMP_S(q0, v1, v2, cNE); break; // Not Eual, ordered
case 0x0d: VFCMP_S(q0, v2, v1, cLE); break; // Greater or Equal ordered
case 0x0e: VFCMP_S(q0, v2, v1, cLT); break; // Greater ordered
+4 -4
View File
@@ -60,8 +60,8 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0xF5:
INST_NAME("PEXT Gd, Vd, Ed");
nextop = F8;
GETGD;
GETVD;
GETGDd;
GETVDs;
GETED(0);
if (gd == ed || gd == vd) {
gb1 = gd;
@@ -90,9 +90,9 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
case 0xF7:
INST_NAME("SARX Gd, Ed, Vd");
nextop = F8;
GETGD;
GETGDd;
GETED(0);
GETVD;
GETVDs;
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
SRAxw(gd, ed, x5);
break;
+73 -1
View File
@@ -25,10 +25,76 @@
#include "bitutils.h"
#include "random.h"
void* create_updateflags();
#ifndef HAVE_TRACE
void PrintTrace() {}
#endif
static const uint8_t la64_vpaes_enc_tables[9][16] __attribute__((aligned(16))) = {
{ 0x00, 0x70, 0x2a, 0x5a, 0x98, 0xe8, 0xb2, 0xc2, 0x08, 0x78, 0x22, 0x52, 0x90, 0xe0, 0xba, 0xca },
{ 0x00, 0x4d, 0x7c, 0x31, 0x7d, 0x30, 0x01, 0x4c, 0x81, 0xcc, 0xfd, 0xb0, 0xfc, 0xb1, 0x80, 0xcd },
{ 0x10, 0x01, 0x08, 0x0d, 0x0f, 0x06, 0x05, 0x0e, 0x02, 0x0c, 0x0b, 0x0a, 0x09, 0x03, 0x07, 0x04 },
{ 0x10, 0x07, 0x0b, 0x0f, 0x06, 0x0a, 0x04, 0x01, 0x09, 0x08, 0x05, 0x02, 0x0c, 0x0e, 0x0d, 0x03 },
{ 0x00, 0xc7, 0xbd, 0x6f, 0x17, 0x6d, 0xd2, 0xd0, 0x78, 0xa8, 0x02, 0xc5, 0x7a, 0xbf, 0xaa, 0x15 },
{ 0x00, 0x6a, 0xbb, 0x5f, 0xa5, 0x74, 0xe4, 0xcf, 0xfa, 0x35, 0x2b, 0x41, 0xd1, 0x90, 0x1e, 0x8e },
{ 0x00, 0x05, 0x0a, 0x0f, 0x04, 0x09, 0x0e, 0x03, 0x08, 0x0d, 0x02, 0x07, 0x0c, 0x01, 0x06, 0x0b },
{ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
{ 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x1b, 0x3b, 0x5b, 0x7b, 0x9b, 0xbb, 0xdb, 0xfb },
};
static const uint8_t la64_vpaes_dec_tables[9][16] __attribute__((aligned(16))) = {
{ 0x00, 0x5f, 0x54, 0x0b, 0x04, 0x5b, 0x50, 0x0f, 0x1a, 0x45, 0x4e, 0x11, 0x1e, 0x41, 0x4a, 0x15 },
{ 0x00, 0x65, 0x05, 0x60, 0xe6, 0x83, 0xe3, 0x86, 0x94, 0xf1, 0x91, 0xf4, 0x72, 0x17, 0x77, 0x12 },
{ 0x10, 0x01, 0x08, 0x0d, 0x0f, 0x06, 0x05, 0x0e, 0x02, 0x0c, 0x0b, 0x0a, 0x09, 0x03, 0x07, 0x04 },
{ 0x10, 0x07, 0x0b, 0x0f, 0x06, 0x0a, 0x04, 0x01, 0x09, 0x08, 0x05, 0x02, 0x0c, 0x0e, 0x0d, 0x03 },
{ 0x00, 0x40, 0xf9, 0x7e, 0x53, 0xea, 0x87, 0x13, 0x2d, 0x3e, 0x94, 0xd4, 0xb9, 0x6d, 0xaa, 0xc7 },
{ 0x00, 0x1d, 0x44, 0x93, 0x0f, 0x56, 0xd7, 0x12, 0x9c, 0x8e, 0xc5, 0xd8, 0x59, 0x81, 0x4b, 0xca },
{ 0x00, 0x0d, 0x0a, 0x07, 0x04, 0x01, 0x0e, 0x0b, 0x08, 0x05, 0x02, 0x0f, 0x0c, 0x09, 0x06, 0x03 },
{ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
{ 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x1b, 0x3b, 0x5b, 0x7b, 0x9b, 0xbb, 0xdb, 0xfb },
};
static const uint8_t la64_vpaes_keygen_tables[8][16] __attribute__((aligned(16))) = {
{ 0x00, 0x70, 0x2a, 0x5a, 0x98, 0xe8, 0xb2, 0xc2, 0x08, 0x78, 0x22, 0x52, 0x90, 0xe0, 0xba, 0xca },
{ 0x00, 0x4d, 0x7c, 0x31, 0x7d, 0x30, 0x01, 0x4c, 0x81, 0xcc, 0xfd, 0xb0, 0xfc, 0xb1, 0x80, 0xcd },
{ 0x10, 0x01, 0x08, 0x0d, 0x0f, 0x06, 0x05, 0x0e, 0x02, 0x0c, 0x0b, 0x0a, 0x09, 0x03, 0x07, 0x04 },
{ 0x10, 0x07, 0x0b, 0x0f, 0x06, 0x0a, 0x04, 0x01, 0x09, 0x08, 0x05, 0x02, 0x0c, 0x0e, 0x0d, 0x03 },
{ 0x00, 0xc7, 0xbd, 0x6f, 0x17, 0x6d, 0xd2, 0xd0, 0x78, 0xa8, 0x02, 0xc5, 0x7a, 0xbf, 0xaa, 0x15 },
{ 0x00, 0x6a, 0xbb, 0x5f, 0xa5, 0x74, 0xe4, 0xcf, 0xfa, 0x35, 0x2b, 0x41, 0xd1, 0x90, 0x1e, 0x8e },
{ 0x04, 0x05, 0x06, 0x07, 0x05, 0x06, 0x07, 0x04, 0x0c, 0x0d, 0x0e, 0x0f, 0x0d, 0x0e, 0x0f, 0x0c },
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00 },
};
#define LA64_DUP16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p
static const uint8_t la64_vpaes_enc_tables_xv[9][32] __attribute__((aligned(32))) = {
{ LA64_DUP16(0x00, 0x70, 0x2a, 0x5a, 0x98, 0xe8, 0xb2, 0xc2, 0x08, 0x78, 0x22, 0x52, 0x90, 0xe0, 0xba, 0xca) },
{ LA64_DUP16(0x00, 0x4d, 0x7c, 0x31, 0x7d, 0x30, 0x01, 0x4c, 0x81, 0xcc, 0xfd, 0xb0, 0xfc, 0xb1, 0x80, 0xcd) },
{ LA64_DUP16(0x10, 0x01, 0x08, 0x0d, 0x0f, 0x06, 0x05, 0x0e, 0x02, 0x0c, 0x0b, 0x0a, 0x09, 0x03, 0x07, 0x04) },
{ LA64_DUP16(0x10, 0x07, 0x0b, 0x0f, 0x06, 0x0a, 0x04, 0x01, 0x09, 0x08, 0x05, 0x02, 0x0c, 0x0e, 0x0d, 0x03) },
{ LA64_DUP16(0x00, 0xc7, 0xbd, 0x6f, 0x17, 0x6d, 0xd2, 0xd0, 0x78, 0xa8, 0x02, 0xc5, 0x7a, 0xbf, 0xaa, 0x15) },
{ LA64_DUP16(0x00, 0x6a, 0xbb, 0x5f, 0xa5, 0x74, 0xe4, 0xcf, 0xfa, 0x35, 0x2b, 0x41, 0xd1, 0x90, 0x1e, 0x8e) },
{ LA64_DUP16(0x00, 0x05, 0x0a, 0x0f, 0x04, 0x09, 0x0e, 0x03, 0x08, 0x0d, 0x02, 0x07, 0x0c, 0x01, 0x06, 0x0b) },
{ LA64_DUP16(0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e) },
{ LA64_DUP16(0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x1b, 0x3b, 0x5b, 0x7b, 0x9b, 0xbb, 0xdb, 0xfb) },
};
static const uint8_t la64_vpaes_dec_tables_xv[9][32] __attribute__((aligned(32))) = {
{ LA64_DUP16(0x00, 0x5f, 0x54, 0x0b, 0x04, 0x5b, 0x50, 0x0f, 0x1a, 0x45, 0x4e, 0x11, 0x1e, 0x41, 0x4a, 0x15) },
{ LA64_DUP16(0x00, 0x65, 0x05, 0x60, 0xe6, 0x83, 0xe3, 0x86, 0x94, 0xf1, 0x91, 0xf4, 0x72, 0x17, 0x77, 0x12) },
{ LA64_DUP16(0x10, 0x01, 0x08, 0x0d, 0x0f, 0x06, 0x05, 0x0e, 0x02, 0x0c, 0x0b, 0x0a, 0x09, 0x03, 0x07, 0x04) },
{ LA64_DUP16(0x10, 0x07, 0x0b, 0x0f, 0x06, 0x0a, 0x04, 0x01, 0x09, 0x08, 0x05, 0x02, 0x0c, 0x0e, 0x0d, 0x03) },
{ LA64_DUP16(0x00, 0x40, 0xf9, 0x7e, 0x53, 0xea, 0x87, 0x13, 0x2d, 0x3e, 0x94, 0xd4, 0xb9, 0x6d, 0xaa, 0xc7) },
{ LA64_DUP16(0x00, 0x1d, 0x44, 0x93, 0x0f, 0x56, 0xd7, 0x12, 0x9c, 0x8e, 0xc5, 0xd8, 0x59, 0x81, 0x4b, 0xca) },
{ LA64_DUP16(0x00, 0x0d, 0x0a, 0x07, 0x04, 0x01, 0x0e, 0x0b, 0x08, 0x05, 0x02, 0x0f, 0x0c, 0x09, 0x06, 0x03) },
{ LA64_DUP16(0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e) },
{ LA64_DUP16(0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x1b, 0x3b, 0x5b, 0x7b, 0x9b, 0xbb, 0xdb, 0xfb) },
};
#undef LA64_DUP16
uintptr_t getConst(la64_consts_t which)
{
switch(which) {
@@ -61,6 +127,11 @@ uintptr_t getConst(la64_consts_t which)
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_la64_vpaes_enc_tables: return (uintptr_t)la64_vpaes_enc_tables;
case const_la64_vpaes_dec_tables: return (uintptr_t)la64_vpaes_dec_tables;
case const_la64_vpaes_keygen_tables: return (uintptr_t)la64_vpaes_keygen_tables;
case const_la64_vpaes_enc_tables_xv: return (uintptr_t)la64_vpaes_enc_tables_xv;
case const_la64_vpaes_dec_tables_xv: return (uintptr_t)la64_vpaes_dec_tables_xv;
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;
@@ -107,6 +178,7 @@ uintptr_t getConst(la64_consts_t which)
case const_cpuid: return (uintptr_t)my_cpuid;
case const_getsegmentbase: return (uintptr_t)GetSegmentBaseEmu;
case const_updateflags: return (uintptr_t)UpdateFlags;
case const_updateflags_la64: return (uintptr_t)create_updateflags();
case const_reset_fpu: return (uintptr_t)reset_fpu;
case const_sha1nexte: return (uintptr_t)sha1nexte;
case const_sha1msg1: return (uintptr_t)sha1msg1;
@@ -141,4 +213,4 @@ uintptr_t getConst(la64_consts_t which)
}
dynarec_log(LOG_NONE, "Warning, Unknown const %d used\n", which);
return 0;
}
}
+7 -1
View File
@@ -31,6 +31,11 @@ typedef enum la64_consts_s {
const_native_aeselast,
const_native_aeselast_y,
const_native_aeskeygenassist,
const_la64_vpaes_enc_tables,
const_la64_vpaes_dec_tables,
const_la64_vpaes_keygen_tables,
const_la64_vpaes_enc_tables_xv,
const_la64_vpaes_dec_tables_xv,
const_native_pclmul,
const_native_pclmul_x,
const_native_pclmul_y,
@@ -77,6 +82,7 @@ typedef enum la64_consts_s {
const_cpuid,
const_getsegmentbase,
const_updateflags,
const_updateflags_la64,
const_reset_fpu,
const_sha1nexte,
const_sha1msg1,
@@ -114,4 +120,4 @@ uintptr_t getConst(la64_consts_t which);
// temporary define...
#define const_PrintTrace const_printtrace
#endif //__DYNAREC_LA64_CONSTS__
#endif //__DYNAREC_LA64_CONSTS__
+9 -1
View File
@@ -121,7 +121,7 @@ uintptr_t dynarec64_D9(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
// not in cache, so check Empty status and load it
i2 = -dyn->lsx.x87stack;
LD_WU(x3, xEmu, offsetof(x64emu_t, fpu_stack));
LD_W(x3, xEmu, offsetof(x64emu_t, fpu_stack));
if (i2) {
ADDI_D(x3, x3, -i2);
}
@@ -149,6 +149,14 @@ uintptr_t dynarec64_D9(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
}
} else {
// check if stack is empty (freed register will not count, but might work if using tags instead)
i2 = -dyn->lsx.x87stack;
LD_W(x3, xEmu, offsetof(x64emu_t, fpu_stack));
if (i2) {
ADDI_D(x3, x3, -i2);
}
MOV32w(x4, 0b100000100000000); // empty: C3,C2,C0 = 101
BGE_MARK3(xZR, x3);
// simply move from cache reg to x2
v1 = dyn->lsx.x87reg[i1];
MOVFR2GR_D(x2, v1);
+2 -2
View File
@@ -120,7 +120,7 @@ uintptr_t dynarec64_DB(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 0xE8 ... 0xEF:
INST_NAME("FUCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop & 7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7));
if (ST_IS_F(0)) {
@@ -132,7 +132,7 @@ uintptr_t dynarec64_DB(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
break;
case 0xF0 ... 0xF7:
INST_NAME("FCOMI ST0, STx");
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop & 7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7));
if (ST_IS_F(0)) {
+1 -1
View File
@@ -87,7 +87,7 @@ uintptr_t dynarec64_DF(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("FCOMIP ST0, STx");
}
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
SET_DFNONE();
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop & 7));
v2 = x87_get_st(dyn, ninst, x1, x2, nextop & 7, X87_COMBINE(0, nextop & 7));
+9 -17
View File
@@ -168,7 +168,7 @@ void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
X64_XOR_W(s1, s2);
}
XOR(s1, s1, s2);
if (!rex.w && s1 != s2) ZEROUP(s1);
if (s1 != s2 && NEED_ZEROUP(s1)) ZEROUP(s1);
IFX(X_PEND)
SDxw(s1, xEmu, offsetof(x64emu_t, res));
@@ -185,9 +185,7 @@ void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w && s1 != s2) {
ZEROUP(s1);
}
if (!rex.w && s1 != s2) ZEROUP(s1);
IFX(X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
@@ -231,9 +229,7 @@ void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
}
XOR(s1, s1, s3);
}
if (!rex.w) {
ZEROUP(s1);
}
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND)
SDxw(s1, xEmu, offsetof(x64emu_t, res));
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
@@ -254,9 +250,7 @@ void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
@@ -412,16 +406,16 @@ void emit_and32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
AND(s1, s1, s2); // res = s1 & s2
if (!rex.w) ZEROUP(s1);
IFX(X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
if (cpuext.lbt) {
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
} else if (!rex.w) ZEROUP(s1);
CLEAR_FLAGS(s3);
IFX(X_SF) {
@@ -554,7 +548,7 @@ void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
}
if (cpuext.lbt) {
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
@@ -607,7 +601,7 @@ void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
}
if (cpuext.lbt) {
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
@@ -619,9 +613,7 @@ void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX(X_ZF) {
BNEZ(s1, 8);
+33 -61
View File
@@ -44,7 +44,7 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
X64_ADD_W(s1, s2);
}
ADDxw(s1, s1, s2);
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND)
SDxw(s1, xEmu, offsetof(x64emu_t, res));
@@ -55,17 +55,9 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
CLEAR_FLAGS(s3);
IFX (X_CF) {
if (rex.w) {
ZEROUP2(s5, s1);
ZEROUP2(s4, s2);
ADD_D(s5, s5, s4);
SRLI_D(s3, s1, 0x20);
SRLI_D(s4, s2, 0x20);
ADD_D(s4, s4, s3);
SRLI_D(s5, s5, 0x20);
ADD_D(s5, s5, s4); // hi
SRAI_D(s5, s5, 0x20);
BEQZ(s5, 8);
ORI(xFlags, xFlags, 1 << F_CF);
ADD_D(s5, s1, s2); // s5 = op1 + op2
SLTU(s5, s5, s1); // carry = (s5 < op1) ? 1 : 0
OR(xFlags, xFlags, s5);
} else {
ZEROUP2(s3, s1);
ZEROUP2(s4, s2);
@@ -105,9 +97,7 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
@@ -159,7 +149,7 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
} else {
ADDxw(s1, s1, s2);
}
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND) SDxw(s1, xEmu, offsetof(x64emu_t, res));
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
@@ -169,17 +159,9 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
CLEAR_FLAGS(s3);
IFX (X_CF) {
if (rex.w) {
ZEROUP2(s5, s1);
ZEROUP2(s4, s2);
ADD_D(s5, s5, s4);
SRLI_D(s3, s1, 0x20);
SRLI_D(s4, s2, 0x20);
ADD_D(s4, s4, s3);
SRLI_D(s5, s5, 0x20);
ADD_D(s5, s5, s4); // hi
SRAI_D(s5, s5, 0x20);
BEQZ(s5, 8);
ORI(xFlags, xFlags, 1 << F_CF);
ADD_D(s5, s1, s2); // s5 = op1 + op2
SLTU(s5, s5, s1); // carry = (s5 < op1) ? 1 : 0
OR(xFlags, xFlags, s5);
} else {
ZEROUP2(s3, s1);
ZEROUP2(s4, s2);
@@ -223,9 +205,7 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
@@ -588,7 +568,7 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
X64_SUB_W(s1, s2);
}
SUBxw(s1, s1, s2);
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND)
SDxw(s1, xEmu, offsetof(x64emu_t, res));
@@ -610,9 +590,7 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
IFX (X_ZF) {
BNEZ(s1, 8);
@@ -666,7 +644,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
} else {
SUBxw(s1, s1, s2);
}
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND)
SDxw(s1, xEmu, offsetof(x64emu_t, res));
@@ -693,9 +671,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
IFX (X_ZF) {
BNEZ(s1, 8);
@@ -1015,7 +991,7 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
if (cpuext.lbt) {
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
@@ -1048,9 +1024,7 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s2);
}
@@ -1236,21 +1210,23 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
if (cpuext.lbt) {
if (rex.w)
ADC_D(s3, s1, s2);
else
ADC_W(s3, s1, s2);
IFX (X_ALL) {
if (rex.w)
if (rex.w) {
ADC_D(s3, s1, s2);
X64_ADC_D(s1, s2);
else
MV(s1, s3);
} else {
ADC_W(s3, s1, s2);
X64_ADC_W(s1, s2);
ZEROUP2(s1, s3);
}
} else {
if (rex.w)
ADC_D(s1, s1, s2);
else
ADC_W(s1, s1, s2);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
}
if (rex.w)
MV(s1, s3);
else
ZEROUP2(s1, s3);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -1318,9 +1294,7 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s4);
}
@@ -1474,7 +1448,7 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
ADDIxw(s1, s1, 1);
if (cpuext.lbt) {
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
@@ -1499,9 +1473,7 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PF) {
emit_pf(dyn, ninst, s1, s3, s2);
}
@@ -1640,7 +1612,7 @@ void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
}
ADDIxw(s1, s1, -1);
if (!rex.w) ZEROUP(s1);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
+127 -92
View File
@@ -110,7 +110,7 @@ void emit_shl16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
if (cpuext.lbt) {
IFX (X_PEND) {
} else {
} else IFX (X_ALL) {
MOV64x(s3, c);
}
IFX (X_ALL) {
@@ -222,7 +222,7 @@ void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
X64_SET_EFLAGS(s3, (X_OF | X_AF));
}
SLL_D(s1, s1, s2);
if (!rex.w) { ZEROUP(s1); }
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -286,7 +286,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
if (cpuext.lbt) {
IFX (X_PEND) {
} else {
} else IFX (X_ALL) {
MOV64x(s3, c);
}
IFX (X_ALL) {
@@ -302,8 +302,11 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
BSTRINS_D(s3, xZR, F_AF, F_AF);
X64_SET_EFLAGS(s3, (X_OF | X_AF));
}
SLLIxw(s1, s1, c);
if (!rex.w) ZEROUP(s1);
if (rex.w)
SLLI_D(s1, s1, c);
else
SLLI_W(s1, s1, c);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -333,9 +336,7 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
SLTI(s3, s1, 0);
BSTRINS_D(xFlags, s3, F_SF, F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -824,8 +825,11 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BSTRINS_D(s3, xZR, F_AF, F_AF);
X64_SET_EFLAGS(s3, X_OF | X_AF);
}
SRL_D(s1, s1, s2);
if (!rex.w) ZEROUP(s1);
if (rex.w)
SRL_D(s1, s1, s2);
else
SRL_W(s1, s1, s2);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -846,15 +850,16 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
BSTRINS_D(xFlags, s3, F_OF, F_OF);
}
SRL_D(s1, s1, s2);
if (rex.w)
SRL_D(s1, s1, s2);
else
SRL_W(s1, s1, s2);
IFX (X_SF) {
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -1024,7 +1029,7 @@ void emit_sar16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
if (cpuext.lbt) {
IFX (X_PEND) {
} else {
} else IFX (X_ALL) {
MOV64x(s3, c);
}
IFX (X_ALL) {
@@ -1100,7 +1105,7 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
if (cpuext.lbt) {
IFX (X_PEND) {
} else {
} else IFX (X_ALL) {
MOV64x(s3, c);
}
IFX (X_ALL) {
@@ -1112,8 +1117,11 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
IFXA ((X_AF | X_OF), BOX64DRENV(dynarec_safeflags)) X64_SET_EFLAGS(xZR, X_OF | X_AF);
SRAIxw(s1, s1, c);
if (!rex.w) ZEROUP(s1);
if (rex.w)
SRAI_D(s1, s1, c);
else
SRAI_W(s1, s1, c);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -1146,9 +1154,7 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
BGE(s1, xZR, 8);
ORI(xFlags, xFlags, 1 << F_SF);
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -1182,8 +1188,11 @@ void emit_sar32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
IFXA ((X_AF | X_OF), BOX64DRENV(dynarec_safeflags)) X64_SET_EFLAGS(xZR, X_OF | X_AF);
SRAxw(s1, s1, s2);
if (!rex.w) ZEROUP(s1);
if (rex.w)
SRA_D(s1, s1, s2);
else
SRA_W(s1, s1, s2);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
@@ -1199,7 +1208,7 @@ void emit_sar32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
}
if (rex.w)
SRA_D(s1, s1, s2);
else
else
SRA_W(s1, s1, s2);
IFX (X_SF) {
@@ -1226,47 +1235,61 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
{
if (!c) return;
IFXA ((X_CF | X_OF), cpuext.lbt) {
if (rex.w)
X64_ROTRI_D(s1, c);
else
X64_ROTRI_W(s1, c);
}
int preserve_of = c > 1 && !(dyn->insts[ninst].x64.gen_flags & X_OF);
IFXA (X_CF | X_OF, !cpuext.lbt) {
MOV64x(s4, ((1UL << F_CF) | (1UL << F_OF)));
ANDN(xFlags, xFlags, s4);
}
IFXA (X_OF, (!cpuext.lbt || BOX64DRENV(dynarec_safeflags))) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
XOR(s3, s3, s1);
if (cpuext.lbt) {
if (cpuext.lbt && !preserve_of) {
IFX (X_CF | X_OF) {
if (rex.w)
X64_ROTRI_D(s1, c);
else
X64_ROTRI_W(s1, c);
}
IFXA (X_OF, BOX64DRENV(dynarec_safeflags)) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
XOR(s3, s3, s1);
SLLI_D(s3, s3, F_OF);
X64_SET_EFLAGS(s3, X_OF);
} else
BSTRINS_D(xFlags, s3, F_OF, F_OF);
}
}
ROTRIxw(s1, s1, c);
if (!rex.w) ZEROUP(s1);
if (rex.w)
ROTRI_D(s1, s1, c);
else
ROTRI_W(s1, s1, c);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (cpuext.lbt) {
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
if (preserve_of) RESTORE_EFLAGS(s3);
IFX (X_CF) BSTRINS_D(xFlags, xZR, F_CF, F_CF);
IFX (X_OF) BSTRINS_D(xFlags, xZR, F_OF, F_OF);
IFX (X_OF) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
XOR(s3, s3, s1);
BSTRINS_D(xFlags, s3, F_OF, F_OF);
}
if (rex.w)
ROTRI_D(s1, s1, c);
else
ROTRI_W(s1, s1, c);
if (!rex.w) ZEROUP(s1);
IFX (X_CF) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
OR(xFlags, xFlags, s3);
}
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
// emit ROL8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_rol8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
RESTORE_EFLAGS(s3);
IFX (X_ALL) RESTORE_EFLAGS(s3);
IFX (X_OF) {
SRLI_W(s3, s1, 6);
@@ -1339,9 +1362,9 @@ void emit_rol8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
void emit_rol16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
{
if (!c) return;
RESTORE_EFLAGS(s3);
IFX (X_ALL) RESTORE_EFLAGS(s3);
IFXA (X_OF, c == 1) {
IFX (X_OF) {
SRLI_D(s3, s1, 14);
SRLI_D(s4, s3, 1);
XOR(s3, s4, s3);
@@ -1403,7 +1426,6 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
ROTR_W(s1, s1, s3);
}
if (!rex.w) ZEROUP(s1);
if (cpuext.lbt) {
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
@@ -1446,12 +1468,12 @@ void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
} else {
ROTR_W(s1, s1, s2);
}
if (!rex.w) ZEROUP(s1);
if (cpuext.lbt) {
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
} else if (!rex.w) ZEROUP(s1);
IFX (X_CF) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
@@ -1465,41 +1487,56 @@ void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
{
if (!c) return;
IFXA (X_CF | X_OF, !cpuext.lbt) {
MOV64x(s3, ((1UL << F_CF) | (1UL << F_OF)));
ANDN(xFlags, xFlags, s3);
}
int preserve_of = c > 1 && !(dyn->insts[ninst].x64.gen_flags & X_OF);
IFXA ((X_CF | X_OF), cpuext.lbt) {
if (rex.w)
X64_ROTLI_D(s1, c);
else
X64_ROTLI_W(s1, c);
}
IFXA (X_OF, (!cpuext.lbt || BOX64DRENV(dynarec_safeflags))) {
SRLIxw(s3, s1, rex.w ? 62 : 30);
SRLI_D(s4, s3, 1);
XOR(s3, s3, s4);
if (cpuext.lbt) {
if (cpuext.lbt && !preserve_of) {
IFX (X_CF | X_OF) {
if (rex.w)
X64_ROTLI_D(s1, c);
else
X64_ROTLI_W(s1, c);
}
IFXA (X_OF, BOX64DRENV(dynarec_safeflags)) {
SRLIxw(s3, s1, rex.w ? 62 : 30);
SRLI_D(s4, s3, 1);
XOR(s3, s3, s4);
SLLI_D(s3, s3, F_OF);
X64_SET_EFLAGS(s3, X_OF);
} else
BSTRINS_D(xFlags, s3, F_OF, F_OF);
}
}
ROTRIxw(s1, s1, (rex.w ? 64 : 32) - c);
if (!rex.w) ZEROUP(s1);
if (rex.w)
ROTRI_D(s1, s1, (rex.w ? 64 : 32) - c);
else
ROTRI_W(s1, s1, (rex.w ? 64 : 32) - c);
if (NEED_ZEROUP(s1)) ZEROUP(s1);
if (cpuext.lbt) {
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
return;
}
if (preserve_of) RESTORE_EFLAGS(s3);
IFX (X_CF) BSTRINS_D(xFlags, xZR, F_CF, F_CF);
IFX (X_OF) BSTRINS_D(xFlags, xZR, F_OF, F_OF);
IFX (X_OF) {
SRLIxw(s3, s1, rex.w ? 62 : 30);
SRLI_D(s4, s3, 1);
XOR(s3, s3, s4);
BSTRINS_D(xFlags, s3, F_OF, F_OF);
}
if (rex.w)
ROTRI_D(s1, s1, (rex.w ? 64 : 32) - c);
else
ROTRI_W(s1, s1, (rex.w ? 64 : 32) - c);
if (!rex.w) ZEROUP(s1);
IFX (X_CF) {
ANDI(s4, s1, 1 << F_CF);
OR(xFlags, xFlags, s4);
}
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
}
@@ -1534,9 +1571,7 @@ void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
SRLIxw(s1, s2, (rex.w ? 64 : 32) - c);
OR(s1, s1, s3);
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_SF) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
BEQZ(s3, 8);
@@ -1593,9 +1628,7 @@ void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
SLLIxw(s1, s2, (rex.w ? 64 : 32) - c);
OR(s1, s1, s3);
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_SF) {
SRLIxw(s3, s1, rex.w ? 63 : 31);
BEQZ(s3, 8);
@@ -1647,9 +1680,7 @@ void emit_shrd32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
IFX (X_PEND) {
SDxw(s1, xEmu, offsetof(x64emu_t, res));
}
if (!rex.w) {
ZEROUP(s1);
}
if (!rex.w) ZEROUP(s1);
IFX (X_ZF) {
BNEZ(s1, 8);
ORI(xFlags, xFlags, 1 << F_ZF);
@@ -1878,7 +1909,6 @@ void emit_rcl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
OR(s1, s5, s4);
}
if (!rex.w) ZEROUP(s1);
IFX (X_CF) {
BSTRINS_D(xFlags, s3, F_CF, F_CF);
}
@@ -1992,10 +2022,16 @@ void emit_rcr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
ADDI_D(s5, s2, -1);
IFX (X_CF) SRL_D(s3, s1, s5); // for later
SRLI_D(s4, s1, 1);
if (rex.w)
SRLI_D(s4, s1, 1);
else
SRLI_W(s4, s1, 1);
BSTRINS_D(s4, xFlags, rex.w ? 63 : 31, rex.w ? 63 : 31); // insert cf
BEQZ(s5, 4 + 4 * 5); // goto label
SRL_D(s4, s4, s5);
if (rex.w)
SRL_D(s4, s4, s5);
else
SRL_W(s4, s4, s5);
ADDI_D(s5, xZR, rex.w ? 65 : 33);
SUB_D(s2, s5, s2);
if (rex.w)
@@ -2036,7 +2072,6 @@ void emit_rcr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
OR(s1, s3, s4);
}
if (!rex.w) ZEROUP(s1);
IFX (X_CF) {
BSTRINS_D(xFlags, s5, F_CF, F_CF);
}
@@ -2048,7 +2083,7 @@ void emit_rcr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
// emit ROR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
RESTORE_EFLAGS(s3);
IFX (X_ALL) RESTORE_EFLAGS(s3);
IFX (X_OF) {
SRLI_D(s3, s1, 7);
@@ -2075,7 +2110,7 @@ void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
{
if (!c) return;
RESTORE_EFLAGS(s3);
IFX (X_ALL) RESTORE_EFLAGS(s3);
IFX (X_OF) {
SRLI_D(s3, s1, 7);
@@ -2103,8 +2138,8 @@ void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
void emit_ror16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
{
if (!c) return;
RESTORE_EFLAGS(s3);
IFXA (X_OF, (c == 1)) {
IFX (X_ALL) RESTORE_EFLAGS(s3);
IFX (X_OF) {
SRLI_D(s3, s1, 15);
XOR(s3, s3, s1);
BSTRINS_D(xFlags, s3, F_OF, F_OF);
@@ -2379,7 +2414,7 @@ void emit_shrd16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
// emit ROL16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_rol16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
RESTORE_EFLAGS(s3);
IFX (X_ALL) RESTORE_EFLAGS(s3);
ANDI(s2, s2, 0xf);
IFX (X_OF) {
@@ -2407,7 +2442,7 @@ void emit_rol16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
// emit ROR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
void emit_ror16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
{
RESTORE_EFLAGS(s3);
IFX (X_ALL) RESTORE_EFLAGS(s3);
ANDI(s2, s2, 0xf);
IFX (X_OF) {
+3 -3
View File
@@ -437,12 +437,12 @@ void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
}
NAT_FLAGS_ENABLE_SIGN();
NAT_FLAGS_ENABLE_SF();
if (cpuext.lbt) {
IFX(X_ALL) {
X64_AND_B(s1, s2);
}
if (s1 == s2) {
NAT_FLAGS_ENABLE_SF();
int r = s1;
if (dyn->insts[ninst].nat_flags_fusion) {
if (dyn->insts[ninst].nat_flags_needsign) {
@@ -561,13 +561,13 @@ void emit_test16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
}
NAT_FLAGS_ENABLE_SIGN();
NAT_FLAGS_ENABLE_SF();
if (cpuext.lbt) {
IFX (X_ALL) {
X64_AND_H(s1, s2);
}
if (s1 == s2) {
NAT_FLAGS_ENABLE_SF();
int r = s1;
if (dyn->insts[ninst].nat_flags_fusion) {
if (dyn->insts[ninst].nat_flags_needsign) {
@@ -630,6 +630,7 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
}
NAT_FLAGS_ENABLE_SIGN();
NAT_FLAGS_ENABLE_SF();
if (cpuext.lbt) {
IFX(X_ALL) {
if (rex.w)
@@ -639,7 +640,6 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
}
if (s1 == s2) {
NAT_FLAGS_ENABLE_SF();
int r = s1;
if (dyn->insts[ninst].nat_flags_fusion) {
if (!rex.w) {
+54 -13
View File
@@ -77,7 +77,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK ADD Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -148,7 +148,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK OR Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -197,7 +197,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
SRAI_D(x1, gd, 3);
@@ -288,7 +288,8 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK CMPXCHG Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
GETGD;
GETGDs;
MARKREGs(xRAX);
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
UFLAG_IF { MVxw(x6, xRAX); }
ANDI(x1, wback, (1 << (rex.w + 2)) - 1);
@@ -339,7 +340,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
nextop = F8;
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
SRAI_D(x1, gd, 3);
@@ -419,7 +420,6 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("LOCK BTR Ed, Ib");
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
SET_DFNONE();
GETGD;
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 0, 1);
u8 = F8;
u8 &= (rex.w ? 0x3f : 0x1f);
@@ -489,7 +489,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK XADD Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDsd;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -556,6 +556,10 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
}
}
if (rex.w) {
MARKREGsd(xRAX);
MARKREGsd(xRDX);
MARKREGs(xRBX);
MARKREGs(xRCX);
if (cpuext.scq) {
MARKLOCK;
LL_D(x2, wback, 0);
@@ -613,6 +617,8 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
AMSWAP_DB_W(xZR, xZR, x6);
}
} else {
UP32_READ(xRDX);
UP32_READ(xRCX);
BSTRINS_D(x3, xRAX, 31, 0);
BSTRINS_D(x3, xRDX, 63, 32);
BSTRINS_D(x4, xRBX, 31, 0);
@@ -680,7 +686,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("LOCK ADC Ed, Gd");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lbt) {
X64_GET_EFLAGS(x7, X_CF);
@@ -736,7 +742,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
INST_NAME("LOCK SBB Ed, Gd");
READFLAGS(X_CF);
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lbt) {
X64_GET_EFLAGS(x6, X_CF);
@@ -823,7 +829,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK AND Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -868,7 +874,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK SUB Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -915,7 +921,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
} else {
INST_NAME("LOCK XOR Ed, Gd");
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
GETGD;
GETGDs;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -1412,7 +1418,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
*ok = 0;
} else {
INST_NAME("LOCK XCHG Ed, Gd");
GETGD;
GETGDsd;
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (rex.w) {
if (!ALIGNED_ATOMICxw) {
@@ -1446,6 +1452,41 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
MVxw(gd, x1);
}
break;
case 0xF6:
nextop = F8;
switch ((nextop >> 3) & 7) {
case 2:
if (MODREG) {
INST_NAME("Invalid LOCK");
UDF();
*need_epilog = 1;
*ok = 0;
} else {
INST_NAME("LOCK NOT Eb");
addr = geted(dyn, addr, ninst, nextop, &wback, x5, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
if (cpuext.lamcas) {
LD_BU(x3, wback, 0);
MARKLOCK2;
MV(x2, x3);
XORI(x1, x3, 0xff);
AMCAS_DB_B(x3, x1, wback);
BSTRPICK_D(x3, x3, 7, 0);
BNE_MARKLOCK2(x3, x2);
} else {
ANDI(x2, wback, 3);
SLLI_D(x2, x2, 3);
MV(x3, wback);
BSTRINS_D(x3, xZR, 1, 0);
ADDI_D(x1, xZR, 0xff);
SLL_W(x1, x1, x2);
AMXOR_DB_W(x4, x1, x3);
}
}
break;
default:
DEFAULT;
}
break;
case 0xF7:
nextop = F8;
switch ((nextop >> 3) & 7) {
Loaded 100 of 514 files, more files were not shown because too many files have changed in this diff. Show more